Device from lobby to call (#1110)
* respect mute state set in lobby for call Signed-off-by: Timo K <toger5@hotmail.de> * move device from lobby to call Signed-off-by: Timo K <toger5@hotmail.de> * save device in local storage Signed-off-by: Timo K <toger5@hotmail.de> * local storage + fixes Signed-off-by: Timo K <toger5@hotmail.de> * device permissions Signed-off-by: Timo K <toger5@hotmail.de> --------- Signed-off-by: Timo K <toger5@hotmail.de>
This commit is contained in:
parent
89768de5e0
commit
41f2728724
3 changed files with 77 additions and 15 deletions
|
@ -1,5 +1,10 @@
|
||||||
import { LocalAudioTrack, LocalVideoTrack, Room } from "livekit-client";
|
import {
|
||||||
import React from "react";
|
ConnectionState,
|
||||||
|
LocalAudioTrack,
|
||||||
|
LocalVideoTrack,
|
||||||
|
Room,
|
||||||
|
} from "livekit-client";
|
||||||
|
import React, { useEffect } from "react";
|
||||||
import {
|
import {
|
||||||
useMediaDeviceSelect,
|
useMediaDeviceSelect,
|
||||||
usePreviewDevice,
|
usePreviewDevice,
|
||||||
|
@ -8,6 +13,7 @@ import {
|
||||||
import { MediaDevicesState, MediaDevices } from "../settings/mediaDevices";
|
import { MediaDevicesState, MediaDevices } from "../settings/mediaDevices";
|
||||||
import { LocalMediaInfo, MediaInfo } from "../room/VideoPreview";
|
import { LocalMediaInfo, MediaInfo } from "../room/VideoPreview";
|
||||||
import { roomOptions } from "./options";
|
import { roomOptions } from "./options";
|
||||||
|
import { useDefaultDevices } from "../settings/useSetting";
|
||||||
|
|
||||||
type LiveKitState = {
|
type LiveKitState = {
|
||||||
// The state of the media devices (changing the devices will also change them in the room).
|
// The state of the media devices (changing the devices will also change them in the room).
|
||||||
|
@ -19,6 +25,10 @@ type LiveKitState = {
|
||||||
room: Room;
|
room: Room;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function emptyToUndef(str) {
|
||||||
|
return str === "" ? undefined : str;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the React state for the LiveKit's Room class.
|
// Returns the React state for the LiveKit's Room class.
|
||||||
// The actual return type should be `LiveKitState`, but since this is a React hook, the initialisation is
|
// The actual return type should be `LiveKitState`, but since this is a React hook, the initialisation is
|
||||||
// delayed (done after the rendering, not during the rendering), because of that this function may return `undefined`.
|
// delayed (done after the rendering, not during the rendering), because of that this function may return `undefined`.
|
||||||
|
@ -32,21 +42,35 @@ export function useLiveKit(): LiveKitState | undefined {
|
||||||
// Create a React state to store the available devices and the selected device for each kind.
|
// Create a React state to store the available devices and the selected device for each kind.
|
||||||
const mediaDevices = useMediaDevicesState(room);
|
const mediaDevices = useMediaDevicesState(room);
|
||||||
|
|
||||||
// Create local video track.
|
const [settingsDefaultDevices] = useDefaultDevices();
|
||||||
|
|
||||||
const [videoEnabled, setVideoEnabled] = React.useState<boolean>(true);
|
const [videoEnabled, setVideoEnabled] = React.useState<boolean>(true);
|
||||||
const selectedVideoId = mediaDevices.state.get("videoinput")?.selectedId;
|
const selectedVideoId = mediaDevices.state.get("videoinput")?.selectedId;
|
||||||
|
|
||||||
|
const [audioEnabled, setAudioEnabled] = React.useState<boolean>(true);
|
||||||
|
const selectedAudioId = mediaDevices.state.get("audioinput")?.selectedId;
|
||||||
|
|
||||||
|
// trigger permission popup first,
|
||||||
|
useEffect(() => {
|
||||||
|
navigator.mediaDevices.getUserMedia({
|
||||||
|
video: { deviceId: selectedVideoId ?? settingsDefaultDevices.videoinput },
|
||||||
|
audio: { deviceId: selectedAudioId ?? settingsDefaultDevices.audioinput },
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// then start the preview device (no permsssion should be triggered agian)
|
||||||
|
// Create local video track.
|
||||||
const video = usePreviewDevice(
|
const video = usePreviewDevice(
|
||||||
videoEnabled,
|
videoEnabled,
|
||||||
selectedVideoId ?? "",
|
selectedVideoId ?? settingsDefaultDevices.videoinput,
|
||||||
"videoinput"
|
"videoinput"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create local audio track.
|
// Create local audio track.
|
||||||
const [audioEnabled, setAudioEnabled] = React.useState<boolean>(true);
|
|
||||||
const selectedAudioId = mediaDevices.state.get("audioinput")?.selectedId;
|
|
||||||
const audio = usePreviewDevice(
|
const audio = usePreviewDevice(
|
||||||
audioEnabled,
|
audioEnabled,
|
||||||
selectedAudioId ?? "",
|
selectedAudioId ?? settingsDefaultDevices.audioinput,
|
||||||
"audioinput"
|
"audioinput"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -71,7 +95,6 @@ export function useLiveKit(): LiveKitState | undefined {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const state: LiveKitState = {
|
const state: LiveKitState = {
|
||||||
mediaDevices: mediaDevices,
|
mediaDevices: mediaDevices,
|
||||||
localMedia: {
|
localMedia: {
|
||||||
|
@ -102,19 +125,24 @@ export function useLiveKit(): LiveKitState | undefined {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if a room is passed this only affects the device selection inside a call. Without room it changes what we see in the lobby
|
||||||
function useMediaDevicesState(room: Room): MediaDevicesState {
|
function useMediaDevicesState(room: Room): MediaDevicesState {
|
||||||
|
let connectedRoom: Room;
|
||||||
|
if (room.state !== ConnectionState.Disconnected) {
|
||||||
|
connectedRoom = room;
|
||||||
|
}
|
||||||
const {
|
const {
|
||||||
devices: videoDevices,
|
devices: videoDevices,
|
||||||
activeDeviceId: activeVideoDevice,
|
activeDeviceId: activeVideoDevice,
|
||||||
setActiveMediaDevice: setActiveVideoDevice,
|
setActiveMediaDevice: setActiveVideoDevice,
|
||||||
} = useMediaDeviceSelect({ kind: "videoinput", room });
|
} = useMediaDeviceSelect({ kind: "videoinput", room: connectedRoom });
|
||||||
const {
|
const {
|
||||||
devices: audioDevices,
|
devices: audioDevices,
|
||||||
activeDeviceId: activeAudioDevice,
|
activeDeviceId: activeAudioDevice,
|
||||||
setActiveMediaDevice: setActiveAudioDevice,
|
setActiveMediaDevice: setActiveAudioDevice,
|
||||||
} = useMediaDeviceSelect({
|
} = useMediaDeviceSelect({
|
||||||
kind: "audioinput",
|
kind: "audioinput",
|
||||||
room,
|
room: connectedRoom,
|
||||||
});
|
});
|
||||||
const {
|
const {
|
||||||
devices: audioOutputDevices,
|
devices: audioOutputDevices,
|
||||||
|
@ -122,7 +150,7 @@ function useMediaDevicesState(room: Room): MediaDevicesState {
|
||||||
setActiveMediaDevice: setActiveAudioOutputDevice,
|
setActiveMediaDevice: setActiveAudioOutputDevice,
|
||||||
} = useMediaDeviceSelect({
|
} = useMediaDeviceSelect({
|
||||||
kind: "audiooutput",
|
kind: "audiooutput",
|
||||||
room,
|
room: connectedRoom,
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectActiveDevice = React.useCallback(
|
const selectActiveDevice = React.useCallback(
|
||||||
|
@ -139,7 +167,7 @@ function useMediaDevicesState(room: Room): MediaDevicesState {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[setActiveAudioDevice, setActiveVideoDevice, setActiveAudioOutputDevice]
|
[setActiveVideoDevice, setActiveAudioOutputDevice, setActiveAudioDevice]
|
||||||
);
|
);
|
||||||
|
|
||||||
const [mediaDevicesState, setMediaDevicesState] =
|
const [mediaDevicesState, setMediaDevicesState] =
|
||||||
|
@ -151,19 +179,35 @@ function useMediaDevicesState(room: Room): MediaDevicesState {
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [settingsDefaultDevices, setDefaultDevices] = useDefaultDevices();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const state = new Map<MediaDeviceKind, MediaDevices>();
|
const state = new Map<MediaDeviceKind, MediaDevices>();
|
||||||
state.set("videoinput", {
|
state.set("videoinput", {
|
||||||
available: videoDevices,
|
available: videoDevices,
|
||||||
selectedId: activeVideoDevice,
|
selectedId:
|
||||||
|
emptyToUndef(activeVideoDevice) ??
|
||||||
|
emptyToUndef(settingsDefaultDevices.videoinput) ??
|
||||||
|
videoDevices[0]?.deviceId,
|
||||||
});
|
});
|
||||||
state.set("audioinput", {
|
state.set("audioinput", {
|
||||||
available: audioDevices,
|
available: audioDevices,
|
||||||
selectedId: activeAudioDevice,
|
selectedId:
|
||||||
|
emptyToUndef(activeAudioDevice) ??
|
||||||
|
emptyToUndef(settingsDefaultDevices.audioinput) ??
|
||||||
|
audioDevices[0]?.deviceId,
|
||||||
});
|
});
|
||||||
state.set("audiooutput", {
|
state.set("audiooutput", {
|
||||||
available: audioOutputDevices,
|
available: audioOutputDevices,
|
||||||
selectedId: activeAudioOutputDevice,
|
selectedId:
|
||||||
|
emptyToUndef(activeAudioOutputDevice) ??
|
||||||
|
emptyToUndef(settingsDefaultDevices.audiooutput) ??
|
||||||
|
audioOutputDevices[0]?.deviceId,
|
||||||
|
});
|
||||||
|
setDefaultDevices({
|
||||||
|
audioinput: state.get("audioinput").selectedId,
|
||||||
|
videoinput: state.get("videoinput").selectedId,
|
||||||
|
audiooutput: state.get("audiooutput").selectedId,
|
||||||
});
|
});
|
||||||
setMediaDevicesState({
|
setMediaDevicesState({
|
||||||
state,
|
state,
|
||||||
|
@ -177,6 +221,10 @@ function useMediaDevicesState(room: Room): MediaDevicesState {
|
||||||
audioOutputDevices,
|
audioOutputDevices,
|
||||||
activeAudioOutputDevice,
|
activeAudioOutputDevice,
|
||||||
selectActiveDevice,
|
selectActiveDevice,
|
||||||
|
setDefaultDevices,
|
||||||
|
settingsDefaultDevices.audioinput,
|
||||||
|
settingsDefaultDevices.videoinput,
|
||||||
|
settingsDefaultDevices.audiooutput,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return mediaDevicesState;
|
return mediaDevicesState;
|
||||||
|
|
|
@ -165,6 +165,13 @@ export function InCallView({
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO: move the room creation into the useRoom hook and out of the useLiveKit hook.
|
||||||
|
// This would than allow to not have those 4 lines
|
||||||
|
livekitRoom.options.audioCaptureDefaults.deviceId =
|
||||||
|
mediaDevices.state.get("audioinput").selectedId;
|
||||||
|
livekitRoom.options.videoCaptureDefaults.deviceId =
|
||||||
|
mediaDevices.state.get("videoinput").selectedId;
|
||||||
|
// Uses a hook to connect to the LiveKit room (on unmount the room will be left) and publish local media tracks (default).
|
||||||
useRoom({
|
useRoom({
|
||||||
token,
|
token,
|
||||||
serverUrl: Config.get().livekit.server_url,
|
serverUrl: Config.get().livekit.server_url,
|
||||||
|
|
|
@ -100,3 +100,10 @@ export const useOptInAnalytics = (): DisableableSetting<boolean | null> => {
|
||||||
|
|
||||||
export const useDeveloperSettingsTab = () =>
|
export const useDeveloperSettingsTab = () =>
|
||||||
useSetting("developer-settings-tab", false);
|
useSetting("developer-settings-tab", false);
|
||||||
|
|
||||||
|
export const useDefaultDevices = () =>
|
||||||
|
useSetting("defaultDevices", {
|
||||||
|
audioinput: "",
|
||||||
|
videoinput: "",
|
||||||
|
audiooutput: "",
|
||||||
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue