From c2952bb2513401d9c7a349ba1d183d7a2dcaa69f Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Fri, 7 Nov 2025 16:16:31 +0100 Subject: [PATCH 1/7] Add support for setting the render quantum size --- src/audio_worklet.js | 4 ++++ src/lib/libwebaudio.js | 15 ++++++++------- src/struct_info.json | 3 ++- src/struct_info_generated.json | 3 ++- src/struct_info_generated_wasm64.json | 1 + system/include/emscripten/webaudio.h | 6 ++++++ test/webaudio/audioworklet_params_mixing.c | 8 ++++++++ test/webaudio/audioworklet_test_shared.inc | 6 +++++- 8 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/audio_worklet.js b/src/audio_worklet.js index ab8dfa2d9ef66..dc2c4eac3bce3 100644 --- a/src/audio_worklet.js +++ b/src/audio_worklet.js @@ -154,6 +154,10 @@ function createWasmAudioWorkletProcessor() { var stackMemoryAligned = (stackMemoryStruct + stackMemoryData + 15) & ~15; var structPtr = stackAlloc(stackMemoryAligned); var dataPtr = structPtr + (stackMemoryAligned - stackMemoryData); +#if ASSERTIONS + // TODO: look at why stackAlloc isn't tripping the assertions + console.assert(stackMemoryAligned <= wwParams.stackSize, `Not enough stack allocated to the AudioWorklet (need ${stackMemoryAligned}, got ${wwParams.stackSize})`); +#endif // Copy input audio descriptor structs and data to Wasm (recall, structs // first, audio data after). 'inputsPtr' is the start of the C callback's diff --git a/src/lib/libwebaudio.js b/src/lib/libwebaudio.js index dde80718a2cce..426620d7d6316 100644 --- a/src/lib/libwebaudio.js +++ b/src/lib/libwebaudio.js @@ -77,12 +77,7 @@ var LibraryWebAudio = { // Performs the work of getting the AudioContext's render quantum size. $emscriptenGetContextQuantumSize: (contextHandle) => { - // TODO: in a future release this will be something like: - // return EmAudio[contextHandle].renderQuantumSize || 128; - // It comes two caveats: it needs the hint when generating the context adding to - // emscripten_create_audio_context(), and altering the quantum requires a secure - // context and fallback implementing. Until then we simply use the 1.0 API value: - return 128; + return EmAudio[contextHandle].renderQuantumSize || 128; }, // emscripten_create_audio_context() does not itself use the @@ -100,9 +95,15 @@ var LibraryWebAudio = { #endif #endif + // AUDIO_CONTEXT_RENDER_SIZE_DEFAULT and AUDIO_CONTEXT_RENDER_SIZE_HARDWARE + // into their AudioContextRenderSizeCategory enum, or take the positive int. + function readRenderSizeHint(val) { + return (val == 0) ? "default" : ((val < 0) ? "hardware" : val); + } var opts = options ? { latencyHint: UTF8ToString({{{ makeGetValue('options', C_STRUCTS.EmscriptenWebAudioCreateAttributes.latencyHint, '*') }}}) || undefined, - sampleRate: {{{ makeGetValue('options', C_STRUCTS.EmscriptenWebAudioCreateAttributes.sampleRate, 'u32') }}} || undefined + sampleRate: {{{ makeGetValue('options', C_STRUCTS.EmscriptenWebAudioCreateAttributes.sampleRate, 'u32') }}} || undefined, + renderSizeHint: readRenderSizeHint({{{ makeGetValue('options', C_STRUCTS.EmscriptenWebAudioCreateAttributes.renderSizeHint, 'i32') }}}) } : undefined; #if WEBAUDIO_DEBUG diff --git a/src/struct_info.json b/src/struct_info.json index 531d76afd8fd9..04c86495b6c12 100644 --- a/src/struct_info.json +++ b/src/struct_info.json @@ -1269,7 +1269,8 @@ "structs": { "EmscriptenWebAudioCreateAttributes": [ "latencyHint", - "sampleRate" + "sampleRate", + "renderSizeHint" ], "WebAudioParamDescriptor": [ "defaultValue", diff --git a/src/struct_info_generated.json b/src/struct_info_generated.json index e9383d3f2ac77..2292ecd56ae48 100644 --- a/src/struct_info_generated.json +++ b/src/struct_info_generated.json @@ -700,8 +700,9 @@ "visibilityState": 4 }, "EmscriptenWebAudioCreateAttributes": { - "__size__": 8, + "__size__": 12, "latencyHint": 0, + "renderSizeHint": 8, "sampleRate": 4 }, "EmscriptenWebGLContextAttributes": { diff --git a/src/struct_info_generated_wasm64.json b/src/struct_info_generated_wasm64.json index 38d3a40980dd3..545192606f982 100644 --- a/src/struct_info_generated_wasm64.json +++ b/src/struct_info_generated_wasm64.json @@ -702,6 +702,7 @@ "EmscriptenWebAudioCreateAttributes": { "__size__": 16, "latencyHint": 0, + "renderSizeHint": 12, "sampleRate": 8 }, "EmscriptenWebGLContextAttributes": { diff --git a/system/include/emscripten/webaudio.h b/system/include/emscripten/webaudio.h index f8c113a0a13f7..213bc81f7f985 100644 --- a/system/include/emscripten/webaudio.h +++ b/system/include/emscripten/webaudio.h @@ -19,10 +19,16 @@ extern "C" { typedef int EMSCRIPTEN_WEBAUDIO_T; +// Default render size of 128 frames +#define AUDIO_CONTEXT_RENDER_SIZE_DEFAULT 0 +// Let the hardware determine the best render size +#define AUDIO_CONTEXT_RENDER_SIZE_HARDWARE -1 + typedef struct EmscriptenWebAudioCreateAttributes { const char *latencyHint; // Specify one of "balanced", "interactive" or "playback" uint32_t sampleRate; // E.g. 44100 or 48000 + int32_t renderSizeHint; // AUDIO_CONTEXT_RENDER_SIZE_* or number of samples } EmscriptenWebAudioCreateAttributes; // Creates a new Web Audio AudioContext, and returns a handle to it. diff --git a/test/webaudio/audioworklet_params_mixing.c b/test/webaudio/audioworklet_params_mixing.c index db877cfe653d1..931e3318cd2fd 100644 --- a/test/webaudio/audioworklet_params_mixing.c +++ b/test/webaudio/audioworklet_params_mixing.c @@ -9,10 +9,18 @@ // create variable parameter data sizes, depending on the browser, it's also the // ideal to test audio worklets don't corrupt TLS variables. +// Large render size (approx 42ms) +#define RENDER_SIZE_HINT 2048 + // This needs to be big enough for the stereo output, 2x inputs, 2x params and // the worker stack. To note that different browsers have different stack size // requirement (see notes in process() plus the expansion of the params). +#ifndef RENDER_SIZE_HINT #define AUDIO_STACK_SIZE 6144 +#else +// float bytes * stereo * ins/outs + extra stack +#define AUDIO_STACK_SIZE ((RENDER_SIZE_HINT * 4 * 2 * 5) + 1024) +#endif // Shared file playback and bootstrap #include "audioworklet_test_shared.inc" diff --git a/test/webaudio/audioworklet_test_shared.inc b/test/webaudio/audioworklet_test_shared.inc index 8af562a7c0635..3e2b2d3ab67db 100644 --- a/test/webaudio/audioworklet_test_shared.inc +++ b/test/webaudio/audioworklet_test_shared.inc @@ -95,8 +95,12 @@ int main(void) { assert(workletStack); // Set at least the latency hint to test the attribute setting + // (The render size we take from the calling code if set) EmscriptenWebAudioCreateAttributes attrs = { - .latencyHint = "balanced" + .latencyHint = "balanced", +#ifdef RENDER_SIZE_HINT + .renderSizeHint = RENDER_SIZE_HINT +#endif }; EMSCRIPTEN_WEBAUDIO_T context = emscripten_create_audio_context(&attrs); emscripten_start_wasm_audio_worklet_thread_async(context, workletStack, AUDIO_STACK_SIZE, getStartCallback(), NULL); From c013e88731551336fe99727dab92ccd32276b22a Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Fri, 7 Nov 2025 16:48:24 +0100 Subject: [PATCH 2/7] Rebaseline code sizes --- test/codesize/audio_worklet_wasm.expected.js | 41 ++++++++++--------- ...nimal_runtime_code_size_audio_worklet.json | 8 ++-- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/test/codesize/audio_worklet_wasm.expected.js b/test/codesize/audio_worklet_wasm.expected.js index 24730436b4982..f86499d03652a 100644 --- a/test/codesize/audio_worklet_wasm.expected.js +++ b/test/codesize/audio_worklet_wasm.expected.js @@ -1,4 +1,4 @@ -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; +var m = globalThis.Module || "undefined" != typeof Module ? Module : {}, p = !!globalThis.AudioWorkletGlobalScope, t = "em-ww" == globalThis.name || p, u, z, I, J, G, E, w, X, F, D, C, Y, A, Z; function v(a) { u = a; @@ -10,12 +10,12 @@ function v(a) { a.G = a.M = 0; } -t && !r && (onmessage = a => { +t && !p && (onmessage = a => { onmessage = null; v(a.data); }); -if (r) { +if (p) { function a(b) { class h extends AudioWorkletProcessor { constructor(d) { @@ -36,7 +36,7 @@ if (r) { return b; } process(d, g, e) { - var l = d.length, p = g.length, f, q, k = 12 * (l + p), n = 0; + var l = d.length, q = g.length, f, r, k = 12 * (l + q), n = 0; for (f of d) n += f.length; n *= this.s; var H = 0; @@ -53,15 +53,15 @@ if (r) { G[k + 4 >> 2] = this.u; G[k + 8 >> 2] = n; k += 12; - for (q of f) E.set(q, n >> 2), n += this.s; + for (r of f) E.set(r, n >> 2), n += this.s; } d = k; - for (f = 0; q = e[f++]; ) G[k >> 2] = q.length, G[k + 4 >> 2] = n, k += 8, E.set(q, n >> 2), - n += 4 * q.length; + for (f = 0; r = e[f++]; ) G[k >> 2] = r.length, G[k + 4 >> 2] = n, k += 8, E.set(r, n >> 2), + n += 4 * r.length; e = k; for (f of g) G[k >> 2] = f.length, G[k + 4 >> 2] = this.u, G[k + 8 >> 2] = n, k += 12, n += this.s * f.length; - if (l = this.v(l, B, p, e, N, d, this.A)) for (f of g) for (q of f) q.set(this.B[--H]); + if (l = this.v(l, B, q, e, N, d, this.A)) for (f of g) for (r of f) r.set(this.B[--H]); F(U); return !!l; } @@ -129,9 +129,12 @@ var K = [], L = a => { }, T = a => { if (a) { var c = G[a >> 2]; + c = (c ? S(c) : "") || void 0; + var b = J[a + 8 >> 2]; a = { - latencyHint: (c ? S(c) : "") || void 0, - sampleRate: G[a + 4 >> 2] || void 0 + latencyHint: c, + sampleRate: G[a + 4 >> 2] || void 0, + O: 0 == b ? "default" : 0 > b ? "hardware" : b }; } else a = void 0; a = new AudioContext(a); @@ -140,10 +143,10 @@ var K = [], L = a => { }, V = (a, c, b, h, d) => { var g = b ? J[b + 4 >> 2] : 0; if (b) { - var e = J[b >> 2], l = G[b + 8 >> 2], p = g; + var e = J[b >> 2], l = G[b + 8 >> 2], q = g; if (l) { l >>= 2; - for (var f = []; p--; ) f.push(G[l++]); + for (var f = []; q--; ) f.push(G[l++]); l = f; } else l = void 0; b = { @@ -156,7 +159,7 @@ var K = [], L = a => { processorOptions: { v: h, A: d, - u: 128 + u: O[a].N || 128 } }; } else b = void 0; @@ -191,17 +194,17 @@ var K = [], L = a => { if (!e) return l(); e.addModule(m.js).then((() => { e.port || (e.port = { - postMessage: p => { - p._boot ? (e.D = new AudioWorkletNode(g, "em-bootstrap", { - processorOptions: p + postMessage: q => { + q._boot ? (e.D = new AudioWorkletNode(g, "em-bootstrap", { + processorOptions: q }), e.D.port.onmessage = f => { e.port.onmessage(f); - }) : e.D.port.postMessage(p); + }) : e.D.port.postMessage(q); } }); e.port.postMessage({ _boot: 1, - N: ba++, + P: ba++, G: m.wasm, L: w, J: c, @@ -243,7 +246,7 @@ function y() { C = a.n; Y = a.o; A = a.k; - t ? (Y(u.J, u.F), r || (removeEventListener("message", M), K = K.forEach(L), addEventListener("message", L))) : a.i(); + t ? (Y(u.J, u.F), p || (removeEventListener("message", M), K = K.forEach(L), addEventListener("message", L))) : a.i(); t || X(); })); } 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 b2092c1fd2632..235ffc1c67446 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": 4235, - "a.js.gz": 2170, + "a.js": 4297, + "a.js.gz": 2208, "a.wasm": 1329, "a.wasm.gz": 895, - "total": 6083, - "total_gz": 3422 + "total": 6145, + "total_gz": 3460 } From 1af27cae926f7c78ca4d0305de1a8bfd67139129 Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Fri, 7 Nov 2025 17:16:41 +0100 Subject: [PATCH 3/7] Pass 'renderQuantumSize' through Closure --- src/lib/libwebaudio.js | 2 +- test/codesize/audio_worklet_wasm.expected.js | 6 +++--- .../test_minimal_runtime_code_size_audio_worklet.json | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib/libwebaudio.js b/src/lib/libwebaudio.js index 426620d7d6316..42219573f763a 100644 --- a/src/lib/libwebaudio.js +++ b/src/lib/libwebaudio.js @@ -77,7 +77,7 @@ var LibraryWebAudio = { // Performs the work of getting the AudioContext's render quantum size. $emscriptenGetContextQuantumSize: (contextHandle) => { - return EmAudio[contextHandle].renderQuantumSize || 128; + return EmAudio[contextHandle]['renderQuantumSize'] || 128; }, // emscripten_create_audio_context() does not itself use the diff --git a/test/codesize/audio_worklet_wasm.expected.js b/test/codesize/audio_worklet_wasm.expected.js index f86499d03652a..c120438e68ee6 100644 --- a/test/codesize/audio_worklet_wasm.expected.js +++ b/test/codesize/audio_worklet_wasm.expected.js @@ -134,7 +134,7 @@ var K = [], L = a => { a = { latencyHint: c, sampleRate: G[a + 4 >> 2] || void 0, - O: 0 == b ? "default" : 0 > b ? "hardware" : b + N: 0 == b ? "default" : 0 > b ? "hardware" : b }; } else a = void 0; a = new AudioContext(a); @@ -159,7 +159,7 @@ var K = [], L = a => { processorOptions: { v: h, A: d, - u: O[a].N || 128 + u: O[a].renderQuantumSize || 128 } }; } else b = void 0; @@ -204,7 +204,7 @@ var K = [], L = a => { }); e.port.postMessage({ _boot: 1, - P: ba++, + O: ba++, G: m.wasm, L: w, J: c, 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 235ffc1c67446..98b87e0948b71 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": 4297, - "a.js.gz": 2208, + "a.js": 4313, + "a.js.gz": 2222, "a.wasm": 1329, "a.wasm.gz": 895, - "total": 6145, - "total_gz": 3460 + "total": 6161, + "total_gz": 3474 } From d7e40b7621c10c95ee6e0078c7b0c1e6776175fd Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Fri, 7 Nov 2025 17:20:39 +0100 Subject: [PATCH 4/7] Code golf --- src/lib/libwebaudio.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/libwebaudio.js b/src/lib/libwebaudio.js index 42219573f763a..dc104b7422f7c 100644 --- a/src/lib/libwebaudio.js +++ b/src/lib/libwebaudio.js @@ -98,7 +98,7 @@ var LibraryWebAudio = { // AUDIO_CONTEXT_RENDER_SIZE_DEFAULT and AUDIO_CONTEXT_RENDER_SIZE_HARDWARE // into their AudioContextRenderSizeCategory enum, or take the positive int. function readRenderSizeHint(val) { - return (val == 0) ? "default" : ((val < 0) ? "hardware" : val); + return (val < 0) ? 'hardware' : (val || 'default'); } var opts = options ? { latencyHint: UTF8ToString({{{ makeGetValue('options', C_STRUCTS.EmscriptenWebAudioCreateAttributes.latencyHint, '*') }}}) || undefined, From e455f226f73e161ecf20b7c2ed3590f970c0cdd9 Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Fri, 7 Nov 2025 17:24:28 +0100 Subject: [PATCH 5/7] Removed superfluous 'console' + rebaseline --- src/audio_worklet.js | 10 +++++----- test/codesize/audio_worklet_wasm.expected.js | 2 +- .../test_minimal_runtime_code_size_audio_worklet.json | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/audio_worklet.js b/src/audio_worklet.js index dc2c4eac3bce3..26dfa5d3ad823 100644 --- a/src/audio_worklet.js +++ b/src/audio_worklet.js @@ -50,7 +50,7 @@ function createWasmAudioWorkletProcessor() { // 64 frames, for the case where a multi-MB stack is passed. this.outputViews = new Array(Math.min(((wwParams.stackSize - {{{ STACK_ALIGN }}}) / this.bytesPerChannel) | 0, /*sensible limit*/ 64)); #if ASSERTIONS - console.assert(this.outputViews.length > 0, `AudioWorklet needs more stack allocating (at least ${this.bytesPerChannel})`); + assert(this.outputViews.length > 0, `AudioWorklet needs more stack allocating (at least ${this.bytesPerChannel})`); #endif this.createOutputViews(); @@ -138,8 +138,8 @@ function createWasmAudioWorkletProcessor() { #endif var oldStackPtr = stackSave(); #if ASSERTIONS - console.assert(oldStackPtr == this.ctorOldStackPtr, 'AudioWorklet stack address has unexpectedly moved'); - console.assert(outputViewsNeeded <= this.outputViews.length, `Too many AudioWorklet outputs (need ${outputViewsNeeded} but have stack space for ${this.outputViews.length})`); + assert(oldStackPtr == this.ctorOldStackPtr, 'AudioWorklet stack address has unexpectedly moved'); + assert(outputViewsNeeded <= this.outputViews.length, `Too many AudioWorklet outputs (need ${outputViewsNeeded} but have stack space for ${this.outputViews.length})`); #endif // Allocate the necessary stack space. All pointer variables are in bytes; @@ -156,7 +156,7 @@ function createWasmAudioWorkletProcessor() { var dataPtr = structPtr + (stackMemoryAligned - stackMemoryData); #if ASSERTIONS // TODO: look at why stackAlloc isn't tripping the assertions - console.assert(stackMemoryAligned <= wwParams.stackSize, `Not enough stack allocated to the AudioWorklet (need ${stackMemoryAligned}, got ${wwParams.stackSize})`); + assert(stackMemoryAligned <= wwParams.stackSize, `Not enough stack allocated to the AudioWorklet (need ${stackMemoryAligned}, got ${wwParams.stackSize})`); #endif // Copy input audio descriptor structs and data to Wasm (recall, structs @@ -225,7 +225,7 @@ function createWasmAudioWorkletProcessor() { // And that the views' size match the passed in output buffers for (entry of outputList) { for (subentry of entry) { - console.assert(subentry.byteLength == this.bytesPerChannel, `AudioWorklet unexpected output buffer size (expected ${this.bytesPerChannel} got ${subentry.byteLength})`); + assert(subentry.byteLength == this.bytesPerChannel, `AudioWorklet unexpected output buffer size (expected ${this.bytesPerChannel} got ${subentry.byteLength})`); } } } diff --git a/test/codesize/audio_worklet_wasm.expected.js b/test/codesize/audio_worklet_wasm.expected.js index c120438e68ee6..f18e8adf6f120 100644 --- a/test/codesize/audio_worklet_wasm.expected.js +++ b/test/codesize/audio_worklet_wasm.expected.js @@ -134,7 +134,7 @@ var K = [], L = a => { a = { latencyHint: c, sampleRate: G[a + 4 >> 2] || void 0, - N: 0 == b ? "default" : 0 > b ? "hardware" : b + N: 0 > b ? "hardware" : b || "default" }; } else a = void 0; a = new AudioContext(a); 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 98b87e0948b71..50ff7beecdafb 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": 4313, - "a.js.gz": 2222, + "a.js": 4309, + "a.js.gz": 2219, "a.wasm": 1329, "a.wasm.gz": 895, - "total": 6161, - "total_gz": 3474 + "total": 6157, + "total_gz": 3471 } From 50e4a04c9c9e2b33e9100d89d8a9de11d7cfe5fe Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Fri, 7 Nov 2025 19:07:12 +0100 Subject: [PATCH 6/7] Indents --- src/lib/libwebaudio.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/libwebaudio.js b/src/lib/libwebaudio.js index dc104b7422f7c..e3fedb4dfe353 100644 --- a/src/lib/libwebaudio.js +++ b/src/lib/libwebaudio.js @@ -98,7 +98,7 @@ var LibraryWebAudio = { // AUDIO_CONTEXT_RENDER_SIZE_DEFAULT and AUDIO_CONTEXT_RENDER_SIZE_HARDWARE // into their AudioContextRenderSizeCategory enum, or take the positive int. function readRenderSizeHint(val) { - return (val < 0) ? 'hardware' : (val || 'default'); + return (val < 0) ? 'hardware' : (val || 'default'); } var opts = options ? { latencyHint: UTF8ToString({{{ makeGetValue('options', C_STRUCTS.EmscriptenWebAudioCreateAttributes.latencyHint, '*') }}}) || undefined, From d7136ea43f99abbf80d78402e915ec52280dba62 Mon Sep 17 00:00:00 2001 From: Carl Woffenden Date: Sat, 8 Nov 2025 15:38:51 +0100 Subject: [PATCH 7/7] Cleaned up comment --- src/lib/libwebaudio.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/libwebaudio.js b/src/lib/libwebaudio.js index e3fedb4dfe353..2c028659ff796 100644 --- a/src/lib/libwebaudio.js +++ b/src/lib/libwebaudio.js @@ -95,8 +95,8 @@ var LibraryWebAudio = { #endif #endif - // AUDIO_CONTEXT_RENDER_SIZE_DEFAULT and AUDIO_CONTEXT_RENDER_SIZE_HARDWARE - // into their AudioContextRenderSizeCategory enum, or take the positive int. + // Converts AUDIO_CONTEXT_RENDER_SIZE_* into AudioContextRenderSizeCategory + // enums, otherwise returns a positive int value. function readRenderSizeHint(val) { return (val < 0) ? 'hardware' : (val || 'default'); }