@observertc/observer-js 0.42.9 → 1.0.1-23e88d8.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 +25 -41
- package/lib/ObservedCall.d.ts.map +1 -1
- package/lib/ObservedCall.js +61 -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 +33 -143
- package/lib/ObservedClient.d.ts.map +1 -1
- package/lib/ObservedClient.js +156 -757
- 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 +20 -70
- package/lib/ObservedDataChannel.d.ts.map +1 -1
- package/lib/ObservedDataChannel.js +39 -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 +40 -0
- package/lib/ObservedIceCandidatePair.d.ts.map +1 -0
- package/lib/ObservedIceCandidatePair.js +83 -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 +118 -78
- package/lib/ObservedPeerConnection.d.ts.map +1 -1
- package/lib/ObservedPeerConnection.js +556 -359
- 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/Observer.d.ts +30 -53
- package/lib/Observer.d.ts.map +1 -1
- package/lib/Observer.js +52 -225
- 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 +23 -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 +74 -167
- package/src/ObservedCertificate.ts +43 -0
- package/src/ObservedClient.ts +173 -1085
- package/src/ObservedCodec.ts +49 -0
- package/src/ObservedDataChannel.ts +36 -178
- package/src/ObservedIceCandidate.ts +64 -0
- package/src/ObservedIceCandidatePair.ts +92 -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 +743 -401
- package/src/ObservedPeerConnectionTransport.ts +38 -0
- package/src/ObservedRemoteInboundRtp.ts +64 -0
- package/src/ObservedRemoteOutboundRtp.ts +65 -0
- package/src/Observer.ts +65 -285
- 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 +23 -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
package/src/ObservedClient.ts
CHANGED
|
@@ -1,1171 +1,259 @@
|
|
|
1
|
-
import { Browser, ClientSample, Engine, IceLocalCandidate, IceRemoteCandidate, MediaCodecStats, MediaDevice, OperationSystem, Platform } from '@observertc/sample-schemas-js';
|
|
2
|
-
import { ObservedCall } from './ObservedCall';
|
|
3
1
|
import { EventEmitter } from 'events';
|
|
4
2
|
import { ObservedPeerConnection } from './ObservedPeerConnection';
|
|
5
3
|
import { createLogger } from './common/logger';
|
|
6
|
-
import { CallMetaType, createCallMetaReport } from './common/CallMetaReports';
|
|
7
4
|
// eslint-disable-next-line camelcase
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
5
|
+
import { ClientEvent, ClientMetaData, ClientSample, PeerConnectionSample, ClientIssue, ExtensionStat } from './schema/ClientSample';
|
|
6
|
+
import * as MetaData from './schema/ClientMetaTypes';
|
|
7
|
+
import { ClientEventTypes } from './schema/ClientEventTypes';
|
|
8
|
+
import { ObservedCall } from './ObservedCall';
|
|
9
|
+
import { ClientMetaTypes } from './schema/ClientMetaTypes';
|
|
10
|
+
import { parseJsonAs } from './common/utils';
|
|
11
|
+
import { CalculatedScore } from './scores/CalculatedScore';
|
|
12
|
+
import { Detectors } from './detectors/Detectors';
|
|
14
13
|
|
|
15
14
|
const logger = createLogger('ObservedClient');
|
|
16
15
|
|
|
17
|
-
export type
|
|
16
|
+
export type ObservedClientSettings<AppData extends Record<string, unknown> = Record<string, unknown>> = {
|
|
18
17
|
clientId: string;
|
|
19
|
-
|
|
20
|
-
userId?: string,
|
|
21
|
-
marker?: string,
|
|
22
|
-
operationSystem?: OperationSystem,
|
|
23
|
-
engine?: Engine,
|
|
24
|
-
platform?: Platform,
|
|
25
|
-
browser?: Browser,
|
|
26
|
-
coordinates?: {
|
|
27
|
-
latitude: number;
|
|
28
|
-
longitude: number;
|
|
29
|
-
},
|
|
18
|
+
appData?: AppData;
|
|
30
19
|
};
|
|
31
20
|
|
|
32
21
|
export type ObservedClientEvents = {
|
|
33
|
-
update: [
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}],
|
|
49
|
-
connectionstatechange: [{
|
|
50
|
-
peerConnection: ObservedPeerConnection,
|
|
51
|
-
state: string,
|
|
52
|
-
}],
|
|
53
|
-
selectedcandidatepair: [{
|
|
54
|
-
peerConnection: ObservedPeerConnection,
|
|
55
|
-
localCandidate: IceLocalCandidate,
|
|
56
|
-
remoteCandidate: IceRemoteCandidate,
|
|
57
|
-
}],
|
|
58
|
-
issue: [ClientIssue],
|
|
59
|
-
usingturn: [boolean],
|
|
60
|
-
usermediaerror: [string],
|
|
61
|
-
rejoined: [{
|
|
62
|
-
lastJoined: number,
|
|
63
|
-
}],
|
|
64
|
-
score: [CalculatedScore],
|
|
22
|
+
update: [
|
|
23
|
+
{
|
|
24
|
+
sample: ClientSample;
|
|
25
|
+
elapsedTimeInMs: number;
|
|
26
|
+
}
|
|
27
|
+
];
|
|
28
|
+
close: [];
|
|
29
|
+
joined: [];
|
|
30
|
+
rejoined: [timestamp: number];
|
|
31
|
+
left: [];
|
|
32
|
+
usingturn: [boolean];
|
|
33
|
+
usermediaerror: [string];
|
|
34
|
+
|
|
35
|
+
// do we need this?
|
|
36
|
+
newpeerconnection: [ObservedPeerConnection];
|
|
65
37
|
};
|
|
66
38
|
|
|
67
|
-
export declare interface ObservedClient
|
|
39
|
+
export declare interface ObservedClient {
|
|
68
40
|
on<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;
|
|
69
41
|
off<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;
|
|
70
42
|
once<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;
|
|
71
43
|
emit<U extends keyof ObservedClientEvents>(event: U, ...args: ObservedClientEvents[U]): boolean;
|
|
72
|
-
readonly appData: AppData;
|
|
73
44
|
}
|
|
74
45
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
peerConnectionId: string;
|
|
78
|
-
timestamp: number;
|
|
79
|
-
}
|
|
46
|
+
export class ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {
|
|
47
|
+
public readonly detectors: Detectors;
|
|
80
48
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
49
|
+
public readonly clientId: string;
|
|
50
|
+
public readonly observedPeerConnections = new Map<string, ObservedPeerConnection>();
|
|
51
|
+
public readonly calculatedScore: CalculatedScore = {
|
|
52
|
+
weight: 1,
|
|
53
|
+
value: undefined,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
public appData?: AppData;
|
|
57
|
+
public attachments?: Record<string, unknown>;
|
|
87
58
|
|
|
88
|
-
export class ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {
|
|
89
|
-
|
|
90
|
-
public readonly created = Date.now();
|
|
91
59
|
public updated = Date.now();
|
|
92
|
-
public
|
|
93
|
-
|
|
94
|
-
private readonly _peerConnections = new Map<string, ObservedPeerConnection>();
|
|
95
|
-
|
|
96
|
-
private _closed = false;
|
|
97
|
-
|
|
98
|
-
private _acceptedSamples = 0;
|
|
99
|
-
private _timeZoneOffsetInHours?: number;
|
|
60
|
+
public acceptedSamples = 0;
|
|
61
|
+
public closed = false;
|
|
100
62
|
|
|
63
|
+
public joinedAt?: number;
|
|
64
|
+
public leftAt?: number;
|
|
101
65
|
// the timestamp of the CLIENT_JOINED event
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
public
|
|
66
|
+
public operationSystem?: MetaData.OperationSystem;
|
|
67
|
+
public engine?: MetaData.Engine;
|
|
68
|
+
public platform?: MetaData.Platform;
|
|
69
|
+
public browser?: MetaData.Browser;
|
|
70
|
+
public mediaConstraints: string[] = [];
|
|
105
71
|
|
|
106
|
-
public score?: CalculatedScore;
|
|
107
72
|
public usingTURN = false;
|
|
108
73
|
public availableOutgoingBitrate = 0;
|
|
109
74
|
public availableIncomingBitrate = 0;
|
|
110
|
-
public totalInboundPacketsLost = 0;
|
|
111
|
-
public totalInboundPacketsReceived = 0;
|
|
112
|
-
public totalOutboundPacketsSent = 0;
|
|
113
|
-
public totalDataChannelBytesSent = 0;
|
|
114
|
-
public totalDataChannelBytesReceived = 0;
|
|
115
|
-
public totalSentBytes = 0;
|
|
116
|
-
public totalReceivedBytes = 0;
|
|
117
|
-
public totalReceivedAudioBytes = 0;
|
|
118
|
-
public totalReceivedVideoBytes = 0;
|
|
119
|
-
public totalSentAudioBytes = 0;
|
|
120
|
-
public totalSentVideoBytes = 0;
|
|
121
|
-
|
|
122
|
-
public deltaReceivedAudioBytes = 0;
|
|
123
|
-
public deltaReceivedVideoBytes = 0;
|
|
124
|
-
public deltaSentAudioBytes = 0;
|
|
125
|
-
public deltaSentVideoBytes = 0;
|
|
126
|
-
public deltaDataChannelBytesSent = 0;
|
|
127
|
-
public deltaDataChannelBytesReceived = 0;
|
|
128
|
-
public deltaInboundPacketsLost = 0;
|
|
129
|
-
public deltaInboundPacketsReceived = 0;
|
|
130
|
-
public deltaOutboundPacketsSent = 0;
|
|
75
|
+
// public totalInboundPacketsLost = 0;
|
|
76
|
+
// public totalInboundPacketsReceived = 0;
|
|
77
|
+
// public totalOutboundPacketsSent = 0;
|
|
78
|
+
// public totalDataChannelBytesSent = 0;
|
|
79
|
+
// public totalDataChannelBytesReceived = 0;
|
|
80
|
+
// public totalSentBytes = 0;
|
|
81
|
+
// public totalReceivedBytes = 0;
|
|
82
|
+
// public totalReceivedAudioBytes = 0;
|
|
83
|
+
// public totalReceivedVideoBytes = 0;
|
|
84
|
+
// public totalSentAudioBytes = 0;
|
|
85
|
+
// public totalSentVideoBytes = 0;
|
|
86
|
+
|
|
87
|
+
// public deltaReceivedAudioBytes = 0;
|
|
88
|
+
// public deltaReceivedVideoBytes = 0;
|
|
89
|
+
// public deltaSentAudioBytes = 0;
|
|
90
|
+
// public deltaSentVideoBytes = 0;
|
|
91
|
+
// public deltaDataChannelBytesSent = 0;
|
|
92
|
+
// public deltaDataChannelBytesReceived = 0;
|
|
93
|
+
// public deltaInboundPacketsLost = 0;
|
|
94
|
+
// public deltaInboundPacketsReceived = 0;
|
|
95
|
+
// public deltaOutboundPacketsSent = 0;
|
|
131
96
|
|
|
132
97
|
public avgRttInMs?: number;
|
|
133
98
|
public outboundAudioBitrate?: number;
|
|
134
99
|
public outboundVideoBitrate?: number;
|
|
135
100
|
public inboundAudioBitrate?: number;
|
|
136
101
|
public inboundVideoBitrate?: number;
|
|
137
|
-
public mediaConstraints: string[] = [];
|
|
138
102
|
|
|
139
|
-
public readonly mediaDevices:
|
|
140
|
-
public readonly mediaCodecs: MediaCodecStats[] = [];
|
|
141
|
-
public readonly userMediaErrors: string[] = [];
|
|
103
|
+
public readonly mediaDevices: MetaData.MediaDeviceInfo[] = [];
|
|
142
104
|
public issues: ClientIssue[] = [];
|
|
143
105
|
|
|
144
|
-
public
|
|
145
|
-
public ωpendingMediaTrackTimestamps: PendingMediaTrackTimestamp[] = [];
|
|
146
|
-
|
|
147
|
-
public constructor(
|
|
148
|
-
private readonly _model: ObservedClientModel,
|
|
149
|
-
public readonly call: ObservedCall,
|
|
150
|
-
public readonly appData: AppData
|
|
151
|
-
) {
|
|
106
|
+
public constructor(settings: ObservedClientSettings<AppData>, public readonly call: ObservedCall) {
|
|
152
107
|
super();
|
|
153
108
|
this.setMaxListeners(Infinity);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
public getSfu<T extends Record<string, unknown> = Record<string, unknown>>(): ObservedSfu<T> | undefined {
|
|
157
|
-
const sfu = this.call.observer.observedSfus.get(this.sfuId ?? '');
|
|
158
|
-
|
|
159
|
-
if (!sfu) return;
|
|
160
|
-
|
|
161
|
-
return sfu as ObservedSfu<T>;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
public get joined() {
|
|
165
|
-
return this._joined;
|
|
166
|
-
}
|
|
167
109
|
|
|
168
|
-
|
|
169
|
-
this.
|
|
170
|
-
|
|
171
|
-
if (this._joined) {
|
|
172
|
-
this.emit('joined');
|
|
173
|
-
}
|
|
110
|
+
this.clientId = settings.clientId;
|
|
111
|
+
this.appData = settings.appData;
|
|
112
|
+
this.detectors = new Detectors();
|
|
174
113
|
}
|
|
175
114
|
|
|
176
|
-
public get
|
|
177
|
-
return this.
|
|
115
|
+
public get score() {
|
|
116
|
+
return this.calculatedScore.value;
|
|
178
117
|
}
|
|
179
118
|
|
|
180
|
-
public set left(value: number | undefined) {
|
|
181
|
-
this._left = value;
|
|
182
|
-
|
|
183
|
-
if (this._left) {
|
|
184
|
-
this.emit('left');
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
public get sfu(): ObservedSfu | undefined {
|
|
189
|
-
if (!this.sfuId) return;
|
|
190
|
-
|
|
191
|
-
return this.call.observer.observedSfus.get(this.sfuId);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
public get coordinates() {
|
|
195
|
-
return this._model.coordinates;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
public set coordinates(value: { latitude: number; longitude: number } | undefined) {
|
|
199
|
-
this._model.coordinates = value;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
public get clientId(): string {
|
|
203
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
204
|
-
return this._model.clientId!;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
public get roomId() {
|
|
208
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
209
|
-
return this.call.roomId!;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
public get serviceId() {
|
|
213
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
214
|
-
return this.call.serviceId!;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
public get callId() {
|
|
218
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
219
|
-
return this.call.callId!;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
public get mediaUnitId() {
|
|
223
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
224
|
-
return this._model.mediaUnitId!;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
public get reports() {
|
|
228
|
-
return this.call.reports;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
public get userId() {
|
|
232
|
-
return this._model.userId;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
public set userId(userId: string | undefined) {
|
|
236
|
-
this._model.userId = userId;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
public get timeZoneOffsetInHours() {
|
|
240
|
-
return this._timeZoneOffsetInHours;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
public get marker() {
|
|
244
|
-
return this._model.marker;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
public get browser() {
|
|
248
|
-
return this._model.browser;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
public get engine() {
|
|
252
|
-
return this._model.engine;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
public get operationSystem() {
|
|
256
|
-
return this._model.operationSystem;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
public get platform() {
|
|
260
|
-
return this._model.platform;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
public get acceptedSamples() {
|
|
264
|
-
return this._acceptedSamples;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
public get closed() {
|
|
268
|
-
return this._closed;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
public get peerConnections(): ReadonlyMap<string, ObservedPeerConnection> {
|
|
272
|
-
return this._peerConnections;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
119
|
public close() {
|
|
276
|
-
if (this.
|
|
277
|
-
this.
|
|
120
|
+
if (this.closed) return;
|
|
121
|
+
this.closed = true;
|
|
278
122
|
|
|
279
|
-
Array.from(this.
|
|
123
|
+
Array.from(this.observedPeerConnections.values()).forEach((peerConnection) => peerConnection.close());
|
|
280
124
|
|
|
281
125
|
this.emit('close');
|
|
282
126
|
}
|
|
283
127
|
|
|
284
|
-
public addEventReport(params: PartialBy<Omit<CallEventReport, 'serviceId' | 'roomId' | 'callId' | 'clientId' | 'userId' | 'marker' | 'attachments'>, 'timestamp'> & { attachments?: Record<string, unknown> }) {
|
|
285
|
-
const {
|
|
286
|
-
attachments,
|
|
287
|
-
...fields
|
|
288
|
-
} = params;
|
|
289
|
-
|
|
290
|
-
this.reports.addCallEventReport({
|
|
291
|
-
...fields,
|
|
292
|
-
serviceId: this.serviceId,
|
|
293
|
-
mediaUnitId: this.mediaUnitId,
|
|
294
|
-
roomId: this.roomId,
|
|
295
|
-
callId: this.callId,
|
|
296
|
-
clientId: this.clientId,
|
|
297
|
-
userId: this.userId,
|
|
298
|
-
timestamp: params.timestamp ?? Date.now(),
|
|
299
|
-
marker: this.marker,
|
|
300
|
-
attachments: attachments ? JSON.stringify(attachments) : undefined,
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
public addExtensionStatsReport(extensionType: string, payload?: Record<string, unknown>) {
|
|
305
|
-
this.reports.addClientExtensionReport({
|
|
306
|
-
serviceId: this.serviceId,
|
|
307
|
-
mediaUnitId: this.mediaUnitId,
|
|
308
|
-
roomId: this.roomId,
|
|
309
|
-
callId: this.callId,
|
|
310
|
-
clientId: this.clientId,
|
|
311
|
-
userId: this.userId,
|
|
312
|
-
timestamp: Date.now(),
|
|
313
|
-
extensionType,
|
|
314
|
-
payload: JSON.stringify(payload),
|
|
315
|
-
marker: this.marker,
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
public addIssue(issue: ClientIssue) {
|
|
320
|
-
try {
|
|
321
|
-
|
|
322
|
-
this.reports.addCallEventReport({
|
|
323
|
-
serviceId: this.serviceId,
|
|
324
|
-
mediaUnitId: this.mediaUnitId,
|
|
325
|
-
roomId: this.roomId,
|
|
326
|
-
callId: this.callId,
|
|
327
|
-
clientId: this.clientId,
|
|
328
|
-
userId: this.userId,
|
|
329
|
-
|
|
330
|
-
name: CallEventType.CLIENT_ISSUE,
|
|
331
|
-
value: issue.severity,
|
|
332
|
-
peerConnectionId: issue.peerConnectionId,
|
|
333
|
-
mediaTrackId: issue.trackId,
|
|
334
|
-
message: issue.description,
|
|
335
|
-
timestamp: issue.timestamp ?? Date.now(),
|
|
336
|
-
attachments: issue.attachments ? JSON.stringify(issue.attachments): undefined,
|
|
337
|
-
});
|
|
338
|
-
} catch (err) {
|
|
339
|
-
logger.warn(`Error adding client issue: ${(err as Error)?.message}`);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
this._addAndEmitIssue(issue);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
128
|
public accept(sample: ClientSample): void {
|
|
346
|
-
if (this.
|
|
347
|
-
if (sample.clientId && sample.clientId !== 'NULL' && sample.clientId !== this.clientId) {
|
|
348
|
-
throw new Error(`Sample client id (${sample.clientId}) does not match the client id of the observed client (${this.clientId})`);
|
|
349
|
-
}
|
|
350
|
-
const now = Date.now();
|
|
351
|
-
|
|
352
|
-
++this._acceptedSamples;
|
|
353
|
-
if (0 < this.issues.length) {
|
|
354
|
-
// we reset the issues every time we accept a new sample
|
|
355
|
-
this.issues = [];
|
|
356
|
-
}
|
|
357
|
-
for (const peerConnection of this._peerConnections.values()) {
|
|
358
|
-
if (peerConnection.closed) continue;
|
|
359
|
-
peerConnection.resetMetrics();
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
if (this._model.userId) {
|
|
363
|
-
if (sample.userId && sample.userId !== 'NULL' && sample.userId !== this._model.userId) {
|
|
364
|
-
this._model.userId = sample.userId;
|
|
365
|
-
}
|
|
366
|
-
} else if (sample.userId && sample.userId !== 'NULL') {
|
|
367
|
-
this._model.userId = sample.userId;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
if (this._model.marker !== sample.marker) {
|
|
371
|
-
this._model.marker = sample.marker;
|
|
372
|
-
this._peerConnections.forEach((peerConnection) => (peerConnection.marker = sample.marker));
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (this._timeZoneOffsetInHours !== sample.timeZoneOffsetInHours) {
|
|
376
|
-
this._timeZoneOffsetInHours = sample.timeZoneOffsetInHours;
|
|
377
|
-
}
|
|
129
|
+
if (this.closed) throw new Error(`Client ${this.clientId} is closed`);
|
|
378
130
|
|
|
379
|
-
|
|
380
|
-
this._model.operationSystem?.name !== sample.os.name ||
|
|
381
|
-
this._model.operationSystem?.version !== sample.os.version ||
|
|
382
|
-
this._model.operationSystem?.versionName !== sample.os.versionName
|
|
383
|
-
)) {
|
|
384
|
-
this._model.operationSystem = sample.os;
|
|
385
|
-
|
|
386
|
-
const callMetaReport = createCallMetaReport(
|
|
387
|
-
this.serviceId,
|
|
388
|
-
this.mediaUnitId,
|
|
389
|
-
this.roomId,
|
|
390
|
-
this.callId,
|
|
391
|
-
this.clientId,
|
|
392
|
-
{
|
|
393
|
-
type: CallMetaType.OPERATION_SYSTEM,
|
|
394
|
-
payload: sample.os,
|
|
395
|
-
},
|
|
396
|
-
this.userId,
|
|
397
|
-
undefined,
|
|
398
|
-
sample.timestamp
|
|
399
|
-
);
|
|
400
|
-
|
|
401
|
-
this.reports.addCallMetaReport(callMetaReport);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
if (sample.engine && (
|
|
405
|
-
this._model.engine?.name !== sample.engine.name ||
|
|
406
|
-
this._model.engine?.version !== sample.engine.version
|
|
407
|
-
)) {
|
|
408
|
-
this._model.engine = sample.engine;
|
|
409
|
-
|
|
410
|
-
const callMetaReport = createCallMetaReport(
|
|
411
|
-
this.serviceId,
|
|
412
|
-
this.mediaUnitId,
|
|
413
|
-
this.roomId,
|
|
414
|
-
this.callId,
|
|
415
|
-
this.clientId,
|
|
416
|
-
{
|
|
417
|
-
type: CallMetaType.ENGINE,
|
|
418
|
-
payload: sample.engine,
|
|
419
|
-
},
|
|
420
|
-
this.userId,
|
|
421
|
-
undefined,
|
|
422
|
-
sample.timestamp
|
|
423
|
-
);
|
|
424
|
-
|
|
425
|
-
this.reports.addCallMetaReport(callMetaReport);
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
if (sample.platform && (
|
|
429
|
-
this._model.platform?.model !== sample.platform.model ||
|
|
430
|
-
this._model.platform?.type !== sample.platform.type ||
|
|
431
|
-
this._model.platform?.vendor !== sample.platform.vendor
|
|
432
|
-
)) {
|
|
433
|
-
this._model.platform = sample.platform;
|
|
434
|
-
|
|
435
|
-
const callMetaReport = createCallMetaReport(
|
|
436
|
-
this.serviceId,
|
|
437
|
-
this.mediaUnitId,
|
|
438
|
-
this.roomId,
|
|
439
|
-
this.callId,
|
|
440
|
-
this.clientId,
|
|
441
|
-
{
|
|
442
|
-
type: CallMetaType.PLATFORM,
|
|
443
|
-
payload: sample.platform,
|
|
444
|
-
},
|
|
445
|
-
this.userId,
|
|
446
|
-
undefined,
|
|
447
|
-
sample.timestamp
|
|
448
|
-
);
|
|
449
|
-
|
|
450
|
-
this.reports.addCallMetaReport(callMetaReport);
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
if (sample.browser && (
|
|
454
|
-
this._model.browser?.name !== sample.browser.name ||
|
|
455
|
-
this._model.browser?.version !== sample.browser.version
|
|
456
|
-
)) {
|
|
457
|
-
this._model.browser = sample.browser;
|
|
458
|
-
|
|
459
|
-
const callMetaReport = createCallMetaReport(
|
|
460
|
-
this.serviceId,
|
|
461
|
-
this.mediaUnitId,
|
|
462
|
-
this.roomId,
|
|
463
|
-
this.callId,
|
|
464
|
-
this.clientId,
|
|
465
|
-
{
|
|
466
|
-
type: CallMetaType.BROWSER,
|
|
467
|
-
payload: sample.browser,
|
|
468
|
-
},
|
|
469
|
-
this.userId,
|
|
470
|
-
undefined,
|
|
471
|
-
sample.timestamp
|
|
472
|
-
);
|
|
473
|
-
|
|
474
|
-
this.reports.addCallMetaReport(callMetaReport);
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
for (const mediaConstraint of sample.mediaConstraints ?? []) {
|
|
478
|
-
const callMetaReport = createCallMetaReport(
|
|
479
|
-
this.serviceId,
|
|
480
|
-
this.mediaUnitId,
|
|
481
|
-
this.roomId,
|
|
482
|
-
this.callId,
|
|
483
|
-
this.clientId,
|
|
484
|
-
{
|
|
485
|
-
type: CallMetaType.MEDIA_CONSTRAINT,
|
|
486
|
-
payload: mediaConstraint,
|
|
487
|
-
},
|
|
488
|
-
this.userId,
|
|
489
|
-
undefined,
|
|
490
|
-
sample.timestamp
|
|
491
|
-
);
|
|
492
|
-
|
|
493
|
-
this.reports.addCallMetaReport(callMetaReport);
|
|
494
|
-
this.mediaConstraints.push(mediaConstraint);
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
for (const localSDP of sample.localSDPs ?? []) {
|
|
498
|
-
const callMetaReport = createCallMetaReport(
|
|
499
|
-
this.serviceId,
|
|
500
|
-
this.mediaUnitId,
|
|
501
|
-
this.roomId,
|
|
502
|
-
this.callId,
|
|
503
|
-
this.clientId,
|
|
504
|
-
{
|
|
505
|
-
type: CallMetaType.LOCAL_SDP,
|
|
506
|
-
payload: localSDP,
|
|
507
|
-
},
|
|
508
|
-
this.userId,
|
|
509
|
-
undefined,
|
|
510
|
-
sample.timestamp
|
|
511
|
-
);
|
|
512
|
-
|
|
513
|
-
this.reports.addCallMetaReport(callMetaReport);
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
for (const extensionStats of sample.extensionStats ?? []) {
|
|
517
|
-
this.reports.addClientExtensionReport({
|
|
518
|
-
serviceId: this.serviceId,
|
|
519
|
-
mediaUnitId: this.mediaUnitId,
|
|
520
|
-
roomId: this.roomId,
|
|
521
|
-
callId: this.callId,
|
|
522
|
-
clientId: this.clientId,
|
|
523
|
-
userId: this.userId,
|
|
524
|
-
timestamp: now,
|
|
525
|
-
payload: extensionStats.payload,
|
|
526
|
-
extensionType: extensionStats.type,
|
|
527
|
-
});
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
for (const { timestamp, ...callEvent } of sample.customCallEvents ?? []) {
|
|
531
|
-
switch (callEvent.name) {
|
|
532
|
-
case CallEventType.CLIENT_JOINED: {
|
|
533
|
-
const lastJoined = this.joined;
|
|
534
|
-
|
|
535
|
-
this.joined = timestamp;
|
|
536
|
-
|
|
537
|
-
// if it is joined before and it is joined again
|
|
538
|
-
if (lastJoined && this.joined && lastJoined !== this.joined) {
|
|
539
|
-
this.emit('rejoined', { lastJoined });
|
|
540
|
-
}
|
|
541
|
-
// in case we have a left event before the joined event
|
|
542
|
-
if (this.left && this.joined && this.left < this.joined) {
|
|
543
|
-
this.left = undefined;
|
|
544
|
-
}
|
|
545
|
-
break;
|
|
546
|
-
}
|
|
547
|
-
case CallEventType.CLIENT_LEFT: {
|
|
548
|
-
this.left = timestamp;
|
|
549
|
-
break;
|
|
550
|
-
}
|
|
551
|
-
case CallEventType.PEER_CONNECTION_OPENED: {
|
|
552
|
-
callEvent.peerConnectionId && this.ωpendingPeerConnectionTimestamps.push({
|
|
553
|
-
type: 'opened',
|
|
554
|
-
peerConnectionId: callEvent.peerConnectionId,
|
|
555
|
-
timestamp: timestamp ?? sample.timestamp,
|
|
556
|
-
});
|
|
557
|
-
break;
|
|
558
|
-
}
|
|
559
|
-
case CallEventType.PEER_CONNECTION_CLOSED: {
|
|
560
|
-
callEvent.peerConnectionId && this.ωpendingPeerConnectionTimestamps.push({
|
|
561
|
-
type: 'closed',
|
|
562
|
-
peerConnectionId: callEvent.peerConnectionId,
|
|
563
|
-
timestamp: timestamp ?? sample.timestamp,
|
|
564
|
-
});
|
|
565
|
-
break;
|
|
566
|
-
}
|
|
567
|
-
case CallEventType.MEDIA_TRACK_ADDED: {
|
|
568
|
-
callEvent.peerConnectionId && callEvent.mediaTrackId && this.ωpendingMediaTrackTimestamps.push({
|
|
569
|
-
type: 'added',
|
|
570
|
-
peerConnectionId: callEvent.peerConnectionId,
|
|
571
|
-
mediaTrackId: callEvent.mediaTrackId,
|
|
572
|
-
timestamp: timestamp ?? sample.timestamp,
|
|
573
|
-
});
|
|
574
|
-
break;
|
|
575
|
-
}
|
|
576
|
-
case CallEventType.MEDIA_TRACK_REMOVED: {
|
|
577
|
-
callEvent.peerConnectionId && callEvent.mediaTrackId && this.ωpendingMediaTrackTimestamps.push({
|
|
578
|
-
type: 'removed',
|
|
579
|
-
peerConnectionId: callEvent.peerConnectionId,
|
|
580
|
-
mediaTrackId: callEvent.mediaTrackId,
|
|
581
|
-
timestamp: timestamp ?? sample.timestamp,
|
|
582
|
-
});
|
|
583
|
-
break;
|
|
584
|
-
}
|
|
585
|
-
case CallEventType.CLIENT_ISSUE: {
|
|
586
|
-
const severity = callEvent.value ? callEvent.value as ClientIssue['severity'] : 'minor';
|
|
587
|
-
|
|
588
|
-
try {
|
|
589
|
-
const issue: ClientIssue = {
|
|
590
|
-
severity,
|
|
591
|
-
timestamp: timestamp ?? Date.now(),
|
|
592
|
-
description: callEvent.message,
|
|
593
|
-
peerConnectionId: callEvent.peerConnectionId,
|
|
594
|
-
trackId: callEvent.mediaTrackId,
|
|
595
|
-
attachments: callEvent.attachments ? JSON.parse(callEvent.attachments) : undefined,
|
|
596
|
-
};
|
|
597
|
-
|
|
598
|
-
this._addAndEmitIssue(issue);
|
|
599
|
-
} catch (err) {
|
|
600
|
-
logger.warn(`Error parsing client issue: ${(err as Error)?.message}`);
|
|
601
|
-
}
|
|
602
|
-
break;
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
this.reports.addCallEventReport({
|
|
607
|
-
serviceId: this.serviceId,
|
|
608
|
-
mediaUnitId: this.mediaUnitId,
|
|
609
|
-
roomId: this.roomId,
|
|
610
|
-
callId: this.callId,
|
|
611
|
-
clientId: this.clientId,
|
|
612
|
-
userId: this.userId,
|
|
613
|
-
timestamp: timestamp ?? now,
|
|
614
|
-
...callEvent,
|
|
615
|
-
});
|
|
616
|
-
|
|
617
|
-
this.call.emit('callevent', {
|
|
618
|
-
mediaUnitId: this.mediaUnitId,
|
|
619
|
-
clientId: this.clientId,
|
|
620
|
-
userId: this.userId,
|
|
621
|
-
timestamp: timestamp ?? now,
|
|
622
|
-
...callEvent,
|
|
623
|
-
});
|
|
624
|
-
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
for (const userMediaError of sample.userMediaErrors ?? []) {
|
|
628
|
-
const callMetaReport = createCallMetaReport(
|
|
629
|
-
this.serviceId,
|
|
630
|
-
this.mediaUnitId,
|
|
631
|
-
this.roomId,
|
|
632
|
-
this.callId,
|
|
633
|
-
this.clientId, {
|
|
634
|
-
type: CallMetaType.USER_MEDIA_ERROR,
|
|
635
|
-
payload: userMediaError,
|
|
636
|
-
},
|
|
637
|
-
this.userId,
|
|
638
|
-
);
|
|
639
|
-
|
|
640
|
-
this.reports.addCallMetaReport(callMetaReport);
|
|
641
|
-
this.userMediaErrors.push(userMediaError);
|
|
642
|
-
this.emit('usermediaerror', userMediaError);
|
|
643
|
-
}
|
|
131
|
+
const now = Date.now();
|
|
644
132
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
this.callId,
|
|
651
|
-
this.clientId, {
|
|
652
|
-
type: CallMetaType.CERTIFICATE,
|
|
653
|
-
payload: certificate,
|
|
654
|
-
},
|
|
655
|
-
this.userId
|
|
656
|
-
);
|
|
133
|
+
sample.clientEvents?.forEach(this._processClientEvent.bind(this));
|
|
134
|
+
sample.clientMetaItems?.forEach(this.processMetadata.bind(this));
|
|
135
|
+
sample.clientIssues?.forEach(this.processIssue.bind(this));
|
|
136
|
+
sample.peerConnections?.forEach(this._updatePeerConnection.bind(this));
|
|
137
|
+
sample.extensionStats?.forEach(this.processExtensionStats.bind(this));
|
|
657
138
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
for (const codec of sample.codecs ?? []) {
|
|
662
|
-
const callMetaReport = createCallMetaReport(
|
|
663
|
-
this.serviceId,
|
|
664
|
-
this.mediaUnitId,
|
|
665
|
-
this.roomId,
|
|
666
|
-
this.callId,
|
|
667
|
-
this.clientId, {
|
|
668
|
-
type: CallMetaType.CODEC,
|
|
669
|
-
payload: codec,
|
|
670
|
-
}, this.userId);
|
|
139
|
+
// emit new attachments?
|
|
140
|
+
this.attachments = sample.attachments;
|
|
671
141
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
this.mediaCodecs.push(codec);
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
for (const iceServer of sample.iceServers ?? []) {
|
|
679
|
-
const callMetaReport = createCallMetaReport(
|
|
680
|
-
this.serviceId,
|
|
681
|
-
this.mediaUnitId,
|
|
682
|
-
this.roomId,
|
|
683
|
-
this.callId,
|
|
684
|
-
this.clientId, {
|
|
685
|
-
type: CallMetaType.ICE_SERVER,
|
|
686
|
-
payload: iceServer,
|
|
687
|
-
}, this.userId);
|
|
142
|
+
this.calculatedScore.value = sample.score;
|
|
143
|
+
this.detectors.update();
|
|
688
144
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
this.roomId,
|
|
697
|
-
this.callId,
|
|
698
|
-
this.clientId, {
|
|
699
|
-
type: CallMetaType.MEDIA_DEVICE,
|
|
700
|
-
payload: mediaDevice,
|
|
701
|
-
}, this.userId);
|
|
702
|
-
|
|
703
|
-
this.reports.addCallMetaReport(callMetaReport);
|
|
704
|
-
if (mediaDevice.id && !this.mediaDevices.find((d) => d.id === mediaDevice.id)) {
|
|
705
|
-
this.mediaDevices.push(mediaDevice);
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
for (const mediaSource of sample.mediaSources ?? []) {
|
|
710
|
-
const callMetaReport = createCallMetaReport(
|
|
711
|
-
this.serviceId,
|
|
712
|
-
this.mediaUnitId,
|
|
713
|
-
this.roomId,
|
|
714
|
-
this.callId,
|
|
715
|
-
this.clientId, {
|
|
716
|
-
type: CallMetaType.MEDIA_SOURCE,
|
|
717
|
-
payload: mediaSource,
|
|
718
|
-
}, this.userId);
|
|
719
|
-
|
|
720
|
-
this.reports.addCallMetaReport(callMetaReport);
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
for (const transport of sample.pcTransports ?? []) {
|
|
724
|
-
try {
|
|
725
|
-
const peerConnection = this._peerConnections.get(transport.transportId) ?? this._createPeerConnection(transport.peerConnectionId);
|
|
145
|
+
// emit update
|
|
146
|
+
this.emit('update', {
|
|
147
|
+
sample,
|
|
148
|
+
elapsedTimeInMs: now - this.updated,
|
|
149
|
+
});
|
|
150
|
+
this.updated = now;
|
|
151
|
+
}
|
|
726
152
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
153
|
+
private _processClientEvent(event: ClientEvent) {
|
|
154
|
+
switch (event.type) {
|
|
155
|
+
case ClientEventTypes.CALL_STARTED: {
|
|
156
|
+
// update call timestamp if it's the first time
|
|
157
|
+
break;
|
|
731
158
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
for (const track of sample.inboundAudioTracks ?? []) {
|
|
736
|
-
if (!track.peerConnectionId || !track.trackId) {
|
|
737
|
-
logger.warn(`InboundAudioTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
|
|
738
|
-
|
|
739
|
-
continue;
|
|
159
|
+
case ClientEventTypes.CALL_ENDED: {
|
|
160
|
+
// update call timestamp if it's the first time
|
|
161
|
+
break;
|
|
740
162
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
});
|
|
752
|
-
|
|
753
|
-
inboundAudioTrack.update(track, sample.timestamp);
|
|
754
|
-
|
|
755
|
-
if (!inboundAudioTrack.remoteOutboundTrack) {
|
|
756
|
-
const remoteOutboundTrack = this.call.sfuStreamIdToOutboundAudioTrack.get(inboundAudioTrack.sfuStreamId ?? '');
|
|
757
|
-
|
|
758
|
-
if (remoteOutboundTrack) {
|
|
759
|
-
inboundAudioTrack.remoteOutboundTrack = remoteOutboundTrack;
|
|
760
|
-
|
|
761
|
-
inboundAudioTrack.once('close', () => {
|
|
762
|
-
remoteOutboundTrack?.remoteInboundTracks.delete(inboundAudioTrack.trackId ?? '');
|
|
763
|
-
});
|
|
764
|
-
remoteOutboundTrack.remoteInboundTracks.set(inboundAudioTrack.trackId ?? '', inboundAudioTrack);
|
|
163
|
+
case ClientEventTypes.CLIENT_JOINED: {
|
|
164
|
+
if (event.timestamp) {
|
|
165
|
+
if (!this.joinedAt) {
|
|
166
|
+
this.joinedAt = event.timestamp;
|
|
167
|
+
this.emit('joined');
|
|
168
|
+
} else if (this.joinedAt < event.timestamp) {
|
|
169
|
+
this.emit('rejoined', event.timestamp);
|
|
170
|
+
} else {
|
|
171
|
+
this.joinedAt = event.timestamp;
|
|
172
|
+
logger.warn(`Client ${this.clientId} joinedAt timestamp was updated to ${event.timestamp}. the joined event will not be emitted.`);
|
|
765
173
|
}
|
|
766
174
|
}
|
|
767
|
-
|
|
768
|
-
logger.error(`Error creating inbound audio track: ${(err as Error)?.message}`);
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
for (const track of sample.inboundVideoTracks ?? []) {
|
|
773
|
-
if (!track.peerConnectionId || !track.trackId) {
|
|
774
|
-
logger.warn(`InboundVideoTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
|
|
775
|
-
|
|
776
|
-
continue;
|
|
777
|
-
}
|
|
778
|
-
if (isValidUuid(track.trackId) === false) {
|
|
779
|
-
// mediasoup-probator trackId is not a valid UUID, no need to warn about it
|
|
780
|
-
if (track.trackId === 'probator') continue;
|
|
781
|
-
logger.warn(`InboundVideoTrack with invalid trackId: ${track.trackId}`);
|
|
782
|
-
continue;
|
|
175
|
+
break;
|
|
783
176
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
const inboundVideoTrack = peerConnection.inboundVideoTracks.get(track.trackId) ?? peerConnection.createInboundVideoTrack({
|
|
791
|
-
trackId: track.trackId,
|
|
792
|
-
sfuStreamId: track.sfuStreamId,
|
|
793
|
-
sfuSinkId: track.sfuSinkId,
|
|
794
|
-
});
|
|
795
|
-
|
|
796
|
-
inboundVideoTrack.update(track, sample.timestamp);
|
|
797
|
-
|
|
798
|
-
if (!inboundVideoTrack.remoteOutboundTrack) {
|
|
799
|
-
const remoteOutboundTrack = this.call.sfuStreamIdToOutboundVideoTrack.get(inboundVideoTrack.sfuStreamId ?? '');
|
|
800
|
-
|
|
801
|
-
if (remoteOutboundTrack) {
|
|
802
|
-
inboundVideoTrack.remoteOutboundTrack = remoteOutboundTrack;
|
|
803
|
-
|
|
804
|
-
inboundVideoTrack.once('close', () => {
|
|
805
|
-
remoteOutboundTrack?.remoteInboundTracks.delete(inboundVideoTrack.trackId ?? '');
|
|
806
|
-
});
|
|
807
|
-
remoteOutboundTrack.remoteInboundTracks.set(inboundVideoTrack.trackId ?? '', inboundVideoTrack);
|
|
177
|
+
case ClientEventTypes.CLIENT_LEFT: {
|
|
178
|
+
if (event.timestamp) {
|
|
179
|
+
if (!this.leftAt) {
|
|
180
|
+
this.leftAt = event.timestamp;
|
|
181
|
+
this.emit('left');
|
|
808
182
|
}
|
|
809
183
|
}
|
|
810
|
-
|
|
811
|
-
logger.error(`Error creating inbound video track: ${(err as Error)?.message}`);
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
for (const track of sample.outboundAudioTracks ?? []) {
|
|
816
|
-
if (!track.peerConnectionId || !track.trackId) {
|
|
817
|
-
logger.warn(`OutboundAudioTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
|
|
818
|
-
|
|
819
|
-
continue;
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
try {
|
|
823
|
-
const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? this._createPeerConnection(track.peerConnectionId);
|
|
824
|
-
|
|
825
|
-
if (!peerConnection) continue;
|
|
826
|
-
|
|
827
|
-
const outboundAudioTrack = peerConnection.outboundAudioTracks.get(track.trackId) ?? peerConnection.createOutboundAudioTrack({
|
|
828
|
-
trackId: track.trackId,
|
|
829
|
-
sfuStreamId: track.sfuStreamId,
|
|
830
|
-
});
|
|
831
|
-
|
|
832
|
-
outboundAudioTrack.update(track, sample.timestamp);
|
|
833
|
-
|
|
834
|
-
if (outboundAudioTrack.sfuStreamId && !this.call.sfuStreamIdToOutboundAudioTrack.has(outboundAudioTrack.sfuStreamId)) {
|
|
835
|
-
this.call.sfuStreamIdToOutboundAudioTrack.set(outboundAudioTrack.sfuStreamId, outboundAudioTrack);
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
} catch (err) {
|
|
839
|
-
logger.error(`Error creating outbound audio track: ${(err as Error)?.message}`);
|
|
184
|
+
break;
|
|
840
185
|
}
|
|
841
|
-
|
|
842
186
|
}
|
|
843
187
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
try {
|
|
852
|
-
const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? this._createPeerConnection(track.peerConnectionId);
|
|
853
|
-
|
|
854
|
-
if (!peerConnection) continue;
|
|
855
|
-
|
|
856
|
-
const outboundVideoTrack = peerConnection.outboundVideoTracks.get(track.trackId) ?? peerConnection.createOutboundVideoTrack({
|
|
857
|
-
trackId: track.trackId,
|
|
858
|
-
sfuStreamId: track.sfuStreamId,
|
|
859
|
-
});
|
|
860
|
-
|
|
861
|
-
outboundVideoTrack.update(track, sample.timestamp);
|
|
862
|
-
|
|
863
|
-
if (outboundVideoTrack.sfuStreamId && !this.call.sfuStreamIdToOutboundVideoTrack.has(outboundVideoTrack.sfuStreamId)) {
|
|
864
|
-
this.call.sfuStreamIdToOutboundVideoTrack.set(outboundVideoTrack.sfuStreamId, outboundVideoTrack);
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
} catch (err) {
|
|
868
|
-
logger.error(`Error creating outbound video track: ${(err as Error)?.message}`);
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
for (const iceLocalCandidate of sample.iceLocalCandidates ?? []) {
|
|
873
|
-
if (!iceLocalCandidate.peerConnectionId) {
|
|
874
|
-
logger.warn(`Local ice candidate without peerConnectionId: ${JSON.stringify(iceLocalCandidate)}`);
|
|
875
|
-
continue;
|
|
876
|
-
}
|
|
877
|
-
const peerConnection = this._peerConnections.get(iceLocalCandidate.peerConnectionId);
|
|
878
|
-
|
|
879
|
-
if (!peerConnection) {
|
|
880
|
-
logger.debug(`Peer connection ${iceLocalCandidate.peerConnectionId} not found for ice local candidate ${iceLocalCandidate.id}`);
|
|
881
|
-
continue;
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
peerConnection.ICE.addLocalCandidate(iceLocalCandidate, sample.timestamp);
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
for (const iceRemoteCandidate of sample.iceRemoteCandidates ?? []) {
|
|
888
|
-
if (!iceRemoteCandidate.peerConnectionId) {
|
|
889
|
-
logger.warn(`Remote ice candidate without peerConnectionId: ${JSON.stringify(iceRemoteCandidate)}`);
|
|
890
|
-
continue;
|
|
891
|
-
}
|
|
892
|
-
const peerConnection = this._peerConnections.get(iceRemoteCandidate.peerConnectionId);
|
|
893
|
-
|
|
894
|
-
if (!peerConnection) {
|
|
895
|
-
logger.debug(`Peer connection ${iceRemoteCandidate.peerConnectionId} not found for ice remote candidate ${iceRemoteCandidate.id}`);
|
|
896
|
-
continue;
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
peerConnection.ICE.addRemoteCandidate(iceRemoteCandidate, sample.timestamp);
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
for (const candidatePair of sample.iceCandidatePairs ?? []) {
|
|
903
|
-
const peerConnection = this._peerConnections.get(candidatePair.peerConnectionId);
|
|
904
|
-
|
|
905
|
-
if (!peerConnection) {
|
|
906
|
-
logger.debug(`Peer connection ${candidatePair.peerConnectionId} not found for ice candidate pair ${candidatePair.localCandidateId}, ${candidatePair.remoteCandidateId}`);
|
|
907
|
-
|
|
908
|
-
continue;
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
peerConnection.ICE.update(candidatePair, sample.timestamp);
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
for (const dataChannel of sample.dataChannels ?? []) {
|
|
915
|
-
if (!dataChannel.peerConnectionId || !dataChannel.dataChannelIdentifier) {
|
|
916
|
-
logger.warn(`DataChannel without peerConnectionId or dataChannelIdentifier: ${JSON.stringify(dataChannel)}`);
|
|
917
|
-
|
|
918
|
-
continue;
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
try {
|
|
922
|
-
const peerConnection = this._peerConnections.get(dataChannel.peerConnectionId) ?? this._createPeerConnection(dataChannel.peerConnectionId);
|
|
923
|
-
|
|
924
|
-
if (!peerConnection) continue;
|
|
925
|
-
|
|
926
|
-
const observedDataChannel = peerConnection.dataChannels.get(dataChannel.dataChannelIdentifier) ?? peerConnection.createDataChannel(dataChannel.dataChannelIdentifier);
|
|
927
|
-
|
|
928
|
-
observedDataChannel.update(dataChannel, sample.timestamp);
|
|
929
|
-
} catch (err) {
|
|
930
|
-
logger.error(`Error creating data channel: ${(err as Error)?.message}`);
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
// try to set the timestamps of the peer connections
|
|
935
|
-
if (0 < this.ωpendingPeerConnectionTimestamps.length) {
|
|
936
|
-
const newPendingTimestamps: PendingPeerConnectionTimestamp[] = [];
|
|
937
|
-
|
|
938
|
-
for (const pendingTimestamp of this.ωpendingPeerConnectionTimestamps) {
|
|
939
|
-
const peerConnection = this._peerConnections.get(pendingTimestamp.peerConnectionId);
|
|
940
|
-
|
|
941
|
-
if (!peerConnection) {
|
|
942
|
-
newPendingTimestamps.push(pendingTimestamp);
|
|
943
|
-
continue;
|
|
944
|
-
}
|
|
945
|
-
if (pendingTimestamp.type === 'opened') peerConnection.opened = pendingTimestamp.timestamp;
|
|
946
|
-
else if (pendingTimestamp.type === 'closed') peerConnection.closedTimestamp = pendingTimestamp.timestamp;
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
this.ωpendingPeerConnectionTimestamps = newPendingTimestamps;
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
// try to set the timestamps of the media tracks
|
|
953
|
-
if (0 < this.ωpendingMediaTrackTimestamps.length) {
|
|
954
|
-
const newPendingTimestamps: PendingMediaTrackTimestamp[] = [];
|
|
955
|
-
|
|
956
|
-
for (const pendingTimestamp of this.ωpendingMediaTrackTimestamps) {
|
|
957
|
-
const peerConnection = this._peerConnections.get(pendingTimestamp.peerConnectionId);
|
|
958
|
-
const mediaTrack = peerConnection?.inboundAudioTracks.get(pendingTimestamp.mediaTrackId) ??
|
|
959
|
-
peerConnection?.inboundVideoTracks.get(pendingTimestamp.mediaTrackId) ??
|
|
960
|
-
peerConnection?.outboundAudioTracks.get(pendingTimestamp.mediaTrackId) ??
|
|
961
|
-
peerConnection?.outboundVideoTracks.get(pendingTimestamp.mediaTrackId);
|
|
962
|
-
|
|
963
|
-
if (!mediaTrack) {
|
|
964
|
-
newPendingTimestamps.push(pendingTimestamp);
|
|
965
|
-
continue;
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
if (pendingTimestamp.type === 'added') mediaTrack.added = pendingTimestamp.timestamp;
|
|
969
|
-
else if (pendingTimestamp.type === 'removed') mediaTrack.removed = pendingTimestamp.timestamp;
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
this.ωpendingMediaTrackTimestamps = newPendingTimestamps;
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
// close resources that are not visited
|
|
976
|
-
for (const peerConnection of this._peerConnections.values()) {
|
|
977
|
-
if (!peerConnection.visited) {
|
|
978
|
-
peerConnection.close();
|
|
979
|
-
|
|
980
|
-
continue;
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
for (const track of peerConnection.inboundAudioTracks.values()) {
|
|
984
|
-
if (!track.visited) {
|
|
985
|
-
track.close();
|
|
986
|
-
|
|
987
|
-
continue;
|
|
988
|
-
}
|
|
989
|
-
|
|
990
|
-
track.visited = false;
|
|
991
|
-
}
|
|
992
|
-
for (const track of peerConnection.inboundVideoTracks.values()) {
|
|
993
|
-
if (!track.visited) {
|
|
994
|
-
track.close();
|
|
995
|
-
|
|
996
|
-
continue;
|
|
997
|
-
}
|
|
188
|
+
this.call.observer.processors.events.process({
|
|
189
|
+
call: this.call,
|
|
190
|
+
client: this,
|
|
191
|
+
data: event,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
998
194
|
|
|
999
|
-
|
|
195
|
+
public processMetadata(metadata: ClientMetaData) {
|
|
196
|
+
switch (metadata.type) {
|
|
197
|
+
case ClientMetaTypes.BROWSER: {
|
|
198
|
+
this.browser = parseJsonAs(metadata.payload);
|
|
199
|
+
break;
|
|
1000
200
|
}
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
continue;
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
track.visited = false;
|
|
201
|
+
case ClientMetaTypes.ENGINE: {
|
|
202
|
+
this.engine = parseJsonAs(metadata.payload);
|
|
203
|
+
break;
|
|
1009
204
|
}
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
continue;
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
dataChannel.visited = false;
|
|
205
|
+
case ClientMetaTypes.PLATFORM: {
|
|
206
|
+
this.platform = parseJsonAs(metadata.payload);
|
|
207
|
+
break;
|
|
1018
208
|
}
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
// update metrics
|
|
1024
|
-
const wasUsingTURN = this.usingTURN;
|
|
1025
|
-
const elapsedTimeInMs = now - this.updated;
|
|
1026
|
-
|
|
1027
|
-
this.usingTURN = false;
|
|
1028
|
-
this.availableIncomingBitrate = 0;
|
|
1029
|
-
this.availableOutgoingBitrate = 0;
|
|
1030
|
-
this.deltaInboundPacketsLost = 0;
|
|
1031
|
-
this.deltaInboundPacketsReceived = 0;
|
|
1032
|
-
this.deltaOutboundPacketsSent = 0;
|
|
1033
|
-
this.deltaReceivedAudioBytes = 0;
|
|
1034
|
-
this.deltaReceivedVideoBytes = 0;
|
|
1035
|
-
this.deltaSentAudioBytes = 0;
|
|
1036
|
-
this.deltaSentVideoBytes = 0;
|
|
1037
|
-
this.deltaDataChannelBytesReceived = 0;
|
|
1038
|
-
this.deltaDataChannelBytesSent = 0;
|
|
1039
|
-
|
|
1040
|
-
this.outboundAudioBitrate = 0;
|
|
1041
|
-
this.outboundVideoBitrate = 0;
|
|
1042
|
-
this.inboundAudioBitrate = 0;
|
|
1043
|
-
this.inboundVideoBitrate = 0;
|
|
1044
|
-
let sumRttInMs = 0;
|
|
1045
|
-
let anyPeerConnectionUsingTurn = false;
|
|
1046
|
-
|
|
1047
|
-
let minPcScore: number | undefined;
|
|
1048
|
-
let maxPcScore: number | undefined;
|
|
1049
|
-
let numberOfScoredPeerConnections = 0;
|
|
1050
|
-
|
|
1051
|
-
for (const peerConnection of this._peerConnections.values()) {
|
|
1052
|
-
if (peerConnection.closed) continue;
|
|
1053
|
-
|
|
1054
|
-
peerConnection.updateMetrics();
|
|
1055
|
-
|
|
1056
|
-
this.deltaInboundPacketsLost += peerConnection.deltaInboundPacketsLost;
|
|
1057
|
-
this.deltaInboundPacketsReceived += peerConnection.deltaInboundPacketsReceived;
|
|
1058
|
-
this.deltaOutboundPacketsSent += peerConnection.deltaOutboundPacketsSent;
|
|
1059
|
-
this.deltaReceivedAudioBytes += peerConnection.deltaReceivedAudioBytes;
|
|
1060
|
-
this.deltaReceivedVideoBytes += peerConnection.deltaReceivedVideoBytes;
|
|
1061
|
-
this.deltaSentAudioBytes += peerConnection.deltaSentAudioBytes;
|
|
1062
|
-
this.deltaSentVideoBytes += peerConnection.deltaSentVideoBytes;
|
|
1063
|
-
this.deltaDataChannelBytesReceived += peerConnection.deltaDataChannelBytesReceived;
|
|
1064
|
-
this.deltaDataChannelBytesSent += peerConnection.deltaDataChannelBytesSent;
|
|
1065
|
-
|
|
1066
|
-
this.availableIncomingBitrate += peerConnection.availableIncomingBitrate ?? 0;
|
|
1067
|
-
this.availableOutgoingBitrate += peerConnection.availableOutgoingBitrate ?? 0;
|
|
1068
|
-
|
|
1069
|
-
sumRttInMs += peerConnection.avgRttInMs ?? 0;
|
|
1070
|
-
|
|
1071
|
-
anyPeerConnectionUsingTurn ||= peerConnection.usingTURN;
|
|
1072
|
-
|
|
1073
|
-
if (peerConnection.score) {
|
|
1074
|
-
if (minPcScore === undefined || peerConnection.score.score < minPcScore) minPcScore = peerConnection.score.score;
|
|
1075
|
-
if (maxPcScore === undefined || peerConnection.score.score > maxPcScore) maxPcScore = peerConnection.score.score;
|
|
1076
|
-
|
|
1077
|
-
++numberOfScoredPeerConnections;
|
|
209
|
+
case ClientMetaTypes.OPERATION_SYSTEM: {
|
|
210
|
+
this.operationSystem = parseJsonAs(metadata.payload);
|
|
211
|
+
break;
|
|
1078
212
|
}
|
|
1079
213
|
}
|
|
1080
214
|
|
|
1081
|
-
this.
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
text: `Min and max score of all peer connections: ${minPcScore}, ${maxPcScore}, number of PeerConnections with scores: ${numberOfScoredPeerConnections}`,
|
|
1086
|
-
} ],
|
|
1087
|
-
timestamp: sample.timestamp,
|
|
1088
|
-
};
|
|
1089
|
-
this.emit('score', this.score);
|
|
1090
|
-
|
|
1091
|
-
this.usingTURN = anyPeerConnectionUsingTurn === true;
|
|
1092
|
-
|
|
1093
|
-
if (wasUsingTURN !== this.usingTURN) this.emit('usingturn', this.usingTURN);
|
|
1094
|
-
|
|
1095
|
-
this.totalSentBytes += this.deltaSentAudioBytes + this.deltaSentVideoBytes;
|
|
1096
|
-
this.totalReceivedBytes += this.deltaReceivedAudioBytes + this.deltaReceivedVideoBytes;
|
|
1097
|
-
this.totalReceivedAudioBytes += this.deltaReceivedAudioBytes;
|
|
1098
|
-
this.totalReceivedVideoBytes += this.deltaReceivedVideoBytes;
|
|
1099
|
-
this.totalSentAudioBytes += this.deltaSentAudioBytes;
|
|
1100
|
-
this.totalSentVideoBytes += this.deltaSentVideoBytes;
|
|
1101
|
-
this.totalOutboundPacketsSent += this.deltaOutboundPacketsSent;
|
|
1102
|
-
this.totalInboundPacketsReceived += this.deltaInboundPacketsReceived;
|
|
1103
|
-
this.totalInboundPacketsLost += this.deltaInboundPacketsLost;
|
|
1104
|
-
this.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
|
|
1105
|
-
this.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
|
|
1106
|
-
|
|
1107
|
-
this.outboundAudioBitrate = (this.deltaSentAudioBytes * 8) / (Math.max(elapsedTimeInMs, 1) / 1000);
|
|
1108
|
-
this.outboundVideoBitrate = (this.deltaSentVideoBytes * 8) / (Math.max(elapsedTimeInMs, 1) / 1000);
|
|
1109
|
-
this.inboundAudioBitrate = (this.deltaReceivedAudioBytes * 8) / (Math.max(elapsedTimeInMs, 1) / 1000);
|
|
1110
|
-
this.inboundVideoBitrate = (this.deltaReceivedVideoBytes * 8) / (Math.max(elapsedTimeInMs, 1) / 1000);
|
|
1111
|
-
|
|
1112
|
-
this.avgRttInMs = this._peerConnections.size ? sumRttInMs / this._peerConnections.size : undefined;
|
|
1113
|
-
|
|
1114
|
-
// to make sure when sample is emitted it can be associated to this client
|
|
1115
|
-
sample.clientId = this.clientId;
|
|
1116
|
-
|
|
1117
|
-
this.updated = now;
|
|
1118
|
-
this.lastStatsTimestamp = sample.timestamp;
|
|
1119
|
-
this.emit('update', {
|
|
1120
|
-
sample,
|
|
1121
|
-
elapsedTimeInMs,
|
|
215
|
+
this.call.observer.processors.metaData.process({
|
|
216
|
+
call: this.call,
|
|
217
|
+
client: this,
|
|
218
|
+
data: metadata,
|
|
1122
219
|
});
|
|
1123
220
|
}
|
|
1124
221
|
|
|
1125
|
-
|
|
1126
|
-
this.issues.
|
|
222
|
+
public processIssue(issue: ClientIssue) {
|
|
223
|
+
this.call.observer.processors.issues.process({
|
|
224
|
+
call: this.call,
|
|
225
|
+
client: this,
|
|
226
|
+
data: issue,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
1127
229
|
|
|
1128
|
-
|
|
1129
|
-
|
|
230
|
+
public processExtensionStats(stats: ExtensionStat) {
|
|
231
|
+
this.call.observer.processors.extensionStats.process({
|
|
232
|
+
call: this.call,
|
|
233
|
+
client: this,
|
|
234
|
+
data: stats,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
1130
237
|
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
if (issue.trackId) {
|
|
1134
|
-
const track = peerConnection.inboundAudioTracks.get(issue.trackId) ?? peerConnection.inboundVideoTracks.get(issue.trackId);
|
|
238
|
+
private _updatePeerConnection(sample: PeerConnectionSample) {
|
|
239
|
+
let observedPeerConnection = this.observedPeerConnections.get(sample.peerConnectionId);
|
|
1135
240
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
241
|
+
if (!observedPeerConnection) {
|
|
242
|
+
if (!sample.peerConnectionId) {
|
|
243
|
+
return logger.warn(
|
|
244
|
+
`ObservedClient received an invalid PeerConnectionSample (missing peerConnectionId field). ClientId: ${this.clientId}, CallId: ${this.call.callId}`,
|
|
245
|
+
sample
|
|
246
|
+
);
|
|
1140
247
|
}
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
this.emit('issue', issue);
|
|
1144
|
-
}
|
|
1145
248
|
|
|
1146
|
-
|
|
1147
|
-
const result = new ObservedPeerConnection({
|
|
1148
|
-
peerConnectionId,
|
|
1149
|
-
label,
|
|
1150
|
-
}, this);
|
|
249
|
+
observedPeerConnection = new ObservedPeerConnection(sample.peerConnectionId, this);
|
|
1151
250
|
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
peerConnection: result,
|
|
1155
|
-
localCandidate,
|
|
1156
|
-
remoteCandidate,
|
|
251
|
+
observedPeerConnection.once('close', () => {
|
|
252
|
+
this.observedPeerConnections.delete(sample.peerConnectionId);
|
|
1157
253
|
});
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
result.once('close', () => {
|
|
1161
|
-
result.ICE.off('new-selected-candidate-pair', onNewSelectedCandidatePair);
|
|
1162
|
-
this._peerConnections.delete(peerConnectionId);
|
|
1163
|
-
});
|
|
1164
|
-
result.ICE.on('new-selected-candidate-pair', onNewSelectedCandidatePair);
|
|
1165
|
-
this._peerConnections.set(peerConnectionId, result);
|
|
1166
|
-
|
|
1167
|
-
this.emit('newpeerconnection', result);
|
|
254
|
+
this.observedPeerConnections.set(sample.peerConnectionId, observedPeerConnection);
|
|
255
|
+
}
|
|
1168
256
|
|
|
1169
|
-
|
|
257
|
+
observedPeerConnection.accept(sample);
|
|
1170
258
|
}
|
|
1171
|
-
}
|
|
259
|
+
}
|