赞
踩
参考文档:语音合成(流式版)WebAPI 文档
微信小程序背景音频播报可参考:uniapp实现微信小程序websocket+背景音频语音播报
实现步骤
- 注册讯飞账号,完成实名认证,获取应用appid
- 连接讯飞websocket,在握手阶段,请求方需要对请求进行签名
- 发送请求文本,讯飞服务器返回合成后的音频片段,采用base64编码
- 将返回的音频片段组合,并转成可播放的MP3文件
1.注册账号,并获取应用appid
打开官网网址:讯飞开放平台-语音合成 点击免费试用,按步骤完成实名认证后得到appid
2.连接讯飞websocket,在握手阶段,请求方需要对请求进行签名
- async getWebsocketUrl() {
- // 合成讯飞语音请求地址
- const that = this;
- return await new Promise((resolve, reject) => {
- var apiKey = API_KEY; // 讯飞控制台查看
- var apiSecret = API_SECRET; // 讯飞控制台查看
- var url = 'wss://tts-api.xfyun.cn/v2/tts';
- var host = BASEURL; // 请求的主机地址
- 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 = that.base64_encode(authorizationOrigin);
- url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;
- resolve(url);
- });
- }
- async linkXunfeiSocket() {
- // 连接讯飞Socket服务器
- let url = await this.getWebsocketUrl();
- let XunfeiSocketTask;
- await new Promise((resolve, reject) => {
- XunfeiSocketTask = uni.connectSocket({
- url: encodeURI(url),
- header: {
- 'content-type': 'application/json'
- },
- success: () => {
- console.log(`讯飞 connect成功`);
- resolve();
- },
- fail: () => {
- console.log('讯飞 connect失败');
- reject();
- }
- });
- });
- this.xunfeiSocketTask = XunfeiSocketTask;
- this.initXunFei(this.xunfeiSocketTask);
- }
- initXunFei(xunfeiSocketTask) {
- // 监听消息
- xunfeiSocketTask.onMessage(res => {
- // console.log('接收讯飞消息');
- this.result(res.data);
- });
- xunfeiSocketTask.onOpen(() => {
- // console.log('讯飞websocket打开');
- this.webSocketSend();
- });
- xunfeiSocketTask.onClose(res => {
- clearTimeout(this.playTimeout);
- // console.error('讯飞断开');
- });
- xunfeiSocketTask.onError(err => {
- // console.error('讯飞连接错误', err);
- });
- }
注意:
(1)signature_sha:hmac-sha256算法结合apiSecret对signature_origin签名,使用crypto-js实现
- // 安装
- npm install crypto-js
- yarn add crypto-js
-
- // 引用
- import CryptoJS from 'crypto-js';
(2)signature:需要使用CryptoJS.enc.Base64.stringify()方式编码后使用
(3)authorization:需要base64编码后使用,编码方式如下(等同于Window.btoa())
- base64_encode(str) {
- // 编码,配合encodeURIComponent使用
- var c1, c2, c3;
- var base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
- var i = 0,
- len = str.length,
- strin = '';
- while (i < len) {
- c1 = str.charCodeAt(i++) & 0xff;
- if (i == len) {
- strin += base64EncodeChars.charAt(c1 >> 2);
- strin += base64EncodeChars.charAt((c1 & 0x3) << 4);
- strin += '==';
- break;
- }
- c2 = str.charCodeAt(i++);
- if (i == len) {
- strin += base64EncodeChars.charAt(c1 >> 2);
- strin += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4));
- strin += base64EncodeChars.charAt((c2 & 0xf) << 2);
- strin += '=';
- break;
- }
- c3 = str.charCodeAt(i++);
- strin += base64EncodeChars.charAt(c1 >> 2);
- strin += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4));
- strin += base64EncodeChars.charAt(((c2 & 0xf) << 2) | ((c3 & 0xc0) >> 6));
- strin += base64EncodeChars.charAt(c3 & 0x3f);
- }
- return strin;
- }
3.发送和接收数据
发送文本消息
- webSocketSend() {
- let params = {
- common: {
- app_id: APPID // 讯飞控制台查看
- },
- business: {
- aue: 'lame', // 音频编码表示mp3格式,当aue=lame时需传参sfl=1
- sfl: 1,
- vcn: 'xiaoyan', // 发音人选择
- tte: 'UTF8'
- },
- data: {
- status: 2,
- text: CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(this.toAudioText))
- }
- };
-
- this.xunfeiSocketTask.send({
- data: JSON.stringify(params),
- success: res => {
- // console.log('发出讯飞消息');
- },
- fail: err => {
- // console.log('发出讯飞消息失败', err);
- }
- });
- }
注意:
(1)发送的文本数据data的text需要使用base64编码
(2)send方法发送的数据需要转成json字符串
(3)返回的数据为合成后的音频片段,采用base64编码
4. 将返回的音频片段组合,并转成可播放的MP3文件
当code为0,data.status为1时,表示合并中,将base64字符串合并
当code为0,data.status为2时,表示一句话合并完成,在此处将合并的base64转成音频文件
- result(resultData) {
- let jsonData = JSON.parse(resultData);
- //陆续合并接收的base64音频流
- this.audioBase64 += jsonData.data.audio;
- if (jsonData.code !== 0) {
- // 合成失败
- console.log(`${jsonData.code}:${jsonData.message}`);
- return;
- }
- if (jsonData.code === 0 && jsonData.data.status === 2) {
- // 分段发送完成,转成语音文件关闭连接
- // 注意:将base64转化成ArrayBuffer
- const data = uni.base64ToArrayBuffer(this.audioBase64);
- const target = `${wx.env.USER_DATA_PATH}/${new Date().getTime()}.mp3`;
- try {
- // 使用fs.writeFileSync完成音频文件的转化
- const res = fs.writeFileSync(target, data, 'binary');
- this.playAudio.push(target);
- this.xunfeiSocketTask.close();
- this.audioBase64 = '';
- } catch (e) {
- console.error(e);
- }
- }
- }
注意:使用fs.writeFileSync转文件时,传入的data为ArrayBuffer格式
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。