mirror of https://github.com/jitsi/jitsi-meet
Refactored conference.js code. Moved almost all code that relates to handling change of media devices to separate module. Fixed couple of bugs.
parent
97237470af
commit
897a6bfbe6
@ -0,0 +1,233 @@ |
||||
/* global $, APP, JitsiMeetJS, config, interfaceConfig */ |
||||
|
||||
let currentAudioInputDevices, |
||||
currentVideoInputDevices, |
||||
currentAudioOutputDevices; |
||||
|
||||
/** |
||||
* Determines if currently selected audio output device should be changed after |
||||
* list of available devices has been changed. |
||||
* @param {MediaDeviceInfo[]} newDevices |
||||
* @returns {string|undefined} - ID of new audio output device to use, undefined |
||||
* if audio output device should not be changed. |
||||
*/ |
||||
function getNewAudioOutputDevice(newDevices) { |
||||
if (!JitsiMeetJS.mediaDevices.isDeviceChangeAvailable('output')) { |
||||
return; |
||||
} |
||||
|
||||
let selectedAudioOutputDeviceId = APP.settings.getAudioOutputDeviceId(); |
||||
let availableAudioOutputDevices = newDevices.filter( |
||||
d => d.kind === 'audiooutput'); |
||||
|
||||
// Switch to 'default' audio output device if we don't have the selected one
|
||||
// available anymore.
|
||||
if (selectedAudioOutputDeviceId !== 'default' && |
||||
!availableAudioOutputDevices.find(d => |
||||
d.deviceId === selectedAudioOutputDeviceId)) { |
||||
return 'default'; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Determines if currently selected audio input device should be changed after |
||||
* list of available devices has been changed. |
||||
* @param {MediaDeviceInfo[]} newDevices |
||||
* @param {JitsiLocalTrack} localAudio |
||||
* @returns {string|undefined} - ID of new microphone device to use, undefined |
||||
* if audio input device should not be changed. |
||||
*/ |
||||
function getNewAudioInputDevice(newDevices, localAudio) { |
||||
let availableAudioInputDevices = newDevices.filter( |
||||
d => d.kind === 'audioinput'); |
||||
let selectedAudioInputDeviceId = APP.settings.getMicDeviceId(); |
||||
let selectedAudioInputDevice = availableAudioInputDevices.find( |
||||
d => d.deviceId === selectedAudioInputDeviceId); |
||||
|
||||
// Here we handle case when no device was initially plugged, but
|
||||
// then it's connected OR new device was connected when previous
|
||||
// track has ended.
|
||||
if (!localAudio || localAudio.disposed || localAudio.isEnded()) { |
||||
// If we have new audio device and permission to use it was granted
|
||||
// (label is not an empty string), then we will try to use the first
|
||||
// available device.
|
||||
if (availableAudioInputDevices.length && |
||||
availableAudioInputDevices[0].label !== '') { |
||||
return availableAudioInputDevices[0].deviceId; |
||||
} |
||||
// Otherwise we assume that we don't have any audio input devices
|
||||
// to use and that's why disable microphone button on UI.
|
||||
else { |
||||
APP.UI.disableMicrophoneButton(); |
||||
} |
||||
} else { |
||||
// And here we handle case when we already have some device working,
|
||||
// but we plug-in a "preferred" (previously selected in settings, stored
|
||||
// in local storage) device.
|
||||
if (selectedAudioInputDevice && |
||||
selectedAudioInputDeviceId !== localAudio.getDeviceId()) { |
||||
return selectedAudioInputDeviceId; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Determines if currently selected video input device should be changed after |
||||
* list of available devices has been changed. |
||||
* @param {MediaDeviceInfo[]} newDevices |
||||
* @param {JitsiLocalTrack} localVideo |
||||
* @returns {string|undefined} - ID of new camera device to use, undefined |
||||
* if video input device should not be changed. |
||||
*/ |
||||
function getNewVideoInputDevice(newDevices, localVideo) { |
||||
let availableVideoInputDevices = newDevices.filter( |
||||
d => d.kind === 'videoinput'); |
||||
let selectedVideoInputDeviceId = APP.settings.getCameraDeviceId(); |
||||
let selectedVideoInputDevice = availableVideoInputDevices.find( |
||||
d => d.deviceId === selectedVideoInputDeviceId); |
||||
|
||||
// Here we handle case when no video input device was initially plugged,
|
||||
// but then device is connected OR new device was connected when
|
||||
// previous track has ended.
|
||||
if (!localVideo || localVideo.disposed || localVideo.isEnded()) { |
||||
// If we have new video device and permission to use it was granted
|
||||
// (label is not an empty string), then we will try to use the first
|
||||
// available device.
|
||||
if (availableVideoInputDevices.length && |
||||
availableVideoInputDevices[0].label !== '') { |
||||
return availableVideoInputDevices[0].deviceId; |
||||
} |
||||
// Otherwise we assume that we don't have any video input devices
|
||||
// to use and that's why disable microphone button on UI.
|
||||
else { |
||||
APP.UI.disableCameraButton(); |
||||
} |
||||
} else { |
||||
// And here we handle case when we already have some device working,
|
||||
// but we plug-in a "preferred" (previously selected in settings, stored
|
||||
// in local storage) device.
|
||||
if (selectedVideoInputDevice && |
||||
selectedVideoInputDeviceId !== localVideo.getDeviceId()) { |
||||
return selectedVideoInputDeviceId; |
||||
} |
||||
} |
||||
} |
||||
|
||||
export default { |
||||
/** |
||||
* Returns list of devices of single kind. |
||||
* @param {MediaDeviceInfo[]} devices |
||||
* @param {'audioinput'|'audiooutput'|'videoinput'} kind |
||||
* @returns {MediaDeviceInfo[]} |
||||
*/ |
||||
getDevicesFromListByKind(devices, kind) { |
||||
return devices.filter(d => d.kind === kind); |
||||
}, |
||||
/** |
||||
* Stores lists of current 'audioinput', 'videoinput' and 'audiooutput' |
||||
* devices. |
||||
* @param {MediaDeviceInfo[]} devices |
||||
*/ |
||||
setCurrentMediaDevices(devices) { |
||||
currentAudioInputDevices = |
||||
this.getDevicesFromListByKind(devices, 'audioinput'); |
||||
currentVideoInputDevices = |
||||
this.getDevicesFromListByKind(devices, 'videoinput'); |
||||
currentAudioOutputDevices = |
||||
this.getDevicesFromListByKind(devices, 'audiooutput'); |
||||
}, |
||||
/** |
||||
* Returns lists of current 'audioinput', 'videoinput' and 'audiooutput' |
||||
* devices. |
||||
* @returns {{ |
||||
* audioinput: (MediaDeviceInfo[]|undefined), |
||||
* videoinput: (MediaDeviceInfo[]|undefined), |
||||
* audiooutput: (MediaDeviceInfo[]|undefined), |
||||
* }} |
||||
*/ |
||||
getCurrentMediaDevices() { |
||||
return { |
||||
audioinput: currentAudioInputDevices, |
||||
videoinput: currentVideoInputDevices, |
||||
audiooutput: currentAudioOutputDevices |
||||
}; |
||||
}, |
||||
/** |
||||
* Determines if currently selected media devices should be changed after |
||||
* list of available devices has been changed. |
||||
* @param {MediaDeviceInfo[]} newDevices |
||||
* @param {boolean} isSharingScreen |
||||
* @param {JitsiLocalTrack} localVideo |
||||
* @param {JitsiLocalTrack} localAudio |
||||
* @returns {{ |
||||
* audioinput: (string|undefined), |
||||
* videoinput: (string|undefined), |
||||
* audiooutput: (string|undefined) |
||||
* }} |
||||
*/ |
||||
getNewMediaDevicesAfterDeviceListChanged( |
||||
newDevices, isSharingScreen, localVideo, localAudio) { |
||||
return { |
||||
audioinput: getNewAudioInputDevice(newDevices, localAudio), |
||||
videoinput: !isSharingScreen && |
||||
getNewVideoInputDevice(newDevices, localVideo), |
||||
audiooutput: getNewAudioOutputDevice(newDevices) |
||||
}; |
||||
}, |
||||
/** |
||||
* Tries to create new local tracks for new devices obtained after device |
||||
* list changed. Shows error dialog in case of failures. |
||||
* @param {function} createLocalTracks |
||||
* @param {string} (cameraDeviceId) |
||||
* @param {string} (micDeviceId) |
||||
* @returns {Promise.<JitsiLocalTrack[]>} |
||||
*/ |
||||
createLocalTracksAfterDeviceListChanged( |
||||
createLocalTracks, cameraDeviceId, micDeviceId) { |
||||
let audioTrackError; |
||||
let videoTrackError; |
||||
let audioRequested = !!micDeviceId; |
||||
let videoRequested = !!cameraDeviceId; |
||||
|
||||
if (audioRequested && videoRequested) { |
||||
// First we try to create both audio and video tracks together.
|
||||
return createLocalTracks( |
||||
['audio', 'video'], cameraDeviceId, micDeviceId) |
||||
// If we fail to do this, try to create them separately.
|
||||
.catch(() => Promise.all( |
||||
[createAudioTrack(false), createVideoTrack(false)])) |
||||
.then((audioTracks, videoTracks) => { |
||||
if (audioTrackError || videoTrackError) { |
||||
APP.UI.showDeviceErrorDialog( |
||||
audioTrackError, videoTrackError); |
||||
} |
||||
|
||||
return (audioTracks || []).concat(videoTracks || []); |
||||
}); |
||||
} else if (videoRequested && !audioRequested) { |
||||
return createVideoTrack(); |
||||
} else if (audioRequested && !videoRequested) { |
||||
return createAudioTrack(); |
||||
} else { |
||||
return Promise.resolve([]); |
||||
} |
||||
|
||||
function createAudioTrack(showError) { |
||||
return createLocalTracks(['audio'], null, micDeviceId) |
||||
.catch(err => { |
||||
audioTrackError = err; |
||||
showError && APP.UI.showDeviceErrorDialog(err, null); |
||||
return []; |
||||
}); |
||||
} |
||||
|
||||
function createVideoTrack(showError) { |
||||
return createLocalTracks(['video'], cameraDeviceId, null) |
||||
.catch(err => { |
||||
videoTrackError = err; |
||||
showError && APP.UI.showDeviceErrorDialog(null, err); |
||||
return []; |
||||
}); |
||||
} |
||||
} |
||||
}; |
Loading…
Reference in new issue