diff --git a/package.json b/package.json index 53edc4a..14adb1e 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { "name": "@observertc/client-monitor-js", - "version": "3.2.0", + "version": "3.3.0", "description": "ObserveRTC Client Integration Javascript Library", "main": "lib/index.js", "types": "lib/index.d.ts", "engines": { "node": ">=10" }, - "files":[ + "files": [ "lib" ], "scripts": { diff --git a/src/detectors/CongestionDetector.ts b/src/detectors/CongestionDetector.ts index 2a88a0e..5bdcdc5 100644 --- a/src/detectors/CongestionDetector.ts +++ b/src/detectors/CongestionDetector.ts @@ -68,11 +68,11 @@ export function createCongestionDetector(config: CongestionDetectorConfig & { const peerConnectionStates = new Map(); const isCongested = (now: number, state: PeerConnectionState, peerConnection: PeerConnectionEntry): boolean => { const { - totalInboundPacketsLost = 0, - totalInboundPacketsReceived = 0, + deltaInboundPacketsLost: totalInboundPacketsLost = 0, + deltaInboundPacketsReceived: totalInboundPacketsReceived = 0, avgRttInS = -1, - totalOutboundPacketsSent = 0, - totalOutboundPacketsLost = 0, + deltaOutboundPacketsSent: totalOutboundPacketsSent = 0, + deltaOutboundPacketsLost: totalOutboundPacketsLost = 0, } = peerConnection; if (state.congested !== undefined && (now - state.congested) < config.minDurationThresholdInMs) { diff --git a/src/entries/PeerConnectionEntryManifest.ts b/src/entries/PeerConnectionEntryManifest.ts index 149a3fa..9d54a9e 100644 --- a/src/entries/PeerConnectionEntryManifest.ts +++ b/src/entries/PeerConnectionEntryManifest.ts @@ -37,11 +37,31 @@ interface InnerOutboundRtpEntry extends OutboundRtpEntry { export class PeerConnectionEntryManifest implements PeerConnectionEntry { - public totalInboundPacketsLost?: number; - public totalInboundPacketsReceived?: number; - public totalOutboundPacketsLost?: number; - public totalOutbounPacketsReceived?: number; - public totalOutboundPacketsSent?: number; + public totalInboundPacketsLost = 0; + public totalInboundPacketsReceived = 0; + public totalOutboundPacketsLost = 0; + public totalOutboundPacketsReceived = 0; + public totalOutboundPacketsSent = 0; + public totalDataChannelBytesSent = 0; + public totalDataChannelBytesReceived = 0; + public totalSentAudioBytes = 0; + public totalSentVideoBytes = 0; + public totalReceivedAudioBytes = 0; + public totalReceivedVideoBytes = 0; + + public deltaInboundPacketsLost?: number; + public deltaInboundPacketsReceived?: number; + public deltaOutboundPacketsLost?: number; + public deltaOutboundPacketsReceived?: number; + public deltaOutboundPacketsSent?: number; + public deltaDataChannelBytesSent?: number; + public deltaDataChannelBytesReceived?: number; + public deltaReceivedAudioBytes?: number; + public deltaReceivedVideoBytes?: number; + public deltaSentAudioBytes?: number; + public deltaSentVideoBytes?: number; + + public avgRttInS?: number; public sendingAudioBitrate?: number; public sendingVideoBitrate?: number; @@ -266,6 +286,7 @@ export class PeerConnectionEntryManifest implements PeerConnectionEntry { entry.avgJitterBufferDelayInMs = (((stats.jitterBufferDelay ?? 0) - (entry.stats.jitterBufferDelay ?? 0)) / ((Math.max(stats.jitterBufferEmittedCount ?? 1, 1)) - (entry.stats.jitterBufferEmittedCount ?? 0))) * 1000.0; entry.receivedPackets = (stats.packetsReceived ?? 0) - (entry.stats.packetsReceived ?? 0); entry.receivingBitrate = (((stats.bytesReceived ?? 0) - (entry.stats.bytesReceived ?? 0)) * 8) / elapsedTimeInSec; + entry.receivedBytes = ((stats.bytesReceived ?? 0) - (entry.stats.bytesReceived ?? 0)); entry.lostPackets = (stats.packetsLost ?? 0) - (entry.stats.packetsLost ?? 0); entry.receivedFrames = (stats.framesReceived ?? 0) - (entry.stats.framesReceived ?? 0); entry.decodedFrames = (stats.framesDecoded ?? 0) - (entry.stats.framesDecoded ?? 0); @@ -308,6 +329,7 @@ export class PeerConnectionEntryManifest implements PeerConnectionEntry { this._emitter.emit('outbound-rtp-added', entry); } const elapsedTimeInSec = (stats.timestamp - entry.stats.timestamp) / 1000.0; + entry.sentBytes = Math.max(0, ((stats.bytesSent ?? 0) - (entry.stats.bytesSent ?? 0))); entry.sendingBitrate = (((stats.bytesSent ?? 0) - (entry.stats.bytesSent ?? 0)) * 8) / elapsedTimeInSec; entry.sentPackets = (stats.packetsSent ?? 0) - (entry.stats.packetsSent ?? 0); entry.stats = stats; @@ -321,7 +343,7 @@ export class PeerConnectionEntryManifest implements PeerConnectionEntry { this._remoteInboundRtps.set(stats.id, entry); this._emitter.emit('remote-inbound-rtp-added', entry); } - entry.receivedPackets = (stats.packetsReceived ?? 0) - (entry.stats.packetsReceived ?? 0); + entry.receivedPackets = Math.max(0, (stats.packetsReceived ?? 0) - (entry.stats.packetsReceived ?? 0)); entry.lostPackets = (stats.packetsLost ?? 0) - (entry.stats.packetsLost ?? 0); entry.stats = stats; entry.visited = true; @@ -480,48 +502,63 @@ export class PeerConnectionEntryManifest implements PeerConnectionEntry { } private _updateMetrics() { - this.totalInboundPacketsLost = 0; - this.totalInboundPacketsReceived = 0; - this.totalOutboundPacketsLost = 0; - this.totalOutbounPacketsReceived = 0; - this.totalOutboundPacketsSent = 0; + this.deltaInboundPacketsLost = 0; + this.deltaInboundPacketsReceived = 0; + this.deltaOutboundPacketsLost = 0; + this.deltaOutboundPacketsReceived = 0; + this.deltaOutboundPacketsSent = 0; this.sendingAudioBitrate = 0; this.sendingVideoBitrate = 0; this.receivingAudioBitrate = 0; this.receivingVideoBitrate = 0; + this.deltaDataChannelBytesSent = 0; + this.deltaDataChannelBytesReceived = 0; + this.deltaReceivedAudioBytes = 0; + this.deltaReceivedVideoBytes = 0; + this.deltaSentAudioBytes = 0; + this.deltaSentVideoBytes = 0; + const roundTripTimesInS = []; for (const inboundRtpEntry of this.inboundRtps()) { if (inboundRtpEntry.stats.kind === 'audio') { this.receivingAudioBitrate += inboundRtpEntry.receivingBitrate ?? 0; + this.deltaReceivedAudioBytes += inboundRtpEntry.receivedBytes ?? 0; } else if (inboundRtpEntry.stats.kind === 'video') { this.receivingVideoBitrate += inboundRtpEntry.receivingBitrate ?? 0; + this.deltaReceivedVideoBytes += inboundRtpEntry.receivedBytes ?? 0; } - this.totalInboundPacketsLost += inboundRtpEntry.lostPackets ?? 0; - this.totalInboundPacketsReceived += inboundRtpEntry.receivedPackets ?? 0; + this.deltaInboundPacketsLost += inboundRtpEntry.lostPackets ?? 0; + this.deltaInboundPacketsReceived += inboundRtpEntry.receivedPackets ?? 0; } for (const remoteInboundRtpEntry of this.remoteInboundRtps()) { - this.totalOutboundPacketsLost += remoteInboundRtpEntry.stats.packetsLost ?? 0; - this.totalOutbounPacketsReceived += remoteInboundRtpEntry.stats.packetsReceived ?? 0; + this.deltaOutboundPacketsLost += remoteInboundRtpEntry.stats.packetsLost ?? 0; + this.deltaOutboundPacketsReceived += remoteInboundRtpEntry.stats.packetsReceived ?? 0; } + this.totalInboundPacketsLost += this.deltaInboundPacketsLost; + this.totalInboundPacketsReceived += this.deltaInboundPacketsReceived; + this.totalOutboundPacketsLost += this.deltaOutboundPacketsLost; + this.totalOutboundPacketsReceived += this.deltaOutboundPacketsReceived; + this.totalReceivedAudioBytes += this.deltaReceivedAudioBytes; + this.totalReceivedVideoBytes += this.deltaReceivedVideoBytes; for (const remoteInboundRtpEntry of this.remoteInboundRtps()) { const { roundTripTime } = remoteInboundRtpEntry.stats; - if (roundTripTime) { + if (roundTripTime && 0 < roundTripTime) { roundTripTimesInS.push(roundTripTime) } } for (const remoteOutboundRtp of this.remoteOutboundRtps()) { const { roundTripTime } = remoteOutboundRtp.stats; - if (roundTripTime) { + if (roundTripTime && 0 < roundTripTime) { roundTripTimesInS.push(roundTripTime) } } for (const iceCandidatePair of this.iceCandidatePairs()) { const { currentRoundTripTime } = iceCandidatePair.stats; - if (currentRoundTripTime) { + if (currentRoundTripTime && 0 < currentRoundTripTime) { roundTripTimesInS.push(currentRoundTripTime) } } @@ -530,13 +567,24 @@ export class PeerConnectionEntryManifest implements PeerConnectionEntry { for (const outboundRtpEntry of this._outboundRtps.values()) { if (outboundRtpEntry.stats.kind === 'audio') { this.sendingAudioBitrate += outboundRtpEntry.sendingBitrate ?? 0; + this.deltaSentAudioBytes += outboundRtpEntry.sentBytes ?? 0; } else if (outboundRtpEntry.stats.kind === 'video') { this.sendingVideoBitrate += outboundRtpEntry.sendingBitrate ?? 0; + this.deltaSentVideoBytes += outboundRtpEntry.sentBytes ?? 0; } - this.totalOutboundPacketsSent += outboundRtpEntry.sentPackets ?? 0; + this.deltaOutboundPacketsSent += outboundRtpEntry.sentPackets ?? 0; outboundRtpEntry.updateStabilityScore(avgRttInS); } + this.totalOutboundPacketsSent += this.deltaOutboundPacketsSent; + this.totalSentAudioBytes += this.deltaSentAudioBytes; + this.totalSentVideoBytes += this.deltaSentVideoBytes; + for (const dataChannelEntry of this.dataChannels()) { + this.deltaDataChannelBytesSent += dataChannelEntry.stats.bytesSent ?? 0; + this.deltaDataChannelBytesReceived += dataChannelEntry.stats.bytesReceived ?? 0; + } + this.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived; + this.totalDataChannelBytesSent += this.deltaDataChannelBytesSent; this.avgRttInS = avgRttInS; } diff --git a/src/entries/StatsEntryInterfaces.ts b/src/entries/StatsEntryInterfaces.ts index c09cf61..fce8cb5 100644 --- a/src/entries/StatsEntryInterfaces.ts +++ b/src/entries/StatsEntryInterfaces.ts @@ -68,6 +68,7 @@ export interface InboundRtpEntry extends ReceivedRtpStreamEntry, StatsEntryAbs { score?: number, avgJitterBufferDelayInMs?: number, receivingBitrate?: number, + receivedBytes?: number, lostPackets?: number, receivedPackets?: number, receivedFrames?: number, @@ -107,6 +108,7 @@ export interface OutboundRtpEntry extends SenderRtpStreamEntry, StatsEntryAbs { // calculated fields score?: number; sendingBitrate?: number, + sentBytes?: number, sentPackets?: number, /** * Gets the SSRC of the Rtp session @@ -324,11 +326,30 @@ export interface PeerConnectionEntry { readonly label: string | undefined; readonly events: TypedEvents; - readonly totalInboundPacketsLost?: number; - readonly totalInboundPacketsReceived?: number; - readonly totalOutboundPacketsLost?: number; - readonly totalOutbounPacketsReceived?: number; - readonly totalOutboundPacketsSent?: number; + readonly totalInboundPacketsLost: number; + readonly totalInboundPacketsReceived: number; + readonly totalOutboundPacketsLost: number; + readonly totalOutboundPacketsReceived: number; + readonly totalOutboundPacketsSent: number; + readonly totalSentAudioBytes: number; + readonly totalSentVideoBytes: number; + readonly totalReceivedAudioBytes: number; + readonly totalReceivedVideoBytes: number; + readonly totalDataChannelBytesSent: number; + readonly totalDataChannelBytesReceived: number; + + readonly deltaInboundPacketsLost?: number; + readonly deltaInboundPacketsReceived?: number; + readonly deltaOutboundPacketsLost?: number; + readonly deltaOutboundPacketsReceived?: number; + readonly deltaOutboundPacketsSent?: number; + readonly deltaSentAudioBytes?: number; + readonly deltaSentVideoBytes?: number; + readonly deltaReceivedAudioBytes?: number; + readonly deltaReceivedVideoBytes?: number; + readonly deltaDataChannelBytesSent?: number; + readonly deltaDataChannelBytesReceived?: number; + readonly avgRttInS?: number; readonly sendingAudioBitrate?: number; readonly sendingVideoBitrate?: number; diff --git a/src/entries/StatsStorage.ts b/src/entries/StatsStorage.ts index 864f0f6..03ab82d 100644 --- a/src/entries/StatsStorage.ts +++ b/src/entries/StatsStorage.ts @@ -44,11 +44,30 @@ export class StatsStorage { public sendingVideoBitrate?: number; public receivingAudioBitrate?: number; public receivingVideoBitrate?: number; - public totalInboundPacketsLost?: number; - public totalInboundPacketsReceived?: number; - public totalOutboundPacketsSent?: number; - public totalOutbounPacketsReceived?: number; - public totalOutboundPacketsLost?: number; + + public totalInboundPacketsLost = 0; + public totalInboundPacketsReceived = 0; + public totalOutboundPacketsSent = 0; + public totalOutbounPacketsReceived = 0; + public totalOutboundPacketsLost = 0; + public totalDataChannelBytesSent = 0; + public totalDataChannelBytesReceived = 0; + public totalSentAudioBytes = 0; + public totalSentVideoBytes = 0; + public totalReceivedAudioBytes = 0; + public totalReceivedVideoBytes = 0; + + public deltaInboundPacketsLost?: number; + public deltaInboundPacketsReceived?: number; + public deltaOutboundPacketsSent?: number; + public deltaOutbounPacketsReceived?: number; + public deltaOutboundPacketsLost?: number; + public deltaDataChannelBytesSent?: number; + public deltaDataChannelBytesReceived?: number; + public deltaSentAudioBytes?: number; + public deltaSentVideoBytes?: number; + public deltaReceivedAudioBytes?: number; + public deltaReceivedVideoBytes?: number; public totalAvailableIncomingBitrate?: number; public totalAvailableOutgoingBitrate?: number; public avgRttInS?: number; @@ -447,11 +466,18 @@ export class StatsStorage { this.sendingVideoBitrate = 0; this.receivingAudioBitrate = 0; this.receivingVideoBitrate = 0; - this.totalInboundPacketsLost = 0; - this.totalInboundPacketsReceived = 0; - this.totalOutboundPacketsSent = 0; - this.totalOutbounPacketsReceived = 0; - this.totalOutboundPacketsLost = 0; + + this.deltaInboundPacketsLost = 0; + this.deltaInboundPacketsReceived = 0; + this.deltaOutboundPacketsSent = 0; + this.deltaOutbounPacketsReceived = 0; + this.deltaOutboundPacketsLost = 0; + this.deltaDataChannelBytesSent = 0; + this.deltaDataChannelBytesReceived = 0; + this.deltaSentAudioBytes = 0; + this.deltaSentVideoBytes = 0; + this.deltaReceivedAudioBytes = 0; + this.deltaReceivedVideoBytes = 0; this.totalAvailableIncomingBitrate = 0; this.totalAvailableOutgoingBitrate = 0; for (const peerConnectionEntry of this._peerConnections.values()) { @@ -465,12 +491,30 @@ export class StatsStorage { this.sendingVideoBitrate += peerConnectionEntry.sendingVideoBitrate ?? 0; this.receivingAudioBitrate += peerConnectionEntry.receivingAudioBitrate ?? 0; this.receivingVideoBitrate += peerConnectionEntry.receivingVideoBitrate ?? 0; - this.totalInboundPacketsLost += peerConnectionEntry.totalInboundPacketsLost ?? 0; - this.totalInboundPacketsReceived += peerConnectionEntry.totalInboundPacketsReceived ?? 0; - this.totalOutboundPacketsSent += peerConnectionEntry.totalOutboundPacketsSent ?? 0; - this.totalOutbounPacketsReceived += peerConnectionEntry.totalOutbounPacketsReceived ?? 0; - this.totalOutboundPacketsLost += peerConnectionEntry.totalOutboundPacketsLost ?? 0; + this.deltaDataChannelBytesSent += peerConnectionEntry.deltaDataChannelBytesSent ?? 0; + this.deltaDataChannelBytesReceived += peerConnectionEntry.deltaDataChannelBytesReceived ?? 0; + this.deltaInboundPacketsLost += peerConnectionEntry.deltaInboundPacketsLost ?? 0; + this.deltaInboundPacketsReceived += peerConnectionEntry.deltaInboundPacketsReceived ?? 0; + this.deltaOutboundPacketsSent += peerConnectionEntry.deltaOutboundPacketsSent ?? 0; + this.deltaOutbounPacketsReceived += peerConnectionEntry.deltaOutboundPacketsReceived ?? 0; + this.deltaOutboundPacketsLost += peerConnectionEntry.deltaOutboundPacketsLost ?? 0; + + this.deltaSentAudioBytes += peerConnectionEntry.deltaSentAudioBytes ?? 0; + this.deltaSentVideoBytes += peerConnectionEntry.deltaSentVideoBytes ?? 0; + this.deltaReceivedAudioBytes += peerConnectionEntry.deltaReceivedAudioBytes ?? 0; + this.deltaReceivedVideoBytes += peerConnectionEntry.deltaReceivedVideoBytes ?? 0; } + this.totalInboundPacketsLost += this.deltaInboundPacketsLost; + this.totalInboundPacketsReceived += this.deltaInboundPacketsReceived; + this.totalOutboundPacketsSent += this.deltaOutboundPacketsSent; + this.totalOutbounPacketsReceived += this.deltaOutbounPacketsReceived; + this.totalOutboundPacketsLost += this.deltaOutboundPacketsLost; + this.totalDataChannelBytesSent += this.deltaDataChannelBytesSent; + this.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived; + this.totalSentAudioBytes += this.deltaSentAudioBytes; + this.totalSentVideoBytes += this.deltaSentVideoBytes; + this.totalReceivedAudioBytes += this.deltaReceivedAudioBytes; + this.totalReceivedVideoBytes += this.deltaReceivedVideoBytes; this.highestSeenSendingBitrate = Math.max( this.highestSeenSendingBitrate ?? 0,