Adds new persistent state for devices user selection.

The state about currently opened devices is filtered and not stored, where we only store when user selects a device preferences.
Also allow changing input devices for Firefox when we are not in a conference.
This commit is contained in:
damencho 2019-05-01 15:13:25 +01:00 committed by Дамян Минков
parent 2d45709a6a
commit 740c1eb84f
8 changed files with 79 additions and 22 deletions

View File

@ -2394,7 +2394,15 @@ export default {
: this.useVideoStream.bind(this);
// 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(() => {
const settings
= mediaType === 'audio'
? { micDeviceId: newDevices.audioinput }
: { cameraDeviceId: newDevices.videoinput };
APP.store.dispatch(updateSettings(settings));
});
}
return Promise.resolve();

View File

@ -39,7 +39,7 @@ function getNewAudioInputDevice(newDevices, localAudio) {
const availableAudioInputDevices = newDevices.filter(
d => d.kind === 'audioinput');
const settings = APP.store.getState()['features/base/settings'];
const selectedAudioInputDeviceId = settings.micDeviceId;
const selectedAudioInputDeviceId = settings.userSelectedMicDeviceId;
const selectedAudioInputDevice = availableAudioInputDevices.find(
d => d.deviceId === selectedAudioInputDeviceId);
@ -78,7 +78,7 @@ function getNewVideoInputDevice(newDevices, localVideo) {
const availableVideoInputDevices = newDevices.filter(
d => d.kind === 'videoinput');
const settings = APP.store.getState()['features/base/settings'];
const selectedVideoInputDeviceId = settings.cameraDeviceId;
const selectedVideoInputDeviceId = settings.userSelectedCameraDeviceId;
const selectedVideoInputDevice = availableVideoInputDevices.find(
d => d.deviceId === selectedVideoInputDeviceId);

View File

@ -90,10 +90,10 @@ export function configureInitialDevices() {
return updateSettingsPromise
.then(() => {
const { audioOutputDeviceId }
const { userSelectedAudioOutputDeviceId }
= getState()['features/base/settings'];
return setAudioOutputDeviceId(audioOutputDeviceId, dispatch)
return setAudioOutputDeviceId(userSelectedAudioOutputDeviceId, dispatch)
.catch(ex => logger.warn(`Failed to set audio output device.
Default audio output device will be used instead ${ex}`));
});

View File

@ -117,14 +117,27 @@ export function groupDevicesByKind(devices: Object[]): Object {
*
* @param {string} newId - New audio output device id.
* @param {Function} dispatch - The Redux dispatch function.
* @param {boolean} userSelection - Whether this is a user selection update.
* @returns {Promise}
*/
export function setAudioOutputDeviceId(
newId: string = 'default',
dispatch: Function): Promise<*> {
dispatch: Function,
userSelection: boolean = false): Promise<*> {
return JitsiMeetJS.mediaDevices.setAudioOutputDevice(newId)
.then(() =>
dispatch(updateSettings({
audioOutputDeviceId: newId
})));
.then(() => {
const newSettings = {
audioOutputDeviceId: newId,
userSelectedAudioOutputDeviceId: undefined
};
if (userSelection) {
newSettings.userSelectedAudioOutputDeviceId = newId;
} else {
// a flow workaround, I needed to add 'userSelectedAudioOutputDeviceId: undefined'
delete newSettings.userSelectedAudioOutputDeviceId;
}
return dispatch(updateSettings(newSettings));
});
}

View File

@ -30,7 +30,10 @@ const DEFAULT_STATE = {
serverURL: undefined,
startAudioOnly: false,
startWithAudioMuted: false,
startWithVideoMuted: false
startWithVideoMuted: false,
userSelectedAudioOutputDeviceId: undefined,
userSelectedCameraDeviceId: undefined,
userSelectedMicDeviceId: undefined
};
const STORE_NAME = 'features/base/settings';
@ -38,7 +41,20 @@ const STORE_NAME = 'features/base/settings';
/**
* Sets up the persistence of the feature {@code base/settings}.
*/
PersistenceRegistry.register(STORE_NAME);
const filterSubtree = {};
// start with the default state
Object.keys(DEFAULT_STATE).forEach(key => {
filterSubtree[key] = true;
});
// we want to filter these props, to not be stored as they represent
// what is currently opened/used as devices
filterSubtree.audioOutputDeviceId = false;
filterSubtree.cameraDeviceId = false;
filterSubtree.micDeviceId = false;
PersistenceRegistry.register(STORE_NAME, filterSubtree);
ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
switch (action.type) {

View File

@ -40,10 +40,10 @@ export function createLocalTracksF(
const settings = store.getState()['features/base/settings'];
if (typeof cameraDeviceId === 'undefined' || cameraDeviceId === null) {
cameraDeviceId = settings.cameraDeviceId;
cameraDeviceId = settings.userSelectedCameraDeviceId;
}
if (typeof micDeviceId === 'undefined' || micDeviceId === null) {
micDeviceId = settings.micDeviceId;
micDeviceId = settings.userSelectedMicDeviceId;
}
}

View File

@ -112,7 +112,8 @@ export function submitDeviceSelectionTab(newState) {
&& newState.selectedVideoInputId
!== currentState.selectedVideoInputId) {
dispatch(updateSettings({
cameraDeviceId: newState.selectedVideoInputId
cameraDeviceId: newState.selectedVideoInputId,
userSelectedCameraDeviceId: newState.selectedVideoInputId
}));
dispatch(
@ -123,7 +124,8 @@ export function submitDeviceSelectionTab(newState) {
&& newState.selectedAudioInputId
!== currentState.selectedAudioInputId) {
dispatch(updateSettings({
micDeviceId: newState.selectedAudioInputId
micDeviceId: newState.selectedAudioInputId,
userSelectedMicDeviceId: newState.selectedAudioInputId
}));
dispatch(
@ -137,7 +139,8 @@ export function submitDeviceSelectionTab(newState) {
setAudioOutputDeviceId(
newState.selectedAudioOutputId,
dispatch)
dispatch,
true)
.then(() => logger.log('changed audio output device'))
.catch(err => {
logger.warn(

View File

@ -26,20 +26,37 @@ import { toState } from '../base/redux';
export function getDeviceSelectionDialogProps(stateful: Object | Function) {
const state = toState(stateful);
const settings = state['features/base/settings'];
const { conference } = state['features/base/conference'];
let disableAudioInputChange = !JitsiMeetJS.mediaDevices.isMultipleAudioInputSupported();
let selectedAudioInputId = settings.micDeviceId;
let selectedAudioOutputId = getAudioOutputDeviceId();
let selectedVideoInputId = 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
// 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
if (!conference) {
disableAudioInputChange = false;
selectedAudioInputId = settings.userSelectedMicDeviceId;
selectedAudioOutputId = settings.userSelectedAudioOutputDeviceId;
selectedVideoInputId = settings.userSelectedCameraDeviceId;
}
// we fill the device selection dialog with the devices that are currently
// used or if none are currently used with what we have in settings(user selected)
return {
availableDevices: state['features/base/devices'].availableDevices,
disableAudioInputChange:
!JitsiMeetJS.isMultipleAudioInputSupported(),
disableAudioInputChange,
disableDeviceChange:
!JitsiMeetJS.mediaDevices.isDeviceChangeAvailable(),
hideAudioInputPreview:
!JitsiMeetJS.isCollectingLocalStats(),
hideAudioOutputSelect: !JitsiMeetJS.mediaDevices
.isDeviceChangeAvailable('output'),
selectedAudioInputId: settings.micDeviceId,
selectedAudioOutputId: getAudioOutputDeviceId(),
selectedVideoInputId: settings.cameraDeviceId
selectedAudioInputId,
selectedAudioOutputId,
selectedVideoInputId
};
}