From c01d037162634c0b3cc6bc36e555e2c0a4daf5ec Mon Sep 17 00:00:00 2001 From: Timo K Date: Tue, 10 Oct 2023 13:56:21 +0200 Subject: [PATCH] add ref for current button state Signed-off-by: Timo K --- src/livekit/useLiveKit.ts | 55 +++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/src/livekit/useLiveKit.ts b/src/livekit/useLiveKit.ts index 40b3660b..5396d4b3 100644 --- a/src/livekit/useLiveKit.ts +++ b/src/livekit/useLiveKit.ts @@ -103,8 +103,14 @@ export function useLiveKit( // Store if audio/video are currently updating. If to prohibit unnecessary calls // to setMicrophoneEnabled/setCameraEnabled - const [audioMuteUpdating, setAudioMuteUpdating] = useState(false); - const [videoMuteUpdating, setVideoMuteUpdating] = useState(false); + const audioMuteUpdating = useRef(false); + const videoMuteUpdating = useRef(false); + // Store the current button mute state that gets passed to this hook via props. + // We need to store it for awaited code that relies on the current value. + const buttonEnabled = useRef({ + audio: initialMuteStates.current.audio.enabled, + video: initialMuteStates.current.video.enabled, + }); // We have to create the room manually here due to a bug inside // @livekit/components-react. JSON.stringify() is used in deps of a @@ -142,47 +148,52 @@ export function useLiveKit( // and setting tracks to be enabled during this time causes errors. if (room !== undefined && connectionState === ConnectionState.Connected) { const participant = room.localParticipant; - + // Always update the muteButtonState Ref so that we can read the current + // state in awaited blocks. + buttonEnabled.current = { + audio: muteStates.audio.enabled, + video: muteStates.video.enabled, + }; const syncMuteStateAudio = async () => { if ( - participant.isMicrophoneEnabled !== muteStates.audio.enabled && - !audioMuteUpdating + participant.isMicrophoneEnabled !== buttonEnabled.current.audio && + !audioMuteUpdating.current ) { - setAudioMuteUpdating(true); - await participant - .setMicrophoneEnabled(muteStates.audio.enabled) - .catch((e) => - logger.error("Failed to sync audio mute state with LiveKit", e) - ); + audioMuteUpdating.current = true; + try { + await participant.setMicrophoneEnabled(buttonEnabled.current.audio); + } catch (e) { + logger.error("Failed to sync audio mute state with LiveKit", e); + } + audioMuteUpdating.current = false; // Run the check again after the change is done. Because the user // can update the state (presses mute button) while the device is enabling // itself we need might need to update the mute state right away. // This async recursion makes sure that setCamera/MicrophoneEnabled is // called as little times as possible. - setAudioMuteUpdating(false); syncMuteStateAudio(); } }; const syncMuteStateVideo = async () => { if ( - participant.isCameraEnabled !== muteStates.video.enabled && - !videoMuteUpdating + participant.isCameraEnabled !== buttonEnabled.current.video && + !videoMuteUpdating.current ) { - setVideoMuteUpdating(true); - await participant - .setCameraEnabled(muteStates.video.enabled) - .catch((e) => - logger.error("Failed to sync video mute state with LiveKit", e) - ); + videoMuteUpdating.current = true; + try { + await participant.setCameraEnabled(buttonEnabled.current.video); + } catch (e) { + logger.error("Failed to sync audio mute state with LiveKit", e); + } + videoMuteUpdating.current = false; // see above - setVideoMuteUpdating(false); syncMuteStateVideo(); } }; syncMuteStateAudio(); syncMuteStateVideo(); } - }, [room, muteStates, connectionState, audioMuteUpdating, videoMuteUpdating]); + }, [room, muteStates, connectionState]); useEffect(() => { // Sync the requested devices with LiveKit's devices