微信小程序实现讯飞语音合成

参考文档:语音合成(流式版)WebAPI 文档

微信小程序背景音频播报可参考:uniapp实现微信小程序websocket+背景音频语音播报

实现步骤

  1. 注册讯飞账号,完成实名认证,获取应用appid
  2. 连接讯飞websocket,在握手阶段,请求方需要对请求进行签名
  3. 发送请求文本,讯飞服务器返回合成后的音频片段,采用base64编码
  4. 将返回的音频片段组合,并转成可播放的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格式

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值