Fox 2026-06-06 telemetry from blanka-chrome speaker session:
· role=speaker sub=connected/connected pub=connected/connected
mesh=2 ... aud.recv pkt=308→556→800 level=0.000
· jitter-buffer started uuid=2d4a target=0.5s
· audio via AudioContext 2d4a target=0.5s ctxState=running
RTP arriving at 50pps (active speaker), worklet started, ctxState
running — every audio invariant green except level=0 and "no audio
from any speakers".
Root cause: the speaker-output picker in the UI only called setSinkId
on <audio> elements. The worklet path (every listener AND every
speaker monitor since c3ff58c routed mesh through the worklet too)
runs through audioCtx.destination, which always emits to the SYSTEM
DEFAULT sink. Users who picked a non-default speaker in the dropdown
heard nothing on their chosen device because the worklet bypassed
the sink-routing entirely.
Firefox where blanka started hearing music again works by accident:
its default output happens to be the speaker fox wants. Chrome's
default is something else (PulseAudio's per-app routing, presumably).
The Jun 5 cascade fixes + Jun 6 flushSfuStreams prefix-match fixed
the FSM; this fixes the actual sink the FSM was emitting to.
Fix: applySinkToAudioCtx() — best-effort audioCtx.setSinkId(deviceId)
mirroring the existing applySinkTo(<audio>) helper. Called on
audioCtx creation (primeAudioOnGesture and attachAudioStreamViaWorklet)
and in applySinkToAll fan-out when the user changes the dropdown.
Browser support: Chrome ≥110, Firefox ≥116. Older versions silently
fall through to system default — same as today.
Diagnostic: log line now includes sink=... so the next telemetry
session shows which sink is routed. 'n/a' when the API doesn't
exist; 'default' when sinkId is the empty string; otherwise the
device id.
Tests:
- audioCtx.setSinkId is wired and callable in the sandbox
- attach does not throw when setSinkId is missing (older browser
fallback contract)