diff --git a/src/app/call/voice.ts b/src/app/call/voice.ts index c74cdaad..5d93aa6b 100644 --- a/src/app/call/voice.ts +++ b/src/app/call/voice.ts @@ -92,6 +92,27 @@ const syncParticipantMedia = (participant: Participant) => { }) } +// LiveKit does not emit ParticipantConnected/Disconnected during reconnect. +const resyncAfterReconnect = (room: LiveKitRoom) => { + const next = new Map() + for (const p of [room.localParticipant, ...room.remoteParticipants.values()]) { + next.set(p.identity, {muted: !p.isMicrophoneEnabled, cameraOn: p.isCameraEnabled}) + } + participantMediaState.set(next) + + const session = get(currentVoiceSession) + if (session?.room !== room) return + + const {localParticipant} = room + voiceMicMuted.set(!localParticipant.isMicrophoneEnabled) + currentVoiceSession.set({ + ...session, + cameraOn: localParticipant.isCameraEnabled, + screenShareOn: localParticipant.isScreenShareEnabled, + }) + triggerVideoFeedCount() +} + const onParticipantMediaChanged = (_publication: TrackPublication, participant: Participant) => { syncParticipantMedia(participant) } @@ -191,6 +212,11 @@ const setUpMicrophone = async ( // (after switching calls or an engine reconnect give-up) must not clobber it. let activeRoom: LiveKitRoom | undefined +const makeOnRoomReconnected = (room: LiveKitRoom) => () => { + if (room !== activeRoom) return + resyncAfterReconnect(room) +} + const makeOnRoomDisconnected = (room: LiveKitRoom) => (reason?: DisconnectReason) => { // Ignore disconnects from rooms that are no longer the active session. if (room !== activeRoom) return @@ -320,6 +346,7 @@ export const joinVoiceRoom = async ( activeRoom = liveKitRoom liveKitRoom.on(RoomEvent.Disconnected, makeOnRoomDisconnected(liveKitRoom)) + liveKitRoom.on(RoomEvent.Reconnected, makeOnRoomReconnected(liveKitRoom)) liveKitRoom.on(RoomEvent.ParticipantConnected, onParticipantConnected) liveKitRoom.on(RoomEvent.ParticipantDisconnected, onParticipantDisconnected) liveKitRoom.on(RoomEvent.TrackSubscribed, onTrackSubscribed) diff --git a/src/app/components/VoiceWidget.svelte b/src/app/components/VoiceWidget.svelte index 195b36be..84954710 100644 --- a/src/app/components/VoiceWidget.svelte +++ b/src/app/components/VoiceWidget.svelte @@ -44,7 +44,7 @@ voiceMicMuted, voiceState, } from "@app/call/stores" - import {cancelJoinVoiceRoom, leaveVoiceRoom, toggleMute} from "@app/call/voice" + import {cancelJoinVoiceRoom, joinVoiceRoom, leaveVoiceRoom, toggleMute} from "@app/call/voice" const {relay, h} = $derived($page.params) const url = $derived(relay ? decodeRelay(relay) : undefined) @@ -86,6 +86,11 @@ pushModal(VoiceRoomJoinDialog, {url: targetRoom.url, h: targetRoom.h}) } + const onReconnect = () => { + if (!targetRoom) return + void joinVoiceRoom(targetRoom.url, targetRoom.h) + } + const goToRoom = () => { if (!targetRoom) return const path = makeRoomPath(targetRoom.url, targetRoom.h) @@ -237,6 +242,13 @@ onclick={leaveVoiceRoom}> + {:else if $currentVoiceRoom} + {:else}