无法在Safari中恢复AudioContext

时间:2019-08-15 13:29:59

标签: safari web-audio-api

我遇到了一个问题:尝试在Safari中播放音频时,在resume上调用AudioContext无法解决。我正在页面加载时创建AudioContext,因此它以挂起状态开始。

According to this chromium issue,如果被浏览器的自动播放策略阻止,则调用resume无法解决。我有一个绑定到<button>的点击事件,如果该事件被挂起,它将恢复上下文。 如果我更改了网站的自动播放设置,则该功能在Firefox和Chrome中都可以使用,并且在Safari中也可以使用。

下面是我通常如何恢复上下文:

await context.resume();

对于Safari,我尝试了不等待承诺解决就调用resume,而是为onstatechange注册了一个回调,然后将其包装在Promise中:

if (window.webkitAudioContext) {
    await new Promise((accept, reject) => {
        this.context.onstatechange = async () => {
            if ((await this.context.state) === "playing") {
                accept();
            } else {
                reject();
            }
         };

        this.context.resume();
    });
}

但是,什么都没有改变:Promise从未解决,这意味着上下文状态没有改变。

我想念什么吗?

2 个答案:

答案 0 :(得分:0)

我终于设法在Safari上播放音频。

“修复”非常简单:我必须在事件处理程序中调用 <span id="price">$100</span> <scrit> document.getElementById("price").innerHTML = "$300"; </script> ,该事件处理程序绑定到用于启动播放的元素。在我的场景中,我将Redux与React一起使用,因此将进行分派,并在以后的另一个组件内恢复上下文。我猜想Safari不会将其视为对用户交互事件的直接响应,因此它将上下文保持在挂起状态。

答案 1 :(得分:0)

只有在 UI 事件处理程序的调用堆栈中运行时,iOS 才会允许恢复 audioContext。在 Promise 中运行它会将调用移动到另一个调用堆栈。

此外,audioContext.resume() 返回一个必须等​​待的承诺。

试试这个:

onPlayHandler() {
   alert("State before: " + this.audioContext.state);
   await this.audioContext.resume();
   alert("State after: " + this.audioContext.state);
}