ref(modules/UI): remove events system.

Many of the events are not used at all or used only on one place. For the rest of them the listeners were added 2 times on promoted visitors and not cleaned at all.
This commit is contained in:
Hristo Terezov
2024-04-16 17:10:36 -05:00
parent d8b0710a19
commit 9bb27b83d9
16 changed files with 153 additions and 298 deletions

View File

@@ -2,7 +2,6 @@
import { jitsiLocalStorage } from '@jitsi/js-utils';
import Logger from '@jitsi/logger';
import EventEmitter from 'events';
import { ENDPOINT_TEXT_MESSAGE_NAME } from './modules/API/constants';
import { AUDIO_ONLY_SCREEN_SHARE_NO_TRACK } from './modules/UI/UIErrors';
@@ -165,12 +164,9 @@ import { AudioMixerEffect } from './react/features/stream-effects/audio-mixer/Au
import { createRnnoiseProcessor } from './react/features/stream-effects/rnnoise';
import { handleToggleVideoMuted } from './react/features/toolbox/actions.any';
import { muteLocal } from './react/features/video-menu/actions.any';
import UIEvents from './service/UI/UIEvents';
const logger = Logger.getLogger(__filename);
const eventEmitter = new EventEmitter();
let room;
/*
@@ -1916,21 +1912,12 @@ export default {
JitsiE2ePingEvents.E2E_RTT_CHANGED,
(...args) => APP.store.dispatch(e2eRttChanged(...args)));
APP.UI.addListener(UIEvents.AUDIO_MUTED, muted => {
this.muteAudio(muted);
});
APP.UI.addListener(UIEvents.VIDEO_MUTED, (muted, showUI = false) => {
this.muteVideo(muted, showUI);
});
room.addCommandListener(this.commands.defaults.ETHERPAD,
({ value }) => {
APP.UI.initEtherpad(value);
}
);
APP.UI.addListener(UIEvents.EMAIL_CHANGED,
this.changeLocalEmail.bind(this));
room.addCommandListener(this.commands.defaults.EMAIL, (data, from) => {
APP.store.dispatch(participantUpdated({
conference: room,
@@ -1950,9 +1937,6 @@ export default {
}));
});
APP.UI.addListener(UIEvents.NICKNAME_CHANGED,
this.changeLocalDisplayName.bind(this));
room.on(
JitsiConferenceEvents.START_MUTED_POLICY_CHANGED,
({ audio, video }) => {
@@ -2007,115 +1991,119 @@ export default {
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
}
);
},
// call hangup
APP.UI.addListener(UIEvents.HANGUP, () => {
this.hangup(true);
/**
* Handles audio device changes.
*
* @param {string} cameraDeviceId - The new device id.
* @returns {Promise}
*/
async onAudioDeviceChanged(micDeviceId) {
const audioWasMuted = this.isLocalAudioMuted();
// Disable noise suppression if it was enabled on the previous track.
await APP.store.dispatch(setNoiseSuppressionEnabled(false));
// When the 'default' mic needs to be selected, we need to pass the real device id to gUM instead of
// 'default' in order to get the correct MediaStreamTrack from chrome because of the following bug.
// https://bugs.chromium.org/p/chromium/issues/detail?id=997689.
const isDefaultMicSelected = micDeviceId === 'default';
const selectedDeviceId = isDefaultMicSelected
? getDefaultDeviceId(APP.store.getState(), 'audioInput')
: micDeviceId;
logger.info(`Switching audio input device to ${selectedDeviceId}`);
sendAnalytics(createDeviceChangedEvent('audio', 'input'));
createLocalTracksF({
devices: [ 'audio' ],
micDeviceId: selectedDeviceId
})
.then(([ stream ]) => {
// if audio was muted before changing the device, mute
// with the new device
if (audioWasMuted) {
return stream.mute()
.then(() => stream);
}
return stream;
})
.then(async stream => {
await this._maybeApplyAudioMixerEffect(stream);
return this.useAudioStream(stream);
})
.then(() => {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
if (localAudio && isDefaultMicSelected) {
// workaround for the default device to be shown as selected in the
// settings even when the real device id was passed to gUM because of the
// above mentioned chrome bug.
localAudio._realDeviceId = localAudio.deviceId = 'default';
}
})
.catch(err => {
logger.error(`Failed to switch to selected audio input device ${selectedDeviceId}, error=${err}`);
APP.store.dispatch(notifyMicError(err));
});
},
APP.UI.addListener(
UIEvents.VIDEO_DEVICE_CHANGED,
cameraDeviceId => {
const videoWasMuted = this.isLocalVideoMuted();
const localVideoTrack = getLocalJitsiVideoTrack(APP.store.getState());
/**
* Handles video device changes.
*
* @param {string} cameraDeviceId - The new device id.
* @returns {void}
*/
onVideoDeviceChanged(cameraDeviceId) {
const videoWasMuted = this.isLocalVideoMuted();
const localVideoTrack = getLocalJitsiVideoTrack(APP.store.getState());
if (localVideoTrack?.getDeviceId() === cameraDeviceId) {
return;
}
if (localVideoTrack?.getDeviceId() === cameraDeviceId) {
return;
}
sendAnalytics(createDeviceChangedEvent('video', 'input'));
sendAnalytics(createDeviceChangedEvent('video', 'input'));
createLocalTracksF({
devices: [ 'video' ],
cameraDeviceId
})
.then(([ stream ]) => {
// if we are in audio only mode or video was muted before
// changing device, then mute
if (this.isAudioOnly() || videoWasMuted) {
return stream.mute()
.then(() => stream);
}
return stream;
})
.then(stream => {
logger.info(`Switching the local video device to ${cameraDeviceId}.`);
return this.useVideoStream(stream);
})
.catch(error => {
logger.error(`Failed to switch to selected camera:${cameraDeviceId}, error:${error}`);
return APP.store.dispatch(notifyCameraError(error));
});
createLocalTracksF({
devices: [ 'video' ],
cameraDeviceId
})
.then(([ stream ]) => {
// if we are in audio only mode or video was muted before
// changing device, then mute
if (this.isAudioOnly() || videoWasMuted) {
return stream.mute()
.then(() => stream);
}
);
APP.UI.addListener(
UIEvents.AUDIO_DEVICE_CHANGED,
async micDeviceId => {
const audioWasMuted = this.isLocalAudioMuted();
return stream;
})
.then(stream => {
logger.info(`Switching the local video device to ${cameraDeviceId}.`);
// Disable noise suppression if it was enabled on the previous track.
await APP.store.dispatch(setNoiseSuppressionEnabled(false));
return this.useVideoStream(stream);
})
.catch(error => {
logger.error(`Failed to switch to selected camera:${cameraDeviceId}, error:${error}`);
// When the 'default' mic needs to be selected, we need to pass the real device id to gUM instead of
// 'default' in order to get the correct MediaStreamTrack from chrome because of the following bug.
// https://bugs.chromium.org/p/chromium/issues/detail?id=997689.
const isDefaultMicSelected = micDeviceId === 'default';
const selectedDeviceId = isDefaultMicSelected
? getDefaultDeviceId(APP.store.getState(), 'audioInput')
: micDeviceId;
logger.info(`Switching audio input device to ${selectedDeviceId}`);
sendAnalytics(createDeviceChangedEvent('audio', 'input'));
createLocalTracksF({
devices: [ 'audio' ],
micDeviceId: selectedDeviceId
})
.then(([ stream ]) => {
// if audio was muted before changing the device, mute
// with the new device
if (audioWasMuted) {
return stream.mute()
.then(() => stream);
}
return stream;
})
.then(async stream => {
await this._maybeApplyAudioMixerEffect(stream);
return this.useAudioStream(stream);
})
.then(() => {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
if (localAudio && isDefaultMicSelected) {
// workaround for the default device to be shown as selected in the
// settings even when the real device id was passed to gUM because of the
// above mentioned chrome bug.
localAudio._realDeviceId = localAudio.deviceId = 'default';
}
})
.catch(err => {
logger.error(`Failed to switch to selected audio input device ${selectedDeviceId}, error=${err}`);
APP.store.dispatch(notifyMicError(err));
});
}
);
APP.UI.addListener(UIEvents.TOGGLE_AUDIO_ONLY, () => {
// Immediately update the UI by having remote videos and the large video update themselves.
const displayedUserId = APP.UI.getLargeVideoID();
if (displayedUserId) {
APP.UI.updateLargeVideo(displayedUserId, true);
}
return APP.store.dispatch(notifyCameraError(error));
});
},
/**
* Handles audio only changes.
*/
onToggleAudioOnly() {
// Immediately update the UI by having remote videos and the large video update themselves.
const displayedUserId = APP.UI.getLargeVideoID();
if (displayedUserId) {
APP.UI.updateLargeVideo(displayedUserId, true);
}
},
/**
* Cleanups local conference on suspend.
*/
@@ -2408,8 +2396,6 @@ export default {
this.deviceChangeListener);
}
APP.UI.removeAllListeners();
let feedbackResultPromise = Promise.resolve({});
if (requestFeedback) {
@@ -2516,37 +2502,6 @@ export default {
room.sendEndpointMessage(to, payload);
},
/**
* Adds new listener.
* @param {String} eventName the name of the event
* @param {Function} listener the listener.
*/
addListener(eventName, listener) {
eventEmitter.addListener(eventName, listener);
},
/**
* Removes listener.
* @param {String} eventName the name of the event that triggers the
* listener
* @param {Function} listener the listener.
*/
removeListener(eventName, listener) {
eventEmitter.removeListener(eventName, listener);
},
/**
* Changes the display name for the local user
* @param nickname {string} the new display name
*/
changeLocalDisplayName(nickname = '') {
const formattedNickname = getNormalizedDisplayName(nickname);
APP.store.dispatch(updateSettings({
displayName: formattedNickname
}));
},
/**
* Callback invoked by the external api create or update a direct connection
* from the local client to an external client.

View File

@@ -76,6 +76,7 @@ import { setMediaEncryptionKey, toggleE2EE } from '../../react/features/e2ee/act
import {
addStageParticipant,
resizeFilmStrip,
setFilmstripVisible,
setVolume,
togglePinStageParticipant
} from '../../react/features/filmstrip/actions.web';
@@ -104,6 +105,7 @@ import { startAudioScreenShareFlow, startScreenShareFlow } from '../../react/fea
import { isScreenAudioSupported } from '../../react/features/screen-share/functions';
import { toggleScreenshotCaptureSummary } from '../../react/features/screenshot-capture/actions';
import { isScreenshotCaptureEnabled } from '../../react/features/screenshot-capture/functions';
import { changeLocalDisplayName } from '../../react/features/settings/actions.web';
import SettingsDialog from '../../react/features/settings/components/web/SettingsDialog';
import { SETTINGS_TABS } from '../../react/features/settings/constants';
import { playSharedVideo, stopSharedVideo } from '../../react/features/shared-video/actions.any';
@@ -199,7 +201,7 @@ function initCommands() {
},
'display-name': displayName => {
sendAnalytics(createApiEvent('display.name.changed'));
APP.conference.changeLocalDisplayName(displayName);
APP.store.dispatch(changeLocalDisplayName(displayName));
},
'local-subject': localSubject => {
sendAnalytics(createApiEvent('local.subject.changed'));
@@ -376,7 +378,9 @@ function initCommands() {
},
'toggle-film-strip': () => {
sendAnalytics(createApiEvent('film.strip.toggled'));
APP.UI.toggleFilmstrip();
const { visible } = APP.store.getState()['features/filmstrip'];
APP.store.dispatch(setFilmstripVisible(!visible));
},
/*

View File

@@ -4,7 +4,6 @@
const UI = {};
import Logger from '@jitsi/logger';
import EventEmitter from 'events';
import {
conferenceWillInit
@@ -13,7 +12,6 @@ import { isMobileBrowser } from '../../react/features/base/environment/utils';
import { setColorAlpha } from '../../react/features/base/util/helpers';
import { sanitizeUrl } from '../../react/features/base/util/uri';
import { setDocumentUrl } from '../../react/features/etherpad/actions';
import { setFilmstripVisible } from '../../react/features/filmstrip/actions.any';
import {
setNotificationsEnabled,
showNotification
@@ -25,7 +23,6 @@ import {
setToolboxEnabled,
showToolbox
} from '../../react/features/toolbox/actions.web';
import UIEvents from '../../service/UI/UIEvents';
import EtherpadManager from './etherpad/Etherpad';
import UIUtil from './util/UIUtil';
@@ -33,22 +30,8 @@ import VideoLayout from './videolayout/VideoLayout';
const logger = Logger.getLogger(__filename);
const eventEmitter = new EventEmitter();
UI.eventEmitter = eventEmitter;
let etherpadManager;
const UIListeners = new Map([
[
UIEvents.ETHERPAD_CLICKED,
() => etherpadManager && etherpadManager.toggleEtherpad()
], [
UIEvents.TOGGLE_FILMSTRIP,
() => UI.toggleFilmstrip()
]
]);
/**
* Indicates if we're currently in full screen mode.
*
@@ -96,10 +79,11 @@ UI.start = function() {
};
/**
* Setup some UI event listeners.
* Handles etherpad click.
*/
UI.registerListeners
= () => UIListeners.forEach((value, key) => UI.addListener(key, value));
UI.onEtherpadClicked = function() {
etherpadManager && etherpadManager.toggleEtherpad();
};
/**
*
@@ -143,7 +127,7 @@ UI.initEtherpad = name => {
}
logger.log('Etherpad is enabled');
etherpadManager = new EtherpadManager(eventEmitter);
etherpadManager = new EtherpadManager();
const url = new URL(name, etherpadBaseUrl);
@@ -197,15 +181,6 @@ UI.updateUserStatus = (user, status) => {
}, NOTIFICATION_TIMEOUT_TYPE.SHORT));
};
/**
* Toggles filmstrip.
*/
UI.toggleFilmstrip = function() {
const { visible } = APP.store.getState()['features/filmstrip'];
APP.store.dispatch(setFilmstripVisible(!visible));
};
/**
* Sets muted video state for participant
*/
@@ -219,33 +194,6 @@ UI.setVideoMuted = function(id) {
UI.updateLargeVideo = (id, forceUpdate) => VideoLayout.updateLargeVideo(id, forceUpdate);
/**
* Adds a listener that would be notified on the given type of event.
*
* @param type the type of the event we're listening for
* @param listener a function that would be called when notified
*/
UI.addListener = function(type, listener) {
eventEmitter.on(type, listener);
};
/**
* Removes the all listeners for all events.
*
* @returns {void}
*/
UI.removeAllListeners = function() {
eventEmitter.removeAllListeners();
};
/**
* Emits the event of given type by specifying the parameters in options.
*
* @param type the type of the event we're emitting
* @param options the parameters for the event
*/
UI.emitEvent = (type, ...options) => eventEmitter.emit(type, ...options);
// Used by torture.
UI.showToolbar = timeout => APP.store.dispatch(showToolbox(timeout));

View File

@@ -138,8 +138,7 @@ export default class EtherpadManager {
/**
*
*/
constructor(eventEmitter) {
this.eventEmitter = eventEmitter;
constructor() {
this.etherpad = null;
}

View File

@@ -1,5 +1,3 @@
// @ts-expect-error
import UIEvents from '../../../../service/UI/UIEvents';
import { createAudioOnlyChangedEvent } from '../../analytics/AnalyticsEvents';
import { sendAnalytics } from '../../analytics/functions';
import { IStore } from '../../app/types';
@@ -33,7 +31,7 @@ export function setAudioOnly(audioOnly: boolean) {
if (typeof APP !== 'undefined') {
// TODO This should be a temporary solution that lasts only until video
// tracks and all ui is moved into react/redux on the web.
APP.UI.emitEvent(UIEvents.TOGGLE_AUDIO_ONLY, audioOnly);
APP.conference.onToggleAudioOnly();
}
}
};

View File

@@ -1,5 +1,3 @@
// @ts-expect-error
import UIEvents from '../../../../service/UI/UIEvents';
import { createStartMutedConfigurationEvent } from '../../analytics/AnalyticsEvents';
import { sendAnalytics } from '../../analytics/functions';
import { IReduxState, IStore } from '../../app/types';
@@ -1083,7 +1081,7 @@ export function redirect(vnode: string, focusJid: string, username: string) {
dispatch(setAudioMuted(false, true));
// // FIXME: The old conference logic still relies on this event being emitted.
typeof APP === 'undefined' || APP.UI.emitEvent(UIEvents.AUDIO_MUTED, false);
typeof APP === 'undefined' || APP.conference.muteAudio(false);
}
}
@@ -1096,7 +1094,7 @@ export function redirect(vnode: string, focusJid: string, username: string) {
dispatch(setVideoMuted(false, VIDEO_MUTISM_AUTHORITY.USER, true));
// // FIXME: The old conference logic still relies on this event being emitted.
typeof APP === 'undefined' || APP.UI.emitEvent(UIEvents.VIDEO_MUTED, false);
typeof APP === 'undefined' || APP.conference.muteVideo(false, false);
}
}
}

View File

@@ -1,7 +1,5 @@
import { AnyAction } from 'redux';
// @ts-expect-error
import UIEvents from '../../../../service/UI/UIEvents';
import { IStore } from '../../app/types';
import { processExternalDeviceRequest } from '../../device-selection/functions';
import { showNotification, showWarningNotification } from '../../notifications/actions';
@@ -161,7 +159,7 @@ MiddlewareRegistry.register(store => next => action => {
if (isPrejoinPageVisible(store.getState())) {
store.dispatch(replaceAudioTrackById(action.deviceId));
} else {
APP.UI.emitEvent(UIEvents.AUDIO_DEVICE_CHANGED, action.deviceId);
APP.conference.onAudioDeviceChanged(action.deviceId);
}
break;
case SET_VIDEO_INPUT_DEVICE: {
@@ -174,7 +172,7 @@ MiddlewareRegistry.register(store => next => action => {
if (isPrejoinPageVisible(store.getState())) {
store.dispatch(replaceVideoTrackById(action.deviceId));
} else {
APP.UI.emitEvent(UIEvents.VIDEO_DEVICE_CHANGED, action.deviceId);
APP.conference.onVideoDeviceChanged(action.deviceId);
}
break;
}

View File

@@ -2,8 +2,6 @@ import i18n from 'i18next';
import { batch } from 'react-redux';
import { AnyAction } from 'redux';
// @ts-expect-error
import UIEvents from '../../../../service/UI/UIEvents';
import { IStore } from '../../app/types';
import { approveParticipant } from '../../av-moderation/actions';
import { UPDATE_BREAKOUT_ROOMS } from '../../breakout-rooms/actionTypes';
@@ -20,6 +18,7 @@ import { isForceMuted } from '../../participants-pane/functions';
import { CALLING, INVITED } from '../../presence-status/constants';
import { RAISE_HAND_SOUND_ID } from '../../reactions/constants';
import { RECORDING_OFF_SOUND_ID, RECORDING_ON_SOUND_ID } from '../../recording/constants';
import { changeLocalDisplayName } from '../../settings/actions';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app/actionTypes';
import { CONFERENCE_WILL_JOIN } from '../conference/actionTypes';
import { forEachConference, getCurrentConference } from '../conference/functions';
@@ -241,7 +240,7 @@ MiddlewareRegistry.register(store => next => action => {
const participant = getLocalParticipant(store.getState());
if (participant && participant.id === action.id) {
APP.UI.emitEvent(UIEvents.NICKNAME_CHANGED, action.name);
store.dispatch(changeLocalDisplayName(action.name));
}
}

View File

@@ -368,8 +368,6 @@ class Conference extends AbstractConference<IProps, any> {
*/
_start() {
APP.UI.start();
APP.UI.registerListeners();
APP.UI.bindEvents();
FULL_SCREEN_EVENTS.forEach(name =>

View File

@@ -1,5 +1,3 @@
// @ts-expect-error
import UIEvents from '../../../service/UI/UIEvents';
import { CONFERENCE_JOIN_IN_PROGRESS } from '../base/conference/actionTypes';
import { getCurrentConference } from '../base/conference/functions';
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
@@ -41,7 +39,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
}
case TOGGLE_DOCUMENT_EDITING: {
if (typeof APP !== 'undefined') {
APP.UI.emitEvent(UIEvents.ETHERPAD_CLICKED);
APP.UI.onEtherpadClicked();
}
break;
}

View File

@@ -1,7 +1,5 @@
import { AnyAction } from 'redux';
// @ts-expect-error
import UIEvents from '../../../service/UI/UIEvents';
import { IStore } from '../app/types';
import {
CONFERENCE_FAILED,
@@ -36,12 +34,6 @@ MiddlewareRegistry.register(store => next => action => {
return _conferenceJoined(store, next, action);
case LOCK_STATE_CHANGED: {
// TODO Remove this logic when all components interested in the lock
// state change event are moved into react/redux.
if (typeof APP !== 'undefined') {
APP.UI.emitEvent(UIEvents.TOGGLE_ROOM_LOCK, action.locked);
}
const previousLockedState = store.getState()['features/base/conference'].locked;
const result = next(action);

View File

@@ -36,3 +36,16 @@ export function openLogoutDialog() {
}));
};
}
/**
* Changes the display name for the local user.
*
* @param {string} _nickname - The new display name.
* @returns {Function}
*/
export function changeLocalDisplayName(_nickname = '') {
// not used on mobile.
return (_dispatch: IStore['dispatch'], _getState: IStore['getState']) => {
// no-op action.
};
}

View File

@@ -12,6 +12,7 @@ import { hangup } from '../base/connection/actions.web';
import { openDialog } from '../base/dialog/actions';
import i18next from '../base/i18n/i18next';
import { browser } from '../base/lib-jitsi-meet';
import { getNormalizedDisplayName } from '../base/participants/functions';
import { updateSettings } from '../base/settings/actions';
import { getLocalVideoTrack } from '../base/tracks/functions.web';
import { appendURLHashParam } from '../base/util/uri';
@@ -191,7 +192,7 @@ export function submitProfileTab(newState: any) {
const currentState = getProfileTabProps(getState());
if (newState.displayName !== currentState.displayName) {
APP.conference.changeLocalDisplayName(newState.displayName);
dispatch(changeLocalDisplayName(newState.displayName));
}
if (newState.email !== currentState.email) {
@@ -200,6 +201,20 @@ export function submitProfileTab(newState: any) {
};
}
/**
* Changes the display name for the local user.
*
* @param {string} nickname - The new display name.
* @returns {Function}
*/
export function changeLocalDisplayName(nickname = '') {
return (dispatch: IStore['dispatch']) => {
const formattedNickname = getNormalizedDisplayName(nickname);
dispatch(updateSettings({ displayName: formattedNickname }));
};
}
/**
* Submits the settings from the "Sounds" tab of the settings dialog.
*

View File

@@ -1,5 +1,3 @@
// @ts-expect-error
import UIEvents from '../../../service/UI/UIEvents';
import { VIDEO_MUTE, createToolbarEvent } from '../analytics/AnalyticsEvents';
import { sendAnalytics } from '../analytics/functions';
import { IStore } from '../app/types';
@@ -103,7 +101,7 @@ export function handleToggleVideoMuted(muted: boolean, showUI: boolean, ensureTr
// FIXME: The old conference logic still relies on this event being
// emitted.
typeof APP === 'undefined'
|| APP.UI.emitEvent(UIEvents.VIDEO_MUTED, muted, showUI);
|| APP.conference.muteVideo(muted, showUI);
};
}

View File

@@ -1,5 +1,3 @@
// @ts-expect-error
import UIEvents from '../../../service/UI/UIEvents';
import {
AUDIO_MUTE,
VIDEO_MUTE,
@@ -55,8 +53,9 @@ export function muteLocal(enable: boolean, mediaType: MediaType, stopScreenShari
: setVideoMuted(enable, VIDEO_MUTISM_AUTHORITY.USER, /* ensureTrack */ true));
// FIXME: The old conference logic still relies on this event being emitted.
typeof APP === 'undefined'
|| APP.UI.emitEvent(isAudio ? UIEvents.AUDIO_MUTED : UIEvents.VIDEO_MUTED, enable);
if (typeof APP !== 'undefined') {
isAudio ? APP.conference.muteAudio(enable) : APP.conference.muteVideo(enable, false);
}
};
}

View File

@@ -1,57 +0,0 @@
export default {
NICKNAME_CHANGED: 'UI.nickname_changed',
/**
* Notifies that local user changed email.
*/
EMAIL_CHANGED: 'UI.email_changed',
/**
* Notifies that "start muted" settings changed.
*/
AUDIO_MUTED: 'UI.audio_muted',
VIDEO_MUTED: 'UI.video_muted',
ETHERPAD_CLICKED: 'UI.etherpad_clicked',
/**
* Updates shared video with params: url, state, time(optional)
* Where url is the video link, state is stop/start/pause and time is the
* current video playing time.
*/
TOGGLE_FULLSCREEN: 'UI.toogle_fullscreen',
FULLSCREEN_TOGGLED: 'UI.fullscreen_toggled',
/**
* Notifies that the audio only mode was toggled.
*/
TOGGLE_AUDIO_ONLY: 'UI.toggle_audioonly',
/**
* Notifies that a command to toggle the filmstrip has been issued. The
* event may optionally specify a {Boolean} (primitive) value to assign to
* the visibility of the filmstrip (i.e. the event may act as a setter).
* The very toggling of the filmstrip may or may not occurred at the time
* of the receipt of the event depending on the position of the receiving
* event listener in relation to the event listener which carries out the
* command to toggle the filmstrip.
*
* @see {TOGGLED_FILMSTRIP}
*/
TOGGLE_FILMSTRIP: 'UI.toggle_filmstrip',
HANGUP: 'UI.hangup',
VIDEO_DEVICE_CHANGED: 'UI.video_device_changed',
AUDIO_DEVICE_CHANGED: 'UI.audio_device_changed',
/**
* Notifies that the side toolbar container has been toggled. The actual
* event must contain the identifier of the container that has been toggled
* and information about toggle on or off.
*/
SIDE_TOOLBAR_CONTAINER_TOGGLED: 'UI.side_container_toggled',
/**
* Notifies that the raise hand has been changed.
*/
LOCAL_RAISE_HAND_CHANGED: 'UI.local_raise_hand_changed'
};