2018-04-12 19:58:20 +00:00
|
|
|
// @flow
|
2019-03-19 17:35:36 +00:00
|
|
|
|
|
|
|
import { randomHexString } from 'js-utils/random';
|
2018-04-12 19:58:20 +00:00
|
|
|
import _ from 'lodash';
|
|
|
|
|
2018-07-11 09:42:43 +00:00
|
|
|
import { APP_WILL_MOUNT } from '../app';
|
2018-04-12 19:58:20 +00:00
|
|
|
import JitsiMeetJS, { browser } from '../lib-jitsi-meet';
|
|
|
|
import { ReducerRegistry } from '../redux';
|
|
|
|
import { PersistenceRegistry } from '../storage';
|
2019-03-19 17:35:36 +00:00
|
|
|
import { assignIfDefined } from '../util';
|
2018-04-12 19:58:20 +00:00
|
|
|
|
|
|
|
import { SETTINGS_UPDATED } from './actionTypes';
|
|
|
|
|
|
|
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The default/initial redux state of the feature {@code base/settings}.
|
|
|
|
*
|
|
|
|
* @type Object
|
|
|
|
*/
|
|
|
|
const DEFAULT_STATE = {
|
|
|
|
audioOutputDeviceId: undefined,
|
|
|
|
avatarID: undefined,
|
|
|
|
avatarURL: undefined,
|
|
|
|
cameraDeviceId: undefined,
|
|
|
|
displayName: undefined,
|
|
|
|
email: undefined,
|
|
|
|
localFlipX: true,
|
|
|
|
micDeviceId: undefined,
|
|
|
|
serverURL: undefined,
|
|
|
|
startAudioOnly: false,
|
|
|
|
startWithAudioMuted: false,
|
|
|
|
startWithVideoMuted: false
|
|
|
|
};
|
|
|
|
|
|
|
|
const STORE_NAME = 'features/base/settings';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets up the persistence of the feature {@code base/settings}.
|
|
|
|
*/
|
|
|
|
PersistenceRegistry.register(STORE_NAME);
|
|
|
|
|
|
|
|
ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
|
|
|
|
switch (action.type) {
|
|
|
|
case APP_WILL_MOUNT:
|
|
|
|
return _initSettings(state);
|
|
|
|
|
|
|
|
case SETTINGS_UPDATED:
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
...action.settings
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return state;
|
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieves the legacy profile values regardless of it's being in pre or
|
|
|
|
* post-flattening format.
|
|
|
|
*
|
2018-11-08 12:25:02 +00:00
|
|
|
* FIXME: Let's remove this after a predefined time (e.g. By July 2018) to avoid
|
2018-04-12 19:58:20 +00:00
|
|
|
* garbage in the source.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns {Object}
|
|
|
|
*/
|
|
|
|
function _getLegacyProfile() {
|
|
|
|
let persistedProfile
|
|
|
|
= window.localStorage.getItem('features/base/profile');
|
|
|
|
|
|
|
|
if (persistedProfile) {
|
|
|
|
try {
|
|
|
|
persistedProfile = JSON.parse(persistedProfile);
|
|
|
|
|
|
|
|
if (persistedProfile && typeof persistedProfile === 'object') {
|
|
|
|
const preFlattenedProfile = persistedProfile.profile;
|
|
|
|
|
|
|
|
return preFlattenedProfile || persistedProfile;
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
logger.warn('Error parsing persisted legacy profile', e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Inits the settings object based on what information we have available.
|
|
|
|
* Info taken into consideration:
|
|
|
|
* - Old Settings.js style data
|
|
|
|
* - Things that we stored in profile earlier but belong here.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @param {Object} featureState - The current state of the feature.
|
|
|
|
* @returns {Object}
|
|
|
|
*/
|
|
|
|
function _initSettings(featureState) {
|
|
|
|
let settings = featureState;
|
|
|
|
|
|
|
|
// Old Settings.js values
|
|
|
|
// FIXME: Let's remove this after a predefined time (e.g. by July 2018) to
|
|
|
|
// avoid garbage in the source.
|
|
|
|
const displayName = _.escape(window.localStorage.getItem('displayname'));
|
|
|
|
const email = _.escape(window.localStorage.getItem('email'));
|
|
|
|
let avatarID = _.escape(window.localStorage.getItem('avatarId'));
|
|
|
|
|
|
|
|
if (!avatarID) {
|
|
|
|
// if there is no avatar id, we generate a unique one and use it forever
|
|
|
|
avatarID = randomHexString(32);
|
|
|
|
}
|
|
|
|
|
|
|
|
settings = assignIfDefined({
|
|
|
|
avatarID,
|
|
|
|
displayName,
|
|
|
|
email
|
|
|
|
}, settings);
|
|
|
|
|
|
|
|
if (!browser.isReactNative()) {
|
|
|
|
// Browser only
|
|
|
|
const localFlipX
|
|
|
|
= JSON.parse(window.localStorage.getItem('localFlipX') || 'true');
|
|
|
|
const cameraDeviceId
|
|
|
|
= window.localStorage.getItem('cameraDeviceId') || '';
|
|
|
|
const micDeviceId = window.localStorage.getItem('micDeviceId') || '';
|
|
|
|
|
|
|
|
// Currently audio output device change is supported only in Chrome and
|
|
|
|
// default output always has 'default' device ID
|
|
|
|
const audioOutputDeviceId
|
|
|
|
= window.localStorage.getItem('audioOutputDeviceId') || 'default';
|
|
|
|
|
2018-07-13 17:04:09 +00:00
|
|
|
settings = assignIfDefined({
|
|
|
|
audioOutputDeviceId,
|
|
|
|
cameraDeviceId,
|
|
|
|
localFlipX,
|
|
|
|
micDeviceId
|
|
|
|
}, settings);
|
|
|
|
|
|
|
|
if (settings.audioOutputDeviceId
|
2018-04-12 19:58:20 +00:00
|
|
|
!== JitsiMeetJS.mediaDevices.getAudioOutputDevice()) {
|
|
|
|
JitsiMeetJS.mediaDevices.setAudioOutputDevice(
|
2018-08-06 15:24:59 +00:00
|
|
|
settings.audioOutputDeviceId
|
2018-04-12 19:58:20 +00:00
|
|
|
).catch(ex => {
|
|
|
|
logger.warn('Failed to set audio output device from local '
|
|
|
|
+ 'storage. Default audio output device will be used'
|
|
|
|
+ 'instead.', ex);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Things we stored in profile earlier
|
|
|
|
const legacyProfile = _getLegacyProfile();
|
|
|
|
|
|
|
|
settings = assignIfDefined(legacyProfile, settings);
|
|
|
|
|
|
|
|
return settings;
|
|
|
|
}
|