功能需求
实现通过传入“语音文案自动播报”,如:“测试播报”,语音自动播报“测试播报”
方案
- 使用wx.playVoice播放语音文件
优点:使用简单,直接播放录制好的音频文件
缺点:只能播放录制好的语音文件
- 第三方语音服务 + wx.createInnerAudioContext
优点:功能强大,可定制,可以满足复杂的场景;
缺点:需要服务端对接,付费
- 小程序插件 + wx.createInnerAudioContext
优点:简单快捷,适用于简单场景;
缺点:功能单一,无法定制,大写英文无法识别,部分小写英文发音不准
第三方语音平台
语音平台
服务端
对接第三方平台,将转换后的语音数据交给小程序。
小程序
1.添加请求
wx.request({
url: 'https://xxxx.com',
data: { data: "待合成的语音数据"},
method: "get",
header: {
'content-type': 'application/json' // 默认值
},
dataType: "json",
success: function (res) {
const innerAudioContext = wx.createInnerAudioContext();
innerAudioContext.src = res.filename;
innerAudioContext.play();
}
})
微信插件
- 添加
微信同声传译
插件:在微信公众平台配置,找到设置–第三方设置–插件管理–点击添加插件 - 搜索
微信同声传译
,点击添加 - 引入插件:在项目根目录app.json文件中配置
"plugins": {
// 引入插件
"WechatSI": { // 自定义的名字
"version": "0.3.5", // 引入插件的版本号
"provider": "wx069ba97219f66d99" // 引入插件的appID
}
}
- 使用
const plugin = requirePlugin('WechatSI');
onReady() {
this.innerAudioContext = wx.createInnerAudioContext();
const that = this;
plugin.textToSpeech({
// 调用插件的方法
lang: 'zh_CN',
content: '测试语音播报',
success: function (res) {
that.playAudio(res.filename);
}
});
},
playAudio(e) {
this.innerAudioContext.src = e;
this.innerAudioContext.play();
},
- 封装优化
const plugin = requirePlugin('WechatSI');
import { trim, isLetter } from '@/shared/index';
class PluginService {
innerAudioContext;
audioBroadcast(content: string): Promise<any> {
return new Promise((resolve, reject) => {
this.innerAudioContext = wx.createInnerAudioContext();
plugin.textToSpeech({
// 调用插件的方法
lang: 'zh_CN',
content,
success: res => {
this.playAudio(res.filename, resolve, reject);
},
fail: reject
});
});
}
playAudio(e, resolve, reject) {
this.innerAudioContext.src = e;
this.innerAudioContext.play();
this.innerAudioContext.onStop(() => {
console.log('[ onStop ] >');
resolve({
type: 'stop'
});
});
this.innerAudioContext.onEnded(() => {
//播放结束,销毁该实例
this.innerAudioContext.destroy();
console.log('[ onEnded ] >');
resolve({
type: 'end'
});
});
this.innerAudioContext.onError(error => {
console.log('[ onError ] >', error);
this.innerAudioContext.destroy();
reject(error);
});
}
stopAudio() {
this.innerAudioContext.stop();
this.innerAudioContext.destroy();
}
}
export default new PluginService();
在shared/index中工具函数:
// 去掉字符串中所有空格(包括中间空格,需要设置第2个参数为:true)
export function trim(str: string, isGlobal = true) {
if (!str) {
return str;
}
const result = str.replace(/(^\s+)|(\s+$)/g, '');
return isGlobal ? result.replace(/\s/g, '') : result;
}
// 判断是否为字母
export function isLetter(str) {
const reg = /^[A-Za-z]+$/;
return reg.test(str);
}
// 字母转中文
export function translateAlphabet(letters) {
if (!letters || !(letters.length > 0)) {
return letters;
}
let tLetters = '';
for (const key of letters) {
tLetters += alphabetComparison(key);
}
return trim(tLetters);
}
// 字母中文读法
export function alphabetComparison(letter) {
if (!letter || !isLetter(letter)) {
return letter;
}
const letterCase = letter.toUpperCase();
const letterMap = {
A: '诶',
B: 'b',
C: '西',
D: '帝',
E: '伊',
F: 'f',
G: 'g',
H: 'h',
I: 'i',
J: 'j',
K: 'k',
L: 'l',
M: 'm',
N: 'n',
O: '欧',
P: 'p',
Q: 'q',
R: 'r',
S: '爱死',
T: 't',
U: '优',
V: 'v',
W: 'w',
X: 'x',
Y: '歪',
Z: 'z'
};
return letterMap[letterCase];
}
在页面中使用
import { pluginService, translateAlphabet } from '@util';
import { formatCabinetNo, getCacheCabinet } from '@/shared/index';
Page({
...
onLoad(e) {
// 获取订单结果类型
this.autoPlay();
},
onUnload() {
pluginService.stopAudio();
},
// 轮询播放多次
autoPlay(timerCount = 0, maxCount = 100) {
const { address, lockerName } = this.data;
console.log('timerCount:', timerCount);
if (timerCount > maxCount) {
return;
}
const tAddress = translateAlphabet(address);
console.log('[ translateAlphabet ] >', tAddress);
// '认准柜门号再存放,不要存错门'
const message = `您的柜门号是${tAddress}${lockerName},请认准柜门号存放,不要存错门`;
pluginService
.audioBroadcast(message)
.then(res => {
if (res.type !== 'stop') {
this.autoPlay(++timerCount);
}
console.log('audioBroadcast.complete', res);
})
.catch(err => {
console.log('[ audioBroadcast.err ] >', err);
this.autoPlay(timerCount);
});
}
});
注意:
- 语音输入配额:每个小程序250条/分钟,3w条/天。
- 文本翻译配额:每个小程序500次/分钟,10w次/天。
- 语音合成配额:每个小程序100次/分钟,2w次/天。
问题归档
- 在小程序onHide,onUnload函数里调用
stop
方法无效;需要同时调用destroy
方法
this.innerAudioContext.stop();
this.innerAudioContext.destroy();
- 经测试发现中文中的大写英文字母无法识别,部分小写英文字母发音有误
参考
关注我
利用空闲时间免费兼职(无门槛,长期有效),请联系我(PS:关注公众号后,点击“联系我”获取联系方式)~