zebra-spaces: ask room to re-announce mic-state on welcome + new peer-joined

Pairs with signal 33dcabf. Fixes the 'host refreshed and now sees
everyone as unmuted' UX gap. Two paths:

- On welcome (any rejoin): send mic-state-req; every speaker in the
  room responds with their current mic-state.
- On peer-joined for anyone else: if I'm a speaker with a live mic,
  re-broadcast my own state so the new arrival sees it without
  having to ping.

Both are bounded: only speakers respond, and the message is the same
E2E-encrypted blob used for normal mic toggles, so no extra privacy
surface beyond what already exists.
This commit is contained in:
Russell Ballestrini 2026-06-03 12:33:35 -04:00
parent b4e0c3d2d6
commit 236661b573
No known key found for this signature in database

View file

@ -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');
<footer style="margin:2.2rem auto 0;font-size:0.65rem;color:#999;line-height:1.7;word-break:break-all;font-family:monospace">
<span id="pi-seal" style="color:#777;cursor:default;user-select:none" title="">page integrity</span> &nbsp;·&nbsp; built <span class="stamp-date">2026-06-03</span><br>
md5 <span class="stamp-md5">66a614bab55cb7b90c288e575177dc4a</span><br>
sha256 <span class="stamp-sha">902f6be9372bc22eaa90e50e140efef9222c80ad30c92d093619c6d59a8c20a5</span><br>
md5 <span class="stamp-md5">4eea6662436f9989ee36bae6060af6e8</span><br>
sha256 <span class="stamp-sha">6a61928bf78af3bfde2e35902f0eca8d8fbb00e08ca56c596b25a0264a96df00</span><br>
<span style="color:#bbb">hashes are of this page with these two fields zeroed — to verify, blank them and re-hash</span><br>
<span style="color:#bbb">one self-contained file — <strong>save a copy</strong> and verify against these hashes; point at your own servers with ?signal= and ?turncred=, or <a href="host-your-own.html" style="color:#999">host your own community</a></span>
</footer>