Fix joining calls without audio or video inputs (#9486)
The lobby view was requesting a stream with both video and audio, even if the system lacked video or audio devices. Requesting one of audio or video is enough to get all device labels.pull/28788/head^2
parent
eafc2d23a7
commit
daf097e123
|
@ -33,7 +33,7 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
|||
import AppTile from "../elements/AppTile";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { useAsyncMemo } from "../../../hooks/useAsyncMemo";
|
||||
import MediaDeviceHandler, { MediaDeviceKindEnum } from "../../../MediaDeviceHandler";
|
||||
import MediaDeviceHandler from "../../../MediaDeviceHandler";
|
||||
import { CallStore } from "../../../stores/CallStore";
|
||||
import IconizedContextMenu, {
|
||||
IconizedContextMenuOption,
|
||||
|
@ -141,36 +141,38 @@ export const Lobby: FC<LobbyProps> = ({ room, joinCallButtonDisabled, joinCallBu
|
|||
}, [videoMuted, setVideoMuted]);
|
||||
|
||||
const [videoStream, audioInputs, videoInputs] = useAsyncMemo(async () => {
|
||||
let previewStream: MediaStream;
|
||||
let devices = await MediaDeviceHandler.getDevices();
|
||||
|
||||
// We get the preview stream before requesting devices: this is because
|
||||
// we need (in some browsers) an active media stream in order to get
|
||||
// non-blank labels for the devices.
|
||||
let stream: MediaStream | null = null;
|
||||
try {
|
||||
// We get the preview stream before requesting devices: this is because
|
||||
// we need (in some browsers) an active media stream in order to get
|
||||
// non-blank labels for the devices. According to the docs, we
|
||||
// need a stream of each type (audio + video) if we want to enumerate
|
||||
// audio & video devices, although this didn't seem to be the case
|
||||
// in practice for me. We request both anyway.
|
||||
// For similar reasons, we also request a stream even if video is muted,
|
||||
// which could be a bit strange but allows us to get the device list
|
||||
// reliably. One option could be to try & get devices without a stream,
|
||||
// then try again with a stream if we get blank deviceids, but... ew.
|
||||
previewStream = await navigator.mediaDevices.getUserMedia({
|
||||
video: { deviceId: videoInputId },
|
||||
audio: { deviceId: MediaDeviceHandler.getAudioInput() },
|
||||
});
|
||||
if (devices.audioinput.length > 0) {
|
||||
// Holding just an audio stream will be enough to get us all device labels, so
|
||||
// if video is muted, don't bother requesting video.
|
||||
stream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: true,
|
||||
video: !videoMuted && devices.videoinput.length > 0 && { deviceId: videoInputId },
|
||||
});
|
||||
} else if (devices.videoinput.length > 0) {
|
||||
// We have to resort to a video stream, even if video is supposed to be muted.
|
||||
stream = await navigator.mediaDevices.getUserMedia({ video: { deviceId: videoInputId } });
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error(`Failed to get stream for device ${videoInputId}`, e);
|
||||
}
|
||||
|
||||
const devices = await MediaDeviceHandler.getDevices();
|
||||
// Refresh the devices now that we hold a stream
|
||||
if (stream !== null) devices = await MediaDeviceHandler.getDevices();
|
||||
|
||||
// If video is muted, we don't actually want the stream, so we can get rid of
|
||||
// it now.
|
||||
// If video is muted, we don't actually want the stream, so we can get rid of it now.
|
||||
if (videoMuted) {
|
||||
previewStream.getTracks().forEach(t => t.stop());
|
||||
previewStream = undefined;
|
||||
stream?.getTracks().forEach(t => t.stop());
|
||||
stream = null;
|
||||
}
|
||||
|
||||
return [previewStream, devices[MediaDeviceKindEnum.AudioInput], devices[MediaDeviceKindEnum.VideoInput]];
|
||||
return [stream, devices.audioinput, devices.videoinput];
|
||||
}, [videoInputId, videoMuted], [null, [], []]);
|
||||
|
||||
const setAudioInput = useCallback((device: MediaDeviceInfo) => {
|
||||
|
@ -188,7 +190,7 @@ export const Lobby: FC<LobbyProps> = ({ room, joinCallButtonDisabled, joinCallBu
|
|||
videoElement.play();
|
||||
|
||||
return () => {
|
||||
videoStream?.getTracks().forEach(track => track.stop());
|
||||
videoStream.getTracks().forEach(track => track.stop());
|
||||
videoElement.srcObject = null;
|
||||
};
|
||||
}
|
||||
|
@ -358,7 +360,7 @@ const JoinCallView: FC<JoinCallViewProps> = ({ room, resizing, call }) => {
|
|||
lobby = <Lobby
|
||||
room={room}
|
||||
connect={connect}
|
||||
joinCallButtonTooltip={joinCallButtonTooltip}
|
||||
joinCallButtonTooltip={joinCallButtonTooltip ?? undefined}
|
||||
joinCallButtonDisabled={joinCallButtonDisabled}
|
||||
>
|
||||
{ facePile }
|
||||
|
|
Loading…
Reference in New Issue