无法在 Safari 中恢复 AudioContext

Rag*_*eth 7 safari web-audio-api

我遇到了一个问题,当尝试在 Safari 中播放音频时,调用永远无法解决resumeAudioContext我正在创建一个AudioContext页面加载,因此它以暂停状态启动。

根据此 chromium 问题resume如果浏览器的自动播放策略阻止,调用将无法解决。我有一个绑定到 a 的点击事件<button>,如果它被挂起,它将恢复上下文。这适用于 Firefox 和 Chrome,并且如果我更改网站的自动播放设置,也将适用于 Safari。

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

await context.resume();
Run Code Online (Sandbox Code Playgroud)

对于 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();
    });
}
Run Code Online (Sandbox Code Playgroud)

然而,什么都没有改变:Promise永远不会解决,这意味着上下文状态没有改变。

我错过了什么吗?

Rag*_*eth 6

我终于成功在 Safari 上播放音频了。

“修复”相当简单:我必须resume在绑定到用于启动播放的元素的事件处理程序中进行调用。在我的场景中,我将 Redux 与 React 结合使用,因此将进行调度,并稍后在另一个组件中恢复上下文。我猜测 Safari 并没有将其视为对用户交互事件的直接响应,因此它将上下文保持在挂起状态。


gri*_*rim 6

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

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

尝试这个:

onPlayHandler() {
   alert("State before: " + this.audioContext.state);
   await this.audioContext.resume();
   alert("State after: " + this.audioContext.state);
}
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢你做的这些。在过去的几天里,我一直在阅读 **Web Audio API** 并尝试(带着不小的挫败感)解决 iOS Safari 和其他所有浏览器之间的不一致问题。当我了解到“new AudioContext()”的重要性时,我取得了一些进展 - 但真正缺少的部分是,对于 iOS Safari,我们需要显式地将“audioContext.state”从“挂起”设置为“运行” ` 通过:`const audioContext = new AudioContext(); audioContext.resume();` 只有这样,Safari 才会像其他浏览器一样运行。 (2认同)