From f1bf8e5f9a243568fcae20a9ed1dcd35316b9ed8 Mon Sep 17 00:00:00 2001 From: Jaya Allamsetty Date: Thu, 9 Sep 2021 13:23:36 -0400 Subject: [PATCH] fix(settings) Disable mic/camera selection on mobile safari. Creating a preview of the same audio/video track kills the tracks that is already being shared in the conference. Therefore, disable camera/mic selection in the settings dialog while the user is in the call. The devices are selectable from the prejoin screen settings dialog. --- .../components/DeviceSelection.js | 50 +++++++++---------- react/features/device-selection/functions.js | 28 ++++++----- 2 files changed, 40 insertions(+), 38 deletions(-) diff --git a/react/features/device-selection/components/DeviceSelection.js b/react/features/device-selection/components/DeviceSelection.js index 41e339b32..74077865f 100644 --- a/react/features/device-selection/components/DeviceSelection.js +++ b/react/features/device-selection/components/DeviceSelection.js @@ -40,6 +40,11 @@ export type Props = { */ disableDeviceChange: boolean, + /** + * Whether video input dropdown should be enabled or not. + */ + disableVideoInputSelect: boolean, + /** * Whether or not the audio permission was granted. */ @@ -57,6 +62,12 @@ export type Props = { */ hideAudioInputPreview: boolean, + /** + * If true, the button to play a test sound on the selected speaker will not be displayed. + * This needs to be hidden on browsers that do not support selecting an audio output device. + */ + hideAudioOutputPreview: boolean, + /** * Whether or not the audio output source selector should display. If * true, the audio output selector and test audio link will not be @@ -70,12 +81,6 @@ export type Props = { */ hideVideoInputPreview: boolean, - /** - * Whether video output dropdown should be displayed or not. - * (In the case of iOS Safari) - */ - hideVideoOutputSelect: boolean, - /** * An optional callback to invoke after the component has completed its * mount logic. @@ -212,7 +217,7 @@ class DeviceSelection extends AbstractDialogTab { render() { const { hideAudioInputPreview, - hideAudioOutputSelect, + hideAudioOutputPreview, hideVideoInputPreview, selectedAudioOutputId } = this.props; @@ -237,7 +242,7 @@ class DeviceSelection extends AbstractDialogTab { className = 'device-selectors'> { this._renderSelectors() } - { !hideAudioOutputSelect + { !hideAudioOutputPreview && } @@ -371,33 +376,27 @@ class DeviceSelection extends AbstractDialogTab { devices: availableDevices.audioInput, hasPermission: hasAudioPermission, icon: 'icon-microphone', - isDisabled: this.props.disableAudioInputChange - || this.props.disableDeviceChange, + isDisabled: this.props.disableAudioInputChange || this.props.disableDeviceChange, key: 'audioInput', id: 'audioInput', label: 'settings.selectMic', - onSelect: selectedAudioInputId => - super._onChange({ selectedAudioInputId }), + onSelect: selectedAudioInputId => super._onChange({ selectedAudioInputId }), selectedDeviceId: this.state.previewAudioTrack - ? this.state.previewAudioTrack.getDeviceId() : null - } - ]; - - if (!this.props.hideVideoOutputSelect) { - configurations.unshift({ + ? this.state.previewAudioTrack.getDeviceId() : this.props.selectedAudioInputId + }, + { devices: availableDevices.videoInput, hasPermission: hasVideoPermission, icon: 'icon-camera', - isDisabled: this.props.disableDeviceChange, + isDisabled: this.props.disableVideoInputSelect || this.props.disableDeviceChange, key: 'videoInput', id: 'videoInput', label: 'settings.selectCamera', - onSelect: selectedVideoInputId => - super._onChange({ selectedVideoInputId }), + onSelect: selectedVideoInputId => super._onChange({ selectedVideoInputId }), selectedDeviceId: this.state.previewVideoTrack - ? this.state.previewVideoTrack.getDeviceId() : null - }); - } + ? this.state.previewVideoTrack.getDeviceId() : this.props.selectedVideoInputId + } + ]; if (!this.props.hideAudioOutputSelect) { configurations.push({ @@ -408,8 +407,7 @@ class DeviceSelection extends AbstractDialogTab { key: 'audioOutput', id: 'audioOutput', label: 'settings.selectAudioOutput', - onSelect: selectedAudioOutputId => - super._onChange({ selectedAudioOutputId }), + onSelect: selectedAudioOutputId => super._onChange({ selectedAudioOutputId }), selectedDeviceId: this.props.selectedAudioOutputId }); } diff --git a/react/features/device-selection/functions.js b/react/features/device-selection/functions.js index 320c06f09..1a498809a 100644 --- a/react/features/device-selection/functions.js +++ b/react/features/device-selection/functions.js @@ -35,10 +35,15 @@ export function getDeviceSelectionDialogProps(stateful: Object | Function) { const { conference } = state['features/base/conference']; const { permissions } = state['features/base/devices']; const isMobileSafari = isIosMobileBrowser(); + const cameraChangeSupported = JitsiMeetJS.mediaDevices.isDeviceChangeAvailable('input'); + const speakerChangeSupported = JitsiMeetJS.mediaDevices.isDeviceChangeAvailable('output'); + const userSelectedCamera = getUserSelectedCameraDeviceId(state); + const userSelectedMic = getUserSelectedMicDeviceId(state); let disableAudioInputChange = !JitsiMeetJS.mediaDevices.isMultipleAudioInputSupported(); - let selectedAudioInputId = settings.micDeviceId; + let disableVideoInputSelect = !cameraChangeSupported; + let selectedAudioInputId = isMobileSafari ? userSelectedMic : settings.micDeviceId; let selectedAudioOutputId = getAudioOutputDeviceId(); - let selectedVideoInputId = settings.cameraDeviceId; + let selectedVideoInputId = isMobileSafari ? userSelectedCamera : settings.cameraDeviceId; // audio input change will be a problem only when we are in a // conference and this is not supported, when we open device selection on @@ -46,9 +51,10 @@ export function getDeviceSelectionDialogProps(stateful: Object | Function) { // on welcome page we also show only what we have saved as user selected devices if (!conference) { disableAudioInputChange = false; - selectedAudioInputId = getUserSelectedMicDeviceId(state); + disableVideoInputSelect = false; + selectedAudioInputId = userSelectedMic; selectedAudioOutputId = getUserSelectedOutputDeviceId(state); - selectedVideoInputId = getUserSelectedCameraDeviceId(state); + selectedVideoInputId = userSelectedCamera; } // we fill the device selection dialog with the devices that are currently @@ -56,16 +62,14 @@ export function getDeviceSelectionDialogProps(stateful: Object | Function) { return { availableDevices: state['features/base/devices'].availableDevices, disableAudioInputChange, - disableDeviceChange: - !JitsiMeetJS.mediaDevices.isDeviceChangeAvailable(), + disableDeviceChange: !JitsiMeetJS.mediaDevices.isDeviceChangeAvailable(), + disableVideoInputSelect, hasAudioPermission: permissions.audio, hasVideoPermission: permissions.video, - hideAudioInputPreview: - !JitsiMeetJS.isCollectingLocalStats(), - hideAudioOutputSelect: !JitsiMeetJS.mediaDevices - .isDeviceChangeAvailable('output'), - hideVideoInputPreview: isMobileSafari, - hideVideoOutputSelect: isMobileSafari, + hideAudioInputPreview: disableAudioInputChange || !JitsiMeetJS.isCollectingLocalStats(), + hideAudioOutputPreview: !speakerChangeSupported, + hideAudioOutputSelect: !speakerChangeSupported, + hideVideoInputPreview: !cameraChangeSupported, selectedAudioInputId, selectedAudioOutputId, selectedVideoInputId