无法创建'AudioContext': 硬件上下文数量已达到最大值

21

我创建了一个 AudioContext 后,有没有办法将其删除?

var analyzers = [];
var contexts = [];

try {
   for(var i = 0; i<20; i++) {
      contexts[i] = new AudioContext();
      analyzers[i] = contexts[i].createAnalyser();
   }
}catch(e) {
   console.log(e);
   // too many contexts created -- how do I remove them?
}

我尝试过这个方法,但它不允许我在之后创建新的上下文:analyzers.forEach(function(analyzer){analyzer.disconnect(analyzer.context.destination)})

我正在使用Ubuntu Linux 14.04上的Chrome 36。

5个回答

36

3
你猜对了,朱利安!在我的React组件卸载时,我开始调用创建的音频上下文实例上的close()方法,这解决了AudioContext创建错误。谢谢! - Moonwalker
还有AudioContext.suspend()。大约4年前我非常需要这个功能。不过很高兴看到它的改进。 - Nek
@Julian 有没有办法检查页面中打开了多少个audioContext?还是我必须手动跟踪它们? - Simone Mazzoni
这应该是答案。 Julian 是真正的 MVP。 - Jack G
不要关闭它太快,否则它将无法按时播放。setTimeout(() => { context.close();}, 400); - weiya ou

19

在页面中,您应该只有一个AudioContext

根据文档:“在大多数情况下,每个文档只使用一个AudioContext。”

我真的想不出为什么你会需要多个。除非您遇到了导致您创建多个上下文的特定问题?


2
不,没有办法销毁 AudioContext。如果没有其他东西包含对它们的引用,它们可能会被垃圾回收,但我不确定是否是这种情况。 - Kevin Ennis
1
在大多数常见的用例中,您希望所有节点都在相同的上下文中运行,以便在需要时可以进行同步。至于强制进行AudioConext的GC,您无法确切知道何时会进行垃圾回收。因此,将其设置为null可以确保它在某个时间点被垃圾回收,但您永远不知道确切的时间。 - notthetup
我想我不太明白你的意思。我需要看一些代码来对比你使用单个上下文的方法和你想要使用多个上下文的方式。 - Kevin Ennis
2
请注意,音频上下文的总数是每个浏览器实例而不是每个窗口。如果其他已打开的站点已经耗尽了可用池,则可能会遇到问题。没有真正的解决方法,但您至少应该将音频上下文初始化包装在try/catch中,并为错误情况提供一些UI。 - Nek
拥有新的音频上下文的一个好理由是为了改变采样率。如果我们从音频设备中捕获,我们需要匹配它的采样率。如果我们更换设备,采样率可能会改变。 - Brad
显示剩余5条评论

8

首先,将其赋值给一个变量,如:
var myAudioCtx = new AudioContext();
然后调用下面的代码销毁它
myAudioCtx.close();
就这样。


1
我正在制作一个媒体播放器小部件,但在Chrome上(但不是Firefox)一旦在单个页面中嵌入了五个以上的小部件,它就会出现问题。
我发现可以创建一个单独的AudioContext并将其全局存储,然后每个实例只需使用共享的AudioContext。它似乎没有任何不同 - 您可以附加多个缓冲区和多个目标,所有音频都会混合在一起。
如果您将其用于定时,则可能需要更多的工作,但对于使用JS代码即时生成的一个或多个音频流的播放,共享单个AudioContext就可以正常工作。

0

在每次点击之前关闭它。如果使用计时器延迟关闭,会出现不完整播放的异常,特别是在切换文件时。

const audioPlay = (() => {
  let context = null;
  return async () => {
    if (context) context.close();
    context = new AudioContext();
    const source = context.createBufferSource();
    source.buffer = await fetch('./2.mp3')
      .then(res => res.arrayBuffer())
      .then(arrayBuffer => context.decodeAudioData(arrayBuffer));
    source.connect(context.destination);
    source.start();
  };
})();

document.querySelector('#add').addEventListener('click', audioPlay);

不建议使用

 setTimeout(() => { context.close();}, 400);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接