@@ -43,7 +43,6 @@ interface DeviceSelectionState {
43
43
videoInputs : MediaDeviceInfo [ ] ;
44
44
audioInputs : MediaDeviceInfo [ ] ;
45
45
audioOutputs : MediaDeviceInfo [ ] ;
46
- // TODO: Add selectedAudioOutputDeviceId
47
46
selectedVideoInputDeviceId : MediaDeviceInfo [ "deviceId" ] | undefined ;
48
47
selectedAudioInputDeviceId : MediaDeviceInfo [ "deviceId" ] | undefined ;
49
48
}
@@ -70,6 +69,7 @@ type DeviceSelectionAction =
70
69
| DeviceSelectionSetUnavailableAction
71
70
| DeviceSelectionUpdateDevicesAction
72
71
| DeviceSelectionUpdateSelectedDeviceIdAction ;
72
+
73
73
const deviceSelectionReducer : Reducer <
74
74
DeviceSelectionState ,
75
75
DeviceSelectionAction
@@ -130,6 +130,7 @@ export interface DeviceSelectProps {
130
130
audio : MediaDeviceInfo [ "deviceId" ] | undefined ;
131
131
} ) => void ;
132
132
}
133
+
133
134
function DeviceSelect ( props : DeviceSelectProps ) {
134
135
const {
135
136
video : useVideo ,
@@ -139,6 +140,7 @@ function DeviceSelect(props: DeviceSelectProps) {
139
140
onSelect,
140
141
} = props ;
141
142
143
+ // ✅ Initialize to "WAITING" directly, no need to set inside effect
142
144
const [ permissionState , setPermissionState ] =
143
145
useState < PermissionState > ( "WAITING" ) ;
144
146
@@ -175,44 +177,36 @@ function DeviceSelect(props: DeviceSelectProps) {
175
177
} ) ;
176
178
} , [ ] ) ;
177
179
178
- // These values are passed to inside the useEffect below via a ref
179
- // because they are used there only for UX improvement
180
- // and should not be added to the dependency list to avoid triggering re-execution.
181
- const defaultDeviceIdsRef = useRef ( {
182
- video : defaultVideoDeviceId ,
183
- audio : defaultAudioDeviceId ,
184
- } ) ;
185
- defaultDeviceIdsRef . current = {
186
- video : defaultVideoDeviceId ,
187
- audio : defaultAudioDeviceId ,
188
- } ;
189
- // Call `getUserMedia()` to ask the user for the permission.
180
+ // Store default device IDs in a ref
181
+ const defaultDeviceIdsRef = useRef < { video ?: string ; audio ?: string } > ( { } ) ;
182
+
183
+ useEffect ( ( ) => {
184
+ defaultDeviceIdsRef . current = {
185
+ video : defaultVideoDeviceId ,
186
+ audio : defaultAudioDeviceId ,
187
+ } ;
188
+ } , [ defaultVideoDeviceId , defaultAudioDeviceId ] ) ;
189
+
190
+ // Call `getUserMedia()` to ask the user for permission.
190
191
useEffect ( ( ) => {
191
192
if ( typeof navigator ?. mediaDevices ?. getUserMedia !== "function" ) {
192
193
deviceSelectionDispatch ( { type : "SET_UNAVAILABLE" } ) ;
193
194
return ;
194
195
}
195
196
196
- setPermissionState ( "WAITING" ) ;
197
-
198
197
const { video : videoDeviceId , audio : audioDeviceId } =
199
198
defaultDeviceIdsRef . current ;
199
+
200
200
navigator . mediaDevices
201
201
. getUserMedia ( {
202
- // Specify the target devices if the user already selected specific ones.
203
- // This is not mandatory but beneficial for better UX
204
- // as unused devices are not accessed so that their LED indicators
205
- // will not be unnecessarily turned on.
206
202
video :
207
203
useVideo && videoDeviceId ? { deviceId : videoDeviceId } : useVideo ,
208
204
audio :
209
205
useAudio && audioDeviceId ? { deviceId : audioDeviceId } : useAudio ,
210
206
} )
211
207
. then ( async ( stream ) => {
212
208
stopAllTracks ( stream ) ;
213
-
214
209
await updateDeviceList ( ) ;
215
-
216
210
setPermissionState ( "ALLOWED" ) ;
217
211
} )
218
212
. catch ( ( err ) => {
@@ -254,7 +248,7 @@ function DeviceSelect(props: DeviceSelectProps) {
254
248
} ) ;
255
249
} , [ ] ) ;
256
250
257
- // Call onSelect
251
+ // Call onSelect whenever inputs change
258
252
useEffect ( ( ) => {
259
253
const videoInput = useVideo
260
254
? videoInputs . find ( ( d ) => d . deviceId === selectedVideoInputDeviceId )
0 commit comments