Browse Source

fix(device-selection): Add a workaround for a chrome bug with default mic

Pass the real deviceId to gUM instead of 'default' for Chrome to return the correct media stream
j8
Jaya Allamsetty 4 years ago
parent
commit
f4bcad02d8
2 changed files with 62 additions and 14 deletions
  1. 33
    2
      conference.js
  2. 29
    12
      react/features/base/devices/functions.js

+ 33
- 2
conference.js View File

48
 import {
48
 import {
49
     checkAndNotifyForNewDevice,
49
     checkAndNotifyForNewDevice,
50
     getAvailableDevices,
50
     getAvailableDevices,
51
+    getDefaultDeviceId,
51
     notifyCameraError,
52
     notifyCameraError,
52
     notifyMicError,
53
     notifyMicError,
53
     setAudioOutputDeviceId,
54
     setAudioOutputDeviceId,
2434
             micDeviceId => {
2435
             micDeviceId => {
2435
                 const audioWasMuted = this.isLocalAudioMuted();
2436
                 const audioWasMuted = this.isLocalAudioMuted();
2436
 
2437
 
2438
+                // When the 'default' mic needs to be selected, we need to
2439
+                // pass the real device id to gUM instead of 'default' in order
2440
+                // to get the correct MediaStreamTrack from chrome because of the
2441
+                // following bug.
2442
+                // https://bugs.chromium.org/p/chromium/issues/detail?id=997689
2443
+                const hasDefaultMicChanged = micDeviceId === 'default';
2444
+
2437
                 sendAnalytics(createDeviceChangedEvent('audio', 'input'));
2445
                 sendAnalytics(createDeviceChangedEvent('audio', 'input'));
2438
                 createLocalTracksF({
2446
                 createLocalTracksF({
2439
                     devices: [ 'audio' ],
2447
                     devices: [ 'audio' ],
2440
                     cameraDeviceId: null,
2448
                     cameraDeviceId: null,
2441
-                    micDeviceId
2449
+                    micDeviceId: hasDefaultMicChanged
2450
+                        ? getDefaultDeviceId(APP.store.getState(), 'audioInput')
2451
+                        : micDeviceId
2442
                 })
2452
                 })
2443
                 .then(([ stream ]) => {
2453
                 .then(([ stream ]) => {
2444
                     // if audio was muted before changing the device, mute
2454
                     // if audio was muted before changing the device, mute
2462
                     return this.useAudioStream(stream);
2472
                     return this.useAudioStream(stream);
2463
                 })
2473
                 })
2464
                 .then(() => {
2474
                 .then(() => {
2475
+                    if (hasDefaultMicChanged) {
2476
+                        // workaround for the default device to be shown as selected in the
2477
+                        // settings even when the real device id was passed to gUM because of the
2478
+                        // above mentioned chrome bug.
2479
+                        this.localAudio._realDeviceId = this.localAudio.deviceId = 'default';
2480
+                    }
2465
                     logger.log(`switched local audio device: ${this.localAudio?.getDeviceId()}`);
2481
                     logger.log(`switched local audio device: ${this.localAudio?.getDeviceId()}`);
2466
 
2482
 
2467
                     this._updateAudioDeviceId();
2483
                     this._updateAudioDeviceId();
2763
                 checkAndNotifyForNewDevice(newAvailDevices.videoInput, oldDevices.videoInput));
2779
                 checkAndNotifyForNewDevice(newAvailDevices.videoInput, oldDevices.videoInput));
2764
         }
2780
         }
2765
 
2781
 
2782
+        // When the 'default' mic needs to be selected, we need to
2783
+        // pass the real device id to gUM instead of 'default' in order
2784
+        // to get the correct MediaStreamTrack from chrome because of the
2785
+        // following bug.
2786
+        // https://bugs.chromium.org/p/chromium/issues/detail?id=997689
2787
+        const hasDefaultMicChanged = newDevices.audioinput === 'default';
2788
+
2766
         promises.push(
2789
         promises.push(
2767
             mediaDeviceHelper.createLocalTracksAfterDeviceListChanged(
2790
             mediaDeviceHelper.createLocalTracksAfterDeviceListChanged(
2768
                     createLocalTracksF,
2791
                     createLocalTracksF,
2769
                     newDevices.videoinput,
2792
                     newDevices.videoinput,
2770
-                    newDevices.audioinput)
2793
+                    hasDefaultMicChanged
2794
+                        ? getDefaultDeviceId(APP.store.getState(), 'audioInput')
2795
+                        : newDevices.audioinput)
2771
                 .then(tracks => {
2796
                 .then(tracks => {
2772
                     // If audio or video muted before, or we unplugged current
2797
                     // If audio or video muted before, or we unplugged current
2773
                     // device and selected new one, then mute new track.
2798
                     // device and selected new one, then mute new track.
2792
                                     // Use the new stream or null if we failed to obtain it.
2817
                                     // Use the new stream or null if we failed to obtain it.
2793
                                     return useStream(tracks.find(track => track.getType() === mediaType) || null)
2818
                                     return useStream(tracks.find(track => track.getType() === mediaType) || null)
2794
                                         .then(() => {
2819
                                         .then(() => {
2820
+                                            if (hasDefaultMicChanged) {
2821
+                                                // workaround for the default device to be shown as selected in the
2822
+                                                // settings even when the real device id was passed to gUM because of
2823
+                                                // the above mentioned chrome bug.
2824
+                                                this.localAudio._realDeviceId = this.localAudio.deviceId = 'default';
2825
+                                            }
2795
                                             mediaType === 'audio'
2826
                                             mediaType === 'audio'
2796
                                                 ? this._updateAudioDeviceId()
2827
                                                 ? this._updateAudioDeviceId()
2797
                                                 : this._updateVideoDeviceId();
2828
                                                 : this._updateVideoDeviceId();

+ 29
- 12
react/features/base/devices/functions.js View File

8
 
8
 
9
 declare var APP: Object;
9
 declare var APP: Object;
10
 
10
 
11
+const webrtcKindToJitsiKindTranslator = {
12
+    audioinput: 'audioInput',
13
+    audiooutput: 'audioOutput',
14
+    videoinput: 'videoInput'
15
+};
16
+
11
 /**
17
 /**
12
  * Detects the use case when the labels are not available if the A/V permissions
18
  * Detects the use case when the labels are not available if the A/V permissions
13
  * are not yet granted.
19
  * are not yet granted.
41
     return JitsiMeetJS.mediaDevices.getAudioOutputDevice();
47
     return JitsiMeetJS.mediaDevices.getAudioOutputDevice();
42
 }
48
 }
43
 
49
 
50
+/**
51
+ * Finds the real device id of the default device of the given type.
52
+ *
53
+ * @param {Object} state - The redux state.
54
+ * @param {*} kind - The type of the device. One of "audioInput",
55
+ * "audioOutput", and "videoInput". Also supported is all lowercase versions
56
+ * of the preceding types.
57
+ * @returns {string|undefined}
58
+ */
59
+export function getDefaultDeviceId(state: Object, kind: string) {
60
+    const kindToSearch = webrtcKindToJitsiKindTranslator[kind] || kind;
61
+    const defaultDevice = (state['features/base/devices'].availableDevices[kindToSearch] || [])
62
+        .find(d => d.deviceId === 'default');
63
+
64
+    // Find the device with a matching group id.
65
+    const matchingDevice = (state['features/base/devices'].availableDevices[kindToSearch] || [])
66
+        .find(d => d.deviceId !== 'default' && d.groupId === defaultDevice.groupId);
67
+
68
+    if (matchingDevice) {
69
+        return matchingDevice.deviceId;
70
+    }
71
+}
72
+
44
 /**
73
 /**
45
  * Finds a device with a label that matches the passed label and returns its id.
74
  * Finds a device with a label that matches the passed label and returns its id.
46
  *
75
  *
52
  * @returns {string|undefined}
81
  * @returns {string|undefined}
53
  */
82
  */
54
 export function getDeviceIdByLabel(state: Object, label: string, kind: string) {
83
 export function getDeviceIdByLabel(state: Object, label: string, kind: string) {
55
-    const webrtcKindToJitsiKindTranslator = {
56
-        audioinput: 'audioInput',
57
-        audiooutput: 'audioOutput',
58
-        videoinput: 'videoInput'
59
-    };
60
-
61
     const kindToSearch = webrtcKindToJitsiKindTranslator[kind] || kind;
84
     const kindToSearch = webrtcKindToJitsiKindTranslator[kind] || kind;
62
 
85
 
63
     const device
86
     const device
80
  * @returns {string|undefined}
103
  * @returns {string|undefined}
81
  */
104
  */
82
 export function getDeviceLabelById(state: Object, id: string, kind: string) {
105
 export function getDeviceLabelById(state: Object, id: string, kind: string) {
83
-    const webrtcKindToJitsiKindTranslator = {
84
-        audioinput: 'audioInput',
85
-        audiooutput: 'audioOutput',
86
-        videoinput: 'videoInput'
87
-    };
88
-
89
     const kindToSearch = webrtcKindToJitsiKindTranslator[kind] || kind;
106
     const kindToSearch = webrtcKindToJitsiKindTranslator[kind] || kind;
90
 
107
 
91
     const device
108
     const device

Loading…
Cancel
Save