123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- // import Base64 from "crypto-js/enc-base64";
- import CryptoJS from "crypto-js";
- import AudioPlayer from "./audioPlayer.esm";
- import Base64 from "./base64";
- export default class TtsVoice {
- appId = "";
- apiSecret = "";
- apiKey = "";
- ttsWS = null;
- status = "UNDEFINED";
- statusStr = "";
- audioPlayer = null;
- text = "";
- blob = "";
- cb = () => {};
- blobDoneCb = () => {};
- constructor(params) {
- this.appId = params.appId;
- this.apiSecret = params.apiSecret;
- this.apiKey = params.apiKey;
- if (params.cb) {
- this.cb = params.cb;
- }
- if (params.blobDoneCb) {
- this.blobDoneCb = params.blobDoneCb;
- }
- this.audioPlayer = new AudioPlayer();
- this.audioPlayer.onPlay = () => {
- this.changeBtnStatus("PLAY");
- };
- this.audioPlayer.onStop = (audioDatas) => {
- console.log(audioDatas);
- this.status === "PLAY" && this.changeBtnStatus("STOP");
- };
- }
- setText(text) {
- this.text = text;
- }
- changeBtnStatus(status) {
- this.status = status;
- if (status === "UNDEFINED") {
- this.statusStr = "立即合成";
- } else if (status === "CONNECTING") {
- this.statusStr = "正在合成";
- } else if (status === "PLAY") {
- this.statusStr = "停止播放";
- } else if (status === "STOP") {
- this.statusStr = "重新播放";
- }
- const _this = this;
- this.cb({ status, statusStr: _this.statusStr });
- }
- encodeText(text, type) {
- if (type === "unicode") {
- let buf = new ArrayBuffer(text.length * 4);
- let bufView = new Uint16Array(buf);
- for (let i = 0, strlen = text.length; i < strlen; i++) {
- bufView[i] = text.charCodeAt(i);
- }
- let binary = "";
- let bytes = new Uint8Array(buf);
- let len = bytes.byteLength;
- for (let i = 0; i < len; i++) {
- binary += String.fromCharCode(bytes[i]);
- }
- return window.btoa(binary);
- } else {
- return Base64.encode(text);
- }
- }
- getWebSocketUrl() {
- let apiKey = this.apiKey;
- let apiSecret = this.apiSecret;
- var url = "wss://tts-api.xfyun.cn/v2/tts";
- var host = location.host;
- var date = new Date().toGMTString();
- var algorithm = "hmac-sha256";
- var headers = "host date request-line";
- var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/tts HTTP/1.1`;
- var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
- var signature = CryptoJS.enc.Base64.stringify(signatureSha);
- var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
- var authorization = btoa(authorizationOrigin);
- url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;
- return url;
- }
- stopConnect() {
- this.changeBtnStatus("UNDEFINED");
- this.ttsWS?.close();
- this.audioPlayer.reset();
- }
- action(text) {
- if (text && typeof text === "string") {
- if (text !== this.text) {
- this.changeBtnStatus("UNDEFINED");
- }
- this.setText(text);
- }
- if (this.status === "UNDEFINED") {
- // 开始合成
- this.connect();
- } else if (this.status === "CONNECTING") {
- // 停止合成
- this.changeBtnStatus("UNDEFINED");
- this.ttsWS?.close();
- this.audioPlayer.reset();
- return;
- } else if (this.status === "PLAY") {
- this.audioPlayer.stop();
- } else if (this.status === "STOP") {
- this.audioPlayer.play();
- }
- }
- connect() {
- this.ttsWS?.close();
- this.blob = "";
- this.blobDoneCb && this.blobDoneCb(this.blob);
- const text = this.text || "请输入文字!";
- const appId = this.appId;
- const apiKey = this.apiKey;
- const apiSecret = this.apiSecret;
- const url = this.getWebSocketUrl(apiKey, apiSecret);
- if ("WebSocket" in window) {
- this.ttsWS = new WebSocket(url);
- } else if ("MozWebSocket" in window) {
- this.ttsWS = new window.MozWebSocket(url);
- } else {
- alert("浏览器不支持WebSocket");
- return;
- }
- this.changeBtnStatus("CONNECTING");
- const _this = this;
- this.ttsWS.onopen = () => {
- _this.audioPlayer.start({
- autoPlay: true,
- sampleRate: 16000,
- resumePlayDuration: 1000,
- });
- _this.changeBtnStatus("PLAY");
- var tte = "UTF8";
- var params = {
- common: {
- app_id: appId,
- },
- business: {
- aue: "raw",
- auf: "audio/L16;rate=16000",
- vcn: "50",
- speed: 50,
- volume: 50,
- pitch: 50,
- bgs: 1,
- tte,
- },
- data: {
- status: 2,
- text: _this.encodeText(text, tte),
- },
- };
- _this.ttsWS.send(JSON.stringify(params));
- };
- this.ttsWS.onmessage = (e) => {
- let jsonData = JSON.parse(e.data);
- // 合成失败
- if (jsonData.code !== 0) {
- console.error(jsonData);
- _this.changeBtnStatus("UNDEFINED");
- return;
- }
- _this.audioPlayer.postMessage({
- type: "base64",
- data: jsonData.data.audio,
- isLastData: jsonData.data.status === 2,
- });
- if (jsonData.code === 0 && jsonData.data.status === 2) {
- _this.ttsWS.close();
- setTimeout(() => {
- _this.blob = this.audioPlayer.getAudioDataBlob("wav");
- _this.blobDoneCb && _this.blobDoneCb(_this.blob);
- });
- }
- };
- _this.ttsWS.onerror = (e) => {
- console.error(e);
- };
- _this.ttsWS.onclose = (e) => {
- console.log(e);
- };
- }
- download() {
- const blob = this.audioPlayer.getAudioDataBlob("wav");
- if (!blob) {
- return;
- }
- let defaultName = new Date().getTime();
- let node = document.createElement("a");
- node.href = window.URL.createObjectURL(blob);
- node.download = `${defaultName}.wav`;
- node.click();
- node.remove();
- }
- reset() {
- this.ttsWS?.close();
- this.text = "";
- this.blob = "";
- this.changeBtnStatus("UNDEFINED");
- }
- }
|