【问题标题】:Cannot resume AudioContext in Safari无法在 Safari 中恢复 AudioContext
【发布时间】:2019-12-21 22:33:00
【问题描述】:

我遇到了一个问题:尝试在 Safari 中播放音频时,在 AudioContext 上调用 resume 永远无法解决。我在页面加载时创建了一个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 永远不会解析,这意味着上下文状态没有改变。

我错过了什么吗?

【问题讨论】:

  • 今天遇到了同样的问题。承诺从未解决
  • 我不确定为什么 resume() 返回的承诺永远不会解决,但您的解决方法永远不会解决,因为它检查了错误的值。当上下文成功恢复时,state 将是 'running'。它也是一个不需要等待的常规属性。第四行将是if (this.context.state === "running") {

标签: safari web-audio-api


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

    试试这个:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-07
      • 2015-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多