Speakers, cohosts, and hosts can flip their own row's stream toggle
to listen via the buffered HTTP Ogg/Opus broadcast tap instead of
WebRTC. Mic auto-mutes while in that mode; unmuting hops back to the
live mesh seamlessly. Survives cellular ICE churn that breaks the
WebRTC path.
Hard refresh resumes the last space again — the one-tap friction
buyback didn't actually fix the Firefox Android listener-audio bug
it was supposed to fix.
- DJ self-monitor stream now plays audibly (was muted-start with no
unmute path for non-listeners)
- Screen / camera / game receivers get the same playoutDelayHint as
audio so the picture stays in sync with the voice
Leave was tearing down WebRTC but leaving streamMode/streamAudio/
audioPath stale — re-entry as listener saw "already enrolled" and
never made a fresh /stream request. Now leave wipes all three maps,
removes the <audio> elements, and stops the retry loop. Plus the
primeAudio one-shot gate is gone so every entry click re-primes the
mobile audio session (it can be suspended across tab background).
If the host's mic publish lands after the listener's initial DJ auto-
enrol attempt, the 404 from the SFU was permanent — no event re-
triggered enrol. 4s interval re-checks every speaker and starts streams
that are still missing. Stops on transition out of listener.
Replaces the regressive tap-anywhere-to-resume queue with
primeAudioOnGesture(): the entry-button click handler plays a 1-frame
silent WAV through a hidden <audio>, blessing the page for audio.
Auto-enrolled DJ streams then play() without further user gesture.
No more "tap anywhere" message; no more flip-flop on stalled.
Calls a.load() inside the gesture before a.play() so the retry isn't
no-op'ing on an aborted element. Adds 'click' to the listened events
since Firefox Android only grants gesture-activation on click in some
configs. Logs retry success/failure so we know what's happening.
When mobile Firefox/Safari blocks audio.play() on auto-enrolled DJ
streams, queue the elements and retry on the first pointerdown/
touchstart anywhere on the page. WebRTC stays unmuted as fallback
so the listener isn't silent in the meantime.
Three coupled fixes to the DJ-stream toggle path:
- await setSinkId() before setting .src so it doesn't race + abort
the in-flight media load
- drop the 'stalled' handler that was ping-ponging WebRTC ↔ stream
on every transient mobile-cellular buffer pause
- make startStream idempotent on the same URL so a peer-joined
auto-enrollment race can't reset .src and self-abort
Plus preload="auto" and playsInline on the dynamic <audio> for
mobile compat. Fixes "no music on phone stream stalled" and the
"autoplay blocked: aborted at user's request" log spam from host
self-monitor clicks.
Moves the ◉/○ DJ-stream button out of the bottom mod-actions stack
into the dedicated `strm` grid column on the top row (next to the
mic icon). No more extra sub-row per speaker for the self-monitor or
host-controlled stream toggle — fixes the vertical scroll regression
when many members were in the room.