diff --git a/src/audio_worklet.js b/src/audio_worklet.js index 580af836f24ff..09c719063d6f3 100644 --- a/src/audio_worklet.js +++ b/src/audio_worklet.js @@ -251,7 +251,17 @@ function createWasmAudioWorkletProcessor() { return WasmAudioWorkletProcessor; } -var messagePort; +#if MIN_FIREFOX_VERSION < 138 || MIN_CHROME_VERSION != TARGET_NOT_SUPPORTED || MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED +// If this browser does not support the up-to-date AudioWorklet standard +// that has a MessagePort over to the AudioWorklet, then polyfill that by +// a hacky AudioWorkletProcessor that provides the MessagePort. +// Firefox added support in https://hg-edge.mozilla.org/integration/autoland/rev/ab38a1796126f2b3fc06475ffc5a625059af59c1 +// Chrome ticket: https://issues.chromium.org/issues/446920095 +// Safari ticket: https://bugs.webkit.org/show_bug.cgi?id=299386 +/** + * @suppress {duplicate, checkTypes} + */ +var port = globalThis.port || {}; // Specify a worklet processor that will be used to receive messages to this // AudioWorkletGlobalScope. We never connect this initial AudioWorkletProcessor @@ -260,47 +270,13 @@ class BootstrapMessages extends AudioWorkletProcessor { constructor(arg) { super(); startWasmWorker(arg.processorOptions) -#if WEBAUDIO_DEBUG - console.log('AudioWorklet global scope looks like this:'); - console.dir(globalThis); -#endif // Listen to messages from the main thread. These messages will ask this // scope to create the real AudioWorkletProcessors that call out to Wasm to // do audio processing. - messagePort = this.port; - /** @suppress {checkTypes} */ - messagePort.onmessage = async (msg) => { -#if MINIMAL_RUNTIME - // Wait for the module instantiation before processing messages. - await instantiatePromise; -#endif - let d = msg.data; - if (d['_wpn']) { - // '_wpn' is short for 'Worklet Processor Node', using an identifier - // that will never conflict with user messages - // Register a real AudioWorkletProcessor that will actually do audio processing. -#if AUDIO_WORKLET_SUPPORT_AUDIO_PARAMS - registerProcessor(d['_wpn'], createWasmAudioWorkletProcessor(d.audioParams)); -#else - registerProcessor(d['_wpn'], createWasmAudioWorkletProcessor()); -#endif -#if WEBAUDIO_DEBUG - console.log(`Registered a new WasmAudioWorkletProcessor "${d['_wpn']}" with AudioParams: ${d.audioParams}`); -#endif - // Post a Wasm Call message back telling that we have now registered the - // AudioWorkletProcessor, and should trigger the user onSuccess callback - // of the emscripten_create_wasm_audio_worklet_processor_async() call. - // - // '_wsc' is short for 'wasm call', using an identifier that will never - // conflict with user messages. - // - // Note: we convert the pointer arg manually here since the call site - // ($_EmAudioDispatchProcessorCallback) is used with various signatures - // and we do not know the types in advance. - messagePort.postMessage({'_wsc': d.callback, args: [d.contextHandle, 1/*EM_TRUE*/, {{{ to64('d.userData') }}}] }); - } else if (d['_wsc']) { - getWasmTableEntry(d['_wsc'])(...d.args); - }; + if (!(port instanceof MessagePort)) { + this.port.onmessage = port.onmessage; + /** @suppress {checkTypes} */ + port = this.port; } } @@ -317,5 +293,46 @@ class BootstrapMessages extends AudioWorkletProcessor { // Register the dummy processor that will just receive messages. registerProcessor('em-bootstrap', BootstrapMessages); +#endif + +port.onmessage = async (msg) => { +#if MINIMAL_RUNTIME + // Wait for the module instantiation before processing messages. + await instantiatePromise; +#endif + let d = msg.data; + if (d['_boot']) { + startWasmWorker(d); +#if WEBAUDIO_DEBUG + console.log('AudioWorklet global scope looks like this:'); + console.dir(globalThis); +#endif + } else if (d['_wpn']) { + // '_wpn' is short for 'Worklet Processor Node', using an identifier + // that will never conflict with user messages + // Register a real AudioWorkletProcessor that will actually do audio processing. +#if AUDIO_WORKLET_SUPPORT_AUDIO_PARAMS + registerProcessor(d['_wpn'], createWasmAudioWorkletProcessor(d.audioParams)); +#else + registerProcessor(d['_wpn'], createWasmAudioWorkletProcessor()); +#endif +#if WEBAUDIO_DEBUG + console.log(`Registered a new WasmAudioWorkletProcessor "${d['_wpn']}" with AudioParams: ${d.audioParams}`); +#endif + // Post a Wasm Call message back telling that we have now registered the + // AudioWorkletProcessor, and should trigger the user onSuccess callback + // of the emscripten_create_wasm_audio_worklet_processor_async() call. + // + // '_wsc' is short for 'wasm call', using an identifier that will never + // conflict with user messages. + // + // Note: we convert the pointer arg manually here since the call site + // ($_EmAudioDispatchProcessorCallback) is used with various signatures + // and we do not know the types in advance. + port.postMessage({'_wsc': d.callback, args: [d.contextHandle, 1/*EM_TRUE*/, {{{ to64('d.userData') }}}] }); + } else if (d['_wsc']) { + getWasmTableEntry(d['_wsc'])(...d.args); + }; +} } // ENVIRONMENT_IS_AUDIO_WORKLET diff --git a/src/closure-externs/audio-worklet-externs.js b/src/closure-externs/audio-worklet-externs.js new file mode 100644 index 0000000000000..45ba6da819d9b --- /dev/null +++ b/src/closure-externs/audio-worklet-externs.js @@ -0,0 +1,11 @@ +/* + * AudioWorkletGlobalScope globals + */ +var registerProcessor = function(name, obj) {}; +var currentFrame; +var currentTime; +var sampleRate; +/** + * @suppress {duplicate, checkTypes} + */ +var port; diff --git a/src/closure-externs/closure-externs.js b/src/closure-externs/closure-externs.js index b5bfc58576197..dbb17a89417aa 100644 --- a/src/closure-externs/closure-externs.js +++ b/src/closure-externs/closure-externs.js @@ -222,14 +222,6 @@ var outerHeight; var event; var devicePixelRatio; -/* - * AudioWorkletGlobalScope globals - */ -var registerProcessor = function(name, obj) {}; -var currentFrame; -var currentTime; -var sampleRate; - /* * Avoid closure minifying anything to "id". See #13965 */ diff --git a/src/lib/libwebaudio.js b/src/lib/libwebaudio.js index 5574ee7baedbc..69a324bd0564a 100644 --- a/src/lib/libwebaudio.js +++ b/src/lib/libwebaudio.js @@ -192,23 +192,49 @@ var LibraryWebAudio = { #if WEBAUDIO_DEBUG console.log(`emscripten_start_wasm_audio_worklet_thread_async() addModule() completed`); #endif - audioWorklet.bootstrapMessage = new AudioWorkletNode(audioContext, 'em-bootstrap', { - processorOptions: { - // Assign the loaded AudioWorkletGlobalScope a Wasm Worker ID so that - // it can utilized its own TLS slots, and it is recognized to not be - // the main browser thread. - wwID: _wasmWorkersID++, + +#if MIN_FIREFOX_VERSION < 138 || MIN_CHROME_VERSION != TARGET_NOT_SUPPORTED || MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED + // If this browser does not support the up-to-date AudioWorklet standard + // that has a MessagePort over to the AudioWorklet, then polyfill that by + // instantiating a dummy AudioWorkletNode to get a MessagePort over. + // Firefox added support in https://hg-edge.mozilla.org/integration/autoland/rev/ab38a1796126f2b3fc06475ffc5a625059af59c1 + // Chrome ticket: https://issues.chromium.org/issues/446920095 + // Safari ticket: https://bugs.webkit.org/show_bug.cgi?id=299386 + if (!audioWorklet['port']) { + audioWorklet['port'] = { + postMessage: (msg) => { + if (msg['_boot']) { + audioWorklet.bootstrapMessage = new AudioWorkletNode(audioContext, 'em-bootstrap', { + processorOptions: msg + }); + audioWorklet.bootstrapMessage['port'].onmessage = (msg) => { + audioWorklet['port'].onmessage(msg); + } + } else { + audioWorklet.bootstrapMessage['port'].postMessage(msg); + } + } + } + } +#endif + + audioWorklet['port'].postMessage({ + // This is the bootstrap message to the Audio Worklet. + '_boot': 1, + // Assign the loaded AudioWorkletGlobalScope a Wasm Worker ID so that + // it can utilized its own TLS slots, and it is recognized to not be + // the main browser thread. + wwID: _wasmWorkersID++, #if MINIMAL_RUNTIME - wasm: Module['wasm'], + wasm: Module['wasm'], #else - wasm: wasmModule, + wasm: wasmModule, #endif - wasmMemory, - stackLowestAddress, // sb = stack base - stackSize, // sz = stack size - } + wasmMemory, + stackLowestAddress, // sb = stack base + stackSize, // sz = stack size }); - audioWorklet.bootstrapMessage.port.onmessage = _EmAudioDispatchProcessorCallback; + audioWorklet['port'].onmessage = _EmAudioDispatchProcessorCallback; {{{ makeDynCall('viip', 'callback') }}}(contextHandle, 1/*EM_TRUE*/, userData); }).catch(audioWorkletCreationFailed); }, @@ -256,7 +282,7 @@ var LibraryWebAudio = { console.log(`emscripten_create_wasm_audio_worklet_processor_async() creating a new AudioWorklet processor with name ${processorName}`); #endif - EmAudio[contextHandle].audioWorklet.bootstrapMessage.port.postMessage({ + EmAudio[contextHandle].audioWorklet['port'].postMessage({ // Deliberately mangled and short names used here ('_wpn', the 'Worklet // Processor Name' used as a 'key' to verify the message type so as to // not get accidentally mixed with user submitted messages, the remainder @@ -334,11 +360,11 @@ var LibraryWebAudio = { emscripten_current_thread_is_audio_worklet: () => ENVIRONMENT_IS_AUDIO_WORKLET, emscripten_audio_worklet_post_function_v: (audioContext, funcPtr) => { - (audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : messagePort).postMessage({'_wsc': funcPtr, args: [] }); // "WaSm Call" + (audioContext ? EmAudio[audioContext].audioWorklet['port'] : port).postMessage({'_wsc': funcPtr, args: [] }); // "WaSm Call" }, $emscripten_audio_worklet_post_function_1: (audioContext, funcPtr, arg0) => { - (audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : messagePort).postMessage({'_wsc': funcPtr, args: [arg0] }); // "WaSm Call" + (audioContext ? EmAudio[audioContext].audioWorklet['port'] : port).postMessage({'_wsc': funcPtr, args: [arg0] }); // "WaSm Call" }, emscripten_audio_worklet_post_function_vi__deps: ['$emscripten_audio_worklet_post_function_1'], @@ -352,7 +378,7 @@ var LibraryWebAudio = { }, $emscripten_audio_worklet_post_function_2: (audioContext, funcPtr, arg0, arg1) => { - (audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : messagePort).postMessage({'_wsc': funcPtr, args: [arg0, arg1] }); // "WaSm Call" + (audioContext ? EmAudio[audioContext].audioWorklet['port'] : port).postMessage({'_wsc': funcPtr, args: [arg0, arg1] }); // "WaSm Call" }, emscripten_audio_worklet_post_function_vii__deps: ['$emscripten_audio_worklet_post_function_2'], @@ -366,7 +392,7 @@ var LibraryWebAudio = { }, $emscripten_audio_worklet_post_function_3: (audioContext, funcPtr, arg0, arg1, arg2) => { - (audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : messagePort).postMessage({'_wsc': funcPtr, args: [arg0, arg1, arg2] }); // "WaSm Call" + (audioContext ? EmAudio[audioContext].audioWorklet['port'] : port).postMessage({'_wsc': funcPtr, args: [arg0, arg1, arg2] }); // "WaSm Call" }, emscripten_audio_worklet_post_function_viii__deps: ['$emscripten_audio_worklet_post_function_3'], emscripten_audio_worklet_post_function_viii: (audioContext, funcPtr, arg0, arg1, arg2) => { @@ -386,7 +412,7 @@ var LibraryWebAudio = { 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.'); assert(varargs); #endif - (audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : messagePort).postMessage({'_wsc': funcPtr, args: readEmAsmArgs(sigPtr, varargs) }); + (audioContext ? EmAudio[audioContext].audioWorklet['port'] : port).postMessage({'_wsc': funcPtr, args: readEmAsmArgs(sigPtr, varargs) }); } }; diff --git a/test/codesize/audio_worklet_wasm.expected.js b/test/codesize/audio_worklet_wasm.expected.js index c9cb7d9562844..7b42f0b8fc59d 100644 --- a/test/codesize/audio_worklet_wasm.expected.js +++ b/test/codesize/audio_worklet_wasm.expected.js @@ -1,228 +1,236 @@ -var m = globalThis.Module || "undefined" != typeof Module ? Module : {}, q = !!globalThis.AudioWorkletGlobalScope, r = "em-ww" == globalThis.name || q, t, z, J, K, H, E, v, X, F, D, C, Y, A, Z; +var m = globalThis.Module || "undefined" != typeof Module ? Module : {}, r = !!globalThis.AudioWorkletGlobalScope, t = "em-ww" == globalThis.name || r, u, z, I, J, G, E, w, X, F, D, C, Y, A, Z; -function u(a) { - t = a; - v = a.L; - w(); +function v(a) { + u = a; + w = a.L; + x(); m ||= {}; m.wasm = a.G; y(); a.G = a.M = 0; } -r && !q && (onmessage = a => { +t && !r && (onmessage = a => { onmessage = null; - u(a.data); + v(a.data); }); -if (q) { - function a(e) { - class d extends AudioWorkletProcessor { - constructor(c) { +if (r) { + function a(b) { + class f extends AudioWorkletProcessor { + constructor(d) { super(); - c = c.processorOptions; - this.v = A.get(c.v); - this.A = c.A; - this.u = c.u; + d = d.processorOptions; + this.v = A.get(d.v); + this.A = d.A; + this.u = d.u; this.s = 4 * this.u; - this.B = Array(Math.min((t.F - 16) / this.s | 0, 64)); + this.B = Array(Math.min((u.F - 16) / this.s | 0, 64)); this.K(); } K() { - for (var c = C(), g = D(this.B.length * this.s) >> 2, f = this.B.length - 1; 0 <= f; f--) this.B[f] = E.subarray(g, g += this.u); - F(c); + for (var d = C(), g = D(this.B.length * this.s) >> 2, e = this.B.length - 1; 0 <= e; e--) this.B[e] = E.subarray(g, g += this.u); + F(d); } static get parameterDescriptors() { - return e; + return b; } - process(c, g, f) { - var n = c.length, x = g.length, k, p, h = 12 * (n + x), l = 0; - for (k of c) l += k.length; + process(d, g, e) { + var n = d.length, p = g.length, h, q, k = 12 * (n + p), l = 0; + for (h of d) l += h.length; l *= this.s; - var G = 0; - for (k of g) G += k.length; - l += G * this.s; - var O = 0; - for (k in f) ++O, h += 8, l += f[k].byteLength; - var V = C(), B = h + l + 15 & -16; - h = D(B); - l = h + (B - l); - B = h; - for (k of c) { - H[h >> 2] = k.length; - H[h + 4 >> 2] = this.u; - H[h + 8 >> 2] = l; - h += 12; - for (p of k) E.set(p, l >> 2), l += this.s; + var H = 0; + for (h of g) H += h.length; + l += H * this.s; + var N = 0; + for (h in e) ++N, k += 8, l += e[h].byteLength; + var U = C(), B = k + l + 15 & -16; + k = D(B); + l = k + (B - l); + B = k; + for (h of d) { + G[k >> 2] = h.length; + G[k + 4 >> 2] = this.u; + G[k + 8 >> 2] = l; + k += 12; + for (q of h) E.set(q, l >> 2), l += this.s; } - c = h; - for (k = 0; p = f[k++]; ) H[h >> 2] = p.length, H[h + 4 >> 2] = l, h += 8, E.set(p, l >> 2), - l += 4 * p.length; - f = h; - for (k of g) H[h >> 2] = k.length, H[h + 4 >> 2] = this.u, H[h + 8 >> 2] = l, h += 12, - l += this.s * k.length; - if (n = this.v(n, B, x, f, O, c, this.A)) for (k of g) for (p of k) p.set(this.B[--G]); - F(V); + d = k; + for (h = 0; q = e[h++]; ) G[k >> 2] = q.length, G[k + 4 >> 2] = l, k += 8, E.set(q, l >> 2), + l += 4 * q.length; + e = k; + for (h of g) G[k >> 2] = h.length, G[k + 4 >> 2] = this.u, G[k + 8 >> 2] = l, k += 12, + l += this.s * h.length; + if (n = this.v(n, B, p, e, N, d, this.A)) for (h of g) for (q of h) q.set(this.B[--H]); + F(U); return !!n; } } - return d; + return f; } - var I; - class b extends AudioWorkletProcessor { - constructor(e) { + var port = globalThis.port || {}; + class c extends AudioWorkletProcessor { + constructor(b) { super(); - u(e.processorOptions); - I = this.port; - I.onmessage = async d => { - await z; - d = d.data; - d._wpn ? (registerProcessor(d._wpn, a(d.H)), I.postMessage({ - _wsc: d.v, - C: [ d.I, 1, d.A ] - })) : d._wsc && A.get(d._wsc)(...d.C); - }; + v(b.processorOptions); + port instanceof MessagePort || (this.port.onmessage = port.onmessage, port = this.port); } process() {} } - registerProcessor("em-bootstrap", b); + registerProcessor("em-bootstrap", c); + port.onmessage = async b => { + await z; + b = b.data; + b._boot ? v(b) : b._wpn ? (registerProcessor(b._wpn, a(b.H)), port.postMessage({ + _wsc: b.v, + C: [ b.I, 1, b.A ] + })) : b._wsc && A.get(b._wsc)(...b.C); + }; } -function w() { - var a = v.buffer; - J = new Uint8Array(a); - K = new Int32Array(a); - H = new Uint32Array(a); +function x() { + var a = w.buffer; + I = new Uint8Array(a); + J = new Int32Array(a); + G = new Uint32Array(a); E = new Float32Array(a); } -r || (v = m.mem || new WebAssembly.Memory({ +t || (w = m.mem || new WebAssembly.Memory({ initial: 256, maximum: 256, shared: !0 -}), w()); +}), x()); -var L = [], M = a => { +var K = [], L = a => { a = a.data; - let b = a._wsc; - b && A.get(b)(...a.x); -}, N = a => { - L.push(a); -}, Q = (a, b, e, d) => { - b = P[b]; - P[a].connect(b.destination || b, e, d); -}, P = {}, R = 0, S = globalThis.TextDecoder ? new TextDecoder : void 0, T = (a = 0) => { - for (var b = J, e = a, d = e + void 0; b[e] && !(e >= d); ) ++e; - if (16 < e - a && b.buffer && S) return S.decode(b.slice(a, e)); - for (d = ""; a < e; ) { - var c = b[a++]; - if (c & 128) { - var g = b[a++] & 63; - if (192 == (c & 224)) d += String.fromCharCode((c & 31) << 6 | g); else { - var f = b[a++] & 63; - c = 224 == (c & 240) ? (c & 15) << 12 | g << 6 | f : (c & 7) << 18 | g << 12 | f << 6 | b[a++] & 63; - 65536 > c ? d += String.fromCharCode(c) : (c -= 65536, d += String.fromCharCode(55296 | c >> 10, 56320 | c & 1023)); + let c = a._wsc; + c && A.get(c)(...a.x); +}, M = a => { + K.push(a); +}, P = (a, c, b, f) => { + c = O[c]; + O[a].connect(c.destination || c, b, f); +}, O = {}, Q = 0, R = globalThis.TextDecoder ? new TextDecoder : void 0, S = (a = 0) => { + for (var c = I, b = a, f = b + void 0; c[b] && !(b >= f); ) ++b; + if (16 < b - a && c.buffer && R) return R.decode(c.slice(a, b)); + for (f = ""; a < b; ) { + var d = c[a++]; + if (d & 128) { + var g = c[a++] & 63; + if (192 == (d & 224)) f += String.fromCharCode((d & 31) << 6 | g); else { + var e = c[a++] & 63; + d = 224 == (d & 240) ? (d & 15) << 12 | g << 6 | e : (d & 7) << 18 | g << 12 | e << 6 | c[a++] & 63; + 65536 > d ? f += String.fromCharCode(d) : (d -= 65536, f += String.fromCharCode(55296 | d >> 10, 56320 | d & 1023)); } - } else d += String.fromCharCode(c); + } else f += String.fromCharCode(d); } - return d; -}, U = a => { + return f; +}, T = a => { if (a) { - var b = H[a >> 2]; + var c = G[a >> 2]; a = { - latencyHint: (b ? T(b) : "") || void 0, - sampleRate: H[a + 4 >> 2] || void 0 + latencyHint: (c ? S(c) : "") || void 0, + sampleRate: G[a + 4 >> 2] || void 0 }; } else a = void 0; a = new AudioContext(a); - P[++R] = a; - return R; -}, W = (a, b, e, d, c) => { - var g = e ? K[e + 4 >> 2] : 0; - if (e) { - var f = K[e >> 2]; - e = H[e + 8 >> 2]; + O[++Q] = a; + return Q; +}, V = (a, c, b, f, d) => { + var g = b ? J[b + 4 >> 2] : 0; + if (b) { + var e = J[b >> 2]; + b = G[b + 8 >> 2]; var n = g; - if (e) { - e >>= 2; - for (var x = []; n--; ) x.push(H[e++]); - e = x; - } else e = void 0; - d = { - numberOfInputs: f, + if (b) { + b >>= 2; + for (var p = []; n--; ) p.push(G[b++]); + b = p; + } else b = void 0; + f = { + numberOfInputs: e, numberOfOutputs: g, - outputChannelCount: e, + outputChannelCount: b, processorOptions: { - v: d, - A: c, + v: f, + A: d, u: 128 } }; - } else d = void 0; - a = new AudioWorkletNode(P[a], b ? T(b) : "", d); - P[++R] = a; - return R; -}, aa = (a, b, e, d) => { - var c = (c = H[b >> 2]) ? T(c) : "", g = K[b + 4 >> 2]; - b = H[b + 8 >> 2]; - for (var f = [], n = 0; g--; ) f.push({ + } else f = void 0; + a = new AudioWorkletNode(O[a], c ? S(c) : "", f); + O[++Q] = a; + return Q; +}, W = (a, c, b, f) => { + var d = (d = G[c >> 2]) ? S(d) : "", g = J[c + 4 >> 2]; + c = G[c + 8 >> 2]; + for (var e = [], n = 0; g--; ) e.push({ name: n++, - defaultValue: E[b >> 2], - minValue: E[b + 4 >> 2], - maxValue: E[b + 8 >> 2], - automationRate: (K[b + 12 >> 2] ? "k" : "a") + "-rate" - }), b += 16; - P[a].audioWorklet.D.port.postMessage({ - _wpn: c, - H: f, + defaultValue: E[c >> 2], + minValue: E[c + 4 >> 2], + maxValue: E[c + 8 >> 2], + automationRate: (J[c + 12 >> 2] ? "k" : "a") + "-rate" + }), c += 16; + O[a].audioWorklet.port.postMessage({ + _wpn: d, + H: e, I: a, - v: e, - A: d + v: b, + A: f }); -}, ba = () => !1, ca = 1, da = a => { +}, aa = () => !1, ba = 1, ca = a => { a = a.data; - var b = a._wsc; - b && A.get(b)(...a.C); -}, ea = (a, b, e, d, c) => { - var g = P[a], f = g.audioWorklet, n = () => { - A.get(d)(a, 0, c); + var c = a._wsc; + c && A.get(c)(...a.C); +}, da = (a, c, b, f, d) => { + var g = O[a], e = g.audioWorklet, n = () => { + A.get(f)(a, 0, d); }; - if (!f) return n(); - f.addModule(m.js).then((() => { - f.D = new AudioWorkletNode(g, "em-bootstrap", { - processorOptions: { - N: ca++, - G: m.wasm, - L: v, - J: b, - F: e + if (!e) return n(); + e.addModule(m.js).then((() => { + e.port || (e.port = { + postMessage: p => { + p._boot ? (e.D = new AudioWorkletNode(g, "em-bootstrap", { + processorOptions: p + }), e.D.port.onmessage = h => { + e.port.onmessage(h); + }) : e.D.port.postMessage(p); } }); - f.D.port.onmessage = da; - A.get(d)(a, 1, c); + e.port.postMessage({ + _boot: 1, + N: ba++, + G: m.wasm, + L: w, + J: c, + F: b + }); + e.port.onmessage = ca; + A.get(f)(a, 1, d); })).catch(n); }; -function fa(a) { - let b = document.createElement("button"); - b.innerHTML = "Toggle playback"; - document.body.appendChild(b); - a = P[a]; - b.onclick = () => { +function ea(a) { + let c = document.createElement("button"); + c.innerHTML = "Toggle playback"; + document.body.appendChild(c); + a = O[a]; + c.onclick = () => { "running" != a.state ? a.resume() : a.suspend(); }; } function y() { Z = { - f: fa, - g: Q, - d: U, - h: W, - e: aa, - b: ba, - c: ea, - a: v + f: ea, + g: P, + d: T, + h: V, + e: W, + b: aa, + c: da, + a: w }; z = WebAssembly.instantiate(m.wasm, { a: Z @@ -234,9 +242,9 @@ function y() { C = a.n; Y = a.o; A = a.k; - r ? (Y(t.J, t.F), q || (removeEventListener("message", N), L = L.forEach(M), addEventListener("message", M))) : a.i(); - r || X(); + t ? (Y(u.J, u.F), r || (removeEventListener("message", M), K = K.forEach(L), addEventListener("message", L))) : a.i(); + t || X(); })); } -r || y(); \ No newline at end of file +t || y(); \ No newline at end of file diff --git a/test/codesize/test_minimal_runtime_code_size_audio_worklet.json b/test/codesize/test_minimal_runtime_code_size_audio_worklet.json index 3b300a7165dfc..0df0a1a9df5fc 100644 --- a/test/codesize/test_minimal_runtime_code_size_audio_worklet.json +++ b/test/codesize/test_minimal_runtime_code_size_audio_worklet.json @@ -1,10 +1,10 @@ { "a.html": 519, "a.html.gz": 357, - "a.js": 3859, - "a.js.gz": 2037, + "a.js": 4108, + "a.js.gz": 2104, "a.wasm": 1308, "a.wasm.gz": 876, - "total": 5686, - "total_gz": 3270 + "total": 5935, + "total_gz": 3337 } diff --git a/tools/building.py b/tools/building.py index 69e0fec9f9a69..4f02511804ed4 100644 --- a/tools/building.py +++ b/tools/building.py @@ -563,6 +563,9 @@ def closure_compiler(filename, advanced=True, extra_closure_args=None): if settings.USE_WEBGPU: CLOSURE_EXTERNS += [path_from_root('src/closure-externs/webgpu-externs.js')] + if settings.AUDIO_WORKLET: + CLOSURE_EXTERNS += [path_from_root('src/closure-externs/audio-worklet-externs.js')] + # Closure compiler needs to know about all exports that come from the wasm module, because to optimize for small code size, # the exported symbols are added to global scope via a foreach loop in a way that evades Closure's static analysis. With an explicit # externs file for the exports, Closure is able to reason about the exports.