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