From ca6e6c866b250dac68d25c0d75d241afe6b42284 Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Mon, 15 Sep 2025 15:23:26 +0200 Subject: [PATCH 01/22] Add a waiting state Also fix erroneous looking switch fall-through. --- test/webaudio/audioworklet_emscripten_locks.c | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/test/webaudio/audioworklet_emscripten_locks.c b/test/webaudio/audioworklet_emscripten_locks.c index 20471eced5f63..7482f0bab7ff5 100644 --- a/test/webaudio/audioworklet_emscripten_locks.c +++ b/test/webaudio/audioworklet_emscripten_locks.c @@ -17,6 +17,8 @@ int _emscripten_thread_supports_atomics_wait(void); typedef enum { + // The test hasn't yet started + TEST_NOT_STARTED, // No wait support in audio worklets TEST_HAS_WAIT, // Acquired in main, fail in process @@ -40,26 +42,17 @@ typedef enum { // Lock used in all the tests emscripten_lock_t testLock = EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER; // Which test is running (sometimes in the worklet, sometimes in the main thread) -_Atomic Test whichTest = TEST_HAS_WAIT; +_Atomic Test whichTest = TEST_NOT_STARTED; // Time at which the test starts taken in main() double startTime = 0; bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, AudioSampleFrame *outputs, int numParams, const AudioParamFrame *params, void *userData) { assert(emscripten_current_thread_is_audio_worklet()); - // Produce at few empty frames of audio before we start trying to interact - // with the with main thread. - // On chrome at least it appears the main thread completely blocks until - // a few frames have been produced. This means it may not be safe to interact - // with the main thread during initial frames? - // In my experiments it seems like 5 was the magic number that I needed to - // produce before the main thread could continue to run. - // See https://github.com/emscripten-core/emscripten/issues/24213 - static int count = 0; - if (count++ < 5) return true; - int result = 0; switch (whichTest) { + case TEST_NOT_STARTED: + break; case TEST_HAS_WAIT: // Should not have wait support here result = _emscripten_thread_supports_atomics_wait(); @@ -80,6 +73,7 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, emscripten_outf("TEST_WAIT_ACQUIRE_FAIL: %d (expect: 0)", result); assert(!result); whichTest = TEST_WAIT_ACQUIRE; + break; case TEST_WAIT_ACQUIRE: // Will get unlocked in main thread, so should quickly acquire result = emscripten_lock_busyspin_wait_acquire(&testLock, 10000); @@ -130,6 +124,10 @@ bool MainLoop(double time, void* data) { assert(!emscripten_current_thread_is_audio_worklet()); static int didUnlock = false; switch (whichTest) { + case TEST_NOT_STARTED: + emscripten_out("Staring test (may need a button click)"); + whichTest = TEST_HAS_WAIT; + break; case TEST_WAIT_ACQUIRE: if (!didUnlock) { emscripten_out("main thread releasing lock"); @@ -178,9 +176,9 @@ int main() { startTime = emscripten_get_now(); - emscripten_set_timeout_loop(MainLoop, 10, NULL); EMSCRIPTEN_WEBAUDIO_T context = emscripten_create_audio_context(NULL); emscripten_start_wasm_audio_worklet_thread_async(context, wasmAudioWorkletStack, sizeof(wasmAudioWorkletStack), WebAudioWorkletThreadInitialized, NULL); + emscripten_set_timeout_loop(MainLoop, 10, NULL); emscripten_exit_with_live_runtime(); } From 569db6dc5c5c07bb6dff573c224bd6c58b2dca30 Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Mon, 15 Sep 2025 18:11:20 +0200 Subject: [PATCH 02/22] Move work off the main thread --- test/webaudio/audioworklet_emscripten_locks.c | 74 +++++++++++-------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/test/webaudio/audioworklet_emscripten_locks.c b/test/webaudio/audioworklet_emscripten_locks.c index 7482f0bab7ff5..fe84eb0fdfac7 100644 --- a/test/webaudio/audioworklet_emscripten_locks.c +++ b/test/webaudio/audioworklet_emscripten_locks.c @@ -46,6 +46,12 @@ _Atomic Test whichTest = TEST_NOT_STARTED; // Time at which the test starts taken in main() double startTime = 0; +void do_exit() { + emscripten_out("Test success"); + emscripten_terminate_all_wasm_workers(); + emscripten_force_exit(0); +} + bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, AudioSampleFrame *outputs, int numParams, const AudioParamFrame *params, void *userData) { assert(emscripten_current_thread_is_audio_worklet()); @@ -120,37 +126,39 @@ EM_JS(void, InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext), { }; }); -bool MainLoop(double time, void* data) { +void WorkerLoop() { assert(!emscripten_current_thread_is_audio_worklet()); - static int didUnlock = false; - switch (whichTest) { - case TEST_NOT_STARTED: - emscripten_out("Staring test (may need a button click)"); - whichTest = TEST_HAS_WAIT; - break; - case TEST_WAIT_ACQUIRE: - if (!didUnlock) { - emscripten_out("main thread releasing lock"); - // Release here to acquire in process - emscripten_lock_release(&testLock); - didUnlock = true; - } - break; - case TEST_WAIT_INFINTE_1: - // Spin here until released in process (but don't change test until we know this case ran) - whichTest = TEST_WAIT_INFINTE_2; - emscripten_lock_busyspin_waitinf_acquire(&testLock); - emscripten_out("TEST_WAIT_INFINTE (from main)"); - break; - case TEST_DONE: - // Finished, exit from the main thread - emscripten_out("Test success"); - emscripten_force_exit(0); - return false; - default: - break; + int didUnlock = false; + while (true) { + switch (whichTest) { + case TEST_NOT_STARTED: + emscripten_out("Staring test (may need a button click)"); + whichTest = TEST_HAS_WAIT; + break; + case TEST_WAIT_ACQUIRE: + if (!didUnlock) { + emscripten_out("main thread releasing lock"); + // Release here to acquire in process + emscripten_lock_release(&testLock); + didUnlock = true; + } + break; + case TEST_WAIT_INFINTE_1: + // Spin here until released in process (but don't change test until we know this case ran) + whichTest = TEST_WAIT_INFINTE_2; + emscripten_lock_busyspin_waitinf_acquire(&testLock); + emscripten_out("TEST_WAIT_INFINTE (from main)"); + break; + case TEST_DONE: + // Finished, exit from the main thread (and return out of this loop) + emscripten_wasm_worker_post_function_v(EMSCRIPTEN_WASM_WORKER_ID_PARENT, &do_exit); + return; + default: + break; + } + // Repeat every 16ms (except when TEST_DONE) + emscripten_wasm_worker_sleep(16 * 1000000ULL); } - return true; } void AudioWorkletProcessorCreated(EMSCRIPTEN_WEBAUDIO_T audioContext, bool success, void *userData) { @@ -169,16 +177,20 @@ void WebAudioWorkletThreadInitialized(EMSCRIPTEN_WEBAUDIO_T audioContext, bool s uint8_t wasmAudioWorkletStack[2048]; int main() { - // Main thread init and acquire (work passes to the processor) + // Main thread init and acquire (work passes to the audio processor) emscripten_lock_init(&testLock); int hasLock = emscripten_lock_busyspin_wait_acquire(&testLock, 0); assert(hasLock); startTime = emscripten_get_now(); + // Audio processor callback setup EMSCRIPTEN_WEBAUDIO_T context = emscripten_create_audio_context(NULL); emscripten_start_wasm_audio_worklet_thread_async(context, wasmAudioWorkletStack, sizeof(wasmAudioWorkletStack), WebAudioWorkletThreadInitialized, NULL); - emscripten_set_timeout_loop(MainLoop, 10, NULL); + + // Worker thread setup + emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(1024); + emscripten_wasm_worker_post_function_v(worker, WorkerLoop); emscripten_exit_with_live_runtime(); } From 1db640d9bf2f375d03e9c23e85f47aa6e8ec90ef Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Mon, 15 Sep 2025 18:13:55 +0200 Subject: [PATCH 03/22] Updated docs --- test/webaudio/audioworklet_emscripten_locks.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/webaudio/audioworklet_emscripten_locks.c b/test/webaudio/audioworklet_emscripten_locks.c index fe84eb0fdfac7..6fa6a0ccc9832 100644 --- a/test/webaudio/audioworklet_emscripten_locks.c +++ b/test/webaudio/audioworklet_emscripten_locks.c @@ -41,7 +41,7 @@ typedef enum { // Lock used in all the tests emscripten_lock_t testLock = EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER; -// Which test is running (sometimes in the worklet, sometimes in the main thread) +// Which test is running (sometimes in the worklet, sometimes in the worker) _Atomic Test whichTest = TEST_NOT_STARTED; // Time at which the test starts taken in main() double startTime = 0; @@ -81,7 +81,7 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, whichTest = TEST_WAIT_ACQUIRE; break; case TEST_WAIT_ACQUIRE: - // Will get unlocked in main thread, so should quickly acquire + // Will get unlocked in worker, so should quickly acquire result = emscripten_lock_busyspin_wait_acquire(&testLock, 10000); emscripten_outf("TEST_WAIT_ACQUIRE: %d (expect: 1)", result); assert(result); @@ -96,7 +96,7 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, whichTest = TEST_WAIT_INFINTE_1; break; case TEST_WAIT_INFINTE_1: - // Still locked when we enter here but move on in the main thread + // Still locked when we enter here but move on in the worker break; case TEST_WAIT_INFINTE_2: emscripten_lock_release(&testLock); @@ -137,7 +137,7 @@ void WorkerLoop() { break; case TEST_WAIT_ACQUIRE: if (!didUnlock) { - emscripten_out("main thread releasing lock"); + emscripten_out("Worker releasing lock"); // Release here to acquire in process emscripten_lock_release(&testLock); didUnlock = true; @@ -147,7 +147,7 @@ void WorkerLoop() { // Spin here until released in process (but don't change test until we know this case ran) whichTest = TEST_WAIT_INFINTE_2; emscripten_lock_busyspin_waitinf_acquire(&testLock); - emscripten_out("TEST_WAIT_INFINTE (from main)"); + emscripten_out("TEST_WAIT_INFINTE (from worker)"); break; case TEST_DONE: // Finished, exit from the main thread (and return out of this loop) From d347a766e018b640b74bd01f4b7bd8a099e690b8 Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Mon, 15 Sep 2025 19:16:32 +0200 Subject: [PATCH 04/22] Something to re-run the CI --- test/webaudio/audioworklet_emscripten_locks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/webaudio/audioworklet_emscripten_locks.c b/test/webaudio/audioworklet_emscripten_locks.c index 6fa6a0ccc9832..bd71bd302c917 100644 --- a/test/webaudio/audioworklet_emscripten_locks.c +++ b/test/webaudio/audioworklet_emscripten_locks.c @@ -19,7 +19,7 @@ int _emscripten_thread_supports_atomics_wait(void); typedef enum { // The test hasn't yet started TEST_NOT_STARTED, - // No wait support in audio worklets + // No atomics wait support in audio worklets TEST_HAS_WAIT, // Acquired in main, fail in process TEST_TRY_ACQUIRE, From dda7d0550bda84844e84fc8968e9ef8d1f24ff00 Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Tue, 16 Sep 2025 13:40:12 +0200 Subject: [PATCH 05/22] Added docs (and moved the a spin to happen faster) --- test/webaudio/audioworklet_emscripten_locks.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/webaudio/audioworklet_emscripten_locks.c b/test/webaudio/audioworklet_emscripten_locks.c index bd71bd302c917..68a81bd08bc8d 100644 --- a/test/webaudio/audioworklet_emscripten_locks.c +++ b/test/webaudio/audioworklet_emscripten_locks.c @@ -79,7 +79,7 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, emscripten_outf("TEST_WAIT_ACQUIRE_FAIL: %d (expect: 0)", result); assert(!result); whichTest = TEST_WAIT_ACQUIRE; - break; + // Fall through here so the worker has a chance to unlock whilst spinning case TEST_WAIT_ACQUIRE: // Will get unlocked in worker, so should quickly acquire result = emscripten_lock_busyspin_wait_acquire(&testLock, 10000); @@ -107,6 +107,7 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, emscripten_outf("TEST_GET_NOW: %d (expect: > 0)", result); assert(result > 0); whichTest = TEST_DONE; + // Fall through here and stop playback (shutting down in the worker) case TEST_DONE: return false; default: From 9a67852e257186fd4db8e59a6105254ca3378c25 Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Tue, 16 Sep 2025 14:38:00 +0200 Subject: [PATCH 06/22] Removed flaky flag --- test/test_browser.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_browser.py b/test/test_browser.py index 8c2d013a61040..f35cb078e198c 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5504,7 +5504,6 @@ def test_audio_worklet_params_mixing(self, args): # Tests AudioWorklet with emscripten_lock_busyspin_wait_acquire() and friends @requires_sound_hardware @also_with_minimal_runtime - @flaky('https://github.com/emscripten-core/emscripten/issues/25245') def test_audio_worklet_emscripten_locks(self): self.btest_exit('webaudio/audioworklet_emscripten_locks.c', cflags=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-pthread']) From 52c6052e0c8d728187f67a0fad99a405f3061253 Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Tue, 16 Sep 2025 14:43:16 +0200 Subject: [PATCH 07/22] Removed flaky import --- test/test_browser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_browser.py b/test/test_browser.py index f35cb078e198c..7b8ace3fe3757 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -19,7 +19,7 @@ import common from common import BrowserCore, RunnerCore, path_from_root, has_browser, Reporting, is_chrome, is_firefox, CHROMIUM_BASED_BROWSERS -from common import create_file, parameterized, ensure_dir, disabled, flaky, test_file, WEBIDL_BINDER +from common import create_file, parameterized, ensure_dir, disabled, test_file, WEBIDL_BINDER from common import read_file, EMRUN, no_wasm64, no_2gb, no_4gb, copytree from common import requires_wasm2js, parameterize, find_browser_test_file, with_all_sjlj from common import also_with_minimal_runtime, also_with_wasm2js, also_with_asan, also_with_wasmfs From f19b38cd4547aa3470d9f9484e21b327087b8225 Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Tue, 16 Sep 2025 16:00:36 +0200 Subject: [PATCH 08/22] Revert "Removed flaky import" This reverts commit cdc1834070d6246974ffd59f188bfa24742d2f68. --- test/test_browser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_browser.py b/test/test_browser.py index 7b8ace3fe3757..f35cb078e198c 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -19,7 +19,7 @@ import common from common import BrowserCore, RunnerCore, path_from_root, has_browser, Reporting, is_chrome, is_firefox, CHROMIUM_BASED_BROWSERS -from common import create_file, parameterized, ensure_dir, disabled, test_file, WEBIDL_BINDER +from common import create_file, parameterized, ensure_dir, disabled, flaky, test_file, WEBIDL_BINDER from common import read_file, EMRUN, no_wasm64, no_2gb, no_4gb, copytree from common import requires_wasm2js, parameterize, find_browser_test_file, with_all_sjlj from common import also_with_minimal_runtime, also_with_wasm2js, also_with_asan, also_with_wasmfs From 5983cda0fbfe4bd0310c3785b2c7f73916ac4b4f Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Tue, 16 Sep 2025 17:34:22 +0200 Subject: [PATCH 09/22] Revert "Removed flaky flag" This reverts commit 4df7999cb32fc68a9d56aaee59376005d1db0f09. --- test/test_browser.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_browser.py b/test/test_browser.py index f35cb078e198c..8c2d013a61040 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5504,6 +5504,7 @@ def test_audio_worklet_params_mixing(self, args): # Tests AudioWorklet with emscripten_lock_busyspin_wait_acquire() and friends @requires_sound_hardware @also_with_minimal_runtime + @flaky('https://github.com/emscripten-core/emscripten/issues/25245') def test_audio_worklet_emscripten_locks(self): self.btest_exit('webaudio/audioworklet_emscripten_locks.c', cflags=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-pthread']) From 04cdeb03c90a95fa72499615501a002f880f46ba Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Fri, 19 Sep 2025 13:29:08 +0200 Subject: [PATCH 10/22] Added explicit audio shutdown --- test/webaudio/audioworklet_emscripten_locks.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/webaudio/audioworklet_emscripten_locks.c b/test/webaudio/audioworklet_emscripten_locks.c index 68a81bd08bc8d..1a2423ace578b 100644 --- a/test/webaudio/audioworklet_emscripten_locks.c +++ b/test/webaudio/audioworklet_emscripten_locks.c @@ -13,6 +13,9 @@ // - emscripten_lock_release() // - emscripten_get_now() +// Global audio context +EMSCRIPTEN_WEBAUDIO_T context; + // Internal, found in 'system/lib/pthread/threading_internal.h' (and requires building with -pthread) int _emscripten_thread_supports_atomics_wait(void); @@ -48,6 +51,7 @@ double startTime = 0; void do_exit() { emscripten_out("Test success"); + emscripten_destroy_audio_context(context); emscripten_terminate_all_wasm_workers(); emscripten_force_exit(0); } @@ -186,7 +190,8 @@ int main() { startTime = emscripten_get_now(); // Audio processor callback setup - EMSCRIPTEN_WEBAUDIO_T context = emscripten_create_audio_context(NULL); + context = emscripten_create_audio_context(NULL); + assert(context); emscripten_start_wasm_audio_worklet_thread_async(context, wasmAudioWorkletStack, sizeof(wasmAudioWorkletStack), WebAudioWorkletThreadInitialized, NULL); // Worker thread setup From 82405f74aa3b5036f0e3fd0b81f2fe01d65ea12d Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Fri, 19 Sep 2025 14:45:54 +0200 Subject: [PATCH 11/22] Removed flaky (again) --- test/test_browser.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_browser.py b/test/test_browser.py index 8c2d013a61040..f35cb078e198c 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5504,7 +5504,6 @@ def test_audio_worklet_params_mixing(self, args): # Tests AudioWorklet with emscripten_lock_busyspin_wait_acquire() and friends @requires_sound_hardware @also_with_minimal_runtime - @flaky('https://github.com/emscripten-core/emscripten/issues/25245') def test_audio_worklet_emscripten_locks(self): self.btest_exit('webaudio/audioworklet_emscripten_locks.c', cflags=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-pthread']) From 42a582db7011eb5c68786e7d35441fc2a43a7ef9 Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Mon, 10 Nov 2025 13:51:36 +0100 Subject: [PATCH 12/22] Re-added flaky This reverts commit 82405f74aa3b5036f0e3fd0b81f2fe01d65ea12d. --- test/test_browser.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_browser.py b/test/test_browser.py index 0b88db80c852a..18ca7709c7eb1 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5617,6 +5617,7 @@ def test_audio_worklet_params_mixing(self, args): # Tests AudioWorklet with emscripten_lock_busyspin_wait_acquire() and friends @requires_sound_hardware @also_with_minimal_runtime + @flaky('https://github.com/emscripten-core/emscripten/issues/25245') def test_audio_worklet_emscripten_locks(self): self.btest_exit('webaudio/audioworklet_emscripten_locks.c', cflags=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-pthread']) From 76d750cb69f4b02e4446fd342ddfde1d25a485c3 Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Wed, 12 Nov 2025 14:01:32 +0100 Subject: [PATCH 13/22] Run on both main and worker thread --- test/test_browser.py | 10 ++-- test/webaudio/audioworklet_emscripten_locks.c | 52 ++++++++++++++----- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/test/test_browser.py b/test/test_browser.py index 18ca7709c7eb1..368e4f42acd4d 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5615,11 +5615,15 @@ def test_audio_worklet_params_mixing(self, args): self.btest_exit('webaudio/audioworklet_params_mixing.c', cflags=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-DTEST_AND_EXIT'] + args) # Tests AudioWorklet with emscripten_lock_busyspin_wait_acquire() and friends - @requires_sound_hardware @also_with_minimal_runtime + @parameterized({ + '': ([],), + 'worker': (['-DTEST_ON_WORKER'],), + }) + @requires_sound_hardware @flaky('https://github.com/emscripten-core/emscripten/issues/25245') - def test_audio_worklet_emscripten_locks(self): - self.btest_exit('webaudio/audioworklet_emscripten_locks.c', cflags=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-pthread']) + def test_audio_worklet_emscripten_locks(self, args): + self.btest_exit('webaudio/audioworklet_emscripten_locks.c', cflags=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-pthread'] + args) # Verifies setting audio context sample rate, and that emscripten_audio_context_sample_rate() works. @requires_sound_hardware diff --git a/test/webaudio/audioworklet_emscripten_locks.c b/test/webaudio/audioworklet_emscripten_locks.c index 1a2423ace578b..14761244aef40 100644 --- a/test/webaudio/audioworklet_emscripten_locks.c +++ b/test/webaudio/audioworklet_emscripten_locks.c @@ -12,6 +12,8 @@ // - emscripten_lock_busyspin_waitinf_acquire() // - emscripten_lock_release() // - emscripten_get_now() +// +// Define TEST_ON_WORKER to run on a worker, otherwise it runs on the main thread // Global audio context EMSCRIPTEN_WEBAUDIO_T context; @@ -44,7 +46,7 @@ typedef enum { // Lock used in all the tests emscripten_lock_t testLock = EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER; -// Which test is running (sometimes in the worklet, sometimes in the worker) +// Which test is running (sometimes in the worklet, sometimes in the worker/main) _Atomic Test whichTest = TEST_NOT_STARTED; // Time at which the test starts taken in main() double startTime = 0; @@ -52,7 +54,9 @@ double startTime = 0; void do_exit() { emscripten_out("Test success"); emscripten_destroy_audio_context(context); +#ifdef TEST_ON_WORKER emscripten_terminate_all_wasm_workers(); +#endif emscripten_force_exit(0); } @@ -83,9 +87,9 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, emscripten_outf("TEST_WAIT_ACQUIRE_FAIL: %d (expect: 0)", result); assert(!result); whichTest = TEST_WAIT_ACQUIRE; - // Fall through here so the worker has a chance to unlock whilst spinning + // Fall through here so the worker/main has a chance to unlock whilst spinning case TEST_WAIT_ACQUIRE: - // Will get unlocked in worker, so should quickly acquire + // Will get unlocked in worker/main, so should quickly acquire result = emscripten_lock_busyspin_wait_acquire(&testLock, 10000); emscripten_outf("TEST_WAIT_ACQUIRE: %d (expect: 1)", result); assert(result); @@ -100,7 +104,7 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, whichTest = TEST_WAIT_INFINTE_1; break; case TEST_WAIT_INFINTE_1: - // Still locked when we enter here but move on in the worker + // Still locked when we enter here but move on in the worker/main break; case TEST_WAIT_INFINTE_2: emscripten_lock_release(&testLock); @@ -111,7 +115,7 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, emscripten_outf("TEST_GET_NOW: %d (expect: > 0)", result); assert(result > 0); whichTest = TEST_DONE; - // Fall through here and stop playback (shutting down in the worker) + // Fall through here and stop playback (shutting down in the worker/main) case TEST_DONE: return false; default: @@ -131,10 +135,16 @@ EM_JS(void, InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext), { }; }); +#ifdef TEST_ON_WORKER void WorkerLoop() { +#else +bool MainLoop(double time, void* data) { +#endif assert(!emscripten_current_thread_is_audio_worklet()); int didUnlock = false; +#ifdef TEST_ON_WORKER while (true) { +#endif switch (whichTest) { case TEST_NOT_STARTED: emscripten_out("Staring test (may need a button click)"); @@ -142,7 +152,7 @@ void WorkerLoop() { break; case TEST_WAIT_ACQUIRE: if (!didUnlock) { - emscripten_out("Worker releasing lock"); + emscripten_out("Worker/main releasing lock"); // Release here to acquire in process emscripten_lock_release(&testLock); didUnlock = true; @@ -152,30 +162,42 @@ void WorkerLoop() { // Spin here until released in process (but don't change test until we know this case ran) whichTest = TEST_WAIT_INFINTE_2; emscripten_lock_busyspin_waitinf_acquire(&testLock); - emscripten_out("TEST_WAIT_INFINTE (from worker)"); + emscripten_out("TEST_WAIT_INFINTE (from worker/main)"); break; case TEST_DONE: // Finished, exit from the main thread (and return out of this loop) +#ifdef TEST_ON_WORKER emscripten_wasm_worker_post_function_v(EMSCRIPTEN_WASM_WORKER_ID_PARENT, &do_exit); + // WorkerLoop contract (end the worker) return; +#else + do_exit(); + // MainLoop contract (stop the repeats) + return false; +#endif default: break; } - // Repeat every 16ms (except when TEST_DONE) - emscripten_wasm_worker_sleep(16 * 1000000ULL); +#ifdef TEST_ON_WORKER + // Repeat every 10ms (except when TEST_DONE) + emscripten_wasm_worker_sleep(10 * 1000000ULL); } +#else + // Run again + return true; +#endif } void AudioWorkletProcessorCreated(EMSCRIPTEN_WEBAUDIO_T audioContext, bool success, void *userData) { 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, NULL); + EMSCRIPTEN_AUDIO_WORKLET_NODE_T wasmAudioWorklet = emscripten_create_wasm_audio_worklet_node(audioContext, "locks-test", &options, &ProcessAudio, NULL); emscripten_audio_node_connect(wasmAudioWorklet, audioContext, 0, 0); InitHtmlUi(audioContext); } void WebAudioWorkletThreadInitialized(EMSCRIPTEN_WEBAUDIO_T audioContext, bool success, void *userData) { - WebAudioWorkletProcessorCreateOptions opts = { .name = "noise-generator" }; + WebAudioWorkletProcessorCreateOptions opts = { .name = "locks-test" }; emscripten_create_wasm_audio_worklet_processor_async(audioContext, &opts, AudioWorkletProcessorCreated, NULL); } @@ -193,10 +215,14 @@ int main() { context = emscripten_create_audio_context(NULL); assert(context); emscripten_start_wasm_audio_worklet_thread_async(context, wasmAudioWorkletStack, sizeof(wasmAudioWorkletStack), WebAudioWorkletThreadInitialized, NULL); - - // Worker thread setup + + // Either call every 10ms or create a worker that sleeps every 10ms +#ifdef TEST_ON_WORKER emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(1024); emscripten_wasm_worker_post_function_v(worker, WorkerLoop); +#else + emscripten_set_timeout_loop(MainLoop, 10, NULL); +#endif emscripten_exit_with_live_runtime(); } From e2106bb9540679401243ed4a842e503ef1e1c41f Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Wed, 12 Nov 2025 15:08:07 +0100 Subject: [PATCH 14/22] Allow out calls to be silenced --- test/webaudio/audioworklet_emscripten_locks.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/test/webaudio/audioworklet_emscripten_locks.c b/test/webaudio/audioworklet_emscripten_locks.c index 14761244aef40..f6cb57c92bb93 100644 --- a/test/webaudio/audioworklet_emscripten_locks.c +++ b/test/webaudio/audioworklet_emscripten_locks.c @@ -3,6 +3,8 @@ #include #include +#define QUIET_AUDIO_WORKLET + // Tests that these audio worklet compatible functions work, details in comments below: // // - _emscripten_thread_supports_atomics_wait() @@ -70,28 +72,36 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, case TEST_HAS_WAIT: // Should not have wait support here result = _emscripten_thread_supports_atomics_wait(); +#ifndef QUIET_AUDIO_WORKLET emscripten_outf("TEST_HAS_WAIT: %d (expect: 0)", result); +#endif assert(!result); whichTest = TEST_TRY_ACQUIRE; break; case TEST_TRY_ACQUIRE: // Was locked after init, should fail to acquire result = emscripten_lock_try_acquire(&testLock); +#ifndef QUIET_AUDIO_WORKLET emscripten_outf("TEST_TRY_ACQUIRE: %d (expect: 0)", result); +#endif assert(!result); whichTest = TEST_WAIT_ACQUIRE_FAIL; break; case TEST_WAIT_ACQUIRE_FAIL: // Still locked so we fail to acquire result = emscripten_lock_busyspin_wait_acquire(&testLock, 100); +#ifndef QUIET_AUDIO_WORKLET emscripten_outf("TEST_WAIT_ACQUIRE_FAIL: %d (expect: 0)", result); +#endif assert(!result); whichTest = TEST_WAIT_ACQUIRE; // Fall through here so the worker/main has a chance to unlock whilst spinning case TEST_WAIT_ACQUIRE: // Will get unlocked in worker/main, so should quickly acquire - result = emscripten_lock_busyspin_wait_acquire(&testLock, 10000); + result = emscripten_lock_busyspin_wait_acquire(&testLock, 1000); +#ifndef QUIET_AUDIO_WORKLET emscripten_outf("TEST_WAIT_ACQUIRE: %d (expect: 1)", result); +#endif assert(result); whichTest = TEST_RELEASE; break; @@ -99,7 +109,9 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, // Unlock, check the result emscripten_lock_release(&testLock); result = emscripten_lock_try_acquire(&testLock); +#ifndef QUIET_AUDIO_WORKLET emscripten_outf("TEST_RELEASE: %d (expect: 1)", result); +#endif assert(result); whichTest = TEST_WAIT_INFINTE_1; break; @@ -112,7 +124,9 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, break; case TEST_GET_NOW: result = (int) (emscripten_get_now() - startTime); +#ifndef QUIET_AUDIO_WORKLET emscripten_outf("TEST_GET_NOW: %d (expect: > 0)", result); +#endif assert(result > 0); whichTest = TEST_DONE; // Fall through here and stop playback (shutting down in the worker/main) From db0c8aa6480468e4ff6bb9ae3905de8a92dfb34f Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Wed, 12 Nov 2025 15:30:56 +0100 Subject: [PATCH 15/22] Only run on worker, re-enable out() calls --- test/test_browser.py | 10 +++------- test/webaudio/audioworklet_emscripten_locks.c | 3 +-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/test/test_browser.py b/test/test_browser.py index 368e4f42acd4d..f563bebea4c4a 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5615,15 +5615,11 @@ def test_audio_worklet_params_mixing(self, args): self.btest_exit('webaudio/audioworklet_params_mixing.c', cflags=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-DTEST_AND_EXIT'] + args) # Tests AudioWorklet with emscripten_lock_busyspin_wait_acquire() and friends - @also_with_minimal_runtime - @parameterized({ - '': ([],), - 'worker': (['-DTEST_ON_WORKER'],), - }) @requires_sound_hardware + @also_with_minimal_runtime @flaky('https://github.com/emscripten-core/emscripten/issues/25245') - def test_audio_worklet_emscripten_locks(self, args): - self.btest_exit('webaudio/audioworklet_emscripten_locks.c', cflags=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-pthread'] + args) + def test_audio_worklet_emscripten_locks(self): + self.btest_exit('webaudio/audioworklet_emscripten_locks.c', cflags=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-pthread', '-DTEST_ON_WORKER']) # Verifies setting audio context sample rate, and that emscripten_audio_context_sample_rate() works. @requires_sound_hardware diff --git a/test/webaudio/audioworklet_emscripten_locks.c b/test/webaudio/audioworklet_emscripten_locks.c index f6cb57c92bb93..30dfe629f94bc 100644 --- a/test/webaudio/audioworklet_emscripten_locks.c +++ b/test/webaudio/audioworklet_emscripten_locks.c @@ -3,8 +3,6 @@ #include #include -#define QUIET_AUDIO_WORKLET - // Tests that these audio worklet compatible functions work, details in comments below: // // - _emscripten_thread_supports_atomics_wait() @@ -16,6 +14,7 @@ // - emscripten_get_now() // // Define TEST_ON_WORKER to run on a worker, otherwise it runs on the main thread +// Define QUIET_AUDIO_WORKLET to remove emscripten_out() calls in the audio worker // Global audio context EMSCRIPTEN_WEBAUDIO_T context; From 70c1930911e2d823b264ebe3090900d4b610c93d Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Wed, 12 Nov 2025 18:34:42 +0100 Subject: [PATCH 16/22] Minor renaming --- test/webaudio/audioworklet_emscripten_locks.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/webaudio/audioworklet_emscripten_locks.c b/test/webaudio/audioworklet_emscripten_locks.c index 30dfe629f94bc..78dbf355c874b 100644 --- a/test/webaudio/audioworklet_emscripten_locks.c +++ b/test/webaudio/audioworklet_emscripten_locks.c @@ -13,8 +13,8 @@ // - emscripten_lock_release() // - emscripten_get_now() // -// Define TEST_ON_WORKER to run on a worker, otherwise it runs on the main thread -// Define QUIET_AUDIO_WORKLET to remove emscripten_out() calls in the audio worker +// Define RUN_ON_WORKER to run on a worker, otherwise it runs on the main thread +// Define QUIET_AUDIO_WORKLET to remove emscripten_out() calls in the audio worklet // Global audio context EMSCRIPTEN_WEBAUDIO_T context; @@ -55,7 +55,7 @@ double startTime = 0; void do_exit() { emscripten_out("Test success"); emscripten_destroy_audio_context(context); -#ifdef TEST_ON_WORKER +#ifdef RUN_ON_WORKER emscripten_terminate_all_wasm_workers(); #endif emscripten_force_exit(0); @@ -148,14 +148,14 @@ EM_JS(void, InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext), { }; }); -#ifdef TEST_ON_WORKER +#ifdef RUN_ON_WORKER void WorkerLoop() { #else bool MainLoop(double time, void* data) { #endif assert(!emscripten_current_thread_is_audio_worklet()); int didUnlock = false; -#ifdef TEST_ON_WORKER +#ifdef RUN_ON_WORKER while (true) { #endif switch (whichTest) { @@ -179,7 +179,7 @@ bool MainLoop(double time, void* data) { break; case TEST_DONE: // Finished, exit from the main thread (and return out of this loop) -#ifdef TEST_ON_WORKER +#ifdef RUN_ON_WORKER emscripten_wasm_worker_post_function_v(EMSCRIPTEN_WASM_WORKER_ID_PARENT, &do_exit); // WorkerLoop contract (end the worker) return; @@ -191,7 +191,7 @@ bool MainLoop(double time, void* data) { default: break; } -#ifdef TEST_ON_WORKER +#ifdef RUN_ON_WORKER // Repeat every 10ms (except when TEST_DONE) emscripten_wasm_worker_sleep(10 * 1000000ULL); } @@ -230,7 +230,7 @@ int main() { emscripten_start_wasm_audio_worklet_thread_async(context, wasmAudioWorkletStack, sizeof(wasmAudioWorkletStack), WebAudioWorkletThreadInitialized, NULL); // Either call every 10ms or create a worker that sleeps every 10ms -#ifdef TEST_ON_WORKER +#ifdef RUN_ON_WORKER emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(1024); emscripten_wasm_worker_post_function_v(worker, WorkerLoop); #else From 4cb45b066529f8f528100e4992b2fae80137ed39 Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Wed, 12 Nov 2025 18:37:21 +0100 Subject: [PATCH 17/22] Minor: moved out until after release --- test/webaudio/audioworklet_emscripten_locks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/webaudio/audioworklet_emscripten_locks.c b/test/webaudio/audioworklet_emscripten_locks.c index 78dbf355c874b..d7ad522f4ec85 100644 --- a/test/webaudio/audioworklet_emscripten_locks.c +++ b/test/webaudio/audioworklet_emscripten_locks.c @@ -165,9 +165,9 @@ bool MainLoop(double time, void* data) { break; case TEST_WAIT_ACQUIRE: if (!didUnlock) { - emscripten_out("Worker/main releasing lock"); // Release here to acquire in process emscripten_lock_release(&testLock); + emscripten_out("TEST_WAIT_ACQUIRE: worker/main released lock"); didUnlock = true; } break; From 65231aba3f5093f4f9118e3aabd84641d4622a62 Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Wed, 12 Nov 2025 18:39:55 +0100 Subject: [PATCH 18/22] Quiet printing throughout --- test/webaudio/audioworklet_emscripten_locks.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/test/webaudio/audioworklet_emscripten_locks.c b/test/webaudio/audioworklet_emscripten_locks.c index d7ad522f4ec85..73bd12c853f9f 100644 --- a/test/webaudio/audioworklet_emscripten_locks.c +++ b/test/webaudio/audioworklet_emscripten_locks.c @@ -14,7 +14,7 @@ // - emscripten_get_now() // // Define RUN_ON_WORKER to run on a worker, otherwise it runs on the main thread -// Define QUIET_AUDIO_WORKLET to remove emscripten_out() calls in the audio worklet +// Define QUIETEN_PRINTING to remove most of the emscripten_out() calls // Global audio context EMSCRIPTEN_WEBAUDIO_T context; @@ -71,7 +71,7 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, case TEST_HAS_WAIT: // Should not have wait support here result = _emscripten_thread_supports_atomics_wait(); -#ifndef QUIET_AUDIO_WORKLET +#ifndef QUIETEN_PRINTING emscripten_outf("TEST_HAS_WAIT: %d (expect: 0)", result); #endif assert(!result); @@ -80,7 +80,7 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, case TEST_TRY_ACQUIRE: // Was locked after init, should fail to acquire result = emscripten_lock_try_acquire(&testLock); -#ifndef QUIET_AUDIO_WORKLET +#ifndef QUIETEN_PRINTING emscripten_outf("TEST_TRY_ACQUIRE: %d (expect: 0)", result); #endif assert(!result); @@ -89,7 +89,7 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, case TEST_WAIT_ACQUIRE_FAIL: // Still locked so we fail to acquire result = emscripten_lock_busyspin_wait_acquire(&testLock, 100); -#ifndef QUIET_AUDIO_WORKLET +#ifndef QUIETEN_PRINTING emscripten_outf("TEST_WAIT_ACQUIRE_FAIL: %d (expect: 0)", result); #endif assert(!result); @@ -98,7 +98,7 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, case TEST_WAIT_ACQUIRE: // Will get unlocked in worker/main, so should quickly acquire result = emscripten_lock_busyspin_wait_acquire(&testLock, 1000); -#ifndef QUIET_AUDIO_WORKLET +#ifndef QUIETEN_PRINTING emscripten_outf("TEST_WAIT_ACQUIRE: %d (expect: 1)", result); #endif assert(result); @@ -108,7 +108,7 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, // Unlock, check the result emscripten_lock_release(&testLock); result = emscripten_lock_try_acquire(&testLock); -#ifndef QUIET_AUDIO_WORKLET +#ifndef QUIETEN_PRINTING emscripten_outf("TEST_RELEASE: %d (expect: 1)", result); #endif assert(result); @@ -123,7 +123,7 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, break; case TEST_GET_NOW: result = (int) (emscripten_get_now() - startTime); -#ifndef QUIET_AUDIO_WORKLET +#ifndef QUIETEN_PRINTING emscripten_outf("TEST_GET_NOW: %d (expect: > 0)", result); #endif assert(result > 0); @@ -167,7 +167,9 @@ bool MainLoop(double time, void* data) { if (!didUnlock) { // Release here to acquire in process emscripten_lock_release(&testLock); +#ifndef QUIETEN_PRINTING emscripten_out("TEST_WAIT_ACQUIRE: worker/main released lock"); +#endif didUnlock = true; } break; @@ -175,7 +177,9 @@ bool MainLoop(double time, void* data) { // Spin here until released in process (but don't change test until we know this case ran) whichTest = TEST_WAIT_INFINTE_2; emscripten_lock_busyspin_waitinf_acquire(&testLock); +#ifndef QUIETEN_PRINTING emscripten_out("TEST_WAIT_INFINTE (from worker/main)"); +#endif break; case TEST_DONE: // Finished, exit from the main thread (and return out of this loop) From 55c6569b8043b11f1c262182c245577be137277b Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Wed, 12 Nov 2025 18:59:15 +0100 Subject: [PATCH 19/22] Missed rename --- test/test_browser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_browser.py b/test/test_browser.py index f563bebea4c4a..aa4bdcee7b672 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5619,7 +5619,7 @@ def test_audio_worklet_params_mixing(self, args): @also_with_minimal_runtime @flaky('https://github.com/emscripten-core/emscripten/issues/25245') def test_audio_worklet_emscripten_locks(self): - self.btest_exit('webaudio/audioworklet_emscripten_locks.c', cflags=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-pthread', '-DTEST_ON_WORKER']) + self.btest_exit('webaudio/audioworklet_emscripten_locks.c', cflags=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-pthread', '-DRUN_ON_WORKER']) # Verifies setting audio context sample rate, and that emscripten_audio_context_sample_rate() works. @requires_sound_hardware From 055df5f26429b6659fc8ea175321d60a924841ca Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Fri, 14 Nov 2025 11:42:12 +0100 Subject: [PATCH 20/22] Minor tidy --- test/webaudio/audioworklet_emscripten_locks.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/webaudio/audioworklet_emscripten_locks.c b/test/webaudio/audioworklet_emscripten_locks.c index 73bd12c853f9f..5318d75fb89c1 100644 --- a/test/webaudio/audioworklet_emscripten_locks.c +++ b/test/webaudio/audioworklet_emscripten_locks.c @@ -95,6 +95,7 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, assert(!result); whichTest = TEST_WAIT_ACQUIRE; // Fall through here so the worker/main has a chance to unlock whilst spinning + // (otherwise the lock has a chance to be released before spinning). case TEST_WAIT_ACQUIRE: // Will get unlocked in worker/main, so should quickly acquire result = emscripten_lock_busyspin_wait_acquire(&testLock, 1000); @@ -145,16 +146,19 @@ EM_JS(void, InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext), { audioContext = emscriptenGetAudioObject(audioContext); startButton.onclick = () => { audioContext.resume(); + document.removeChild(startButton); }; }); +// Has TEST_WAIT_ACQUIRE unlocked testLock? +int waitAcquireUnlocked = false; + #ifdef RUN_ON_WORKER void WorkerLoop() { #else bool MainLoop(double time, void* data) { #endif assert(!emscripten_current_thread_is_audio_worklet()); - int didUnlock = false; #ifdef RUN_ON_WORKER while (true) { #endif @@ -164,13 +168,13 @@ bool MainLoop(double time, void* data) { whichTest = TEST_HAS_WAIT; break; case TEST_WAIT_ACQUIRE: - if (!didUnlock) { + if (!waitAcquireUnlocked) { // Release here to acquire in process emscripten_lock_release(&testLock); #ifndef QUIETEN_PRINTING emscripten_out("TEST_WAIT_ACQUIRE: worker/main released lock"); #endif - didUnlock = true; + waitAcquireUnlocked = true; } break; case TEST_WAIT_INFINTE_1: @@ -210,7 +214,6 @@ void AudioWorkletProcessorCreated(EMSCRIPTEN_WEBAUDIO_T audioContext, bool succe EmscriptenAudioWorkletNodeCreateOptions options = { .numberOfInputs = 0, .numberOfOutputs = 1, .outputChannelCounts = outputChannelCounts }; EMSCRIPTEN_AUDIO_WORKLET_NODE_T wasmAudioWorklet = emscripten_create_wasm_audio_worklet_node(audioContext, "locks-test", &options, &ProcessAudio, NULL); emscripten_audio_node_connect(wasmAudioWorklet, audioContext, 0, 0); - InitHtmlUi(audioContext); } void WebAudioWorkletThreadInitialized(EMSCRIPTEN_WEBAUDIO_T audioContext, bool success, void *userData) { @@ -231,6 +234,7 @@ int main() { // Audio processor callback setup context = emscripten_create_audio_context(NULL); assert(context); + InitHtmlUi(context); emscripten_start_wasm_audio_worklet_thread_async(context, wasmAudioWorkletStack, sizeof(wasmAudioWorkletStack), WebAudioWorkletThreadInitialized, NULL); // Either call every 10ms or create a worker that sleeps every 10ms From 409a7d85b68c3cb5b8abb60342f58b8757d58adc Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Fri, 14 Nov 2025 11:49:36 +0100 Subject: [PATCH 21/22] Fix button removal --- test/webaudio/audioworklet_emscripten_locks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/webaudio/audioworklet_emscripten_locks.c b/test/webaudio/audioworklet_emscripten_locks.c index 5318d75fb89c1..0b846628a7754 100644 --- a/test/webaudio/audioworklet_emscripten_locks.c +++ b/test/webaudio/audioworklet_emscripten_locks.c @@ -146,7 +146,7 @@ EM_JS(void, InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext), { audioContext = emscriptenGetAudioObject(audioContext); startButton.onclick = () => { audioContext.resume(); - document.removeChild(startButton); + document.body.removeChild(startButton); }; }); From e12e8a3a179493eec27c0bc299577dd12da6cf0c Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Fri, 14 Nov 2025 14:03:54 +0100 Subject: [PATCH 22/22] Minor tidy (and another run) --- test/webaudio/audioworklet_emscripten_locks.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/webaudio/audioworklet_emscripten_locks.c b/test/webaudio/audioworklet_emscripten_locks.c index 0b846628a7754..517e79ae31a27 100644 --- a/test/webaudio/audioworklet_emscripten_locks.c +++ b/test/webaudio/audioworklet_emscripten_locks.c @@ -51,6 +51,8 @@ emscripten_lock_t testLock = EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER; _Atomic Test whichTest = TEST_NOT_STARTED; // Time at which the test starts taken in main() double startTime = 0; +// Has TEST_WAIT_ACQUIRE unlocked testLock? +int waitAcquireUnlocked = false; void do_exit() { emscripten_out("Test success"); @@ -140,7 +142,7 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, EM_JS(void, InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext), { let startButton = document.createElement('button'); - startButton.innerHTML = 'Start playback'; + startButton.innerHTML = 'Start Test'; document.body.appendChild(startButton); audioContext = emscriptenGetAudioObject(audioContext); @@ -150,9 +152,6 @@ EM_JS(void, InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext), { }; }); -// Has TEST_WAIT_ACQUIRE unlocked testLock? -int waitAcquireUnlocked = false; - #ifdef RUN_ON_WORKER void WorkerLoop() { #else