@@ -33,7 +33,7 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
3333import AppTile from "../elements/AppTile" ;
3434import { _t } from "../../../languageHandler" ;
3535import { useAsyncMemo } from "../../../hooks/useAsyncMemo" ;
36- import MediaDeviceHandler , { MediaDeviceKindEnum } from "../../../MediaDeviceHandler" ;
36+ import MediaDeviceHandler from "../../../MediaDeviceHandler" ;
3737import { CallStore } from "../../../stores/CallStore" ;
3838import IconizedContextMenu , {
3939 IconizedContextMenuOption ,
@@ -141,36 +141,38 @@ export const Lobby: FC<LobbyProps> = ({ room, joinCallButtonDisabled, joinCallBu
141141 } , [ videoMuted , setVideoMuted ] ) ;
142142
143143 const [ videoStream , audioInputs , videoInputs ] = useAsyncMemo ( async ( ) => {
144- let previewStream : MediaStream ;
144+ let devices = await MediaDeviceHandler . getDevices ( ) ;
145+
146+ // We get the preview stream before requesting devices: this is because
147+ // we need (in some browsers) an active media stream in order to get
148+ // non-blank labels for the devices.
149+ let stream : MediaStream | null = null ;
145150 try {
146- // We get the preview stream before requesting devices: this is because
147- // we need (in some browsers) an active media stream in order to get
148- // non-blank labels for the devices. According to the docs, we
149- // need a stream of each type (audio + video) if we want to enumerate
150- // audio & video devices, although this didn't seem to be the case
151- // in practice for me. We request both anyway.
152- // For similar reasons, we also request a stream even if video is muted,
153- // which could be a bit strange but allows us to get the device list
154- // reliably. One option could be to try & get devices without a stream,
155- // then try again with a stream if we get blank deviceids, but... ew.
156- previewStream = await navigator . mediaDevices . getUserMedia ( {
157- video : { deviceId : videoInputId } ,
158- audio : { deviceId : MediaDeviceHandler . getAudioInput ( ) } ,
159- } ) ;
151+ if ( devices . audioinput . length > 0 ) {
152+ // Holding just an audio stream will be enough to get us all device labels, so
153+ // if video is muted, don't bother requesting video.
154+ stream = await navigator . mediaDevices . getUserMedia ( {
155+ audio : true ,
156+ video : ! videoMuted && devices . videoinput . length > 0 && { deviceId : videoInputId } ,
157+ } ) ;
158+ } else if ( devices . videoinput . length > 0 ) {
159+ // We have to resort to a video stream, even if video is supposed to be muted.
160+ stream = await navigator . mediaDevices . getUserMedia ( { video : { deviceId : videoInputId } } ) ;
161+ }
160162 } catch ( e ) {
161163 logger . error ( `Failed to get stream for device ${ videoInputId } ` , e ) ;
162164 }
163165
164- const devices = await MediaDeviceHandler . getDevices ( ) ;
166+ // Refresh the devices now that we hold a stream
167+ if ( stream !== null ) devices = await MediaDeviceHandler . getDevices ( ) ;
165168
166- // If video is muted, we don't actually want the stream, so we can get rid of
167- // it now.
169+ // If video is muted, we don't actually want the stream, so we can get rid of it now.
168170 if ( videoMuted ) {
169- previewStream . getTracks ( ) . forEach ( t => t . stop ( ) ) ;
170- previewStream = undefined ;
171+ stream ? .getTracks ( ) . forEach ( t => t . stop ( ) ) ;
172+ stream = null ;
171173 }
172174
173- return [ previewStream , devices [ MediaDeviceKindEnum . AudioInput ] , devices [ MediaDeviceKindEnum . VideoInput ] ] ;
175+ return [ stream , devices . audioinput , devices . videoinput ] ;
174176 } , [ videoInputId , videoMuted ] , [ null , [ ] , [ ] ] ) ;
175177
176178 const setAudioInput = useCallback ( ( device : MediaDeviceInfo ) => {
@@ -188,7 +190,7 @@ export const Lobby: FC<LobbyProps> = ({ room, joinCallButtonDisabled, joinCallBu
188190 videoElement . play ( ) ;
189191
190192 return ( ) => {
191- videoStream ? .getTracks ( ) . forEach ( track => track . stop ( ) ) ;
193+ videoStream . getTracks ( ) . forEach ( track => track . stop ( ) ) ;
192194 videoElement . srcObject = null ;
193195 } ;
194196 }
@@ -358,7 +360,7 @@ const JoinCallView: FC<JoinCallViewProps> = ({ room, resizing, call }) => {
358360 lobby = < Lobby
359361 room = { room }
360362 connect = { connect }
361- joinCallButtonTooltip = { joinCallButtonTooltip }
363+ joinCallButtonTooltip = { joinCallButtonTooltip ?? undefined }
362364 joinCallButtonDisabled = { joinCallButtonDisabled }
363365 >
364366 { facePile }
0 commit comments