Are web audio API events running in a separate thread?

I'm especially interested in onaudioprocess ScriptProcessorNode (until recently called JavaScriptNode). This is an event listener that is periodically called to process sound. Is it running in a separate thread?

I want to transfer data to a circular buffer and process it outside of this callback so that I do not hang up the CPU. I can use web workers to handle async, but AFAIK I will need a different ring buffer implementation in case of different threads.

Is there any way to check this?

+6
source share
2 answers

All JavaScript are single-threaded, synchronously executed. Any asynchronous material is executed through events that add their handlers to the task queue - they are executed when the current task is completed.

To use individual threads, you need an environment such as WebWorkers β€” each thread has its own execution context (global scope) and task queue; communication between them is through events.

Since the onaudioprocess handler seems to live in the same area as the DOM, it is unlikely that it works in its own thread. If you really have a difficult computational task that makes your page inactive, you should use WebWorker, into which you feed sound events:

 myScriptProcessorNode.onaudioprocess = myWebWorker.postMessage; 
+5
source

With Bergi's solution, you will run into problems with a structured clone algorithm that is unable to copy read-only parameters to audioProcessingEvent. What you need to do is break up the parts you need from what you clone and pass them to your worker in another structure data as follows:

 _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, }); } 

You will also need to access the link to your OutputBuffer in setMessageHandler in order to copy the processed data back, in order to ultimately reproduce the user.

0
source

All Articles