snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
This commit is contained in:
7
react/features/base/lib-jitsi-meet/_.native.ts
Normal file
7
react/features/base/lib-jitsi-meet/_.native.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
// Re-export JitsiMeetJS from the library lib-jitsi-meet to (the other features
|
||||
// of) the project jitsi-meet.
|
||||
//
|
||||
|
||||
// @ts-ignore
|
||||
import JitsiMeetJS from 'lib-jitsi-meet';
|
||||
export { JitsiMeetJS as default };
|
||||
3
react/features/base/lib-jitsi-meet/_.web.ts
Normal file
3
react/features/base/lib-jitsi-meet/_.web.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
declare let JitsiMeetJS: any;
|
||||
|
||||
export default JitsiMeetJS;
|
||||
48
react/features/base/lib-jitsi-meet/actionTypes.ts
Normal file
48
react/features/base/lib-jitsi-meet/actionTypes.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* The type of Redux action which signals that {@link JitsiMeetJS} was disposed.
|
||||
*
|
||||
* {
|
||||
* type: LIB_DID_DISPOSE
|
||||
* }
|
||||
*/
|
||||
export const LIB_DID_DISPOSE = 'LIB_DID_DISPOSE';
|
||||
|
||||
/**
|
||||
* The type of Redux action which signals that {@link JitsiMeetJS.init()} was
|
||||
* invoked and completed successfully.
|
||||
*
|
||||
* {
|
||||
* type: LIB_DID_INIT
|
||||
* }
|
||||
*/
|
||||
export const LIB_DID_INIT = 'LIB_DID_INIT';
|
||||
|
||||
/**
|
||||
* Action to signal that lib-jitsi-meet initialized failed with error.
|
||||
*
|
||||
* {
|
||||
* type: LIB_INIT_ERROR,
|
||||
* error: Error
|
||||
* }
|
||||
*/
|
||||
export const LIB_INIT_ERROR = 'LIB_INIT_ERROR';
|
||||
|
||||
/**
|
||||
* The type of Redux action which signals that {@link JitsiMeetJS} will be
|
||||
* disposed.
|
||||
*
|
||||
* {
|
||||
* type: LIB_WILL_DISPOSE
|
||||
* }
|
||||
*/
|
||||
export const LIB_WILL_DISPOSE = 'LIB_WILL_DISPOSE';
|
||||
|
||||
/**
|
||||
* The type of Redux action which signals that {@link JitsiMeetJS.init()} will
|
||||
* be invoked.
|
||||
*
|
||||
* {
|
||||
* type: LIB_WILL_INIT
|
||||
* }
|
||||
*/
|
||||
export const LIB_WILL_INIT = 'LIB_WILL_INIT';
|
||||
83
react/features/base/lib-jitsi-meet/actions.ts
Normal file
83
react/features/base/lib-jitsi-meet/actions.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { jitsiLocalStorage } from '@jitsi/js-utils';
|
||||
|
||||
import { IStore } from '../../app/types';
|
||||
import { isOnline } from '../net-info/selectors';
|
||||
|
||||
import JitsiMeetJS from './_';
|
||||
import {
|
||||
LIB_DID_DISPOSE,
|
||||
LIB_DID_INIT,
|
||||
LIB_INIT_ERROR,
|
||||
LIB_WILL_DISPOSE,
|
||||
LIB_WILL_INIT
|
||||
} from './actionTypes';
|
||||
import { isAnalyticsEnabled } from './functions.any';
|
||||
import logger from './logger';
|
||||
|
||||
/**
|
||||
* Disposes (of) lib-jitsi-meet.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function disposeLib() {
|
||||
return (dispatch: IStore['dispatch']) => {
|
||||
dispatch({ type: LIB_WILL_DISPOSE });
|
||||
|
||||
// TODO Currently, lib-jitsi-meet doesn't have the functionality to
|
||||
// dispose itself.
|
||||
dispatch({ type: LIB_DID_DISPOSE });
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes lib-jitsi-meet (i.e. {@link invokes JitsiMeetJS.init()}) with the
|
||||
* current config(uration).
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function initLib() {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const state = getState();
|
||||
const config = state['features/base/config'];
|
||||
|
||||
if (!config) {
|
||||
throw new Error('Cannot init lib-jitsi-meet without config');
|
||||
}
|
||||
|
||||
dispatch({ type: LIB_WILL_INIT });
|
||||
|
||||
try {
|
||||
JitsiMeetJS.init({
|
||||
enableAnalyticsLogging: isAnalyticsEnabled(getState),
|
||||
...config,
|
||||
externalStorage: jitsiLocalStorage.isLocalStorageDisabled() ? jitsiLocalStorage : undefined
|
||||
});
|
||||
JitsiMeetJS.setNetworkInfo({
|
||||
isOnline: isOnline(state)
|
||||
});
|
||||
|
||||
logger.info(`lib-jitsi-meet version: ${JitsiMeetJS.version}`);
|
||||
logger.info(`User Agent: ${navigator.userAgent}`);
|
||||
|
||||
dispatch({ type: LIB_DID_INIT });
|
||||
} catch (error: any) {
|
||||
dispatch(libInitError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies about a specific error raised by {@link JitsiMeetJS.init()}.
|
||||
*
|
||||
* @param {Error} error - The Error raised by JitsiMeetJS.init().
|
||||
* @returns {{
|
||||
* type: LIB_INIT_ERROR,
|
||||
* error: Error
|
||||
* }}
|
||||
*/
|
||||
export function libInitError(error: Error) {
|
||||
return {
|
||||
type: LIB_INIT_ERROR,
|
||||
error
|
||||
};
|
||||
}
|
||||
99
react/features/base/lib-jitsi-meet/functions.any.ts
Normal file
99
react/features/base/lib-jitsi-meet/functions.any.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { IStateful } from '../app/types';
|
||||
import { ConnectionFailedError } from '../connection/types';
|
||||
import { toState } from '../redux/functions';
|
||||
|
||||
import JitsiMeetJS from './_';
|
||||
|
||||
|
||||
const JitsiConferenceErrors = JitsiMeetJS.errors.conference;
|
||||
const JitsiConnectionErrors = JitsiMeetJS.errors.connection;
|
||||
|
||||
/**
|
||||
* Creates a {@link JitsiLocalTrack} model from the given device id.
|
||||
*
|
||||
* @param {string} type - The media type of track being created. Expected values
|
||||
* are "video" or "audio".
|
||||
* @param {string} deviceId - The id of the target media source.
|
||||
* @param {number} [timeout] - A timeout for the JitsiMeetJS.createLocalTracks function call.
|
||||
* @param {Object} additionalOptions - Extra options to be passed to lib-jitsi-meet's {@code createLocalTracks}.
|
||||
*
|
||||
* @returns {Promise<JitsiLocalTrack>}
|
||||
*/
|
||||
export function createLocalTrack(type: string, deviceId: string | null, timeout?: number | null,
|
||||
additionalOptions?: Object) {
|
||||
return (
|
||||
JitsiMeetJS.createLocalTracks({
|
||||
cameraDeviceId: deviceId,
|
||||
devices: [ type ],
|
||||
micDeviceId: deviceId,
|
||||
timeout,
|
||||
...additionalOptions
|
||||
})
|
||||
.then(([ jitsiLocalTrack ]: any[]) => jitsiLocalTrack));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether analytics is enabled in a specific redux {@code store}.
|
||||
*
|
||||
* @param {IStateful} stateful - The redux store, state, or
|
||||
* {@code getState} function.
|
||||
* @returns {boolean} If analytics is enabled, {@code true}; {@code false},
|
||||
* otherwise.
|
||||
*/
|
||||
export function isAnalyticsEnabled(stateful: IStateful) {
|
||||
const { disableThirdPartyRequests, analytics = {} } = toState(stateful)['features/base/config'];
|
||||
|
||||
return !(disableThirdPartyRequests || analytics.disabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a specific {@link JitsiConferenceErrors} instance
|
||||
* indicates a fatal {@link JitsiConference} error.
|
||||
*
|
||||
* FIXME Figure out the category of errors defined by the function and describe
|
||||
* that category. I've currently named the category fatal because it appears to
|
||||
* be used in the cases of unrecoverable errors that necessitate a reload.
|
||||
*
|
||||
* @param {Error|string} error - The {@code JitsiConferenceErrors} instance to
|
||||
* categorize/classify or an {@link Error}-like object.
|
||||
* @returns {boolean} If the specified {@code JitsiConferenceErrors} instance
|
||||
* indicates a fatal {@code JitsiConference} error, {@code true}; otherwise,
|
||||
* {@code false}.
|
||||
*/
|
||||
export function isFatalJitsiConferenceError(error: Error | string) {
|
||||
if (typeof error !== 'string') {
|
||||
error = error.name; // eslint-disable-line no-param-reassign
|
||||
}
|
||||
|
||||
return (
|
||||
error === JitsiConferenceErrors.FOCUS_DISCONNECTED
|
||||
|| error === JitsiConferenceErrors.FOCUS_LEFT
|
||||
|| error === JitsiConferenceErrors.ICE_FAILED
|
||||
|| error === JitsiConferenceErrors.OFFER_ANSWER_FAILED
|
||||
|| error === JitsiConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a specific {@link JitsiConnectionErrors} instance
|
||||
* indicates a fatal {@link JitsiConnection} error.
|
||||
*
|
||||
* FIXME Figure out the category of errors defined by the function and describe
|
||||
* that category. I've currently named the category fatal because it appears to
|
||||
* be used in the cases of unrecoverable errors that necessitate a reload.
|
||||
*
|
||||
* @param {Error|string} error - The {@code JitsiConnectionErrors} instance to
|
||||
* categorize/classify or an {@link Error}-like object.
|
||||
* @returns {boolean} If the specified {@code JitsiConnectionErrors} instance
|
||||
* indicates a fatal {@code JitsiConnection} error, {@code true}; otherwise,
|
||||
* {@code false}.
|
||||
*/
|
||||
export function isFatalJitsiConnectionError(error: Error | string | ConnectionFailedError) {
|
||||
if (typeof error !== 'string') {
|
||||
error = error.name; // eslint-disable-line no-param-reassign
|
||||
}
|
||||
|
||||
return (
|
||||
error === JitsiConnectionErrors.CONNECTION_DROPPED_ERROR
|
||||
|| error === JitsiConnectionErrors.OTHER_ERROR
|
||||
|| error === JitsiConnectionErrors.SERVER_ERROR);
|
||||
}
|
||||
74
react/features/base/lib-jitsi-meet/functions.native.ts
Normal file
74
react/features/base/lib-jitsi-meet/functions.native.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { safeJsonParse } from '@jitsi/js-utils/json';
|
||||
// @ts-ignore
|
||||
import { Worklets } from 'react-native-worklets-core';
|
||||
|
||||
import { loadScript } from '../util/loadScript.native';
|
||||
|
||||
import logger from './logger';
|
||||
|
||||
export * from './functions.any';
|
||||
|
||||
|
||||
/**
|
||||
* Worklet context usefull for running small tasks off the JS thread.
|
||||
*/
|
||||
export const workletContext = Worklets.createContext('ConfigParser');
|
||||
|
||||
|
||||
/**
|
||||
* Loads config.js from a specific remote server.
|
||||
*
|
||||
* @param {string} url - The URL to load.
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export async function loadConfig(url: string): Promise<Object> {
|
||||
try {
|
||||
const configTxt = await loadScript(url, 10 * 1000, true);
|
||||
|
||||
const parseConfigAsync = workletContext.createRunAsync(function parseConfig(configText: string): string {
|
||||
'worklet';
|
||||
try {
|
||||
// Used IIFE wrapper to capture config object from config.js
|
||||
const configObj = eval(
|
||||
'(function(){\n'
|
||||
+ configText
|
||||
+ '\n; return (typeof config !== "undefined" ? config : globalThis.config); })()'
|
||||
);
|
||||
|
||||
if (configObj == void 0) {
|
||||
return 'Worklet_Error: config is undefined after eval()';
|
||||
}
|
||||
|
||||
if (typeof configObj !== 'object') {
|
||||
return 'Worklet_Error: config is not an object';
|
||||
}
|
||||
|
||||
return JSON.stringify(configObj);
|
||||
} catch (err) {
|
||||
return 'Worklet_Error:' + ((err as Error)?.message ?? String(err));
|
||||
}
|
||||
});
|
||||
|
||||
const workletConfig = await parseConfigAsync(configTxt);
|
||||
|
||||
if (typeof workletConfig !== 'string') {
|
||||
throw new Error('Worklet error: workletConfig is not a string');
|
||||
}
|
||||
|
||||
if (workletConfig.startsWith('Worklet_Error:')) {
|
||||
const msg = workletConfig.slice('Worklet_Error:'.length);
|
||||
|
||||
throw new Error(`Worklet error: ${msg}`);
|
||||
}
|
||||
|
||||
const config = safeJsonParse(workletConfig);
|
||||
|
||||
logger.info(`Config loaded from ${url}`);
|
||||
|
||||
return config;
|
||||
} catch (err) {
|
||||
logger.error(`Failed to load config from ${url}`, err);
|
||||
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
99
react/features/base/lib-jitsi-meet/functions.web.ts
Normal file
99
react/features/base/lib-jitsi-meet/functions.web.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { safeJsonParse } from '@jitsi/js-utils/json';
|
||||
|
||||
import { IConfig } from '../config/configType';
|
||||
|
||||
import logger from './logger';
|
||||
|
||||
export * from './functions.any';
|
||||
|
||||
const WORKER_SCRIPT = `
|
||||
self.onmessage = function(e) {
|
||||
const configText = e.data;
|
||||
try {
|
||||
const configObj = eval(
|
||||
'(function(){\\n'
|
||||
+ configText
|
||||
+ '\\n; return (typeof config !== "undefined" ? config : globalThis.config); })()'
|
||||
);
|
||||
|
||||
if (configObj == void 0) {
|
||||
self.postMessage({ error: 'config is undefined after eval()' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof configObj !== 'object') {
|
||||
self.postMessage({ error: 'config is not an object' });
|
||||
return;
|
||||
}
|
||||
|
||||
self.postMessage({ result: JSON.stringify(configObj) });
|
||||
} catch (err) {
|
||||
self.postMessage({ error: err?.message ?? String(err) });
|
||||
}
|
||||
};
|
||||
`;
|
||||
|
||||
/**
|
||||
* Parses config.js text content inside a Web Worker for isolation.
|
||||
*
|
||||
* @param {string} configText - The raw config.js source text.
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
function parseConfigInWorker(configText: string): Promise<Object> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const blob = new Blob([ WORKER_SCRIPT ]);
|
||||
// @ts-ignore -- URL.createObjectURL/revokeObjectURL not typed in this ts-loader context
|
||||
const workerUrl = URL.createObjectURL(blob);
|
||||
const worker = new Worker(workerUrl);
|
||||
|
||||
worker.onmessage = (e: MessageEvent) => {
|
||||
// @ts-ignore
|
||||
URL.revokeObjectURL(workerUrl);
|
||||
worker.terminate();
|
||||
|
||||
if (e.data.error) {
|
||||
reject(new Error(e.data.error));
|
||||
} else {
|
||||
resolve(safeJsonParse(e.data.result));
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = (err: ErrorEvent) => {
|
||||
// @ts-ignore
|
||||
URL.revokeObjectURL(workerUrl);
|
||||
worker.terminate();
|
||||
reject(new Error(err.message));
|
||||
};
|
||||
|
||||
worker.postMessage(configText);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads config.js from a specific URL.
|
||||
*
|
||||
* @param {string} [url] - The URL to load.
|
||||
* @returns {Promise<IConfig>}
|
||||
*/
|
||||
export async function loadConfig(url: string): Promise<IConfig> {
|
||||
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
|
||||
if (!response.ok) {
|
||||
return Promise.reject(
|
||||
new Error(`Failed to fetch config: ${response.status} ${response.statusText}`));
|
||||
}
|
||||
|
||||
const configText = await response.text();
|
||||
const config = await parseConfigInWorker(configText);
|
||||
|
||||
logger.info(`Config loaded from ${url}`);
|
||||
|
||||
return Promise.resolve(config);
|
||||
} catch (err) {
|
||||
logger.error(`Failed to load config from ${url}`, err);
|
||||
|
||||
return Promise.reject(err);
|
||||
}
|
||||
}
|
||||
26
react/features/base/lib-jitsi-meet/index.ts
Normal file
26
react/features/base/lib-jitsi-meet/index.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
// Re-export JitsiMeetJS from the library lib-jitsi-meet to (the other features
|
||||
// of) the project jitsi-meet.
|
||||
import JitsiMeetJS from './_';
|
||||
export { JitsiMeetJS as default };
|
||||
|
||||
// XXX Re-export the properties exported by JitsiMeetJS in order to prevent
|
||||
// undefined imported JitsiMeetJS. It may be caused by import cycles but I have
|
||||
// not confirmed the theory.
|
||||
export const analytics = JitsiMeetJS.analytics;
|
||||
export const browser = JitsiMeetJS.util.browser;
|
||||
export const JitsiAudioTranslationErrors = JitsiMeetJS.errors.audioTranslation;
|
||||
export const JitsiConferenceErrors = JitsiMeetJS.errors.conference;
|
||||
export const JitsiConferenceEvents = JitsiMeetJS.events.conference;
|
||||
export const JitsiConnectionErrors = JitsiMeetJS.errors.connection;
|
||||
export const JitsiConnectionEvents = JitsiMeetJS.events.connection;
|
||||
export const JitsiConnectionQualityEvents = JitsiMeetJS.events.connectionQuality;
|
||||
export const JitsiDetectionEvents = JitsiMeetJS.events.detection;
|
||||
export const JitsiE2ePingEvents = JitsiMeetJS.events.e2eping;
|
||||
export const JitsiIceRestartReason = JitsiMeetJS.constants.iceRestartReason;
|
||||
export const JitsiMediaDevicesEvents = JitsiMeetJS.events.mediaDevices;
|
||||
export const JitsiTrackStreamingStatus = JitsiMeetJS.constants.trackStreamingStatus;
|
||||
export const JitsiRecordingConstants = JitsiMeetJS.constants.recording;
|
||||
export const JitsiSIPVideoGWStatus = JitsiMeetJS.constants.sipVideoGW;
|
||||
export const JitsiTrackErrors = JitsiMeetJS.errors.track;
|
||||
export const JitsiTrackEvents = JitsiMeetJS.events.track;
|
||||
export const RTCStatsEvents = JitsiMeetJS.events.rtcstats;
|
||||
3
react/features/base/lib-jitsi-meet/logger.ts
Normal file
3
react/features/base/lib-jitsi-meet/logger.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { getLogger } from '../logging/functions';
|
||||
|
||||
export default getLogger('app:lib-jitsi-meet');
|
||||
74
react/features/base/lib-jitsi-meet/middleware.ts
Normal file
74
react/features/base/lib-jitsi-meet/middleware.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { AnyAction } from 'redux';
|
||||
|
||||
import { IStore } from '../../app/types';
|
||||
import { SET_CONFIG } from '../config/actionTypes';
|
||||
import { SET_NETWORK_INFO } from '../net-info/actionTypes';
|
||||
import { PARTICIPANT_LEFT } from '../participants/actionTypes';
|
||||
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
|
||||
import JitsiMeetJS from './_';
|
||||
import { disposeLib, initLib } from './actions';
|
||||
|
||||
/**
|
||||
* Middleware that captures PARTICIPANT_LEFT action for a local participant
|
||||
* (which signalizes that we finally left the app) and disposes lib-jitsi-meet.
|
||||
* Also captures SET_CONFIG action and disposes previous instance (if any) of
|
||||
* lib-jitsi-meet, and initializes a new one with new config.
|
||||
*
|
||||
* @param {Store} store - Redux store.
|
||||
* @private
|
||||
* @returns {Function}
|
||||
*/
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
switch (action.type) {
|
||||
case SET_NETWORK_INFO:
|
||||
JitsiMeetJS.setNetworkInfo({
|
||||
isOnline: action.isOnline
|
||||
});
|
||||
break;
|
||||
|
||||
case PARTICIPANT_LEFT:
|
||||
action.participant.local && store.dispatch(disposeLib());
|
||||
break;
|
||||
|
||||
case SET_CONFIG:
|
||||
return _setConfig(store, next, action);
|
||||
}
|
||||
|
||||
return next(action);
|
||||
});
|
||||
|
||||
/**
|
||||
* Notifies the feature base/lib-jitsi-meet that the action SET_CONFIG is being
|
||||
* dispatched within a specific Redux store.
|
||||
*
|
||||
* @param {Store} store - The Redux store in which the specified action is being
|
||||
* dispatched.
|
||||
* @param {Dispatch} next - The Redux dispatch function to dispatch the
|
||||
* specified action to the specified store.
|
||||
* @param {Action} action - The Redux action SET_CONFIG which is being
|
||||
* dispatched in the specified store.
|
||||
* @private
|
||||
* @returns {Object} The new state that is the result of the reduction of the
|
||||
* specified action.
|
||||
*/
|
||||
function _setConfig({ dispatch, getState }: IStore, next: Function, action: AnyAction) {
|
||||
const { initialized } = getState()['features/base/lib-jitsi-meet'];
|
||||
|
||||
// XXX Since the config is changing, the library lib-jitsi-meet must be
|
||||
// initialized again with the new config. Consequently, it may need to be
|
||||
// disposed of first.
|
||||
// TODO Currently, disposeLib actually does not dispose of lib-jitsi-meet
|
||||
// because lib-jitsi-meet does not implement such functionality.
|
||||
if (initialized) {
|
||||
dispatch(disposeLib());
|
||||
}
|
||||
|
||||
// Let the new config into the Redux store (because initLib will read it
|
||||
// from there).
|
||||
const result = next(action);
|
||||
|
||||
dispatch(initLib());
|
||||
|
||||
return result;
|
||||
}
|
||||
45
react/features/base/lib-jitsi-meet/reducer.ts
Normal file
45
react/features/base/lib-jitsi-meet/reducer.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import ReducerRegistry from '../redux/ReducerRegistry';
|
||||
|
||||
import {
|
||||
LIB_DID_DISPOSE,
|
||||
LIB_DID_INIT,
|
||||
LIB_INIT_ERROR
|
||||
} from './actionTypes';
|
||||
|
||||
/**
|
||||
* The default/initial redux state of the feature base/lib-jitsi-meet.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const DEFAULT_STATE = {};
|
||||
|
||||
export interface ILibJitsiMeetState {
|
||||
initError?: Error;
|
||||
initialized?: boolean;
|
||||
}
|
||||
|
||||
ReducerRegistry.register<ILibJitsiMeetState>(
|
||||
'features/base/lib-jitsi-meet',
|
||||
(state = DEFAULT_STATE, action): ILibJitsiMeetState => {
|
||||
switch (action.type) {
|
||||
case LIB_DID_DISPOSE:
|
||||
return DEFAULT_STATE;
|
||||
|
||||
case LIB_DID_INIT:
|
||||
return {
|
||||
...state,
|
||||
initError: undefined,
|
||||
initialized: true
|
||||
};
|
||||
|
||||
case LIB_INIT_ERROR:
|
||||
return {
|
||||
...state,
|
||||
initError: action.error,
|
||||
initialized: false
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user