- Camera and screen-share badges are decided by `shouldShowStreamIndicator`,
so a live stream is visible from outside the voice channel and clicking the
badge joins the streamer's channel before focusing the stream.
- `ringParticipants` reports whether a `direct-call` ring reached anyone; a
call that reached nobody shows `call.errors.ringUndelivered` instead of
sitting in "calling" as if it were live.
- Direct messages resolve every local identity alias, so a conversation
opened from a foreign roster entry lands in the same thread.
Outgoing voice was gated on the observer's roster copy of the remote user's
voice state, which is signaling gossip. The signal server broadcasts
`user_left` for any socket it declares dead, so a suspended laptop or a flaky
hop wiped that copy and the observer detached its microphone from a peer that
never left the channel - a silent member with no way back through the UI.
`decideVoicePathRouting` now closes a path only on positive evidence: we left
voice, the peer itself reported another channel or none, or the connection is
gone. Missing gossip holds an established path instead. Opening still needs
confirmation, so a guess never starts sending; the same rule gates playback,
camera video, and the microphone a new connection puts in its first offer.
Peers are also asked for their voice state when a connection or data channel
comes up, so a rebuilt path re-confirms itself.
Alongside it, the microphone can be switched mid-call: capture moves to a
device service and rules, the live track is swapped with `replaceTrack` so
the session is never renegotiated, and the speaking indicator follows the new
stream.
A client that could not authorize against a foreign signal server was
redirected into a dead end with no way to retry, so servers joined from
another signal route became unreachable.
The home server now stores a per-user provision secret, clients keep it in
their own store, and a recovery service records why authorization failed per
server URL. Invite, server browser, and chat room surface that reason and
offer a retry instead of silently redirecting.
Stream large receives to disk with chunk acks to cap renderer RAM, evict
off-screen display blobs, and route exports through a disk-aware download
service. Fix the high-memory dialog (backdrop dismiss, copy, log actions),
allow diagnostics paths in the path jail, and restore persisted image
hydration after reload.
Co-authored-by: Cursor <cursoragent@cursor.com>
Stream oversized generic attachments to disk instead of silently dropping chunks, avoid loading completed file downloads into renderer memory, and surface a clear error when the browser client cannot receive a file.
Co-authored-by: Cursor <cursoragent@cursor.com>
Expose settings logout on mobile where the title bar is hidden, and enable
Capacitor data settings with storage visibility and local erase/sign-out.
Co-authored-by: Cursor <cursoragent@cursor.com>