@observertc/observer-js
Version:
Server Side NodeJS Library for processing ObserveRTC Samples
774 lines (773 loc) • 38.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ObservedPeerConnection = void 0;
const events_1 = require("events");
const ObservedInboundRtp_1 = require("./ObservedInboundRtp");
const logger_1 = require("./common/logger");
const ObservedOutboundRtp_1 = require("./ObservedOutboundRtp");
const ObservedCertificate_1 = require("./ObservedCertificate");
const ObservedCodec_1 = require("./ObservedCodec");
const ObservedDataChannel_1 = require("./ObservedDataChannel");
const ObservedIceCandidate_1 = require("./ObservedIceCandidate");
const ObservedIceCandidatePair_1 = require("./ObservedIceCandidatePair");
const ObservedIceTransport_1 = require("./ObservedIceTransport");
const ObservedMediaSource_1 = require("./ObservedMediaSource");
const ObservedPeerConnectionTransport_1 = require("./ObservedPeerConnectionTransport");
const ObservedMediaPlayout_1 = require("./ObservedMediaPlayout");
const ObservedRemoteInboundRtp_1 = require("./ObservedRemoteInboundRtp");
const ObservedRemoteOutboundRtp_1 = require("./ObservedRemoteOutboundRtp");
const ObservedInboundTrack_1 = require("./ObservedInboundTrack");
const ObservedOutboundTrack_1 = require("./ObservedOutboundTrack");
const utils_1 = require("./common/utils");
const logger = (0, logger_1.createLogger)('ObservedPeerConnection');
class ObservedPeerConnection extends events_1.EventEmitter {
peerConnectionId;
client;
_visited = true;
appData;
calculatedScore = {
weight: 1,
value: undefined,
};
closed = false;
// timestamp of the PEER_CONNECTION_OPENED event
openedAt;
// timestamp of the PEER_CONNECTION_CLOSED event
closedAt;
updated = Date.now();
connectionState;
iceConnectionState;
iceGatheringState;
availableIncomingBitrate = 0;
availableOutgoingBitrate = 0;
totalInboundPacketsLost = 0;
totalInboundPacketsReceived = 0;
totalOutboundPacketsSent = 0;
totalDataChannelBytesSent = 0;
totalDataChannelBytesReceived = 0;
totalDataChannelMessagesSent = 0;
totalDataChannelMessagesReceived = 0;
totalSentAudioBytes = 0;
totalSentVideoBytes = 0;
totalSentAudioPackets = 0;
totalSentVideoPackets = 0;
totalReceivedAudioPacktes = 0;
totalReceivedVideoPackets = 0;
totalReceivedAudioBytes = 0;
totalReceivedVideoBytes = 0;
deltaInboundPacketsLost = 0;
deltaInboundPacketsReceived = 0;
deltaOutboundPacketsSent = 0;
deltaDataChannelBytesSent = 0;
deltaDataChannelBytesReceived = 0;
deltaDataChannelMessagesSent = 0;
deltaDataChannelMessagesReceived = 0;
deltaInboundReceivedBytes = 0;
deltaOutboundSentBytes = 0;
deltaReceivedAudioBytes = 0;
deltaReceivedVideoBytes = 0;
deltaReceivedAudioPackets = 0;
deltaReceivedVideoPackets = 0;
deltaSentAudioBytes = 0;
deltaSentVideoBytes = 0;
deltaTransportSentBytes = 0;
deltaTransportReceivedBytes = 0;
receivingPacketsPerSecond = 0;
sendingPacketsPerSecond = 0;
sendingAudioBitrate = 0;
sendingVideoBitrate = 0;
receivingAudioBitrate = 0;
receivingVideoBitrate = 0;
currentRttInMs;
currentJitter;
usingTCP = false;
usingTURN = false;
observedTurnServer;
observedCertificates = new Map();
observedCodecs = new Map();
observedDataChannels = new Map();
observedIceCandidates = new Map();
observedIceCandidatesPair = new Map();
observedIceTransports = new Map();
observedInboundRtps = new Map();
observedInboundTracks = new Map();
observedMediaPlayouts = new Map();
observedMediaSources = new Map();
observedOutboundRtps = new Map();
observedOutboundTracks = new Map();
observedPeerConnectionTransports = new Map();
observedRemoteInboundRtps = new Map();
observedRemoteOutboundRtps = new Map();
constructor(peerConnectionId, client) {
super();
this.peerConnectionId = peerConnectionId;
this.client = client;
this.setMaxListeners(Infinity);
}
get score() {
return this.calculatedScore.value;
}
get visited() {
const visited = this._visited;
this._visited = false;
return visited;
}
get codecs() {
return [...this.observedCodecs.values()];
}
get inboundRtps() {
return [...this.observedInboundRtps.values()];
}
get remoteOutboundRtps() {
return [...this.observedRemoteOutboundRtps.values()];
}
get outboundRtps() {
return [...this.observedOutboundRtps.values()];
}
get remoteInboundRtps() {
return [...this.observedRemoteInboundRtps.values()];
}
get mediaSources() {
return [...this.observedMediaSources.values()];
}
get mediaPlayouts() {
return [...this.observedMediaPlayouts.values()];
}
get dataChannels() {
return [...this.observedDataChannels.values()];
}
get peerConnectionTransports() {
return [...this.observedPeerConnectionTransports.values()];
}
get iceTransports() {
return [...this.observedIceTransports.values()];
}
get iceCandidates() {
return [...this.observedIceCandidates.values()];
}
get iceCandidatePairs() {
return [...this.observedIceCandidatesPair.values()];
}
get certificates() {
return [...this.observedCertificates.values()];
}
get selectedIceCandidatePairs() {
return this.iceTransports.map((iceTransport) => iceTransport.getSelectedCandidatePair())
.filter((pair) => pair !== undefined);
}
get selectedIceCandiadtePairForTurn() {
return this.selectedIceCandidatePairs
.filter((pair) => pair.getLocalCandidate()?.candidateType === 'relay' &&
pair.getRemoteCandidate()?.url?.startsWith('turn:'));
}
close() {
if (this.closed)
return;
this.closed = true;
this.observedCertificates.clear();
this.observedCodecs.clear();
this.observedDataChannels.clear();
this.observedIceCandidates.clear();
this.observedIceCandidatesPair.clear();
this.observedIceTransports.clear();
this.observedInboundRtps.clear();
this.observedInboundTracks.clear();
this.observedMediaPlayouts.clear();
this.observedMediaSources.clear();
this.observedOutboundRtps.clear();
this.observedOutboundTracks.clear();
this.observedPeerConnectionTransports.clear();
this.observedRemoteInboundRtps.clear();
this.observedRemoteOutboundRtps.clear();
this.client.call.observer.observedTURN.removePeerConnection(this);
if (!this.closedAt)
this.closedAt = Date.now();
this.emit('close');
}
accept(sample) {
if (this.closed)
return;
this._visited = true;
this.availableIncomingBitrate = 0;
this.availableOutgoingBitrate = 0;
this.deltaInboundPacketsLost = 0;
this.deltaInboundPacketsReceived = 0;
this.deltaOutboundPacketsSent = 0;
this.deltaDataChannelBytesSent = 0;
this.deltaDataChannelBytesReceived = 0;
this.deltaInboundReceivedBytes = 0;
this.deltaOutboundSentBytes = 0;
this.deltaReceivedAudioBytes = 0;
this.deltaReceivedVideoBytes = 0;
this.deltaReceivedAudioPackets = 0;
this.deltaReceivedVideoPackets = 0;
this.deltaSentAudioBytes = 0;
this.deltaSentVideoBytes = 0;
this.deltaTransportReceivedBytes = 0;
this.deltaTransportSentBytes = 0;
this.sendingAudioBitrate = 0;
this.sendingVideoBitrate = 0;
this.receivingAudioBitrate = 0;
this.receivingVideoBitrate = 0;
const now = Date.now();
const elapsedTimeInMs = now - this.updated;
const elapsedTimeInSec = elapsedTimeInMs / 1000;
const rttMeasurementsInSec = [];
const jitterMeasurements = [];
if (sample.certificates) {
for (const certificate of sample.certificates) {
this._updateCertificateStats(certificate);
}
}
if (sample.codecs) {
for (const codec of sample.codecs) {
this._updateCodecStats(codec);
}
}
if (sample.dataChannels) {
for (const dataChannel of sample.dataChannels) {
const observedDataChannel = this._updateDataChannelStats(dataChannel);
if (!observedDataChannel)
continue;
this.deltaDataChannelBytesSent += observedDataChannel.deltaBytesSent;
this.deltaDataChannelBytesReceived += observedDataChannel.deltaBytesReceived;
this.deltaDataChannelMessagesSent += observedDataChannel.deltaMessagesSent;
this.deltaDataChannelMessagesReceived += observedDataChannel.deltaMessagesReceived;
}
}
if (sample.iceCandidates) {
for (const iceCandidate of sample.iceCandidates) {
this._updateIceCandidateStats(iceCandidate);
}
}
if (sample.iceCandidatePairs) {
for (const iceCandidatePair of sample.iceCandidatePairs) {
const observedCandidatePair = this._updateIceCandidatePairStats(iceCandidatePair);
if (!observedCandidatePair)
continue;
if (observedCandidatePair.currentRoundTripTime) {
rttMeasurementsInSec.push(observedCandidatePair.currentRoundTripTime);
}
if (observedCandidatePair.availableIncomingBitrate) {
this.availableIncomingBitrate += observedCandidatePair.availableIncomingBitrate;
}
if (observedCandidatePair.availableOutgoingBitrate) {
this.availableOutgoingBitrate += observedCandidatePair.availableOutgoingBitrate;
}
}
}
if (sample.iceTransports) {
for (const iceTransport of sample.iceTransports) {
const observedIceTransport = this._updateIceTransportStats(iceTransport);
if (!observedIceTransport)
return;
observedIceTransport.bytesReceived;
}
}
if (sample.inboundRtps) {
for (const inboundRtp of sample.inboundRtps) {
const observedInboundRtp = this._updateInboundRtpStats(inboundRtp);
if (!observedInboundRtp)
continue;
this.deltaInboundPacketsLost += observedInboundRtp.deltaLostPackets;
this.deltaInboundPacketsReceived += observedInboundRtp.deltaReceivedPackets;
this.deltaInboundReceivedBytes += observedInboundRtp.deltaBytesReceived;
switch (inboundRtp.kind) {
case 'audio':
this.deltaReceivedAudioBytes += observedInboundRtp.deltaBytesReceived;
this.deltaReceivedAudioPackets += observedInboundRtp.deltaReceivedPackets;
break;
case 'video':
this.deltaReceivedVideoBytes += observedInboundRtp.deltaBytesReceived;
this.deltaReceivedVideoPackets += observedInboundRtp.deltaReceivedPackets;
break;
}
if (observedInboundRtp.jitter) {
jitterMeasurements.push(observedInboundRtp.jitter);
}
}
}
if (sample.mediaPlayouts) {
for (const mediaPlayout of sample.mediaPlayouts) {
this._updateMediaPlayoutStats(mediaPlayout);
}
}
if (sample.mediaSources) {
for (const mediaSource of sample.mediaSources) {
this._updateMediaSourceStats(mediaSource);
}
}
if (sample.outboundRtps) {
for (const outboundRtp of sample.outboundRtps) {
const observedOutboundRtp = this._updateOutboundRtpStats(outboundRtp);
if (!observedOutboundRtp)
continue;
this.deltaOutboundPacketsSent += observedOutboundRtp.deltaPacketsSent ?? 0;
this.deltaOutboundSentBytes += observedOutboundRtp.deltaBytesSent ?? 0;
switch (outboundRtp.kind) {
case 'audio':
this.deltaSentAudioBytes += observedOutboundRtp.deltaBytesSent;
this.deltaSentAudioBytes += observedOutboundRtp.deltaPacketsSent;
break;
case 'video':
this.deltaSentVideoBytes += observedOutboundRtp.deltaBytesSent;
this.deltaSentVideoBytes += observedOutboundRtp.deltaPacketsSent;
break;
}
}
}
if (sample.peerConnectionTransports) {
for (const peerConnectionTransport of sample.peerConnectionTransports) {
const observedTransport = this._updatePeerConnectionTransportStats(peerConnectionTransport);
if (!observedTransport)
continue;
}
}
if (sample.remoteInboundRtps) {
for (const remoteInboundRtp of sample.remoteInboundRtps) {
const observedRemoteInboundRtp = this._updateRemoteInboundRtpStats(remoteInboundRtp);
if (!observedRemoteInboundRtp)
continue;
if (observedRemoteInboundRtp.roundTripTime) {
rttMeasurementsInSec.push(observedRemoteInboundRtp.roundTripTime);
}
}
}
if (sample.remoteOutboundRtps) {
for (const remoteOutboundRtp of sample.remoteOutboundRtps) {
const observedRemoteOutboundRtp = this._updateRemoteOutboundRtpStats(remoteOutboundRtp);
if (!observedRemoteOutboundRtp)
continue;
}
}
// tracks should be updated last as they are derived stats
// and depends on base stats but they all received in the sample sample
if (sample.inboundTracks) {
for (const inboundTrack of sample.inboundTracks) {
this._updateInboundTrackSample(inboundTrack);
}
}
if (sample.outboundTracks) {
for (const outboundTrack of sample.outboundTracks) {
this._updateOutboundTrackSample(outboundTrack);
}
}
this.totalInboundPacketsLost += this.deltaInboundPacketsLost;
this.totalInboundPacketsReceived += this.deltaInboundPacketsReceived;
this.totalOutboundPacketsSent += this.deltaOutboundPacketsSent;
this.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
this.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
this.totalDataChannelMessagesSent += this.deltaDataChannelMessagesSent;
this.totalDataChannelMessagesReceived += this.deltaDataChannelMessagesReceived;
this.totalReceivedAudioBytes += this.deltaReceivedAudioBytes;
this.totalReceivedVideoBytes += this.deltaReceivedVideoBytes;
this.totalSentAudioBytes += this.deltaSentAudioBytes;
this.totalSentVideoBytes += this.deltaSentVideoBytes;
this.totalReceivedAudioPacktes += this.deltaReceivedAudioPackets;
this.totalReceivedVideoPackets += this.deltaReceivedVideoPackets;
this.totalSentAudioPackets += this.deltaSentAudioBytes;
this.totalSentVideoPackets += this.deltaSentVideoBytes;
this.receivingPacketsPerSecond = this.deltaInboundPacketsReceived / elapsedTimeInSec;
this.sendingPacketsPerSecond = this.deltaOutboundPacketsSent / elapsedTimeInSec;
this.sendingAudioBitrate = (this.deltaSentAudioBytes * 8) / elapsedTimeInSec;
this.sendingVideoBitrate = (this.deltaSentVideoBytes * 8) / elapsedTimeInSec;
this.receivingAudioBitrate = (this.deltaReceivedAudioBytes * 8) / elapsedTimeInSec;
this.receivingVideoBitrate = (this.deltaReceivedVideoBytes * 8) / elapsedTimeInSec;
if (rttMeasurementsInSec.length > 0) {
this.currentRttInMs = (0, utils_1.getMedian)(rttMeasurementsInSec, false) * 1000;
}
else {
this.currentRttInMs = undefined;
}
if (jitterMeasurements.length > 0) {
this.currentJitter = (0, utils_1.getMedian)(jitterMeasurements, false);
}
else {
this.currentJitter = undefined;
}
const wasUsingTURN = this.usingTURN;
const selectedIceCandidatePairs = this.selectedIceCandidatePairs;
const selectedCandidatePairForTurn = [];
this.usingTCP = false;
this.usingTURN = false;
for (const selectedCandidatePair of selectedIceCandidatePairs) {
if (selectedCandidatePair.getLocalCandidate()?.protocol === 'tcp') {
this.usingTCP = true;
}
if (selectedCandidatePair.getLocalCandidate()?.candidateType === 'relay' && selectedCandidatePair.getRemoteCandidate()?.url?.startsWith('turn:')) {
selectedCandidatePairForTurn.push(selectedCandidatePair);
this.usingTURN = true;
}
this.deltaTransportReceivedBytes += selectedCandidatePair.deltaBytesReceived;
this.deltaTransportSentBytes += selectedCandidatePair.deltaBytesSent;
}
if (this.usingTURN) {
if (!this.observedTurnServer) {
this.observedTurnServer = this.client.call.observer.observedTURN.addPeerConnection(this);
}
this.observedTurnServer?.updateTurnUsage(...selectedCandidatePairForTurn);
}
else if (wasUsingTURN) {
if (!this.usingTURN) {
this.client.call.observer.observedTURN.removePeerConnection(this);
}
}
this.calculatedScore.value = sample.score;
this.updated = now;
this._checkVisited();
this.emit('update');
}
_checkVisited() {
for (const certificate of [...this.observedCertificates.values()]) {
if (certificate.visited)
continue;
this.observedCertificates.delete(certificate.id);
}
for (const codec of [...this.observedCodecs.values()]) {
if (codec.visited)
continue;
this.observedCodecs.delete(codec.id);
this.emit('removed-codec', codec);
}
for (const dataChannel of [...this.observedDataChannels.values()]) {
if (dataChannel.visited)
continue;
this.observedDataChannels.delete(dataChannel.id);
this.emit('removed-data-channel', dataChannel);
}
for (const iceCandidate of [...this.observedIceCandidates.values()]) {
if (iceCandidate.visited)
continue;
this.observedIceCandidates.delete(iceCandidate.id);
this.emit('removed-ice-candidate', iceCandidate);
}
for (const iceCandidatePair of [...this.observedIceCandidatesPair.values()]) {
if (iceCandidatePair.visited)
continue;
this.observedIceCandidatesPair.delete(iceCandidatePair.id);
this.emit('removed-ice-candidate-pair', iceCandidatePair);
}
for (const iceTransport of [...this.observedIceTransports.values()]) {
if (iceTransport.visited)
continue;
this.observedIceTransports.delete(iceTransport.id);
this.emit('removed-ice-transport', iceTransport);
}
for (const inboundRtp of [...this.observedInboundRtps.values()]) {
if (inboundRtp.visited)
continue;
this.observedInboundRtps.delete(inboundRtp.ssrc);
this.emit('removed-inbound-rtp', inboundRtp);
}
for (const inboundTrack of [...this.observedInboundTracks.values()]) {
if (inboundTrack.visited)
continue;
this.observedInboundTracks.delete(inboundTrack.id);
this.emit('removed-inbound-track', inboundTrack);
}
for (const mediaPlayout of [...this.observedMediaPlayouts.values()]) {
if (mediaPlayout.visited)
continue;
this.observedMediaPlayouts.delete(mediaPlayout.id);
this.emit('removed-media-playout', mediaPlayout);
}
for (const mediaSource of [...this.observedMediaSources.values()]) {
if (mediaSource.visited)
continue;
this.observedMediaSources.delete(mediaSource.id);
this.emit('removed-media-source', mediaSource);
}
for (const outboundRtp of [...this.observedOutboundRtps.values()]) {
if (outboundRtp.visited)
continue;
this.observedOutboundRtps.delete(outboundRtp.ssrc);
this.emit('removed-outbound-rtp', outboundRtp);
}
for (const outboundTrack of [...this.observedOutboundTracks.values()]) {
if (outboundTrack.visited)
continue;
this.observedOutboundTracks.delete(outboundTrack.id);
this.emit('removed-outbound-track', outboundTrack);
}
for (const peerConnectionTransport of [...this.observedPeerConnectionTransports.values()]) {
if (peerConnectionTransport.visited)
continue;
this.observedPeerConnectionTransports.delete(peerConnectionTransport.id);
this.emit('removed-peer-connection-transport', peerConnectionTransport);
}
for (const remoteInboundRtp of [...this.observedRemoteInboundRtps.values()]) {
if (remoteInboundRtp.visited)
continue;
this.observedRemoteInboundRtps.delete(remoteInboundRtp.ssrc);
this.emit('removed-remote-inbound-rtp', remoteInboundRtp);
}
for (const remoteOutboundRtp of [...this.observedRemoteOutboundRtps.values()]) {
if (remoteOutboundRtp.visited)
continue;
this.observedRemoteOutboundRtps.delete(remoteOutboundRtp.ssrc);
this.emit('removed-remote-outbound-rtp', remoteOutboundRtp);
}
}
_updateCertificateStats(stats) {
let observedCertificate = this.observedCertificates.get(stats.id);
if (!observedCertificate) {
if (!stats.timestamp || !stats.id || !stats.fingerprint) {
return logger.warn(`ObservedPeerConnection received an invalid CertificateStats (missing timestamp OR id OR fingerprint field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`, stats);
}
observedCertificate = new ObservedCertificate_1.ObservedCertificate(stats.timestamp, stats.id, this);
observedCertificate.update(stats);
this.observedCertificates.set(stats.id, observedCertificate);
this.emit('added-certificate', observedCertificate);
}
else {
observedCertificate.update(stats);
this.emit('updated-certificate', observedCertificate);
}
return observedCertificate;
}
_updateCodecStats(stats) {
let observedCodec = this.observedCodecs.get(stats.id);
if (!observedCodec) {
if (!stats.timestamp || !stats.id || !stats.mimeType) {
return logger.warn(`ObservedPeerConnection received an invalid CodecStats (missing timestamp OR id OR mimeType field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`, stats);
}
observedCodec = new ObservedCodec_1.ObservedCodec(stats.timestamp, stats.id, stats.mimeType, this);
observedCodec.update(stats);
this.observedCodecs.set(stats.id, observedCodec);
this.emit('added-codec', observedCodec);
}
else {
observedCodec.update(stats);
}
this.emit('updated-codec', observedCodec);
return observedCodec;
}
_updateDataChannelStats(stats) {
let observedDataChannel = this.observedDataChannels.get(stats.id);
if (!observedDataChannel) {
if (!stats.timestamp || !stats.id) {
return logger.warn(`ObservedPeerConnection received an invalid DataChannelStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`, stats);
}
observedDataChannel = new ObservedDataChannel_1.ObservedDataChannel(stats.timestamp, stats.id, this);
observedDataChannel.update(stats);
this.observedDataChannels.set(stats.id, observedDataChannel);
this.emit('added-data-channel', observedDataChannel);
}
else {
observedDataChannel.update(stats);
}
this.emit('updated-data-channel', observedDataChannel);
return observedDataChannel;
}
_updateIceCandidateStats(stats) {
let observedIceCandidate = this.observedIceCandidates.get(stats.id);
if (!observedIceCandidate) {
if (!stats.timestamp || !stats.id) {
return logger.warn(`ObservedPeerConnection received an invalid IceCandidateStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`, stats);
}
observedIceCandidate = new ObservedIceCandidate_1.ObservedIceCandidate(stats.timestamp, stats.id, this);
observedIceCandidate.update(stats);
this.observedIceCandidates.set(stats.id, observedIceCandidate);
this.emit('added-ice-candidate', observedIceCandidate);
}
else {
observedIceCandidate.update(stats);
}
this.emit('updated-ice-candidate', observedIceCandidate);
return observedIceCandidate;
}
_updateIceCandidatePairStats(stats) {
let observedIceCandidatePair = this.observedIceCandidatesPair.get(stats.id);
if (!observedIceCandidatePair) {
if (!stats.timestamp || !stats.id) {
return logger.warn(`ObservedPeerConnection received an invalid IceCandidateStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`, stats);
}
observedIceCandidatePair = new ObservedIceCandidatePair_1.ObservedIceCandidatePair(stats.timestamp, stats.id, this);
observedIceCandidatePair.update(stats);
this.observedIceCandidatesPair.set(stats.id, observedIceCandidatePair);
this.emit('added-ice-candidate-pair', observedIceCandidatePair);
}
else {
observedIceCandidatePair.update(stats);
}
this.emit('updated-ice-candidate-pair', observedIceCandidatePair);
return observedIceCandidatePair;
}
_updateIceTransportStats(stats) {
let observedIceTransport = this.observedIceTransports.get(stats.id);
if (!observedIceTransport) {
if (!stats.timestamp || !stats.id) {
return logger.warn(`ObservedPeerConnection received an invalid IceCandidateStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`, stats);
}
observedIceTransport = new ObservedIceTransport_1.ObservedIceTransport(stats.timestamp, stats.id, this);
observedIceTransport.update(stats);
this.observedIceTransports.set(stats.id, observedIceTransport);
this.emit('added-ice-transport', observedIceTransport);
}
else {
observedIceTransport.update(stats);
}
this.emit('updated-ice-transport', observedIceTransport);
return observedIceTransport;
}
_updateInboundRtpStats(stats) {
let observedInboundRtp = this.observedInboundRtps.get(stats.ssrc);
if (!observedInboundRtp) {
if (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind || !stats.trackIdentifier) {
return logger.warn(`ObservedPeerConnection received an invalid InboundRtpStats (missing timestamp OR id OR ssrc OR kind OR trackIdentifier field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`, stats);
}
observedInboundRtp = new ObservedInboundRtp_1.ObservedInboundRtp(stats.timestamp, stats.id, stats.ssrc, stats.kind, stats.trackIdentifier, this);
observedInboundRtp.update(stats);
this.observedInboundRtps.set(stats.ssrc, observedInboundRtp);
this.emit('added-inbound-rtp', observedInboundRtp);
}
else {
observedInboundRtp.update(stats);
}
this.emit('updated-inbound-rtp', observedInboundRtp);
return observedInboundRtp;
}
_updateInboundTrackSample(stats) {
let observedInboundTrack = this.observedInboundTracks.get(stats.id);
if (!observedInboundTrack) {
if (!stats.timestamp || !stats.id || !stats.kind) {
return logger.warn(`ObservedPeerConnection received an invalid InboundTrackSample (missing timestamp OR id OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`, stats);
}
const inboundRtp = [...this.observedInboundRtps.values()].find((inbRtp) => inbRtp.trackIdentifier === stats.id);
const mediaPlayout = inboundRtp ?
[...this.observedMediaPlayouts.values()].find((mp) => mp.id === inboundRtp.playoutId) : undefined;
observedInboundTrack = new ObservedInboundTrack_1.ObservedInboundTrack(stats.timestamp, stats.id, stats.kind, this, inboundRtp, mediaPlayout);
observedInboundTrack.update(stats);
this.observedInboundTracks.set(stats.id, observedInboundTrack);
this.emit('added-inbound-track', observedInboundTrack);
}
else {
observedInboundTrack.update(stats);
}
this.emit('updated-inbound-track', observedInboundTrack);
return observedInboundTrack;
}
_updateMediaPlayoutStats(stats) {
let observedMediaPlayout = this.observedMediaPlayouts.get(stats.id);
if (!observedMediaPlayout) {
if (!stats.timestamp || !stats.id || !stats.kind) {
return logger.warn(`ObservedPeerConnection received an invalid InboundRtpStats (missing timestamp OR id OR kind OR trackIdentifier field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`, stats);
}
observedMediaPlayout = new ObservedMediaPlayout_1.ObservedMediaPlayout(stats.timestamp, stats.id, stats.kind, this);
observedMediaPlayout.update(stats);
this.observedMediaPlayouts.set(stats.id, observedMediaPlayout);
this.emit('added-media-playout', observedMediaPlayout);
}
else {
observedMediaPlayout.update(stats);
}
this.emit('updated-media-playout', observedMediaPlayout);
return observedMediaPlayout;
}
_updateMediaSourceStats(stats) {
let observedMediaSource = this.observedMediaSources.get(stats.id);
if (!observedMediaSource) {
if (!stats.timestamp || !stats.id || !stats.kind) {
return logger.warn(`ObservedPeerConnection received an invalid InboundRtpStats (missing timestamp OR id OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`, stats);
}
observedMediaSource = new ObservedMediaSource_1.ObservedMediaSource(stats.timestamp, stats.id, stats.kind, this);
observedMediaSource.update(stats);
this.observedMediaSources.set(stats.id, observedMediaSource);
this.emit('added-media-source', observedMediaSource);
}
else {
observedMediaSource.update(stats);
}
this.emit('updated-media-source', observedMediaSource);
return observedMediaSource;
}
_updateOutboundRtpStats(stats) {
let observedOutboundRtp = this.observedOutboundRtps.get(stats.ssrc);
if (!observedOutboundRtp) {
if (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind) {
return logger.warn(`ObservedPeerConnection received an invalid OutboundRtpStats (missing timestamp OR id OR ssrc OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`, stats);
}
observedOutboundRtp = new ObservedOutboundRtp_1.ObservedOutboundRtp(stats.timestamp, stats.id, stats.ssrc, stats.kind, this);
observedOutboundRtp.update(stats);
this.observedOutboundRtps.set(stats.ssrc, observedOutboundRtp);
this.emit('added-outbound-rtp', observedOutboundRtp);
}
else {
observedOutboundRtp.update(stats);
}
this.emit('updated-outbound-rtp', observedOutboundRtp);
return observedOutboundRtp;
}
_updateOutboundTrackSample(stats) {
let observedOutboundTrack = this.observedOutboundTracks.get(stats.id);
if (!observedOutboundTrack) {
if (!stats.timestamp || !stats.id || !stats.kind) {
return logger.warn(`ObservedPeerConnection received an invalid OutboundTrackSample (missing timestamp OR id OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`, stats);
}
const observedMediaSource = [...this.observedMediaSources.values()].find((mediaSource) => mediaSource.trackIdentifier === stats.id);
const outboundRtps = observedMediaSource
? [...this.observedOutboundRtps.values()].filter((outboundRtp) => outboundRtp.mediaSourceId === observedMediaSource?.id) : undefined;
observedOutboundTrack = new ObservedOutboundTrack_1.ObservedOutboundTrack(stats.timestamp, stats.id, stats.kind, this, outboundRtps, observedMediaSource);
observedOutboundTrack.update(stats);
this.observedOutboundTracks.set(stats.id, observedOutboundTrack);
this.emit('added-outbound-track', observedOutboundTrack);
}
else {
observedOutboundTrack.update(stats);
}
this.emit('updated-outbound-track', observedOutboundTrack);
return observedOutboundTrack;
}
_updatePeerConnectionTransportStats(stats) {
let observedPeerConnectionTransport = this.observedPeerConnectionTransports.get(stats.id);
if (!observedPeerConnectionTransport) {
if (!stats.timestamp || !stats.id) {
return logger.warn(`ObservedPeerConnection received an invalid PeerConnectionTransportStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`, stats);
}
observedPeerConnectionTransport = new ObservedPeerConnectionTransport_1.ObservedPeerConnectionTransport(stats.timestamp, stats.id, this);
observedPeerConnectionTransport.update(stats);
this.observedPeerConnectionTransports.set(stats.id, observedPeerConnectionTransport);
this.emit('added-peer-connection-transport', observedPeerConnectionTransport);
}
else {
observedPeerConnectionTransport.update(stats);
}
this.emit('updated-peer-connection-transport', observedPeerConnectionTransport);
return observedPeerConnectionTransport;
}
_updateRemoteInboundRtpStats(stats) {
let observedRemoteInboundRtp = this.observedRemoteInboundRtps.get(stats.ssrc);
if (!observedRemoteInboundRtp) {
if (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind) {
return logger.warn(`ObservedPeerConnection received an invalid RemoteInboundRtpStats (missing timestamp OR id OR ssrc OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`, stats);
}
observedRemoteInboundRtp = new ObservedRemoteInboundRtp_1.ObservedRemoteInboundRtp(stats.timestamp, stats.id, stats.ssrc, stats.kind, this);
observedRemoteInboundRtp.update(stats);
this.observedRemoteInboundRtps.set(stats.ssrc, observedRemoteInboundRtp);
this.emit('added-remote-inbound-rtp', observedRemoteInboundRtp);
}
else {
observedRemoteInboundRtp.update(stats);
}
this.emit('updated-remote-inbound-rtp', observedRemoteInboundRtp);
return observedRemoteInboundRtp;
}
_updateRemoteOutboundRtpStats(stats) {
let observedRemoteOutboundRtp = this.observedRemoteOutboundRtps.get(stats.ssrc);
if (!observedRemoteOutboundRtp) {
if (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind) {
return logger.warn(`ObservedPeerConnection received an invalid RemoteOutboundRtpStats (missing timestamp OR id OR ssrc OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`, stats);
}
observedRemoteOutboundRtp = new ObservedRemoteOutboundRtp_1.ObservedRemoteOutboundRtp(stats.timestamp, stats.id, stats.ssrc, stats.kind, this);
observedRemoteOutboundRtp.update(stats);
this.observedRemoteOutboundRtps.set(stats.ssrc, observedRemoteOutboundRtp);
this.emit('added-remote-outbound-rtp', observedRemoteOutboundRtp);
}
else {
observedRemoteOutboundRtp.update(stats);
}
this.emit('updated-remote-outbound-rtp', observedRemoteOutboundRtp);
return observedRemoteOutboundRtp;
}
}
exports.ObservedPeerConnection = ObservedPeerConnection;