我遇到了一个问题:尝试在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
从未解决,这意味着上下文状态没有改变。
我想念什么吗?
答案 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);
}