1- #include < emscripten/webaudio.h>
21#include < emscripten/threading.h>
3- #include < stdio .h>
4- #include < stdlib .h>
2+ #include < emscripten/wasm_worker .h>
3+ #include < emscripten/webaudio .h>
54#include < assert.h>
65
7- // Tests that
8- // - _emscripten_thread_supports_atomics_wait() returns true in a Wasm Audio Worklet.
9- // - emscripten_futex_wake() does not crash in a Wasm Audio Worklet.
10- // - emscripten_futex_wait() does not crash in a Wasm Audio Worklet.
11- // - emscripten_get_now() does not crash in a Wasm Audio Worklet.
12-
13- int futexLocation = 0 ;
14- int testSuccess = 0 ;
6+ // Tests that these audio worklet compatible functions work, details in comments below:
7+ //
8+ // - _emscripten_thread_supports_atomics_wait()
9+ // - emscripten_lock_init()
10+ // - emscripten_lock_try_acquire()
11+ // - emscripten_lock_busyspin_wait_acquire()
12+ // - emscripten_lock_busyspin_waitinf_acquire()
13+ // - emscripten_lock_release()
14+ // - emscripten_get_now()
1515
16- // Internal, found in 'system/lib/pthread/threading_internal.h'
17- extern " C" int _emscripten_thread_supports_atomics_wait ();
16+ // Internal, found in 'system/lib/pthread/threading_internal.h' (and requires building with -pthread)
17+ extern " C" int _emscripten_thread_supports_atomics_wait (void );
1818
19- bool ProcessAudio (int numInputs, const AudioSampleFrame *inputs, int numOutputs, AudioSampleFrame *outputs, int numParams, const AudioParamFrame *params, void *userData) {
20- int supportsAtomicWait = _emscripten_thread_supports_atomics_wait ();
21- printf (" supportsAtomicWait: %d\n " , supportsAtomicWait);
22- assert (!supportsAtomicWait);
23- emscripten_futex_wake (&futexLocation, 1 );
24- printf (" %f\n " , emscripten_get_now ());
19+ typedef enum {
20+ // No wait support in audio worklets
21+ TEST_HAS_WAIT,
22+ // Acquired in main, fail in process
23+ TEST_TRY_ACQUIRE,
24+ // Keep acquired so time-out
25+ TEST_WAIT_ACQUIRE_FAIL,
26+ // Release in main, succeed in process
27+ TEST_WAIT_ACQUIRE,
28+ // Release in process after above
29+ TEST_RELEASE,
30+ // Released in process above, spin in main
31+ TEST_WAIT_INFINTE_1,
32+ // Release in process to stop spinning in main
33+ TEST_WAIT_INFINTE_2,
34+ // Call emscripten_get_now() in process
35+ TEST_GET_NOW,
36+ // Test finished
37+ TEST_DONE
38+ } Test;
2539
26- emscripten_futex_wait (&futexLocation, 1 , /* maxWaitMs=*/ 2 );
27- testSuccess = 1 ;
40+ // Lock used in all the tests
41+ emscripten_lock_t testLock = EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER;
42+ // Which test is running (sometimes in the worklet, sometimes in the main thread)
43+ _Atomic Test whichTest = TEST_HAS_WAIT;
44+ // Time at which the test starts taken in main()
45+ double startTime = 0 ;
2846
29- return false ;
47+ bool ProcessAudio (int numInputs, const AudioSampleFrame *inputs, int numOutputs, AudioSampleFrame *outputs, int numParams, const AudioParamFrame *params, void *userData) {
48+ int result = 0 ;
49+ switch (whichTest) {
50+ case TEST_HAS_WAIT:
51+ // Should not have wait support here
52+ result = _emscripten_thread_supports_atomics_wait ();
53+ emscripten_outf (" TEST_HAS_WAIT: %d (expect: 0)" , result);
54+ assert (!result);
55+ whichTest = TEST_TRY_ACQUIRE;
56+ break ;
57+ case TEST_TRY_ACQUIRE:
58+ // Was locked after init, should fail to acquire
59+ result = emscripten_lock_try_acquire (&testLock);
60+ emscripten_outf (" TEST_TRY_ACQUIRE: %d (expect: 0)" , result);
61+ assert (!result);
62+ whichTest = TEST_WAIT_ACQUIRE_FAIL;
63+ break ;
64+ case TEST_WAIT_ACQUIRE_FAIL:
65+ // Still locked so we fail to acquire
66+ result = emscripten_lock_busyspin_wait_acquire (&testLock, 100 );
67+ emscripten_outf (" TEST_WAIT_ACQUIRE_FAIL: %d (expect: 0)" , result);
68+ assert (!result);
69+ whichTest = TEST_WAIT_ACQUIRE;
70+ case TEST_WAIT_ACQUIRE:
71+ // Will get unlocked in main thread, so should quickly acquire
72+ result = emscripten_lock_busyspin_wait_acquire (&testLock, 100 );
73+ emscripten_outf (" TEST_WAIT_ACQUIRE: %d (expect: 1)" , result);
74+ assert (result);
75+ whichTest = TEST_RELEASE;
76+ break ;
77+ case TEST_RELEASE:
78+ // Unlock, check the result
79+ emscripten_lock_release (&testLock);
80+ result = emscripten_lock_try_acquire (&testLock);
81+ emscripten_outf (" TEST_RELEASE: %d (expect: 1)" , result);
82+ assert (result);
83+ whichTest = TEST_WAIT_INFINTE_1;
84+ break ;
85+ case TEST_WAIT_INFINTE_1:
86+ // Still locked when we enter here but move on in the main thread
87+ break ;
88+ case TEST_WAIT_INFINTE_2:
89+ emscripten_lock_release (&testLock);
90+ whichTest = TEST_GET_NOW;
91+ break ;
92+ case TEST_GET_NOW:
93+ result = (int ) (emscripten_get_now () - startTime);
94+ emscripten_outf (" TEST_GET_NOW: %d (expect: > 0)" , result);
95+ assert (result > 0 );
96+ whichTest = TEST_DONE;
97+ case TEST_DONE:
98+ return false ;
99+ default :
100+ break ;
101+ }
102+ return true ;
30103}
31104
32105EM_JS (void , InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext), {
@@ -40,34 +113,55 @@ EM_JS(void, InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext), {
40113 };
41114});
42115
43- bool PollTestSuccess (double , void *) {
44- if (testSuccess) {
45- printf (" Test success!\n " );
46- #ifdef REPORT_RESULT
47- REPORT_RESULT (0 );
48- #endif
116+ bool MainLoop (double time, void * data) {
117+ switch (whichTest) {
118+ case TEST_WAIT_ACQUIRE:
119+ // Release here to acquire in process
120+ emscripten_lock_release (&testLock);
121+ break ;
122+ case TEST_WAIT_INFINTE_1:
123+ // Spin here until released in process (but don't change test until we know this case ran)
124+ whichTest = TEST_WAIT_INFINTE_2;
125+ emscripten_lock_busyspin_waitinf_acquire (&testLock);
126+ emscripten_out (" TEST_WAIT_INFINTE (from main)" );
127+ break ;
128+ case TEST_DONE:
129+ // Finished, exit from the main thread
130+ emscripten_out (" Test success" );
131+ emscripten_force_exit (0 );
49132 return false ;
133+ default :
134+ break ;
50135 }
51136 return true ;
52137}
53138
54139void AudioWorkletProcessorCreated (EMSCRIPTEN_WEBAUDIO_T audioContext, bool success, void *userData) {
55140 int outputChannelCounts[1 ] = { 1 };
56141 EmscriptenAudioWorkletNodeCreateOptions options = { .numberOfInputs = 0 , .numberOfOutputs = 1 , .outputChannelCounts = outputChannelCounts };
57- EMSCRIPTEN_AUDIO_WORKLET_NODE_T wasmAudioWorklet = emscripten_create_wasm_audio_worklet_node (audioContext, " noise-generator" , &options, &ProcessAudio, 0 );
142+ EMSCRIPTEN_AUDIO_WORKLET_NODE_T wasmAudioWorklet = emscripten_create_wasm_audio_worklet_node (audioContext, " noise-generator" , &options, &ProcessAudio, NULL );
58143 emscripten_audio_node_connect (wasmAudioWorklet, audioContext, 0 , 0 );
59144 InitHtmlUi (audioContext);
60145}
61146
62147void WebAudioWorkletThreadInitialized (EMSCRIPTEN_WEBAUDIO_T audioContext, bool success, void *userData) {
63148 WebAudioWorkletProcessorCreateOptions opts = { .name = " noise-generator" };
64- emscripten_create_wasm_audio_worklet_processor_async (audioContext, &opts, AudioWorkletProcessorCreated, 0 );
149+ emscripten_create_wasm_audio_worklet_processor_async (audioContext, &opts, AudioWorkletProcessorCreated, NULL );
65150}
66151
67- uint8_t wasmAudioWorkletStack[4096 ];
152+ uint8_t wasmAudioWorkletStack[2048 ];
68153
69154int main () {
70- emscripten_set_timeout_loop (PollTestSuccess, 10 , 0 );
71- EMSCRIPTEN_WEBAUDIO_T context = emscripten_create_audio_context (0 );
72- emscripten_start_wasm_audio_worklet_thread_async (context, wasmAudioWorkletStack, sizeof (wasmAudioWorkletStack), WebAudioWorkletThreadInitialized, 0 );
155+ // Main thread init and acquire (work passes to the processor)
156+ emscripten_lock_init (&testLock);
157+ int hasLock = emscripten_lock_busyspin_wait_acquire (&testLock, 0 );
158+ assert (hasLock);
159+
160+ startTime = emscripten_get_now ();
161+
162+ emscripten_set_timeout_loop (MainLoop, 10 , NULL );
163+ EMSCRIPTEN_WEBAUDIO_T context = emscripten_create_audio_context (NULL );
164+ emscripten_start_wasm_audio_worklet_thread_async (context, wasmAudioWorkletStack, sizeof (wasmAudioWorkletStack), WebAudioWorkletThreadInitialized, NULL );
165+
166+ emscripten_exit_with_live_runtime ();
73167}
0 commit comments