From 1e8464e7af0a8933b21da5156b073eb452a36ace Mon Sep 17 00:00:00 2001 From: Russell Ballestrini Date: Wed, 3 Jun 2026 12:45:38 -0400 Subject: [PATCH] =?UTF-8?q?zebra-spaces:=20don't=20auto-rebuild=20screen?= =?UTF-8?q?=20publish=20PC=20=E2=80=94=20needs=20user=20gesture?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug surfaced in CLIENT_LOG telemetry from a real session: when the host's screen publish PC hit ICE failure, the watchPublishPC auto- rebuilder called sfuPublishScreen() which immediately failed with 'getDisplayMedia requires transient activation from a user gesture.' The auto-call path has no click, so getDisplayMedia can never succeed from there. Match the game-share pattern: on 'failed' tear down the dead PC + log a clear 'tap share screen to re-share' message + clear state via sfuUnpublishScreen(). User clicks the share button → picker opens (the click IS the gesture) → fresh publish PC. Mic + camera keep their auto-rebuild because getUserMedia honors the persisted permission grant, no gesture needed. --- web/zebra-spaces.html | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/web/zebra-spaces.html b/web/zebra-spaces.html index 33e1fc0..ab5456b 100644 --- a/web/zebra-spaces.html +++ b/web/zebra-spaces.html @@ -2188,9 +2188,16 @@ async function sfuPublishScreen(){ if (s.track.kind === 'video') setSenderMaxBitrate(s, 6000000); if (s.track.kind === 'audio') setSenderMaxBitrate(s, 256000); } - watchPublishPC(pc, 'screen', sfuPublishScreen, - () => sfuScreenPC === pc, - () => { sfuScreenPC = null; sfuScreenPeerID = null; sfuScreenStream = null; }); + /* Screen share CANNOT auto-rebuild like mic + camera — getDisplayMedia + * requires a fresh user gesture (transient activation). Auto-calling + * sfuPublishScreen() after a 'failed' state just fires the picker + * with no gesture and gets rejected. Instead: tear down on failed + * + surface the share button so the user can re-trigger themselves. */ + pc.onconnectionstatechange = () => { + if (pc.connectionState !== 'failed' || sfuScreenPC !== pc) return; + logLine('err', 'sfu screen publish PC failed — tap "share screen" to re-share (browsers need a fresh click for screen capture)'); + sfuUnpublishScreen().catch(()=>{}); + }; logLine('', 'sfu: sharing screen as '+sfuScreenPeerID); /* render a muted local preview so the publisher sees what they're * sharing — SFU does not echo the publisher's own stream back */ @@ -4003,8 +4010,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');