UNPKG

@observertc/observer-js

Version:

Server Side NodeJS Library for processing ObserveRTC Samples

161 lines (160 loc) 6.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Observer = void 0; const logger_1 = require("./common/logger"); const ObservedCall_1 = require("./ObservedCall"); const events_1 = require("events"); const ObservedTURN_1 = require("./ObservedTURN"); const Detectors_1 = require("./detectors/Detectors"); const OnIntervalUpdater_1 = require("./updaters/OnIntervalUpdater"); const OnAllCallObserverUpdater_1 = require("./updaters/OnAllCallObserverUpdater"); const OnAnyCallObserverUpdater_1 = require("./updaters/OnAnyCallObserverUpdater"); const ObserverEventMonitor_1 = require("./ObserverEventMonitor"); const MediasoupRemoteTrackResolver_1 = require("./utils/MediasoupRemoteTrackResolver"); const logger = (0, logger_1.createLogger)('Observer'); class Observer extends events_1.EventEmitter { config; detectors; observedTURN = new ObservedTURN_1.ObservedTURN(); observedCalls = new Map(); updater; closed = false; totalAddedCall = 0; totalRemovedCall = 0; numberOfClientsUsingTurn = 0; numberOfClients = 0; numberOfInboundRtpStreams = 0; numberOfOutboundRtpStreams = 0; numberOfDataChannels = 0; numberOfPeerConnections = 0; get numberOfCalls() { return this.observedCalls.size; } _timer; constructor(config = { updatePolicy: 'update-when-all-call-updated', updateIntervalInMs: undefined, appData: {}, }) { super(); this.config = config; this.setMaxListeners(Infinity); this.update = this.update.bind(this); const currentUpdatePolicy = (config?.updatePolicy) ?? 'update-when-all-call-updated'; switch (currentUpdatePolicy) { case 'update-on-any-call-updated': this.updater = new OnAnyCallObserverUpdater_1.OnAnyCallObserverUpdater(this); break; case 'update-when-all-call-updated': this.updater = new OnAllCallObserverUpdater_1.OnAllCallObserverUpdater(this); break; case 'update-on-interval': { const interval = config?.updateIntervalInMs; if (!interval) { throw new Error('updateIntervalInMs setting in config must be set if updatePolicy is update-on-interval'); } this.updater = new OnIntervalUpdater_1.OnIntervalUpdater(interval, this.update.bind(this)); break; } } this.detectors = new Detectors_1.Detectors(); } get appData() { return this.config.appData; } getObservedCall(callId) { if (this.closed || !this.observedCalls.has(callId)) return; return this.observedCalls.get(callId); } createObservedCall(settings) { if (this.closed) { throw new Error('Attempted to create a call source on a closed observer'); } if (!settings.updatePolicy) { settings.updatePolicy = this.config.defaultCallUpdatePolicy; settings.updateIntervalInMs = this.config.defaultCallUpdateIntervalInMs; } if (!settings.closeCallIfEmptyForMs) { settings.closeCallIfEmptyForMs = this.config.closeCallIfEmptyForMs; } const observedCall = new ObservedCall_1.ObservedCall(settings, this); const onCallUpdated = () => this._onObservedCallUpdated(observedCall); if (this.observedCalls.has(observedCall.callId)) throw new Error(`Observed Call with id ${observedCall.callId} already exists`); if (settings.remoteTrackResolvePolicy === 'mediasoup-sfu') { observedCall.remoteTrackResolver = new MediasoupRemoteTrackResolver_1.MediasoupRemoteTrackResolver(observedCall); } else if (settings.remoteTrackResolvePolicy === 'p2p') { // For future implementation } else if (settings.remoteTrackResolvePolicy === 'none' || !settings.remoteTrackResolvePolicy) { // do nothing } observedCall.once('close', () => { this.observedCalls.delete(observedCall.callId); observedCall.off('update', onCallUpdated); ++this.totalRemovedCall; }); this.observedCalls.set(observedCall.callId, observedCall); observedCall.on('update', onCallUpdated); ++this.totalAddedCall; this.emit('newcall', observedCall); return observedCall; } close() { if (this.closed) { return logger.debug('Attempted to close twice'); } this.closed = true; clearInterval(this._timer); this._timer = undefined; this.observedCalls.forEach((call) => call.close()); this.emit('close'); } accept(sample) { if (this.closed) return; if (!sample.callId) return logger.warn('Received sample without callId. %o', sample); if (!sample.clientId) return logger.warn('Received sample without clientId %o', sample); const call = this.getObservedCall(sample.callId) ?? this.createObservedCall({ callId: sample.callId, updateIntervalInMs: this.config.defaultCallUpdateIntervalInMs, updatePolicy: this.config.defaultCallUpdatePolicy, }); const client = call.getObservedClient(sample.clientId) ?? call.createObservedClient({ clientId: sample.clientId, }); client.accept(sample); } update() { if (this.closed) { return; } this.numberOfInboundRtpStreams = 0; this.numberOfOutboundRtpStreams = 0; this.numberOfPeerConnections = 0; this.numberOfDataChannels = 0; this.numberOfClients = 0; this.numberOfClientsUsingTurn = 0; for (const call of this.observedCalls.values()) { this.numberOfInboundRtpStreams += call.numberOfInboundRtpStreams; this.numberOfOutboundRtpStreams += call.numberOfOutboundRtpStreams; this.numberOfPeerConnections += call.numberOfPeerConnections; this.numberOfDataChannels += call.numberOfDataChannels; this.numberOfClients += call.numberOfClients; this.numberOfClientsUsingTurn += call.clientsUsedTurn.size; } this.observedTURN.update(); this.emit('update'); } _onObservedCallUpdated(call) { call; } createEventMonitor(ctx) { return new ObserverEventMonitor_1.ObserverEventMonitor(this, ctx ?? {}); } } exports.Observer = Observer;