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.
This commit is contained in:
Jaya Allamsetty 2021-09-09 13:23:36 -04:00 committed by Jaya Allamsetty
parent 131d2476ae
commit f1bf8e5f9a
2 changed files with 40 additions and 38 deletions

View File

@ -40,6 +40,11 @@ export type Props = {
*/ */
disableDeviceChange: boolean, disableDeviceChange: boolean,
/**
* Whether video input dropdown should be enabled or not.
*/
disableVideoInputSelect: boolean,
/** /**
* Whether or not the audio permission was granted. * Whether or not the audio permission was granted.
*/ */
@ -57,6 +62,12 @@ export type Props = {
*/ */
hideAudioInputPreview: boolean, 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 * Whether or not the audio output source selector should display. If
* true, the audio output selector and test audio link will not be * true, the audio output selector and test audio link will not be
@ -70,12 +81,6 @@ export type Props = {
*/ */
hideVideoInputPreview: boolean, 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 * An optional callback to invoke after the component has completed its
* mount logic. * mount logic.
@ -212,7 +217,7 @@ class DeviceSelection extends AbstractDialogTab<Props, State> {
render() { render() {
const { const {
hideAudioInputPreview, hideAudioInputPreview,
hideAudioOutputSelect, hideAudioOutputPreview,
hideVideoInputPreview, hideVideoInputPreview,
selectedAudioOutputId selectedAudioOutputId
} = this.props; } = this.props;
@ -237,7 +242,7 @@ class DeviceSelection extends AbstractDialogTab<Props, State> {
className = 'device-selectors'> className = 'device-selectors'>
{ this._renderSelectors() } { this._renderSelectors() }
</div> </div>
{ !hideAudioOutputSelect { !hideAudioOutputPreview
&& <AudioOutputPreview && <AudioOutputPreview
deviceId = { selectedAudioOutputId } /> } deviceId = { selectedAudioOutputId } /> }
</div> </div>
@ -371,33 +376,27 @@ class DeviceSelection extends AbstractDialogTab<Props, State> {
devices: availableDevices.audioInput, devices: availableDevices.audioInput,
hasPermission: hasAudioPermission, hasPermission: hasAudioPermission,
icon: 'icon-microphone', icon: 'icon-microphone',
isDisabled: this.props.disableAudioInputChange isDisabled: this.props.disableAudioInputChange || this.props.disableDeviceChange,
|| this.props.disableDeviceChange,
key: 'audioInput', key: 'audioInput',
id: 'audioInput', id: 'audioInput',
label: 'settings.selectMic', label: 'settings.selectMic',
onSelect: selectedAudioInputId => onSelect: selectedAudioInputId => super._onChange({ selectedAudioInputId }),
super._onChange({ selectedAudioInputId }),
selectedDeviceId: this.state.previewAudioTrack selectedDeviceId: this.state.previewAudioTrack
? this.state.previewAudioTrack.getDeviceId() : null ? this.state.previewAudioTrack.getDeviceId() : this.props.selectedAudioInputId
} },
]; {
if (!this.props.hideVideoOutputSelect) {
configurations.unshift({
devices: availableDevices.videoInput, devices: availableDevices.videoInput,
hasPermission: hasVideoPermission, hasPermission: hasVideoPermission,
icon: 'icon-camera', icon: 'icon-camera',
isDisabled: this.props.disableDeviceChange, isDisabled: this.props.disableVideoInputSelect || this.props.disableDeviceChange,
key: 'videoInput', key: 'videoInput',
id: 'videoInput', id: 'videoInput',
label: 'settings.selectCamera', label: 'settings.selectCamera',
onSelect: selectedVideoInputId => onSelect: selectedVideoInputId => super._onChange({ selectedVideoInputId }),
super._onChange({ selectedVideoInputId }),
selectedDeviceId: this.state.previewVideoTrack selectedDeviceId: this.state.previewVideoTrack
? this.state.previewVideoTrack.getDeviceId() : null ? this.state.previewVideoTrack.getDeviceId() : this.props.selectedVideoInputId
});
} }
];
if (!this.props.hideAudioOutputSelect) { if (!this.props.hideAudioOutputSelect) {
configurations.push({ configurations.push({
@ -408,8 +407,7 @@ class DeviceSelection extends AbstractDialogTab<Props, State> {
key: 'audioOutput', key: 'audioOutput',
id: 'audioOutput', id: 'audioOutput',
label: 'settings.selectAudioOutput', label: 'settings.selectAudioOutput',
onSelect: selectedAudioOutputId => onSelect: selectedAudioOutputId => super._onChange({ selectedAudioOutputId }),
super._onChange({ selectedAudioOutputId }),
selectedDeviceId: this.props.selectedAudioOutputId selectedDeviceId: this.props.selectedAudioOutputId
}); });
} }

View File

@ -35,10 +35,15 @@ export function getDeviceSelectionDialogProps(stateful: Object | Function) {
const { conference } = state['features/base/conference']; const { conference } = state['features/base/conference'];
const { permissions } = state['features/base/devices']; const { permissions } = state['features/base/devices'];
const isMobileSafari = isIosMobileBrowser(); 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 disableAudioInputChange = !JitsiMeetJS.mediaDevices.isMultipleAudioInputSupported();
let selectedAudioInputId = settings.micDeviceId; let disableVideoInputSelect = !cameraChangeSupported;
let selectedAudioInputId = isMobileSafari ? userSelectedMic : settings.micDeviceId;
let selectedAudioOutputId = getAudioOutputDeviceId(); 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 // 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 // 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 // on welcome page we also show only what we have saved as user selected devices
if (!conference) { if (!conference) {
disableAudioInputChange = false; disableAudioInputChange = false;
selectedAudioInputId = getUserSelectedMicDeviceId(state); disableVideoInputSelect = false;
selectedAudioInputId = userSelectedMic;
selectedAudioOutputId = getUserSelectedOutputDeviceId(state); selectedAudioOutputId = getUserSelectedOutputDeviceId(state);
selectedVideoInputId = getUserSelectedCameraDeviceId(state); selectedVideoInputId = userSelectedCamera;
} }
// we fill the device selection dialog with the devices that are currently // we fill the device selection dialog with the devices that are currently
@ -56,16 +62,14 @@ export function getDeviceSelectionDialogProps(stateful: Object | Function) {
return { return {
availableDevices: state['features/base/devices'].availableDevices, availableDevices: state['features/base/devices'].availableDevices,
disableAudioInputChange, disableAudioInputChange,
disableDeviceChange: disableDeviceChange: !JitsiMeetJS.mediaDevices.isDeviceChangeAvailable(),
!JitsiMeetJS.mediaDevices.isDeviceChangeAvailable(), disableVideoInputSelect,
hasAudioPermission: permissions.audio, hasAudioPermission: permissions.audio,
hasVideoPermission: permissions.video, hasVideoPermission: permissions.video,
hideAudioInputPreview: hideAudioInputPreview: disableAudioInputChange || !JitsiMeetJS.isCollectingLocalStats(),
!JitsiMeetJS.isCollectingLocalStats(), hideAudioOutputPreview: !speakerChangeSupported,
hideAudioOutputSelect: !JitsiMeetJS.mediaDevices hideAudioOutputSelect: !speakerChangeSupported,
.isDeviceChangeAvailable('output'), hideVideoInputPreview: !cameraChangeSupported,
hideVideoInputPreview: isMobileSafari,
hideVideoOutputSelect: isMobileSafari,
selectedAudioInputId, selectedAudioInputId,
selectedAudioOutputId, selectedAudioOutputId,
selectedVideoInputId selectedVideoInputId