1 Chrome自动播放音频报错,The AudioContext was not allowed to start. It must be resumed (or created)

1.1 问题

今天用js实现一个接收到服务器通知之后自动播放通知音频的功能,用的AudioContext播放音频,示例的音频播放代码如下

function server_notify()
{
    var audioContext = new AudioContext();
    let array_buffer = Base64Binary.decodeArrayBuffer(audio_base64_data);
    audioContext.decodeAudioData(array_buffer, function (buffer) {
        let audio_source = audioContext.createBufferSource();
        audio_source.buffer = buffer;
        audio_source.connect(audioContext.destination);
        audio_source.start(0);
       },function (e){
        console.error("decodeAudioData failed: "+ audio_base64_data);
   });
}

在本地Webstorm测试代码是正常的,可以自动播放声音,但是上线到测试服测试的时候出现了声音无法播放的问题,并输出了如下的错误

The AudioContext was not allowed to start. It must be resumed (or created) a ...

这主要是因为Chrome为了改善用户浏览体验,对音频自动播放的控制更加严格,不允许在没有用户交互下自动播放音频,具体的可看Google的官方文档:https://developer.chrome.com/blog/autoplay/#webaudio

1.2 解决方案

解决方案有很多种:

  • 添加一个按钮,在点击按钮中播放音频(不过这种方式就不是自动播放音频了)

或者可以通过这种方式

var constraints = { audio: true } // add video constraints if required

navigator.mediaDevices.getUserMedia(constraints)
.then((stream) => {
    var audioContext = new AudioContext();
    // ... rest of code
})

通过这种方式让AudioContext不进入挂起状态,并可自动播放音频。所以1.1节中的代码就修改为

function server_notify()
{
    var constraints = { audio: true }
    navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
         var audioContext = new AudioContext();
        let array_buffer = Base64Binary.decodeArrayBuffer(audio_base64_data);
        audioContext.decodeAudioData(array_buffer, function (buffer) {
            let audio_source = audioContext.createBufferSource();
            audio_source.buffer = buffer;
            audio_source.connect(audioContext.destination);
            audio_source.start(0);

           },function (e){
            console.error("decodeAudioData failed: "+ audio_base64_data);
       });
    })
}

修改为这种方式就可以自动播放音频了,并且控制台就不会报1.1节的错误了。

参考