业务场景:
小程序在后台运行着,接收websocket通讯,然后播报后台发来的文本。
遇到的问题:
小程序在后台通过BackgroundAudioManager播报时,会播报三次,然后报资源错误。
代码里监听了onEnded时间,用于停止播报,在微信开发者工具中可以正常执行,但是在android、ios小程序里,前台、后台情况下都无法正确执行。
下面是示例代码
const bgAudioManager = uni.getBackgroundAudioManager();
bgAudioManager.title = title;
const url = '***.mp3'
bgAudioManager.singer = '暂无';
bgAudioManager.onPlay(async(...args) => {
console.log('onPlay_args :>> ', args)
})
bgAudioManager.onEnded((...args) => {
console.log('onEnded_args :>> ', args);
bgAudioManager.stop(); // 此处代码在android,ios上无法执行
});
bgAudioManager.onStop((...args) => {
console.log('onStop_args :>> ', args)
});
bgAudioManager.onError((args: any) => {
console.log('onError_args :>> ', args);
})
bgAudioManager.src = url;
解决方案:
思路:
语音播报时,会触发onPlay
钩子,在onPlay
中添加定时器,自动关闭语音。
const palyInterval = 10000; // 定时时间
bgAudioManage.onPlay((...args)=>{
setTimeout(()=>{
bgAudioManager.stop()
}, palyInterval)
})
以上代码可以正确执行。^_^ ^_^
接下来让我们解决这个"完美时间"问题。
前提:我们的语音播报是不让用户操作的,所以这个时间就是mp3文件的播放时间。
我用的是 wx.createWebAudioContext() api,将mp3文件转为ArrayBuffer,然后拿到时间
export const resolveAudioUrl = (url: string): Promise<WebAudioBuffer> => {
return new Promise((resolve, reject) => {
uni.request({
url: url, // 音频 url
responseType: 'arraybuffer',
success: res => {
const audioContext = uni.createWebAudioContext()
const _audioArrayBuffer = res.data as unknown as ArrayBuffer;
audioContext.decodeAudioData(_audioArrayBuffer , (buffer: WebAudioBuffer) => {
resolve(buffer)
}, (err: any) => {
reject(err)
console.error('decodeAudioData fail', err)
})
}
})
})
}
resolve的buffer的duration
属性能够拿到mp3的时长。
所以完整代码如下
export const sleep = (time=200) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(0);
}, time)
})
}
/**
*
* @param title 音频标题
* @param url 音频资源内容
*/
export const playAudioBackground = async (title: string='', url: string) => {
const bgAudioManager = uni.getBackgroundAudioManager();
bgAudioManager.title = title;
bgAudioManager.singer = '暂无';
const {duration} = await resolveAudioUrl(url) // 解析音频时长
bgAudioManager.onPlay(async(...args) => {
console.log('onPlay');
await sleep(duration * 1000)
bgAudioManager.stop();
})
bgAudioManager.onEnded(async (...args) => {
console.log('onEnded_args :>> ', args);
bgAudioManager.stop();
});
bgAudioManager.onStop((...args) => {
console.log('onStop_args :>> ', args)
});
(bgAudioManager as any).onError((args: any) => {
console.log('onError_args :>> ', args);
})
bgAudioManager.src = url;
}
/**
* @description 解析音频url,获取音频时长
* @param url 音频资源内容url
* @returns WebAudioBuffer
*/
export const resolveAudioUrl = (url: string): Promise<WebAudioBuffer> => {
return new Promise((resolve, reject) => {
uni.request({
url: url, // 音频 url
responseType: 'arraybuffer',
success: res => {
const audioContext = uni.createWebAudioContext()
const _audioArrayBuffer = res.data as unknown as ArrayBuffer;
audioContext.decodeAudioData(_audioArrayBuffer , (buffer: WebAudioBuffer) => {
resolve(buffer)
}, (err: any) => {
reject(err)
console.error('decodeAudioData fail', err)
})
}
})
})
}
// 测试
playAudioBackground('标题', '**.mp3')
太强了
到现在依然有这个问题 感谢楼主分享的方法