From 361de29780f90ee6744c78faae771a575ab2e694 Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Mon, 11 Aug 2025 12:20:32 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=A9=B9(frontend)=20refactor=20track=20mut?= =?UTF-8?q?ing=20for=20proper=20audio/video=20control?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix useTrackToggle hook that wasn't properly muting/unmuting tracks outside room context. Previously only toggled boolean state via setUpManualToggle without actual track control. This caused misleading visual feedback where prejoin showed "camera disabled" while hardware remained active. Users could see camera/mic LEDs still on despite UI indicating otherwise. Refactor provides genuine track muting for accurate user feedback. --- .../rooms/components/join/ToggleDevice.tsx | 52 ++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/frontend/src/features/rooms/components/join/ToggleDevice.tsx b/src/frontend/src/features/rooms/components/join/ToggleDevice.tsx index b47a518c..155ae33e 100644 --- a/src/frontend/src/features/rooms/components/join/ToggleDevice.tsx +++ b/src/frontend/src/features/rooms/components/join/ToggleDevice.tsx @@ -1,4 +1,4 @@ -import { useTrackToggle, UseTrackToggleProps } from '@livekit/components-react' +import { UseTrackToggleProps } from '@livekit/components-react' import { ToggleDevice as BaseToggleDevice } from '../../livekit/components/controls/ToggleDevice' import { TOGGLE_DEVICE_CONFIG, @@ -6,6 +6,9 @@ import { } from '../../livekit/config/ToggleDeviceConfig' import { LocalAudioTrack, LocalVideoTrack } from 'livekit-client' import { ButtonRecipeProps } from '@/primitives/buttonRecipe' +import { useCallback, useMemo, useState } from 'react' +import { useSnapshot } from 'valtio' +import { permissionsStore } from '@/stores/permissions' type ToggleDeviceProps = UseTrackToggleProps & { track?: LocalAudioTrack | LocalVideoTrack | undefined @@ -13,20 +16,57 @@ type ToggleDeviceProps = UseTrackToggleProps & { variant?: NonNullable['variant'] } -export const ToggleDevice = ( - props: ToggleDeviceProps -) => { +export const ToggleDevice = ({ + track, + onChange, + ...props +}: ToggleDeviceProps) => { const config = TOGGLE_DEVICE_CONFIG[props.source] if (!config) { throw new Error('Invalid source') } - const trackProps = useTrackToggle(props) + const [isTrackEnabled, setIsTrackEnabled] = useState( + props.initialState ?? false + ) + + const permissions = useSnapshot(permissionsStore) + + const isPermissionDeniedOrPrompted = useMemo(() => { + if (config.kind == 'audioinput') { + return permissions.isMicrophoneDenied || permissions.isMicrophonePrompted + } + if (config.kind == 'videoinput') { + return permissions.isCameraDenied || permissions.isCameraPrompted + } + }, [config, permissions]) + + const toggle = useCallback(async () => { + if (!track) { + console.error('Track is undefined.') + return + } + try { + if (isTrackEnabled) { + await track.mute() + setIsTrackEnabled(false) + onChange?.(false, true) + } else { + await track.unmute() + setIsTrackEnabled(true) + onChange?.(true, true) + } + } catch (error) { + console.error('Failed to toggle track:', error) + } + }, [track, onChange, isTrackEnabled]) return (