From cc10876b93c505e9179a37010e446d31e27bd145 Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:25:42 +0100 Subject: [PATCH] feat: wire setVoiceWs into voice join and DM call handlers Adds device-switch guardrail to handleVoiceJoin: if the user already has a voice session on a different WebSocket, that old socket receives a voice_disconnected/displaced event before the new session takes over. Also binds voiceWs on the caller socket in handleDmCallStart and on the acceptor socket in handleDmCallAccept. --- packages/server/src/ws/events.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/server/src/ws/events.ts b/packages/server/src/ws/events.ts index 34e3a902..f3049ea1 100644 --- a/packages/server/src/ws/events.ts +++ b/packages/server/src/ws/events.ts @@ -573,6 +573,23 @@ function handleVoiceJoin(event: Record, userId: string, ws: Web return; } + // ── Device switch guardrail ── + // If this user already has a voice session on a different socket, + // notify that socket to tear down its LiveKit connection. + { + const oldVoiceWs = connectionManager.getVoiceWs(userId); + if (oldVoiceWs && oldVoiceWs !== ws) { + const oldRoom = connectionManager.getUserRoom(userId); + connectionManager.sendToWs(oldVoiceWs, { + type: 'voice_disconnected', + userId, + channelId: oldRoom?.roomId ?? channelId, + reason: 'displaced', + }); + } + connectionManager.setVoiceWs(userId, ws); + } + // If the user is already in this exact room (e.g. WS reconnect re-registration), // skip the leave+join broadcast to avoid visual flicker for other users. const currentRoom = connectionManager.getUserRoom(userId); @@ -1316,6 +1333,10 @@ function handleDmCallStart(event: Record, userId: string, usern return; } + // Bind voice session to this socket so removeConnection can clean up + // if the caller closes the tab while the call is ringing + connectionManager.setVoiceWs(userId, ws); + // Ring other members connectionManager.sendToDmMembers(dmChannelId, { type: 'dm_call_incoming', @@ -1378,6 +1399,9 @@ function handleDmCallAccept(event: Record, userId: string, ws: // Join acceptor into the DM room connectionManager.joinRoom(dmChannelId, userId); + // Bind voice session to this socket for the acceptor + connectionManager.setVoiceWs(userId, ws); + // Notify all DM members that the call was accepted connectionManager.sendToDmMembers(dmChannelId, { type: 'dm_call_accepted',