From 61d456d113f08f12e0890f1dd1397352d9ba311b Mon Sep 17 00:00:00 2001 From: Russell Ballestrini Date: Fri, 5 Jun 2026 16:05:54 -0400 Subject: [PATCH] zebra-spaces: prime audioCtx on first interaction anywhere (fix desktop auto-rejoin regression) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fox 2026-06-05: "speaker on firefox chrome was hard restarted and cannot hear host" / "host is working phone listeners hear host, speaker does not see hosts mic open or waveform." Root cause: desktop auto-rejoin reaches joinSpace() without a click, so primeAudioOnGesture() never fires. Chrome (Fedora especially) leaves audioCtx suspended until a real user gesture, and the fire-and-forget audioCtx.resume() inside attachAudioStreamViaWorklet silently fails outside one. Worklet reports "started" but the destination renders nothing, the meter analyser pulls no samples → no audio, no waveform, no mic-open indicator (the indicator IS the waveform). Pre-zero-click-auto-rejoin, the manual entry button always primed audio; the regression arrived with that convenience. Now: install a document-wide one-shot click/keydown/touchstart listener that calls primeAudioOnGesture() on first interaction anywhere. Zero-click auto-rejoin convenience preserved — any later page click engages audio for the rest of the session. Listener self-unregisters after firing so we don't repeatedly spawn silent oscillators. Idempotent — primeAudioOnGesture's audioCtx check makes re-runs safe. --- web/zebra-spaces.html | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/web/zebra-spaces.html b/web/zebra-spaces.html index 8867285..77bd97d 100644 --- a/web/zebra-spaces.html +++ b/web/zebra-spaces.html @@ -7365,6 +7365,34 @@ $('rdv-code').addEventListener('keydown', e=>{ if(e.key==='Enter'){ e.preventDefault(); primeAudioOnGesture(); joinSpace(); } }); +/* Desktop auto-rejoin (below) reaches joinSpace() without a click, so + * the entry-button gesture never fires. Chrome (Fedora especially) + * leaves audioCtx suspended until a real user gesture, and the + * fire-and-forget audioCtx.resume() inside attachAudioStreamViaWorklet + * silently fails outside a gesture → no audio, no waveform, no + * mic-open indicator. Fox 2026-06-05: "speaker on firefox chrome was + * hard restarted and cannot hear host." + * + * Document-wide one-shot listener: on first interaction anywhere (any + * click, any keydown), prime audio. Idempotent — primeAudioOnGesture() + * is safe to re-run because it checks `audioCtx` and only resumes if + * suspended. Unregisters itself after firing so we don't repeatedly + * spawn silent oscillators. */ +(function installFirstGesturePrimer(){ + let primed = false; + function prime(){ + if (primed) return; + primed = true; + try { primeAudioOnGesture(); } catch(e){ logLine('err','first-gesture prime: '+e.message); } + document.removeEventListener('click', prime, true); + document.removeEventListener('keydown', prime, true); + document.removeEventListener('touchstart', prime, true); + } + document.addEventListener('click', prime, true); + document.addEventListener('keydown', prime, true); + document.addEventListener('touchstart', prime, true); +})(); + /* ?code=… autofills the rendezvous code (used by the share URL). The code * stays in the URL so a refresh keeps you in the same space; if you want * to leave it cleanly, hit the leave button or close the tab. */ @@ -7504,8 +7532,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');