xfyun-client-sdk
Version:
xunfei voice sdk
2 lines (1 loc) • 3.17 kB
JavaScript
import t from"crypto-js";class o{constructor(t){var o;this.ttsWS=null,this.audioChunks=[],this.audioContext=null,this.audioSource=null,this.isPlaying=!1,this.appid=t.appid,this.apiKey=t.apiKey,this.apiSecret=t.apiSecret,this.content=null!==(o=t.content)&&void 0!==o?o:"",this.validateConfig(t)}validateConfig(t){if(!t.appid||!t.apiKey||!t.apiSecret)throw new Error("Missing required authenication parameters")}generateSignature(){const o=location.host,e=(new Date).toUTCString(),i=`host: ${o}\ndate: ${e}\nGET /v2/tts HTTP/1.1`,s=t.HmacSHA256(i,this.apiSecret),a=t.enc.Base64.stringify(s),n=`api_key="${this.apiKey}", algorithm="hmac-sha256", headers="host date request-line", signature="${a}"`;return`wss://tts-api.xfyun.cn/v2/tts?authorization=${btoa(n)}&date=${e}&host=${o}`}async playAudio(){if(0!==this.audioChunks.length)try{const t=this.audioChunks.reduce(((t,o)=>t+o.byteLength),0),o=new Uint8Array(t);let e=0;for(const t of this.audioChunks)o.set(new Uint8Array(t),e),e+=t.byteLength;this.audioContext=new(window.AudioContext||window.webkitAudioContext);const i=await this.audioContext.decodeAudioData(o.buffer);this.audioSource=this.audioContext.createBufferSource(),this.audioSource.buffer=i,this.audioSource.connect(this.audioContext.destination),this.audioSource.onended=()=>{this.isPlaying=!1,console.log("Play finished")},this.audioSource.start(0),this.isPlaying=!0,console.log("Audio play started")}catch(t){console.log("Failed to play audio",t)}else console.warn("No audio data to play")}stopPlayAudio(){this.isPlaying&&this.audioSource&&(this.audioSource.stop(),this.isPlaying=!1,console.log("play stopped"))}async synthesize(t={}){return new Promise(((o,e)=>{const i=this.generateSignature();if(!("WebSocket"in window))return e(new Error("WebSocket is not supported in this environment"));this.ttsWS=new WebSocket(i),this.ttsWS.onopen=()=>{var o,e,i,s,a,n;const r={common:{app_id:this.appid},business:{aue:null!==(o=t.audioFormat)&&void 0!==o?o:"lame",auf:`audio/L16;rate=${t.sampleRate||16e3}`,vcn:null!==(e=t.voice)&&void 0!==e?e:"xiaoyan",speed:null!==(i=t.speed)&&void 0!==i?i:50,volume:null!==(s=t.volume)&&void 0!==s?s:50,pitch:null!==(a=t.pitch)&&void 0!==a?a:50,tte:"UTF8"},data:{status:2,text:btoa(String.fromCharCode(...(new TextEncoder).encode(this.content)))}};null===(n=this.ttsWS)||void 0===n||n.send(JSON.stringify(r))},this.ttsWS.onmessage=t=>{var i,s;const a=JSON.parse(t.data);if(0===a.code){const t=Uint8Array.from(atob(a.data.audio),(t=>t.charCodeAt(0)));this.audioChunks.push(t.buffer),2===a.data.status&&(console.log("Received all audio data"),null===(i=this.ttsWS)||void 0===i||i.close(),this.playAudio().then(o).catch(e))}else null===(s=this.ttsWS)||void 0===s||s.close(),e(new Error(`TTS error:${a.message} (code ${a.code})`))},this.ttsWS.onerror=t=>{var o;console.log("websocket error:",t),null===(o=this.ttsWS)||void 0===o||o.close(),e(new Error("webscoket connection error"))},this.ttsWS.onclose=()=>{this.ttsWS=null}}))}destory(){this.stopPlayAudio(),this.ttsWS&&(this.ttsWS.close(),this.ttsWS=null),this.audioContext&&(this.audioContext.close(),this.audioContext=null),this.audioChunks=[]}}export{o as default};