评论

BackgroundAudioManager.onEnded不被调用的兼容方案

BackgroundAudioManager.onEnded在单向播报时的兼容方案

业务场景:

小程序在后台运行着,接收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')
最后一次编辑于  08-08  
点赞 0
收藏
评论

2 个评论

  • 林俊宇
    林俊宇
    08-09

    太强了

    08-09
    赞同 2
    回复
  • 江上舟明
    江上舟明
    09-14

    到现在依然有这个问题 感谢楼主分享的方法

    09-14
    赞同
    回复
登录 后发表内容