fix(device-selection): Handle properly on prejoin

The device selection initialization on the prejoin use case was handled
like the welcome page. This was introducing issues with selecting the
stored devices and not the ones used, enabling the device selection when
it will fail and others.
This commit is contained in:
Hristo Terezov 2022-05-24 14:04:21 -05:00
parent 7e942173aa
commit ae565aaac6
6 changed files with 44 additions and 19 deletions

View File

@ -14,11 +14,13 @@ import logger from './logger';
* Submits the settings related to device selection. * Submits the settings related to device selection.
* *
* @param {Object} newState - The new settings. * @param {Object} newState - The new settings.
* @param {boolean} isDisplayedOnWelcomePage - Indicates whether the device selection dialog is displayed on the
* welcome page or not.
* @returns {Function} * @returns {Function}
*/ */
export function submitDeviceSelectionTab(newState) { export function submitDeviceSelectionTab(newState, isDisplayedOnWelcomePage) {
return (dispatch, getState) => { return (dispatch, getState) => {
const currentState = getDeviceSelectionDialogProps(getState()); const currentState = getDeviceSelectionDialogProps(getState(), isDisplayedOnWelcomePage);
if (newState.selectedVideoInputId && (newState.selectedVideoInputId !== currentState.selectedVideoInputId)) { if (newState.selectedVideoInputId && (newState.selectedVideoInputId !== currentState.selectedVideoInputId)) {
dispatch(updateSettings({ dispatch(updateSettings({

View File

@ -27,23 +27,28 @@ import {
* *
* @param {(Function|Object)} stateful -The (whole) redux state, or redux's * @param {(Function|Object)} stateful -The (whole) redux state, or redux's
* {@code getState} function to be used to retrieve the state. * {@code getState} function to be used to retrieve the state.
* @param {boolean} isDisplayedOnWelcomePage - Indicates whether the device selection dialog is displayed on the
* welcome page or not.
* @returns {Object} - The properties for the device selection dialog. * @returns {Object} - The properties for the device selection dialog.
*/ */
export function getDeviceSelectionDialogProps(stateful: Object | Function) { export function getDeviceSelectionDialogProps(stateful: Object | Function, isDisplayedOnWelcomePage) {
// On mobile Safari because of https://bugs.webkit.org/show_bug.cgi?id=179363#c30, the old track is stopped // On mobile Safari because of https://bugs.webkit.org/show_bug.cgi?id=179363#c30, the old track is stopped
// by the browser when a new track is created for preview. That's why we are disabling all previews. // by the browser when a new track is created for preview. That's why we are disabling all previews.
const disablePreviews = isIosMobileBrowser(); const disablePreviews = isIosMobileBrowser();
const state = toState(stateful); const state = toState(stateful);
const settings = state['features/base/settings']; const settings = state['features/base/settings'];
const { conference } = state['features/base/conference'];
const { permissions } = state['features/base/devices']; const { permissions } = state['features/base/devices'];
const cameraChangeSupported = JitsiMeetJS.mediaDevices.isDeviceChangeAvailable('input'); const inputDeviceChangeSupported = JitsiMeetJS.mediaDevices.isDeviceChangeAvailable('input');
const speakerChangeSupported = JitsiMeetJS.mediaDevices.isDeviceChangeAvailable('output'); const speakerChangeSupported = JitsiMeetJS.mediaDevices.isDeviceChangeAvailable('output');
const userSelectedCamera = getUserSelectedCameraDeviceId(state); const userSelectedCamera = getUserSelectedCameraDeviceId(state);
const userSelectedMic = getUserSelectedMicDeviceId(state); const userSelectedMic = getUserSelectedMicDeviceId(state);
let disableAudioInputChange = !JitsiMeetJS.mediaDevices.isMultipleAudioInputSupported();
let disableVideoInputSelect = !cameraChangeSupported; // When the previews are disabled we don't need multiple audio input support in order to chage the mic. This is the
// case for Safari on iOS.
let disableAudioInputChange
= !JitsiMeetJS.mediaDevices.isMultipleAudioInputSupported() && !(disablePreviews && inputDeviceChangeSupported);
let disableVideoInputSelect = !inputDeviceChangeSupported;
let selectedAudioInputId = settings.micDeviceId; let selectedAudioInputId = settings.micDeviceId;
let selectedAudioOutputId = getAudioOutputDeviceId(); let selectedAudioOutputId = getAudioOutputDeviceId();
let selectedVideoInputId = settings.cameraDeviceId; let selectedVideoInputId = settings.cameraDeviceId;
@ -52,7 +57,7 @@ export function getDeviceSelectionDialogProps(stateful: Object | Function) {
// conference and this is not supported, when we open device selection on // conference and this is not supported, when we open device selection on
// welcome page changing input devices will not be a problem // welcome page changing input devices will not be a problem
// 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 (isDisplayedOnWelcomePage) {
disableAudioInputChange = false; disableAudioInputChange = false;
disableVideoInputSelect = false; disableVideoInputSelect = false;
selectedAudioInputId = userSelectedMic; selectedAudioInputId = userSelectedMic;
@ -72,7 +77,7 @@ export function getDeviceSelectionDialogProps(stateful: Object | Function) {
hideAudioInputPreview: disableAudioInputChange || !JitsiMeetJS.isCollectingLocalStats() || disablePreviews, hideAudioInputPreview: disableAudioInputChange || !JitsiMeetJS.isCollectingLocalStats() || disablePreviews,
hideAudioOutputPreview: !speakerChangeSupported || disablePreviews, hideAudioOutputPreview: !speakerChangeSupported || disablePreviews,
hideAudioOutputSelect: !speakerChangeSupported, hideAudioOutputSelect: !speakerChangeSupported,
hideVideoInputPreview: !cameraChangeSupported || disablePreviews, hideVideoInputPreview: !inputDeviceChangeSupported || disablePreviews,
selectedAudioInputId, selectedAudioInputId,
selectedAudioOutputId, selectedAudioOutputId,
selectedVideoInputId selectedVideoInputId

View File

@ -43,10 +43,15 @@ export function openLogoutDialog(onLogout: Function) {
* *
* @param {string} defaultTab - The tab in {@code SettingsDialog} that should be * @param {string} defaultTab - The tab in {@code SettingsDialog} that should be
* displayed initially. * displayed initially.
* @param {boolean} isDisplayedOnWelcomePage - Indicates whether the device selection dialog is displayed on the
* welcome page or not.
* @returns {Function} * @returns {Function}
*/ */
export function openSettingsDialog(defaultTab: string) { export function openSettingsDialog(defaultTab: string, isDisplayedOnWelcomePage: boolean) {
return openDialog(SettingsDialog, { defaultTab }); return openDialog(SettingsDialog, {
defaultTab,
isDisplayedOnWelcomePage
});
} }
/** /**

View File

@ -21,7 +21,13 @@ type Props = AbstractButtonProps & {
/** /**
* The redux {@code dispatch} function. * The redux {@code dispatch} function.
*/ */
dispatch: Function dispatch: Function,
/**
* Indicates whether the device selection dialog is displayed on the
* welcome page or not.
*/
isDisplayedOnWelcomePage: boolean
}; };
/** /**
@ -40,10 +46,10 @@ class SettingsButton extends AbstractButton<Props, *> {
* @returns {void} * @returns {void}
*/ */
_handleClick() { _handleClick() {
const { defaultTab = SETTINGS_TABS.DEVICES, dispatch } = this.props; const { defaultTab = SETTINGS_TABS.DEVICES, dispatch, isDisplayedOnWelcomePage = false } = this.props;
sendAnalytics(createToolbarEvent('settings')); sendAnalytics(createToolbarEvent('settings'));
dispatch(openSettingsDialog(defaultTab)); dispatch(openSettingsDialog(defaultTab, isDisplayedOnWelcomePage));
} }
} }

View File

@ -59,7 +59,13 @@ type Props = {
/** /**
* Invoked to save changed settings. * Invoked to save changed settings.
*/ */
dispatch: Function dispatch: Function,
/**
* Indicates whether the device selection dialog is displayed on the
* welcome page or not.
*/
isDisplayedOnWelcomePage: boolean
}; };
/** /**
@ -253,7 +259,7 @@ class SettingsDialog extends Component<Props> {
* }} * }}
*/ */
function _mapStateToProps(state, ownProps) { function _mapStateToProps(state, ownProps) {
const { classes } = ownProps; const { classes, isDisplayedOnWelcomePage } = ownProps;
const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || []; const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || [];
// The settings sections to display. // The settings sections to display.
@ -276,7 +282,7 @@ function _mapStateToProps(state, ownProps) {
component: DeviceSelection, component: DeviceSelection,
label: 'settings.devices', label: 'settings.devices',
onMount: getAvailableDevices, onMount: getAvailableDevices,
props: getDeviceSelectionDialogProps(state), props: getDeviceSelectionDialogProps(state, isDisplayedOnWelcomePage),
propsUpdateFunction: (tabState, newProps) => { propsUpdateFunction: (tabState, newProps) => {
// Ensure the device selection tab gets updated when new devices // Ensure the device selection tab gets updated when new devices
// are found by taking the new props and only preserving the // are found by taking the new props and only preserving the
@ -292,7 +298,7 @@ function _mapStateToProps(state, ownProps) {
}; };
}, },
styles: `settings-pane ${classes.settingsDialog} devices-pane`, styles: `settings-pane ${classes.settingsDialog} devices-pane`,
submit: submitDeviceSelectionTab submit: newState => submitDeviceSelectionTab(newState, isDisplayedOnWelcomePage)
}); });
} }

View File

@ -191,7 +191,8 @@ class WelcomePage extends AbstractWelcomePage {
<div className = 'header'> <div className = 'header'>
<div className = 'welcome-page-settings'> <div className = 'welcome-page-settings'>
<SettingsButton <SettingsButton
defaultTab = { SETTINGS_TABS.CALENDAR } /> defaultTab = { SETTINGS_TABS.CALENDAR }
isDisplayedOnWelcomePage = { true } />
{ showAdditionalToolbarContent { showAdditionalToolbarContent
? <div ? <div
className = 'settings-toolbar-content' className = 'settings-toolbar-content'