123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- import { getLogger } from '@jitsi/logger';
-
- import rtcstatsInit from '@jitsi/rtcstats/rtcstats';
- import traceInit from '@jitsi/rtcstats/trace-ws';
- import EventEmitter from 'events';
-
- import {
- CONFERENCE_JOINED,
- CONFERENCE_LEFT,
- CONFERENCE_UNIQUE_ID_SET
- } from '../../JitsiConferenceEvents';
- import JitsiConference from '../../JitsiConference';
- import { IRTCStatsConfiguration } from './interfaces';
- import { RTC_STATS_PC_EVENT, RTC_STATS_WC_DISCONNECTED } from './RTCStatsEvents';
-
- const logger = getLogger(__filename);
-
- /**
- * RTCStats Singleton that is initialized only once for the lifetime of the app, subsequent calls to init will be ignored.
- * Config and conference changes are handled by the start method.
- */
- class RTCStats {
- private _initialized: boolean = false;
- private _trace: any = null;
- public events: EventEmitter = new EventEmitter();
-
- /**
- * RTCStats "proxies" WebRTC functions such as GUM and RTCPeerConnection by rewriting the global objects.
- * The proxies will then send data to the rtcstats server via the trace object.
- * The initialization procedure must be called once when lib-jitsi-meet is loaded.
- *
- * @param {IRTCStatsConfiguration} initConfig initial config for rtcstats.
- * @returns {void}
- */
- init(initConfig: IRTCStatsConfiguration) {
- const {
- analytics: {
- rtcstatsUseLegacy: useLegacy = false,
- rtcstatsPollInterval: pollInterval= 10000,
- rtcstatsSendSdp: sendSdp = false,
- rtcstatsEnabled = false
- } = {}
- } = initConfig;
-
- // If rtcstats is not enabled or already initialized, do nothing.
- // Calling rtcsatsInit multiple times will cause the global objects to be rewritten multiple times,
- // with unforeseen consequences.
- if (!rtcstatsEnabled || this._initialized) return;
-
- rtcstatsInit(
- { statsEntry: this.sendStatsEntry.bind(this) },
- { pollInterval,
- useLegacy,
- sendSdp,
- eventCallback: (event) => this.events.emit(RTC_STATS_PC_EVENT, event)}
- );
-
- this._initialized = true;
- }
-
- /**
- * When a conference is about to start, we need to reset the trace module, and initialize it with the
- * new conference's config. On a normal conference flow this wouldn't be necessary, as the whole page is
- * reloaded, but in the case of breakout rooms or react native the js context doesn't reload, hence the
- * RTCStats singleton and its config persists between conferences.
- *
- * @param conference - JitsiConference instance that's about to start.
- * @returns {void}
- */
- start(conference: JitsiConference) {
- const {
- options: {
- config : confConfig = {},
- name: confName = ''
- } = {},
- _statsCurrentId : displayName = ''
- } = conference;
-
- const {
- analytics: {
- rtcstatsEnabled = false,
- rtcstatsEndpoint: endpoint = '',
- rtcstatsUseLegacy: useLegacy = false
- } = {}
- } = confConfig;
-
- // 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();
-
- // The new conference config might have rtcstats disabled, so we need to check again.
- if (!rtcstatsEnabled) return;
-
- // If rtcstats proxy module is not initialized, do nothing.
- if (!this._initialized) {
- logger.error('Calling start before RTCStats proxy module is initialized.');
-
- return;
- }
-
- // 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
- }
-
- this.sendIdentity(identityData);
- });
-
- // Note, this will only be called for normal rooms, not breakout rooms.
- conference.once(CONFERENCE_UNIQUE_ID_SET, (meetingUniqueId) => {
- this.sendIdentity({meetingUniqueId});
- });
-
- conference.once(CONFERENCE_LEFT, () => {
- this.reset();
- });
- }
-
- /**
- * Sends the identity data to the rtcstats server.
- *
- * @param identityData - Identity data to send.
- * @returns {void}
- */
- sendIdentity(identityData) {
- this._trace?.identity('identity', null, identityData);
- }
-
- /**
- * Resets the trace module by closing the websocket and deleting the object.
- * After reset, the rtcstats proxy module that tries to send data via `sendStatsEntry`, will no longer
- * send any data, until the trace module is initialized again. This comes in handy on react-native
- * where ljm doesn't get reloaded, so we need to switch the trace module between conferences.
- *
- * @returns {void}
- */
- reset() {
- this._trace?.close();
- this._trace = null;
- }
-
- /**
- * Sends a stats entry to the rtcstats server. This is called by the rtcstats proxy module,
- * or any other app that wants to send custom stats.
- *
- * @param entry - Stats entry to send.
- * @returns {void}
- */
- sendStatsEntry(statsType, pcId, data) {
- this._trace?.statsEntry(statsType, pcId, data);
- }
- }
-
- export default new RTCStats();
|