@@ -33,7 +33,7 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
33
33
import AppTile from "../elements/AppTile" ;
34
34
import { _t } from "../../../languageHandler" ;
35
35
import { useAsyncMemo } from "../../../hooks/useAsyncMemo" ;
36
- import MediaDeviceHandler , { MediaDeviceKindEnum } from "../../../MediaDeviceHandler" ;
36
+ import MediaDeviceHandler from "../../../MediaDeviceHandler" ;
37
37
import { CallStore } from "../../../stores/CallStore" ;
38
38
import IconizedContextMenu , {
39
39
IconizedContextMenuOption ,
@@ -141,36 +141,38 @@ export const Lobby: FC<LobbyProps> = ({ room, joinCallButtonDisabled, joinCallBu
141
141
} , [ videoMuted , setVideoMuted ] ) ;
142
142
143
143
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 ;
145
150
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
+ }
160
162
} catch ( e ) {
161
163
logger . error ( `Failed to get stream for device ${ videoInputId } ` , e ) ;
162
164
}
163
165
164
- const devices = await MediaDeviceHandler . getDevices ( ) ;
166
+ // Refresh the devices now that we hold a stream
167
+ if ( stream !== null ) devices = await MediaDeviceHandler . getDevices ( ) ;
165
168
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.
168
170
if ( videoMuted ) {
169
- previewStream . getTracks ( ) . forEach ( t => t . stop ( ) ) ;
170
- previewStream = undefined ;
171
+ stream ? .getTracks ( ) . forEach ( t => t . stop ( ) ) ;
172
+ stream = null ;
171
173
}
172
174
173
- return [ previewStream , devices [ MediaDeviceKindEnum . AudioInput ] , devices [ MediaDeviceKindEnum . VideoInput ] ] ;
175
+ return [ stream , devices . audioinput , devices . videoinput ] ;
174
176
} , [ videoInputId , videoMuted ] , [ null , [ ] , [ ] ] ) ;
175
177
176
178
const setAudioInput = useCallback ( ( device : MediaDeviceInfo ) => {
@@ -188,7 +190,7 @@ export const Lobby: FC<LobbyProps> = ({ room, joinCallButtonDisabled, joinCallBu
188
190
videoElement . play ( ) ;
189
191
190
192
return ( ) => {
191
- videoStream ? .getTracks ( ) . forEach ( track => track . stop ( ) ) ;
193
+ videoStream . getTracks ( ) . forEach ( track => track . stop ( ) ) ;
192
194
videoElement . srcObject = null ;
193
195
} ;
194
196
}
@@ -358,7 +360,7 @@ const JoinCallView: FC<JoinCallViewProps> = ({ room, resizing, call }) => {
358
360
lobby = < Lobby
359
361
room = { room }
360
362
connect = { connect }
361
- joinCallButtonTooltip = { joinCallButtonTooltip }
363
+ joinCallButtonTooltip = { joinCallButtonTooltip ?? undefined }
362
364
joinCallButtonDisabled = { joinCallButtonDisabled }
363
365
>
364
366
{ facePile }
0 commit comments