@observertc/observer-js 0.42.9 → 1.0.1-57a1811.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +6 -6
- package/README.md +0 -104
- package/lib/ObservedCall.d.ts +38 -41
- package/lib/ObservedCall.d.ts.map +1 -1
- package/lib/ObservedCall.js +97 -109
- package/lib/ObservedCertificate.d.ts +19 -0
- package/lib/ObservedCertificate.d.ts.map +1 -0
- package/lib/ObservedCertificate.js +38 -0
- package/lib/ObservedClient.d.ts +49 -127
- package/lib/ObservedClient.d.ts.map +1 -1
- package/lib/ObservedClient.js +201 -750
- package/lib/ObservedCodec.d.ts +22 -0
- package/lib/ObservedCodec.d.ts.map +1 -0
- package/lib/ObservedCodec.js +45 -0
- package/lib/ObservedDataChannel.d.ts +23 -69
- package/lib/ObservedDataChannel.d.ts.map +1 -1
- package/lib/ObservedDataChannel.js +67 -109
- package/lib/ObservedIceCandidate.d.ts +29 -0
- package/lib/ObservedIceCandidate.d.ts.map +1 -0
- package/lib/ObservedIceCandidate.js +59 -0
- package/lib/ObservedIceCandidatePair.d.ts +44 -0
- package/lib/ObservedIceCandidatePair.d.ts.map +1 -0
- package/lib/ObservedIceCandidatePair.js +111 -0
- package/lib/ObservedIceTransport.d.ts +32 -0
- package/lib/ObservedIceTransport.d.ts.map +1 -0
- package/lib/ObservedIceTransport.js +65 -0
- package/lib/ObservedInboundRtp.d.ts +92 -0
- package/lib/ObservedInboundRtp.d.ts.map +1 -0
- package/lib/ObservedInboundRtp.js +193 -0
- package/lib/ObservedInboundTrack.d.ts +29 -0
- package/lib/ObservedInboundTrack.d.ts.map +1 -0
- package/lib/ObservedInboundTrack.js +57 -0
- package/lib/ObservedMediaPlayout.d.ts +22 -0
- package/lib/ObservedMediaPlayout.d.ts.map +1 -0
- package/lib/ObservedMediaPlayout.js +42 -0
- package/lib/ObservedMediaSource.d.ts +28 -0
- package/lib/ObservedMediaSource.d.ts.map +1 -0
- package/lib/ObservedMediaSource.js +55 -0
- package/lib/ObservedOutboundRtp.d.ts +62 -0
- package/lib/ObservedOutboundRtp.d.ts.map +1 -0
- package/lib/ObservedOutboundRtp.js +144 -0
- package/lib/ObservedOutboundTrack.d.ts +29 -0
- package/lib/ObservedOutboundTrack.d.ts.map +1 -0
- package/lib/ObservedOutboundTrack.js +57 -0
- package/lib/ObservedPeerConnection.d.ts +128 -78
- package/lib/ObservedPeerConnection.d.ts.map +1 -1
- package/lib/ObservedPeerConnection.js +624 -357
- package/lib/ObservedPeerConnectionTransport.d.ts +17 -0
- package/lib/ObservedPeerConnectionTransport.d.ts.map +1 -0
- package/lib/ObservedPeerConnectionTransport.js +34 -0
- package/lib/ObservedRemoteInboundRtp.d.ts +30 -0
- package/lib/ObservedRemoteInboundRtp.d.ts.map +1 -0
- package/lib/ObservedRemoteInboundRtp.js +60 -0
- package/lib/ObservedRemoteOutboundRtp.d.ts +30 -0
- package/lib/ObservedRemoteOutboundRtp.d.ts.map +1 -0
- package/lib/ObservedRemoteOutboundRtp.js +60 -0
- package/lib/ObservedTURN.d.ts +31 -0
- package/lib/ObservedTURN.d.ts.map +1 -0
- package/lib/ObservedTURN.js +58 -0
- package/lib/ObservedTurnServer.d.ts +25 -0
- package/lib/ObservedTurnServer.d.ts.map +1 -0
- package/lib/ObservedTurnServer.js +59 -0
- package/lib/Observer.d.ts +31 -51
- package/lib/Observer.d.ts.map +1 -1
- package/lib/Observer.js +75 -229
- package/lib/common/Middleware.d.ts +10 -1
- package/lib/common/Middleware.d.ts.map +1 -1
- package/lib/common/Middleware.js +55 -36
- package/lib/common/logger.d.ts +8 -4
- package/lib/common/logger.d.ts.map +1 -1
- package/lib/common/logger.js +44 -68
- package/lib/common/types.d.ts +0 -21
- package/lib/common/types.d.ts.map +1 -1
- package/lib/common/types.js +1 -0
- package/lib/common/utils.d.ts +1 -0
- package/lib/common/utils.d.ts.map +1 -1
- package/lib/common/utils.js +13 -1
- package/lib/detectors/Detector.d.ts +5 -0
- package/lib/detectors/Detector.d.ts.map +1 -0
- package/lib/detectors/Detector.js +3 -0
- package/lib/detectors/Detectors.d.ts +11 -0
- package/lib/detectors/Detectors.d.ts.map +1 -0
- package/lib/detectors/Detectors.js +34 -0
- package/lib/index.d.ts +24 -25
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +41 -41
- package/lib/monitors/TurnUsageMonitor.d.ts +0 -52
- package/lib/monitors/TurnUsageMonitor.d.ts.map +1 -1
- package/lib/monitors/TurnUsageMonitor.js +145 -120
- package/lib/schema/ClientEventTypes.d.ts +33 -0
- package/lib/schema/ClientEventTypes.d.ts.map +1 -0
- package/lib/schema/ClientEventTypes.js +38 -0
- package/lib/schema/ClientMetaTypes.d.ts +34 -0
- package/lib/schema/ClientMetaTypes.d.ts.map +1 -0
- package/lib/schema/ClientMetaTypes.js +16 -0
- package/lib/schema/ClientSample.d.ts +1333 -0
- package/lib/schema/ClientSample.d.ts.map +1 -0
- package/lib/schema/ClientSample.js +4 -0
- package/lib/scores/CalculatedScore.d.ts +6 -0
- package/lib/scores/CalculatedScore.d.ts.map +1 -0
- package/lib/scores/DefaultCallScoreCalculator.d.ts +7 -0
- package/lib/scores/DefaultCallScoreCalculator.d.ts.map +1 -0
- package/lib/scores/DefaultCallScoreCalculator.js +21 -0
- package/lib/scores/ScoreCalculator.d.ts +4 -0
- package/lib/scores/ScoreCalculator.d.ts.map +1 -0
- package/lib/scores/ScoreCalculator.js +2 -0
- package/lib/utils/CallUpdater.d.ts +5 -0
- package/lib/utils/CallUpdater.d.ts.map +1 -0
- package/lib/utils/CallUpdater.js +2 -0
- package/lib/utils/OnAllClientCallUpdater.d.ts +16 -0
- package/lib/utils/OnAllClientCallUpdater.d.ts.map +1 -0
- package/lib/utils/OnAllClientCallUpdater.js +58 -0
- package/lib/utils/RemoteTrackResolver.d.ts +7 -0
- package/lib/utils/RemoteTrackResolver.d.ts.map +1 -0
- package/lib/utils/RemoteTrackResolver.js +2 -0
- package/lib/utils/onAnyClientCallUpdater.d.ts +14 -0
- package/lib/utils/onAnyClientCallUpdater.d.ts.map +1 -0
- package/lib/utils/onAnyClientCallUpdater.js +51 -0
- package/package.json +4 -4
- package/src/ObservedCall.ts +116 -166
- package/src/ObservedCertificate.ts +43 -0
- package/src/ObservedClient.ts +213 -1060
- package/src/ObservedCodec.ts +49 -0
- package/src/ObservedDataChannel.ts +68 -181
- package/src/ObservedIceCandidate.ts +64 -0
- package/src/ObservedIceCandidatePair.ts +118 -0
- package/src/ObservedIceTransport.ts +70 -0
- package/src/ObservedInboundRtp.ts +205 -0
- package/src/ObservedInboundTrack.ts +70 -0
- package/src/ObservedMediaPlayout.ts +49 -0
- package/src/ObservedMediaSource.ts +60 -0
- package/src/ObservedOutboundRtp.ts +156 -0
- package/src/ObservedOutboundTrack.ts +69 -0
- package/src/ObservedPeerConnection.ts +827 -405
- package/src/ObservedPeerConnectionTransport.ts +38 -0
- package/src/ObservedRemoteInboundRtp.ts +64 -0
- package/src/ObservedRemoteOutboundRtp.ts +65 -0
- package/src/ObservedTURN.ts +86 -0
- package/src/ObservedTurnServer.ts +72 -0
- package/src/Observer.ts +91 -302
- package/src/common/Middleware.ts +70 -42
- package/src/common/logger.ts +60 -69
- package/src/common/types.ts +0 -42
- package/src/common/utils.ts +12 -0
- package/src/detectors/Detector.ts +6 -0
- package/src/detectors/Detectors.ts +38 -0
- package/src/index.ts +24 -90
- package/src/monitors/TurnUsageMonitor.ts +164 -164
- package/src/schema/ClientEventTypes.ts +36 -0
- package/src/schema/ClientMetaTypes.ts +41 -0
- package/src/schema/ClientSample.ts +1682 -0
- package/src/scores/CalculatedScore.ts +6 -0
- package/src/scores/DefaultCallScoreCalculator.ts +23 -0
- package/src/scores/ScoreCalculator.ts +3 -0
- package/src/utils/CallUpdater.ts +5 -0
- package/src/utils/OnAllClientCallUpdater.ts +68 -0
- package/src/utils/RemoteTrackResolver.ts +12 -0
- package/src/utils/onAnyClientCallUpdater.ts +59 -0
- package/tsconfig.json +3 -3
- package/lib/ObservedICE.d.ts +0 -64
- package/lib/ObservedICE.d.ts.map +0 -1
- package/lib/ObservedICE.js +0 -141
- package/lib/ObservedInboundAudioTrack.d.ts +0 -96
- package/lib/ObservedInboundAudioTrack.d.ts.map +0 -1
- package/lib/ObservedInboundAudioTrack.js +0 -217
- package/lib/ObservedInboundVideoTrack.d.ts +0 -101
- package/lib/ObservedInboundVideoTrack.d.ts.map +0 -1
- package/lib/ObservedInboundVideoTrack.js +0 -232
- package/lib/ObservedOutboundAudioTrack.d.ts +0 -87
- package/lib/ObservedOutboundAudioTrack.d.ts.map +0 -1
- package/lib/ObservedOutboundAudioTrack.js +0 -186
- package/lib/ObservedOutboundVideoTrack.d.ts +0 -91
- package/lib/ObservedOutboundVideoTrack.d.ts.map +0 -1
- package/lib/ObservedOutboundVideoTrack.js +0 -193
- package/lib/ObservedSfu.d.ts +0 -59
- package/lib/ObservedSfu.d.ts.map +0 -1
- package/lib/ObservedSfu.js +0 -157
- package/lib/ObservedSfuInboundRtpPad.d.ts +0 -42
- package/lib/ObservedSfuInboundRtpPad.d.ts.map +0 -1
- package/lib/ObservedSfuInboundRtpPad.js +0 -71
- package/lib/ObservedSfuOutboundRtpPad.d.ts +0 -42
- package/lib/ObservedSfuOutboundRtpPad.d.ts.map +0 -1
- package/lib/ObservedSfuOutboundRtpPad.js +0 -72
- package/lib/ObservedSfuSctpChannel.d.ts +0 -42
- package/lib/ObservedSfuSctpChannel.d.ts.map +0 -1
- package/lib/ObservedSfuSctpChannel.js +0 -57
- package/lib/ObservedSfuTransport.d.ts +0 -58
- package/lib/ObservedSfuTransport.d.ts.map +0 -1
- package/lib/ObservedSfuTransport.js +0 -120
- package/lib/RemoteTrackAssigner.d.ts +0 -14
- package/lib/RemoteTrackAssigner.d.ts.map +0 -1
- package/lib/RemoteTrackAssigner.js +0 -52
- package/lib/ReportsCollector.d.ts +0 -109
- package/lib/ReportsCollector.d.ts.map +0 -1
- package/lib/ReportsCollector.js +0 -207
- package/lib/common/CalculatedScore.d.ts +0 -80
- package/lib/common/CalculatedScore.d.ts.map +0 -1
- package/lib/common/CalculatedScore.js +0 -162
- package/lib/common/CallEventType.d.ts +0 -63
- package/lib/common/CallEventType.d.ts.map +0 -1
- package/lib/common/CallEventType.js +0 -39
- package/lib/common/CallMetaReports.d.ts +0 -42
- package/lib/common/CallMetaReports.d.ts.map +0 -1
- package/lib/common/CallMetaReports.js +0 -36
- package/lib/common/QualityScoreUtils.d.ts +0 -1
- package/lib/common/QualityScoreUtils.d.ts.map +0 -1
- package/lib/common/QualityScoreUtils.js +0 -1
- package/lib/common/TypedEventEmitter.d.ts +0 -22
- package/lib/common/TypedEventEmitter.d.ts.map +0 -1
- package/lib/common/TypedEventEmitter.js +0 -11
- package/lib/common/callEventReports.d.ts +0 -10
- package/lib/common/callEventReports.d.ts.map +0 -1
- package/lib/common/callEventReports.js +0 -112
- package/lib/monitors/CallSummary.d.ts +0 -37
- package/lib/monitors/CallSummary.d.ts.map +0 -1
- package/lib/monitors/CallSummaryMonitor.d.ts +0 -32
- package/lib/monitors/CallSummaryMonitor.d.ts.map +0 -1
- package/lib/monitors/CallSummaryMonitor.js +0 -152
- package/lib/monitors/ClientIssueMonitor.d.ts +0 -32
- package/lib/monitors/ClientIssueMonitor.d.ts.map +0 -1
- package/lib/monitors/ClientIssueMonitor.js +0 -49
- package/lib/monitors/SfuServerMonitor.d.ts +0 -79
- package/lib/monitors/SfuServerMonitor.d.ts.map +0 -1
- package/lib/monitors/SfuServerMonitor.js +0 -198
- package/src/ObservedICE.ts +0 -237
- package/src/ObservedInboundAudioTrack.ts +0 -344
- package/src/ObservedInboundVideoTrack.ts +0 -361
- package/src/ObservedOutboundAudioTrack.ts +0 -307
- package/src/ObservedOutboundVideoTrack.ts +0 -319
- package/src/ObservedSfu.ts +0 -231
- package/src/ObservedSfuInboundRtpPad.ts +0 -106
- package/src/ObservedSfuOutboundRtpPad.ts +0 -107
- package/src/ObservedSfuSctpChannel.ts +0 -103
- package/src/ObservedSfuTransport.ts +0 -185
- package/src/RemoteTrackAssigner.ts +0 -68
- package/src/ReportsCollector.ts +0 -336
- package/src/common/CalculatedScore.ts +0 -188
- package/src/common/CallEventType.ts +0 -69
- package/src/common/CallMetaReports.ts +0 -82
- package/src/common/QualityScoreUtils.ts +0 -0
- package/src/common/TypedEventEmitter.ts +0 -32
- package/src/common/callEventReports.ts +0 -178
- package/src/monitors/CallSummary.ts +0 -38
- package/src/monitors/CallSummaryMonitor.ts +0 -192
- package/src/monitors/ClientIssueMonitor.ts +0 -88
- package/src/monitors/SfuServerMonitor.ts +0 -285
- /package/lib/{monitors/CallSummary.js → scores/CalculatedScore.js} +0 -0
|
@@ -1,65 +1,121 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
import { PeerConnectionTransport } from '@observertc/sample-schemas-js';
|
|
3
2
|
import { ObservedClient } from './ObservedClient';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { CertificateStats, CodecStats, DataChannelStats, IceCandidateStats, InboundRtpStats, InboundTrackSample, MediaPlayoutStats, MediaSourceStats, OutboundRtpStats, OutboundTrackSample, PeerConnectionSample, PeerConnectionTransportStats, RemoteInboundRtpStats, RemoteOutboundRtpStats } from './schema/ClientSample';
|
|
4
|
+
import { ObservedInboundRtp } from './ObservedInboundRtp';
|
|
5
|
+
import { createLogger } from './common/logger';
|
|
6
|
+
import { MediaKind } from './common/types';
|
|
7
|
+
import { ObservedOutboundRtp } from './ObservedOutboundRtp';
|
|
8
|
+
import { ObservedCertificate } from './ObservedCertificate';
|
|
9
|
+
import { ObservedCodec } from './ObservedCodec';
|
|
6
10
|
import { ObservedDataChannel } from './ObservedDataChannel';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
11
|
+
import { ObservedIceCandidate } from './ObservedIceCandidate';
|
|
12
|
+
import { ObservedIceCandidatePair } from './ObservedIceCandidatePair';
|
|
13
|
+
import { ObservedIceTransport } from './ObservedIceTransport';
|
|
14
|
+
import { ObservedMediaSource } from './ObservedMediaSource';
|
|
15
|
+
import { ObservedPeerConnectionTransport } from './ObservedPeerConnectionTransport';
|
|
16
|
+
import { ObservedMediaPlayout } from './ObservedMediaPlayout';
|
|
17
|
+
import { ObservedRemoteInboundRtp } from './ObservedRemoteInboundRtp';
|
|
18
|
+
import { ObservedRemoteOutboundRtp } from './ObservedRemoteOutboundRtp';
|
|
19
|
+
import { ObservedInboundTrack } from './ObservedInboundTrack';
|
|
20
|
+
import { ObservedOutboundTrack } from './ObservedOutboundTrack';
|
|
21
|
+
import { CalculatedScore } from './scores/CalculatedScore';
|
|
22
|
+
import { ObservedTurnServer } from './ObservedTurnServer';
|
|
23
|
+
|
|
24
|
+
const logger = createLogger('ObservedPeerConnection');
|
|
14
25
|
|
|
15
26
|
export type ObservedPeerConnectionEvents = {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
iceconnectionstatechange: [
|
|
28
|
+
{
|
|
29
|
+
state: string;
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
icegatheringstatechange: [
|
|
33
|
+
{
|
|
34
|
+
state: string;
|
|
35
|
+
}
|
|
36
|
+
];
|
|
37
|
+
connectionstatechange: [
|
|
38
|
+
{
|
|
39
|
+
state: string;
|
|
40
|
+
}
|
|
41
|
+
];
|
|
42
|
+
selectedcandidatepair: [];
|
|
43
|
+
|
|
44
|
+
'added-certificate': [ObservedCertificate];
|
|
45
|
+
'added-codec': [ObservedCodec];
|
|
46
|
+
'added-data-channel': [ObservedDataChannel];
|
|
47
|
+
'added-ice-candidate': [ObservedIceCandidate];
|
|
48
|
+
'added-ice-candidate-pair': [ObservedIceCandidatePair];
|
|
49
|
+
'added-ice-transport': [ObservedIceTransport];
|
|
50
|
+
'added-inbound-rtp': [ObservedInboundRtp];
|
|
51
|
+
'added-inbound-track': [ObservedInboundTrack];
|
|
52
|
+
'added-media-playout': [ObservedMediaPlayout];
|
|
53
|
+
'added-media-source': [ObservedMediaSource];
|
|
54
|
+
'added-outbound-rtp': [ObservedOutboundRtp];
|
|
55
|
+
'added-outbound-track': [ObservedOutboundTrack];
|
|
56
|
+
'added-peer-connection-transport': [ObservedPeerConnectionTransport];
|
|
57
|
+
'added-remote-inbound-rtp': [ObservedRemoteInboundRtp];
|
|
58
|
+
'added-remote-outbound-rtp': [ObservedRemoteOutboundRtp];
|
|
59
|
+
'removed-certificate': [ObservedCertificate];
|
|
60
|
+
'removed-codec': [ObservedCodec];
|
|
61
|
+
'removed-data-channel': [ObservedDataChannel];
|
|
62
|
+
'removed-ice-candidate': [ObservedIceCandidate];
|
|
63
|
+
'removed-ice-candidate-pair': [ObservedIceCandidatePair];
|
|
64
|
+
'removed-ice-transport': [ObservedIceTransport];
|
|
65
|
+
'removed-inbound-rtp': [ObservedInboundRtp];
|
|
66
|
+
'removed-inbound-track': [ObservedInboundTrack];
|
|
67
|
+
'removed-media-playout': [ObservedMediaPlayout];
|
|
68
|
+
'removed-media-source': [ObservedMediaSource];
|
|
69
|
+
'removed-outbound-rtp': [ObservedOutboundRtp];
|
|
70
|
+
'removed-outbound-track': [ObservedOutboundTrack];
|
|
71
|
+
'removed-peer-connection-transport': [ObservedPeerConnectionTransport];
|
|
72
|
+
'removed-remote-inbound-rtp': [ObservedRemoteInboundRtp];
|
|
73
|
+
'removed-remote-outbound-rtp': [ObservedRemoteOutboundRtp];
|
|
74
|
+
'update': [],
|
|
75
|
+
close: [];
|
|
31
76
|
};
|
|
32
77
|
|
|
33
|
-
export type ObservedPeerConnectionStats = Omit<PeerConnectionTransport, 'transportId' | 'label'>;
|
|
34
|
-
|
|
35
78
|
export declare interface ObservedPeerConnection {
|
|
36
|
-
on<U extends keyof ObservedPeerConnectionEvents>(
|
|
37
|
-
|
|
38
|
-
|
|
79
|
+
on<U extends keyof ObservedPeerConnectionEvents>(
|
|
80
|
+
event: U,
|
|
81
|
+
listener: (...args: ObservedPeerConnectionEvents[U]) => void
|
|
82
|
+
): this;
|
|
83
|
+
off<U extends keyof ObservedPeerConnectionEvents>(
|
|
84
|
+
event: U,
|
|
85
|
+
listener: (...args: ObservedPeerConnectionEvents[U]) => void
|
|
86
|
+
): this;
|
|
87
|
+
once<U extends keyof ObservedPeerConnectionEvents>(
|
|
88
|
+
event: U,
|
|
89
|
+
listener: (...args: ObservedPeerConnectionEvents[U]) => void
|
|
90
|
+
): this;
|
|
39
91
|
emit<U extends keyof ObservedPeerConnectionEvents>(event: U, ...args: ObservedPeerConnectionEvents[U]): boolean;
|
|
40
92
|
}
|
|
41
93
|
|
|
42
94
|
export class ObservedPeerConnection extends EventEmitter {
|
|
43
|
-
|
|
44
|
-
public visited = true;
|
|
95
|
+
private _visited = true;
|
|
45
96
|
|
|
97
|
+
public appData?: Record<string, unknown>;
|
|
98
|
+
public readonly calculatedScore: CalculatedScore = {
|
|
99
|
+
weight: 1,
|
|
100
|
+
value: undefined,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
public closed = false;
|
|
46
104
|
// timestamp of the PEER_CONNECTION_OPENED event
|
|
47
|
-
public
|
|
105
|
+
public openedAt?: number;
|
|
48
106
|
// timestamp of the PEER_CONNECTION_CLOSED event
|
|
49
|
-
public
|
|
50
|
-
|
|
51
|
-
private _elapsedTimeSinceLastUpdate?: number;
|
|
52
|
-
private _statsTimestamp?: number;
|
|
53
|
-
private _stabilityScores: number[] = [];
|
|
107
|
+
public closedAt?: number;
|
|
108
|
+
public updated = Date.now();
|
|
54
109
|
|
|
55
|
-
public
|
|
56
|
-
|
|
57
|
-
public score?: CalculatedScore;
|
|
110
|
+
public availableIncomingBitrate = 0;
|
|
111
|
+
public availableOutgoingBitrate = 0;
|
|
58
112
|
public totalInboundPacketsLost = 0;
|
|
59
113
|
public totalInboundPacketsReceived = 0;
|
|
60
114
|
public totalOutboundPacketsSent = 0;
|
|
61
115
|
public totalDataChannelBytesSent = 0;
|
|
62
116
|
public totalDataChannelBytesReceived = 0;
|
|
117
|
+
public totalDataChannelMessagesSent = 0;
|
|
118
|
+
public totalDataChannelMessagesReceived = 0;
|
|
63
119
|
|
|
64
120
|
public totalSentAudioBytes = 0;
|
|
65
121
|
public totalSentVideoBytes = 0;
|
|
@@ -75,182 +131,161 @@ export class ObservedPeerConnection extends EventEmitter {
|
|
|
75
131
|
public deltaOutboundPacketsSent = 0;
|
|
76
132
|
public deltaDataChannelBytesSent = 0;
|
|
77
133
|
public deltaDataChannelBytesReceived = 0;
|
|
134
|
+
public deltaDataChannelMessagesSent = 0;
|
|
135
|
+
public deltaDataChannelMessagesReceived = 0;
|
|
78
136
|
public deltaInboundReceivedBytes = 0;
|
|
79
137
|
public deltaOutboundSentBytes = 0;
|
|
80
|
-
|
|
138
|
+
|
|
81
139
|
public deltaReceivedAudioBytes = 0;
|
|
82
140
|
public deltaReceivedVideoBytes = 0;
|
|
83
141
|
public deltaReceivedAudioPackets = 0;
|
|
84
142
|
public deltaReceivedVideoPackets = 0;
|
|
85
143
|
public deltaSentAudioBytes = 0;
|
|
86
144
|
public deltaSentVideoBytes = 0;
|
|
145
|
+
|
|
87
146
|
public receivingPacketsPerSecond = 0;
|
|
88
147
|
public sendingPacketsPerSecond = 0;
|
|
89
148
|
public sendingAudioBitrate = 0;
|
|
90
149
|
public sendingVideoBitrate = 0;
|
|
91
150
|
public receivingAudioBitrate = 0;
|
|
92
151
|
public receivingVideoBitrate = 0;
|
|
93
|
-
|
|
152
|
+
|
|
94
153
|
public avgRttInMs?: number;
|
|
95
154
|
public avgJitter?: number;
|
|
96
155
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
public readonly
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
public
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
)
|
|
156
|
+
public usingTCP = false;
|
|
157
|
+
public usingTURN = false;
|
|
158
|
+
|
|
159
|
+
public observedTurnServer?: ObservedTurnServer;
|
|
160
|
+
public readonly observedCertificates = new Map<string, ObservedCertificate>();
|
|
161
|
+
public readonly observedCodecs = new Map<string, ObservedCodec>();
|
|
162
|
+
public readonly observedDataChannels = new Map<string, ObservedDataChannel>();
|
|
163
|
+
public readonly observedIceCandidates = new Map<string, ObservedIceCandidate>();
|
|
164
|
+
public readonly observedIceCandidatesPair = new Map<string, ObservedIceCandidatePair>();
|
|
165
|
+
public readonly observedIceTransports = new Map<string, ObservedIceTransport>();
|
|
166
|
+
public readonly observedInboundRtps = new Map<number, ObservedInboundRtp>();
|
|
167
|
+
public readonly observedInboundTracks = new Map<string, ObservedInboundTrack>();
|
|
168
|
+
public readonly observedMediaPlayouts = new Map<string, ObservedMediaPlayout>();
|
|
169
|
+
public readonly observedMediaSources = new Map<string, ObservedMediaSource>();
|
|
170
|
+
public readonly observedOutboundRtps = new Map<number, ObservedOutboundRtp>();
|
|
171
|
+
public readonly observedOutboundTracks = new Map<string, ObservedOutboundTrack>();
|
|
172
|
+
public readonly observedPeerConnectionTransports = new Map<string, ObservedPeerConnectionTransport>();
|
|
173
|
+
public readonly observedRemoteInboundRtps = new Map<number, ObservedRemoteInboundRtp>();
|
|
174
|
+
public readonly observedRemoteOutboundRtps = new Map<number, ObservedRemoteOutboundRtp>();
|
|
175
|
+
|
|
176
|
+
public constructor(public readonly peerConnectionId: string, public readonly client: ObservedClient) {
|
|
113
177
|
super();
|
|
114
178
|
this.setMaxListeners(Infinity);
|
|
115
179
|
}
|
|
116
180
|
|
|
117
|
-
public get
|
|
118
|
-
return this.
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
public get roomId() {
|
|
122
|
-
return this.client.roomId;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
public get callId() {
|
|
126
|
-
return this.client.callId;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
public get clientId() {
|
|
130
|
-
return this.client.clientId;
|
|
181
|
+
public get score() {
|
|
182
|
+
return this.calculatedScore.value;
|
|
131
183
|
}
|
|
132
184
|
|
|
133
|
-
public get
|
|
134
|
-
|
|
135
|
-
}
|
|
185
|
+
public get visited() {
|
|
186
|
+
const visited = this._visited;
|
|
136
187
|
|
|
137
|
-
|
|
138
|
-
return this._model.label;
|
|
139
|
-
}
|
|
188
|
+
this._visited = false;
|
|
140
189
|
|
|
141
|
-
|
|
142
|
-
this._model.label = value;
|
|
190
|
+
return visited;
|
|
143
191
|
}
|
|
144
192
|
|
|
145
|
-
public get
|
|
146
|
-
return this.
|
|
193
|
+
public get codecs() {
|
|
194
|
+
return [ ...this.observedCodecs.values() ];
|
|
147
195
|
}
|
|
148
196
|
|
|
149
|
-
public get
|
|
150
|
-
return this.
|
|
197
|
+
public get inboundRtps() {
|
|
198
|
+
return [ ...this.observedInboundRtps.values() ];
|
|
151
199
|
}
|
|
152
200
|
|
|
153
|
-
public get
|
|
154
|
-
return this.
|
|
201
|
+
public get remoteOutboundRtps() {
|
|
202
|
+
return [ ...this.observedRemoteOutboundRtps.values() ];
|
|
155
203
|
}
|
|
156
204
|
|
|
157
|
-
public get
|
|
158
|
-
|
|
159
|
-
return this._model.peerConnectionId!;
|
|
205
|
+
public get outboundRtps() {
|
|
206
|
+
return [ ...this.observedOutboundRtps.values() ];
|
|
160
207
|
}
|
|
161
208
|
|
|
162
|
-
public get
|
|
163
|
-
return this.
|
|
209
|
+
public get remoteInboundRtps() {
|
|
210
|
+
return [ ...this.observedRemoteInboundRtps.values() ];
|
|
164
211
|
}
|
|
165
212
|
|
|
166
|
-
public get
|
|
167
|
-
return this.
|
|
213
|
+
public get mediaSources() {
|
|
214
|
+
return [ ...this.observedMediaSources.values() ];
|
|
168
215
|
}
|
|
169
216
|
|
|
170
|
-
public get
|
|
171
|
-
return this.
|
|
217
|
+
public get mediaPlayouts() {
|
|
218
|
+
return [ ...this.observedMediaPlayouts.values() ];
|
|
172
219
|
}
|
|
173
220
|
|
|
174
|
-
public get
|
|
175
|
-
return this.
|
|
221
|
+
public get dataChannels() {
|
|
222
|
+
return [ ...this.observedDataChannels.values() ];
|
|
176
223
|
}
|
|
177
224
|
|
|
178
|
-
public get
|
|
179
|
-
return this.
|
|
225
|
+
public get peerConnectionTransports() {
|
|
226
|
+
return [ ...this.observedPeerConnectionTransports.values() ];
|
|
180
227
|
}
|
|
181
228
|
|
|
182
|
-
public get
|
|
183
|
-
return this.
|
|
229
|
+
public get iceTransports() {
|
|
230
|
+
return [ ...this.observedIceTransports.values() ];
|
|
184
231
|
}
|
|
185
232
|
|
|
186
|
-
public get
|
|
187
|
-
return this.
|
|
233
|
+
public get iceCandidates() {
|
|
234
|
+
return [ ...this.observedIceCandidates.values() ];
|
|
188
235
|
}
|
|
189
236
|
|
|
190
|
-
public get
|
|
191
|
-
return this.
|
|
237
|
+
public get iceCandidatePairs() {
|
|
238
|
+
return [ ...this.observedIceCandidatesPair.values() ];
|
|
192
239
|
}
|
|
193
240
|
|
|
194
|
-
public get
|
|
195
|
-
return this.
|
|
241
|
+
public get certificates() {
|
|
242
|
+
return [ ...this.observedCertificates.values() ];
|
|
196
243
|
}
|
|
197
244
|
|
|
198
|
-
public get
|
|
199
|
-
return this.
|
|
245
|
+
public get selectedIceCandidatePairs() {
|
|
246
|
+
return this.iceTransports.map((iceTransport) => iceTransport.getSelectedCandidatePair())
|
|
247
|
+
.filter((pair) => pair !== undefined) as ObservedIceCandidatePair[];
|
|
200
248
|
}
|
|
201
249
|
|
|
202
|
-
public
|
|
203
|
-
this.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
this._dataChannels.forEach((channel) => (channel.marker = value));
|
|
209
|
-
this.ICE.marker = value;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
public addEventReport(params: PartialBy<Omit<CallEventReport, 'serviceId' | 'roomId' | 'callId' | 'clientId' | 'userId' | 'peerConnectionId' | 'marker'>, 'timestamp'>) {
|
|
213
|
-
this.reports.addCallEventReport({
|
|
214
|
-
...params,
|
|
215
|
-
serviceId: this.serviceId,
|
|
216
|
-
mediaUnitId: this.mediaUnitId,
|
|
217
|
-
roomId: this.roomId,
|
|
218
|
-
callId: this.callId,
|
|
219
|
-
clientId: this.clientId,
|
|
220
|
-
userId: this.client.userId,
|
|
221
|
-
peerConnectionId: this.peerConnectionId,
|
|
222
|
-
marker: this.client.marker,
|
|
223
|
-
timestamp: params.timestamp ?? Date.now(),
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
public get closed() {
|
|
228
|
-
return this._closed;
|
|
250
|
+
public get selectedIceCandiadtePairForTurn() {
|
|
251
|
+
return this.selectedIceCandidatePairs
|
|
252
|
+
.filter((pair) =>
|
|
253
|
+
pair.getLocalCandidate()?.candidateType === 'relay' &&
|
|
254
|
+
pair.getRemoteCandidate()?.url?.startsWith('turn:')
|
|
255
|
+
);
|
|
229
256
|
}
|
|
230
257
|
|
|
231
258
|
public close() {
|
|
232
|
-
if (this.
|
|
233
|
-
this.
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
259
|
+
if (this.closed) return;
|
|
260
|
+
this.closed = true;
|
|
261
|
+
|
|
262
|
+
this.observedCertificates.clear();
|
|
263
|
+
this.observedCodecs.clear();
|
|
264
|
+
this.observedDataChannels.clear();
|
|
265
|
+
this.observedIceCandidates.clear();
|
|
266
|
+
this.observedIceCandidatesPair.clear();
|
|
267
|
+
this.observedIceTransports.clear();
|
|
268
|
+
this.observedInboundRtps.clear();
|
|
269
|
+
this.observedInboundTracks.clear();
|
|
270
|
+
this.observedMediaPlayouts.clear();
|
|
271
|
+
this.observedMediaSources.clear();
|
|
272
|
+
this.observedOutboundRtps.clear();
|
|
273
|
+
this.observedOutboundTracks.clear();
|
|
274
|
+
this.observedPeerConnectionTransports.clear();
|
|
275
|
+
this.observedRemoteInboundRtps.clear();
|
|
276
|
+
this.observedRemoteOutboundRtps.clear();
|
|
277
|
+
|
|
278
|
+
this.client.call.observer.observedTURN.removePeerConnection(this);
|
|
279
|
+
|
|
246
280
|
this.emit('close');
|
|
247
281
|
}
|
|
248
282
|
|
|
249
|
-
public
|
|
250
|
-
|
|
251
|
-
|
|
283
|
+
public accept(sample: PeerConnectionSample) {
|
|
284
|
+
if (this.closed) return;
|
|
285
|
+
this._visited = true;
|
|
252
286
|
|
|
253
|
-
|
|
287
|
+
this.availableIncomingBitrate = 0;
|
|
288
|
+
this.availableOutgoingBitrate = 0;
|
|
254
289
|
this.deltaInboundPacketsLost = 0;
|
|
255
290
|
this.deltaInboundPacketsReceived = 0;
|
|
256
291
|
this.deltaOutboundPacketsSent = 0;
|
|
@@ -258,7 +293,6 @@ export class ObservedPeerConnection extends EventEmitter {
|
|
|
258
293
|
this.deltaDataChannelBytesReceived = 0;
|
|
259
294
|
this.deltaInboundReceivedBytes = 0;
|
|
260
295
|
this.deltaOutboundSentBytes = 0;
|
|
261
|
-
|
|
262
296
|
this.deltaReceivedAudioBytes = 0;
|
|
263
297
|
this.deltaReceivedVideoBytes = 0;
|
|
264
298
|
this.deltaReceivedAudioPackets = 0;
|
|
@@ -270,304 +304,692 @@ export class ObservedPeerConnection extends EventEmitter {
|
|
|
270
304
|
this.receivingAudioBitrate = 0;
|
|
271
305
|
this.receivingVideoBitrate = 0;
|
|
272
306
|
|
|
273
|
-
|
|
307
|
+
const now = Date.now();
|
|
308
|
+
const elapsedTimeInMs = now - this.updated;
|
|
309
|
+
const elapsedTimeInSec = elapsedTimeInMs / 1000;
|
|
310
|
+
const rttMeasurementsInSec: number[] = [];
|
|
311
|
+
const jitterMeasurements: number[] = [];
|
|
312
|
+
|
|
313
|
+
if (sample.certificates) {
|
|
314
|
+
for (const certificate of sample.certificates) {
|
|
315
|
+
this._updateCertificateStats(certificate);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (sample.codecs) {
|
|
319
|
+
for (const codec of sample.codecs) {
|
|
320
|
+
this._updateCodecStats(codec);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (sample.dataChannels) {
|
|
324
|
+
for (const dataChannel of sample.dataChannels) {
|
|
325
|
+
const observedDataChannel = this._updateDataChannelStats(dataChannel);
|
|
326
|
+
|
|
327
|
+
if (!observedDataChannel) continue;
|
|
328
|
+
|
|
329
|
+
this.deltaDataChannelBytesSent += observedDataChannel.deltaBytesSent;
|
|
330
|
+
this.deltaDataChannelBytesReceived += observedDataChannel.deltaBytesReceived;
|
|
331
|
+
this.deltaDataChannelMessagesSent += observedDataChannel.deltaMessagesSent;
|
|
332
|
+
this.deltaDataChannelMessagesReceived += observedDataChannel.deltaMessagesReceived;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (sample.iceCandidates) {
|
|
336
|
+
for (const iceCandidate of sample.iceCandidates) {
|
|
337
|
+
this._updateIceCandidateStats(iceCandidate);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (sample.iceCandidatePairs) {
|
|
341
|
+
for (const iceCandidatePair of sample.iceCandidatePairs) {
|
|
342
|
+
const observedCandidatePair = this._updateIceCandidatePairStats(iceCandidatePair);
|
|
343
|
+
|
|
344
|
+
if (!observedCandidatePair) continue;
|
|
345
|
+
|
|
346
|
+
if (observedCandidatePair.currentRoundTripTime) {
|
|
347
|
+
rttMeasurementsInSec.push(observedCandidatePair.currentRoundTripTime);
|
|
348
|
+
}
|
|
349
|
+
if (observedCandidatePair.availableIncomingBitrate) {
|
|
350
|
+
this.availableIncomingBitrate += observedCandidatePair.availableIncomingBitrate;
|
|
351
|
+
}
|
|
352
|
+
if (observedCandidatePair.availableOutgoingBitrate) {
|
|
353
|
+
this.availableOutgoingBitrate += observedCandidatePair.availableOutgoingBitrate;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (sample.iceTransports) {
|
|
358
|
+
for (const iceTransport of sample.iceTransports) {
|
|
359
|
+
this._updateIceTransportStats(iceTransport);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (sample.inboundRtps) {
|
|
363
|
+
for (const inboundRtp of sample.inboundRtps) {
|
|
364
|
+
const observedInboundRtp = this._updateInboundRtpStats(inboundRtp);
|
|
365
|
+
|
|
366
|
+
if (!observedInboundRtp) continue;
|
|
367
|
+
|
|
368
|
+
this.deltaInboundPacketsLost += observedInboundRtp.deltaLostPackets;
|
|
369
|
+
this.deltaInboundPacketsReceived += observedInboundRtp.deltaReceivedPackets;
|
|
370
|
+
this.deltaInboundReceivedBytes += observedInboundRtp.deltaBytesReceived;
|
|
371
|
+
|
|
372
|
+
switch (inboundRtp.kind) {
|
|
373
|
+
case 'audio':
|
|
374
|
+
this.deltaReceivedAudioBytes += observedInboundRtp.deltaBytesReceived;
|
|
375
|
+
this.deltaReceivedAudioPackets += observedInboundRtp.deltaReceivedPackets;
|
|
376
|
+
break;
|
|
377
|
+
case 'video':
|
|
378
|
+
this.deltaReceivedVideoBytes += observedInboundRtp.deltaBytesReceived;
|
|
379
|
+
this.deltaReceivedVideoPackets += observedInboundRtp.deltaReceivedPackets;
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (observedInboundRtp.jitter) {
|
|
384
|
+
jitterMeasurements.push(observedInboundRtp.jitter);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
if (sample.mediaPlayouts) {
|
|
389
|
+
for (const mediaPlayout of sample.mediaPlayouts) {
|
|
390
|
+
this._updateMediaPlayoutStats(mediaPlayout);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (sample.mediaSources) {
|
|
394
|
+
for (const mediaSource of sample.mediaSources) {
|
|
395
|
+
this._updateMediaSourceStats(mediaSource);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
if (sample.outboundRtps) {
|
|
399
|
+
for (const outboundRtp of sample.outboundRtps) {
|
|
400
|
+
const observedOutboundRtp = this._updateOutboundRtpStats(outboundRtp);
|
|
401
|
+
|
|
402
|
+
if (!observedOutboundRtp) continue;
|
|
403
|
+
|
|
404
|
+
this.deltaOutboundPacketsSent += observedOutboundRtp.deltaPacketsSent ?? 0;
|
|
405
|
+
this.deltaOutboundSentBytes += observedOutboundRtp.deltaBytesSent ?? 0;
|
|
406
|
+
|
|
407
|
+
switch (outboundRtp.kind) {
|
|
408
|
+
case 'audio':
|
|
409
|
+
this.deltaSentAudioBytes += observedOutboundRtp.deltaBytesSent;
|
|
410
|
+
this.deltaSentAudioBytes += observedOutboundRtp.deltaPacketsSent;
|
|
411
|
+
break;
|
|
412
|
+
case 'video':
|
|
413
|
+
this.deltaSentVideoBytes += observedOutboundRtp.deltaBytesSent;
|
|
414
|
+
this.deltaSentVideoBytes += observedOutboundRtp.deltaPacketsSent;
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
if (sample.peerConnectionTransports) {
|
|
421
|
+
for (const peerConnectionTransport of sample.peerConnectionTransports) {
|
|
422
|
+
this._updatePeerConnectionTransportStats(peerConnectionTransport);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
if (sample.remoteInboundRtps) {
|
|
426
|
+
for (const remoteInboundRtp of sample.remoteInboundRtps) {
|
|
427
|
+
const observedRemoteInboundRtp = this._updateRemoteInboundRtpStats(remoteInboundRtp);
|
|
428
|
+
|
|
429
|
+
if (!observedRemoteInboundRtp) continue;
|
|
430
|
+
|
|
431
|
+
if (observedRemoteInboundRtp.roundTripTime) {
|
|
432
|
+
rttMeasurementsInSec.push(observedRemoteInboundRtp.roundTripTime);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
if (sample.remoteOutboundRtps) {
|
|
437
|
+
for (const remoteOutboundRtp of sample.remoteOutboundRtps) {
|
|
438
|
+
const observedRemoteOutboundRtp = this._updateRemoteOutboundRtpStats(remoteOutboundRtp);
|
|
439
|
+
|
|
440
|
+
if (!observedRemoteOutboundRtp) continue;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// tracks should be updated last as they are derived stats
|
|
445
|
+
// and depends on base stats but they all received in the sample sample
|
|
446
|
+
if (sample.inboundTracks) {
|
|
447
|
+
for (const inboundTrack of sample.inboundTracks) {
|
|
448
|
+
this._updateInboundTrackSample(inboundTrack);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
if (sample.outboundTracks) {
|
|
452
|
+
for (const outboundTrack of sample.outboundTracks) {
|
|
453
|
+
this._updateOutboundTrackSample(outboundTrack);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
this.totalInboundPacketsLost += this.deltaInboundPacketsLost;
|
|
458
|
+
this.totalInboundPacketsReceived += this.deltaInboundPacketsReceived;
|
|
459
|
+
this.totalOutboundPacketsSent += this.deltaOutboundPacketsSent;
|
|
460
|
+
this.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
|
|
461
|
+
this.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
|
|
462
|
+
this.totalDataChannelMessagesSent += this.deltaDataChannelMessagesSent;
|
|
463
|
+
this.totalDataChannelMessagesReceived += this.deltaDataChannelMessagesReceived;
|
|
464
|
+
this.totalReceivedAudioBytes += this.deltaReceivedAudioBytes;
|
|
465
|
+
this.totalReceivedVideoBytes += this.deltaReceivedVideoBytes;
|
|
466
|
+
this.totalSentAudioBytes += this.deltaSentAudioBytes;
|
|
467
|
+
this.totalSentVideoBytes += this.deltaSentVideoBytes;
|
|
468
|
+
this.totalReceivedAudioPacktes += this.deltaReceivedAudioPackets;
|
|
469
|
+
this.totalReceivedVideoPackets += this.deltaReceivedVideoPackets;
|
|
470
|
+
this.totalSentAudioPackets += this.deltaSentAudioBytes;
|
|
471
|
+
this.totalSentVideoPackets += this.deltaSentVideoBytes;
|
|
472
|
+
|
|
473
|
+
this.receivingPacketsPerSecond = this.deltaInboundPacketsReceived / elapsedTimeInSec;
|
|
474
|
+
this.sendingPacketsPerSecond = this.deltaOutboundPacketsSent / elapsedTimeInSec;
|
|
475
|
+
this.sendingAudioBitrate = (this.deltaSentAudioBytes * 8) / elapsedTimeInSec;
|
|
476
|
+
this.sendingVideoBitrate = (this.deltaSentVideoBytes * 8) / elapsedTimeInSec;
|
|
477
|
+
this.receivingAudioBitrate = (this.deltaReceivedAudioBytes * 8) / elapsedTimeInSec;
|
|
478
|
+
this.receivingVideoBitrate = (this.deltaReceivedVideoBytes * 8) / elapsedTimeInSec;
|
|
479
|
+
|
|
480
|
+
if (rttMeasurementsInSec.length > 0) {
|
|
481
|
+
this.avgRttInMs = rttMeasurementsInSec.reduce((acc, val) => acc + val, 0) / rttMeasurementsInSec.length;
|
|
482
|
+
} else {
|
|
483
|
+
this.avgRttInMs = undefined;
|
|
484
|
+
}
|
|
485
|
+
if (jitterMeasurements.length > 0) {
|
|
486
|
+
this.avgJitter = jitterMeasurements.reduce((acc, val) => acc + val, 0) / jitterMeasurements.length;
|
|
487
|
+
} else {
|
|
488
|
+
this.avgJitter = undefined;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
const selectedIceCandidatePairs = this.selectedIceCandidatePairs;
|
|
492
|
+
const selectedCandidatePairForTurn = selectedIceCandidatePairs.filter((pair) =>
|
|
493
|
+
pair.getLocalCandidate()?.candidateType === 'relay' &&
|
|
494
|
+
pair.getRemoteCandidate()?.url?.startsWith('turn:')
|
|
495
|
+
);
|
|
496
|
+
const wasUsingTURN = this.usingTURN;
|
|
497
|
+
|
|
498
|
+
this.usingTCP = selectedIceCandidatePairs.some((pair) => pair.getLocalCandidate()?.protocol === 'tcp');
|
|
499
|
+
this.usingTURN = 0 < selectedCandidatePairForTurn.length;
|
|
500
|
+
|
|
501
|
+
if (this.usingTURN) {
|
|
502
|
+
if (!this.observedTurnServer) {
|
|
503
|
+
this.observedTurnServer = this.client.call.observer.observedTURN.addPeerConnection(this);
|
|
504
|
+
}
|
|
505
|
+
this.observedTurnServer?.updateTurnUsage(...selectedCandidatePairForTurn);
|
|
506
|
+
} else if (wasUsingTURN) {
|
|
507
|
+
if (!this.usingTURN) {
|
|
508
|
+
this.client.call.observer.observedTURN.removePeerConnection(this);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
this.calculatedScore.value = sample.score;
|
|
512
|
+
this.updated = now;
|
|
513
|
+
this._checkVisited();
|
|
514
|
+
|
|
515
|
+
this.emit('update');
|
|
274
516
|
}
|
|
275
517
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
518
|
+
private _checkVisited() {
|
|
519
|
+
for (const certificate of [ ...this.observedCertificates.values() ]) {
|
|
520
|
+
if (certificate.visited) continue;
|
|
279
521
|
|
|
280
|
-
|
|
281
|
-
if (this._model.label !== sample.label) {
|
|
282
|
-
this._model.label = sample.label;
|
|
522
|
+
this.observedCertificates.delete(certificate.id);
|
|
283
523
|
}
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
serviceId: this.client.call.serviceId,
|
|
287
|
-
roomId: this.client.call.roomId,
|
|
288
|
-
callId: this.client.call.callId,
|
|
289
|
-
clientId: this.client.clientId,
|
|
290
|
-
userId: this.client.userId,
|
|
291
|
-
mediaUnitId: this.client.mediaUnitId,
|
|
292
|
-
...sample,
|
|
293
|
-
timestamp,
|
|
294
|
-
sampleSeq: -1, // deprecated
|
|
295
|
-
marker: this.marker,
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
this.reports.addPeerConnectionTransportReports(report);
|
|
299
|
-
this._elapsedTimeSinceLastUpdate = now - this._updated;
|
|
300
|
-
this.visited = true;
|
|
301
|
-
this._updated = now;
|
|
302
|
-
this._statsTimestamp = timestamp;
|
|
303
|
-
this.emit('update', {
|
|
304
|
-
elapsedTimeInMs: this._elapsedTimeSinceLastUpdate,
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
public createInboundAudioTrack(config: ObservedInboundAudioTrackModel): ObservedInboundAudioTrack {
|
|
309
|
-
if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
|
|
310
|
-
|
|
311
|
-
const result = new ObservedInboundAudioTrack(config, this);
|
|
524
|
+
for (const codec of [ ...this.observedCodecs.values() ]) {
|
|
525
|
+
if (codec.visited) continue;
|
|
312
526
|
|
|
313
|
-
|
|
314
|
-
this.
|
|
315
|
-
}
|
|
316
|
-
this.
|
|
527
|
+
this.observedCodecs.delete(codec.id);
|
|
528
|
+
this.emit('removed-codec', codec);
|
|
529
|
+
}
|
|
530
|
+
for (const dataChannel of [ ...this.observedDataChannels.values() ]) {
|
|
531
|
+
if (dataChannel.visited) continue;
|
|
532
|
+
|
|
533
|
+
this.observedDataChannels.delete(dataChannel.id);
|
|
534
|
+
this.emit('removed-data-channel', dataChannel);
|
|
535
|
+
}
|
|
536
|
+
for (const iceCandidate of [ ...this.observedIceCandidates.values() ]) {
|
|
537
|
+
if (iceCandidate.visited) continue;
|
|
317
538
|
|
|
318
|
-
|
|
539
|
+
this.observedIceCandidates.delete(iceCandidate.id);
|
|
540
|
+
this.emit('removed-ice-candidate', iceCandidate);
|
|
541
|
+
}
|
|
542
|
+
for (const iceCandidatePair of [ ...this.observedIceCandidatesPair.values() ]) {
|
|
543
|
+
if (iceCandidatePair.visited) continue;
|
|
319
544
|
|
|
320
|
-
|
|
545
|
+
this.observedIceCandidatesPair.delete(iceCandidatePair.id);
|
|
546
|
+
this.emit('removed-ice-candidate-pair', iceCandidatePair);
|
|
547
|
+
}
|
|
548
|
+
for (const iceTransport of [ ...this.observedIceTransports.values() ]) {
|
|
549
|
+
if (iceTransport.visited) continue;
|
|
550
|
+
|
|
551
|
+
this.observedIceTransports.delete(iceTransport.id);
|
|
552
|
+
this.emit('removed-ice-transport', iceTransport);
|
|
553
|
+
}
|
|
554
|
+
for (const inboundRtp of [ ...this.observedInboundRtps.values() ]) {
|
|
555
|
+
if (inboundRtp.visited) continue;
|
|
556
|
+
|
|
557
|
+
this.observedInboundRtps.delete(inboundRtp.ssrc);
|
|
558
|
+
this.emit('removed-inbound-rtp', inboundRtp);
|
|
559
|
+
}
|
|
560
|
+
for (const inboundTrack of [ ...this.observedInboundTracks.values() ]) {
|
|
561
|
+
if (inboundTrack.visited) continue;
|
|
562
|
+
|
|
563
|
+
this.observedInboundTracks.delete(inboundTrack.id);
|
|
564
|
+
this.emit('removed-inbound-track', inboundTrack);
|
|
565
|
+
}
|
|
566
|
+
for (const mediaPlayout of [ ...this.observedMediaPlayouts.values() ]) {
|
|
567
|
+
if (mediaPlayout.visited) continue;
|
|
568
|
+
|
|
569
|
+
this.observedMediaPlayouts.delete(mediaPlayout.id);
|
|
570
|
+
this.emit('removed-media-playout', mediaPlayout);
|
|
571
|
+
}
|
|
572
|
+
for (const mediaSource of [ ...this.observedMediaSources.values() ]) {
|
|
573
|
+
if (mediaSource.visited) continue;
|
|
574
|
+
|
|
575
|
+
this.observedMediaSources.delete(mediaSource.id);
|
|
576
|
+
this.emit('removed-media-source', mediaSource);
|
|
577
|
+
}
|
|
578
|
+
for (const outboundRtp of [ ...this.observedOutboundRtps.values() ]) {
|
|
579
|
+
if (outboundRtp.visited) continue;
|
|
580
|
+
|
|
581
|
+
this.observedOutboundRtps.delete(outboundRtp.ssrc);
|
|
582
|
+
this.emit('removed-outbound-rtp', outboundRtp);
|
|
583
|
+
}
|
|
584
|
+
for (const outboundTrack of [ ...this.observedOutboundTracks.values() ]) {
|
|
585
|
+
if (outboundTrack.visited) continue;
|
|
586
|
+
|
|
587
|
+
this.observedOutboundTracks.delete(outboundTrack.id);
|
|
588
|
+
this.emit('removed-outbound-track', outboundTrack);
|
|
589
|
+
}
|
|
590
|
+
for (const peerConnectionTransport of [ ...this.observedPeerConnectionTransports.values() ]) {
|
|
591
|
+
if (peerConnectionTransport.visited) continue;
|
|
592
|
+
|
|
593
|
+
this.observedPeerConnectionTransports.delete(peerConnectionTransport.id);
|
|
594
|
+
this.emit('removed-peer-connection-transport', peerConnectionTransport);
|
|
595
|
+
}
|
|
596
|
+
for (const remoteInboundRtp of [ ...this.observedRemoteInboundRtps.values() ]) {
|
|
597
|
+
if (remoteInboundRtp.visited) continue;
|
|
598
|
+
|
|
599
|
+
this.observedRemoteInboundRtps.delete(remoteInboundRtp.ssrc);
|
|
600
|
+
this.emit('removed-remote-inbound-rtp', remoteInboundRtp);
|
|
601
|
+
}
|
|
602
|
+
for (const remoteOutboundRtp of [ ...this.observedRemoteOutboundRtps.values() ]) {
|
|
603
|
+
if (remoteOutboundRtp.visited) continue;
|
|
604
|
+
|
|
605
|
+
this.observedRemoteOutboundRtps.delete(remoteOutboundRtp.ssrc);
|
|
606
|
+
this.emit('removed-remote-outbound-rtp', remoteOutboundRtp);
|
|
607
|
+
}
|
|
321
608
|
}
|
|
322
609
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
610
|
+
private _updateCertificateStats(stats: CertificateStats) {
|
|
611
|
+
let observedCertificate = this.observedCertificates.get(stats.id);
|
|
612
|
+
|
|
613
|
+
if (!observedCertificate) {
|
|
614
|
+
if (!stats.timestamp || !stats.id || !stats.fingerprint) {
|
|
615
|
+
return logger.warn(
|
|
616
|
+
`ObservedPeerConnection received an invalid CertificateStats (missing timestamp OR id OR fingerprint field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
|
|
617
|
+
stats
|
|
618
|
+
);
|
|
619
|
+
}
|
|
327
620
|
|
|
328
|
-
|
|
329
|
-
this._inboundVideoTracks.delete(result.trackId);
|
|
330
|
-
});
|
|
331
|
-
this._inboundVideoTracks.set(result.trackId, result);
|
|
621
|
+
observedCertificate = new ObservedCertificate(stats.timestamp, stats.id, this);
|
|
332
622
|
|
|
333
|
-
|
|
623
|
+
this.observedCertificates.set(stats.id, observedCertificate);
|
|
624
|
+
this.emit('added-certificate', observedCertificate);
|
|
625
|
+
}
|
|
334
626
|
|
|
335
|
-
|
|
627
|
+
observedCertificate.update(stats);
|
|
628
|
+
|
|
629
|
+
return observedCertificate;
|
|
336
630
|
}
|
|
337
631
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
const result = new ObservedOutboundAudioTrack(config, this);
|
|
632
|
+
private _updateCodecStats(stats: CodecStats) {
|
|
633
|
+
let observedCodec = this.observedCodecs.get(stats.id);
|
|
342
634
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
635
|
+
if (!observedCodec) {
|
|
636
|
+
if (!stats.timestamp || !stats.id || !stats.mimeType) {
|
|
637
|
+
return logger.warn(
|
|
638
|
+
`ObservedPeerConnection received an invalid CodecStats (missing timestamp OR id OR mimeType field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
|
|
639
|
+
stats
|
|
640
|
+
);
|
|
641
|
+
}
|
|
347
642
|
|
|
348
|
-
|
|
643
|
+
observedCodec = new ObservedCodec(stats.timestamp, stats.id, stats.mimeType, this);
|
|
349
644
|
|
|
350
|
-
|
|
645
|
+
this.observedCodecs.set(stats.id, observedCodec);
|
|
646
|
+
this.emit('added-codec', observedCodec);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
observedCodec.update(stats);
|
|
650
|
+
|
|
651
|
+
return observedCodec;
|
|
351
652
|
}
|
|
352
653
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
const result = new ObservedOutboundVideoTrack(config, this);
|
|
654
|
+
private _updateDataChannelStats(stats: DataChannelStats) {
|
|
655
|
+
let observedDataChannel = this.observedDataChannels.get(stats.id);
|
|
357
656
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
657
|
+
if (!observedDataChannel) {
|
|
658
|
+
if (!stats.timestamp || !stats.id) {
|
|
659
|
+
return logger.warn(
|
|
660
|
+
`ObservedPeerConnection received an invalid DataChannelStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
|
|
661
|
+
stats
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
observedDataChannel = new ObservedDataChannel(stats.timestamp, stats.id, this);
|
|
666
|
+
|
|
667
|
+
this.observedDataChannels.set(stats.id, observedDataChannel);
|
|
668
|
+
this.emit('added-data-channel', observedDataChannel);
|
|
669
|
+
}
|
|
362
670
|
|
|
363
|
-
|
|
671
|
+
observedDataChannel.update(stats);
|
|
364
672
|
|
|
365
|
-
return
|
|
673
|
+
return observedDataChannel;
|
|
366
674
|
}
|
|
367
675
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
676
|
+
private _updateIceCandidateStats(stats: IceCandidateStats) {
|
|
677
|
+
let observedIceCandidate = this.observedIceCandidates.get(stats.id);
|
|
678
|
+
|
|
679
|
+
if (!observedIceCandidate) {
|
|
680
|
+
if (!stats.timestamp || !stats.id) {
|
|
681
|
+
return logger.warn(
|
|
682
|
+
`ObservedPeerConnection received an invalid IceCandidateStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
|
|
683
|
+
stats
|
|
684
|
+
);
|
|
685
|
+
}
|
|
374
686
|
|
|
375
|
-
|
|
376
|
-
this._dataChannels.delete(result.channelId);
|
|
377
|
-
});
|
|
378
|
-
this._dataChannels.set(result.channelId, result);
|
|
687
|
+
observedIceCandidate = new ObservedIceCandidate(stats.timestamp, stats.id, this);
|
|
379
688
|
|
|
380
|
-
|
|
689
|
+
this.observedIceCandidates.set(stats.id, observedIceCandidate);
|
|
690
|
+
this.emit('added-ice-candidate', observedIceCandidate);
|
|
691
|
+
}
|
|
381
692
|
|
|
382
|
-
|
|
693
|
+
observedIceCandidate.update(stats);
|
|
694
|
+
|
|
695
|
+
return observedIceCandidate;
|
|
383
696
|
}
|
|
384
697
|
|
|
385
|
-
|
|
386
|
-
let
|
|
387
|
-
let sumJitter = 0;
|
|
388
|
-
const trackScores: CalculatedScore[] = [];
|
|
698
|
+
private _updateIceCandidatePairStats(stats: IceCandidateStats) {
|
|
699
|
+
let observedIceCandidatePair = this.observedIceCandidatesPair.get(stats.id);
|
|
389
700
|
|
|
390
|
-
|
|
391
|
-
|
|
701
|
+
if (!observedIceCandidatePair) {
|
|
702
|
+
if (!stats.timestamp || !stats.id) {
|
|
703
|
+
return logger.warn(
|
|
704
|
+
`ObservedPeerConnection received an invalid IceCandidateStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
|
|
705
|
+
stats
|
|
706
|
+
);
|
|
707
|
+
}
|
|
392
708
|
|
|
393
|
-
|
|
394
|
-
this.deltaInboundPacketsReceived += track.deltaReceivedPackets;
|
|
395
|
-
this.deltaInboundReceivedBytes += track.deltaBytesReceived;
|
|
396
|
-
|
|
397
|
-
this.deltaReceivedAudioBytes += track.deltaBytesReceived;
|
|
398
|
-
this.deltaReceivedAudioPackets += track.deltaReceivedPackets;
|
|
399
|
-
|
|
400
|
-
this.receivingAudioBitrate += track.bitrate;
|
|
709
|
+
observedIceCandidatePair = new ObservedIceCandidatePair(stats.timestamp, stats.id, this);
|
|
401
710
|
|
|
402
|
-
|
|
403
|
-
|
|
711
|
+
this.observedIceCandidatesPair.set(stats.id, observedIceCandidatePair);
|
|
712
|
+
this.emit('added-ice-candidate-pair', observedIceCandidatePair);
|
|
713
|
+
}
|
|
404
714
|
|
|
405
|
-
|
|
406
|
-
});
|
|
715
|
+
observedIceCandidatePair.update(stats);
|
|
407
716
|
|
|
408
|
-
|
|
409
|
-
|
|
717
|
+
return observedIceCandidatePair;
|
|
718
|
+
}
|
|
410
719
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
this.deltaInboundReceivedBytes += track.deltaBytesReceived;
|
|
414
|
-
|
|
415
|
-
this.deltaReceivedVideoBytes += track.deltaBytesReceived;
|
|
416
|
-
this.deltaReceivedVideoPackets += track.deltaReceivedPackets;
|
|
417
|
-
|
|
418
|
-
this.receivingVideoBitrate += track.bitrate;
|
|
720
|
+
private _updateIceTransportStats(stats: IceCandidateStats) {
|
|
721
|
+
let observedIceTransport = this.observedIceTransports.get(stats.id);
|
|
419
722
|
|
|
420
|
-
|
|
421
|
-
|
|
723
|
+
if (!observedIceTransport) {
|
|
724
|
+
if (!stats.timestamp || !stats.id) {
|
|
725
|
+
return logger.warn(
|
|
726
|
+
`ObservedPeerConnection received an invalid IceCandidateStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
|
|
727
|
+
stats
|
|
728
|
+
);
|
|
729
|
+
}
|
|
422
730
|
|
|
423
|
-
|
|
424
|
-
});
|
|
731
|
+
observedIceTransport = new ObservedIceTransport(stats.timestamp, stats.id, this);
|
|
425
732
|
|
|
426
|
-
|
|
427
|
-
|
|
733
|
+
this.observedIceTransports.set(stats.id, observedIceTransport);
|
|
734
|
+
this.emit('added-ice-transport', observedIceTransport);
|
|
735
|
+
}
|
|
428
736
|
|
|
429
|
-
|
|
430
|
-
this.deltaOutboundSentBytes += track.deltaSentBytes;
|
|
431
|
-
|
|
432
|
-
this.deltaSentAudioBytes += track.deltaSentBytes;
|
|
433
|
-
this.deltaSentAudioBytes += track.deltaSentPackets;
|
|
434
|
-
|
|
435
|
-
this.sendingAudioBitrate += track.bitrate;
|
|
737
|
+
observedIceTransport.update(stats);
|
|
436
738
|
|
|
437
|
-
|
|
438
|
-
|
|
739
|
+
return observedIceTransport;
|
|
740
|
+
}
|
|
439
741
|
|
|
440
|
-
|
|
441
|
-
|
|
742
|
+
private _updateInboundRtpStats(stats: InboundRtpStats) {
|
|
743
|
+
let observedInboundRtp = this.observedInboundRtps.get(stats.ssrc);
|
|
442
744
|
|
|
443
|
-
|
|
444
|
-
|
|
745
|
+
if (!observedInboundRtp) {
|
|
746
|
+
if (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind || !stats.trackIdentifier) {
|
|
747
|
+
return logger.warn(
|
|
748
|
+
`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}`,
|
|
749
|
+
stats
|
|
750
|
+
);
|
|
751
|
+
}
|
|
445
752
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
753
|
+
observedInboundRtp = new ObservedInboundRtp(
|
|
754
|
+
stats.timestamp,
|
|
755
|
+
stats.id,
|
|
756
|
+
stats.ssrc,
|
|
757
|
+
stats.kind as MediaKind,
|
|
758
|
+
stats.trackIdentifier,
|
|
759
|
+
this
|
|
760
|
+
);
|
|
761
|
+
|
|
762
|
+
this.observedInboundRtps.set(stats.ssrc, observedInboundRtp);
|
|
763
|
+
this.emit('added-inbound-rtp', observedInboundRtp);
|
|
764
|
+
}
|
|
453
765
|
|
|
454
|
-
|
|
455
|
-
sumJitter += (track.jitter ?? 0);
|
|
766
|
+
observedInboundRtp.update(stats);
|
|
456
767
|
|
|
457
|
-
|
|
458
|
-
|
|
768
|
+
return observedInboundRtp;
|
|
769
|
+
}
|
|
459
770
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
this.deltaDataChannelBytesReceived += channel.deltaBytesReceived;
|
|
463
|
-
});
|
|
771
|
+
private _updateInboundTrackSample(stats: InboundTrackSample) {
|
|
772
|
+
let observedInboundTrack = this.observedInboundTracks.get(stats.id);
|
|
464
773
|
|
|
465
|
-
|
|
466
|
-
|
|
774
|
+
if (!observedInboundTrack) {
|
|
775
|
+
if (!stats.timestamp || !stats.id || !stats.kind) {
|
|
776
|
+
return logger.warn(
|
|
777
|
+
`ObservedPeerConnection received an invalid InboundTrackSample (missing timestamp OR id OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
|
|
778
|
+
stats
|
|
779
|
+
);
|
|
780
|
+
}
|
|
467
781
|
|
|
468
|
-
|
|
782
|
+
const inboundRtp = [ ...this.observedInboundRtps.values() ].find((inbRtp) => inbRtp.trackIdentifier === stats.id);
|
|
783
|
+
const mediaPlayout = inboundRtp ?
|
|
784
|
+
[ ...this.observedMediaPlayouts.values() ].find((mp) => mp.id === inboundRtp.playoutId) : undefined;
|
|
785
|
+
|
|
786
|
+
observedInboundTrack = new ObservedInboundTrack(
|
|
787
|
+
stats.timestamp,
|
|
788
|
+
stats.id,
|
|
789
|
+
stats.kind as MediaKind,
|
|
790
|
+
this,
|
|
791
|
+
inboundRtp,
|
|
792
|
+
mediaPlayout,
|
|
793
|
+
);
|
|
794
|
+
|
|
795
|
+
this.observedInboundTracks.set(stats.id, observedInboundTrack);
|
|
796
|
+
this.emit('added-inbound-track', observedInboundTrack);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
observedInboundTrack.update(stats);
|
|
469
800
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
801
|
+
return observedInboundTrack;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
private _updateMediaPlayoutStats(stats: MediaPlayoutStats) {
|
|
805
|
+
let observedMediaPlayout = this.observedMediaPlayouts.get(stats.id);
|
|
806
|
+
|
|
807
|
+
if (!observedMediaPlayout) {
|
|
808
|
+
if (!stats.timestamp || !stats.id || !stats.kind) {
|
|
809
|
+
return logger.warn(
|
|
810
|
+
`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}`,
|
|
811
|
+
stats
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
observedMediaPlayout = new ObservedMediaPlayout(
|
|
816
|
+
stats.timestamp,
|
|
817
|
+
stats.id,
|
|
818
|
+
stats.kind as MediaKind,
|
|
819
|
+
this
|
|
820
|
+
);
|
|
821
|
+
|
|
822
|
+
this.observedMediaPlayouts.set(stats.id, observedMediaPlayout);
|
|
823
|
+
this.emit('added-media-playout', observedMediaPlayout);
|
|
473
824
|
}
|
|
474
825
|
|
|
475
|
-
|
|
476
|
-
this.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
|
|
477
|
-
this.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
|
|
478
|
-
this.totalInboundPacketsLost += this.deltaInboundPacketsLost;
|
|
479
|
-
this.totalInboundPacketsReceived += this.deltaInboundPacketsReceived;
|
|
480
|
-
this.totalOutboundPacketsSent += this.deltaOutboundPacketsSent;
|
|
481
|
-
this.totalSentAudioBytes += this.deltaSentAudioBytes;
|
|
482
|
-
this.totalSentVideoBytes += this.deltaSentVideoBytes;
|
|
483
|
-
this.totalReceivedAudioBytes += this.deltaReceivedAudioBytes;
|
|
484
|
-
this.totalReceivedVideoBytes += this.deltaReceivedVideoBytes;
|
|
485
|
-
this.totalReceivedAudioPacktes += this.deltaReceivedAudioPackets;
|
|
486
|
-
this.totalReceivedVideoPackets += this.deltaReceivedVideoPackets;
|
|
487
|
-
this.totalSentAudioPackets += this.deltaSentAudioBytes;
|
|
488
|
-
this.totalSentVideoPackets += this.deltaSentVideoBytes;
|
|
826
|
+
observedMediaPlayout.update(stats);
|
|
489
827
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
let
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
}
|
|
828
|
+
return observedMediaPlayout;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
private _updateMediaSourceStats(stats: MediaSourceStats) {
|
|
832
|
+
let observedMediaSource = this.observedMediaSources.get(stats.id);
|
|
833
|
+
|
|
834
|
+
if (!observedMediaSource) {
|
|
835
|
+
if (!stats.timestamp || !stats.id || !stats.kind) {
|
|
836
|
+
return logger.warn(
|
|
837
|
+
`ObservedPeerConnection received an invalid InboundRtpStats (missing timestamp OR id OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
|
|
838
|
+
stats
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
observedMediaSource = new ObservedMediaSource(
|
|
843
|
+
stats.timestamp,
|
|
844
|
+
stats.id,
|
|
845
|
+
stats.kind as MediaKind,
|
|
846
|
+
this
|
|
847
|
+
);
|
|
848
|
+
|
|
849
|
+
this.observedMediaSources.set(stats.id, observedMediaSource);
|
|
850
|
+
this.emit('added-media-source', observedMediaSource);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
observedMediaSource.update(stats);
|
|
854
|
+
|
|
855
|
+
return observedMediaSource;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
private _updateOutboundRtpStats(stats: OutboundRtpStats) {
|
|
859
|
+
let observedOutboundRtp = this.observedOutboundRtps.get(stats.ssrc);
|
|
860
|
+
|
|
861
|
+
if (!observedOutboundRtp) {
|
|
862
|
+
if (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind) {
|
|
863
|
+
return logger.warn(
|
|
864
|
+
`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}`,
|
|
865
|
+
stats
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
observedOutboundRtp = new ObservedOutboundRtp(
|
|
870
|
+
stats.timestamp,
|
|
871
|
+
stats.id,
|
|
872
|
+
stats.ssrc,
|
|
873
|
+
stats.kind as MediaKind,
|
|
874
|
+
this
|
|
875
|
+
);
|
|
876
|
+
|
|
877
|
+
this.observedOutboundRtps.set(stats.ssrc, observedOutboundRtp);
|
|
878
|
+
this.emit('added-outbound-rtp', observedOutboundRtp);
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
observedOutboundRtp.update(stats);
|
|
882
|
+
|
|
883
|
+
return observedOutboundRtp;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
public _updateOutboundTrackSample(stats: OutboundTrackSample) {
|
|
887
|
+
let observedOutboundTrack = this.observedOutboundTracks.get(stats.id);
|
|
888
|
+
|
|
889
|
+
if (!observedOutboundTrack) {
|
|
890
|
+
if (!stats.timestamp || !stats.id || !stats.kind) {
|
|
891
|
+
return logger.warn(
|
|
892
|
+
`ObservedPeerConnection received an invalid OutboundTrackSample (missing timestamp OR id OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
|
|
893
|
+
stats
|
|
894
|
+
);
|
|
895
|
+
}
|
|
896
|
+
const observedMediaSource = [ ...this.observedMediaSources.values() ].find((mediaSource) => mediaSource.trackIdentifier === stats.id);
|
|
897
|
+
const outboundRtps = observedMediaSource
|
|
898
|
+
? [ ...this.observedOutboundRtps.values() ].filter((outboundRtp) => outboundRtp.mediaSourceId === observedMediaSource?.id) : undefined;
|
|
899
|
+
|
|
900
|
+
observedOutboundTrack = new ObservedOutboundTrack(
|
|
901
|
+
stats.timestamp,
|
|
902
|
+
stats.id,
|
|
903
|
+
stats.kind as MediaKind,
|
|
904
|
+
this,
|
|
905
|
+
outboundRtps,
|
|
906
|
+
observedMediaSource,
|
|
907
|
+
);
|
|
908
|
+
|
|
909
|
+
this.observedOutboundTracks.set(stats.id, observedOutboundTrack);
|
|
910
|
+
this.emit('added-outbound-track', observedOutboundTrack);
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
observedOutboundTrack.update(stats);
|
|
914
|
+
|
|
915
|
+
return observedOutboundTrack;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
private _updatePeerConnectionTransportStats(stats: PeerConnectionTransportStats) {
|
|
919
|
+
let observedPeerConnectionTransport = this.observedPeerConnectionTransports.get(stats.id);
|
|
920
|
+
|
|
921
|
+
if (!observedPeerConnectionTransport) {
|
|
922
|
+
if (!stats.timestamp || !stats.id) {
|
|
923
|
+
return logger.warn(
|
|
924
|
+
`ObservedPeerConnection received an invalid PeerConnectionTransportStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
|
|
925
|
+
stats
|
|
926
|
+
);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
observedPeerConnectionTransport = new ObservedPeerConnectionTransport(stats.timestamp, stats.id, this);
|
|
930
|
+
|
|
931
|
+
this.observedPeerConnectionTransports.set(stats.id, observedPeerConnectionTransport);
|
|
932
|
+
this.emit('added-peer-connection-transport', observedPeerConnectionTransport);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
observedPeerConnectionTransport.update(stats);
|
|
936
|
+
|
|
937
|
+
return observedPeerConnectionTransport;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
private _updateRemoteInboundRtpStats(stats: RemoteInboundRtpStats) {
|
|
941
|
+
let observedRemoteInboundRtp = this.observedRemoteInboundRtps.get(stats.ssrc);
|
|
942
|
+
|
|
943
|
+
if (!observedRemoteInboundRtp) {
|
|
944
|
+
if (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind) {
|
|
945
|
+
return logger.warn(
|
|
946
|
+
`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}`,
|
|
947
|
+
stats
|
|
948
|
+
);
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
observedRemoteInboundRtp = new ObservedRemoteInboundRtp(
|
|
952
|
+
stats.timestamp,
|
|
953
|
+
stats.id,
|
|
954
|
+
stats.ssrc,
|
|
955
|
+
stats.kind as MediaKind,
|
|
956
|
+
this
|
|
957
|
+
);
|
|
958
|
+
|
|
959
|
+
this.observedRemoteInboundRtps.set(stats.ssrc, observedRemoteInboundRtp);
|
|
960
|
+
this.emit('added-remote-inbound-rtp', observedRemoteInboundRtp);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
observedRemoteInboundRtp.update(stats);
|
|
964
|
+
|
|
965
|
+
return observedRemoteInboundRtp;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
private _updateRemoteOutboundRtpStats(stats: RemoteOutboundRtpStats) {
|
|
969
|
+
let observedRemoteOutboundRtp = this.observedRemoteOutboundRtps.get(stats.ssrc);
|
|
970
|
+
|
|
971
|
+
if (!observedRemoteOutboundRtp) {
|
|
972
|
+
if (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind) {
|
|
973
|
+
return logger.warn(
|
|
974
|
+
`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}`,
|
|
975
|
+
stats
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
observedRemoteOutboundRtp = new ObservedRemoteOutboundRtp(
|
|
980
|
+
stats.timestamp,
|
|
981
|
+
stats.id,
|
|
982
|
+
stats.ssrc,
|
|
983
|
+
stats.kind as MediaKind,
|
|
984
|
+
this
|
|
985
|
+
);
|
|
986
|
+
|
|
987
|
+
this.observedRemoteOutboundRtps.set(stats.ssrc, observedRemoteOutboundRtp);
|
|
988
|
+
this.emit('added-remote-outbound-rtp', observedRemoteOutboundRtp);
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
observedRemoteOutboundRtp.update(stats);
|
|
992
|
+
|
|
993
|
+
return observedRemoteOutboundRtp;
|
|
994
|
+
}
|
|
995
|
+
}
|