zebra-report/web
Russell Ballestrini d9198727d9
zebra-spaces: stream-toggle reliability — await sinkId, drop stalled handler, idempotent
Fox saw repeated "stream stalled" and "autoplay blocked: aborted at
user's request" log lines on both auto-enrolled mobile listeners and
host self-monitor clicks. Three coupled causes:

1. applySinkTo() was called sync-fire-and-forget right before setting
   .src and calling .play(). setSinkId() can re-init the media
   pipeline; when it landed during the in-flight load it aborted the
   request — Firefox surfaces that as
   "The fetching process for the media resource was aborted by the
   user agent at the user's request." on the play() promise. We
   wrongly logged that as autoplay-blocked. Fix: await applySinkTo()
   BEFORE assigning .src.

2. The 'stalled' event handler called unmuteWebRtcOnFail every time
   it fired. 'stalled' fires constantly during normal mobile-cellular
   buffering and isn't a terminal failure. Each fire ping-ponged the
   audio path between WebRTC (unmuted) and the still-loading HTTP
   stream. Drop the handler — only 'error' and a rejected play()
   promise indicate real failure.

3. A second toggle-on for the same pubHex (auto-enroll race when
   peer-joined fires during initial enrol) reassigned .src on the
   same <audio> element, aborting the prior load with the same abort
   error. Make startStream idempotent: if the element already has
   our wantUrl and no .error, return immediately.

Plus two cheap mobile-friendly attrs on the dynamic <audio>:
  - preload="auto" so buffering starts before play() (gives the
    user-gesture window time to last past the initial fill)
  - playsInline so iOS/Safari doesn't escalate to a fullscreen player

startStream is now async — callers (toggleStreamFor,
autoEnableDjModeForListener) fire-and-forget the returned promise,
which is fine since all error paths are already caught inside.

Tests green (83 fsm + 16 zebra-spaces).
2026-06-03 20:06:36 -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 zebra-spaces: boot-error logging + watchFirstFrame keyframe diagnostic 2026-06-03 15:51:18 -04:00
host-your-own.html zebra-spaces: boot-error logging + watchFirstFrame keyframe diagnostic 2026-06-03 15:51:18 -04:00
how-it-works.html zebra-spaces: boot-error logging + watchFirstFrame keyframe diagnostic 2026-06-03 15:51:18 -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 zebra-spaces: boot-error logging + watchFirstFrame keyframe diagnostic 2026-06-03 15:51:18 -04:00
zebra-spaces.html zebra-spaces: stream-toggle reliability — await sinkId, drop stalled handler, idempotent 2026-06-03 20:06:36 -04:00