zebra-spaces: clear DJ-stream state on leave + re-prime audio every entry
Two regressions where the phone went silent across a leave + re-enter cycle, with no way to recover short of a hard refresh: 1. Leave handler tore down WebRTC + members + tiles but left: - streamMode (Set of streaming pubHexes) - streamAudio (uuid -> <audio>) - audioPath (uuid -> 'dj'|'rtc') - autoEnrolRetryTimer running On the next entry as listener, autoEnableDjModeForListener would skip every pubHex because streamMode.has(pubHex) was still true from the prior session → startStream never called → no HTTP /stream request → phone falls back to WebRTC and stays there even when the host's mic publish is live. Fix: stopAutoEnrolRetryLoop + autoDisableDjModeForAll + remove every stale streamAudio element from the DOM + clear all three maps as part of the leave click handler. 2. primeAudioOnGesture had an audioPrimed=true short-circuit that skipped the silent-WAV prime on re-entry. Mobile browsers can suspend the audio session on tab background / leave, so a one-shot prime doesn't carry across sessions. Drop the gate — every entry click re-primes. The primer element self-removes 500ms after play() resolves so we don't accumulate hidden <audio> elements. Tests green (83 fsm + 16 zebra-spaces).
This commit is contained in:
parent
f196714410
commit
8d861e94a6
1 changed files with 25 additions and 6 deletions
|
|
@ -4785,16 +4785,22 @@ document.addEventListener('visibilitychange', () => {
|
|||
* Tiny WAV header + 1 sample of silence — the smallest valid PCM
|
||||
* audio resource a browser will accept. Base64 ~80 bytes. */
|
||||
const SILENCE_WAV = 'data:audio/wav;base64,UklGRiYAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQIAAAAAAA==';
|
||||
let audioPrimed = false;
|
||||
/* audioPrimed gate REMOVED — every entry click should re-prime even
|
||||
* after a successful first prime. Mobile browsers can suspend the
|
||||
* audio session on tab background / leave; the next entry click needs
|
||||
* a fresh play() to re-bless audio for the new session. */
|
||||
function primeAudioOnGesture(){
|
||||
if (audioPrimed) return;
|
||||
const a = document.createElement('audio');
|
||||
a.src = SILENCE_WAV; a.muted = false; a.volume = 0;
|
||||
a.style.display = 'none';
|
||||
document.body.appendChild(a);
|
||||
const p = a.play();
|
||||
if (p && p.then) p.then(() => { audioPrimed = true; })
|
||||
.catch(()=>{ /* still try the rest of join */ });
|
||||
if (p && p.then) p.then(() => {
|
||||
/* keep the element around briefly so the play() actually emits a
|
||||
* frame; then yank it from the DOM to avoid a growing pile of
|
||||
* primer elements after many entry clicks. */
|
||||
setTimeout(() => { try { a.remove(); } catch(_){} }, 500);
|
||||
}).catch(()=>{ try { a.remove(); } catch(_){} });
|
||||
/* Also try resuming any existing AudioContext (meter / chime).
|
||||
* resume() on an already-running context is a no-op, and on a
|
||||
* suspended one it transitions to running — granting Web Audio
|
||||
|
|
@ -4860,6 +4866,19 @@ $('btn-leave').addEventListener('click', async () => {
|
|||
try { sessionStorage.removeItem(ACTIVE_CALL_KEY); } catch(_){}
|
||||
try { sessionStorage.removeItem(ACTIVE_CAM_KEY); } catch(_){}
|
||||
if (sigReconnect){ clearTimeout(sigReconnect); sigReconnect = null; }
|
||||
/* tear down ALL DJ-mode HTTP streams + their <audio> elements +
|
||||
* clear streamMode / audioPath so a fresh entry doesn't get
|
||||
* blocked by `streamMode.has(pubHex)` from the old session.
|
||||
* Stops the auto-enrol retry loop too — it'd otherwise tick on
|
||||
* for the next 4s firing at a dead members map. */
|
||||
stopAutoEnrolRetryLoop();
|
||||
autoDisableDjModeForAll();
|
||||
for (const a of [...streamAudio.values()]){
|
||||
try { a.pause(); a.removeAttribute('src'); a.load(); a.remove(); } catch(_){}
|
||||
}
|
||||
streamAudio.clear();
|
||||
streamMode.clear();
|
||||
audioPath.clear();
|
||||
for (const u of [...peers.keys()]) tearPeer(u);
|
||||
/* send 'bye' BEFORE closing the WS — server distinguishes a strong
|
||||
* leave (user clicked leave / closed tab) from a hiccup disconnect
|
||||
|
|
@ -4907,8 +4926,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');
|
|||
|
||||
<footer style="margin:2.2rem auto 0;font-size:0.65rem;color:#999;line-height:1.7;word-break:break-all;font-family:monospace">
|
||||
<span id="pi-seal" style="color:#777;cursor:default;user-select:none" title="">page integrity</span> · built <span class="stamp-date">2026-06-04</span><br>
|
||||
md5 <span class="stamp-md5">62e317cdbfd3e536107c394d0380e36c</span><br>
|
||||
sha256 <span class="stamp-sha">4e3cee1e45894ed48628267704c5658fca14da3ca169de4366f69e4c3e48fc0c</span><br>
|
||||
md5 <span class="stamp-md5">8a8a289a9c7301537a899c53e1f6b762</span><br>
|
||||
sha256 <span class="stamp-sha">740fb758e0de907972a277b4f961ea21b978d76e980b853f4a616954ab7c0e47</span><br>
|
||||
<span style="color:#bbb">hashes are of this page with these two fields zeroed — to verify, blank them and re-hash</span><br>
|
||||
<span style="color:#bbb">one self-contained file — <strong>save a copy</strong> and verify against these hashes; point at your own servers with ?signal= and ?turncred=, or <a href="host-your-own.html" style="color:#999">host your own community</a></span>
|
||||
</footer>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue