我又双叒叕来了,自己写的bug,跪着也要改完,我是真的服了
-
首先,我们来说说是什么问题吧
-
- 上一篇文章的这张图还记得吧,不记得的,我在下面贴出来了;
-
- 我们在长度大于300的时候,根据句号或者逗号进行了切片,然后将这些片段转换成若干个短语音,通过遍历来进行完整播放(不记得的看上一篇吧);
-
- 图中的1和2都是根据句号来切成几个小片段;
-
- 在1正在播放时,切换到2进行播放,等2播放完成了之后,图标会从红色变成绿色,但是语音会接着1暂停的时机继续播放;
-
原因呢?其实我也不确定,我稍微思考了几个可能得原因
-
- 可能是我写的遍历播放的方法有问题?
-
- 或者是因为我在切换的时候写的是pause(),暂停的方法
-
- 又或者是,wx.createInnerAudioContext()实例里面已经缓存了之前的语音地址
-
- 反正我不确定,但是问题我解决了(鼓掌吧,兄弟们)
解决方式
在切换图中1和2时,直接把实例清掉,然后再重新注册一个实例,简单且粗暴(我另外又偷偷的进行了一项优化)
js
// 我在page外定义了两个全局属性,注意:这是写在page外的哈
let radioId = 0 // 存储当前播放id
let radioOldList = [] // 存储当前正在播放的语音列表
// 在onLoad里面进行实例化
this.innerAudioContext = wx.createInnerAudioContext();
// 阅读文字,页面上的点击图标
readText: async function (e) {
const { item } = e.currentTarget.dataset
const that = this;
// 判断当前id和上一次存储的id是不是相同
if (item.id == radioId) {
// 相同就调用pause()暂停方法,再次点击会接着之前暂停处播放
that.innerAudioContext.pause()
} else {
// 不相同就调用stop()停止方法
that.innerAudioContext.stop()
// 同时将实例清除
that.innerAudioContext = null
// 重新创建一个实例
that.innerAudioContext = wx.createInnerAudioContext()
}
that.data.questionList.forEach(el => {
if (el.id == item.id) {
el.type = 'pause'
} else {
el.type = 'play'
}
});
that.setData({
questionList: that.data.questionList,
playItem: item
})
// 当前id和上一次存储的id相同时,跳过语音转换步骤,直接使用之前的存储的语音列表
if (item.id == radioId) {
that.readStart(radioOldList, item.id)
return
}
let list = splitStringByLength(item.audiodialogue, 300)
let radioList = list.map(el => {
return new Promise(resolve => {
plugin.textToSpeech({
lang: "zh_CN",
tts: true,
content: el,
success: function (res) {
resolve(res.filename)
},
fail: function (res) {
wx.showToast({
title: '语音转换失败',
})
}
})
})
})
Promise.all(radioList).then(res => {
that.readStart(res, item.id)
})
},
// 开始阅读
readStart: async function (radioList, id) {
const that = this
// 将当前播放的语音列表存储起来
radioOldList = radioList
for (let text of radioList) {
this.innerAudioContext.src = text;
this.innerAudioContext.onPlay(() => {
console.log('开始播放当前片段', 'onPlay');
});
this.innerAudioContext.onError((err) => {
console.error('音频播放出错', err);
});
this.innerAudioContext.onEnded(async () => {
// 如果是最后一个片段,这里可以结束,否则不需要await
if (text === radioList[radioList.length - 1]) {
that.data.questionList.forEach(el => {
if (el.id == id) {
el.type = 'play'
}
})
that.setData({
questionList: that.data.questionList,
})
that.innerAudioContext.stop()
return
}
});
// 将当前播放的id存储起来
radioId = id
// 确保前一个音频播放结束后再播放下一个
await new Promise(resolve => {
this.innerAudioContext.onEnded(resolve);
this.innerAudioContext.play();
});
}
},
关键代码:
-
存储上一次的播放id和播放列表
-
readText方法内,判断当前播放的id是否和存储的相同,相同就跳过语音转换步骤
-
如果不相同,先停止当前的播放并清除实例后,重新创建实例