@observertc/observer-js 1.0.1-c3edea3.0 → 1.0.1-c665f5a.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/README.md +535 -1
- package/lib/ObservedCall.d.ts +45 -7
- package/lib/ObservedCall.d.ts.map +1 -1
- package/lib/ObservedCall.js +156 -14
- package/lib/ObservedCallEventMonitor.d.ts +104 -0
- package/lib/ObservedCallEventMonitor.d.ts.map +1 -0
- package/lib/ObservedCallEventMonitor.js +314 -0
- package/lib/ObservedCallSummary.d.ts +18 -0
- package/lib/ObservedCallSummary.d.ts.map +1 -0
- package/lib/ObservedClient.d.ts +78 -19
- package/lib/ObservedClient.d.ts.map +1 -1
- package/lib/ObservedClient.js +537 -80
- package/lib/ObservedClientEventMonitor.d.ts +91 -0
- package/lib/ObservedClientEventMonitor.d.ts.map +1 -0
- package/lib/ObservedClientEventMonitor.js +254 -0
- package/lib/ObservedClientSummary.d.ts +23 -0
- package/lib/ObservedClientSummary.d.ts.map +1 -0
- package/lib/ObservedClientSummary.js +2 -0
- package/lib/ObservedTURN.d.ts +31 -0
- package/lib/ObservedTURN.d.ts.map +1 -0
- package/lib/ObservedTURN.js +59 -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 +42 -22
- package/lib/Observer.d.ts.map +1 -1
- package/lib/Observer.js +115 -40
- package/lib/ObserverEventMonitor.d.ts +138 -0
- package/lib/ObserverEventMonitor.d.ts.map +1 -0
- package/lib/ObserverEventMonitor.js +433 -0
- package/lib/ObserverSummary.d.ts +13 -0
- package/lib/ObserverSummary.d.ts.map +1 -0
- package/lib/ObserverSummary.js +2 -0
- package/lib/common/utils.d.ts +2 -1
- package/lib/common/utils.d.ts.map +1 -1
- package/lib/common/utils.js +11 -3
- package/lib/index.d.ts +22 -16
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +25 -17
- package/lib/mediasoup/ObservedMediasoupRouter.d.ts +7 -0
- package/lib/mediasoup/ObservedMediasoupRouter.d.ts.map +1 -0
- package/lib/mediasoup/ObservedMediasoupRouter.js +12 -0
- package/lib/schema/ClientEventTypes.d.ts +228 -0
- package/lib/schema/ClientEventTypes.d.ts.map +1 -0
- package/lib/schema/ClientEventTypes.js +41 -0
- package/lib/schema/{metaTypes.d.ts → ClientMetaTypes.d.ts} +2 -2
- package/lib/schema/ClientMetaTypes.d.ts.map +1 -0
- package/lib/schema/ClientMetaTypes.js +16 -0
- package/lib/schema/ClientSample.d.ts +1 -1
- package/lib/schema/ClientSample.d.ts.map +1 -1
- package/lib/updaters/CallUpdater.d.ts.map +1 -0
- package/lib/updaters/CallUpdater.js +2 -0
- package/lib/updaters/ObserverUpdater.d.ts +5 -0
- package/lib/updaters/ObserverUpdater.d.ts.map +1 -0
- package/lib/updaters/ObserverUpdater.js +2 -0
- package/lib/updaters/OnAllCallObserverUpdater.d.ts +15 -0
- package/lib/updaters/OnAllCallObserverUpdater.d.ts.map +1 -0
- package/lib/updaters/OnAllCallObserverUpdater.js +50 -0
- package/lib/updaters/OnAllClientCallUpdater.d.ts +15 -0
- package/lib/updaters/OnAllClientCallUpdater.d.ts.map +1 -0
- package/lib/updaters/OnAllClientCallUpdater.js +53 -0
- package/lib/updaters/OnAnyCallObserverUpdater.d.ts +12 -0
- package/lib/updaters/OnAnyCallObserverUpdater.d.ts.map +1 -0
- package/lib/updaters/OnAnyCallObserverUpdater.js +37 -0
- package/lib/updaters/OnAnyClientCallUpdater.d.ts +12 -0
- package/lib/updaters/OnAnyClientCallUpdater.d.ts.map +1 -0
- package/lib/updaters/OnAnyClientCallUpdater.js +36 -0
- package/lib/updaters/OnIntervalUpdater.d.ts +10 -0
- package/lib/updaters/OnIntervalUpdater.d.ts.map +1 -0
- package/lib/updaters/OnIntervalUpdater.js +17 -0
- package/lib/updaters/Updater.d.ts +6 -0
- package/lib/updaters/Updater.d.ts.map +1 -0
- package/lib/updaters/Updater.js +2 -0
- package/lib/utils/MediasoupRemoteTrackResolver.d.ts +25 -0
- package/lib/utils/MediasoupRemoteTrackResolver.d.ts.map +1 -0
- package/lib/utils/MediasoupRemoteTrackResolver.js +110 -0
- package/lib/utils/RemoteTrackResolver.d.ts +2 -2
- package/lib/utils/RemoteTrackResolver.d.ts.map +1 -1
- package/lib/{ObservedCertificate.d.ts → webrtc/ObservedCertificate.d.ts} +1 -1
- package/lib/webrtc/ObservedCertificate.d.ts.map +1 -0
- package/lib/{ObservedCodec.d.ts → webrtc/ObservedCodec.d.ts} +1 -1
- package/lib/webrtc/ObservedCodec.d.ts.map +1 -0
- package/lib/{ObservedDataChannel.d.ts → webrtc/ObservedDataChannel.d.ts} +7 -1
- package/lib/webrtc/ObservedDataChannel.d.ts.map +1 -0
- package/lib/{ObservedDataChannel.js → webrtc/ObservedDataChannel.js} +30 -0
- package/lib/{ObservedIceCandidate.d.ts → webrtc/ObservedIceCandidate.d.ts} +1 -1
- package/lib/webrtc/ObservedIceCandidate.d.ts.map +1 -0
- package/lib/{ObservedIceCandidatePair.d.ts → webrtc/ObservedIceCandidatePair.d.ts} +7 -2
- package/lib/webrtc/ObservedIceCandidatePair.d.ts.map +1 -0
- package/lib/{ObservedIceCandidatePair.js → webrtc/ObservedIceCandidatePair.js} +45 -1
- package/lib/{ObservedIceTransport.d.ts → webrtc/ObservedIceTransport.d.ts} +5 -1
- package/lib/webrtc/ObservedIceTransport.d.ts.map +1 -0
- package/lib/{ObservedIceTransport.js → webrtc/ObservedIceTransport.js} +28 -0
- package/lib/{ObservedInboundRtp.d.ts → webrtc/ObservedInboundRtp.d.ts} +2 -2
- package/lib/webrtc/ObservedInboundRtp.d.ts.map +1 -0
- package/lib/{ObservedInboundTrack.d.ts → webrtc/ObservedInboundTrack.d.ts} +7 -4
- package/lib/webrtc/ObservedInboundTrack.d.ts.map +1 -0
- package/lib/{ObservedInboundTrack.js → webrtc/ObservedInboundTrack.js} +4 -1
- package/lib/{ObservedMediaPlayout.d.ts → webrtc/ObservedMediaPlayout.d.ts} +2 -2
- package/lib/webrtc/ObservedMediaPlayout.d.ts.map +1 -0
- package/lib/{ObservedMediaSource.d.ts → webrtc/ObservedMediaSource.d.ts} +2 -2
- package/lib/webrtc/ObservedMediaSource.d.ts.map +1 -0
- package/lib/{ObservedOutboundRtp.d.ts → webrtc/ObservedOutboundRtp.d.ts} +2 -2
- package/lib/webrtc/ObservedOutboundRtp.d.ts.map +1 -0
- package/lib/{ObservedOutboundTrack.d.ts → webrtc/ObservedOutboundTrack.d.ts} +7 -4
- package/lib/webrtc/ObservedOutboundTrack.d.ts.map +1 -0
- package/lib/{ObservedOutboundTrack.js → webrtc/ObservedOutboundTrack.js} +4 -1
- package/lib/{ObservedPeerConnection.d.ts → webrtc/ObservedPeerConnection.d.ts} +39 -5
- package/lib/webrtc/ObservedPeerConnection.d.ts.map +1 -0
- package/lib/{ObservedPeerConnection.js → webrtc/ObservedPeerConnection.js} +185 -30
- package/lib/{ObservedPeerConnectionTransport.d.ts → webrtc/ObservedPeerConnectionTransport.d.ts} +1 -1
- package/lib/webrtc/ObservedPeerConnectionTransport.d.ts.map +1 -0
- package/lib/{ObservedRemoteInboundRtp.d.ts → webrtc/ObservedRemoteInboundRtp.d.ts} +2 -2
- package/lib/webrtc/ObservedRemoteInboundRtp.d.ts.map +1 -0
- package/lib/{ObservedRemoteOutboundRtp.d.ts → webrtc/ObservedRemoteOutboundRtp.d.ts} +2 -2
- package/lib/webrtc/ObservedRemoteOutboundRtp.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/ObservedCall.ts +233 -17
- package/src/ObservedCallEventMonitor.ts +392 -0
- package/src/ObservedCallSummary.ts +22 -0
- package/src/ObservedClient.ts +644 -92
- package/src/ObservedClientEventMonitor.ts +309 -0
- package/src/ObservedClientSummary.ts +24 -0
- package/src/ObservedTURN.ts +87 -0
- package/src/ObservedTurnServer.ts +72 -0
- package/src/Observer.ts +168 -64
- package/src/ObserverEventMonitor.ts +551 -0
- package/src/ObserverSummary.ts +15 -0
- package/src/common/utils.ts +12 -2
- package/src/index.ts +22 -17
- package/src/mediasoup/ObservedMediasoupRouter.ts +12 -0
- package/src/schema/ClientEventTypes.ts +280 -0
- package/src/schema/{metaTypes.ts → ClientMetaTypes.ts} +1 -1
- package/src/schema/ClientSample.ts +1 -1
- package/src/updaters/ObserverUpdater.ts +5 -0
- package/src/updaters/OnAllCallObserverUpdater.ts +59 -0
- package/src/updaters/OnAllClientCallUpdater.ts +61 -0
- package/src/updaters/OnAnyCallObserverUpdater.ts +41 -0
- package/src/updaters/OnAnyClientCallUpdater.ts +39 -0
- package/src/updaters/OnIntervalUpdater.ts +19 -0
- package/src/updaters/Updater.ts +5 -0
- package/src/utils/MediasoupRemoteTrackResolver.ts +155 -0
- package/src/utils/RemoteTrackResolver.ts +2 -2
- package/src/{ObservedCertificate.ts → webrtc/ObservedCertificate.ts} +1 -1
- package/src/{ObservedCodec.ts → webrtc/ObservedCodec.ts} +1 -1
- package/src/{ObservedDataChannel.ts → webrtc/ObservedDataChannel.ts} +33 -1
- package/src/{ObservedIceCandidate.ts → webrtc/ObservedIceCandidate.ts} +1 -1
- package/src/{ObservedIceCandidatePair.ts → webrtc/ObservedIceCandidatePair.ts} +45 -3
- package/src/{ObservedIceTransport.ts → webrtc/ObservedIceTransport.ts} +30 -1
- package/src/{ObservedInboundRtp.ts → webrtc/ObservedInboundRtp.ts} +2 -2
- package/src/{ObservedInboundTrack.ts → webrtc/ObservedInboundTrack.ts} +9 -4
- package/src/{ObservedMediaPlayout.ts → webrtc/ObservedMediaPlayout.ts} +2 -2
- package/src/{ObservedMediaSource.ts → webrtc/ObservedMediaSource.ts} +2 -2
- package/src/{ObservedOutboundRtp.ts → webrtc/ObservedOutboundRtp.ts} +2 -2
- package/src/{ObservedOutboundTrack.ts → webrtc/ObservedOutboundTrack.ts} +9 -4
- package/src/{ObservedPeerConnection.ts → webrtc/ObservedPeerConnection.ts} +240 -51
- package/src/{ObservedPeerConnectionTransport.ts → webrtc/ObservedPeerConnectionTransport.ts} +1 -1
- package/src/{ObservedRemoteInboundRtp.ts → webrtc/ObservedRemoteInboundRtp.ts} +2 -2
- package/src/{ObservedRemoteOutboundRtp.ts → webrtc/ObservedRemoteOutboundRtp.ts} +2 -2
- package/tsconfig.json +1 -1
- package/lib/ObservedCertificate.d.ts.map +0 -1
- package/lib/ObservedCodec.d.ts.map +0 -1
- package/lib/ObservedDataChannel.d.ts.map +0 -1
- package/lib/ObservedIceCandidate.d.ts.map +0 -1
- package/lib/ObservedIceCandidatePair.d.ts.map +0 -1
- package/lib/ObservedIceTransport.d.ts.map +0 -1
- package/lib/ObservedInboundRtp.d.ts.map +0 -1
- package/lib/ObservedInboundTrack.d.ts.map +0 -1
- package/lib/ObservedMediaPlayout.d.ts.map +0 -1
- package/lib/ObservedMediaSource.d.ts.map +0 -1
- package/lib/ObservedOutboundRtp.d.ts.map +0 -1
- package/lib/ObservedOutboundTrack.d.ts.map +0 -1
- package/lib/ObservedPeerConnection.d.ts.map +0 -1
- package/lib/ObservedPeerConnectionTransport.d.ts.map +0 -1
- package/lib/ObservedRemoteInboundRtp.d.ts.map +0 -1
- package/lib/ObservedRemoteOutboundRtp.d.ts.map +0 -1
- package/lib/schema/eventTypes.d.ts +0 -33
- package/lib/schema/eventTypes.d.ts.map +0 -1
- package/lib/schema/eventTypes.js +0 -38
- package/lib/schema/metaTypes.d.ts.map +0 -1
- package/lib/schema/metaTypes.js +0 -16
- package/lib/utils/CallUpdater.d.ts.map +0 -1
- package/lib/utils/OnAllClientCallUpdater.d.ts +0 -16
- package/lib/utils/OnAllClientCallUpdater.d.ts.map +0 -1
- package/lib/utils/OnAllClientCallUpdater.js +0 -58
- package/lib/utils/onAnyClientCallUpdater.d.ts +0 -14
- package/lib/utils/onAnyClientCallUpdater.d.ts.map +0 -1
- package/lib/utils/onAnyClientCallUpdater.js +0 -51
- package/src/schema/eventTypes.ts +0 -36
- package/src/utils/OnAllClientCallUpdater.ts +0 -68
- package/src/utils/onAnyClientCallUpdater.ts +0 -59
- /package/lib/{utils/CallUpdater.js → ObservedCallSummary.js} +0 -0
- /package/lib/{utils → updaters}/CallUpdater.d.ts +0 -0
- /package/lib/{ObservedCertificate.js → webrtc/ObservedCertificate.js} +0 -0
- /package/lib/{ObservedCodec.js → webrtc/ObservedCodec.js} +0 -0
- /package/lib/{ObservedIceCandidate.js → webrtc/ObservedIceCandidate.js} +0 -0
- /package/lib/{ObservedInboundRtp.js → webrtc/ObservedInboundRtp.js} +0 -0
- /package/lib/{ObservedMediaPlayout.js → webrtc/ObservedMediaPlayout.js} +0 -0
- /package/lib/{ObservedMediaSource.js → webrtc/ObservedMediaSource.js} +0 -0
- /package/lib/{ObservedOutboundRtp.js → webrtc/ObservedOutboundRtp.js} +0 -0
- /package/lib/{ObservedPeerConnectionTransport.js → webrtc/ObservedPeerConnectionTransport.js} +0 -0
- /package/lib/{ObservedRemoteInboundRtp.js → webrtc/ObservedRemoteInboundRtp.js} +0 -0
- /package/lib/{ObservedRemoteOutboundRtp.js → webrtc/ObservedRemoteOutboundRtp.js} +0 -0
- /package/src/{utils → updaters}/CallUpdater.ts +0 -0
package/src/ObservedClient.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
import { ObservedPeerConnection } from './ObservedPeerConnection';
|
|
2
|
+
import { ObservedPeerConnection } from './webrtc/ObservedPeerConnection';
|
|
3
3
|
import { createLogger } from './common/logger';
|
|
4
4
|
// eslint-disable-next-line camelcase
|
|
5
5
|
import { ClientEvent, ClientMetaData, ClientSample, PeerConnectionSample, ClientIssue, ExtensionStat } from './schema/ClientSample';
|
|
6
|
-
import * as MetaData from './schema/
|
|
7
|
-
import {
|
|
6
|
+
import * as MetaData from './schema/ClientMetaTypes';
|
|
7
|
+
import { ClientEventTypes } from './schema/ClientEventTypes';
|
|
8
8
|
import { ObservedCall } from './ObservedCall';
|
|
9
|
-
import {
|
|
9
|
+
import { ClientMetaTypes } from './schema/ClientMetaTypes';
|
|
10
10
|
import { parseJsonAs } from './common/utils';
|
|
11
11
|
import { CalculatedScore } from './scores/CalculatedScore';
|
|
12
12
|
import { Detectors } from './detectors/Detectors';
|
|
@@ -15,24 +15,23 @@ const logger = createLogger('ObservedClient');
|
|
|
15
15
|
|
|
16
16
|
export type ObservedClientSettings<AppData extends Record<string, unknown> = Record<string, unknown>> = {
|
|
17
17
|
clientId: string;
|
|
18
|
+
maxIdleTimeMs?: number;
|
|
18
19
|
appData?: AppData;
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
export type ObservedClientEvents = {
|
|
22
|
-
update: [
|
|
23
|
-
{
|
|
24
|
-
sample: ClientSample;
|
|
25
|
-
elapsedTimeInMs: number;
|
|
26
|
-
}
|
|
27
|
-
];
|
|
23
|
+
update: [sample: ClientSample, elapsedTimeInMs: number];
|
|
28
24
|
close: [];
|
|
29
25
|
joined: [];
|
|
26
|
+
issue: [ClientIssue];
|
|
27
|
+
metaData: [ClientMetaData];
|
|
30
28
|
rejoined: [timestamp: number];
|
|
31
29
|
left: [];
|
|
32
30
|
usingturn: [boolean];
|
|
33
31
|
usermediaerror: [string];
|
|
32
|
+
extensionStats: [ExtensionStat];
|
|
33
|
+
clientEvent: [ClientEvent];
|
|
34
34
|
|
|
35
|
-
// do we need this?
|
|
36
35
|
newpeerconnection: [ObservedPeerConnection];
|
|
37
36
|
};
|
|
38
37
|
|
|
@@ -46,14 +45,12 @@ export declare interface ObservedClient {
|
|
|
46
45
|
export class ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {
|
|
47
46
|
public readonly detectors: Detectors;
|
|
48
47
|
|
|
49
|
-
public readonly clientId: string;
|
|
50
48
|
public readonly observedPeerConnections = new Map<string, ObservedPeerConnection>();
|
|
51
49
|
public readonly calculatedScore: CalculatedScore = {
|
|
52
50
|
weight: 1,
|
|
53
51
|
value: undefined,
|
|
54
52
|
};
|
|
55
53
|
|
|
56
|
-
public appData?: AppData;
|
|
57
54
|
public attachments?: Record<string, unknown>;
|
|
58
55
|
|
|
59
56
|
public updated = Date.now();
|
|
@@ -62,6 +59,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
62
59
|
|
|
63
60
|
public joinedAt?: number;
|
|
64
61
|
public leftAt?: number;
|
|
62
|
+
public closedAt?: number;
|
|
63
|
+
public lastSampleTimestamp?: number;
|
|
65
64
|
// the timestamp of the CLIENT_JOINED event
|
|
66
65
|
public operationSystem?: MetaData.OperationSystem;
|
|
67
66
|
public engine?: MetaData.Engine;
|
|
@@ -70,48 +69,96 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
70
69
|
public mediaConstraints: string[] = [];
|
|
71
70
|
|
|
72
71
|
public usingTURN = false;
|
|
72
|
+
public usingTCP = false;
|
|
73
73
|
public availableOutgoingBitrate = 0;
|
|
74
74
|
public availableIncomingBitrate = 0;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
public
|
|
98
|
-
public
|
|
99
|
-
public
|
|
100
|
-
public
|
|
101
|
-
public
|
|
75
|
+
|
|
76
|
+
public totalInboundPacketsLost = 0;
|
|
77
|
+
public totalInboundPacketsReceived = 0;
|
|
78
|
+
public totalOutboundPacketsSent = 0;
|
|
79
|
+
public totalDataChannelBytesSent = 0;
|
|
80
|
+
public totalDataChannelBytesReceived = 0;
|
|
81
|
+
public totalDataChannelMessagesSent = 0;
|
|
82
|
+
public totalDataChannelMessagesReceived = 0;
|
|
83
|
+
public totalReceivedAudioBytes = 0;
|
|
84
|
+
public totalReceivedVideoBytes = 0;
|
|
85
|
+
public totalSentAudioBytes = 0;
|
|
86
|
+
public totalSentVideoBytes = 0;
|
|
87
|
+
public totalSentBytes = 0;
|
|
88
|
+
public totalReceivedBytes = 0;
|
|
89
|
+
|
|
90
|
+
public deltaReceivedAudioBytes = 0;
|
|
91
|
+
public deltaReceivedVideoBytes = 0;
|
|
92
|
+
public deltaSentAudioBytes = 0;
|
|
93
|
+
public deltaSentVideoBytes = 0;
|
|
94
|
+
public deltaDataChannelBytesSent = 0;
|
|
95
|
+
public deltaDataChannelBytesReceived = 0;
|
|
96
|
+
public deltaDataChannelMessagesSent = 0;
|
|
97
|
+
public deltaDataChannelMessagesReceived = 0;
|
|
98
|
+
public deltaInboundPacketsLost = 0;
|
|
99
|
+
public deltaInboundPacketsReceived = 0;
|
|
100
|
+
public deltaOutboundPacketsSent = 0;
|
|
101
|
+
public deltaTransportSentBytes = 0;
|
|
102
|
+
public deltaTransportReceivedBytes = 0;
|
|
103
|
+
public deltaRttLt50Measurements = 0;
|
|
104
|
+
public deltaRttLt150Measurements = 0;
|
|
105
|
+
public deltaRttLt300Measurements = 0;
|
|
106
|
+
public deltaRttGtOrEq300Measurements = 0;
|
|
107
|
+
|
|
108
|
+
public currentMaxRttInMs?: number;
|
|
109
|
+
public currentMinRttInMs?: number;
|
|
110
|
+
public currentAvgRttInMs?: number;
|
|
111
|
+
|
|
112
|
+
public sendingAudioBitrate = 0;
|
|
113
|
+
public sendingVideoBitrate = 0;
|
|
114
|
+
public receivingAudioBitrate = 0;
|
|
115
|
+
public receivingVideoBitrate = 0;
|
|
116
|
+
|
|
117
|
+
public numberOfInboundRtpStreams = 0;
|
|
118
|
+
public numberOfInbundTracks = 0;
|
|
119
|
+
public numberOfOutboundRtpStreams = 0;
|
|
120
|
+
public numberOfOutboundTracks = 0;
|
|
121
|
+
public numberOfDataChannels = 0;
|
|
122
|
+
|
|
123
|
+
public totalRttLt50Measurements = 0;
|
|
124
|
+
public totalRttLt150Measurements = 0;
|
|
125
|
+
public totalRttLt300Measurements = 0;
|
|
126
|
+
public totalRttGtOrEq300Measurements = 0;
|
|
127
|
+
public deltaNumberOfIssues = 0;
|
|
128
|
+
|
|
129
|
+
public totalScoreSum = 0;
|
|
130
|
+
public numberOfScoreMeasurements = 0;
|
|
131
|
+
public totalNumberOfIssues = 0;
|
|
102
132
|
|
|
103
133
|
public readonly mediaDevices: MetaData.MediaDeviceInfo[] = [];
|
|
104
134
|
public issues: ClientIssue[] = [];
|
|
105
135
|
|
|
106
|
-
|
|
136
|
+
private _injections: Pick<ClientSample, 'clientEvents' | 'clientIssues' | 'extensionStats' | 'attachments' | 'clientMetaItems'> = {};
|
|
137
|
+
private _autoCloseTimer?: ReturnType<typeof setTimeout>;
|
|
138
|
+
|
|
139
|
+
public constructor(
|
|
140
|
+
public readonly settings: ObservedClientSettings<AppData>,
|
|
141
|
+
public readonly call: ObservedCall
|
|
142
|
+
) {
|
|
107
143
|
super();
|
|
108
144
|
this.setMaxListeners(Infinity);
|
|
145
|
+
this._createAutoClose();
|
|
109
146
|
|
|
110
|
-
this.clientId = settings.clientId;
|
|
111
|
-
this.appData = settings.appData;
|
|
112
147
|
this.detectors = new Detectors();
|
|
113
148
|
}
|
|
114
149
|
|
|
150
|
+
public get clientId() {
|
|
151
|
+
return this.settings.clientId;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
public get appData(): AppData {
|
|
155
|
+
return this.settings.appData ?? {} as AppData;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
public get numberOfPeerConnections() {
|
|
159
|
+
return this.observedPeerConnections.size;
|
|
160
|
+
}
|
|
161
|
+
|
|
115
162
|
public get score() {
|
|
116
163
|
return this.calculatedScore.value;
|
|
117
164
|
}
|
|
@@ -120,47 +167,216 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
120
167
|
if (this.closed) return;
|
|
121
168
|
this.closed = true;
|
|
122
169
|
|
|
170
|
+
this._injections.clientEvents?.forEach((clientEvent) => this._processClientEvent(clientEvent));
|
|
171
|
+
this._injections.clientIssues?.forEach((clientIssue) => this.addIssue(clientIssue));
|
|
172
|
+
this._injections.extensionStats?.forEach((extensionStat) => this.addExtensionStats(extensionStat));
|
|
173
|
+
this._injections.clientMetaItems?.forEach((clientMetaItem) => this.addMetadata(clientMetaItem));
|
|
174
|
+
|
|
123
175
|
Array.from(this.observedPeerConnections.values()).forEach((peerConnection) => peerConnection.close());
|
|
176
|
+
if (!this.leftAt) {
|
|
177
|
+
this.leftAt = this.lastSampleTimestamp;
|
|
178
|
+
|
|
179
|
+
if (this.leftAt) {
|
|
180
|
+
this.emit('left');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
this.closedAt = Date.now();
|
|
124
184
|
|
|
125
185
|
this.emit('close');
|
|
126
186
|
}
|
|
127
187
|
|
|
188
|
+
private _createAutoClose() {
|
|
189
|
+
if (this.closed) return;
|
|
190
|
+
if (this.settings.maxIdleTimeMs === undefined || this.settings.maxIdleTimeMs < 1) return;
|
|
191
|
+
|
|
192
|
+
this._autoCloseTimer = setTimeout(() => {
|
|
193
|
+
if (this.closed) return;
|
|
194
|
+
|
|
195
|
+
logger.debug(`Client ${this.clientId} is idle for ${this.settings.maxIdleTimeMs}ms, closing...`);
|
|
196
|
+
this.close();
|
|
197
|
+
}, this.settings.maxIdleTimeMs);
|
|
198
|
+
}
|
|
199
|
+
|
|
128
200
|
public accept(sample: ClientSample): void {
|
|
129
201
|
if (this.closed) throw new Error(`Client ${this.clientId} is closed`);
|
|
202
|
+
|
|
203
|
+
this._createAutoClose();
|
|
130
204
|
|
|
131
205
|
const now = Date.now();
|
|
206
|
+
const elapsedInMs = now - this.updated;
|
|
207
|
+
const elapsedInSeconds = elapsedInMs / 1000;
|
|
208
|
+
let sumOfRtts = 0;
|
|
209
|
+
let numberOfRttMeasurements = 0;
|
|
210
|
+
|
|
211
|
+
++this.acceptedSamples;
|
|
212
|
+
|
|
213
|
+
this.availableIncomingBitrate = 0;
|
|
214
|
+
this.availableOutgoingBitrate = 0;
|
|
215
|
+
this.deltaDataChannelBytesReceived = 0;
|
|
216
|
+
this.deltaDataChannelBytesSent = 0;
|
|
217
|
+
this.deltaDataChannelMessagesReceived = 0;
|
|
218
|
+
this.deltaDataChannelMessagesSent = 0;
|
|
219
|
+
this.deltaInboundPacketsLost = 0;
|
|
220
|
+
this.deltaInboundPacketsReceived = 0;
|
|
221
|
+
this.deltaOutboundPacketsSent = 0;
|
|
222
|
+
this.deltaReceivedAudioBytes = 0;
|
|
223
|
+
this.deltaReceivedVideoBytes = 0;
|
|
224
|
+
this.deltaSentAudioBytes = 0;
|
|
225
|
+
this.deltaSentVideoBytes = 0;
|
|
226
|
+
this.deltaTransportReceivedBytes = 0;
|
|
227
|
+
this.deltaTransportSentBytes = 0;
|
|
228
|
+
this.deltaRttLt50Measurements = 0;
|
|
229
|
+
this.deltaRttLt150Measurements = 0;
|
|
230
|
+
this.deltaRttLt300Measurements = 0;
|
|
231
|
+
this.deltaRttGtOrEq300Measurements = 0;
|
|
232
|
+
this.deltaNumberOfIssues = 0;
|
|
233
|
+
|
|
234
|
+
this.numberOfDataChannels = 0;
|
|
235
|
+
this.numberOfInboundRtpStreams = 0;
|
|
236
|
+
this.numberOfInbundTracks = 0;
|
|
237
|
+
this.numberOfOutboundRtpStreams = 0;
|
|
238
|
+
this.numberOfOutboundTracks = 0;
|
|
239
|
+
this.usingTURN = false;
|
|
240
|
+
this.usingTCP = false;
|
|
241
|
+
this.currentMinRttInMs = undefined;
|
|
242
|
+
this.currentMaxRttInMs = undefined;
|
|
243
|
+
|
|
244
|
+
this._mergeInjections(sample);
|
|
245
|
+
|
|
246
|
+
const clientEventsPostBuffer: ClientEvent[] = [];
|
|
247
|
+
|
|
248
|
+
for (const clientEvent of sample.clientEvents ?? []) {
|
|
249
|
+
this._processClientEvent(clientEvent, clientEventsPostBuffer);
|
|
250
|
+
|
|
251
|
+
this.call.observer.emit('client-event', this, clientEvent);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
for (const metaData of sample.clientMetaItems ?? []) {
|
|
255
|
+
this.addMetadata(metaData);
|
|
256
|
+
}
|
|
132
257
|
|
|
133
|
-
sample.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
258
|
+
for (const issue of sample.clientIssues ?? []) {
|
|
259
|
+
this.addIssue(issue);
|
|
260
|
+
|
|
261
|
+
++this.deltaNumberOfIssues;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
for (const extensionStat of sample.extensionStats ?? []) {
|
|
265
|
+
this.addExtensionStats(extensionStat);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
for (const pcSample of sample.peerConnections ?? []) {
|
|
269
|
+
const observedPeerConnection = this._updatePeerConnection(pcSample);
|
|
270
|
+
|
|
271
|
+
if (!observedPeerConnection) continue;
|
|
272
|
+
|
|
273
|
+
this.deltaDataChannelBytesReceived += observedPeerConnection.deltaDataChannelBytesReceived;
|
|
274
|
+
this.deltaDataChannelBytesSent += observedPeerConnection.deltaDataChannelBytesSent;
|
|
275
|
+
this.deltaDataChannelMessagesReceived += observedPeerConnection.deltaDataChannelMessagesReceived;
|
|
276
|
+
this.deltaDataChannelMessagesSent += observedPeerConnection.deltaDataChannelMessagesSent;
|
|
277
|
+
this.deltaInboundPacketsLost += observedPeerConnection.deltaInboundPacketsLost;
|
|
278
|
+
this.deltaInboundPacketsReceived += observedPeerConnection.deltaInboundPacketsReceived;
|
|
279
|
+
this.deltaOutboundPacketsSent += observedPeerConnection.deltaOutboundPacketsSent;
|
|
280
|
+
this.deltaReceivedAudioBytes += observedPeerConnection.deltaReceivedAudioBytes;
|
|
281
|
+
this.deltaReceivedVideoBytes += observedPeerConnection.deltaReceivedVideoBytes;
|
|
282
|
+
this.deltaSentAudioBytes += observedPeerConnection.deltaSentAudioBytes;
|
|
283
|
+
this.deltaSentVideoBytes += observedPeerConnection.deltaSentVideoBytes;
|
|
284
|
+
this.deltaTransportReceivedBytes += observedPeerConnection.deltaTransportReceivedBytes;
|
|
285
|
+
this.deltaTransportSentBytes += observedPeerConnection.deltaTransportSentBytes;
|
|
286
|
+
|
|
287
|
+
this.availableIncomingBitrate += observedPeerConnection.availableIncomingBitrate;
|
|
288
|
+
this.availableOutgoingBitrate += observedPeerConnection.availableOutgoingBitrate;
|
|
289
|
+
|
|
290
|
+
this.numberOfDataChannels += observedPeerConnection.observedDataChannels.size;
|
|
291
|
+
this.numberOfInbundTracks += observedPeerConnection.observedInboundTracks.size;
|
|
292
|
+
this.numberOfOutboundRtpStreams += observedPeerConnection.observedOutboundRtps.size;
|
|
293
|
+
this.numberOfOutboundTracks += observedPeerConnection.observedOutboundTracks.size;
|
|
294
|
+
this.numberOfInboundRtpStreams += observedPeerConnection.observedInboundRtps.size;
|
|
295
|
+
|
|
296
|
+
if (observedPeerConnection.usingTURN) {
|
|
297
|
+
this.usingTURN = true;
|
|
298
|
+
}
|
|
299
|
+
if (observedPeerConnection.usingTCP) {
|
|
300
|
+
this.usingTCP = true;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (observedPeerConnection.currentRttInMs) {
|
|
304
|
+
if (this.currentMinRttInMs === undefined || observedPeerConnection.currentRttInMs < this.currentMinRttInMs) {
|
|
305
|
+
this.currentMinRttInMs = observedPeerConnection.currentRttInMs;
|
|
306
|
+
}
|
|
307
|
+
if (this.currentMaxRttInMs === undefined || observedPeerConnection.currentRttInMs > this.currentMaxRttInMs) {
|
|
308
|
+
this.currentMaxRttInMs = observedPeerConnection.currentRttInMs;
|
|
309
|
+
}
|
|
310
|
+
if (observedPeerConnection.currentRttInMs < 50) {
|
|
311
|
+
this.deltaRttLt50Measurements += 1;
|
|
312
|
+
} else if (observedPeerConnection.currentRttInMs < 150) {
|
|
313
|
+
this.deltaRttLt150Measurements += 1;
|
|
314
|
+
} else if (observedPeerConnection.currentRttInMs < 300) {
|
|
315
|
+
this.deltaRttLt300Measurements += 1;
|
|
316
|
+
} else if (300 <= observedPeerConnection.currentRttInMs) {
|
|
317
|
+
this.deltaRttGtOrEq300Measurements += 1;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
sumOfRtts += observedPeerConnection.currentRttInMs;
|
|
321
|
+
++numberOfRttMeasurements;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
for (const clientEvent of clientEventsPostBuffer) {
|
|
326
|
+
this._processClientEvent(clientEvent);
|
|
327
|
+
}
|
|
138
328
|
|
|
139
329
|
// emit new attachments?
|
|
140
330
|
this.attachments = sample.attachments;
|
|
141
331
|
|
|
332
|
+
this.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
|
|
333
|
+
this.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
|
|
334
|
+
this.totalDataChannelMessagesReceived += this.deltaDataChannelMessagesReceived;
|
|
335
|
+
this.totalDataChannelMessagesSent += this.deltaDataChannelMessagesSent;
|
|
336
|
+
this.totalInboundPacketsLost += this.deltaInboundPacketsLost;
|
|
337
|
+
this.totalInboundPacketsReceived += this.deltaInboundPacketsReceived;
|
|
338
|
+
this.totalOutboundPacketsSent += this.deltaOutboundPacketsSent;
|
|
339
|
+
this.totalReceivedAudioBytes += this.deltaReceivedAudioBytes;
|
|
340
|
+
this.totalReceivedVideoBytes += this.deltaReceivedVideoBytes;
|
|
341
|
+
this.totalSentAudioBytes += this.deltaSentAudioBytes;
|
|
342
|
+
this.totalSentVideoBytes += this.deltaSentVideoBytes;
|
|
343
|
+
this.totalReceivedBytes += this.deltaTransportReceivedBytes;
|
|
344
|
+
this.totalSentBytes += this.deltaTransportSentBytes;
|
|
345
|
+
this.totalRttLt50Measurements += this.deltaRttLt50Measurements;
|
|
346
|
+
this.totalRttLt150Measurements += this.deltaRttLt150Measurements;
|
|
347
|
+
this.totalRttLt300Measurements += this.deltaRttLt300Measurements;
|
|
348
|
+
this.totalRttGtOrEq300Measurements += this.deltaRttGtOrEq300Measurements;
|
|
349
|
+
this.totalNumberOfIssues += this.deltaNumberOfIssues;
|
|
350
|
+
|
|
351
|
+
this.receivingAudioBitrate = (this.deltaReceivedAudioBytes * 8) / (elapsedInSeconds);
|
|
352
|
+
this.receivingVideoBitrate = (this.totalReceivedVideoBytes * 8) / (elapsedInSeconds);
|
|
353
|
+
this.sendingAudioBitrate = (this.deltaSentAudioBytes * 8) / (elapsedInSeconds);
|
|
354
|
+
this.sendingVideoBitrate = (this.deltaSentVideoBytes * 8) / (elapsedInSeconds);
|
|
355
|
+
this.currentAvgRttInMs = 0 < numberOfRttMeasurements ? sumOfRtts / numberOfRttMeasurements : undefined;
|
|
356
|
+
|
|
142
357
|
this.calculatedScore.value = sample.score;
|
|
143
358
|
this.detectors.update();
|
|
144
359
|
|
|
360
|
+
this.lastSampleTimestamp = sample.timestamp;
|
|
145
361
|
// emit update
|
|
146
|
-
this.emit('update',
|
|
362
|
+
this.emit('update',
|
|
147
363
|
sample,
|
|
148
|
-
|
|
149
|
-
|
|
364
|
+
now - this.updated,
|
|
365
|
+
);
|
|
150
366
|
this.updated = now;
|
|
367
|
+
|
|
368
|
+
// if result changed after update
|
|
369
|
+
if (this.calculatedScore.value) {
|
|
370
|
+
this.totalScoreSum += this.calculatedScore.value;
|
|
371
|
+
++this.numberOfScoreMeasurements;
|
|
372
|
+
}
|
|
151
373
|
}
|
|
152
374
|
|
|
153
|
-
private _processClientEvent(event: ClientEvent) {
|
|
375
|
+
private _processClientEvent(event: ClientEvent, postBuffer?: ClientEvent[]) {
|
|
376
|
+
// eslint-disable-next-line no-console
|
|
377
|
+
// console.warn('ClientEvent', event);
|
|
154
378
|
switch (event.type) {
|
|
155
|
-
case
|
|
156
|
-
// update call timestamp if it's the first time
|
|
157
|
-
break;
|
|
158
|
-
}
|
|
159
|
-
case ClientEventType.CALL_ENDED: {
|
|
160
|
-
// update call timestamp if it's the first time
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
case ClientEventType.CLIENT_JOINED: {
|
|
379
|
+
case ClientEventTypes.CLIENT_JOINED: {
|
|
164
380
|
if (event.timestamp) {
|
|
165
381
|
if (!this.joinedAt) {
|
|
166
382
|
this.joinedAt = event.timestamp;
|
|
@@ -172,78 +388,321 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
172
388
|
logger.warn(`Client ${this.clientId} joinedAt timestamp was updated to ${event.timestamp}. the joined event will not be emitted.`);
|
|
173
389
|
}
|
|
174
390
|
}
|
|
391
|
+
logger.debug('Client %s joined at %o', this.clientId, event);
|
|
175
392
|
break;
|
|
176
393
|
}
|
|
177
|
-
case
|
|
394
|
+
case ClientEventTypes.CLIENT_LEFT: {
|
|
178
395
|
if (event.timestamp) {
|
|
179
396
|
if (!this.leftAt) {
|
|
180
397
|
this.leftAt = event.timestamp;
|
|
181
398
|
this.emit('left');
|
|
399
|
+
} else {
|
|
400
|
+
logger.warn(`Client ${this.clientId} leftAt timestamp was already set`);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
}
|
|
404
|
+
logger.debug('Client %s left at %o', this.clientId, event);
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
407
|
+
case ClientEventTypes.PEER_CONNECTION_OPENED: {
|
|
408
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
409
|
+
|
|
410
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string') {
|
|
411
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
412
|
+
|
|
413
|
+
if (observedPeerConnection) {
|
|
414
|
+
observedPeerConnection.openedAt = event.timestamp;
|
|
415
|
+
} else if (postBuffer) {
|
|
416
|
+
postBuffer.push(event);
|
|
417
|
+
} else {
|
|
418
|
+
logger.warn('Received PEER_CONNECTION_OPENED event without a corresponding observedPeerConnection: %o', event);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
}
|
|
422
|
+
break;
|
|
423
|
+
}
|
|
424
|
+
case ClientEventTypes.PEER_CONNECTION_CLOSED: {
|
|
425
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
426
|
+
|
|
427
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string') {
|
|
428
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
429
|
+
|
|
430
|
+
if (observedPeerConnection) {
|
|
431
|
+
observedPeerConnection.closedAt = event.timestamp;
|
|
432
|
+
} else if (postBuffer) {
|
|
433
|
+
postBuffer.push(event);
|
|
434
|
+
} else {
|
|
435
|
+
logger.warn('Received PEER_CONNECTION_CLOSED event without a corresponding observedPeerConnection: %o', event);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
case ClientEventTypes.MEDIA_TRACK_ADDED: {
|
|
441
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
442
|
+
|
|
443
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
|
|
444
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
445
|
+
const observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
|
|
446
|
+
|
|
447
|
+
if (observedTrack) {
|
|
448
|
+
observedTrack.addedAt = event.timestamp;
|
|
449
|
+
} else if (postBuffer) {
|
|
450
|
+
postBuffer.push(event);
|
|
451
|
+
} else {
|
|
452
|
+
logger.warn('Received MEDIA_TRACK_ADDED event without a corresponding observedPeerConnection or observedTrack: %o', event);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
457
|
+
case ClientEventTypes.MEDIA_TRACK_REMOVED: {
|
|
458
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
459
|
+
|
|
460
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
|
|
461
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
462
|
+
const observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
|
|
463
|
+
|
|
464
|
+
if (observedTrack) {
|
|
465
|
+
observedTrack.removedAt = event.timestamp;
|
|
466
|
+
} else if (postBuffer) {
|
|
467
|
+
postBuffer.push(event);
|
|
468
|
+
} else {
|
|
469
|
+
logger.warn('Received MEDIA_TRACK_REMOVED event without a corresponding observedPeerConnection or observedTrack: %o', event);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
break;
|
|
473
|
+
}
|
|
474
|
+
case ClientEventTypes.DATA_CHANNEL_OPEN: {
|
|
475
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
476
|
+
|
|
477
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.dataChannelId && typeof payload.dataChannelId === 'string') {
|
|
478
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
479
|
+
const observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);
|
|
480
|
+
|
|
481
|
+
if (observedDataChannel) {
|
|
482
|
+
observedDataChannel.addedAt = event.timestamp;
|
|
483
|
+
} else if (postBuffer) {
|
|
484
|
+
postBuffer.push(event);
|
|
485
|
+
} else {
|
|
486
|
+
logger.warn('Received DATA_CHANNEL_OPENED event without a corresponding observedPeerConnection or observedDataChannel: %o', event);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
break;
|
|
490
|
+
}
|
|
491
|
+
case ClientEventTypes.DATA_CHANNEL_CLOSED: {
|
|
492
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
493
|
+
|
|
494
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.dataChannelId && typeof payload.dataChannelId === 'string') {
|
|
495
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
496
|
+
const observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);
|
|
497
|
+
|
|
498
|
+
if (observedDataChannel) {
|
|
499
|
+
observedDataChannel.removedAt = event.timestamp;
|
|
500
|
+
} else if (postBuffer) {
|
|
501
|
+
postBuffer.push(event);
|
|
502
|
+
} else {
|
|
503
|
+
logger.warn('Received DATA_CHANNEL_CLOSE event without a corresponding observedPeerConnection or observedDataChannel: %o', event);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
case ClientEventTypes.MEDIA_TRACK_MUTED: {
|
|
509
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
510
|
+
|
|
511
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
|
|
512
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
513
|
+
const observedInboundTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId);
|
|
514
|
+
const observedOutboundTrack = observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
|
|
515
|
+
|
|
516
|
+
if (observedPeerConnection) {
|
|
517
|
+
if (observedInboundTrack) {
|
|
518
|
+
observedInboundTrack.muted = true;
|
|
519
|
+
observedPeerConnection?.emit('muted-inbound-track', observedInboundTrack);
|
|
520
|
+
} else if (observedOutboundTrack) {
|
|
521
|
+
observedOutboundTrack.muted = true;
|
|
522
|
+
observedPeerConnection?.emit('muted-outbound-track', observedOutboundTrack);
|
|
523
|
+
}
|
|
524
|
+
} else if (postBuffer) {
|
|
525
|
+
postBuffer.push(event);
|
|
526
|
+
} else {
|
|
527
|
+
logger.warn('Received MEDIA_TRACK_MUTED event without a corresponding observedPeerConnection or observedTrack: %o', event);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
break;
|
|
532
|
+
}
|
|
533
|
+
case ClientEventTypes.MEDIA_TRACK_UNMUTED: {
|
|
534
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
535
|
+
|
|
536
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
|
|
537
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
538
|
+
const observedInboundTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId);
|
|
539
|
+
const observedOutboundTrack = observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
|
|
540
|
+
|
|
541
|
+
if (observedPeerConnection) {
|
|
542
|
+
if (observedInboundTrack) {
|
|
543
|
+
observedInboundTrack.muted = false;
|
|
544
|
+
observedPeerConnection?.emit('unmuted-inbound-track', observedInboundTrack);
|
|
545
|
+
} else if (observedOutboundTrack) {
|
|
546
|
+
observedOutboundTrack.muted = false;
|
|
547
|
+
observedPeerConnection?.emit('unmuted-outbound-track', observedOutboundTrack);
|
|
548
|
+
}
|
|
549
|
+
} else if (postBuffer) {
|
|
550
|
+
postBuffer.push(event);
|
|
551
|
+
} else {
|
|
552
|
+
logger.warn('Received MEDIA_TRACK_UNMUTED event without a corresponding observedPeerConnection or observedTrack: %o', event);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
break;
|
|
556
|
+
}
|
|
557
|
+
case ClientEventTypes.ICE_CONNECTION_STATE_CHANGED: {
|
|
558
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
559
|
+
|
|
560
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.iceConnectionState && typeof payload.iceConnectionState === 'string') {
|
|
561
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
562
|
+
|
|
563
|
+
if (observedPeerConnection) {
|
|
564
|
+
observedPeerConnection.iceConnectionState = payload.iceConnectionState;
|
|
565
|
+
observedPeerConnection.emit('iceconnectionstatechange', {
|
|
566
|
+
state: payload.iceConnectionState,
|
|
567
|
+
});
|
|
568
|
+
} else if (postBuffer) {
|
|
569
|
+
postBuffer.push(event);
|
|
570
|
+
} else {
|
|
571
|
+
logger.warn('Received ICE_CONNECTION_STATE_CHANGED event without a corresponding observedPeerConnection: %o', event);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
case ClientEventTypes.ICE_GATHERING_STATE_CHANGED: {
|
|
577
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
578
|
+
|
|
579
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.iceGatheringState && typeof payload.iceGatheringState === 'string') {
|
|
580
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
581
|
+
|
|
582
|
+
if (observedPeerConnection) {
|
|
583
|
+
observedPeerConnection.iceGatheringState = payload.iceGatheringState;
|
|
584
|
+
observedPeerConnection.emit('icegatheringstatechange', {
|
|
585
|
+
state: payload.iceGatheringState,
|
|
586
|
+
});
|
|
587
|
+
} else if (postBuffer) {
|
|
588
|
+
postBuffer.push(event);
|
|
589
|
+
} else {
|
|
590
|
+
logger.warn('Received ICE_GATHERING_STATE_CHANGED event without a corresponding observedPeerConnection: %o', event);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
break;
|
|
594
|
+
}
|
|
595
|
+
case ClientEventTypes.PEER_CONNECTION_STATE_CHANGED: {
|
|
596
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
597
|
+
|
|
598
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.peerConnectionState && typeof payload.peerConnectionState === 'string') {
|
|
599
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
600
|
+
|
|
601
|
+
if (observedPeerConnection) {
|
|
602
|
+
observedPeerConnection.connectionState = payload.peerConnectionState;
|
|
603
|
+
observedPeerConnection.emit('connectionstatechange', {
|
|
604
|
+
state: payload.peerConnectionState,
|
|
605
|
+
});
|
|
606
|
+
} else if (postBuffer) {
|
|
607
|
+
postBuffer.push(event);
|
|
608
|
+
} else {
|
|
609
|
+
logger.warn('Received PEER_CONNECTION_STATE_CHANGED event without a corresponding observedPeerConnection: %o', event);
|
|
182
610
|
}
|
|
183
611
|
}
|
|
184
612
|
break;
|
|
185
613
|
}
|
|
186
614
|
}
|
|
615
|
+
|
|
616
|
+
this.emit('clientEvent', event);
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
public injectMetaData(metaData: ClientMetaData) {
|
|
620
|
+
if (this.closed) return;
|
|
621
|
+
|
|
622
|
+
if (!this._injections.clientMetaItems) this._injections.clientMetaItems = [];
|
|
187
623
|
|
|
188
|
-
this.
|
|
189
|
-
call: this.call,
|
|
190
|
-
client: this,
|
|
191
|
-
data: event,
|
|
192
|
-
});
|
|
624
|
+
this._injections.clientMetaItems.push(metaData);
|
|
193
625
|
}
|
|
194
626
|
|
|
195
|
-
public
|
|
627
|
+
public injectEvent(event: ClientEvent) {
|
|
628
|
+
if (this.closed) return;
|
|
629
|
+
|
|
630
|
+
if (!this._injections.clientEvents) this._injections.clientEvents = [];
|
|
631
|
+
|
|
632
|
+
this._injections.clientEvents.push(event);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
public injectIssue(issue: ClientIssue) {
|
|
636
|
+
if (this.closed) return;
|
|
637
|
+
|
|
638
|
+
if (!this._injections.clientIssues) this._injections.clientIssues = [];
|
|
639
|
+
|
|
640
|
+
this._injections.clientIssues.push(issue);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
public injectExtensionStat(stat: ExtensionStat) {
|
|
644
|
+
if (this.closed) return;
|
|
645
|
+
|
|
646
|
+
if (!this._injections.extensionStats) this._injections.extensionStats = [];
|
|
647
|
+
|
|
648
|
+
this._injections.extensionStats.push(stat);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
public injectAttachment(key: string, value: unknown) {
|
|
652
|
+
if (this.closed) return;
|
|
653
|
+
|
|
654
|
+
if (!this._injections.attachments) this._injections.attachments = {};
|
|
655
|
+
|
|
656
|
+
this._injections.attachments[key] = value;
|
|
657
|
+
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
public addMetadata(metadata: ClientMetaData) {
|
|
661
|
+
if (this.closed) return;
|
|
662
|
+
|
|
196
663
|
switch (metadata.type) {
|
|
197
|
-
case
|
|
664
|
+
case ClientMetaTypes.BROWSER: {
|
|
198
665
|
this.browser = parseJsonAs(metadata.payload);
|
|
199
666
|
break;
|
|
200
667
|
}
|
|
201
|
-
case
|
|
668
|
+
case ClientMetaTypes.ENGINE: {
|
|
202
669
|
this.engine = parseJsonAs(metadata.payload);
|
|
203
670
|
break;
|
|
204
671
|
}
|
|
205
|
-
case
|
|
672
|
+
case ClientMetaTypes.PLATFORM: {
|
|
206
673
|
this.platform = parseJsonAs(metadata.payload);
|
|
207
674
|
break;
|
|
208
675
|
}
|
|
209
|
-
case
|
|
676
|
+
case ClientMetaTypes.OPERATION_SYSTEM: {
|
|
210
677
|
this.operationSystem = parseJsonAs(metadata.payload);
|
|
211
678
|
break;
|
|
212
679
|
}
|
|
213
680
|
}
|
|
214
681
|
|
|
215
|
-
this.call.observer.
|
|
216
|
-
call: this.call,
|
|
217
|
-
client: this,
|
|
218
|
-
data: metadata,
|
|
219
|
-
});
|
|
682
|
+
this.call.observer.emit('client-metadata', this, metadata);
|
|
220
683
|
}
|
|
221
684
|
|
|
222
|
-
public
|
|
223
|
-
this.
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
});
|
|
685
|
+
public addIssue(issue: ClientIssue) {
|
|
686
|
+
if (this.closed) return;
|
|
687
|
+
|
|
688
|
+
this.emit('issue', issue);
|
|
689
|
+
this.call.observer.emit('client-issue', this, issue);
|
|
228
690
|
}
|
|
229
691
|
|
|
230
|
-
public
|
|
231
|
-
this.call.observer.
|
|
232
|
-
|
|
233
|
-
client: this,
|
|
234
|
-
data: stats,
|
|
235
|
-
});
|
|
692
|
+
public addExtensionStats(stats: ExtensionStat) {
|
|
693
|
+
this.call.observer.emit('client-extension-stats', this, stats);
|
|
694
|
+
this.emit('extensionStats', stats);
|
|
236
695
|
}
|
|
237
696
|
|
|
238
|
-
private _updatePeerConnection(sample: PeerConnectionSample) {
|
|
697
|
+
private _updatePeerConnection(sample: PeerConnectionSample): ObservedPeerConnection | undefined {
|
|
239
698
|
let observedPeerConnection = this.observedPeerConnections.get(sample.peerConnectionId);
|
|
240
699
|
|
|
241
700
|
if (!observedPeerConnection) {
|
|
242
701
|
if (!sample.peerConnectionId) {
|
|
243
|
-
return logger.warn(
|
|
702
|
+
return (logger.warn(
|
|
244
703
|
`ObservedClient received an invalid PeerConnectionSample (missing peerConnectionId field). ClientId: ${this.clientId}, CallId: ${this.call.callId}`,
|
|
245
704
|
sample
|
|
246
|
-
);
|
|
705
|
+
), void 0);
|
|
247
706
|
}
|
|
248
707
|
|
|
249
708
|
observedPeerConnection = new ObservedPeerConnection(sample.peerConnectionId, this);
|
|
@@ -252,8 +711,101 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
252
711
|
this.observedPeerConnections.delete(sample.peerConnectionId);
|
|
253
712
|
});
|
|
254
713
|
this.observedPeerConnections.set(sample.peerConnectionId, observedPeerConnection);
|
|
714
|
+
|
|
715
|
+
this.emit('newpeerconnection', observedPeerConnection);
|
|
255
716
|
}
|
|
256
717
|
|
|
257
718
|
observedPeerConnection.accept(sample);
|
|
719
|
+
|
|
720
|
+
return observedPeerConnection;
|
|
258
721
|
}
|
|
722
|
+
|
|
723
|
+
private _mergeInjections(sample: ClientSample): ClientSample {
|
|
724
|
+
if (this.closed) return sample;
|
|
725
|
+
|
|
726
|
+
if (this._injections.clientEvents) {
|
|
727
|
+
if (!sample.clientEvents) sample.clientEvents = [];
|
|
728
|
+
sample.clientEvents.push(...this._injections.clientEvents);
|
|
729
|
+
|
|
730
|
+
this._injections.clientEvents = undefined;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
if (this._injections.clientIssues) {
|
|
734
|
+
if (!sample.clientIssues) sample.clientIssues = [];
|
|
735
|
+
sample.clientIssues.push(...this._injections.clientIssues);
|
|
736
|
+
|
|
737
|
+
this._injections.clientIssues = undefined;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
if (this._injections.extensionStats) {
|
|
741
|
+
if (!sample.extensionStats) sample.extensionStats = [];
|
|
742
|
+
sample.extensionStats.push(...this._injections.extensionStats);
|
|
743
|
+
|
|
744
|
+
this._injections.extensionStats = undefined;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
if (this._injections.attachments) {
|
|
748
|
+
if (!sample.attachments) sample.attachments = {};
|
|
749
|
+
Object.assign(sample.attachments, this._injections.attachments);
|
|
750
|
+
|
|
751
|
+
this._injections.attachments = undefined;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
if (this._injections.clientMetaItems) {
|
|
755
|
+
if (!sample.clientMetaItems) sample.clientMetaItems = [];
|
|
756
|
+
sample.clientMetaItems.push(...this._injections.clientMetaItems);
|
|
757
|
+
|
|
758
|
+
this._injections.clientMetaItems = undefined;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
return sample;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// public resetSummaryMetrics() {
|
|
765
|
+
// this.totalDataChannelBytesReceived = 0;
|
|
766
|
+
// this.totalDataChannelBytesSent = 0;
|
|
767
|
+
// this.totalDataChannelMessagesReceived = 0;
|
|
768
|
+
// this.totalDataChannelMessagesSent = 0;
|
|
769
|
+
// this.totalInboundPacketsLost = 0;
|
|
770
|
+
// this.totalInboundPacketsReceived = 0;
|
|
771
|
+
// this.totalOutboundPacketsSent = 0;
|
|
772
|
+
// this.totalReceivedAudioBytes = 0;
|
|
773
|
+
// this.totalReceivedVideoBytes = 0;
|
|
774
|
+
// this.totalSentAudioBytes = 0;
|
|
775
|
+
// this.totalSentVideoBytes = 0;
|
|
776
|
+
// this.totalSentBytes = 0;
|
|
777
|
+
// this.totalReceivedBytes = 0;
|
|
778
|
+
|
|
779
|
+
// this.totalNumberOfIssues = 0;
|
|
780
|
+
|
|
781
|
+
// this.totalScoreSum = 0;
|
|
782
|
+
// this.numberOfScoreMeasurements = 0;
|
|
783
|
+
// }
|
|
784
|
+
|
|
785
|
+
// public createSummary(): ObservedClientSummary {
|
|
786
|
+
// return {
|
|
787
|
+
// totalRttLt50Measurements: this.totalRttLt50Measurements,
|
|
788
|
+
// totalRttLt150Measurements: this.totalRttLt150Measurements,
|
|
789
|
+
// totalRttLt300Measurements: this.totalRttLt300Measurements,
|
|
790
|
+
// totalRttGtOrEq300Measurements: this.totalRttGtOrEq300Measurements,
|
|
791
|
+
// totalDataChannelBytesReceived: this.totalDataChannelBytesReceived,
|
|
792
|
+
// totalDataChannelBytesSent: this.totalDataChannelBytesSent,
|
|
793
|
+
// totalDataChannelMessagesReceived: this.totalDataChannelMessagesReceived,
|
|
794
|
+
// totalDataChannelMessagesSent: this.totalDataChannelMessagesSent,
|
|
795
|
+
// totalInboundPacketsLost: this.totalInboundPacketsLost,
|
|
796
|
+
// totalInboundPacketsReceived: this.totalInboundPacketsReceived,
|
|
797
|
+
// totalOutboundPacketsSent: this.totalOutboundPacketsSent,
|
|
798
|
+
// totalReceivedAudioBytes: this.totalReceivedAudioBytes,
|
|
799
|
+
// totalReceivedVideoBytes: this.totalReceivedVideoBytes,
|
|
800
|
+
// totalSentAudioBytes: this.totalSentAudioBytes,
|
|
801
|
+
// totalSentVideoBytes: this.totalSentVideoBytes,
|
|
802
|
+
// totalSentBytes: this.totalSentBytes,
|
|
803
|
+
// totalReceivedBytes: this.totalReceivedBytes,
|
|
804
|
+
|
|
805
|
+
// numberOfIssues: this.totalNumberOfIssues,
|
|
806
|
+
|
|
807
|
+
// totalScoreSum: this.totalScoreSum,
|
|
808
|
+
// numberOfScoreMeasurements: this.numberOfScoreMeasurements,
|
|
809
|
+
// };
|
|
810
|
+
// }
|
|
259
811
|
}
|