From d8c8dae4ba3c0e7606fe4170e5c4e61a1d415e0d Mon Sep 17 00:00:00 2001 From: Russell Ballestrini Date: Wed, 3 Jun 2026 10:57:05 -0400 Subject: [PATCH] zebra-spaces: bump camera mute window 15s -> 60s for phone-network jitter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Repro: host shares camera, laptop sees it fine, phone (FF Android on cellular) reaped the tile at 15s even though the publisher was alive and well. The laptop's subscribe path doesn't see the same RTP jitter the phone does — 15s was too tight for mobile networks. 60s sits above the typical NACK/transport-cc recovery window and Pion's ICE timeout: a path that's really broken fires renegotiation + 'ended' within that window anyway, so the only difference is fewer false reaps on jittery mobile paths. Screen + game window stays at 120s — static content needs the longer fuse. --- web/zebra-spaces.html | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/web/zebra-spaces.html b/web/zebra-spaces.html index 3f21c53..eeff56f 100644 --- a/web/zebra-spaces.html +++ b/web/zebra-spaces.html @@ -1609,23 +1609,30 @@ function flushSfuStreams(){ * isn't producing RTP — we cancel the removal. * * Window depends on the kind of content (caller passes via windowMs): - * - 15s for cameras: face/motion content keeps RTP flowing - * continuously, so a 15s gap is meaningful. Generous enough to - * weather Wi-Fi stalls and mobile network handoffs. - * - 120s for screen / gameshare: STATIC content (a still desktop, a + * - 60s for cameras: face/motion content keeps RTP flowing most of + * the time, but Firefox Android + cellular handoffs can stall a + * decoded video element on jittery paths well past 15s without + * the publisher being gone. 60s is comfortably above the typical + * NACK + transport-cc recovery window; matches Pion's ICE + * failure timeout, so if the path is genuinely broken the SFU + * fires renegotiation + 'ended' before this anyway. + * - 120s for screen / gameshare: STATIC content (still desktop, a * paused video, a code editor with no caret motion) doesn't push * new RTP for long stretches. The encoder genuinely stops emitting - * packets, the receiver's track goes muted, and the 15s window - * would falsely reap a live tile. 120s lets a static screen - * survive comfortably; a real unshare still resolves through the - * 'ended' path within a frame. + * packets; 120s lets a static screen survive comfortably. + * + * Genuine unshares always resolve through the 'ended' path (within a + * frame of the SFU's removePubFromSub), so these windows only matter + * for slow-failure scenarios (PC dies silently, SSE renegotiation + * dropped, etc.). * * Window history: * - 3s (all kinds): killed live tiles on any transient mute. - * - 15s (all kinds): cameras ok, but static screens vanished after - * 15s of no motion. - * - 15s camera / 120s screen+game (current). */ -const VIDEO_REMOVE_MUTE_WINDOW_MS = 15000; + * - 15s (all kinds): cameras ok on desktop, static screens vanished. + * - 15s camera / 120s screen+game: cameras OK on desktop, phone on + * cellular still occasionally reaped live faces during jitter. + * - 60s camera / 120s screen+game (current). */ +const VIDEO_REMOVE_MUTE_WINDOW_MS = 60000; const VIDEO_REMOVE_MUTE_WINDOW_SCREEN_MS = 120000; function watchVideoTrackForRemoval(track, removeFn, windowMs){ if (!track) return; @@ -3854,8 +3861,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');