Files
backspace/packages/web/src/stores/voiceStore.js
T
Jannis Braun 4f65ea9c86 fix: resolve LiveKit voice/video stability issues
- Guard Disconnected/ConnectionStateChanged event handlers against stale rooms:
  old room events no longer nuke the new room's state (root cause of buttons
  failing, mute getting stuck, DUPLICATE_IDENTITY cascades)
- Reset media state (isMuted/isCameraOn/isScreenSharing) on connect to prevent
  desync after reconnects
- Add voiceStates to WS ready payload so users see who's in voice on page load
- Wire VoiceControls buttons to check getActiveRoom() before SDK calls
- Guard ChannelSidebar against re-joining the same voice channel
- Switch LIVEKIT_URL to wss://nova.ddns.net/livekit for HTTPS secure context
  (required for getUserMedia in Safari)
2026-02-18 07:52:25 +01:00

58 lines
2.2 KiB
JavaScript

import { create } from 'zustand';
export const useVoiceStore = create((set, get) => ({
voiceUsers: new Map(),
currentVoiceChannelId: null,
isMuted: false,
isDeafened: false,
isCameraOn: false,
isScreenSharing: false,
participants: [],
connectionError: null,
isLiveKitConnected: false,
setVoiceUsers: (channelId, userIds) => {
set((state) => {
const newMap = new Map(state.voiceUsers);
newMap.set(channelId, userIds);
return { voiceUsers: newMap };
});
},
addVoiceUser: (channelId, userId) => {
set((state) => {
const newMap = new Map(state.voiceUsers);
const current = newMap.get(channelId) ?? [];
if (!current.includes(userId)) {
newMap.set(channelId, [...current, userId]);
}
return { voiceUsers: newMap };
});
},
removeVoiceUser: (channelId, userId) => {
set((state) => {
const newMap = new Map(state.voiceUsers);
const current = newMap.get(channelId) ?? [];
newMap.set(channelId, current.filter(id => id !== userId));
return { voiceUsers: newMap };
});
},
setCurrentVoiceChannel: (channelId) => set({ currentVoiceChannelId: channelId }),
setParticipants: (participants) => set({ participants }),
setConnectionError: (error) => set({ connectionError: error }),
setIsLiveKitConnected: (connected) => set({ isLiveKitConnected: connected }),
toggleMic: () => set((state) => ({ isMuted: !state.isMuted })),
toggleDeafen: () => set((state) => ({ isDeafened: !state.isDeafened })),
toggleCamera: () => set((state) => ({ isCameraOn: !state.isCameraOn })),
toggleScreenShare: () => set((state) => ({ isScreenSharing: !state.isScreenSharing })),
getVoiceUsers: (channelId) => get().voiceUsers.get(channelId) ?? [],
reset: () => set({
voiceUsers: new Map(),
currentVoiceChannelId: null,
isMuted: false,
isDeafened: false,
isCameraOn: false,
isScreenSharing: false,
participants: [],
connectionError: null,
isLiveKitConnected: false,
}),
}));