fix: notify displaced tab when user joins voice from another session
When a user joins a voice channel while already connected from another tab, the server now sends a 'displaced' reason on voice_disconnected. The client tears down LiveKit and shows an informational toast.
This commit is contained in:
@@ -537,6 +537,14 @@ function handleVoiceJoin(event: Record<string, unknown>, userId: string): void {
|
||||
const left = connectionManager.leaveCurrentRoom(userId);
|
||||
if (left) {
|
||||
broadcastRoomLeave(left.roomId, left.room, userId);
|
||||
|
||||
// Notify all of the user's tabs so the displaced tab tears down LiveKit
|
||||
connectionManager.sendToUser(userId, {
|
||||
type: 'voice_disconnected',
|
||||
userId,
|
||||
channelId: left.roomId,
|
||||
reason: 'displaced',
|
||||
});
|
||||
}
|
||||
|
||||
// Cancel any ringing DM rooms where this user is the caller
|
||||
|
||||
@@ -330,7 +330,7 @@ export type ServerEvent =
|
||||
| { type: 'voice_space_deafened'; userId: string; channelId: string; spaceId: string; deafened: boolean }
|
||||
| { type: 'voice_permission_muted'; userId: string; spaceId: string; muted: boolean }
|
||||
| { type: 'voice_moved'; userId: string; oldChannelId: string; newChannelId: string }
|
||||
| { type: 'voice_disconnected'; userId: string; channelId: string }
|
||||
| { type: 'voice_disconnected'; userId: string; channelId: string; reason?: 'displaced' }
|
||||
| { type: 'user_updated'; user: User }
|
||||
| { type: 'member_banned'; spaceId: string; reason: string | null }
|
||||
| { type: 'category_created'; category: ChannelCategory; spaceId: string }
|
||||
|
||||
@@ -9,6 +9,8 @@ import type { ServerEvent, ClientEvent, ActiveCallInfo } from '@backspace/shared
|
||||
import { resolveAssetUrl, normalizeUserAssets, normalizeMessageAssets } from '../utils/assetUrls';
|
||||
import { broadcastVoiceStatus, broadcastDeafenViaLiveKit } from '../utils/voice';
|
||||
import { registerSelfId } from '../utils/identity';
|
||||
import { getActiveRoom } from './useLiveKit';
|
||||
import { useUIStore } from '../stores/uiStore';
|
||||
|
||||
// ─── Connection state ─────────────────────────────────────────────────────────
|
||||
|
||||
@@ -428,7 +430,14 @@ function handleEvent(origin: string, event: ServerEvent): void {
|
||||
case 'voice_disconnected': {
|
||||
const myDisconnectId = isHome ? useAuthStore.getState().user?.id : getMyUserIdForOrigin(origin);
|
||||
if (event.userId === myDisconnectId) {
|
||||
const { currentVoiceChannelId } = useVoiceStore.getState();
|
||||
if (event.channelId === currentVoiceChannelId) {
|
||||
useVoiceStore.getState().handleForceDisconnect();
|
||||
getActiveRoom()?.disconnect();
|
||||
if (event.reason === 'displaced') {
|
||||
useUIStore.getState().addToast('Voice disconnected — joined from another session', 'info');
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user