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