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
This commit is contained in:
parent
26f7951894
commit
f4bcad02d8
|
@ -48,6 +48,7 @@ import {
|
||||||
import {
|
import {
|
||||||
checkAndNotifyForNewDevice,
|
checkAndNotifyForNewDevice,
|
||||||
getAvailableDevices,
|
getAvailableDevices,
|
||||||
|
getDefaultDeviceId,
|
||||||
notifyCameraError,
|
notifyCameraError,
|
||||||
notifyMicError,
|
notifyMicError,
|
||||||
setAudioOutputDeviceId,
|
setAudioOutputDeviceId,
|
||||||
|
@ -2434,11 +2435,20 @@ export default {
|
||||||
micDeviceId => {
|
micDeviceId => {
|
||||||
const audioWasMuted = this.isLocalAudioMuted();
|
const audioWasMuted = this.isLocalAudioMuted();
|
||||||
|
|
||||||
|
// When the 'default' mic needs to be selected, we need to
|
||||||
|
// pass the real device id to gUM instead of 'default' in order
|
||||||
|
// to get the correct MediaStreamTrack from chrome because of the
|
||||||
|
// following bug.
|
||||||
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=997689
|
||||||
|
const hasDefaultMicChanged = micDeviceId === 'default';
|
||||||
|
|
||||||
sendAnalytics(createDeviceChangedEvent('audio', 'input'));
|
sendAnalytics(createDeviceChangedEvent('audio', 'input'));
|
||||||
createLocalTracksF({
|
createLocalTracksF({
|
||||||
devices: [ 'audio' ],
|
devices: [ 'audio' ],
|
||||||
cameraDeviceId: null,
|
cameraDeviceId: null,
|
||||||
micDeviceId
|
micDeviceId: hasDefaultMicChanged
|
||||||
|
? getDefaultDeviceId(APP.store.getState(), 'audioInput')
|
||||||
|
: micDeviceId
|
||||||
})
|
})
|
||||||
.then(([ stream ]) => {
|
.then(([ stream ]) => {
|
||||||
// if audio was muted before changing the device, mute
|
// if audio was muted before changing the device, mute
|
||||||
|
@ -2462,6 +2472,12 @@ export default {
|
||||||
return this.useAudioStream(stream);
|
return this.useAudioStream(stream);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
if (hasDefaultMicChanged) {
|
||||||
|
// workaround for the default device to be shown as selected in the
|
||||||
|
// settings even when the real device id was passed to gUM because of the
|
||||||
|
// above mentioned chrome bug.
|
||||||
|
this.localAudio._realDeviceId = this.localAudio.deviceId = 'default';
|
||||||
|
}
|
||||||
logger.log(`switched local audio device: ${this.localAudio?.getDeviceId()}`);
|
logger.log(`switched local audio device: ${this.localAudio?.getDeviceId()}`);
|
||||||
|
|
||||||
this._updateAudioDeviceId();
|
this._updateAudioDeviceId();
|
||||||
|
@ -2763,11 +2779,20 @@ export default {
|
||||||
checkAndNotifyForNewDevice(newAvailDevices.videoInput, oldDevices.videoInput));
|
checkAndNotifyForNewDevice(newAvailDevices.videoInput, oldDevices.videoInput));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When the 'default' mic needs to be selected, we need to
|
||||||
|
// pass the real device id to gUM instead of 'default' in order
|
||||||
|
// to get the correct MediaStreamTrack from chrome because of the
|
||||||
|
// following bug.
|
||||||
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=997689
|
||||||
|
const hasDefaultMicChanged = newDevices.audioinput === 'default';
|
||||||
|
|
||||||
promises.push(
|
promises.push(
|
||||||
mediaDeviceHelper.createLocalTracksAfterDeviceListChanged(
|
mediaDeviceHelper.createLocalTracksAfterDeviceListChanged(
|
||||||
createLocalTracksF,
|
createLocalTracksF,
|
||||||
newDevices.videoinput,
|
newDevices.videoinput,
|
||||||
newDevices.audioinput)
|
hasDefaultMicChanged
|
||||||
|
? getDefaultDeviceId(APP.store.getState(), 'audioInput')
|
||||||
|
: newDevices.audioinput)
|
||||||
.then(tracks => {
|
.then(tracks => {
|
||||||
// If audio or video muted before, or we unplugged current
|
// If audio or video muted before, or we unplugged current
|
||||||
// device and selected new one, then mute new track.
|
// device and selected new one, then mute new track.
|
||||||
|
@ -2792,6 +2817,12 @@ export default {
|
||||||
// Use the new stream or null if we failed to obtain it.
|
// Use the new stream or null if we failed to obtain it.
|
||||||
return useStream(tracks.find(track => track.getType() === mediaType) || null)
|
return useStream(tracks.find(track => track.getType() === mediaType) || null)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
if (hasDefaultMicChanged) {
|
||||||
|
// workaround for the default device to be shown as selected in the
|
||||||
|
// settings even when the real device id was passed to gUM because of
|
||||||
|
// the above mentioned chrome bug.
|
||||||
|
this.localAudio._realDeviceId = this.localAudio.deviceId = 'default';
|
||||||
|
}
|
||||||
mediaType === 'audio'
|
mediaType === 'audio'
|
||||||
? this._updateAudioDeviceId()
|
? this._updateAudioDeviceId()
|
||||||
: this._updateVideoDeviceId();
|
: this._updateVideoDeviceId();
|
||||||
|
|
|
@ -8,6 +8,12 @@ import logger from './logger';
|
||||||
|
|
||||||
declare var APP: Object;
|
declare var APP: Object;
|
||||||
|
|
||||||
|
const webrtcKindToJitsiKindTranslator = {
|
||||||
|
audioinput: 'audioInput',
|
||||||
|
audiooutput: 'audioOutput',
|
||||||
|
videoinput: 'videoInput'
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detects the use case when the labels are not available if the A/V permissions
|
* Detects the use case when the labels are not available if the A/V permissions
|
||||||
* are not yet granted.
|
* are not yet granted.
|
||||||
|
@ -41,6 +47,29 @@ export function getAudioOutputDeviceId() {
|
||||||
return JitsiMeetJS.mediaDevices.getAudioOutputDevice();
|
return JitsiMeetJS.mediaDevices.getAudioOutputDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the real device id of the default device of the given type.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The redux state.
|
||||||
|
* @param {*} kind - The type of the device. One of "audioInput",
|
||||||
|
* "audioOutput", and "videoInput". Also supported is all lowercase versions
|
||||||
|
* of the preceding types.
|
||||||
|
* @returns {string|undefined}
|
||||||
|
*/
|
||||||
|
export function getDefaultDeviceId(state: Object, kind: string) {
|
||||||
|
const kindToSearch = webrtcKindToJitsiKindTranslator[kind] || kind;
|
||||||
|
const defaultDevice = (state['features/base/devices'].availableDevices[kindToSearch] || [])
|
||||||
|
.find(d => d.deviceId === 'default');
|
||||||
|
|
||||||
|
// Find the device with a matching group id.
|
||||||
|
const matchingDevice = (state['features/base/devices'].availableDevices[kindToSearch] || [])
|
||||||
|
.find(d => d.deviceId !== 'default' && d.groupId === defaultDevice.groupId);
|
||||||
|
|
||||||
|
if (matchingDevice) {
|
||||||
|
return matchingDevice.deviceId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a device with a label that matches the passed label and returns its id.
|
* Finds a device with a label that matches the passed label and returns its id.
|
||||||
*
|
*
|
||||||
|
@ -52,12 +81,6 @@ export function getAudioOutputDeviceId() {
|
||||||
* @returns {string|undefined}
|
* @returns {string|undefined}
|
||||||
*/
|
*/
|
||||||
export function getDeviceIdByLabel(state: Object, label: string, kind: string) {
|
export function getDeviceIdByLabel(state: Object, label: string, kind: string) {
|
||||||
const webrtcKindToJitsiKindTranslator = {
|
|
||||||
audioinput: 'audioInput',
|
|
||||||
audiooutput: 'audioOutput',
|
|
||||||
videoinput: 'videoInput'
|
|
||||||
};
|
|
||||||
|
|
||||||
const kindToSearch = webrtcKindToJitsiKindTranslator[kind] || kind;
|
const kindToSearch = webrtcKindToJitsiKindTranslator[kind] || kind;
|
||||||
|
|
||||||
const device
|
const device
|
||||||
|
@ -80,12 +103,6 @@ export function getDeviceIdByLabel(state: Object, label: string, kind: string) {
|
||||||
* @returns {string|undefined}
|
* @returns {string|undefined}
|
||||||
*/
|
*/
|
||||||
export function getDeviceLabelById(state: Object, id: string, kind: string) {
|
export function getDeviceLabelById(state: Object, id: string, kind: string) {
|
||||||
const webrtcKindToJitsiKindTranslator = {
|
|
||||||
audioinput: 'audioInput',
|
|
||||||
audiooutput: 'audioOutput',
|
|
||||||
videoinput: 'videoInput'
|
|
||||||
};
|
|
||||||
|
|
||||||
const kindToSearch = webrtcKindToJitsiKindTranslator[kind] || kind;
|
const kindToSearch = webrtcKindToJitsiKindTranslator[kind] || kind;
|
||||||
|
|
||||||
const device
|
const device
|
||||||
|
|
Loading…
Reference in New Issue