Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AUDIO_WORKLET] Add new emscripten_audio_node_connect API #22667

Merged
merged 4 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions site/source/docs/api_reference/wasm_audio_worklets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/library_sigs.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
15 changes: 15 additions & 0 deletions src/library_webaudio.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
4 changes: 4 additions & 0 deletions system/include/emscripten/webaudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
10 changes: 4 additions & 6 deletions test/webaudio/audio_worklet_tone_generator.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,25 +82,23 @@ 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();
} else {
audioContext.suspend();
}
};
}, audioContext, wasmAudioWorklet);
}, audioContext);

#ifdef REPORT_RESULT
emscripten_set_timeout_loop(observe_test_end, 10, 0);
Expand Down
12 changes: 5 additions & 7 deletions test/webaudio/audioworklet.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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
Expand Down
9 changes: 4 additions & 5 deletions test/webaudio/audioworklet_emscripten_futex_wake.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
};
Expand All @@ -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) {
Expand Down
Loading