diff --git a/site/source/docs/api_reference/wasm_audio_worklets.rst b/site/source/docs/api_reference/wasm_audio_worklets.rst index b7a24dc4f02df..2328e8fd1bda0 100644 --- a/site/source/docs/api_reference/wasm_audio_worklets.rst +++ b/site/source/docs/api_reference/wasm_audio_worklets.rst @@ -126,8 +126,7 @@ which resumes the audio context when the user clicks on the DOM Canvas element t "noise-generator", &options, &GenerateNoise, 0); // Connect it to audio context destination - EM_ASM({emscriptenGetAudioObject($0).connect(emscriptenGetAudioObject($1).destination)}, - wasmAudioWorklet, audioContext); + emscripten_audio_node_connect(wasmAudioWorklet, audioContext, 0, 0); // Resume context on mouse click emscripten_set_click_callback("canvas", (void*)audioContext, 0, OnCanvasClick); diff --git a/src/library_sigs.js b/src/library_sigs.js index d7e6a059b8822..e7de157534c83 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -587,6 +587,7 @@ sigs = { emscripten_atomic_wait_async__sig: 'ipippd', emscripten_atomics_is_lock_free__sig: 'ii', emscripten_audio_context_state__sig: 'ii', + emscripten_audio_node_connect__sig: 'viiii', emscripten_audio_worklet_post_function_sig__sig: 'vippp', emscripten_audio_worklet_post_function_v__sig: 'vip', emscripten_audio_worklet_post_function_vd__sig: 'vipd', diff --git a/src/library_webaudio.js b/src/library_webaudio.js index ad3db42b13b98..23a174e213347 100644 --- a/src/library_webaudio.js +++ b/src/library_webaudio.js @@ -293,6 +293,21 @@ let LibraryWebAudio = { }, #endif // ~AUDIO_WORKLET + emscripten_audio_node_connect: (source, destination, outputIndex, inputIndex) => { + var srcNode = EmAudio[source]; + var dstNode = EmAudio[destination]; +#if ASSERTIONS + assert(srcNode, `Called emscripten_audio_node_connect() with an invalid AudioNode handle ${source}`); + assert(srcNode instanceof window.AudioNode, `Called emscripten_audio_node_connect() on handle ${source} that is not an AudiotNode, but of type ${srcNode}`); + assert(dstNode, `Called emscripten_audio_node_connect() with an invalid AudioNode handle ${destination}!`); + assert(dstNode instanceof (window.AudioContext || window.webkitAudioContext) || dstNode instanceof window.AudioNode, `Called emscripten_audio_node_connect() on handle ${destination} that is not an AudioContext or AudioNode, but of type ${dstNode}`); +#endif +#if WEBAUDIO_DEBUG + console.log(`Connecting audio node ID ${source} to audio node ID ${destination} (${srcNode} to ${dstNode})`); +#endif + srcNode.connect(dstNode.destination || dstNode, outputIndex, inputIndex); + }, + emscripten_current_thread_is_audio_worklet: () => typeof AudioWorkletGlobalScope !== 'undefined', emscripten_audio_worklet_post_function_v: (audioContext, funcPtr) => { diff --git a/system/include/emscripten/webaudio.h b/system/include/emscripten/webaudio.h index a3261c47ac1d1..d3e3a5fe427e6 100644 --- a/system/include/emscripten/webaudio.h +++ b/system/include/emscripten/webaudio.h @@ -129,6 +129,10 @@ typedef struct EmscriptenAudioWorkletNodeCreateOptions // userData4: A custom userdata pointer to pass to the callback function. This value will be passed on to the call to the given EmscriptenWorkletNodeProcessCallback callback function. EMSCRIPTEN_AUDIO_WORKLET_NODE_T emscripten_create_wasm_audio_worklet_node(EMSCRIPTEN_WEBAUDIO_T audioContext, const char *name, const EmscriptenAudioWorkletNodeCreateOptions *options, EmscriptenWorkletNodeProcessCallback processCallback, void *userData4); +// Connects a node's output to a target, e.g., connect the worklet node to the context. +// For outputIndex and inputIndex, see the AudioNode.connect() documentation (setting 0 as the default values) +void emscripten_audio_node_connect(EMSCRIPTEN_WEBAUDIO_T source, EMSCRIPTEN_WEBAUDIO_T destination, int outputIndex, int inputIndex); + // Returns true if the current thread is executing a Wasm AudioWorklet, false otherwise. // Note that calling this function can be relatively slow as it incurs a Wasm->JS transition, // so avoid calling it in hot paths. diff --git a/test/webaudio/audio_worklet_tone_generator.c b/test/webaudio/audio_worklet_tone_generator.c index cfec0dc0ec879..90bc522ae66bf 100644 --- a/test/webaudio/audio_worklet_tone_generator.c +++ b/test/webaudio/audio_worklet_tone_generator.c @@ -82,17 +82,15 @@ void AudioWorkletProcessorCreated(EMSCRIPTEN_WEBAUDIO_T audioContext, bool succe // Instantiate the noise-generator Audio Worklet Processor. EMSCRIPTEN_AUDIO_WORKLET_NODE_T wasmAudioWorklet = emscripten_create_wasm_audio_worklet_node(audioContext, "tone-generator", &options, &ProcessAudio, 0); + // Connect the audio worklet node to the graph. + emscripten_audio_node_connect(wasmAudioWorklet, audioContext, 0, 0); EM_ASM({ - let audioContext = emscriptenGetAudioObject($0); - let audioWorkletNode = emscriptenGetAudioObject($1); - // Connect the audio worklet node to the graph. - audioWorkletNode.connect(audioContext.destination); - // Add a button on the page to toggle playback as a response to user click. let startButton = document.createElement('button'); startButton.innerHTML = 'Toggle playback'; document.body.appendChild(startButton); + let audioContext = emscriptenGetAudioObject($0); startButton.onclick = () => { if (audioContext.state != 'running') { audioContext.resume(); @@ -100,7 +98,7 @@ void AudioWorkletProcessorCreated(EMSCRIPTEN_WEBAUDIO_T audioContext, bool succe audioContext.suspend(); } }; - }, audioContext, wasmAudioWorklet); + }, audioContext); #ifdef REPORT_RESULT emscripten_set_timeout_loop(observe_test_end, 10, 0); diff --git a/test/webaudio/audioworklet.c b/test/webaudio/audioworklet.c index 9240063a8648c..9da333c67d716 100644 --- a/test/webaudio/audioworklet.c +++ b/test/webaudio/audioworklet.c @@ -47,17 +47,13 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, return true; } -EM_JS(void, InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext, EMSCRIPTEN_AUDIO_WORKLET_NODE_T audioWorkletNode), { - audioContext = emscriptenGetAudioObject(audioContext); - audioWorkletNode = emscriptenGetAudioObject(audioWorkletNode); - // Connect the audio worklet node to the graph. - audioWorkletNode.connect(audioContext.destination); - +EM_JS(void, InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext), { // Add a button on the page to toggle playback as a response to user click. let startButton = document.createElement('button'); startButton.innerHTML = 'Toggle playback'; document.body.appendChild(startButton); + audioContext = emscriptenGetAudioObject(audioContext); startButton.onclick = () => { if (audioContext.state != 'running') { audioContext.resume(); @@ -98,12 +94,14 @@ void AudioWorkletProcessorCreated(EMSCRIPTEN_WEBAUDIO_T audioContext, bool succe // Instantiate the noise-generator Audio Worklet Processor. EMSCRIPTEN_AUDIO_WORKLET_NODE_T wasmAudioWorklet = emscripten_create_wasm_audio_worklet_node(audioContext, "noise-generator", &options, &ProcessAudio, 0); + // Connect the audio worklet node to the graph. + emscripten_audio_node_connect(wasmAudioWorklet, audioContext, 0, 0); #ifdef REPORT_RESULT emscripten_set_timeout_loop(main_thread_tls_access, 10, 0); #endif - InitHtmlUi(audioContext, wasmAudioWorklet); + InitHtmlUi(audioContext); } // This callback will fire when the Wasm Module has been shared to the diff --git a/test/webaudio/audioworklet_emscripten_futex_wake.cpp b/test/webaudio/audioworklet_emscripten_futex_wake.cpp index 428d9168f4dd3..65d0c8dd60234 100644 --- a/test/webaudio/audioworklet_emscripten_futex_wake.cpp +++ b/test/webaudio/audioworklet_emscripten_futex_wake.cpp @@ -26,14 +26,12 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, return false; } -EM_JS(void, InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext, EMSCRIPTEN_AUDIO_WORKLET_NODE_T audioWorkletNode), { - audioContext = emscriptenGetAudioObject(audioContext); - audioWorkletNode = emscriptenGetAudioObject(audioWorkletNode); - audioWorkletNode.connect(audioContext.destination); +EM_JS(void, InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext), { let startButton = document.createElement('button'); startButton.innerHTML = 'Start playback'; document.body.appendChild(startButton); + audioContext = emscriptenGetAudioObject(audioContext); startButton.onclick = () => { audioContext.resume(); }; @@ -54,7 +52,8 @@ void AudioWorkletProcessorCreated(EMSCRIPTEN_WEBAUDIO_T audioContext, bool succe int outputChannelCounts[1] = { 1 }; EmscriptenAudioWorkletNodeCreateOptions options = { .numberOfInputs = 0, .numberOfOutputs = 1, .outputChannelCounts = outputChannelCounts }; EMSCRIPTEN_AUDIO_WORKLET_NODE_T wasmAudioWorklet = emscripten_create_wasm_audio_worklet_node(audioContext, "noise-generator", &options, &ProcessAudio, 0); - InitHtmlUi(audioContext, wasmAudioWorklet); + emscripten_audio_node_connect(wasmAudioWorklet, audioContext, 0, 0); + InitHtmlUi(audioContext); } void WebAudioWorkletThreadInitialized(EMSCRIPTEN_WEBAUDIO_T audioContext, bool success, void *userData) {