feat(reload): Preserve local track mute state.
This commit is contained in:
parent
a48aa2b999
commit
d388a7bd3c
|
@ -1,7 +1,7 @@
|
||||||
/* global config, createConnectionExternally */
|
/* global config, createConnectionExternally */
|
||||||
|
|
||||||
import getRoomName from '../react/features/base/config/getRoomName';
|
import getRoomName from '../react/features/base/config/getRoomName';
|
||||||
import parseURLParams from '../react/features/base/config/parseURLParams';
|
import { parseURLParams } from '../react/features/base/util/parseURLParams';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements external connect using createConnectionExternally function defined
|
* Implements external connect using createConnectionExternally function defined
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// XXX The function parseURLParams is exported by the feature base/config (as
|
// XXX The function parseURLParams is exported by the feature base/util (as
|
||||||
// defined in the terminology of react/). However, this file is (very likely)
|
// defined in the terminology of react/). However, this file is (very likely)
|
||||||
// bundled in external_api in addition to app.bundle and, consequently, it is
|
// bundled in external_api in addition to app.bundle and, consequently, it is
|
||||||
// best to import as little as possible here (rather than the whole feature
|
// best to import as little as possible here (rather than the whole feature
|
||||||
// base/config) in order to minimize the amount of source code bundled into
|
// base/util) in order to minimize the amount of source code bundled into
|
||||||
// multiple bundles.
|
// multiple bundles.
|
||||||
import parseURLParams from '../../react/features/base/config/parseURLParams';
|
import { parseURLParams } from '../../react/features/base/util/parseURLParams';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JitsiMeetExternalAPI id - unique for a webpage.
|
* JitsiMeetExternalAPI id - unique for a webpage.
|
||||||
|
|
|
@ -13,8 +13,11 @@ import {
|
||||||
} from '../base/config';
|
} from '../base/config';
|
||||||
import { connect, disconnect, setLocationURL } from '../base/connection';
|
import { connect, disconnect, setLocationURL } from '../base/connection';
|
||||||
import { loadConfig } from '../base/lib-jitsi-meet';
|
import { loadConfig } from '../base/lib-jitsi-meet';
|
||||||
import { createDesiredLocalTracks } from '../base/tracks';
|
import { MEDIA_TYPE } from '../base/media';
|
||||||
|
import { toState } from '../base/redux';
|
||||||
|
import { createDesiredLocalTracks, isLocalVideoTrackMuted, isLocalTrackMuted } from '../base/tracks';
|
||||||
import {
|
import {
|
||||||
|
addHashParamsToURL,
|
||||||
getBackendSafeRoomName,
|
getBackendSafeRoomName,
|
||||||
getLocationContextRoot,
|
getLocationContextRoot,
|
||||||
parseURIString,
|
parseURIString,
|
||||||
|
@ -191,18 +194,42 @@ export function reloadNow() {
|
||||||
return (dispatch: Dispatch<Function>, getState: Function) => {
|
return (dispatch: Dispatch<Function>, getState: Function) => {
|
||||||
dispatch(setFatalError(undefined));
|
dispatch(setFatalError(undefined));
|
||||||
|
|
||||||
const { locationURL } = getState()['features/base/connection'];
|
const state = getState();
|
||||||
|
const { locationURL } = state['features/base/connection'];
|
||||||
|
|
||||||
|
// Preserve the local tracks muted state after the reload.
|
||||||
|
const newURL = addTrackStateToURL(locationURL, state);
|
||||||
|
|
||||||
logger.info(`Reloading the conference using URL: ${locationURL}`);
|
logger.info(`Reloading the conference using URL: ${locationURL}`);
|
||||||
|
|
||||||
if (navigator.product === 'ReactNative') {
|
if (navigator.product === 'ReactNative') {
|
||||||
dispatch(appNavigate(toURLString(locationURL)));
|
dispatch(appNavigate(toURLString(newURL)));
|
||||||
} else {
|
} else {
|
||||||
dispatch(reloadWithStoredParams());
|
dispatch(reloadWithStoredParams());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the current track state to the passed URL.
|
||||||
|
*
|
||||||
|
* @param {URL} url - The URL that will be modified.
|
||||||
|
* @param {Function|Object} stateful - The redux store or {@code getState} function.
|
||||||
|
* @returns {URL} - Returns the modified URL.
|
||||||
|
*/
|
||||||
|
function addTrackStateToURL(url, stateful) {
|
||||||
|
const state = toState(stateful);
|
||||||
|
const tracks = state['features/base/tracks'];
|
||||||
|
const isVideoMuted = isLocalVideoTrackMuted(tracks);
|
||||||
|
const isAudioMuted = isLocalTrackMuted(tracks, MEDIA_TYPE.AUDIO);
|
||||||
|
|
||||||
|
return addHashParamsToURL(new URL(url), { // use new URL object in order to not pollute the passed parameter.
|
||||||
|
'config.startWithAudioMuted': isAudioMuted,
|
||||||
|
'config.startWithVideoMuted': isVideoMuted
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reloads the page by restoring the original URL.
|
* Reloads the page by restoring the original URL.
|
||||||
*
|
*
|
||||||
|
@ -210,17 +237,20 @@ export function reloadNow() {
|
||||||
*/
|
*/
|
||||||
export function reloadWithStoredParams() {
|
export function reloadWithStoredParams() {
|
||||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
return (dispatch: Dispatch<any>, getState: Function) => {
|
||||||
const { locationURL } = getState()['features/base/connection'];
|
const state = getState();
|
||||||
|
const { locationURL } = state['features/base/connection'];
|
||||||
|
|
||||||
|
// Preserve the local tracks muted states.
|
||||||
|
const newURL = addTrackStateToURL(locationURL, state);
|
||||||
const windowLocation = window.location;
|
const windowLocation = window.location;
|
||||||
const oldSearchString = windowLocation.search;
|
const oldSearchString = windowLocation.search;
|
||||||
|
|
||||||
windowLocation.replace(locationURL.toString());
|
windowLocation.replace(newURL.toString());
|
||||||
|
|
||||||
if (window.self !== window.top
|
if (newURL.search === oldSearchString) {
|
||||||
&& locationURL.search === oldSearchString) {
|
|
||||||
// NOTE: Assuming that only the hash or search part of the URL will
|
// NOTE: Assuming that only the hash or search part of the URL will
|
||||||
// be changed!
|
// be changed!
|
||||||
// location.reload will not trigger redirect/reload for iframe when
|
// location.replace will not trigger redirect/reload when
|
||||||
// only the hash params are changed. That's why we need to call
|
// only the hash params are changed. That's why we need to call
|
||||||
// reload in addition to replace.
|
// reload in addition to replace.
|
||||||
windowLocation.reload();
|
windowLocation.reload();
|
||||||
|
|
|
@ -6,15 +6,14 @@ import _ from 'lodash';
|
||||||
import CONFIG_WHITELIST from './configWhitelist';
|
import CONFIG_WHITELIST from './configWhitelist';
|
||||||
import { _CONFIG_STORE_PREFIX } from './constants';
|
import { _CONFIG_STORE_PREFIX } from './constants';
|
||||||
import INTERFACE_CONFIG_WHITELIST from './interfaceConfigWhitelist';
|
import INTERFACE_CONFIG_WHITELIST from './interfaceConfigWhitelist';
|
||||||
import parseURLParams from './parseURLParams';
|
import { parseURLParams } from '../util';
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
|
|
||||||
// XXX The functions getRoomName and parseURLParams are split out of
|
// XXX The function getRoomName is split out of
|
||||||
// functions.js because they are bundled in both app.bundle and
|
// functions.js because it is bundled in both app.bundle and
|
||||||
// do_external_connect, webpack 1 does not support tree shaking, and we don't
|
// do_external_connect, webpack 1 does not support tree shaking, and we don't
|
||||||
// want all functions to be bundled in do_external_connect.
|
// want all functions to be bundled in do_external_connect.
|
||||||
export { default as getRoomName } from './getRoomName';
|
export { default as getRoomName } from './getRoomName';
|
||||||
export { parseURLParams };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a "fake" configuration object for the given base URL. This is used in case the config
|
* Create a "fake" configuration object for the given base URL. This is used in case the config
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import { parseURLParams } from '../config';
|
import { parseURLParams } from '../util';
|
||||||
import JitsiMeetJS from '../lib-jitsi-meet';
|
import JitsiMeetJS from '../lib-jitsi-meet';
|
||||||
import { updateSettings } from '../settings';
|
import { updateSettings } from '../settings';
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* @flow */
|
/* @flow */
|
||||||
|
|
||||||
import { parseURLParams } from '../config';
|
import { parseURLParams } from '../util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the JSON Web Token (JWT), if any, defined by a specific
|
* Retrieves the JSON Web Token (JWT), if any, defined by a specific
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { CONFIG_WHITELIST, parseURLParams } from '../config';
|
import { CONFIG_WHITELIST } from '../config';
|
||||||
import { toState } from '../redux';
|
import { toState } from '../redux';
|
||||||
|
import { parseURLParams } from '../util';
|
||||||
|
|
||||||
import { DEFAULT_SERVER_URL } from './constants';
|
import { DEFAULT_SERVER_URL } from './constants';
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import _ from 'lodash';
|
||||||
|
|
||||||
import { APP_WILL_MOUNT } from '../app';
|
import { APP_WILL_MOUNT } from '../app';
|
||||||
import { setAudioOnly } from '../audio-only';
|
import { setAudioOnly } from '../audio-only';
|
||||||
import parseURLParams from '../config/parseURLParams'; // minimize imports to avoid circular imports
|
import { parseURLParams } from '../util';
|
||||||
import { SET_LOCATION_URL } from '../connection/actionTypes'; // minimize imports to avoid circular imports
|
import { SET_LOCATION_URL } from '../connection/actionTypes'; // minimize imports to avoid circular imports
|
||||||
import { getLocalParticipant, participantUpdated } from '../participants';
|
import { getLocalParticipant, participantUpdated } from '../participants';
|
||||||
import { MiddlewareRegistry } from '../redux';
|
import { MiddlewareRegistry } from '../redux';
|
||||||
|
|
|
@ -3,3 +3,4 @@ export * from './httpUtils';
|
||||||
export * from './loadScript';
|
export * from './loadScript';
|
||||||
export * from './openURLInBrowser';
|
export * from './openURLInBrowser';
|
||||||
export * from './uri';
|
export * from './uri';
|
||||||
|
export * from './parseURLParams';
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
/* @flow */
|
/* @flow */
|
||||||
|
|
||||||
import { reportError } from '../util';
|
import { reportError } from './helpers';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the query/search or fragment/hash parameters out of a specific URL and
|
* Parses the query/search or fragment/hash parameters out of a specific URL and
|
||||||
* returns them as a JS object.
|
* returns them as a JS object.
|
||||||
*
|
*
|
||||||
* @param {string} url - The URL to parse.
|
* @param {URL} url - The URL to parse.
|
||||||
* @param {boolean} dontParse - If falsy, some transformations (for parsing the
|
* @param {boolean} dontParse - If falsy, some transformations (for parsing the
|
||||||
* value as JSON) will be executed.
|
* value as JSON) will be executed.
|
||||||
* @param {string} source - If {@code 'search'}, the parameters will parsed out
|
* @param {string} source - If {@code 'search'}, the parameters will parsed out
|
||||||
* of {@code url.search}; otherwise, out of {@code url.hash}.
|
* of {@code url.search}; otherwise, out of {@code url.hash}.
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
export default function parseURLParams(
|
export function parseURLParams(
|
||||||
url: URL,
|
url: URL,
|
||||||
dontParse: boolean = false,
|
dontParse: boolean = false,
|
||||||
source: string = 'hash'): Object {
|
source: string = 'hash'): Object {
|
|
@ -1,5 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
import { parseURLParams } from './parseURLParams';
|
||||||
import { normalizeNFKC } from './strings';
|
import { normalizeNFKC } from './strings';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -551,3 +552,24 @@ export function urlObjectToString(o: Object): ?string {
|
||||||
|
|
||||||
return url.toString() || undefined;
|
return url.toString() || undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds hash params to URL.
|
||||||
|
*
|
||||||
|
* @param {URL} url - The URL.
|
||||||
|
* @param {Object} hashParamsToAdd - A map with the parameters to be set.
|
||||||
|
* @returns {URL} - The new URL.
|
||||||
|
*/
|
||||||
|
export function addHashParamsToURL(url: URL, hashParamsToAdd: Object = {}) {
|
||||||
|
const params = parseURLParams(url);
|
||||||
|
const urlParamsArray = _objectToURLParamsArray({
|
||||||
|
...params,
|
||||||
|
...hashParamsToAdd
|
||||||
|
});
|
||||||
|
|
||||||
|
if (urlParamsArray.length) {
|
||||||
|
url.hash = `#${urlParamsArray.join('&')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
|
@ -6,8 +6,7 @@ import type { Dispatch } from 'redux';
|
||||||
|
|
||||||
import { createDeferred } from '../../../../modules/util/helpers';
|
import { createDeferred } from '../../../../modules/util/helpers';
|
||||||
|
|
||||||
import parseURLParams from '../../base/config/parseURLParams';
|
import { parseStandardURIString, parseURLParams } from '../../base/util';
|
||||||
import { parseStandardURIString } from '../../base/util';
|
|
||||||
import { getShareInfoText } from '../../invite';
|
import { getShareInfoText } from '../../invite';
|
||||||
|
|
||||||
import { setCalendarAPIAuthState } from '../actions';
|
import { setCalendarAPIAuthState } from '../actions';
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
import { Dropbox } from 'dropbox';
|
import { Dropbox } from 'dropbox';
|
||||||
|
|
||||||
import { parseURLParams } from '../base/config';
|
|
||||||
import {
|
import {
|
||||||
getJitsiMeetGlobalNS,
|
getJitsiMeetGlobalNS,
|
||||||
parseStandardURIString
|
parseStandardURIString,
|
||||||
|
parseURLParams
|
||||||
} from '../base/util';
|
} from '../base/util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,9 +2,9 @@ import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { I18nextProvider } from 'react-i18next';
|
import { I18nextProvider } from 'react-i18next';
|
||||||
|
|
||||||
import parseURLParams from '../../../base/config/parseURLParams';
|
|
||||||
import { i18next } from '../../../base/i18n';
|
import { i18next } from '../../../base/i18n';
|
||||||
import { isMobileBrowser } from '../../../base/environment/utils';
|
import { isMobileBrowser } from '../../../base/environment/utils';
|
||||||
|
import { parseURLParams } from '../../../base/util/parseURLParams';
|
||||||
import { DialInSummary } from '../dial-in-summary';
|
import { DialInSummary } from '../dial-in-summary';
|
||||||
|
|
||||||
import NoRoomError from './NoRoomError';
|
import NoRoomError from './NoRoomError';
|
||||||
|
|
|
@ -20,8 +20,8 @@ import {
|
||||||
setVideoInputDevice
|
setVideoInputDevice
|
||||||
} from '../../../../../modules/API/external/functions';
|
} from '../../../../../modules/API/external/functions';
|
||||||
|
|
||||||
import parseURLParams from '../../../base/config/parseURLParams';
|
|
||||||
import DialogWithTabs from '../../../base/dialog/components/web/DialogWithTabs';
|
import DialogWithTabs from '../../../base/dialog/components/web/DialogWithTabs';
|
||||||
|
import { parseURLParams } from '../../../base/util/parseURLParams';
|
||||||
import DeviceSelection from '../../../device-selection/components/DeviceSelection';
|
import DeviceSelection from '../../../device-selection/components/DeviceSelection';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue