diff --git a/src/settings/useMediaHandler.jsx b/src/settings/useMediaHandler.jsx index 1b54073..67a9aea 100644 --- a/src/settings/useMediaHandler.jsx +++ b/src/settings/useMediaHandler.jsx @@ -9,6 +9,32 @@ import React, { const MediaHandlerContext = createContext(); +function getMediaPreferences() { + const mediaPreferences = localStorage.getItem("matrix-media-preferences"); + + if (mediaPreferences) { + try { + return JSON.parse(mediaPreferences); + } catch (e) { + return undefined; + } + } else { + return undefined; + } +} + +function updateMediaPreferences(newPreferences) { + const oldPreferences = getMediaPreferences(newPreferences); + + localStorage.setItem( + "matrix-media-preferences", + JSON.stringify({ + ...oldPreferences, + ...newPreferences, + }) + ); +} + export function MediaHandlerProvider({ client, children }) { const [ { @@ -21,8 +47,14 @@ export function MediaHandlerProvider({ client, children }) { }, setState, ] = useState(() => { + const mediaPreferences = getMediaPreferences(); const mediaHandler = client.getMediaHandler(); + mediaHandler.restoreMediaSettings( + mediaPreferences?.audioInput, + mediaPreferences?.videoInput + ); + return { audioInput: mediaHandler.audioInput, videoInput: mediaHandler.videoInput, @@ -38,42 +70,67 @@ export function MediaHandlerProvider({ client, children }) { function updateDevices() { navigator.mediaDevices.enumerateDevices().then((devices) => { + const mediaPreferences = getMediaPreferences(); + const audioInputs = devices.filter( (device) => device.kind === "audioinput" ); + const audioConnected = audioInputs.some( + (device) => device.deviceId === mediaHandler.audioInput + ); + + let audioInput = mediaHandler.audioInput; + + if (!audioConnected && audioInputs.length > 0) { + audioInput = audioInputs[0].deviceId; + } + const videoInputs = devices.filter( (device) => device.kind === "videoinput" ); + const videoConnected = videoInputs.some( + (device) => device.deviceId === mediaHandler.videoInput + ); + + let videoInput = mediaHandler.videoInput; + + if (!videoConnected && videoInputs.length > 0) { + videoInput = videoInputs[0].deviceId; + } + const audioOutputs = devices.filter( (device) => device.kind === "audiooutput" ); - let audioOutput = undefined; - const audioOutputPreference = localStorage.getItem( - "matrix-audio-output" - ); - if ( - audioOutputPreference && + mediaPreferences && audioOutputs.some( - (device) => device.deviceId === audioOutputPreference + (device) => device.deviceId === mediaPreferences.audioOutput ) ) { - audioOutput = audioOutputPreference; + audioOutput = mediaPreferences.audioOutput; } + if ( + mediaHandler.videoInput !== videoInput || + mediaHandler.audioInput !== audioInput + ) { + mediaHandler.setMediaInputs(audioInput, videoInput); + } + + updateMediaPreferences({ audioInput, videoInput, audioOutput }); + setState({ - audioInput: mediaHandler.audioInput, - videoInput: mediaHandler.videoInput, + audioInput, + videoInput, audioOutput, audioInputs, - audioOutputs, videoInputs, + audioOutputs, }); }); } - updateDevices(); mediaHandler.on("local_streams_changed", updateDevices); @@ -82,11 +139,13 @@ export function MediaHandlerProvider({ client, children }) { return () => { mediaHandler.removeListener("local_streams_changed", updateDevices); navigator.mediaDevices.removeEventListener("devicechange", updateDevices); + mediaHandler.stopAllStreams(); }; }, [client]); const setAudioInput = useCallback( (deviceId) => { + updateMediaPreferences({ audioInput: deviceId }); setState((prevState) => ({ ...prevState, audioInput: deviceId })); client.getMediaHandler().setAudioInput(deviceId); }, @@ -95,6 +154,7 @@ export function MediaHandlerProvider({ client, children }) { const setVideoInput = useCallback( (deviceId) => { + updateMediaPreferences({ videoInput: deviceId }); setState((prevState) => ({ ...prevState, videoInput: deviceId })); client.getMediaHandler().setVideoInput(deviceId); }, @@ -102,7 +162,7 @@ export function MediaHandlerProvider({ client, children }) { ); const setAudioOutput = useCallback((deviceId) => { - localStorage.setItem("matrix-audio-output", deviceId); + updateMediaPreferences({ audioOutput: deviceId }); setState((prevState) => ({ ...prevState, audioOutput: deviceId })); }, []);