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:
parent
2d45709a6a
commit
740c1eb84f
|
@ -2394,7 +2394,15 @@ export default {
|
||||||
: this.useVideoStream.bind(this);
|
: this.useVideoStream.bind(this);
|
||||||
|
|
||||||
// Use the new stream or null if we failed to obtain it.
|
// 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();
|
return Promise.resolve();
|
||||||
|
|
|
@ -39,7 +39,7 @@ function getNewAudioInputDevice(newDevices, localAudio) {
|
||||||
const availableAudioInputDevices = newDevices.filter(
|
const availableAudioInputDevices = newDevices.filter(
|
||||||
d => d.kind === 'audioinput');
|
d => d.kind === 'audioinput');
|
||||||
const settings = APP.store.getState()['features/base/settings'];
|
const settings = APP.store.getState()['features/base/settings'];
|
||||||
const selectedAudioInputDeviceId = settings.micDeviceId;
|
const selectedAudioInputDeviceId = settings.userSelectedMicDeviceId;
|
||||||
const selectedAudioInputDevice = availableAudioInputDevices.find(
|
const selectedAudioInputDevice = availableAudioInputDevices.find(
|
||||||
d => d.deviceId === selectedAudioInputDeviceId);
|
d => d.deviceId === selectedAudioInputDeviceId);
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ function getNewVideoInputDevice(newDevices, localVideo) {
|
||||||
const availableVideoInputDevices = newDevices.filter(
|
const availableVideoInputDevices = newDevices.filter(
|
||||||
d => d.kind === 'videoinput');
|
d => d.kind === 'videoinput');
|
||||||
const settings = APP.store.getState()['features/base/settings'];
|
const settings = APP.store.getState()['features/base/settings'];
|
||||||
const selectedVideoInputDeviceId = settings.cameraDeviceId;
|
const selectedVideoInputDeviceId = settings.userSelectedCameraDeviceId;
|
||||||
const selectedVideoInputDevice = availableVideoInputDevices.find(
|
const selectedVideoInputDevice = availableVideoInputDevices.find(
|
||||||
d => d.deviceId === selectedVideoInputDeviceId);
|
d => d.deviceId === selectedVideoInputDeviceId);
|
||||||
|
|
||||||
|
|
|
@ -90,10 +90,10 @@ export function configureInitialDevices() {
|
||||||
|
|
||||||
return updateSettingsPromise
|
return updateSettingsPromise
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const { audioOutputDeviceId }
|
const { userSelectedAudioOutputDeviceId }
|
||||||
= getState()['features/base/settings'];
|
= getState()['features/base/settings'];
|
||||||
|
|
||||||
return setAudioOutputDeviceId(audioOutputDeviceId, dispatch)
|
return setAudioOutputDeviceId(userSelectedAudioOutputDeviceId, dispatch)
|
||||||
.catch(ex => logger.warn(`Failed to set audio output device.
|
.catch(ex => logger.warn(`Failed to set audio output device.
|
||||||
Default audio output device will be used instead ${ex}`));
|
Default audio output device will be used instead ${ex}`));
|
||||||
});
|
});
|
||||||
|
|
|
@ -117,14 +117,27 @@ export function groupDevicesByKind(devices: Object[]): Object {
|
||||||
*
|
*
|
||||||
* @param {string} newId - New audio output device id.
|
* @param {string} newId - New audio output device id.
|
||||||
* @param {Function} dispatch - The Redux dispatch function.
|
* @param {Function} dispatch - The Redux dispatch function.
|
||||||
|
* @param {boolean} userSelection - Whether this is a user selection update.
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
export function setAudioOutputDeviceId(
|
export function setAudioOutputDeviceId(
|
||||||
newId: string = 'default',
|
newId: string = 'default',
|
||||||
dispatch: Function): Promise<*> {
|
dispatch: Function,
|
||||||
|
userSelection: boolean = false): Promise<*> {
|
||||||
return JitsiMeetJS.mediaDevices.setAudioOutputDevice(newId)
|
return JitsiMeetJS.mediaDevices.setAudioOutputDevice(newId)
|
||||||
.then(() =>
|
.then(() => {
|
||||||
dispatch(updateSettings({
|
const newSettings = {
|
||||||
audioOutputDeviceId: newId
|
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));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,10 @@ const DEFAULT_STATE = {
|
||||||
serverURL: undefined,
|
serverURL: undefined,
|
||||||
startAudioOnly: false,
|
startAudioOnly: false,
|
||||||
startWithAudioMuted: false,
|
startWithAudioMuted: false,
|
||||||
startWithVideoMuted: false
|
startWithVideoMuted: false,
|
||||||
|
userSelectedAudioOutputDeviceId: undefined,
|
||||||
|
userSelectedCameraDeviceId: undefined,
|
||||||
|
userSelectedMicDeviceId: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
const STORE_NAME = 'features/base/settings';
|
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}.
|
* 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) => {
|
ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
|
|
@ -40,10 +40,10 @@ export function createLocalTracksF(
|
||||||
const settings = store.getState()['features/base/settings'];
|
const settings = store.getState()['features/base/settings'];
|
||||||
|
|
||||||
if (typeof cameraDeviceId === 'undefined' || cameraDeviceId === null) {
|
if (typeof cameraDeviceId === 'undefined' || cameraDeviceId === null) {
|
||||||
cameraDeviceId = settings.cameraDeviceId;
|
cameraDeviceId = settings.userSelectedCameraDeviceId;
|
||||||
}
|
}
|
||||||
if (typeof micDeviceId === 'undefined' || micDeviceId === null) {
|
if (typeof micDeviceId === 'undefined' || micDeviceId === null) {
|
||||||
micDeviceId = settings.micDeviceId;
|
micDeviceId = settings.userSelectedMicDeviceId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,8 @@ export function submitDeviceSelectionTab(newState) {
|
||||||
&& newState.selectedVideoInputId
|
&& newState.selectedVideoInputId
|
||||||
!== currentState.selectedVideoInputId) {
|
!== currentState.selectedVideoInputId) {
|
||||||
dispatch(updateSettings({
|
dispatch(updateSettings({
|
||||||
cameraDeviceId: newState.selectedVideoInputId
|
cameraDeviceId: newState.selectedVideoInputId,
|
||||||
|
userSelectedCameraDeviceId: newState.selectedVideoInputId
|
||||||
}));
|
}));
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
|
@ -123,7 +124,8 @@ export function submitDeviceSelectionTab(newState) {
|
||||||
&& newState.selectedAudioInputId
|
&& newState.selectedAudioInputId
|
||||||
!== currentState.selectedAudioInputId) {
|
!== currentState.selectedAudioInputId) {
|
||||||
dispatch(updateSettings({
|
dispatch(updateSettings({
|
||||||
micDeviceId: newState.selectedAudioInputId
|
micDeviceId: newState.selectedAudioInputId,
|
||||||
|
userSelectedMicDeviceId: newState.selectedAudioInputId
|
||||||
}));
|
}));
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
|
@ -137,7 +139,8 @@ export function submitDeviceSelectionTab(newState) {
|
||||||
|
|
||||||
setAudioOutputDeviceId(
|
setAudioOutputDeviceId(
|
||||||
newState.selectedAudioOutputId,
|
newState.selectedAudioOutputId,
|
||||||
dispatch)
|
dispatch,
|
||||||
|
true)
|
||||||
.then(() => logger.log('changed audio output device'))
|
.then(() => logger.log('changed audio output device'))
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
|
|
|
@ -26,20 +26,37 @@ import { toState } from '../base/redux';
|
||||||
export function getDeviceSelectionDialogProps(stateful: Object | Function) {
|
export function getDeviceSelectionDialogProps(stateful: Object | Function) {
|
||||||
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'];
|
||||||
|
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 {
|
return {
|
||||||
availableDevices: state['features/base/devices'].availableDevices,
|
availableDevices: state['features/base/devices'].availableDevices,
|
||||||
disableAudioInputChange:
|
disableAudioInputChange,
|
||||||
!JitsiMeetJS.isMultipleAudioInputSupported(),
|
|
||||||
disableDeviceChange:
|
disableDeviceChange:
|
||||||
!JitsiMeetJS.mediaDevices.isDeviceChangeAvailable(),
|
!JitsiMeetJS.mediaDevices.isDeviceChangeAvailable(),
|
||||||
hideAudioInputPreview:
|
hideAudioInputPreview:
|
||||||
!JitsiMeetJS.isCollectingLocalStats(),
|
!JitsiMeetJS.isCollectingLocalStats(),
|
||||||
hideAudioOutputSelect: !JitsiMeetJS.mediaDevices
|
hideAudioOutputSelect: !JitsiMeetJS.mediaDevices
|
||||||
.isDeviceChangeAvailable('output'),
|
.isDeviceChangeAvailable('output'),
|
||||||
selectedAudioInputId: settings.micDeviceId,
|
selectedAudioInputId,
|
||||||
selectedAudioOutputId: getAudioOutputDeviceId(),
|
selectedAudioOutputId,
|
||||||
selectedVideoInputId: settings.cameraDeviceId
|
selectedVideoInputId
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue