diff --git a/zebra-report/zebra-spaces.html b/zebra-report/zebra-spaces.html index ab5456b..231fd54 100644 --- a/zebra-report/zebra-spaces.html +++ b/zebra-report/zebra-spaces.html @@ -2531,10 +2531,17 @@ function handleRemoteSfuTrack(ev){ for (const [uuid, mm] of members){ try { if (mm.pubkey && hex(unb64(mm.pubkey)) === pubHex){ - /* speakers get their peers' audio via mesh (lower latency) — - * skip the duplicate SFU mic. screens + cameras still came - * through above. */ - if (canSpeak(myRole) && peers.has(uuid)) return; + /* speakers get their peers' audio via mesh (lower latency) + * AT THE TIMES THE MESH PC IS CONNECTED. A stale or failing + * mesh PC must NOT block the SFU fallback — that's how the + * 'phone re-promoted but nobody hears them' regression + * appeared: the peers map still had an entry whose state + * was 'failed', so we skipped SFU and the receiver got no + * audio at all. */ + if (canSpeak(myRole)){ + const meshPC = peers.get(uuid); + if (meshPC && meshPC.connectionState === 'connected') return; + } attachSfuTrack(uuid, ev.streams[0]); return; } @@ -3433,6 +3440,11 @@ async function connectToPeer(uuid, weOffer){ if (pc.connectionState === 'failed' && peers.get(uuid) === pc){ logLine('', 'peer '+uuid+' failed — reconnecting'); tearPeer(uuid); + /* Mesh PC just died; the audio element for this peer was bound to + * the dying mesh stream and won't recover on its own. Switch back + * to the cached SFU stream so the user keeps hearing them while + * mesh reconnect attempts run in the background. */ + try { attachCachedSfuStreamFor(uuid); } catch(_){} /* let the offerer drive recovery */ setTimeout(()=>{ if (members.has(uuid) && canSpeak(members.get(uuid).role) && canSpeak(myRole)) connectToPeer(uuid, myUUID < uuid); }, 1500); @@ -4010,8 +4022,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');