Дамян Минков a6555c5d24
Singleton follow me (#4144)
* Prints errors in case of wrong initialization.

Not printing can masks some errors in the code.

* Allow only one Follow Me moderator in a meeting.

* Sends Follow Me state with all presences of the moderator.

This fixes an issue where the moderator sends the Follow Me state and then for example mute or unmute video (this will produce a presence without Follow Me state) and the new comers will not reflect current Follow Me state till a change of it comes.

* Changes fixing comments.

* Changes fixing comments.
2019-04-26 18:11:53 +00:00

120 lines
3.6 KiB
JavaScript

// @flow
import { StateListenerRegistry } from '../base/redux';
import { getCurrentConference } from '../base/conference';
import {
getPinnedParticipant,
isLocalParticipantModerator
} from '../base/participants';
import { FOLLOW_ME_COMMAND } from './constants';
/**
* Subscribes to changes to the Follow Me setting for the local participant to
* notify remote participants of current user interface status.
* Changing newSelectedValue param to off, when feature is turned of so we can
* notify all listeners.
*/
StateListenerRegistry.register(
/* selector */ state => state['features/base/conference'].followMeEnabled,
/* listener */ (newSelectedValue, store) => _sendFollowMeCommand(newSelectedValue || 'off', store));
/**
* Subscribes to changes to the currently pinned participant in the user
* interface of the local participant.
*/
StateListenerRegistry.register(
/* selector */ state => {
const pinnedParticipant = getPinnedParticipant(state);
return pinnedParticipant ? pinnedParticipant.id : null;
},
/* listener */ _sendFollowMeCommand);
/**
* Subscribes to changes to the shared document (etherpad) visibility in the
* user interface of the local participant.
*
* @param sharedDocumentVisible {Boolean} {true} if the shared document was
* shown (as a result of the toggle) or {false} if it was hidden
*/
StateListenerRegistry.register(
/* selector */ state => state['features/etherpad'].editing,
/* listener */ _sendFollowMeCommand);
/**
* Subscribes to changes to the filmstrip visibility in the user interface of
* the local participant.
*/
StateListenerRegistry.register(
/* selector */ state => state['features/filmstrip'].visible,
/* listener */ _sendFollowMeCommand);
/**
* Subscribes to changes to the tile view setting in the user interface of the
* local participant.
*/
StateListenerRegistry.register(
/* selector */ state => state['features/video-layout'].tileViewEnabled,
/* listener */ _sendFollowMeCommand);
/**
* Private selector for returning state from redux that should be respected by
* other participants while follow me is enabled.
*
* @param {Object} state - The redux state.
* @returns {Object}
*/
function _getFollowMeState(state) {
const pinnedParticipant = getPinnedParticipant(state);
return {
filmstripVisible: state['features/filmstrip'].visible,
nextOnStage: pinnedParticipant && pinnedParticipant.id,
sharedDocumentVisible: state['features/etherpad'].editing,
tileViewEnabled: state['features/video-layout'].tileViewEnabled
};
}
/**
* Sends the follow-me command, when a local property change occurs.
*
* @param {*} newSelectedValue - The changed selected value from the selector.
* @param {Object} store - The redux store.
* @private
* @returns {void}
*/
function _sendFollowMeCommand(
newSelectedValue, store) { // eslint-disable-line no-unused-vars
const state = store.getState();
const conference = getCurrentConference(state);
if (!conference) {
return;
}
// Only a moderator is allowed to send commands.
if (!isLocalParticipantModerator(state)) {
return;
}
if (newSelectedValue === 'off') {
// if the change is to off, local user turned off follow me and
// we want to signal this
conference.sendCommandOnce(
FOLLOW_ME_COMMAND,
{ attributes: { off: true } }
);
return;
} else if (!state['features/base/conference'].followMeEnabled) {
return;
}
conference.sendCommand(
FOLLOW_ME_COMMAND,
{ attributes: _getFollowMeState(state) }
);
}