diff --git a/modules/RTCStats/RTCStats.ts b/modules/RTCStats/RTCStats.ts index d0d2376924..7f450d050e 100644 --- a/modules/RTCStats/RTCStats.ts +++ b/modules/RTCStats/RTCStats.ts @@ -5,6 +5,7 @@ import traceInit from '@jitsi/rtcstats/trace-ws'; import { CONFERENCE_CREATED_TIMESTAMP, + CONFERENCE_FAILED, CONFERENCE_JOINED, CONFERENCE_LEFT, CONFERENCE_UNIQUE_ID_SET @@ -14,6 +15,8 @@ import { IRTCStatsConfiguration } from './interfaces'; import { RTC_STATS_PC_EVENT, RTC_STATS_WC_DISCONNECTED } from './RTCStatsEvents'; import EventEmitter from '../util/EventEmitter'; import Settings from '../settings/Settings'; +import { XMPPEvents } from "../../service/xmpp/XMPPEvents"; +import { JitsiConferenceErrors } from "../../JitsiConferenceErrors"; const logger = getLogger(__filename); @@ -72,30 +75,16 @@ class RTCStats { start(conference: JitsiConference) { const { options: { - config : confConfig = {}, - name: confName = '' + config : confConfig = {} } = {}, - _statsCurrentId : displayName = '' } = conference; const { analytics: { - rtcstatsEnabled = false, - rtcstatsEndpoint: endpoint = '', - rtcstatsUseLegacy: useLegacy = false + rtcstatsEnabled = false } = {} } = confConfig; - // The statisticsId, statisticsDisplayName and _statsCurrentId (renamed to displayName) fields - // that are sent through options might be a bit confusing. Depending on the context, they could - // be intermixed inside ljm, for instance _statsCurrentId might refer to the email field which is stored - // in statisticsId or it could have the same value as callStatsUserName. - // The following is the mapping between the fields, and a short explanation of each: - // statisticsId -> email, this is only send by jitsi-meet if enableEmailInStats option is set. - // statisticsDisplayName -> nick, this is only send by jitsi-meet if enableDisplayNameInStats option is set. - // localId, this is the unique id that is used to track users throughout stats. - const localId = Settings?.callStatsUserName ?? ''; - // Reset the trace module in case it wasn't during the previous conference. // Closing the underlying websocket connection and deleting the trace obj. this.reset(); @@ -113,35 +102,18 @@ class RTCStats { // When the conference is joined, we need to initialize the trace module with the new conference's config. // The trace module will then connect to the rtcstats server and send the identity data. conference.once(CONFERENCE_JOINED, () => { - const traceOptions = { - endpoint, - meetingFqn: confName, - onCloseCallback: (event) => this.events.emit(RTC_STATS_WC_DISCONNECTED, event), - useLegacy - }; - - const isBreakoutRoom = Boolean(conference.getBreakoutRooms()?.isBreakoutRoom()); - const endpointId = conference.myUserId(); - const meetingUniqueId = conference.getMeetingUniqueId(); - - this._trace = traceInit(traceOptions); - - // Connect to the rtcstats server instance. Stats (data obtained from getstats) won't be send until the - // connect successfully initializes, however calls to GUM are recorded in an internal buffer even if not - // connected and sent once it is established. - this._trace.connect(isBreakoutRoom); - - const identityData = { - ...confConfig, - endpointId, - confName, - displayName, - meetingUniqueId, - isBreakoutRoom, - localId + this._connect(conference, conference.getMeetingUniqueId()); + }); + conference.once(CONFERENCE_FAILED, (error) => { + if (error === JitsiConferenceErrors.MEMBERS_ONLY_ERROR) { + conference.room.eventEmitter.once(XMPPEvents.MUC_LOBBY_JOINED, (lobbyRoom) => { + if (!lobbyRoom?.getMeetingId()) { + lobbyRoom?.eventEmitter.once(XMPPEvents.MEETING_ID_SET, () => { + this._connect(conference, lobbyRoom.getMeetingId()); + }); + } + }); } - - this.sendIdentity(identityData); }); // Note, this will only be called for normal rooms, not breakout rooms. @@ -158,6 +130,67 @@ class RTCStats { }) } + _connect(conference: JitsiConference, meetingUniqueId: string, isLobby = false) { + const { + options: { + config : confConfig = {}, + name: confName = '' + } = {}, + _statsCurrentId : displayName = '' + } = conference; + + const { + analytics: { + rtcstatsEndpoint: endpoint = '', + rtcstatsUseLegacy: useLegacy = false + } = {} + } = confConfig; + + // The statisticsId, statisticsDisplayName and _statsCurrentId (renamed to displayName) fields + // that are sent through options might be a bit confusing. Depending on the context, they could + // be intermixed inside ljm, for instance _statsCurrentId might refer to the email field which is stored + // in statisticsId, or it could have the same value as callStatsUserName. + // The following is the mapping between the fields, and a short explanation of each: + // statisticsId -> email, this is only send by jitsi-meet if enableEmailInStats option is set. + // statisticsDisplayName -> nick, this is only send by jitsi-meet if enableDisplayNameInStats option is set. + // localId, this is the unique id that is used to track users throughout stats. + const localId = Settings?.callStatsUserName ?? ''; + + const traceOptions = { + endpoint, + meetingFqn: confName, + onCloseCallback: (event) => this.events.emit(RTC_STATS_WC_DISCONNECTED, event), + useLegacy + }; + + const isBreakoutRoom = Boolean(conference.getBreakoutRooms()?.isBreakoutRoom()); + const endpointId = conference.myUserId(); + + if (this._trace && this._trace.isConnected()) { + // in case of lobby we may try to call this twice, once on lobby join and once when admitted + + return; + } + this._trace = traceInit(traceOptions); + + // Connect to the rtcstats server instance. Stats (data obtained from getstats) won't be sent until + // connect successfully initializes, however calls to GUM are recorded in an internal buffer even if not + // connected and sent once it is established. + this._trace.connect(isBreakoutRoom || isLobby); + + const identityData = { + ...confConfig, + endpointId, + confName, + displayName, + meetingUniqueId, + isBreakoutRoom, + localId + } + + this.sendIdentity(identityData); + } + /** * Sends the identity data to the rtcstats server. * diff --git a/modules/xmpp/ChatRoom.js b/modules/xmpp/ChatRoom.js index 7142495f87..ded1d6a9f5 100644 --- a/modules/xmpp/ChatRoom.js +++ b/modules/xmpp/ChatRoom.js @@ -359,6 +359,22 @@ export default class ChatRoom extends Listenable { .c('query', { xmlns: Strophe.NS.DISCO_INFO }); this.connection.sendIQ(getInfo, result => { + const meetingIdValEl + = $(result).find('>query>x[type="result"]>field[var="muc#roominfo_meetingId"]>value'); + + if (meetingIdValEl.length) { + this.setMeetingId(meetingIdValEl.text()); + } else { + logger.warn('No meeting ID from backend'); + } + + if (!this.lobby) { + // if this is in the lobby room, we need just the meetingId + // only the main room has this.lobby + + return; + } + const locked = $(result).find('>query>feature[var="muc_passwordprotected"]') .length @@ -369,14 +385,6 @@ export default class ChatRoom extends Listenable { this.locked = locked; } - const meetingIdValEl - = $(result).find('>query>x[type="result"]>field[var="muc#roominfo_meetingId"]>value'); - - if (meetingIdValEl.length) { - this.setMeetingId(meetingIdValEl.text()); - } else { - logger.warn('No meeting ID from backend'); - } const meetingCreatedTSValEl = $(result).find('>query>x[type="result"]>field[var="muc#roominfo_created_timestamp"]>value'); diff --git a/modules/xmpp/Lobby.js b/modules/xmpp/Lobby.js index 6db86c7a1d..cc9eed94c0 100644 --- a/modules/xmpp/Lobby.js +++ b/modules/xmpp/Lobby.js @@ -251,7 +251,6 @@ export default class Lobby { this.lobbyRoom = this.xmpp.createRoom( roomName, { customDomain, - disableDiscoInfo: true, disableFocus: true, enableLobby: false } @@ -379,6 +378,8 @@ export default class Lobby { this.lobbyRoom.addOrReplaceInPresence(EMAIL_COMMAND, { value: email }) && this.lobbyRoom.sendPresence(); } + + this.mainRoom.emit(XMPPEvents.MUC_LOBBY_JOINED, this.lobbyRoom); }); this.lobbyRoom.addEventListener(XMPPEvents.ROOM_JOIN_ERROR, reject); this.lobbyRoom.addEventListener(XMPPEvents.ROOM_CONNECT_NOT_ALLOWED_ERROR, reject); diff --git a/service/xmpp/XMPPEvents.ts b/service/xmpp/XMPPEvents.ts index 1c61c54950..03a9718042 100644 --- a/service/xmpp/XMPPEvents.ts +++ b/service/xmpp/XMPPEvents.ts @@ -152,6 +152,9 @@ export enum XMPPEvents { // Designates an event indicating that a participant left the XMPP MUC. MUC_MEMBER_LEFT = 'xmpp.muc_member_left', + // Designates an event indicating that the lobby XMPP MUC is joined. + MUC_LOBBY_JOINED = 'xmpp.muc_lobby_joined', + // Designates an event indicating that a participant joined the lobby XMPP MUC. MUC_LOBBY_MEMBER_JOINED = 'xmpp.muc_lobby_member_joined',