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');