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)
This commit is contained in:
Jannis Braun
2026-02-18 07:52:25 +01:00
parent 5ef502f2e3
commit 4f65ea9c86
27 changed files with 573 additions and 143 deletions
@@ -1,5 +1,6 @@
import React, { useRef, useEffect } from 'react';
import { Avatar } from '../ui/Avatar';
import { useVoiceStore } from '../../stores/voiceStore';
import type { ParticipantInfo } from '../../hooks/useLiveKit';
interface VoiceUserProps {
@@ -9,6 +10,7 @@ interface VoiceUserProps {
export function VoiceUser({ participant }: VoiceUserProps) {
const videoRef = useRef<HTMLVideoElement>(null);
const audioRef = useRef<HTMLAudioElement>(null);
const isDeafened = useVoiceStore((s) => s.isDeafened);
useEffect(() => {
const videoEl = videoRef.current;
@@ -31,6 +33,14 @@ export function VoiceUser({ participant }: VoiceUserProps) {
audioEl.srcObject = stream;
}, [participant.audioTrack]);
// Mute remote audio when deafened
useEffect(() => {
const audioEl = audioRef.current;
if (audioEl) {
audioEl.muted = isDeafened;
}
}, [isDeafened]);
const hasVideo = participant.isCameraOn || participant.isScreenSharing;
const isLocal = participant.isLocal;