【问题标题】:does the web audio api clear out a source node after it finishes playing?网络音频 api 播放完成后是否清除源节点?
【发布时间】:2019-03-17 14:05:44
【问题描述】:

当用户点击一个按钮时,就会播放一个声音,如果他再次点击它,就会播放一个相同声音的新实例。

我通过在每次点击时将一个新的源节点连接到音频上下文来做到这一点。

现在说用户单击按钮 1 小时,是否每个已完成播放的源节点都被删除或保持连接到音频上下文?

【问题讨论】:

  • 在您的浏览器上点击 cntrl+shift+i 以显示开发工具 --> 网络 -> 执行您的点击并观察流量 --- 然后您就具备了回答这个问题并将您置于通往其他问题的大道

标签: javascript audio audiocontext audio-source


【解决方案1】:

这里是relevant specs

以下行为提供了 AudioNode 处于活动状态的条件的规范描述,这意味着它必须由实现保留在图中。在这些条件不适用的情况下,AudioNodes 可以由实现释放。

有几种类型的引用:

  1. 遵循正常垃圾收集规则的正常引用。

  2. AudioBufferSourceNodes、MediaElementAudioSourceNodes、MediaStreamAudioSourceNodes 和 OscillatorNodes 的播放参考。这些节点在当前播放时保持对自己的播放引用。

  3. 当另一个 AudioNode 连接到它的一个或多个输入时发生的连接引用。与节点的 AudioParam 的连接并不意味着连接引用。

  4. AudioNode 维护自身的尾部时间引用,只要它有任何尚未发出的内部处理状态。例如,ConvolverNode 有一个尾巴,即使在接收到无声输入后仍会继续播放(想想在大型音乐厅拍手并继续听到整个大厅回响的声音)。一些 AudioNodes 有这个属性。请查看具体节点的详细信息。

  5. 只要通过 MediaStreamAudioSourceNode 播放的底层 MediaStreamTrack 尚未结束(根据 [mediacapture-streams]),MediaStreams 就会使 MediaStreamAudioSourceNode 保持活动状态。

  6. 只要 HTMLMediaElement 处于将来可以播放音频的状态,HTMLMediaElements 就会保持其关联的 MediaElementAudioSourceNode 处于活动状态。

因此,例如,一个 AudioBufferSourceNode,因为它没有输入 (3),没有 tail-time(4),所以没有链接到外部 MediaStream(5) 或 MediaElement(6),如果您的 js 代码中没有保留对节点的任何引用(1),并且该节点已播放完毕(2),则可以将其从图中删除,然后是垃圾收集。


还要注意,大多数节点的指纹都很少。

如果我们再次以 AudioBufferSourceNodes 为例,那么您必须了解它们不会复制 AudioBuffer,它们只是引用它。
因此,从同一个 AudioBuffer 创建数千个 AudioBufferSourceNodes 就可以了。

然而,从同一个 ArrayBuffer 中创建数千个 AudioBuffers,或从同一个文件中创建数千个 ArrayBuffers,或者两者兼而有之,这根本不合适,所以请确保当您处理点击事件时,您所做的只是从预先存在的 AudioBuffer 创建一个新的 AudioBufferSourceNode

【讨论】:

  • 我现在正在做的只是调用一个play(buffer) 函数,该函数创建一个引用了 Audiobuffer 的源节点,然后将其连接到上下文。所以如果我理解正确,因为源节点没有在任何地方被引用,它会被垃圾收集,因为它在代码中的任何地方都没有引用,对吧?
  • 是的,没错。一旦它完成播放。
  • 如何创建多个音频上下文?这是一个坏习惯吗?我需要使用两个。
  • 是的,AudioContexts 与硬件几乎没有联系,所以最好避免同时拥有太多,一些浏览器甚至对你可以拥有的同时上下文的数量设置了限制。但我想不出为什么你自己的代码中需要多个上下文。
  • 我正在尝试通过做鼓机来练习网络音频 API。所以我的问题是,如果用户选择了一些以前录制的曲目,然后同时播放它们,他仍然可以使用打击垫,当他暂停这些相同的曲目时也是如此。经过一番研究,我完成了使用两个音频上下文的想法,一个用于打击垫,一个用于录制的轨道,因此我可以通过调用 tracksContext.suspend()tracksContext.resume()tracksContext.close() 来单独暂停它们以关闭上下文没有曲目正在播放。
【解决方案2】:

如果 BufferSourceNode 仍然连接到音频上下文,它不会被删除。您可以通过使用 Firefox Web Audio 开发工具或安装 Audion Chrome 扩展来检查这一点。

您可以在 BufferSourceNode 中添加onended 函数,以便在使用后断开连接。然后,只要没有其他东西引用该缓冲区源节点,它就会被垃圾收集器清理掉。

来源:https://developer.mozilla.org/en-US/docs/Web/API/AudioScheduledSourceNode/onended

【讨论】:

  • 我们在连接上没有反向引用的真正原因是允许节点在我们完成它们后被垃圾收集。如果他们不是,我会感到非常惊讶。也许你应该责怪你的开发工具/扩展保持对这些节点的引用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-02-21
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多