我对ScriptProcessorNode的onaudioprocess(直到最近称为JavaScriptNode)特别感兴趣。它是一个事件侦听器,定期调用以进行音频处理。它是否在单独的线程中运行?
我想将数据提供给循环缓冲区并在此回调之外处理它,这样我就不会占用 CPU。我可以使用网络工作者进行异步处理,但是在不同线程的情况下,我需要一个不同的环形缓冲区实现。
有没有办法测试这个?
我对ScriptProcessorNode的onaudioprocess(直到最近称为JavaScriptNode)特别感兴趣。它是一个事件侦听器,定期调用以进行音频处理。它是否在单独的线程中运行?
我想将数据提供给循环缓冲区并在此回调之外处理它,这样我就不会占用 CPU。我可以使用网络工作者进行异步处理,但是在不同线程的情况下,我需要一个不同的环形缓冲区实现。
有没有办法测试这个?
所有的 JavaScript 都是单线程的,同步执行的。任何异步操作都是通过事件完成的,这些事件将它们的处理程序添加到任务队列中——在当前任务完成时执行。
要使用单独的线程,您需要一个像 WebWorkers 这样的环境——每个线程都有自己的执行上下文(全局范围)和任务队列;它们之间的通信是通过事件完成的。
由于onaudioprocess
处理程序似乎与 DOM 位于同一范围内,因此它不太可能在自己的线程中运行。如果您确实有一个计算密集型任务导致您的页面无响应,您应该使用一个 WebWorker 来提供音频事件:
myScriptProcessorNode.onaudioprocess = myWebWorker.postMessage;
使用 Bergi 的解决方案,您将遇到结构化克隆算法无法复制 audioProcessingEvent 中的只读参数的问题。您需要做的是从可克隆的事件中分解出您需要的部分,并将它们以不同的数据结构传递给您的工作人员,如下所示:
_onAudioProcess(audioProcessingEvent) {
const {inputBuffer, outputBuffer} = audioProcessingEvent;
// The output buffer contains the samples that will be modified and
// eventually played, so we need to keep a reference to it.
this._outputBuffer = outputBuffer;
const numChannels = inputBuffer.numberOfChannels;
const inputChannels =
Array.from({length: numChannels}, (i) => {
return inputBuffer.getChannelData(i);
});
this._worker.postMessage({
command: 'DO_STUFF',
inputChannels: inputChannels,
});
}
您还需要访问 setMessageHandler 中对 outputBuffer 的引用,以便将处理后的数据复制回最终由用户播放。