zebra-report/web
Russell Ballestrini ae9721e336
zebra-spaces: serialise SFU subscribe renegotiation + skip own mic echo
Bug fox reported: late joiner sees host's screen + camera initially.
The moment they share their own screen/camera, they lose the host's
tiles. The host never sees their stuff either. Symptoms point at the
renegotiation flow being raced.

Root cause: SSE delivers offers via async onmessage handlers. JS is
single-threaded but each `await` yields. When a speaker publishes
mic + screen + camera in quick succession, the SFU's addPubToSub
serialises and fires three SSE offers. The browser handler picks up
offer 1 with setRemoteDescription (state → have-remote-offer), then
awaits createAnswer. During that await another onmessage fires for
offer 2 and tries setRemoteDescription — which throws because the PC
is in have-remote-offer state. Offer 2 is dropped, the new tracks for
that publish never register on the browser side. SFU still forwards
RTP for those tracks but the browser has no receiver, so they vanish.
Existing tiles can also stop receiving RTP when the SFU's track set
diverges from the browser's transceiver set.

Fix:
- chain onmessage handlers through a single Promise queue
  (`renegQueue = renegQueue.then(...)`) so each renegotiation fully
  completes (SRD → answer → SLD → /answer POST) before the next starts.
  Browser PC always returns to stable between offers.
- ontrack mic-path now also short-circuits when pubHex === own pubHex.
  Without this, a speaker who subscribes to the SFU would attach their
  OWN mic to a remote-audio sink and hear themselves.
2026-06-02 10:20:48 -04:00
..
blog phase 1: unfirehose reconstruction from session JSONL ingest 2026-05-27 13:51:14 -04:00
fonts phase 2: gap analysis — cat>> append + binary asset recovery 2026-05-27 13:54:19 -04:00
chat.html css: .row uses minmax(0, max-content) so long labels shrink + wrap 2026-06-02 09:27:55 -04:00
host-your-own.html zebra: dark mode default on all pages + unified theme key 2026-06-01 22:18:02 -04:00
how-it-works.html zebra: dark mode default on all pages + unified theme key 2026-06-01 22:18:02 -04:00
index.html web: bump mobile body padding from 1rem to 1.25rem so the right edge has visible breathing room 2026-05-31 14:13:25 -04:00
kernel.html web: bump mobile body padding from 1rem to 1.25rem so the right edge has visible breathing room 2026-05-31 14:13:25 -04:00
stamp.js web: stamp each zebra-report page with build date + md5/sha256 2026-05-28 17:50:12 -04:00
zebra-audio.html css: .row uses minmax(0, max-content) so long labels shrink + wrap 2026-06-02 09:27:55 -04:00
zebra-spaces.html zebra-spaces: serialise SFU subscribe renegotiation + skip own mic echo 2026-06-02 10:20:48 -04:00