diff --git a/desktop/src/main.ts b/desktop/src/main.ts index cd929b2..283c4a1 100644 --- a/desktop/src/main.ts +++ b/desktop/src/main.ts @@ -835,6 +835,14 @@ async function doConnect() { } } +// Phase 5.6: when we're in a direct P2P call (not relay- +// mediated), the relay's room infrastructure never sends a +// RoomUpdate because neither peer actually joined the room. +// pollStatus sees an empty participant list and shows "Waiting +// for participants...". Track the peer's identity from the +// signal plane and render a synthetic participant entry instead. +let directCallPeer: { fingerprint: string; alias: string | null } | null = null; + function showCallScreen() { connectScreen.classList.add("hidden"); callScreen.classList.remove("hidden"); @@ -855,6 +863,7 @@ function showConnectScreen() { connectBtn.disabled = false; connectBtn.textContent = "Connect"; levelBar.style.width = "0%"; + directCallPeer = null; if (statusInterval) { clearInterval(statusInterval); statusInterval = null; } } @@ -975,14 +984,23 @@ async function pollStatus() { const pct = rms > 0 ? Math.min(100, (Math.log(rms) / Math.log(32767)) * 100) : 0; levelBar.style.width = `${pct}%`; - // Participants grouped by relay - if (st.participants.length === 0) { + // Participants grouped by relay. For direct P2P calls the + // relay never sends a RoomUpdate (neither peer joins the + // relay's media room) so st.participants is empty. If we + // have a directCallPeer from the signal plane, inject a + // synthetic entry so the UI shows who we're talking to. + const displayParticipants = + st.participants.length === 0 && directCallPeer + ? [{ ...directCallPeer, relay_label: "P2P Direct" }] + : st.participants; + + if (displayParticipants.length === 0) { participantsDiv.innerHTML = '