fix(external_api): Fix number of participants in meeting (#12052)
This commit is contained in:
parent
17008237dc
commit
5f62acc67c
|
@ -55,7 +55,7 @@ import {
|
|||
removeBreakoutRoom,
|
||||
sendParticipantToRoom
|
||||
} from '../../react/features/breakout-rooms/actions';
|
||||
import { getBreakoutRooms } from '../../react/features/breakout-rooms/functions';
|
||||
import { getBreakoutRooms, getRoomsInfo } from '../../react/features/breakout-rooms/functions';
|
||||
import {
|
||||
sendMessage,
|
||||
setPrivateMessageRecipient,
|
||||
|
@ -846,6 +846,10 @@ function initCommands() {
|
|||
callback(getBreakoutRooms(APP.store.getState()));
|
||||
break;
|
||||
}
|
||||
case 'rooms-info': {
|
||||
callback(getRoomsInfo(APP.store.getState()));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -619,6 +619,9 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
|||
case 'video-quality-changed':
|
||||
this._videoQuality = data.videoQuality;
|
||||
break;
|
||||
case 'breakout-rooms-updated':
|
||||
this.updateNumberOfParticipants(data.rooms);
|
||||
break;
|
||||
case 'local-storage-changed':
|
||||
jitsiLocalStorage.setItem('jitsiLocalStorage', data.localStorageContent);
|
||||
|
||||
|
@ -638,6 +641,40 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update number of participants based on all rooms.
|
||||
*
|
||||
* @param {Object} rooms - Rooms available rooms in the conference.
|
||||
* @returns {void}
|
||||
*/
|
||||
updateNumberOfParticipants(rooms) {
|
||||
if (!rooms || !Object.keys(rooms).length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const allParticipants = Object.keys(rooms).reduce((prev, roomItemKey) => {
|
||||
if (rooms[roomItemKey]?.participants) {
|
||||
return Object.keys(rooms[roomItemKey].participants).length + prev;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}, 0);
|
||||
|
||||
this._numberOfParticipants = allParticipants;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the rooms info in the conference.
|
||||
*
|
||||
* @returns {Object} Rooms info.
|
||||
*/
|
||||
async getRoomsInfo() {
|
||||
return this._transport.sendRequest({
|
||||
name: 'rooms-info'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds event listener to Meet Jitsi.
|
||||
*
|
||||
|
@ -1101,7 +1138,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the number of participants in the conference. The local
|
||||
* Returns the number of participants in the conference from all rooms. The local
|
||||
* participant is included.
|
||||
*
|
||||
* @returns {int} The number of participants in the conference.
|
||||
|
|
|
@ -132,7 +132,7 @@ export function commonUserLeftHandling(
|
|||
} else {
|
||||
const isReplaced = user.isReplaced && user.isReplaced();
|
||||
|
||||
dispatch(participantLeft(id, conference, isReplaced));
|
||||
dispatch(participantLeft(id, conference, { isReplaced }));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -381,8 +381,13 @@ export function hiddenParticipantLeft(id: string) {
|
|||
* with the participant identified by the specified {@code id}. Only the local
|
||||
* participant is allowed to not specify an associated {@code JitsiConference}
|
||||
* instance.
|
||||
* @param {boolean} isReplaced - Whether the participant is to be replaced in the meeting.
|
||||
* @param {boolean} isVirtualScreenshareParticipant - Whether the participant is a virtual screen share participant.
|
||||
* @param {Object} participantLeftProps - Other participant properties.
|
||||
* @typedef {Object} participantLeftProps
|
||||
* @param {boolean} participantLeftProps.isReplaced - Whether the participant is to be replaced in the meeting.
|
||||
* @param {boolean} participantLeftProps.isVirtualScreenshareParticipant - Whether the participant is a
|
||||
* virtual screen share participant.
|
||||
* @param {boolean} participantLeftProps.isFakeParticipant - Whether the participant is a fake participant.
|
||||
*
|
||||
* @returns {{
|
||||
* type: PARTICIPANT_LEFT,
|
||||
* participant: {
|
||||
|
@ -391,15 +396,15 @@ export function hiddenParticipantLeft(id: string) {
|
|||
* }
|
||||
* }}
|
||||
*/
|
||||
export function participantLeft(id: string, conference: any,
|
||||
isReplaced?: boolean, isVirtualScreenshareParticipant?: boolean) {
|
||||
export function participantLeft(id: string, conference: any, participantLeftProps: any = {}) {
|
||||
return {
|
||||
type: PARTICIPANT_LEFT,
|
||||
participant: {
|
||||
conference,
|
||||
id,
|
||||
isReplaced,
|
||||
isVirtualScreenshareParticipant
|
||||
isReplaced: participantLeftProps.isReplaced,
|
||||
isVirtualScreenshareParticipant: participantLeftProps.isVirtualScreenshareParticipant,
|
||||
isFakeParticipant: participantLeftProps.isFakeParticipant
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -369,7 +369,9 @@ StateListenerRegistry.register(
|
|||
batch(() => {
|
||||
for (const [ id, p ] of getRemoteParticipants(getState())) {
|
||||
(!conference || p.conference !== conference)
|
||||
&& dispatch(participantLeft(id, p.conference, p.isReplaced));
|
||||
&& dispatch(participantLeft(id, p.conference, {
|
||||
isReplaced: p.isReplaced
|
||||
}));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -56,7 +56,10 @@ function _updateScreenshareParticipants({ getState, dispatch }) {
|
|||
}
|
||||
|
||||
if (localScreenShare && !newLocalSceenshareSourceName) {
|
||||
dispatch(participantLeft(localScreenShare.id, conference, undefined, true));
|
||||
dispatch(participantLeft(localScreenShare.id, conference, {
|
||||
isReplaced: undefined,
|
||||
isVirtualScreenshareParticipant: true
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,7 +67,10 @@ function _updateScreenshareParticipants({ getState, dispatch }) {
|
|||
const addedScreenshareSourceNames = _.difference(currentScreenshareSourceNames, previousScreenshareSourceNames);
|
||||
|
||||
if (removedScreenshareSourceNames.length) {
|
||||
removedScreenshareSourceNames.forEach(id => dispatch(participantLeft(id, conference, undefined, true)));
|
||||
removedScreenshareSourceNames.forEach(id => dispatch(participantLeft(id, conference, {
|
||||
isReplaced: undefined,
|
||||
isVirtualScreenshareParticipant: true
|
||||
})));
|
||||
}
|
||||
|
||||
if (addedScreenshareSourceNames.length) {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import _ from 'lodash';
|
||||
|
||||
import { getCurrentConference } from '../base/conference';
|
||||
import { getParticipantCount, isLocalParticipantModerator } from '../base/participants';
|
||||
import { getParticipantById, getParticipantCount, isLocalParticipantModerator } from '../base/participants';
|
||||
import { toState } from '../base/redux';
|
||||
|
||||
import { FEATURE_KEY } from './constants';
|
||||
|
@ -30,6 +30,69 @@ export const getMainRoom = (stateful: Function | Object) => {
|
|||
return _.find(rooms, (room: Object) => room.isMainRoom);
|
||||
};
|
||||
|
||||
export const getRoomsInfo = (stateful: Function | Object) => {
|
||||
const breakoutRooms = getBreakoutRooms(stateful);
|
||||
const conference = getCurrentConference(stateful);
|
||||
|
||||
const initialRoomsInfo = {
|
||||
rooms: []
|
||||
};
|
||||
|
||||
// only main roomn
|
||||
if (!breakoutRooms || Object.keys(breakoutRooms).length === 0) {
|
||||
return {
|
||||
...initialRoomsInfo,
|
||||
rooms: [ {
|
||||
isMainRoom: true,
|
||||
id: conference?.room?.roomjid,
|
||||
jid: conference?.room?.myroomjid,
|
||||
participants: conference && conference.participants && Object.keys(conference.participants).length
|
||||
? Object.keys(conference.participants).map(participantId => {
|
||||
const participantItem = conference?.participants[participantId];
|
||||
const storeParticipant = getParticipantById(stateful, participantItem._id);
|
||||
|
||||
return {
|
||||
jid: participantItem._jid,
|
||||
role: participantItem._role,
|
||||
displayName: participantItem._displayName,
|
||||
avatarUrl: storeParticipant?.loadableAvatarUrl,
|
||||
id: participantItem._id
|
||||
};
|
||||
}) : []
|
||||
} ]
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...initialRoomsInfo,
|
||||
rooms: Object.keys(breakoutRooms).map(breakoutRoomKey => {
|
||||
const breakoutRoomItem = breakoutRooms[breakoutRoomKey];
|
||||
|
||||
return {
|
||||
isMainRoom: Boolean(breakoutRoomItem.isMainRoom),
|
||||
id: breakoutRoomItem.id,
|
||||
jid: breakoutRoomItem.jid,
|
||||
participants: breakoutRoomItem.participants && Object.keys(breakoutRoomItem.participants).length
|
||||
? Object.keys(breakoutRoomItem.participants).map(participantLongId => {
|
||||
const participantItem = breakoutRoomItem.participants[participantLongId];
|
||||
const ids = participantLongId.split('/');
|
||||
const storeParticipant = getParticipantById(stateful,
|
||||
ids.length > 1 ? ids[1] : participantItem.jid);
|
||||
|
||||
return {
|
||||
jid: participantItem?.jid,
|
||||
role: participantItem?.role,
|
||||
displayName: participantItem?.displayName,
|
||||
avatarUrl: storeParticipant?.loadableAvatarUrl,
|
||||
id: storeParticipant ? storeParticipant.id
|
||||
: participantLongId
|
||||
};
|
||||
}) : []
|
||||
};
|
||||
})
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the room by Jid.
|
||||
*
|
||||
|
|
|
@ -150,19 +150,32 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
{ id: action.kicker });
|
||||
break;
|
||||
|
||||
case PARTICIPANT_LEFT:
|
||||
case PARTICIPANT_LEFT: {
|
||||
const { participant } = action;
|
||||
const { isFakeParticipant, isVirtualScreenshareParticipant } = participant;
|
||||
|
||||
// Skip sending participant left event for fake or virtual screenshare participants.
|
||||
if (isFakeParticipant || isVirtualScreenshareParticipant) {
|
||||
break;
|
||||
}
|
||||
|
||||
APP.API.notifyUserLeft(action.participant.id);
|
||||
break;
|
||||
|
||||
}
|
||||
case PARTICIPANT_JOINED: {
|
||||
const state = store.getState();
|
||||
const { defaultRemoteDisplayName } = state['features/base/config'];
|
||||
const { participant } = action;
|
||||
const { id, local, name } = participant;
|
||||
const { id, isFakeParticipant, isVirtualScreenshareParticipant, local, name } = participant;
|
||||
|
||||
// The version of external api outside of middleware did not emit
|
||||
// the local participant being created.
|
||||
if (!local) {
|
||||
// Skip sending participant joined event for fake or virtual screenshare participants.
|
||||
if (isFakeParticipant || isVirtualScreenshareParticipant) {
|
||||
break;
|
||||
}
|
||||
|
||||
APP.API.notifyUserJoined(id, {
|
||||
displayName: name,
|
||||
formattedDisplayName: appendSuffix(
|
||||
|
|
|
@ -10,7 +10,8 @@ import {
|
|||
getLocalParticipant,
|
||||
participantJoined,
|
||||
participantLeft,
|
||||
pinParticipant
|
||||
pinParticipant,
|
||||
getParticipantById
|
||||
} from '../base/participants';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
|
||||
|
@ -51,7 +52,12 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
if (isSharingStatus(sharedVideoStatus)) {
|
||||
handleSharingVideoStatus(store, value, attributes, conference);
|
||||
} else if (sharedVideoStatus === 'stop') {
|
||||
dispatch(participantLeft(value, conference));
|
||||
const videoParticipant = getParticipantById(state, value);
|
||||
|
||||
dispatch(participantLeft(value, conference, {
|
||||
isFakeParticipant: videoParticipant?.isFakeParticipant
|
||||
}));
|
||||
|
||||
if (localParticipantId !== from) {
|
||||
dispatch(resetSharedVideoStatus());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue