背景:
在使用微信官方语音合成插件的时候遇到一个问题,textToSpeech这个api的内容限制在官网的文档上明明是1000个字节,也就是说能保证333个中文字符应该是没有问题的,但是也不知道为什么我这里仅仅传了150个中文字符就报错了,报错内容返回{“retcode”:-20003,“msg”:“text to speech inner server failed.”},查了一下是因为内容过长导致的错误。
解决办法:
事实与文档说明完全不符,这个没办法解决,就想了一个分割内容分段合成的办法,但是分段吧就会有一个问题,那就是如果每段文字合成语音后,播放,然后再合成,在播放,就会出现明显的停顿,一点都不丝滑,很难受,为了解决这个问题,想了一个预加载的办法,也就是预先合成一段段的音频文件,然后将这些音频文件存到一个数组里面,通过shift函数每次从数组取出一个这样就实现了不管多少文字内容,都能够非常丝滑的合成语音文件。
代码:
data() {
return {
showAudioModal: false,
textAyy: [],
audioAyy: [],
content: '超长的文本'
};
},
onLoad(e) {
this.audioContext = uni.createInnerAudioContext();
this.audioContext.onEnded(() => {
if(this.audioAyy && this.audioAyy.length > 0){
this.audioContext.src = this.audioAyy.shift()
this.audioContext.play()
}else{
this.showAudioModal = false
}
})
},
methods: {
async textToSpeech(){
this.audioAyy = []
this.textAyy = this.splitStringByLength(this.content,100,100)
let flag = true
for (var i = 0,len = this.textAyy.length; i < len; i++) {
if(i === 0){
uni.showLoading({
title: '语音加载中',
mask: true
})
}
await this.callTextToSpeech(this.textAyy[i]).then(res => {
console.log(i)
this.showAudioModal = true
if(flag){
this.audioContext.src = res;
this.audioContext.play();
flag = false
}else{
this.audioAyy.push(res)
}
uni.hideLoading()
}).catch(() => {
})
}
if(flag){
uni.hideLoading()
uni.showToast({
title:'语音合成失败'
})
}
},
callTextToSpeech(content){
return new Promise((resolve,reject) => {
this.$wcs.textToSpeech({
lang: "zh_CN",
tts: true,
content,
success: (res) => {
console.log("succ tts", res.filename)
resolve(res.filename)
},
fail: function(res) {
console.log("fail tts", res)
reject()
}
})
})
},
splitStringByLength(str, maxSize, chunkSize) {
const totalLength = str.length;
if (totalLength <= maxSize) {
return [str];
}
const chunks = [];
let start = 0;
while (start < totalLength) {
let end = Math.min(start + chunkSize, totalLength);
const chunk = str.substring(start, end);
chunks.push(chunk);
start = end;
}
return chunks;
},
}
大致逻辑
通过async和await保证语音合成的有序性,第一段成功的语音直接播放,后续的放入数组,等音频播放结束事件触发后,自动从数组中获取资源,这样一来就实现了预合成的效果,达到了非常丝滑的效果