| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 | 
							- // @flow
 - 
 - import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app';
 - import {
 -     CONFERENCE_WILL_JOIN,
 -     forEachConference,
 -     getCurrentConference
 - } from '../conference';
 - import { CALLING, INVITED } from '../../presence-status';
 - import { MiddlewareRegistry, StateListenerRegistry } from '../redux';
 - import UIEvents from '../../../../service/UI/UIEvents';
 - import { playSound, registerSound, unregisterSound } from '../sounds';
 - 
 - import {
 -     localParticipantIdChanged,
 -     localParticipantJoined,
 -     localParticipantLeft,
 -     participantLeft,
 -     participantUpdated
 - } from './actions';
 - import {
 -     DOMINANT_SPEAKER_CHANGED,
 -     KICK_PARTICIPANT,
 -     MUTE_REMOTE_PARTICIPANT,
 -     PARTICIPANT_DISPLAY_NAME_CHANGED,
 -     PARTICIPANT_JOINED,
 -     PARTICIPANT_LEFT,
 -     PARTICIPANT_UPDATED
 - } from './actionTypes';
 - import {
 -     LOCAL_PARTICIPANT_DEFAULT_ID,
 -     PARTICIPANT_JOINED_SOUND_ID,
 -     PARTICIPANT_LEFT_SOUND_ID
 - } from './constants';
 - import {
 -     getAvatarURLByParticipantId,
 -     getLocalParticipant,
 -     getParticipantById,
 -     getParticipantCount
 - } from './functions';
 - import { PARTICIPANT_JOINED_FILE, PARTICIPANT_LEFT_FILE } from './sounds';
 - 
 - declare var APP: Object;
 - 
 - /**
 -  * Middleware that captures CONFERENCE_JOINED and CONFERENCE_LEFT actions and
 -  * updates respectively ID of local participant.
 -  *
 -  * @param {Store} store - The redux store.
 -  * @returns {Function}
 -  */
 - MiddlewareRegistry.register(store => next => action => {
 -     switch (action.type) {
 -     case APP_WILL_MOUNT:
 -         _registerSounds(store);
 - 
 -         return _localParticipantJoined(store, next, action);
 - 
 -     case APP_WILL_UNMOUNT:
 -         _unregisterSounds(store);
 - 
 -         return _localParticipantLeft(store, next, action);
 - 
 -     case CONFERENCE_WILL_JOIN:
 -         store.dispatch(localParticipantIdChanged(action.conference.myUserId()));
 -         break;
 - 
 -     case DOMINANT_SPEAKER_CHANGED: {
 -         // Ensure the raised hand state is cleared for the dominant speaker.
 - 
 -         const { conference, id } = action.participant;
 -         const participant = getLocalParticipant(store.getState());
 - 
 -         participant
 -             && store.dispatch(participantUpdated({
 -                 conference,
 -                 id,
 -                 local: participant.id === id,
 -                 raisedHand: false
 -             }));
 - 
 -         break;
 -     }
 - 
 -     case KICK_PARTICIPANT: {
 -         const { conference } = store.getState()['features/base/conference'];
 - 
 -         conference.kickParticipant(action.id);
 -         break;
 -     }
 - 
 -     case MUTE_REMOTE_PARTICIPANT: {
 -         const { conference } = store.getState()['features/base/conference'];
 - 
 -         conference.muteParticipant(action.id);
 -         break;
 -     }
 - 
 -     // TODO Remove this middleware when the local display name update flow is
 -     // fully brought into redux.
 -     case PARTICIPANT_DISPLAY_NAME_CHANGED: {
 -         if (typeof APP !== 'undefined') {
 -             const participant = getLocalParticipant(store.getState());
 - 
 -             if (participant && participant.id === action.id) {
 -                 APP.UI.emitEvent(UIEvents.NICKNAME_CHANGED, action.name);
 -             }
 -         }
 - 
 -         break;
 -     }
 - 
 -     case PARTICIPANT_JOINED:
 -         _maybePlaySounds(store, action);
 - 
 -         return _participantJoinedOrUpdated(store, next, action);
 - 
 -     case PARTICIPANT_LEFT:
 -         _maybePlaySounds(store, action);
 -         break;
 - 
 -     case PARTICIPANT_UPDATED:
 -         return _participantJoinedOrUpdated(store, next, action);
 -     }
 - 
 -     return next(action);
 - });
 - 
 - /**
 -  * Syncs the redux state features/base/participants up with the redux state
 -  * features/base/conference by ensuring that the former does not contain remote
 -  * participants no longer relevant to the latter. Introduced to address an issue
 -  * with multiplying thumbnails in the filmstrip.
 -  */
 - StateListenerRegistry.register(
 -     /* selector */ state => getCurrentConference(state),
 -     /* listener */ (conference, { dispatch, getState }) => {
 -         for (const p of getState()['features/base/participants']) {
 -             !p.local
 -                 && (!conference || p.conference !== conference)
 -                 && dispatch(participantLeft(p.id, p.conference));
 -         }
 -     });
 - 
 - /**
 -  * Reset the ID of the local participant to
 -  * {@link LOCAL_PARTICIPANT_DEFAULT_ID}. Such a reset is deemed possible only if
 -  * the local participant and, respectively, her ID is not involved in a
 -  * conference which is still of interest to the user and, consequently, the app.
 -  * For example, a conference which is in the process of leaving is no longer of
 -  * interest the user, is unrecoverable from the perspective of the user and,
 -  * consequently, the app.
 -  */
 - StateListenerRegistry.register(
 -     /* selector */ state => state['features/base/conference'],
 -     /* listener */ ({ leaving }, { dispatch, getState }) => {
 -         const state = getState();
 -         const localParticipant = getLocalParticipant(state);
 -         let id;
 - 
 -         if (!localParticipant
 -                 || (id = localParticipant.id)
 -                     === LOCAL_PARTICIPANT_DEFAULT_ID) {
 -             // The ID of the local participant has been reset already.
 -             return;
 -         }
 - 
 -         // The ID of the local may be reset only if it is not in use.
 -         const dispatchLocalParticipantIdChanged
 -             = forEachConference(
 -                 state,
 -                 conference =>
 -                     conference === leaving || conference.myUserId() !== id);
 - 
 -         dispatchLocalParticipantIdChanged
 -             && dispatch(
 -                 localParticipantIdChanged(LOCAL_PARTICIPANT_DEFAULT_ID));
 -     });
 - 
 - /**
 -  * Initializes the local participant and signals that it joined.
 -  *
 -  * @private
 -  * @param {Store} store - The redux store.
 -  * @param {Dispatch} next - The redux dispatch function to dispatch the
 -  * specified action to the specified store.
 -  * @param {Action} action - The redux action which is being dispatched
 -  * in the specified store.
 -  * @private
 -  * @returns {Object} The value returned by {@code next(action)}.
 -  */
 - function _localParticipantJoined({ getState, dispatch }, next, action) {
 -     const result = next(action);
 - 
 -     const settings = getState()['features/base/settings'];
 - 
 -     dispatch(localParticipantJoined({
 -         avatarID: settings.avatarID,
 -         avatarURL: settings.avatarURL,
 -         email: settings.email,
 -         name: settings.displayName
 -     }));
 - 
 -     return result;
 - }
 - 
 - /**
 -  * Signals that the local participant has left.
 -  *
 -  * @param {Store} store - The redux store.
 -  * @param {Dispatch} next - The redux {@code dispatch} function to dispatch the
 -  * specified {@code action} into the specified {@code store}.
 -  * @param {Action} action - The redux action which is being dispatched in the
 -  * specified {@code store}.
 -  * @private
 -  * @returns {Object} The value returned by {@code next(action)}.
 -  */
 - function _localParticipantLeft({ dispatch }, next, action) {
 -     const result = next(action);
 - 
 -     dispatch(localParticipantLeft());
 - 
 -     return result;
 - }
 - 
 - /**
 -  * Plays sounds when participants join/leave conference.
 -  *
 -  * @param {Store} store - The redux store.
 -  * @param {Action} action - The redux action. Should be either
 -  * {@link PARTICIPANT_JOINED} or {@link PARTICIPANT_LEFT}.
 -  * @private
 -  * @returns {void}
 -  */
 - function _maybePlaySounds({ getState, dispatch }, action) {
 -     const state = getState();
 -     const { startAudioMuted } = state['features/base/config'];
 - 
 -     // We're not playing sounds for local participant
 -     // nor when the user is joining past the "startAudioMuted" limit.
 -     // The intention there was to not play user joined notification in big
 -     // conferences where 100th person is joining.
 -     if (!action.participant.local
 -             && (!startAudioMuted
 -                 || getParticipantCount(state) < startAudioMuted)) {
 -         if (action.type === PARTICIPANT_JOINED) {
 -             const { presence } = action.participant;
 - 
 -             // The sounds for the poltergeist are handled by features/invite.
 -             if (presence !== INVITED && presence !== CALLING) {
 -                 dispatch(playSound(PARTICIPANT_JOINED_SOUND_ID));
 -             }
 -         } else if (action.type === PARTICIPANT_LEFT) {
 -             dispatch(playSound(PARTICIPANT_LEFT_SOUND_ID));
 -         }
 -     }
 - }
 - 
 - /**
 -  * Notifies the feature base/participants that the action
 -  * {@code PARTICIPANT_JOINED} or {@code PARTICIPANT_UPDATED} is being dispatched
 -  * within a specific redux store.
 -  *
 -  * @param {Store} store - The redux store in which the specified {@code action}
 -  * is being dispatched.
 -  * @param {Dispatch} next - The redux {@code dispatch} function to dispatch the
 -  * specified {@code action} in the specified {@code store}.
 -  * @param {Action} action - The redux action {@code PARTICIPANT_JOINED} or
 -  * {@code PARTICIPANT_UPDATED} which is being dispatched in the specified
 -  * {@code store}.
 -  * @private
 -  * @returns {Object} The value returned by {@code next(action)}.
 -  */
 - function _participantJoinedOrUpdated({ getState }, next, action) {
 -     const { participant: { id, local, raisedHand } } = action;
 - 
 -     // Send an external update of the local participant's raised hand state
 -     // if a new raised hand state is defined in the action.
 -     if (typeof raisedHand !== 'undefined') {
 -         if (local) {
 -             const { conference } = getState()['features/base/conference'];
 - 
 -             conference
 -                 && conference.setLocalParticipantProperty(
 -                     'raisedHand',
 -                     raisedHand);
 -         }
 - 
 -         if (typeof APP === 'object') {
 -             if (local) {
 -                 APP.UI.onLocalRaiseHandChanged(raisedHand);
 -                 APP.UI.setLocalRaisedHandStatus(raisedHand);
 -             } else {
 -                 const remoteParticipant = getParticipantById(getState(), id);
 - 
 -                 remoteParticipant
 -                     && APP.UI.setRaisedHandStatus(
 -                         remoteParticipant.id,
 -                         remoteParticipant.name,
 -                         raisedHand);
 -             }
 -         }
 -     }
 - 
 -     // Notify external listeners of potential avatarURL changes.
 -     if (typeof APP === 'object') {
 -         const oldAvatarURL = getAvatarURLByParticipantId(getState(), id);
 - 
 -         // Allow the redux update to go through and compare the old avatar
 -         // to the new avatar and emit out change events if necessary.
 -         const result = next(action);
 -         const newAvatarURL = getAvatarURLByParticipantId(getState(), id);
 - 
 -         if (oldAvatarURL !== newAvatarURL) {
 -             const currentKnownId = local ? APP.conference.getMyUserId() : id;
 - 
 -             APP.UI.refreshAvatarDisplay(currentKnownId, newAvatarURL);
 -             APP.API.notifyAvatarChanged(currentKnownId, newAvatarURL);
 -         }
 - 
 -         return result;
 -     }
 - 
 -     return next(action);
 - }
 - 
 - /**
 -  * Registers sounds related with the participants feature.
 -  *
 -  * @param {Store} store - The redux store.
 -  * @private
 -  * @returns {void}
 -  */
 - function _registerSounds({ dispatch }) {
 -     dispatch(
 -         registerSound(PARTICIPANT_JOINED_SOUND_ID, PARTICIPANT_JOINED_FILE));
 -     dispatch(registerSound(PARTICIPANT_LEFT_SOUND_ID, PARTICIPANT_LEFT_FILE));
 - }
 - 
 - /**
 -  * Unregisters sounds related with the participants feature.
 -  *
 -  * @param {Store} store - The redux store.
 -  * @private
 -  * @returns {void}
 -  */
 - function _unregisterSounds({ dispatch }) {
 -     dispatch(unregisterSound(PARTICIPANT_JOINED_SOUND_ID));
 -     dispatch(unregisterSound(PARTICIPANT_LEFT_SOUND_ID));
 - }
 
 
  |