Associate remote participant w/ JitsiConference (_JOINED)

The plan set in motion here is to associate remote participants with the
JitsiConference instances that created them in order to be able to
remove remote participants when a JitsiConference is no longer the
primary focus of the jitsi-meet app. And that's supposed to alleviate a
problem with multiplying remote thumbnails.

Doing all of the above in a single commit is a bit of a high order. So
I'm splitting the whole into multiple successive commits for the
purposes of observability, comprehension. Each commit is supposed to be
safe even if subsequent commits are not accepted, are reverted,
whatever. Obviously, without the successive commits, a commit may be
"unused".

One of the important pieces of the multiplying remote thumbnails "fix"
offered is removing remote participants who are no longer of interest
i.e. PARTICIPANT_LEFT. But in order for _LEFT to be implemented, _JOINED
must be implemented first.
This commit is contained in:
Lyubo Marinov 2018-05-22 14:30:51 -05:00
parent fcca15c827
commit 983e62ffe9
6 changed files with 99 additions and 78 deletions

View File

@ -1688,6 +1688,7 @@ export default {
const displayName = user.getDisplayName();
APP.store.dispatch(participantJoined({
conference: room,
id,
name: displayName,
role: user.getRole()

View File

@ -306,6 +306,7 @@ export default class SharedVideoManager {
SHARED_VIDEO_CONTAINER_TYPE, self.sharedVideo);
APP.store.dispatch(participantJoined({
conference: APP.conference,
id: self.url,
isBot: true,
name: 'YouTube'

View File

@ -140,6 +140,7 @@ function _addConferenceListeners(conference, dispatch) {
conference.on(
JitsiConferenceEvents.USER_JOINED,
(id, user) => dispatch(participantJoined({
conference,
id,
name: user.getDisplayName(),
role: user.getRole()

View File

@ -214,11 +214,16 @@ export function participantDisplayNameChanged(id, displayName = '') {
*
* @param {Participant} participant - Information about participant.
* @returns {{
* type: PARTICIPANT_JOINED,
* participant: Participant
* type: PARTICIPANT_JOINED,
* participant: Participant
* }}
*/
export function participantJoined(participant) {
if (!participant.local && !participant.conference) {
throw Error(
'A remote participant must be associated with a JitsiConference!');
}
return {
type: PARTICIPANT_JOINED,
participant
@ -393,7 +398,5 @@ export function showParticipantJoinedNotification(displayName) {
joinedParticipantsNames.push(
displayName || interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME);
return dispatch => {
_throttledNotifyParticipantConnected(dispatch);
};
return dispatch => _throttledNotifyParticipantConnected(dispatch);
}

View File

@ -139,15 +139,15 @@ MiddlewareRegistry.register(store => next => action => {
*/
function _localParticipantJoined({ getState, dispatch }, next, action) {
const result = next(action);
const settings = getState()['features/base/settings'];
const localParticipant = {
dispatch(localParticipantJoined({
avatarID: settings.avatarID,
avatarURL: settings.avatarURL,
email: settings.email,
name: settings.displayName
};
dispatch(localParticipantJoined(localParticipant));
}));
return result;
}
@ -204,7 +204,10 @@ function _participantJoinedOrUpdated({ getState }, next, action) {
if (local) {
const { conference } = getState()['features/base/conference'];
conference.setLocalParticipantProperty('raisedHand', raisedHand);
conference
&& conference.setLocalParticipantProperty(
'raisedHand',
raisedHand);
}
if (typeof APP === 'object') {

View File

@ -39,6 +39,35 @@ declare var APP: Object;
const PARTICIPANT_PROPS_TO_OMIT_WHEN_UPDATE
= [ 'dominantSpeaker', 'id', 'local', 'pinned' ];
/**
* Listen for actions which add, remove, or update the set of participants in
* the conference.
*
* @param {Participant[]} state - List of participants to be modified.
* @param {Object} action - Action object.
* @param {string} action.type - Type of action.
* @param {Participant} action.participant - Information about participant to be
* added/removed/modified.
* @returns {Participant[]}
*/
ReducerRegistry.register('features/base/participants', (state = [], action) => {
switch (action.type) {
case DOMINANT_SPEAKER_CHANGED:
case PARTICIPANT_ID_CHANGED:
case PARTICIPANT_UPDATED:
case PIN_PARTICIPANT:
return state.map(p => _participant(p, action));
case PARTICIPANT_JOINED:
return [ ...state, _participantJoined(action) ];
case PARTICIPANT_LEFT:
return state.filter(p => p.id !== action.participant.id);
}
return state;
});
/**
* Reducer function for a single participant.
*
@ -67,52 +96,6 @@ function _participant(state: Object = {}, action) {
}
break;
case PARTICIPANT_JOINED: {
const { participant } = action; // eslint-disable-line no-shadow
const {
avatarURL,
connectionStatus,
dominantSpeaker,
email,
isBot,
local,
name,
pinned,
role
} = participant;
let { avatarID, id } = participant;
// avatarID
//
// TODO Get the avatarID of the local participant from localStorage.
if (!avatarID && local) {
avatarID = randomHexString(32);
}
// id
//
// XXX The situation of not having an ID for a remote participant should
// not happen. Maybe we should raise an error in this case or generate a
// random ID.
if (!id && local) {
id = LOCAL_PARTICIPANT_DEFAULT_ID;
}
return {
avatarID,
avatarURL,
connectionStatus,
dominantSpeaker: dominantSpeaker || false,
email,
id,
isBot,
local: local || false,
name,
pinned: pinned || false,
role: role || PARTICIPANT_ROLE.NONE
};
}
case PARTICIPANT_UPDATED: {
const { participant } = action; // eslint-disable-line no-shadow
let { id } = participant;
@ -147,31 +130,60 @@ function _participant(state: Object = {}, action) {
}
/**
* Listen for actions which add, remove, or update the set of participants in
* the conference.
* Reduces a specific redux action of type {@link PARTICIPANT_JOINED} in the
* feature base/participants.
*
* @param {Participant[]} state - List of participants to be modified.
* @param {Object} action - Action object.
* @param {string} action.type - Type of action.
* @param {Participant} action.participant - Information about participant to be
* added/removed/modified.
* @returns {Participant[]}
* @param {Action} action - The redux action of type {@code PARTICIPANT_JOINED}
* to reduce.
* @private
* @returns {Object} The new participant derived from the payload of the
* specified {@code action} to be added into the redux state of the feature
* base/participants after the reduction of the specified
* {@code action}.
*/
ReducerRegistry.register('features/base/participants', (state = [], action) => {
switch (action.type) {
case DOMINANT_SPEAKER_CHANGED:
case PARTICIPANT_ID_CHANGED:
case PARTICIPANT_UPDATED:
case PIN_PARTICIPANT:
return state.map(p => _participant(p, action));
function _participantJoined({ participant }) {
const {
avatarURL,
connectionStatus,
dominantSpeaker,
email,
isBot,
local,
name,
pinned,
role
} = participant;
let { avatarID, conference, id } = participant;
case PARTICIPANT_JOINED:
return [ ...state, _participant(undefined, action) ];
if (local) {
// avatarID
//
// TODO Get the avatarID of the local participant from localStorage.
avatarID || (avatarID = randomHexString(32));
case PARTICIPANT_LEFT:
return state.filter(p => p.id !== action.participant.id);
// conference
//
// XXX The local participant is not identified in association with a
// JitsiConference because it is identified by the very fact that it is
// the local participant.
conference = undefined;
default:
return state;
// id
id || (id = LOCAL_PARTICIPANT_DEFAULT_ID);
}
});
return {
avatarID,
avatarURL,
conference,
connectionStatus,
dominantSpeaker: dominantSpeaker || false,
email,
id,
isBot,
local: local || false,
name,
pinned: pinned || false,
role: role || PARTICIPANT_ROLE.NONE
};
}