From 497d14e028e2a913193f7f475c0b15d3a37f8278 Mon Sep 17 00:00:00 2001 From: userAdityaa Date: Tue, 19 May 2026 22:42:56 +0530 Subject: [PATCH] fix: video blink when toggling mic mute in calls --- src/app/call/stores.ts | 4 +++- src/app/call/voice.ts | 14 ++++++++------ src/app/components/VoiceWidget.svelte | 10 +++++----- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/app/call/stores.ts b/src/app/call/stores.ts index abe4084e..9b5fbac0 100644 --- a/src/app/call/stores.ts +++ b/src/app/call/stores.ts @@ -6,11 +6,13 @@ export type VoiceSession = { url: string h: string room: LiveKitRoom - muted: boolean cameraOn: boolean screenShareOn: boolean } +/** Mic mute state is separate so toggling it does not re-render video tiles. */ +export const voiceMicMuted = writable(true) + export type Pubkey = string export type VoiceParticipant = {pubkey?: Pubkey; identity: string} diff --git a/src/app/call/voice.ts b/src/app/call/voice.ts index 07ab0648..050e2385 100644 --- a/src/app/call/voice.ts +++ b/src/app/call/voice.ts @@ -13,7 +13,7 @@ import { type AudioCaptureOptions, } from "livekit-client" import {derived, get} from "svelte/store" -import {map, removeUndefined, uniqBy} from "@welshman/lib" +import {map, not, removeUndefined, uniqBy} from "@welshman/lib" import type {TrustedEvent} from "@welshman/util" import {makeHttpAuth, makeHttpAuthHeader, getTags} from "@welshman/util" import {signer} from "@welshman/app" @@ -22,6 +22,7 @@ import {AbortError, whenAborted, whenTimeout} from "$lib/util" import { currentVoiceRoom, currentVoiceSession, + voiceMicMuted, participantFromLiveKitIdentity, participantKey, participantPubkeyMap, @@ -173,6 +174,7 @@ const setUpMicrophone = async ( const onRoomDisconnected = (reason?: DisconnectReason) => { videoPrimaryTileKey.set(undefined) + voiceMicMuted.set(true) currentVoiceSession.set(undefined) resetVideoCallLayout() if (reason !== undefined && reason !== DisconnectReason.CLIENT_INITIATED) { @@ -295,11 +297,11 @@ export const joinVoiceRoom = async ( const muted = await setUpMicrophone(startMuted, preferredMicId, liveKitRoom.localParticipant) + voiceMicMuted.set(muted) currentVoiceSession.set({ url, h, room: liveKitRoom, - muted, cameraOn: false, screenShareOn: false, }) @@ -339,6 +341,7 @@ export const leaveVoiceRoom = async () => { voiceState.set(VoiceState.Disconnected) videoPrimaryTileKey.set(undefined) + voiceMicMuted.set(true) currentVoiceSession.set(undefined) resetVideoCallLayout() session.room.disconnect() @@ -356,18 +359,17 @@ export const toggleMute = async () => { const session = get(currentVoiceSession) if (!session) return - const muted = !session.muted - if (muted) { + voiceMicMuted.update(not) + if (get(voiceMicMuted)) { // Disable and re-enable microphone to trigger permission prompt session.room.localParticipant.setMicrophoneEnabled(false) - currentVoiceSession.set({...session, muted}) return } try { await session.room.localParticipant.setMicrophoneEnabled(true) - currentVoiceSession.set({...session, muted}) } catch (e) { + voiceMicMuted.set(true) pushToast({theme: "error", message: "Could not access microphone"}) } } diff --git a/src/app/components/VoiceWidget.svelte b/src/app/components/VoiceWidget.svelte index c8601644..1882b3f8 100644 --- a/src/app/components/VoiceWidget.svelte +++ b/src/app/components/VoiceWidget.svelte @@ -41,6 +41,7 @@ VoiceState, currentVoiceSession, currentVoiceRoom, + voiceMicMuted, voiceState, isLocalSpeaking, } from "@app/call/stores" @@ -183,18 +184,17 @@ {:else if $voiceState === VoiceState.Connected && $currentVoiceSession}