Add testing for audio worklets + pthreads. NFC (#26982)

This should have been part of #25930
diff --git a/src/lib/libwebaudio.js b/src/lib/libwebaudio.js
index 1da3306..3aeae6f 100644
--- a/src/lib/libwebaudio.js
+++ b/src/lib/libwebaudio.js
@@ -186,6 +186,11 @@
     assert(stackSize % 16 == 0, `AudioWorklet stack size should be a multiple of 16 bytes! (was ${stackSize} == ${stackSize%16} mod 16)`);
     assert(!audioContext.audioWorkletInitialized, `emscripten_create_wasm_audio_worklet() was already called for AudioContext ${contextHandle}! Only call this function once per AudioContext`);
     audioContext.audioWorkletInitialized = 1;
+#if PTHREADS
+    assert(pthreadPtr);
+#else
+    assert(!pthreadPtr);
+#endif
 #endif
 
 #if WEBAUDIO_DEBUG
diff --git a/system/lib/wasm_worker/audio_worklet.c b/system/lib/wasm_worker/audio_worklet.c
index 80cbca2..f9c2d0e 100644
--- a/system/lib/wasm_worker/audio_worklet.c
+++ b/system/lib/wasm_worker/audio_worklet.c
@@ -14,11 +14,13 @@
 // function that adds the _emscripten_get_next_tid() as arg0
 void emscripten_start_wasm_audio_worklet_thread_async(EMSCRIPTEN_WEBAUDIO_T audioContext, void *stackLowestAddress, uint32_t stackSize, EmscriptenStartWebAudioWorkletCallback callback, void *userData2) {
   emscripten_wasm_worker_t wwID = _emscripten_get_next_tid();
-  void* pthreadPtr = stackLowestAddress;
 #ifdef __EMSCRIPTEN_PTHREADS__
+  void* pthreadPtr = stackLowestAddress;
   size_t stackSize_ = stackSize;
   stackLowestAddress = _emscripten_init_pthread(stackLowestAddress, &stackSize_, wwID);
   stackSize = stackSize_;
+#else
+  void* pthreadPtr = NULL;
 #endif
   _emscripten_create_audio_worklet(wwID, audioContext, stackLowestAddress, stackSize, pthreadPtr, callback, userData2);
 }
diff --git a/test/codesize/audio_worklet_wasm.expected.js b/test/codesize/audio_worklet_wasm.expected.js
index 9e7fed0..94166f5 100644
--- a/test/codesize/audio_worklet_wasm.expected.js
+++ b/test/codesize/audio_worklet_wasm.expected.js
@@ -1,36 +1,36 @@
-var m = globalThis.Module || typeof Module != "undefined" ? Module : {}, r = !!globalThis.AudioWorkletGlobalScope, t = globalThis.name == "em-ww" || r, u, z, J, E, G, I, w, X, F, D, C, Y, A, Z;
+var m = globalThis.Module || typeof Module != "undefined" ? Module : {}, r = !!globalThis.WorkerGlobalScope, t = !!globalThis.AudioWorkletGlobalScope, u = globalThis.name == "em-ww" || t, v, A, K, F, H, J, x, W, O, G, E, D, X, C, Z;
 
-function v(a) {
-    u = a;
-    w = a.I;
-    x();
+function w(a) {
+    v = a;
+    x = a.I;
+    y();
     m ||= {};
     m.wasm = a.H;
-    y();
+    z();
     a.H = a.I = 0;
 }
 
-t && !r && (onmessage = a => {
+u && !t && (onmessage = a => {
     onmessage = null;
-    v(a.data);
+    w(a.data);
 });
 
-if (r) {
+if (t) {
     function a(c) {
         class k extends AudioWorkletProcessor {
             constructor(d) {
                 super();
                 d = d.processorOptions;
-                this.A = A.get(d.A);
+                this.A = C.get(d.A);
                 this.B = d.B;
                 this.u = d.u;
                 this.v = this.u * 4;
-                this.C = Array(Math.min((u.G - 16) / this.v | 0, 64));
+                this.C = Array(Math.min((v.G - 16) / this.v | 0, 64));
                 this.J();
             }
             J() {
-                for (var d = C(), g = D(this.C.length * this.v) >> 2, f = this.C.length - 1; f >= 0; f--) this.C[f] = E.subarray(g, g += this.u);
-                F(d);
+                for (var d = D(), g = E(this.C.length * this.v) >> 2, f = this.C.length - 1; f >= 0; f--) this.C[f] = F.subarray(g, g += this.u);
+                G(d);
             }
             static get parameterDescriptors() {
                 return c;
@@ -39,30 +39,30 @@
                 var l = d.length, n = g.length, e, q, h = (l + n) * 12, p = 0;
                 for (e of d) p += e.length;
                 p *= this.v;
-                var H = 0;
-                for (e of g) H += e.length;
-                p += H * this.v;
-                var O = 0;
-                for (e in f) ++O, h += 8, p += f[e].byteLength;
-                var V = C(), B = h + p + 15 & -16;
-                h = D(B);
+                var I = 0;
+                for (e of g) I += e.length;
+                p += I * this.v;
+                var P = 0;
+                for (e in f) ++P, h += 8, p += f[e].byteLength;
+                var Y = D(), B = h + p + 15 & -16;
+                h = E(B);
                 p = h + (B - p);
                 B = h;
                 for (e of d) {
-                    G[h >> 2] = e.length;
-                    G[h + 4 >> 2] = this.u;
-                    G[h + 8 >> 2] = p;
+                    H[h >> 2] = e.length;
+                    H[h + 4 >> 2] = this.u;
+                    H[h + 8 >> 2] = p;
                     h += 12;
-                    for (q of e) E.set(q, p >> 2), p += this.v;
+                    for (q of e) F.set(q, p >> 2), p += this.v;
                 }
                 d = h;
-                for (e = 0; q = f[e++]; ) G[h >> 2] = q.length, G[h + 4 >> 2] = p, h += 8, E.set(q, p >> 2), 
+                for (e = 0; q = f[e++]; ) H[h >> 2] = q.length, H[h + 4 >> 2] = p, h += 8, F.set(q, p >> 2), 
                 p += q.length * 4;
                 f = h;
-                for (e of g) G[h >> 2] = e.length, G[h + 4 >> 2] = this.u, G[h + 8 >> 2] = p, h += 12, 
+                for (e of g) H[h >> 2] = e.length, H[h + 4 >> 2] = this.u, H[h + 8 >> 2] = p, h += 12, 
                 p += this.v * e.length;
-                if (l = this.A(l, B, n, f, O, d, this.B)) for (e of g) for (q of e) q.set(this.C[--H]);
-                F(V);
+                if (l = this.A(l, B, n, f, P, d, this.B)) for (e of g) for (q of e) q.set(this.C[--I]);
+                G(Y);
                 return !!l;
             }
         }
@@ -72,50 +72,52 @@
     class b extends AudioWorkletProcessor {
         constructor(c) {
             super();
-            v(c.processorOptions);
+            w(c.processorOptions);
             port instanceof MessagePort || (this.port.onmessage = port.onmessage, port = this.port);
         }
         process() {}
     }
     registerProcessor("em-bootstrap", b);
     port.onmessage = async c => {
-        await z;
+        await A;
         c = c.data;
-        c._boot ? v(c) : c._wpn ? (registerProcessor(c._wpn, a(c.K)), port.postMessage({
+        c._boot ? w(c) : c._wpn ? (registerProcessor(c._wpn, a(c.K)), port.postMessage({
             _wsc: c.A,
             D: [ c.L, 1, c.B ]
-        })) : c._wsc && A.get(c._wsc)(...c.D);
+        })) : c._wsc && C.get(c._wsc)(...c.D);
     };
 }
 
-function x() {
-    var a = w.buffer;
-    I = new Uint8Array(a);
-    J = new Int32Array(a);
-    G = new Uint32Array(a);
-    E = new Float32Array(a);
+function y() {
+    var a = x.buffer;
+    J = new Uint8Array(a);
+    K = new Int32Array(a);
+    H = new Uint32Array(a);
+    F = new Float32Array(a);
 }
 
-t || (w = m.mem || new WebAssembly.Memory({
+u || (x = m.mem || new WebAssembly.Memory({
     initial: 256,
     maximum: 256,
     shared: !0
-}), x());
+}), y());
 
-var K = [], L = a => {
+var L = [], M = a => {
     a = a.data;
     var b = a._wsc;
-    b && A.get(b)(...a.x);
-}, M = a => {
-    K.push(a);
+    b && C.get(b)(...a.x);
 }, N = a => {
+    L.push(a);
+}, aa = () => {
+    O(0, !r && !t, !u, r && !t);
+}, ba = a => {
     a = a.data;
     var b = a._wsc;
-    b && A.get(b)(...a.D);
-}, Q = (a, b, c, k, d, g, f) => {
-    var l = P[b], n = l.audioWorklet;
+    b && C.get(b)(...a.D);
+}, ca = (a, b, c, k, d, g, f) => {
+    var l = Q[b], n = l.audioWorklet;
     d = () => {
-        A.get(g)(b, 0, f);
+        C.get(g)(b, 0, f);
     };
     if (!n) return d();
     n.addModule(m.js).then((() => {
@@ -132,19 +134,19 @@
             _boot: 1,
             N: a,
             H: m.wasm,
-            I: w,
+            I: x,
             M: c,
             G: k
         });
-        n.port.onmessage = N;
-        A.get(g)(b, 1, f);
+        n.port.onmessage = ba;
+        C.get(g)(b, 1, f);
     })).catch(d);
-}, R = (a, b, c, k) => {
-    b = P[b];
-    P[a].connect(b.destination || b, c, k);
-}, P = {}, S = 0, T = globalThis.TextDecoder && new TextDecoder, U = (a = 0) => {
-    for (var b = I, c = a, k = c + void 0; b[c] && !(c >= k); ) ++c;
-    if (c - a > 16 && b.buffer && T) return T.decode(b.slice(a, c));
+}, da = (a, b, c, k) => {
+    b = Q[b];
+    Q[a].connect(b.destination || b, c, k);
+}, Q = {}, R = 0, S = globalThis.TextDecoder && new TextDecoder, T = (a = 0) => {
+    for (var b = J, c = a, k = c + void 0; b[c] && !(c >= k); ) ++c;
+    if (c - a > 16 && b.buffer && S) return S.decode(b.slice(a, c));
     for (k = ""; a < c; ) {
         var d = b[a++];
         if (d & 128) {
@@ -157,102 +159,109 @@
         } else k += String.fromCharCode(d);
     }
     return k;
-}, aa = a => {
+}, ea = a => {
     if (a) {
-        var b = G[a >> 2];
-        b = (b ? U(b) : "") || void 0;
-        var c = J[a + 8 >> 2];
+        var b = H[a >> 2];
+        b = (b ? T(b) : "") || void 0;
+        var c = K[a + 8 >> 2];
         a = {
             latencyHint: b,
-            sampleRate: G[a + 4 >> 2] || void 0,
+            sampleRate: H[a + 4 >> 2] || void 0,
             O: c < 0 ? "hardware" : c || "default"
         };
     } else a = void 0;
     a = new AudioContext(a);
-    P[++S] = a;
-    return S;
-}, ba = (a, b, c, k, d) => {
-    var g = c ? J[c + 4 >> 2] : 0;
+    Q[++R] = a;
+    return R;
+}, fa = (a, b, c, k, d) => {
+    var g = c ? K[c + 4 >> 2] : 0;
     if (c) {
-        var f = J[c >> 2], l = G[c + 8 >> 2], n = g;
+        var f = K[c >> 2], l = H[c + 8 >> 2], n = g;
         if (l) {
             l >>= 2;
-            for (var e = []; n--; ) e.push(G[l++]);
+            for (var e = []; n--; ) e.push(H[l++]);
             l = e;
         } else l = void 0;
         c = {
             numberOfInputs: f,
             numberOfOutputs: g,
             outputChannelCount: l,
-            channelCount: G[c + 12 >> 2] || void 0,
-            channelCountMode: [ , "clamped-max", "explicit" ][J[c + 16 >> 2]],
-            channelInterpretation: [ , "discrete" ][J[c + 20 >> 2]],
+            channelCount: H[c + 12 >> 2] || void 0,
+            channelCountMode: [ , "clamped-max", "explicit" ][K[c + 16 >> 2]],
+            channelInterpretation: [ , "discrete" ][K[c + 20 >> 2]],
             processorOptions: {
                 A: k,
                 B: d,
-                u: P[a].renderQuantumSize || 128
+                u: Q[a].renderQuantumSize || 128
             }
         };
     } else c = void 0;
-    a = new AudioWorkletNode(P[a], b ? U(b) : "", c);
-    P[++S] = a;
-    return S;
-}, ca = (a, b, c, k) => {
-    var d = (d = G[b >> 2]) ? U(d) : "", g = J[b + 4 >> 2];
-    b = G[b + 8 >> 2];
+    a = new AudioWorkletNode(Q[a], b ? T(b) : "", c);
+    Q[++R] = a;
+    return R;
+}, ha = (a, b, c, k) => {
+    var d = (d = H[b >> 2]) ? T(d) : "", g = K[b + 4 >> 2];
+    b = H[b + 8 >> 2];
     for (var f = [], l = 0; g--; ) f.push({
         name: l++,
-        defaultValue: E[b >> 2],
-        minValue: E[b + 4 >> 2],
-        maxValue: E[b + 8 >> 2],
-        automationRate: (J[b + 12 >> 2] ? "k" : "a") + "-rate"
+        defaultValue: F[b >> 2],
+        minValue: F[b + 4 >> 2],
+        maxValue: F[b + 8 >> 2],
+        automationRate: (K[b + 12 >> 2] ? "k" : "a") + "-rate"
     }), b += 16;
-    P[a].audioWorklet.port.postMessage({
+    Q[a].audioWorklet.port.postMessage({
         _wpn: d,
         K: f,
         L: a,
         A: c,
         B: k
     });
-}, da = () => !1, ea = () => r ? () => 138 : a => (a.set(crypto.getRandomValues(new Uint8Array(a.byteLength))), 
-0), W = a => (W = ea())(a), fa = (a, b) => W(I.subarray(a, a + b));
+}, U = globalThis.performance?.now ? () => performance.now() : Date.now, ia = a => {
+    a = [ a ? T(a) : "" ];
+    return console.log(...a);
+}, ja = () => !1, ka = () => t ? () => 138 : a => (a.set(crypto.getRandomValues(new Uint8Array(a.byteLength))), 
+0), V = a => (V = ka())(a), la = (a, b) => V(J.subarray(a, a + b));
 
-function ha(a) {
+function ma(a) {
     var b = document.createElement("button");
     b.innerHTML = "Toggle playback";
     document.body.appendChild(b);
-    a = P[a];
+    a = Q[a];
     b.onclick = () => {
         a.state != "running" ? a.resume() : a.suspend();
     };
 }
 
-function y() {
+function z() {
     Z = {
-        g: ha,
-        c: Q,
-        h: R,
+        i: ma,
         e: aa,
-        i: ba,
-        f: ca,
-        b: da,
-        a: w,
-        d: fa
+        d: ca,
+        k: da,
+        g: ea,
+        l: fa,
+        h: ha,
+        b: U,
+        c: ia,
+        j: ja,
+        a: x,
+        f: la
     };
-    z = WebAssembly.instantiate(m.wasm, {
+    A = WebAssembly.instantiate(m.wasm, {
         a: Z
     }).then((a => {
         a = (a.instance || a).exports;
-        X = a.k;
-        F = a.m;
-        D = a.n;
+        W = a.n;
+        O = a.p;
+        G = a.q;
+        E = a.r;
+        D = a.s;
+        X = a.t;
         C = a.o;
-        Y = a.p;
-        A = a.l;
-        t ? (Y(u.N, u.M, u.G), r || (removeEventListener("message", M), K = K.forEach(L), 
-        addEventListener("message", L))) : a.j();
-        t || X();
+        u ? (X(v.N, v.M, v.G), t || (removeEventListener("message", N), L = L.forEach(M), 
+        addEventListener("message", M))) : a.m();
+        u || W();
     }));
 }
 
-t || y();
\ No newline at end of file
+u || z();
\ 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 03fa3d3..408b66e 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": 515,
   "a.html.gz": 355,
-  "a.js": 4448,
-  "a.js.gz": 2289,
-  "a.wasm": 1409,
-  "a.wasm.gz": 936,
-  "total": 6372,
-  "total_gz": 3580
+  "a.js": 4647,
+  "a.js.gz": 2380,
+  "a.wasm": 11064,
+  "a.wasm.gz": 6028,
+  "total": 16226,
+  "total_gz": 8763
 }
diff --git a/test/webaudio/audioworklet.c b/test/webaudio/audioworklet.c
index 228b7e5..ce7ff6c 100644
--- a/test/webaudio/audioworklet.c
+++ b/test/webaudio/audioworklet.c
@@ -1,3 +1,5 @@
+#define _GNU_SOURCE // for gettid
+#include <emscripten/console.h>
 #include <emscripten/webaudio.h>
 #include <emscripten/threading.h>
 #include <assert.h>
@@ -31,6 +33,9 @@
 int lastTlsVariableValueInAudioThread = 1;
 #endif
 
+bool worklet_started = false;
+pid_t main_tid = 0;
+
 // This function will be called for every fixed-size buffer of audio samples to be processed.
 bool ProcessAudio(int numInputs,
                   const AudioSampleFrame* inputs,
@@ -41,6 +46,17 @@
                   void* userData) {
   assert(!emscripten_is_main_browser_thread());
   assert(emscripten_current_thread_is_audio_worklet());
+  if (!worklet_started) {
+    worklet_started = true;
+    pid_t worklet_tid = gettid();
+    emscripten_outf("worklet thread tid: %d\n", worklet_tid);
+    assert(worklet_tid && worklet_tid > main_tid);
+#ifdef __EMSCRIPTEN_PTHREADS__
+    emscripten_outf("worklet thread pthread_self: %p\n", pthread_self());
+    assert(pthread_self());
+#endif
+  }
+
 #ifdef TEST_AND_EXIT
   // Only running in the test harness, see main_thread_tls_access()
   assert(testTlsVariable == lastTlsVariableValueInAudioThread);
@@ -150,6 +166,14 @@
 int main() {
   assert(emscripten_is_main_browser_thread());
   assert(!emscripten_current_thread_is_audio_worklet());
+  main_tid = gettid();
+  emscripten_outf("main thread tid: %d\n", main_tid);
+  emscripten_outf("wasmAudioWorkletStack: %p\n", wasmAudioWorkletStack);
+  assert(main_tid);
+#ifdef __EMSCRIPTEN_PTHREADS__
+  emscripten_outf("main thread pthread_self: %p\n", pthread_self());
+  assert(pthread_self());
+#endif
 
   // Create an audio context
   context = emscripten_create_audio_context(0 /* use default constructor options */);