@observertc/observer-js 0.42.9 → 1.0.1-1b9b3c5.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 +63 -43
- package/lib/ObservedCall.d.ts.map +1 -1
- package/lib/ObservedCall.js +176 -108
- package/lib/ObservedCallEventMonitor.d.ts +103 -0
- package/lib/ObservedCallEventMonitor.d.ts.map +1 -0
- package/lib/ObservedCallEventMonitor.js +312 -0
- package/lib/ObservedCallSummary.d.ts +18 -0
- package/lib/ObservedCallSummary.d.ts.map +1 -0
- 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 +79 -130
- package/lib/ObservedClient.d.ts.map +1 -1
- package/lib/ObservedClient.js +463 -744
- package/lib/ObservedClientEventMonitor.d.ts +89 -0
- package/lib/ObservedClientEventMonitor.d.ts.map +1 -0
- package/lib/ObservedClientEventMonitor.js +247 -0
- package/lib/ObservedClientSummary.d.ts +23 -0
- package/lib/ObservedClientSummary.d.ts.map +1 -0
- package/lib/ObservedClientSummary.js +2 -0
- 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 +25 -69
- package/lib/ObservedDataChannel.d.ts.map +1 -1
- package/lib/ObservedDataChannel.js +69 -109
- package/lib/ObservedIceCandidate.d.ts +29 -0
- package/lib/ObservedIceCandidate.d.ts.map +1 -0
- package/lib/ObservedIceCandidate.js +59 -0
- package/lib/ObservedIceCandidatePair.d.ts +44 -0
- package/lib/ObservedIceCandidatePair.d.ts.map +1 -0
- package/lib/ObservedIceCandidatePair.js +111 -0
- package/lib/ObservedIceTransport.d.ts +36 -0
- package/lib/ObservedIceTransport.d.ts.map +1 -0
- package/lib/ObservedIceTransport.js +93 -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 +31 -0
- package/lib/ObservedInboundTrack.d.ts.map +1 -0
- package/lib/ObservedInboundTrack.js +59 -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 +31 -0
- package/lib/ObservedOutboundTrack.d.ts.map +1 -0
- package/lib/ObservedOutboundTrack.js +59 -0
- package/lib/ObservedPeerConnection.d.ts +132 -80
- package/lib/ObservedPeerConnection.d.ts.map +1 -1
- package/lib/ObservedPeerConnection.js +646 -357
- package/lib/ObservedPeerConnectionTransport.d.ts +17 -0
- package/lib/ObservedPeerConnectionTransport.d.ts.map +1 -0
- package/lib/ObservedPeerConnectionTransport.js +34 -0
- package/lib/ObservedRemoteInboundRtp.d.ts +30 -0
- package/lib/ObservedRemoteInboundRtp.d.ts.map +1 -0
- package/lib/ObservedRemoteInboundRtp.js +60 -0
- package/lib/ObservedRemoteOutboundRtp.d.ts +30 -0
- package/lib/ObservedRemoteOutboundRtp.d.ts.map +1 -0
- package/lib/ObservedRemoteOutboundRtp.js +60 -0
- package/lib/ObservedTURN.d.ts +31 -0
- package/lib/ObservedTURN.d.ts.map +1 -0
- package/lib/ObservedTURN.js +58 -0
- package/lib/ObservedTurnServer.d.ts +25 -0
- package/lib/ObservedTurnServer.d.ts.map +1 -0
- package/lib/ObservedTurnServer.js +59 -0
- package/lib/Observer.d.ts +44 -51
- package/lib/Observer.d.ts.map +1 -1
- package/lib/Observer.js +135 -226
- package/lib/ObserverEventMonitor.d.ts +106 -0
- package/lib/ObserverEventMonitor.d.ts.map +1 -0
- package/lib/ObserverEventMonitor.js +320 -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/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 +3 -1
- package/lib/common/utils.d.ts.map +1 -1
- package/lib/common/utils.js +23 -3
- 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 +26 -25
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +45 -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 +160 -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/CalculatedScore.js +2 -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/updaters/CallUpdater.d.ts +5 -0
- 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 +7 -0
- package/lib/utils/RemoteTrackResolver.d.ts.map +1 -0
- package/lib/utils/RemoteTrackResolver.js +2 -0
- package/package.json +4 -4
- package/src/ObservedCall.ts +267 -166
- package/src/ObservedCallEventMonitor.ts +389 -0
- package/src/ObservedCallSummary.ts +22 -0
- package/src/ObservedCertificate.ts +43 -0
- package/src/ObservedClient.ts +519 -1020
- package/src/ObservedClientEventMonitor.ts +301 -0
- package/src/ObservedClientSummary.ts +24 -0
- package/src/ObservedCodec.ts +49 -0
- package/src/ObservedDataChannel.ts +71 -181
- package/src/ObservedIceCandidate.ts +64 -0
- package/src/ObservedIceCandidatePair.ts +118 -0
- package/src/ObservedIceTransport.ts +99 -0
- package/src/ObservedInboundRtp.ts +205 -0
- package/src/ObservedInboundTrack.ts +73 -0
- package/src/ObservedMediaPlayout.ts +49 -0
- package/src/ObservedMediaSource.ts +60 -0
- package/src/ObservedOutboundRtp.ts +156 -0
- package/src/ObservedOutboundTrack.ts +72 -0
- package/src/ObservedPeerConnection.ts +854 -408
- package/src/ObservedPeerConnectionTransport.ts +38 -0
- package/src/ObservedRemoteInboundRtp.ts +64 -0
- package/src/ObservedRemoteOutboundRtp.ts +65 -0
- package/src/ObservedTURN.ts +86 -0
- package/src/ObservedTurnServer.ts +72 -0
- package/src/Observer.ts +180 -295
- package/src/ObserverEventMonitor.ts +398 -0
- package/src/ObserverSummary.ts +15 -0
- 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 +24 -2
- package/src/detectors/Detector.ts +6 -0
- package/src/detectors/Detectors.ts +38 -0
- package/src/index.ts +26 -90
- package/src/monitors/TurnUsageMonitor.ts +164 -164
- package/src/schema/ClientEventTypes.ts +176 -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/updaters/CallUpdater.ts +5 -0
- 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 +12 -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 → ObservedCallSummary.js} +0 -0
package/src/ObservedClient.ts
CHANGED
|
@@ -1,123 +1,96 @@
|
|
|
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
|
-
|
|
50
|
-
|
|
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
|
+
issue: [ClientIssue];
|
|
31
|
+
metaData: [ClientMetaData];
|
|
32
|
+
rejoined: [timestamp: number];
|
|
33
|
+
left: [];
|
|
34
|
+
usingturn: [boolean];
|
|
35
|
+
usermediaerror: [string];
|
|
36
|
+
extensionStats: [ExtensionStat];
|
|
37
|
+
clientEvent: [ClientEvent];
|
|
38
|
+
|
|
39
|
+
newpeerconnection: [ObservedPeerConnection];
|
|
65
40
|
};
|
|
66
41
|
|
|
67
|
-
export declare interface ObservedClient
|
|
42
|
+
export declare interface ObservedClient {
|
|
68
43
|
on<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;
|
|
69
44
|
off<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;
|
|
70
45
|
once<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;
|
|
71
46
|
emit<U extends keyof ObservedClientEvents>(event: U, ...args: ObservedClientEvents[U]): boolean;
|
|
72
|
-
readonly appData: AppData;
|
|
73
47
|
}
|
|
74
48
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
peerConnectionId: string;
|
|
78
|
-
timestamp: number;
|
|
79
|
-
}
|
|
49
|
+
export class ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {
|
|
50
|
+
public readonly detectors: Detectors;
|
|
80
51
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
52
|
+
public readonly clientId: string;
|
|
53
|
+
public readonly observedPeerConnections = new Map<string, ObservedPeerConnection>();
|
|
54
|
+
public readonly calculatedScore: CalculatedScore = {
|
|
55
|
+
weight: 1,
|
|
56
|
+
value: undefined,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
public appData: AppData;
|
|
60
|
+
public attachments?: Record<string, unknown>;
|
|
87
61
|
|
|
88
|
-
export class ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {
|
|
89
|
-
|
|
90
|
-
public readonly created = Date.now();
|
|
91
62
|
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;
|
|
63
|
+
public acceptedSamples = 0;
|
|
64
|
+
public closed = false;
|
|
100
65
|
|
|
66
|
+
public joinedAt?: number;
|
|
67
|
+
public leftAt?: number;
|
|
68
|
+
public closedAt?: number;
|
|
101
69
|
// the timestamp of the CLIENT_JOINED event
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
public
|
|
70
|
+
public operationSystem?: MetaData.OperationSystem;
|
|
71
|
+
public engine?: MetaData.Engine;
|
|
72
|
+
public platform?: MetaData.Platform;
|
|
73
|
+
public browser?: MetaData.Browser;
|
|
74
|
+
public mediaConstraints: string[] = [];
|
|
105
75
|
|
|
106
|
-
public score?: CalculatedScore;
|
|
107
76
|
public usingTURN = false;
|
|
77
|
+
public usingTCP = false;
|
|
108
78
|
public availableOutgoingBitrate = 0;
|
|
109
79
|
public availableIncomingBitrate = 0;
|
|
80
|
+
|
|
110
81
|
public totalInboundPacketsLost = 0;
|
|
111
82
|
public totalInboundPacketsReceived = 0;
|
|
112
83
|
public totalOutboundPacketsSent = 0;
|
|
113
84
|
public totalDataChannelBytesSent = 0;
|
|
114
85
|
public totalDataChannelBytesReceived = 0;
|
|
115
|
-
public
|
|
116
|
-
public
|
|
86
|
+
public totalDataChannelMessagesSent = 0;
|
|
87
|
+
public totalDataChannelMessagesReceived = 0;
|
|
117
88
|
public totalReceivedAudioBytes = 0;
|
|
118
89
|
public totalReceivedVideoBytes = 0;
|
|
119
90
|
public totalSentAudioBytes = 0;
|
|
120
91
|
public totalSentVideoBytes = 0;
|
|
92
|
+
public totalSentBytes = 0;
|
|
93
|
+
public totalReceivedBytes = 0;
|
|
121
94
|
|
|
122
95
|
public deltaReceivedAudioBytes = 0;
|
|
123
96
|
public deltaReceivedVideoBytes = 0;
|
|
@@ -125,1047 +98,573 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
125
98
|
public deltaSentVideoBytes = 0;
|
|
126
99
|
public deltaDataChannelBytesSent = 0;
|
|
127
100
|
public deltaDataChannelBytesReceived = 0;
|
|
101
|
+
public deltaDataChannelMessagesSent = 0;
|
|
102
|
+
public deltaDataChannelMessagesReceived = 0;
|
|
128
103
|
public deltaInboundPacketsLost = 0;
|
|
129
104
|
public deltaInboundPacketsReceived = 0;
|
|
130
105
|
public deltaOutboundPacketsSent = 0;
|
|
131
|
-
|
|
132
|
-
public
|
|
133
|
-
public
|
|
134
|
-
public
|
|
135
|
-
public
|
|
136
|
-
public
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
public
|
|
140
|
-
public
|
|
141
|
-
|
|
106
|
+
public deltaTransportSentBytes = 0;
|
|
107
|
+
public deltaTransportReceivedBytes = 0;
|
|
108
|
+
public deltaRttLt50Measurements = 0;
|
|
109
|
+
public deltaRttLt150Measurements = 0;
|
|
110
|
+
public deltaRttLt300Measurements = 0;
|
|
111
|
+
public deltaRttGtOrEq300Measurements = 0;
|
|
112
|
+
|
|
113
|
+
public currentMaxRttInMs?: number;
|
|
114
|
+
public currentMinRttInMs?: number;
|
|
115
|
+
public currentAvgRttInMs?: number;
|
|
116
|
+
|
|
117
|
+
public sendingAudioBitrate = 0;
|
|
118
|
+
public sendingVideoBitrate = 0;
|
|
119
|
+
public receivingAudioBitrate = 0;
|
|
120
|
+
public receivingVideoBitrate = 0;
|
|
121
|
+
|
|
122
|
+
public numberOfInboundRtpStreams = 0;
|
|
123
|
+
public numberOfInbundTracks = 0;
|
|
124
|
+
public numberOfOutboundRtpStreams = 0;
|
|
125
|
+
public numberOfOutboundTracks = 0;
|
|
126
|
+
public numberOfDataChannels = 0;
|
|
127
|
+
|
|
128
|
+
public totalRttLt50Measurements = 0;
|
|
129
|
+
public totalRttLt150Measurements = 0;
|
|
130
|
+
public totalRttLt300Measurements = 0;
|
|
131
|
+
public totalRttGtOrEq300Measurements = 0;
|
|
132
|
+
public deltaNumberOfIssues = 0;
|
|
133
|
+
|
|
134
|
+
public totalScoreSum = 0;
|
|
135
|
+
public numberOfScoreMeasurements = 0;
|
|
136
|
+
public totalNumberOfIssues = 0;
|
|
137
|
+
|
|
138
|
+
public readonly mediaDevices: MetaData.MediaDeviceInfo[] = [];
|
|
142
139
|
public issues: ClientIssue[] = [];
|
|
143
140
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
public constructor(
|
|
148
|
-
private readonly _model: ObservedClientModel,
|
|
149
|
-
public readonly call: ObservedCall,
|
|
150
|
-
public readonly appData: AppData
|
|
151
|
-
) {
|
|
141
|
+
private _injections: Pick<ClientSample, 'clientEvents' | 'clientIssues' | 'extensionStats' | 'attachments' | 'clientMetaItems'> = {};
|
|
142
|
+
|
|
143
|
+
public constructor(settings: ObservedClientSettings<AppData>, public readonly call: ObservedCall) {
|
|
152
144
|
super();
|
|
153
145
|
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
|
-
|
|
168
|
-
public set joined(value: number | undefined) {
|
|
169
|
-
this._joined = value;
|
|
170
|
-
|
|
171
|
-
if (this._joined) {
|
|
172
|
-
this.emit('joined');
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
public get left() {
|
|
177
|
-
return this._left;
|
|
178
|
-
}
|
|
179
146
|
|
|
180
|
-
|
|
181
|
-
this.
|
|
147
|
+
this.clientId = settings.clientId;
|
|
148
|
+
this.appData = settings.appData ?? {} as AppData;
|
|
182
149
|
|
|
183
|
-
|
|
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;
|
|
150
|
+
this.detectors = new Detectors();
|
|
261
151
|
}
|
|
262
|
-
|
|
263
|
-
public get
|
|
264
|
-
return this.
|
|
152
|
+
|
|
153
|
+
public get numberOfPeerConnections() {
|
|
154
|
+
return this.observedPeerConnections.size;
|
|
265
155
|
}
|
|
266
156
|
|
|
267
|
-
public get
|
|
268
|
-
return this.
|
|
157
|
+
public get score() {
|
|
158
|
+
return this.calculatedScore.value;
|
|
269
159
|
}
|
|
270
160
|
|
|
271
|
-
public get peerConnections(): ReadonlyMap<string, ObservedPeerConnection> {
|
|
272
|
-
return this._peerConnections;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
161
|
public close() {
|
|
276
|
-
if (this.
|
|
277
|
-
this.
|
|
162
|
+
if (this.closed) return;
|
|
163
|
+
this.closed = true;
|
|
278
164
|
|
|
279
|
-
Array.from(this.
|
|
165
|
+
Array.from(this.observedPeerConnections.values()).forEach((peerConnection) => peerConnection.close());
|
|
280
166
|
|
|
281
|
-
this.
|
|
282
|
-
}
|
|
283
|
-
|
|
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
|
-
}
|
|
167
|
+
this.closedAt = Date.now();
|
|
303
168
|
|
|
304
|
-
|
|
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);
|
|
169
|
+
this.emit('close');
|
|
343
170
|
}
|
|
344
171
|
|
|
345
172
|
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();
|
|
173
|
+
if (this.closed) throw new Error(`Client ${this.clientId} is closed`);
|
|
351
174
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
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
|
-
}
|
|
175
|
+
const now = Date.now();
|
|
176
|
+
const elapsedInMs = now - this.updated;
|
|
177
|
+
const elapsedInSeconds = elapsedInMs / 1000;
|
|
178
|
+
let sumOfRtts = 0;
|
|
179
|
+
let numberOfRttMeasurements = 0;
|
|
369
180
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
181
|
+
++this.acceptedSamples;
|
|
182
|
+
|
|
183
|
+
this.availableIncomingBitrate = 0;
|
|
184
|
+
this.availableOutgoingBitrate = 0;
|
|
185
|
+
this.deltaDataChannelBytesReceived = 0;
|
|
186
|
+
this.deltaDataChannelBytesSent = 0;
|
|
187
|
+
this.deltaDataChannelMessagesReceived = 0;
|
|
188
|
+
this.deltaDataChannelMessagesSent = 0;
|
|
189
|
+
this.deltaInboundPacketsLost = 0;
|
|
190
|
+
this.deltaInboundPacketsReceived = 0;
|
|
191
|
+
this.deltaOutboundPacketsSent = 0;
|
|
192
|
+
this.deltaReceivedAudioBytes = 0;
|
|
193
|
+
this.deltaReceivedVideoBytes = 0;
|
|
194
|
+
this.deltaSentAudioBytes = 0;
|
|
195
|
+
this.deltaSentVideoBytes = 0;
|
|
196
|
+
this.deltaTransportReceivedBytes = 0;
|
|
197
|
+
this.deltaTransportSentBytes = 0;
|
|
198
|
+
this.deltaRttLt50Measurements = 0;
|
|
199
|
+
this.deltaRttLt150Measurements = 0;
|
|
200
|
+
this.deltaRttLt300Measurements = 0;
|
|
201
|
+
this.deltaRttGtOrEq300Measurements = 0;
|
|
202
|
+
this.deltaNumberOfIssues = 0;
|
|
203
|
+
|
|
204
|
+
this.numberOfDataChannels = 0;
|
|
205
|
+
this.numberOfInboundRtpStreams = 0;
|
|
206
|
+
this.numberOfInbundTracks = 0;
|
|
207
|
+
this.numberOfOutboundRtpStreams = 0;
|
|
208
|
+
this.numberOfOutboundTracks = 0;
|
|
209
|
+
this.usingTURN = false;
|
|
210
|
+
this.usingTCP = false;
|
|
211
|
+
this.currentMinRttInMs = undefined;
|
|
212
|
+
this.currentMaxRttInMs = undefined;
|
|
374
213
|
|
|
375
|
-
|
|
376
|
-
this._timeZoneOffsetInHours = sample.timeZoneOffsetInHours;
|
|
377
|
-
}
|
|
214
|
+
this._mergeInjections(sample);
|
|
378
215
|
|
|
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
|
-
}
|
|
216
|
+
const clientEventsPostBuffer: ClientEvent[] = [];
|
|
403
217
|
|
|
404
|
-
|
|
405
|
-
this.
|
|
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
|
-
}
|
|
218
|
+
for (const clientEvent of sample.clientEvents ?? []) {
|
|
219
|
+
this._processClientEvent(clientEvent, clientEventsPostBuffer);
|
|
427
220
|
|
|
428
|
-
|
|
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);
|
|
221
|
+
this.call.observer.emit('client-event', this, clientEvent);
|
|
451
222
|
}
|
|
452
223
|
|
|
453
|
-
|
|
454
|
-
this.
|
|
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);
|
|
224
|
+
for (const metaData of sample.clientMetaItems ?? []) {
|
|
225
|
+
this.addMetadata(metaData);
|
|
475
226
|
}
|
|
476
227
|
|
|
477
|
-
for (const
|
|
478
|
-
|
|
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
|
-
}
|
|
228
|
+
for (const issue of sample.clientIssues ?? []) {
|
|
229
|
+
this.addIssue(issue);
|
|
496
230
|
|
|
497
|
-
|
|
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);
|
|
231
|
+
++this.deltaNumberOfIssues;
|
|
514
232
|
}
|
|
515
233
|
|
|
516
|
-
for (const
|
|
517
|
-
this.
|
|
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
|
-
});
|
|
234
|
+
for (const extensionStat of sample.extensionStats ?? []) {
|
|
235
|
+
this.addExtensionStats(extensionStat);
|
|
528
236
|
}
|
|
529
237
|
|
|
530
|
-
for (const
|
|
531
|
-
|
|
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
|
-
}
|
|
238
|
+
for (const pcSample of sample.peerConnections ?? []) {
|
|
239
|
+
const observedPeerConnection = this._updatePeerConnection(pcSample);
|
|
605
240
|
|
|
606
|
-
|
|
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
|
-
});
|
|
241
|
+
if (!observedPeerConnection) continue;
|
|
616
242
|
|
|
617
|
-
this.
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
243
|
+
this.deltaDataChannelBytesReceived += observedPeerConnection.deltaDataChannelBytesReceived;
|
|
244
|
+
this.deltaDataChannelBytesSent += observedPeerConnection.deltaDataChannelBytesSent;
|
|
245
|
+
this.deltaDataChannelMessagesReceived += observedPeerConnection.deltaDataChannelMessagesReceived;
|
|
246
|
+
this.deltaDataChannelMessagesSent += observedPeerConnection.deltaDataChannelMessagesSent;
|
|
247
|
+
this.deltaInboundPacketsLost += observedPeerConnection.deltaInboundPacketsLost;
|
|
248
|
+
this.deltaInboundPacketsReceived += observedPeerConnection.deltaInboundPacketsReceived;
|
|
249
|
+
this.deltaOutboundPacketsSent += observedPeerConnection.deltaOutboundPacketsSent;
|
|
250
|
+
this.deltaReceivedAudioBytes += observedPeerConnection.deltaReceivedAudioBytes;
|
|
251
|
+
this.deltaReceivedVideoBytes += observedPeerConnection.deltaReceivedVideoBytes;
|
|
252
|
+
this.deltaSentAudioBytes += observedPeerConnection.deltaSentAudioBytes;
|
|
253
|
+
this.deltaSentVideoBytes += observedPeerConnection.deltaSentVideoBytes;
|
|
254
|
+
this.deltaTransportReceivedBytes += observedPeerConnection.deltaTransportReceivedBytes;
|
|
255
|
+
this.deltaTransportSentBytes += observedPeerConnection.deltaTransportSentBytes;
|
|
624
256
|
|
|
625
|
-
|
|
257
|
+
this.availableIncomingBitrate += observedPeerConnection.availableIncomingBitrate;
|
|
258
|
+
this.availableOutgoingBitrate += observedPeerConnection.availableOutgoingBitrate;
|
|
626
259
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
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
|
-
}
|
|
260
|
+
this.numberOfDataChannels += observedPeerConnection.observedDataChannels.size;
|
|
261
|
+
this.numberOfInbundTracks += observedPeerConnection.observedInboundTracks.size;
|
|
262
|
+
this.numberOfOutboundRtpStreams += observedPeerConnection.observedOutboundRtps.size;
|
|
263
|
+
this.numberOfOutboundTracks += observedPeerConnection.observedOutboundTracks.size;
|
|
264
|
+
this.numberOfInboundRtpStreams += observedPeerConnection.observedInboundRtps.size;
|
|
644
265
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
this.serviceId,
|
|
648
|
-
this.mediaUnitId,
|
|
649
|
-
this.roomId,
|
|
650
|
-
this.callId,
|
|
651
|
-
this.clientId, {
|
|
652
|
-
type: CallMetaType.CERTIFICATE,
|
|
653
|
-
payload: certificate,
|
|
654
|
-
},
|
|
655
|
-
this.userId
|
|
656
|
-
);
|
|
657
|
-
|
|
658
|
-
this.reports.addCallMetaReport(callMetaReport);
|
|
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);
|
|
671
|
-
|
|
672
|
-
this.reports.addCallMetaReport(callMetaReport);
|
|
673
|
-
if (codec.mimeType && !this.mediaCodecs.find((c) => c.mimeType === codec.mimeType)) {
|
|
674
|
-
this.mediaCodecs.push(codec);
|
|
266
|
+
if (observedPeerConnection.usingTURN) {
|
|
267
|
+
this.usingTURN = true;
|
|
675
268
|
}
|
|
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);
|
|
688
|
-
|
|
689
|
-
this.reports.addCallMetaReport(callMetaReport);
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
for (const mediaDevice of sample.mediaDevices ?? []) {
|
|
693
|
-
const callMetaReport = createCallMetaReport(
|
|
694
|
-
this.serviceId,
|
|
695
|
-
this.mediaUnitId,
|
|
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);
|
|
269
|
+
if (observedPeerConnection.usingTCP) {
|
|
270
|
+
this.usingTCP = true;
|
|
706
271
|
}
|
|
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
272
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
273
|
+
if (observedPeerConnection.currentRttInMs) {
|
|
274
|
+
if (this.currentMinRttInMs === undefined || observedPeerConnection.currentRttInMs < this.currentMinRttInMs) {
|
|
275
|
+
this.currentMinRttInMs = observedPeerConnection.currentRttInMs;
|
|
276
|
+
}
|
|
277
|
+
if (this.currentMaxRttInMs === undefined || observedPeerConnection.currentRttInMs > this.currentMaxRttInMs) {
|
|
278
|
+
this.currentMaxRttInMs = observedPeerConnection.currentRttInMs;
|
|
279
|
+
}
|
|
280
|
+
if (observedPeerConnection.currentRttInMs < 50) {
|
|
281
|
+
this.deltaRttLt50Measurements += 1;
|
|
282
|
+
} else if (observedPeerConnection.currentRttInMs < 150) {
|
|
283
|
+
this.deltaRttLt150Measurements += 1;
|
|
284
|
+
} else if (observedPeerConnection.currentRttInMs < 300) {
|
|
285
|
+
this.deltaRttLt300Measurements += 1;
|
|
286
|
+
} else if (300 <= observedPeerConnection.currentRttInMs) {
|
|
287
|
+
this.deltaRttGtOrEq300Measurements += 1;
|
|
288
|
+
}
|
|
726
289
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
} catch (err) {
|
|
730
|
-
logger.error(`Error creating peer connection: ${(err as Error)?.message}`);
|
|
290
|
+
sumOfRtts += observedPeerConnection.currentRttInMs;
|
|
291
|
+
++numberOfRttMeasurements;
|
|
731
292
|
}
|
|
732
|
-
|
|
733
293
|
}
|
|
734
294
|
|
|
735
|
-
for (const
|
|
736
|
-
|
|
737
|
-
|
|
295
|
+
for (const clientEvent of clientEventsPostBuffer) {
|
|
296
|
+
this._processClientEvent(clientEvent);
|
|
297
|
+
}
|
|
738
298
|
|
|
739
|
-
|
|
740
|
-
|
|
299
|
+
// emit new attachments?
|
|
300
|
+
this.attachments = sample.attachments;
|
|
741
301
|
|
|
742
|
-
|
|
743
|
-
|
|
302
|
+
this.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
|
|
303
|
+
this.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
|
|
304
|
+
this.totalDataChannelMessagesReceived += this.deltaDataChannelMessagesReceived;
|
|
305
|
+
this.totalDataChannelMessagesSent += this.deltaDataChannelMessagesSent;
|
|
306
|
+
this.totalInboundPacketsLost += this.deltaInboundPacketsLost;
|
|
307
|
+
this.totalInboundPacketsReceived += this.deltaInboundPacketsReceived;
|
|
308
|
+
this.totalOutboundPacketsSent += this.deltaOutboundPacketsSent;
|
|
309
|
+
this.totalReceivedAudioBytes += this.deltaReceivedAudioBytes;
|
|
310
|
+
this.totalReceivedVideoBytes += this.deltaReceivedVideoBytes;
|
|
311
|
+
this.totalSentAudioBytes += this.deltaSentAudioBytes;
|
|
312
|
+
this.totalSentVideoBytes += this.deltaSentVideoBytes;
|
|
313
|
+
this.totalReceivedBytes += this.deltaTransportReceivedBytes;
|
|
314
|
+
this.totalSentBytes += this.deltaTransportSentBytes;
|
|
315
|
+
this.totalRttLt50Measurements += this.deltaRttLt50Measurements;
|
|
316
|
+
this.totalRttLt150Measurements += this.deltaRttLt150Measurements;
|
|
317
|
+
this.totalRttLt300Measurements += this.deltaRttLt300Measurements;
|
|
318
|
+
this.totalRttGtOrEq300Measurements += this.deltaRttGtOrEq300Measurements;
|
|
319
|
+
this.totalNumberOfIssues += this.deltaNumberOfIssues;
|
|
320
|
+
|
|
321
|
+
this.receivingAudioBitrate = (this.deltaReceivedAudioBytes * 8) / (elapsedInSeconds);
|
|
322
|
+
this.receivingVideoBitrate = (this.totalReceivedVideoBytes * 8) / (elapsedInSeconds);
|
|
323
|
+
this.sendingAudioBitrate = (this.deltaSentAudioBytes * 8) / (elapsedInSeconds);
|
|
324
|
+
this.sendingVideoBitrate = (this.deltaSentVideoBytes * 8) / (elapsedInSeconds);
|
|
325
|
+
this.currentAvgRttInMs = 0 < numberOfRttMeasurements ? sumOfRtts / numberOfRttMeasurements : undefined;
|
|
326
|
+
|
|
327
|
+
this.calculatedScore.value = sample.score;
|
|
328
|
+
this.detectors.update();
|
|
329
|
+
|
|
330
|
+
// emit update
|
|
331
|
+
this.emit('update', {
|
|
332
|
+
sample,
|
|
333
|
+
elapsedTimeInMs: now - this.updated,
|
|
334
|
+
});
|
|
335
|
+
this.updated = now;
|
|
744
336
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
if (
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
337
|
+
// if result changed after update
|
|
338
|
+
if (this.calculatedScore.value) {
|
|
339
|
+
this.totalScoreSum += this.calculatedScore.value;
|
|
340
|
+
++this.numberOfScoreMeasurements;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
private _processClientEvent(event: ClientEvent, postBuffer?: ClientEvent[]) {
|
|
345
|
+
// eslint-disable-next-line no-console
|
|
346
|
+
// console.warn('ClientEvent', event);
|
|
347
|
+
switch (event.type) {
|
|
348
|
+
case ClientEventTypes.CLIENT_JOINED: {
|
|
349
|
+
if (event.timestamp) {
|
|
350
|
+
if (!this.joinedAt) {
|
|
351
|
+
this.joinedAt = event.timestamp;
|
|
352
|
+
this.emit('joined');
|
|
353
|
+
} else if (this.joinedAt < event.timestamp) {
|
|
354
|
+
this.emit('rejoined', event.timestamp);
|
|
355
|
+
} else {
|
|
356
|
+
this.joinedAt = event.timestamp;
|
|
357
|
+
logger.warn(`Client ${this.clientId} joinedAt timestamp was updated to ${event.timestamp}. the joined event will not be emitted.`);
|
|
765
358
|
}
|
|
766
359
|
}
|
|
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;
|
|
360
|
+
break;
|
|
777
361
|
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
try {
|
|
786
|
-
const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? this._createPeerConnection(track.peerConnectionId);
|
|
787
|
-
|
|
788
|
-
if (!peerConnection) continue;
|
|
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);
|
|
362
|
+
case ClientEventTypes.CLIENT_LEFT: {
|
|
363
|
+
if (event.timestamp) {
|
|
364
|
+
if (!this.leftAt) {
|
|
365
|
+
this.leftAt = event.timestamp;
|
|
366
|
+
this.emit('left');
|
|
367
|
+
} else {
|
|
368
|
+
logger.warn(`Client ${this.clientId} leftAt timestamp was already set`);
|
|
808
369
|
}
|
|
809
370
|
}
|
|
810
|
-
|
|
811
|
-
logger.error(`Error creating inbound video track: ${(err as Error)?.message}`);
|
|
371
|
+
break;
|
|
812
372
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
373
|
+
case ClientEventTypes.PEER_CONNECTION_OPENED: {
|
|
374
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
375
|
+
|
|
376
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string') {
|
|
377
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
378
|
+
|
|
379
|
+
if (observedPeerConnection) {
|
|
380
|
+
observedPeerConnection.openedAt = event.timestamp;
|
|
381
|
+
} else if (postBuffer) {
|
|
382
|
+
postBuffer.push(event);
|
|
383
|
+
} else {
|
|
384
|
+
logger.warn('Received PEER_CONNECTION_OPENED event without a corresponding observedPeerConnection', event);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
}
|
|
388
|
+
break;
|
|
820
389
|
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
if (outboundAudioTrack.sfuStreamId && !this.call.sfuStreamIdToOutboundAudioTrack.has(outboundAudioTrack.sfuStreamId)) {
|
|
835
|
-
this.call.sfuStreamIdToOutboundAudioTrack.set(outboundAudioTrack.sfuStreamId, outboundAudioTrack);
|
|
390
|
+
case ClientEventTypes.PEER_CONNECTION_CLOSED: {
|
|
391
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
392
|
+
|
|
393
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string') {
|
|
394
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
395
|
+
|
|
396
|
+
if (observedPeerConnection) {
|
|
397
|
+
observedPeerConnection.closedAt = event.timestamp;
|
|
398
|
+
} else if (postBuffer) {
|
|
399
|
+
postBuffer.push(event);
|
|
400
|
+
} else {
|
|
401
|
+
logger.warn('Received PEER_CONNECTION_CLOSED event without a corresponding observedPeerConnection', event);
|
|
402
|
+
}
|
|
836
403
|
}
|
|
837
|
-
|
|
838
|
-
} catch (err) {
|
|
839
|
-
logger.error(`Error creating outbound audio track: ${(err as Error)?.message}`);
|
|
404
|
+
break;
|
|
840
405
|
}
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
406
|
+
case ClientEventTypes.MEDIA_TRACK_ADDED: {
|
|
407
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
408
|
+
|
|
409
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
|
|
410
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
411
|
+
const observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
|
|
412
|
+
|
|
413
|
+
if (observedTrack) {
|
|
414
|
+
observedTrack.addedAt = event.timestamp;
|
|
415
|
+
} else if (postBuffer) {
|
|
416
|
+
postBuffer.push(event);
|
|
417
|
+
} else {
|
|
418
|
+
logger.warn('Received MEDIA_TRACK_ADDED event without a corresponding observedPeerConnection or observedTrack', event);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
break;
|
|
849
422
|
}
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
this.call.sfuStreamIdToOutboundVideoTrack.set(outboundVideoTrack.sfuStreamId, outboundVideoTrack);
|
|
423
|
+
case ClientEventTypes.MEDIA_TRACK_REMOVED: {
|
|
424
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
425
|
+
|
|
426
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
|
|
427
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
428
|
+
const observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
|
|
429
|
+
|
|
430
|
+
if (observedTrack) {
|
|
431
|
+
observedTrack.removedAt = event.timestamp;
|
|
432
|
+
} else if (postBuffer) {
|
|
433
|
+
postBuffer.push(event);
|
|
434
|
+
} else {
|
|
435
|
+
logger.warn('Received MEDIA_TRACK_REMOVED event without a corresponding observedPeerConnection or observedTrack', event);
|
|
436
|
+
}
|
|
865
437
|
}
|
|
866
|
-
|
|
867
|
-
} catch (err) {
|
|
868
|
-
logger.error(`Error creating outbound video track: ${(err as Error)?.message}`);
|
|
438
|
+
break;
|
|
869
439
|
}
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
440
|
+
case ClientEventTypes.DATA_CHANNEL_OPEN: {
|
|
441
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
442
|
+
|
|
443
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.dataChannelId && typeof payload.dataChannelId === 'string') {
|
|
444
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
445
|
+
const observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);
|
|
446
|
+
|
|
447
|
+
if (observedDataChannel) {
|
|
448
|
+
observedDataChannel.addedAt = event.timestamp;
|
|
449
|
+
} else if (postBuffer) {
|
|
450
|
+
postBuffer.push(event);
|
|
451
|
+
} else {
|
|
452
|
+
logger.warn('Received DATA_CHANNEL_OPENED event without a corresponding observedPeerConnection or observedDataChannel', event);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
break;
|
|
876
456
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
457
|
+
case ClientEventTypes.DATA_CHANNEL_CLOSED: {
|
|
458
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
459
|
+
|
|
460
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.dataChannelId && typeof payload.dataChannelId === 'string') {
|
|
461
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
462
|
+
const observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);
|
|
463
|
+
|
|
464
|
+
if (observedDataChannel) {
|
|
465
|
+
observedDataChannel.removedAt = event.timestamp;
|
|
466
|
+
} else if (postBuffer) {
|
|
467
|
+
postBuffer.push(event);
|
|
468
|
+
} else {
|
|
469
|
+
logger.warn('Received DATA_CHANNEL_CLOSE event without a corresponding observedPeerConnection or observedDataChannel', event);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
break;
|
|
882
473
|
}
|
|
883
|
-
|
|
884
|
-
peerConnection.ICE.addLocalCandidate(iceLocalCandidate, sample.timestamp);
|
|
885
474
|
}
|
|
886
|
-
|
|
887
|
-
|
|
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);
|
|
475
|
+
this.emit('clientEvent', event);
|
|
476
|
+
}
|
|
893
477
|
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
478
|
+
public injectMetaData(metaData: ClientMetaData) {
|
|
479
|
+
if (this.closed) return;
|
|
480
|
+
|
|
481
|
+
if (!this._injections.clientMetaItems) this._injections.clientMetaItems = [];
|
|
898
482
|
|
|
899
|
-
|
|
900
|
-
|
|
483
|
+
this._injections.clientMetaItems.push(metaData);
|
|
484
|
+
}
|
|
901
485
|
|
|
902
|
-
|
|
903
|
-
|
|
486
|
+
public injectEvent(event: ClientEvent) {
|
|
487
|
+
if (this.closed) return;
|
|
904
488
|
|
|
905
|
-
|
|
906
|
-
logger.debug(`Peer connection ${candidatePair.peerConnectionId} not found for ice candidate pair ${candidatePair.localCandidateId}, ${candidatePair.remoteCandidateId}`);
|
|
489
|
+
if (!this._injections.clientEvents) this._injections.clientEvents = [];
|
|
907
490
|
|
|
908
|
-
|
|
909
|
-
|
|
491
|
+
this._injections.clientEvents.push(event);
|
|
492
|
+
}
|
|
910
493
|
|
|
911
|
-
|
|
912
|
-
|
|
494
|
+
public injectIssue(issue: ClientIssue) {
|
|
495
|
+
if (this.closed) return;
|
|
913
496
|
|
|
914
|
-
|
|
915
|
-
if (!dataChannel.peerConnectionId || !dataChannel.dataChannelIdentifier) {
|
|
916
|
-
logger.warn(`DataChannel without peerConnectionId or dataChannelIdentifier: ${JSON.stringify(dataChannel)}`);
|
|
497
|
+
if (!this._injections.clientIssues) this._injections.clientIssues = [];
|
|
917
498
|
|
|
918
|
-
|
|
919
|
-
|
|
499
|
+
this._injections.clientIssues.push(issue);
|
|
500
|
+
}
|
|
920
501
|
|
|
921
|
-
|
|
922
|
-
|
|
502
|
+
public injectExtensionStat(stat: ExtensionStat) {
|
|
503
|
+
if (this.closed) return;
|
|
923
504
|
|
|
924
|
-
|
|
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
|
-
}
|
|
505
|
+
if (!this._injections.extensionStats) this._injections.extensionStats = [];
|
|
933
506
|
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
const newPendingTimestamps: PendingPeerConnectionTimestamp[] = [];
|
|
507
|
+
this._injections.extensionStats.push(stat);
|
|
508
|
+
}
|
|
937
509
|
|
|
938
|
-
|
|
939
|
-
|
|
510
|
+
public injectAttachment(key: string, value: unknown) {
|
|
511
|
+
if (this.closed) return;
|
|
940
512
|
|
|
941
|
-
|
|
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
|
-
}
|
|
513
|
+
if (!this._injections.attachments) this._injections.attachments = {};
|
|
948
514
|
|
|
949
|
-
|
|
950
|
-
}
|
|
515
|
+
this._injections.attachments[key] = value;
|
|
951
516
|
|
|
952
|
-
|
|
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
|
-
}
|
|
517
|
+
}
|
|
989
518
|
|
|
990
|
-
|
|
519
|
+
public addMetadata(metadata: ClientMetaData) {
|
|
520
|
+
if (this.closed) return;
|
|
521
|
+
|
|
522
|
+
switch (metadata.type) {
|
|
523
|
+
case ClientMetaTypes.BROWSER: {
|
|
524
|
+
this.browser = parseJsonAs(metadata.payload);
|
|
525
|
+
break;
|
|
991
526
|
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
continue;
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
track.visited = false;
|
|
527
|
+
case ClientMetaTypes.ENGINE: {
|
|
528
|
+
this.engine = parseJsonAs(metadata.payload);
|
|
529
|
+
break;
|
|
1000
530
|
}
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
continue;
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
track.visited = false;
|
|
531
|
+
case ClientMetaTypes.PLATFORM: {
|
|
532
|
+
this.platform = parseJsonAs(metadata.payload);
|
|
533
|
+
break;
|
|
1009
534
|
}
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
continue;
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
dataChannel.visited = false;
|
|
535
|
+
case ClientMetaTypes.OPERATION_SYSTEM: {
|
|
536
|
+
this.operationSystem = parseJsonAs(metadata.payload);
|
|
537
|
+
break;
|
|
1018
538
|
}
|
|
1019
|
-
|
|
1020
|
-
peerConnection.visited = false;
|
|
1021
539
|
}
|
|
1022
540
|
|
|
1023
|
-
|
|
1024
|
-
|
|
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;
|
|
541
|
+
this.call.observer.emit('client-metadata', this, metadata);
|
|
542
|
+
}
|
|
1065
543
|
|
|
1066
|
-
|
|
1067
|
-
|
|
544
|
+
public addIssue(issue: ClientIssue) {
|
|
545
|
+
if (this.closed) return;
|
|
1068
546
|
|
|
1069
|
-
|
|
547
|
+
this.emit('issue', issue);
|
|
548
|
+
this.call.observer.emit('client-issue', this, issue);
|
|
549
|
+
}
|
|
1070
550
|
|
|
1071
|
-
|
|
551
|
+
public addExtensionStats(stats: ExtensionStat) {
|
|
552
|
+
this.call.observer.emit('client-extension-stats', this, stats);
|
|
553
|
+
this.emit('extensionStats', stats);
|
|
554
|
+
}
|
|
1072
555
|
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
if (maxPcScore === undefined || peerConnection.score.score > maxPcScore) maxPcScore = peerConnection.score.score;
|
|
556
|
+
private _updatePeerConnection(sample: PeerConnectionSample): ObservedPeerConnection | undefined {
|
|
557
|
+
let observedPeerConnection = this.observedPeerConnections.get(sample.peerConnectionId);
|
|
1076
558
|
|
|
1077
|
-
|
|
559
|
+
if (!observedPeerConnection) {
|
|
560
|
+
if (!sample.peerConnectionId) {
|
|
561
|
+
return (logger.warn(
|
|
562
|
+
`ObservedClient received an invalid PeerConnectionSample (missing peerConnectionId field). ClientId: ${this.clientId}, CallId: ${this.call.callId}`,
|
|
563
|
+
sample
|
|
564
|
+
), void 0);
|
|
1078
565
|
}
|
|
1079
|
-
}
|
|
1080
566
|
|
|
1081
|
-
|
|
1082
|
-
score: minPcScore ?? -1,
|
|
1083
|
-
remarks: [ {
|
|
1084
|
-
severity: 'none',
|
|
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);
|
|
567
|
+
observedPeerConnection = new ObservedPeerConnection(sample.peerConnectionId, this);
|
|
1094
568
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
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);
|
|
569
|
+
observedPeerConnection.once('close', () => {
|
|
570
|
+
this.observedPeerConnections.delete(sample.peerConnectionId);
|
|
571
|
+
});
|
|
572
|
+
this.observedPeerConnections.set(sample.peerConnectionId, observedPeerConnection);
|
|
573
|
+
|
|
574
|
+
this.emit('newpeerconnection', observedPeerConnection);
|
|
575
|
+
}
|
|
1111
576
|
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
// to make sure when sample is emitted it can be associated to this client
|
|
1115
|
-
sample.clientId = this.clientId;
|
|
577
|
+
observedPeerConnection.accept(sample);
|
|
1116
578
|
|
|
1117
|
-
|
|
1118
|
-
this.lastStatsTimestamp = sample.timestamp;
|
|
1119
|
-
this.emit('update', {
|
|
1120
|
-
sample,
|
|
1121
|
-
elapsedTimeInMs,
|
|
1122
|
-
});
|
|
579
|
+
return observedPeerConnection;
|
|
1123
580
|
}
|
|
1124
581
|
|
|
1125
|
-
private
|
|
1126
|
-
this.
|
|
1127
|
-
|
|
1128
|
-
if (issue.peerConnectionId) {
|
|
1129
|
-
const peerConnection = this._peerConnections.get(issue.peerConnectionId);
|
|
1130
|
-
|
|
1131
|
-
if (peerConnection) {
|
|
1132
|
-
|
|
1133
|
-
if (issue.trackId) {
|
|
1134
|
-
const track = peerConnection.inboundAudioTracks.get(issue.trackId) ?? peerConnection.inboundVideoTracks.get(issue.trackId);
|
|
582
|
+
private _mergeInjections(sample: ClientSample): ClientSample {
|
|
583
|
+
if (this.closed) return sample;
|
|
1135
584
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
585
|
+
if (this._injections.clientEvents) {
|
|
586
|
+
if (!sample.clientEvents) sample.clientEvents = [];
|
|
587
|
+
sample.clientEvents.push(...this._injections.clientEvents);
|
|
588
|
+
|
|
589
|
+
this._injections.clientEvents = undefined;
|
|
1141
590
|
}
|
|
1142
591
|
|
|
1143
|
-
this.
|
|
1144
|
-
|
|
592
|
+
if (this._injections.clientIssues) {
|
|
593
|
+
if (!sample.clientIssues) sample.clientIssues = [];
|
|
594
|
+
sample.clientIssues.push(...this._injections.clientIssues);
|
|
595
|
+
|
|
596
|
+
this._injections.clientIssues = undefined;
|
|
597
|
+
}
|
|
1145
598
|
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
const onNewSelectedCandidatePair = ({ localCandidate, remoteCandidate }: { localCandidate: IceLocalCandidate, remoteCandidate: IceRemoteCandidate }) => {
|
|
1153
|
-
this.emit('selectedcandidatepair', {
|
|
1154
|
-
peerConnection: result,
|
|
1155
|
-
localCandidate,
|
|
1156
|
-
remoteCandidate,
|
|
1157
|
-
});
|
|
1158
|
-
};
|
|
599
|
+
if (this._injections.extensionStats) {
|
|
600
|
+
if (!sample.extensionStats) sample.extensionStats = [];
|
|
601
|
+
sample.extensionStats.push(...this._injections.extensionStats);
|
|
602
|
+
|
|
603
|
+
this._injections.extensionStats = undefined;
|
|
604
|
+
}
|
|
1159
605
|
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
this.
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
606
|
+
if (this._injections.attachments) {
|
|
607
|
+
if (!sample.attachments) sample.attachments = {};
|
|
608
|
+
Object.assign(sample.attachments, this._injections.attachments);
|
|
609
|
+
|
|
610
|
+
this._injections.attachments = undefined;
|
|
611
|
+
}
|
|
1166
612
|
|
|
1167
|
-
this.
|
|
613
|
+
if (this._injections.clientMetaItems) {
|
|
614
|
+
if (!sample.clientMetaItems) sample.clientMetaItems = [];
|
|
615
|
+
sample.clientMetaItems.push(...this._injections.clientMetaItems);
|
|
616
|
+
|
|
617
|
+
this._injections.clientMetaItems = undefined;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
return sample;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// public resetSummaryMetrics() {
|
|
624
|
+
// this.totalDataChannelBytesReceived = 0;
|
|
625
|
+
// this.totalDataChannelBytesSent = 0;
|
|
626
|
+
// this.totalDataChannelMessagesReceived = 0;
|
|
627
|
+
// this.totalDataChannelMessagesSent = 0;
|
|
628
|
+
// this.totalInboundPacketsLost = 0;
|
|
629
|
+
// this.totalInboundPacketsReceived = 0;
|
|
630
|
+
// this.totalOutboundPacketsSent = 0;
|
|
631
|
+
// this.totalReceivedAudioBytes = 0;
|
|
632
|
+
// this.totalReceivedVideoBytes = 0;
|
|
633
|
+
// this.totalSentAudioBytes = 0;
|
|
634
|
+
// this.totalSentVideoBytes = 0;
|
|
635
|
+
// this.totalSentBytes = 0;
|
|
636
|
+
// this.totalReceivedBytes = 0;
|
|
637
|
+
|
|
638
|
+
// this.totalNumberOfIssues = 0;
|
|
639
|
+
|
|
640
|
+
// this.totalScoreSum = 0;
|
|
641
|
+
// this.numberOfScoreMeasurements = 0;
|
|
642
|
+
// }
|
|
643
|
+
|
|
644
|
+
// public createSummary(): ObservedClientSummary {
|
|
645
|
+
// return {
|
|
646
|
+
// totalRttLt50Measurements: this.totalRttLt50Measurements,
|
|
647
|
+
// totalRttLt150Measurements: this.totalRttLt150Measurements,
|
|
648
|
+
// totalRttLt300Measurements: this.totalRttLt300Measurements,
|
|
649
|
+
// totalRttGtOrEq300Measurements: this.totalRttGtOrEq300Measurements,
|
|
650
|
+
// totalDataChannelBytesReceived: this.totalDataChannelBytesReceived,
|
|
651
|
+
// totalDataChannelBytesSent: this.totalDataChannelBytesSent,
|
|
652
|
+
// totalDataChannelMessagesReceived: this.totalDataChannelMessagesReceived,
|
|
653
|
+
// totalDataChannelMessagesSent: this.totalDataChannelMessagesSent,
|
|
654
|
+
// totalInboundPacketsLost: this.totalInboundPacketsLost,
|
|
655
|
+
// totalInboundPacketsReceived: this.totalInboundPacketsReceived,
|
|
656
|
+
// totalOutboundPacketsSent: this.totalOutboundPacketsSent,
|
|
657
|
+
// totalReceivedAudioBytes: this.totalReceivedAudioBytes,
|
|
658
|
+
// totalReceivedVideoBytes: this.totalReceivedVideoBytes,
|
|
659
|
+
// totalSentAudioBytes: this.totalSentAudioBytes,
|
|
660
|
+
// totalSentVideoBytes: this.totalSentVideoBytes,
|
|
661
|
+
// totalSentBytes: this.totalSentBytes,
|
|
662
|
+
// totalReceivedBytes: this.totalReceivedBytes,
|
|
663
|
+
|
|
664
|
+
// numberOfIssues: this.totalNumberOfIssues,
|
|
1168
665
|
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
}
|
|
666
|
+
// totalScoreSum: this.totalScoreSum,
|
|
667
|
+
// numberOfScoreMeasurements: this.numberOfScoreMeasurements,
|
|
668
|
+
// };
|
|
669
|
+
// }
|
|
670
|
+
}
|