diff --git a/web/zebra-spaces.html b/web/zebra-spaces.html index dcf8661..dc6dbde 100644 --- a/web/zebra-spaces.html +++ b/web/zebra-spaces.html @@ -3012,12 +3012,29 @@ async function handleSignal(raw){ renderShareUrl(); onRoleEntered(); renderRoom(); + /* Ask the room to re-broadcast their current mic-state so our + * member list shows the right mute icons. Without this, mm.muted + * defaults to undefined and the UI reports every peer as + * 'open' until they happen to toggle. Fires for hiccup-takeover + * too (since the welcome path runs on every reconnect). */ + try { send({ type: 'mic-state-req' }); } catch(_){} break; case 'state': roomEpoch = m.epoch; applyState(m.state); flushSfuStreams(); renderRoom(); break; + case 'mic-state-req': + /* Another peer just (re)joined and asked the room to re-announce. + * Only speakers with a live mic respond — listeners have no + * meaningful mic-state to share. */ + if (canSpeak(myRole) && micStream) sendMicState(); + break; case 'peer-joined': members.set(m.uuid, { uuid:m.uuid, pubkey:m.pubkey, handle:m.handle, role:m.role, joined_at: Date.now()/1000 }); { const pub = pubHexFromMsg(m, 'pubkey'); logLine('', idTag(m.uuid, pub)+' joined as '+m.role); } + /* re-announce our mic state so the new arrival's UI reflects + * reality. Server-side mic-state-req covers welcome timing; this + * covers the standard 'a new peer joined while we were already + * here' case. */ + if (canSpeak(myRole) && micStream) sendMicState(); /* if the original host rejoined during their grace window, the room * is rescued — drop the "space closing" status from our top bar */ if (m.role === 'host'){ @@ -3915,8 +3932,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');