stale server sockets, passive non-initiators, and race conditions
during peer connection setup.
Fix users unable to see or hear each other in voice channels due to
stale server sockets, passive non-initiators, and race conditions
during peer connection setup.
Server:
- Close stale WebSocket connections sharing the same oderId in
handleIdentify instead of letting them linger up to 45s
- Make user_joined/user_left broadcasts identity-aware so duplicate
sockets don't produce phantom join/leave events
- Include serverIds in user_left payload for multi-room presence
- Simplify findUserByOderId now that stale sockets are cleaned up
Client - signaling:
- Add fallback offer system with 1s timer for missed user_joined races
- Add non-initiator takeover after 5s when the initiator fails to send
an offer (NON_INITIATOR_GIVE_UP_MS)
- Scope peerServerMap per signaling URL to prevent cross-server
collisions
- Add socket identity guards on all signaling event handlers
- Replace canReusePeerConnection with hasActivePeerConnection and
isPeerConnectionNegotiating with extended grace periods
Client - peer connections:
- Extract replaceUnusablePeer helper to deduplicate stale peer
replacement in offer and ICE handlers
- Add stale connectionstatechange guard to ignore events from replaced
RTCPeerConnection instances
- Use deterministic initiator election in peer recovery reconnects
- Track createdAt on PeerData for staleness detection
Client - presence:
- Add multi-room presence tracking via presenceServerIds on User
- Replace clearUsers + individual userJoined with syncServerPresence
for atomic server roster updates
- Make userLeft handle partial server removal instead of full eviction
Documentation:
- Add server-side connection hygiene, non-initiator takeover, and stale
peer replacement sections to the realtime README