Skip to content

Commit a11c913

Browse files
committed
[AUDIO_WORKLET] Wait for Wasm instance to start using audio worklet.
This fixes intermittent test failures where the AudioWorklet was used before the Wasm module was loaded.
1 parent 391ce69 commit a11c913

File tree

9 files changed

+43
-23
lines changed

9 files changed

+43
-23
lines changed

src/audio_worklet.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ class BootstrapMessages extends AudioWorkletProcessor {
153153
messagePort = this.port;
154154
/** @suppress {checkTypes} */
155155
messagePort.onmessage = async (msg) => {
156+
// Wait for the Wasm module to be instantiated.
157+
await readyPromise;
156158
let d = msg.data;
157159
if (d['_wpn']) {
158160
// '_wpn' is short for 'Worklet Processor Node', using an identifier
@@ -170,6 +172,8 @@ class BootstrapMessages extends AudioWorkletProcessor {
170172
// conflict with user messages
171173
messagePort.postMessage({'_wsc': d.callback, args: [d.contextHandle, 1/*EM_TRUE*/, d.userData] });
172174
} else if (d['_wsc']) {
175+
// Wait for the Wasm module to be instantiated.
176+
await readyPromise;
173177
getWasmTableEntry(d['_wsc'])(...d.args);
174178
};
175179
}

src/lib/libcore.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ addToLibrary({
117117
// if exit() was called explicitly, warn the user if the runtime isn't actually being shut down
118118
if (keepRuntimeAlive() && !implicit) {
119119
var msg = `program exited (with status: ${status}), but keepRuntimeAlive() is set (counter=${runtimeKeepaliveCounter}) due to an async operation, so halting execution but not exiting the runtime or preventing further async execution (you can use emscripten_force_exit, if you want to force a true shutdown)`;
120-
#if MODULARIZE
120+
#if USE_READY_PROMISE
121121
readyPromiseReject?.(msg);
122122
#endif // MODULARIZE
123123
err(msg);

src/postamble.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ function run() {
139139

140140
#if PTHREADS || WASM_WORKERS
141141
if ({{{ ENVIRONMENT_IS_WORKER_THREAD() }}}) {
142-
#if MODULARIZE
142+
#if USE_READY_PROMISE
143143
readyPromiseResolve?.(Module);
144144
#endif
145145
initRuntime();
@@ -179,7 +179,7 @@ function run() {
179179
preMain();
180180
#endif
181181

182-
#if MODULARIZE
182+
#if USE_READY_PROMISE
183183
readyPromiseResolve?.(Module);
184184
#endif
185185
#if expectToReceiveOnModule('onRuntimeInitialized')

src/postamble_modularize.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@ if (runtimeInitialized) {
1111
moduleRtn = Module;
1212
} else {
1313
// Set up the promise that indicates the Module is initialized
14-
moduleRtn = new Promise((resolve, reject) => {
15-
readyPromiseResolve = resolve;
16-
readyPromiseReject = reject;
17-
});
14+
moduleRtn = readyPromise = createReadyPromise();
1815
}
1916
#else
2017
moduleRtn = {};

src/preamble.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ function abort(what) {
363363
/** @suppress {checkTypes} */
364364
var e = new WebAssembly.RuntimeError(what);
365365

366-
#if MODULARIZE
366+
#if USE_READY_PROMISE
367367
readyPromiseReject?.(e);
368368
#endif
369369
// Throw the error whether or not MODULARIZE is set because abort is used

src/runtime_common.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,21 @@
2020
#include "runtime_asan.js"
2121
#endif
2222

23-
#if MODULARIZE && USE_READY_PROMISE
24-
var readyPromiseResolve, readyPromiseReject;
23+
#if USE_READY_PROMISE
24+
var readyPromise, readyPromiseResolve, readyPromiseReject;
25+
function createReadyPromise() {
26+
#if ASSERTIONS
27+
assert(!readyPromise, 'Ready promise already initialized.');
28+
#endif
29+
return new Promise((resolve, reject) => {
30+
readyPromiseResolve = resolve;
31+
readyPromiseReject = reject;
32+
});
33+
}
34+
#if !MODULARIZE
35+
// Modularize mode handles initializing the ready promise.
36+
readyPromise = createReadyPromise();
37+
#endif
2538
#endif
2639

2740
#if PTHREADS || WASM_WORKERS

src/settings_internal.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,10 @@ var WASM_EXCEPTIONS = false;
191191
// EXPORTED_FUNCTIONS then this gets set to 0.
192192
var EXPECT_MAIN = true;
193193

194-
// Return a "ready" Promise from the MODULARIZE factory function.
195-
// We disable this under some circumstance if we know its not needed.
196-
var USE_READY_PROMISE = true;
194+
// Create a "ready" Promise that is resolved when the Wasm instance is ready.
195+
// In MODULARIZE mode this Promise is returned from the factory function.
196+
// We omit the Promise under some circumstance if we know it's not needed.
197+
var USE_READY_PROMISE = false;
197198

198199
// If true, building against Emscripten's wasm heap memory profiler.
199200
var MEMORYPROFILER = false;

src/shell_minimal.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@ var err = (...args) => console.error(...args);
116116
// compilation is ready. In that callback, call the function run() to start
117117
// the program.
118118
function ready() {
119-
#if MODULARIZE && USE_READY_PROMISE
119+
#if USE_READY_PROMISE
120120
readyPromiseResolve?.(Module);
121-
#endif // MODULARIZE
121+
#endif
122122
#if INVOKE_RUN && HAS_MAIN
123123
{{{ runIfMainThread("run();") }}}
124124
#elif ASSERTIONS

tools/link.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,15 +1221,20 @@ def limit_incoming_module_api():
12211221
if settings.STACK_OVERFLOW_CHECK >= 2:
12221222
settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$setStackLimits']
12231223

1224-
if settings.MODULARIZE:
1225-
if settings.PROXY_TO_WORKER:
1224+
if settings.MODULARIZE and settings.PROXY_TO_WORKER:
12261225
exit_with_error('-sMODULARIZE is not compatible with --proxy-to-worker (if you want to run in a worker with -sMODULARIZE, you likely want to do the worker side setup manually)')
1227-
# in MINIMAL_RUNTIME we may not need to emit the Promise code, as the
1228-
# HTML output creates a singleton instance, and it does so without the
1229-
# Promise. However, in Pthreads mode the Promise is used for worker
1230-
# creation.
1231-
if settings.MINIMAL_RUNTIME and options.oformat == OFormat.HTML and not settings.PTHREADS:
1232-
settings.USE_READY_PROMISE = 0
1226+
1227+
if settings.AUDIO_WORKLET:
1228+
# The audio worklet needs to wait for the Wasm module to be instantiated
1229+
# before it begins processing.
1230+
settings.USE_READY_PROMISE = 1
1231+
elif settings.MODULARIZE and (not settings.MINIMAL_RUNTIME or options.oformat != OFormat.HTML or settings.PTHREADS):
1232+
# Modularize usually requires the ready promise code, but in certain cases
1233+
# can be omitted. In MINIMAL_RUNTIME we may not need to emit the Promise
1234+
# code, as the HTML output creates a singleton instance, and it does so
1235+
# without the Promise. However, in Pthreads mode the Promise is used for
1236+
# worker creation.
1237+
settings.USE_READY_PROMISE = 1
12331238

12341239
check_browser_versions()
12351240

0 commit comments

Comments
 (0)