diff --git a/zebra-report/zebra-spaces.html b/zebra-report/zebra-spaces.html index 9607626..25b065d 100644 --- a/zebra-report/zebra-spaces.html +++ b/zebra-report/zebra-spaces.html @@ -1868,7 +1868,7 @@ function renderCameraTile(pubHex, stream, opts){ return renderVideoTile('camera' function removeCameraTile(pubHex){ return removeVideoTile('camera', pubHex); } async function sfuPublish(){ - if (sfuPubPC){ logLine('','sfu publish: already publishing'); return; } + if (sfuPubPC) return; /* idempotent — re-entry from signal reconnect is fine */ if (!micStream || !myKeys || !roomID){ logLine('err','sfu publish skipped: mic='+(!!micStream)+' keys='+(!!myKeys)+' room='+(!!roomID)); return; @@ -2618,9 +2618,23 @@ async function handleSignal(raw){ let m; try { m = JSON.parse(raw); } catch(_){ return; } switch (m.type){ case 'welcome': - myUUID = m.your_uuid; myRole = m.role; roomEpoch = m.epoch; - applyState(m.state); - roomMachines.call.send('WELCOME', { uuid: myUUID, role: myRole }); + { + /* a second welcome arrives whenever the signal-WS reconnects. + * If our uuid hasn't changed, the SFU + mesh are still alive — + * just refresh state + role, don't re-run the whole setup + * (that's what caused 'sfu publish: already publishing' + + * other duplicate-effect noise during reconnect cycles). */ + const reentry = !!myUUID && myUUID === m.your_uuid; + myUUID = m.your_uuid; myRole = m.role; roomEpoch = m.epoch; + applyState(m.state); + roomMachines.call.send('WELCOME', { uuid: myUUID, role: myRole }); + if (reentry){ + logLine('', 'signal re-welcomed — role still '+myRole); + flushSfuStreams(); + renderRoom(); + break; + } + } /* any tile auto-spotlit before welcome (during fast-path subscribe) * needs to be broadcast now so the room sees our viewing state */ spotlights.set(myUUID, spotlightKey()); @@ -3491,8 +3505,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');