@observertc/observer-js
Version:
Server Side NodeJS Library for processing ObserveRTC Samples
220 lines (219 loc) • 9.05 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ObservedCall = void 0;
const events_1 = require("events");
const ObservedClient_1 = require("./ObservedClient");
const DefaultCallScoreCalculator_1 = require("./scores/DefaultCallScoreCalculator");
const Detectors_1 = require("./detectors/Detectors");
const OnAllClientCallUpdater_1 = require("./updaters/OnAllClientCallUpdater");
const OnIntervalUpdater_1 = require("./updaters/OnIntervalUpdater");
const OnAnyClientCallUpdater_1 = require("./updaters/OnAnyClientCallUpdater");
const ObservedCallEventMonitor_1 = require("./ObservedCallEventMonitor");
class ObservedCall extends events_1.EventEmitter {
observer;
detectors;
updater;
scoreCalculator;
callId;
observedClients = new Map();
clientsUsedTurn = new Set();
calculatedScore = {
weight: 1,
value: undefined,
};
remoteTrackResolver;
totalAddedClients = 0;
totalRemovedClients = 0;
totalClientsReceivedAudioBytes = 0;
totalClientsReceivedVideoBytes = 0;
totalClientsReceivedDataChannelBytes = 0;
totalClientsReceivedBytes = 0;
totalClientsSentAudioBytes = 0;
totalClientsSentDataChannelBytes = 0;
totalClientsSentVideoBytes = 0;
totalClientsSentBytes = 0;
totalRttLt50Measurements = 0;
totalRttLt150Measurements = 0;
totalRttLt300Measurements = 0;
totalRttGtOrEq300Measurements = 0;
numberOfIssues = 0;
numberOfPeerConnections = 0;
numberOfInboundRtpStreams = 0;
numberOfOutboundRtpStreams = 0;
numberOfDataChannels = 0;
maxNumberOfClients = 0;
deltaNumberOfIssues = 0;
deltaRttLt50Measurements = 0;
deltaRttLt150Measurements = 0;
deltaRttLt300Measurements = 0;
deltaRttGtOrEq300Measurements = 0;
appData;
closed = false;
startedAt;
endedAt;
closedAt;
_callStartedEvent;
_callEndedEvent;
constructor(settings, observer) {
super();
this.observer = observer;
this.setMaxListeners(Infinity);
this.callId = settings.callId;
this.appData = settings.appData ?? {};
this.scoreCalculator = new DefaultCallScoreCalculator_1.DefaultCallScoreCalculator(this);
this.detectors = new Detectors_1.Detectors();
if (settings.updateIntervalInMs) {
if (settings.updatePolicy !== 'update-on-interval') {
throw new Error('updatePolicy must be update-on-interval if updateIntervalInMs is set in config');
}
}
switch (settings.updatePolicy) {
case 'update-on-any-client-updated':
this.updater = new OnAnyClientCallUpdater_1.OnAnyClientCallUpdater(this);
break;
case 'update-when-all-client-updated':
this.updater = new OnAllClientCallUpdater_1.OnAllClientCallUpdater(this);
break;
case 'update-on-interval':
if (!settings.updateIntervalInMs) {
throw new Error('updateIntervalInMs setting in config must be set if updatePolicy is update-on-interval');
}
this.updater = new OnIntervalUpdater_1.OnIntervalUpdater(settings.updateIntervalInMs, this.update.bind(this));
break;
}
switch (settings.remoteTrackResolvePolicy) {
case 'mediasoup-sfu':
break;
}
this._callStartedEvent = {
emitted: false,
};
this._callEndedEvent = {
emitted: false,
};
}
get numberOfClients() {
return this.observedClients.size;
}
get score() {
return this.calculatedScore.value;
}
close() {
if (this.closed)
return;
this.update(); // last update before closing
this.closed = true;
this.updater?.close();
let minSampleTimestamps;
let maxSampleTimestamps;
for (const client of this.observedClients.values()) {
client.close();
if (client.joinedAt)
minSampleTimestamps = Math.min(minSampleTimestamps ?? client.joinedAt, client.joinedAt);
if (client.leftAt)
maxSampleTimestamps = Math.max(maxSampleTimestamps ?? client.leftAt, client.leftAt);
}
if (this.startedAt === undefined)
this.startedAt = minSampleTimestamps;
if (this.endedAt === undefined)
this.endedAt = maxSampleTimestamps;
this.closedAt = Date.now();
this.emit('close');
}
getObservedClient(clientId) {
if (this.closed || !this.observedClients.has(clientId))
return;
return this.observedClients.get(clientId);
}
createObservedClient(settings) {
if (this.closed)
throw new Error(`Call ${this.callId} is closed`);
if (this.observedClients.has(settings.clientId))
throw new Error(`Client with id ${settings.clientId} already exists`);
const result = new ObservedClient_1.ObservedClient(settings, this);
const wasEmpty = this.observedClients.size === 0;
const onUpdate = () => this._onClientUpdate(result);
const joined = () => this._clientJoined(result);
const left = () => this._clientLeft(result);
result.once('close', () => {
result.off('update', onUpdate);
result.off('joined', joined);
result.off('left', left);
this.observedClients.delete(settings.clientId);
if (this.observedClients.size === 0) {
this.emit('empty');
}
++this.totalRemovedClients;
});
result.on('update', onUpdate);
result.on('joined', joined);
result.on('left', left);
++this.totalAddedClients;
this.observedClients.set(settings.clientId, result);
this.maxNumberOfClients = Math.max(this.maxNumberOfClients, this.observedClients.size);
this.emit('newclient', result);
if (wasEmpty) {
this.emit('not-empty');
}
return result;
}
createEventMonitor(context) {
return new ObservedCallEventMonitor_1.ObservedCallEventMonitor(this, context);
}
update() {
if (this.closed)
return;
this.numberOfInboundRtpStreams = 0;
this.numberOfOutboundRtpStreams = 0;
this.numberOfPeerConnections = 0;
this.numberOfDataChannels = 0;
for (const client of this.observedClients.values()) {
this.numberOfInboundRtpStreams += client.numberOfInboundRtpStreams;
this.numberOfOutboundRtpStreams += client.numberOfOutboundRtpStreams;
this.numberOfPeerConnections += client.numberOfPeerConnections;
this.numberOfDataChannels += client.numberOfDataChannels;
}
this.detectors.update();
this.scoreCalculator.update();
this.emit('update');
this.deltaNumberOfIssues = 0;
this.deltaRttLt50Measurements = 0;
this.deltaRttLt150Measurements = 0;
this.deltaRttLt300Measurements = 0;
this.deltaRttGtOrEq300Measurements = 0;
}
_onClientUpdate(client) {
this.totalClientsReceivedAudioBytes += client.deltaReceivedAudioBytes;
this.totalClientsReceivedVideoBytes += client.deltaReceivedVideoBytes;
this.totalClientsReceivedDataChannelBytes += client.deltaDataChannelBytesReceived;
this.totalClientsReceivedBytes += client.deltaTransportReceivedBytes;
this.totalClientsSentAudioBytes += client.deltaSentAudioBytes;
this.totalClientsSentVideoBytes += client.deltaSentVideoBytes;
this.totalClientsSentDataChannelBytes += client.deltaDataChannelBytesSent;
this.totalClientsSentBytes += client.deltaTransportSentBytes;
this.deltaRttLt50Measurements += client.deltaRttLt50Measurements;
this.deltaRttLt150Measurements += client.deltaRttLt150Measurements;
this.deltaRttLt300Measurements += client.deltaRttLt300Measurements;
this.deltaRttGtOrEq300Measurements += client.deltaRttGtOrEq300Measurements;
this.totalRttLt50Measurements += client.deltaRttLt50Measurements;
this.totalRttLt150Measurements += client.deltaRttLt150Measurements;
this.totalRttLt300Measurements += client.deltaRttLt300Measurements;
this.totalRttGtOrEq300Measurements += client.deltaRttGtOrEq300Measurements;
this.deltaNumberOfIssues += client.deltaNumberOfIssues;
this.numberOfIssues += client.deltaNumberOfIssues;
if (client.usingTURN) {
this.clientsUsedTurn.add(client.clientId);
}
}
_clientJoined(client) {
if (!client.joinedAt)
return;
this.startedAt = Math.min(this.startedAt ?? client.joinedAt, client.joinedAt);
}
_clientLeft(client) {
if (!client.leftAt)
return;
this.endedAt = Math.max(this.endedAt ?? client.leftAt, client.leftAt);
}
}
exports.ObservedCall = ObservedCall;