diff --git a/web/zebra-spaces.html b/web/zebra-spaces.html index a916b6b..d98bb51 100644 --- a/web/zebra-spaces.html +++ b/web/zebra-spaces.html @@ -2204,25 +2204,33 @@ async function sfuSubscribe(){ logLine('', 'sfu ontrack: kind=' + kind + ' pub=' + pubHex + ' track=' + ev.track.kind + ' mute=' + ev.track.muted + ' state=' + ev.track.readyState); } + /* Stream-identity guard on removeFn: when a publisher supplants + * themselves (typical: hard refresh — new SFU peer_id same pubkey + + * kind), the OLD track's mute → ended → removeFn would tear down the + * tile that the NEW track just installed. Only remove if the stream + * we registered against is still the one in the store for this pub. */ if (kind === 'screen'){ - screenStreams.set(pubHex, ev.streams[0]); - renderScreenTile(pubHex, ev.streams[0]); - watchVideoTrackForRemoval(ev.track, () => removeScreenTile(pubHex)); + const s = ev.streams[0]; + screenStreams.set(pubHex, s); + renderScreenTile(pubHex, s); + watchVideoTrackForRemoval(ev.track, () => { if (screenStreams.get(pubHex) === s) removeScreenTile(pubHex); }); return; } if (kind === 'camera'){ - cameraStreams.set(pubHex, ev.streams[0]); - renderCameraTile(pubHex, ev.streams[0]); - watchVideoTrackForRemoval(ev.track, () => removeCameraTile(pubHex)); + const s = ev.streams[0]; + cameraStreams.set(pubHex, s); + renderCameraTile(pubHex, s); + watchVideoTrackForRemoval(ev.track, () => { if (cameraStreams.get(pubHex) === s) removeCameraTile(pubHex); }); return; } if (kind === 'game'){ /* a publisher is sharing their gameplay (Region-Capture cropped * iframe). Route to its own TILE_KIND so it coexists with a * normal screen-share from the same person. */ - gameStreams.set(pubHex, ev.streams[0]); - renderVideoTile('gameshare', pubHex, ev.streams[0]); - watchVideoTrackForRemoval(ev.track, () => removeVideoTile('gameshare', pubHex)); + const s = ev.streams[0]; + gameStreams.set(pubHex, s); + renderVideoTile('gameshare', pubHex, s); + watchVideoTrackForRemoval(ev.track, () => { if (gameStreams.get(pubHex) === s) removeVideoTile('gameshare', pubHex); }); return; } if (kind !== 'mic'){ @@ -3595,8 +3603,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');