Skip to content

Commit 353db4a

Browse files
authored
Avoid the Web Audio Worklet bootstrap processor node on browsers that support AudioWorkletScope port (#25354)
Remove the redundant Web Audio Worklet bootstrap processor node after WebAudio/web-audio-api#2456 has been fixed.
1 parent bea78f1 commit 353db4a

File tree

7 files changed

+288
-231
lines changed

7 files changed

+288
-231
lines changed

src/audio_worklet.js

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,17 @@ function createWasmAudioWorkletProcessor() {
251251
return WasmAudioWorkletProcessor;
252252
}
253253

254-
var messagePort;
254+
#if MIN_FIREFOX_VERSION < 138 || MIN_CHROME_VERSION != TARGET_NOT_SUPPORTED || MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED
255+
// If this browser does not support the up-to-date AudioWorklet standard
256+
// that has a MessagePort over to the AudioWorklet, then polyfill that by
257+
// a hacky AudioWorkletProcessor that provides the MessagePort.
258+
// Firefox added support in https://hg-edge.mozilla.org/integration/autoland/rev/ab38a1796126f2b3fc06475ffc5a625059af59c1
259+
// Chrome ticket: https://issues.chromium.org/issues/446920095
260+
// Safari ticket: https://bugs.webkit.org/show_bug.cgi?id=299386
261+
/**
262+
* @suppress {duplicate, checkTypes}
263+
*/
264+
var port = globalThis.port || {};
255265

256266
// Specify a worklet processor that will be used to receive messages to this
257267
// AudioWorkletGlobalScope. We never connect this initial AudioWorkletProcessor
@@ -260,47 +270,13 @@ class BootstrapMessages extends AudioWorkletProcessor {
260270
constructor(arg) {
261271
super();
262272
startWasmWorker(arg.processorOptions)
263-
#if WEBAUDIO_DEBUG
264-
console.log('AudioWorklet global scope looks like this:');
265-
console.dir(globalThis);
266-
#endif
267273
// Listen to messages from the main thread. These messages will ask this
268274
// scope to create the real AudioWorkletProcessors that call out to Wasm to
269275
// do audio processing.
270-
messagePort = this.port;
271-
/** @suppress {checkTypes} */
272-
messagePort.onmessage = async (msg) => {
273-
#if MINIMAL_RUNTIME
274-
// Wait for the module instantiation before processing messages.
275-
await instantiatePromise;
276-
#endif
277-
let d = msg.data;
278-
if (d['_wpn']) {
279-
// '_wpn' is short for 'Worklet Processor Node', using an identifier
280-
// that will never conflict with user messages
281-
// Register a real AudioWorkletProcessor that will actually do audio processing.
282-
#if AUDIO_WORKLET_SUPPORT_AUDIO_PARAMS
283-
registerProcessor(d['_wpn'], createWasmAudioWorkletProcessor(d.audioParams));
284-
#else
285-
registerProcessor(d['_wpn'], createWasmAudioWorkletProcessor());
286-
#endif
287-
#if WEBAUDIO_DEBUG
288-
console.log(`Registered a new WasmAudioWorkletProcessor "${d['_wpn']}" with AudioParams: ${d.audioParams}`);
289-
#endif
290-
// Post a Wasm Call message back telling that we have now registered the
291-
// AudioWorkletProcessor, and should trigger the user onSuccess callback
292-
// of the emscripten_create_wasm_audio_worklet_processor_async() call.
293-
//
294-
// '_wsc' is short for 'wasm call', using an identifier that will never
295-
// conflict with user messages.
296-
//
297-
// Note: we convert the pointer arg manually here since the call site
298-
// ($_EmAudioDispatchProcessorCallback) is used with various signatures
299-
// and we do not know the types in advance.
300-
messagePort.postMessage({'_wsc': d.callback, args: [d.contextHandle, 1/*EM_TRUE*/, {{{ to64('d.userData') }}}] });
301-
} else if (d['_wsc']) {
302-
getWasmTableEntry(d['_wsc'])(...d.args);
303-
};
276+
if (!(port instanceof MessagePort)) {
277+
this.port.onmessage = port.onmessage;
278+
/** @suppress {checkTypes} */
279+
port = this.port;
304280
}
305281
}
306282

@@ -317,5 +293,46 @@ class BootstrapMessages extends AudioWorkletProcessor {
317293

318294
// Register the dummy processor that will just receive messages.
319295
registerProcessor('em-bootstrap', BootstrapMessages);
296+
#endif
297+
298+
port.onmessage = async (msg) => {
299+
#if MINIMAL_RUNTIME
300+
// Wait for the module instantiation before processing messages.
301+
await instantiatePromise;
302+
#endif
303+
let d = msg.data;
304+
if (d['_boot']) {
305+
startWasmWorker(d);
306+
#if WEBAUDIO_DEBUG
307+
console.log('AudioWorklet global scope looks like this:');
308+
console.dir(globalThis);
309+
#endif
310+
} else if (d['_wpn']) {
311+
// '_wpn' is short for 'Worklet Processor Node', using an identifier
312+
// that will never conflict with user messages
313+
// Register a real AudioWorkletProcessor that will actually do audio processing.
314+
#if AUDIO_WORKLET_SUPPORT_AUDIO_PARAMS
315+
registerProcessor(d['_wpn'], createWasmAudioWorkletProcessor(d.audioParams));
316+
#else
317+
registerProcessor(d['_wpn'], createWasmAudioWorkletProcessor());
318+
#endif
319+
#if WEBAUDIO_DEBUG
320+
console.log(`Registered a new WasmAudioWorkletProcessor "${d['_wpn']}" with AudioParams: ${d.audioParams}`);
321+
#endif
322+
// Post a Wasm Call message back telling that we have now registered the
323+
// AudioWorkletProcessor, and should trigger the user onSuccess callback
324+
// of the emscripten_create_wasm_audio_worklet_processor_async() call.
325+
//
326+
// '_wsc' is short for 'wasm call', using an identifier that will never
327+
// conflict with user messages.
328+
//
329+
// Note: we convert the pointer arg manually here since the call site
330+
// ($_EmAudioDispatchProcessorCallback) is used with various signatures
331+
// and we do not know the types in advance.
332+
port.postMessage({'_wsc': d.callback, args: [d.contextHandle, 1/*EM_TRUE*/, {{{ to64('d.userData') }}}] });
333+
} else if (d['_wsc']) {
334+
getWasmTableEntry(d['_wsc'])(...d.args);
335+
};
336+
}
320337

321338
} // ENVIRONMENT_IS_AUDIO_WORKLET
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* AudioWorkletGlobalScope globals
3+
*/
4+
var registerProcessor = function(name, obj) {};
5+
var currentFrame;
6+
var currentTime;
7+
var sampleRate;
8+
/**
9+
* @suppress {duplicate, checkTypes}
10+
*/
11+
var port;

src/closure-externs/closure-externs.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -222,14 +222,6 @@ var outerHeight;
222222
var event;
223223
var devicePixelRatio;
224224

225-
/*
226-
* AudioWorkletGlobalScope globals
227-
*/
228-
var registerProcessor = function(name, obj) {};
229-
var currentFrame;
230-
var currentTime;
231-
var sampleRate;
232-
233225
/*
234226
* Avoid closure minifying anything to "id". See #13965
235227
*/

src/lib/libwebaudio.js

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -192,23 +192,49 @@ var LibraryWebAudio = {
192192
#if WEBAUDIO_DEBUG
193193
console.log(`emscripten_start_wasm_audio_worklet_thread_async() addModule() completed`);
194194
#endif
195-
audioWorklet.bootstrapMessage = new AudioWorkletNode(audioContext, 'em-bootstrap', {
196-
processorOptions: {
197-
// Assign the loaded AudioWorkletGlobalScope a Wasm Worker ID so that
198-
// it can utilized its own TLS slots, and it is recognized to not be
199-
// the main browser thread.
200-
wwID: _wasmWorkersID++,
195+
196+
#if MIN_FIREFOX_VERSION < 138 || MIN_CHROME_VERSION != TARGET_NOT_SUPPORTED || MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED
197+
// If this browser does not support the up-to-date AudioWorklet standard
198+
// that has a MessagePort over to the AudioWorklet, then polyfill that by
199+
// instantiating a dummy AudioWorkletNode to get a MessagePort over.
200+
// Firefox added support in https://hg-edge.mozilla.org/integration/autoland/rev/ab38a1796126f2b3fc06475ffc5a625059af59c1
201+
// Chrome ticket: https://issues.chromium.org/issues/446920095
202+
// Safari ticket: https://bugs.webkit.org/show_bug.cgi?id=299386
203+
if (!audioWorklet['port']) {
204+
audioWorklet['port'] = {
205+
postMessage: (msg) => {
206+
if (msg['_boot']) {
207+
audioWorklet.bootstrapMessage = new AudioWorkletNode(audioContext, 'em-bootstrap', {
208+
processorOptions: msg
209+
});
210+
audioWorklet.bootstrapMessage['port'].onmessage = (msg) => {
211+
audioWorklet['port'].onmessage(msg);
212+
}
213+
} else {
214+
audioWorklet.bootstrapMessage['port'].postMessage(msg);
215+
}
216+
}
217+
}
218+
}
219+
#endif
220+
221+
audioWorklet['port'].postMessage({
222+
// This is the bootstrap message to the Audio Worklet.
223+
'_boot': 1,
224+
// Assign the loaded AudioWorkletGlobalScope a Wasm Worker ID so that
225+
// it can utilized its own TLS slots, and it is recognized to not be
226+
// the main browser thread.
227+
wwID: _wasmWorkersID++,
201228
#if MINIMAL_RUNTIME
202-
wasm: Module['wasm'],
229+
wasm: Module['wasm'],
203230
#else
204-
wasm: wasmModule,
231+
wasm: wasmModule,
205232
#endif
206-
wasmMemory,
207-
stackLowestAddress, // sb = stack base
208-
stackSize, // sz = stack size
209-
}
233+
wasmMemory,
234+
stackLowestAddress, // sb = stack base
235+
stackSize, // sz = stack size
210236
});
211-
audioWorklet.bootstrapMessage.port.onmessage = _EmAudioDispatchProcessorCallback;
237+
audioWorklet['port'].onmessage = _EmAudioDispatchProcessorCallback;
212238
{{{ makeDynCall('viip', 'callback') }}}(contextHandle, 1/*EM_TRUE*/, userData);
213239
}).catch(audioWorkletCreationFailed);
214240
},
@@ -256,7 +282,7 @@ var LibraryWebAudio = {
256282
console.log(`emscripten_create_wasm_audio_worklet_processor_async() creating a new AudioWorklet processor with name ${processorName}`);
257283
#endif
258284

259-
EmAudio[contextHandle].audioWorklet.bootstrapMessage.port.postMessage({
285+
EmAudio[contextHandle].audioWorklet['port'].postMessage({
260286
// Deliberately mangled and short names used here ('_wpn', the 'Worklet
261287
// Processor Name' used as a 'key' to verify the message type so as to
262288
// not get accidentally mixed with user submitted messages, the remainder
@@ -342,11 +368,11 @@ var LibraryWebAudio = {
342368
emscripten_current_thread_is_audio_worklet: () => ENVIRONMENT_IS_AUDIO_WORKLET,
343369

344370
emscripten_audio_worklet_post_function_v: (audioContext, funcPtr) => {
345-
(audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : messagePort).postMessage({'_wsc': funcPtr, args: [] }); // "WaSm Call"
371+
(audioContext ? EmAudio[audioContext].audioWorklet['port'] : port).postMessage({'_wsc': funcPtr, args: [] }); // "WaSm Call"
346372
},
347373

348374
$emscripten_audio_worklet_post_function_1: (audioContext, funcPtr, arg0) => {
349-
(audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : messagePort).postMessage({'_wsc': funcPtr, args: [arg0] }); // "WaSm Call"
375+
(audioContext ? EmAudio[audioContext].audioWorklet['port'] : port).postMessage({'_wsc': funcPtr, args: [arg0] }); // "WaSm Call"
350376
},
351377

352378
emscripten_audio_worklet_post_function_vi__deps: ['$emscripten_audio_worklet_post_function_1'],
@@ -360,7 +386,7 @@ var LibraryWebAudio = {
360386
},
361387

362388
$emscripten_audio_worklet_post_function_2: (audioContext, funcPtr, arg0, arg1) => {
363-
(audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : messagePort).postMessage({'_wsc': funcPtr, args: [arg0, arg1] }); // "WaSm Call"
389+
(audioContext ? EmAudio[audioContext].audioWorklet['port'] : port).postMessage({'_wsc': funcPtr, args: [arg0, arg1] }); // "WaSm Call"
364390
},
365391

366392
emscripten_audio_worklet_post_function_vii__deps: ['$emscripten_audio_worklet_post_function_2'],
@@ -374,7 +400,7 @@ var LibraryWebAudio = {
374400
},
375401

376402
$emscripten_audio_worklet_post_function_3: (audioContext, funcPtr, arg0, arg1, arg2) => {
377-
(audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : messagePort).postMessage({'_wsc': funcPtr, args: [arg0, arg1, arg2] }); // "WaSm Call"
403+
(audioContext ? EmAudio[audioContext].audioWorklet['port'] : port).postMessage({'_wsc': funcPtr, args: [arg0, arg1, arg2] }); // "WaSm Call"
378404
},
379405
emscripten_audio_worklet_post_function_viii__deps: ['$emscripten_audio_worklet_post_function_3'],
380406
emscripten_audio_worklet_post_function_viii: (audioContext, funcPtr, arg0, arg1, arg2) => {
@@ -394,7 +420,7 @@ var LibraryWebAudio = {
394420
assert(UTF8ToString(sigPtr)[0] != 'v', 'Do NOT specify the return argument in the signature string for a call to emscripten_audio_worklet_post_function_sig(), just pass the function arguments.');
395421
assert(varargs);
396422
#endif
397-
(audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : messagePort).postMessage({'_wsc': funcPtr, args: readEmAsmArgs(sigPtr, varargs) });
423+
(audioContext ? EmAudio[audioContext].audioWorklet['port'] : port).postMessage({'_wsc': funcPtr, args: readEmAsmArgs(sigPtr, varargs) });
398424
}
399425
};
400426

0 commit comments

Comments
 (0)