1
- #include < emscripten/webaudio.h>
2
1
#include < emscripten/threading.h>
3
- #include < stdio .h>
4
- #include < stdlib .h>
2
+ #include < emscripten/wasm_worker .h>
3
+ #include < emscripten/webaudio .h>
5
4
#include < assert.h>
6
5
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()
15
15
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 );
18
18
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;
25
39
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 ;
28
46
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 ;
30
103
}
31
104
32
105
EM_JS (void , InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext), {
@@ -40,34 +113,55 @@ EM_JS(void, InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext), {
40
113
};
41
114
});
42
115
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 );
49
132
return false ;
133
+ default :
134
+ break ;
50
135
}
51
136
return true ;
52
137
}
53
138
54
139
void AudioWorkletProcessorCreated (EMSCRIPTEN_WEBAUDIO_T audioContext, bool success, void *userData) {
55
140
int outputChannelCounts[1 ] = { 1 };
56
141
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 );
58
143
emscripten_audio_node_connect (wasmAudioWorklet, audioContext, 0 , 0 );
59
144
InitHtmlUi (audioContext);
60
145
}
61
146
62
147
void WebAudioWorkletThreadInitialized (EMSCRIPTEN_WEBAUDIO_T audioContext, bool success, void *userData) {
63
148
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 );
65
150
}
66
151
67
- uint8_t wasmAudioWorkletStack[4096 ];
152
+ uint8_t wasmAudioWorkletStack[2048 ];
68
153
69
154
int 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 ();
73
167
}
0 commit comments