@observertc/observer-js 0.42.8 → 1.0.0-beta.1
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 +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 +131 -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 -24
- 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 +625 -1006
- 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 +86 -0
- package/src/ObservedTurnServer.ts +72 -0
- package/src/Observer.ts +182 -298
- 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/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,1045 +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
|
-
|
|
180
|
-
public set left(value: number | undefined) {
|
|
181
|
-
this._left = value;
|
|
182
|
-
|
|
183
|
-
if (this._left) {
|
|
184
|
-
this.emit('left');
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
142
|
|
|
188
|
-
|
|
189
|
-
|
|
143
|
+
this.clientId = settings.clientId;
|
|
144
|
+
this.appData = settings.appData ?? {} as AppData;
|
|
190
145
|
|
|
191
|
-
|
|
146
|
+
this.detectors = new Detectors();
|
|
192
147
|
}
|
|
193
|
-
|
|
194
|
-
public get
|
|
195
|
-
return this.
|
|
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;
|
|
148
|
+
|
|
149
|
+
public get numberOfPeerConnections() {
|
|
150
|
+
return this.observedPeerConnections.size;
|
|
245
151
|
}
|
|
246
152
|
|
|
247
|
-
public get
|
|
248
|
-
return this.
|
|
153
|
+
public get score() {
|
|
154
|
+
return this.calculatedScore.value;
|
|
249
155
|
}
|
|
250
156
|
|
|
251
|
-
public
|
|
252
|
-
|
|
253
|
-
|
|
157
|
+
public close() {
|
|
158
|
+
if (this.closed) return;
|
|
159
|
+
this.closed = true;
|
|
254
160
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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));
|
|
258
165
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
166
|
+
Array.from(this.observedPeerConnections.values()).forEach((peerConnection) => peerConnection.close());
|
|
167
|
+
if (!this.leftAt) {
|
|
168
|
+
this.leftAt = this.lastSampleTimestamp;
|
|
262
169
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
170
|
+
if (this.leftAt) {
|
|
171
|
+
this.emit('left');
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
this.closedAt = Date.now();
|
|
266
175
|
|
|
267
|
-
|
|
268
|
-
return this._closed;
|
|
176
|
+
this.emit('close');
|
|
269
177
|
}
|
|
270
178
|
|
|
271
|
-
public
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
public close() {
|
|
276
|
-
if (this._closed) return;
|
|
277
|
-
this._closed = true;
|
|
179
|
+
public accept(sample: ClientSample): void {
|
|
180
|
+
if (this.closed) throw new Error(`Client ${this.clientId} is closed`);
|
|
278
181
|
|
|
279
|
-
|
|
182
|
+
const now = Date.now();
|
|
183
|
+
const elapsedInMs = now - this.updated;
|
|
184
|
+
const elapsedInSeconds = elapsedInMs / 1000;
|
|
185
|
+
let sumOfRtts = 0;
|
|
186
|
+
let numberOfRttMeasurements = 0;
|
|
187
|
+
|
|
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;
|
|
280
220
|
|
|
281
|
-
this.
|
|
282
|
-
}
|
|
221
|
+
this._mergeInjections(sample);
|
|
283
222
|
|
|
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
|
-
}
|
|
223
|
+
const clientEventsPostBuffer: ClientEvent[] = [];
|
|
303
224
|
|
|
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
|
-
}
|
|
225
|
+
for (const clientEvent of sample.clientEvents ?? []) {
|
|
226
|
+
this._processClientEvent(clientEvent, clientEventsPostBuffer);
|
|
318
227
|
|
|
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}`);
|
|
228
|
+
this.call.observer.emit('client-event', this, clientEvent);
|
|
340
229
|
}
|
|
341
230
|
|
|
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})`);
|
|
231
|
+
for (const metaData of sample.clientMetaItems ?? []) {
|
|
232
|
+
this.addMetadata(metaData);
|
|
349
233
|
}
|
|
350
|
-
const now = Date.now();
|
|
351
234
|
|
|
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
|
-
}
|
|
235
|
+
for (const issue of sample.clientIssues ?? []) {
|
|
236
|
+
this.addIssue(issue);
|
|
361
237
|
|
|
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));
|
|
238
|
+
++this.deltaNumberOfIssues;
|
|
373
239
|
}
|
|
374
240
|
|
|
375
|
-
|
|
376
|
-
this.
|
|
241
|
+
for (const extensionStat of sample.extensionStats ?? []) {
|
|
242
|
+
this.addExtensionStats(extensionStat);
|
|
377
243
|
}
|
|
378
244
|
|
|
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
|
-
}
|
|
245
|
+
for (const pcSample of sample.peerConnections ?? []) {
|
|
246
|
+
const observedPeerConnection = this._updatePeerConnection(pcSample);
|
|
403
247
|
|
|
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
|
-
}
|
|
248
|
+
if (!observedPeerConnection) continue;
|
|
427
249
|
|
|
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
|
-
}
|
|
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;
|
|
263
|
+
|
|
264
|
+
this.availableIncomingBitrate += observedPeerConnection.availableIncomingBitrate;
|
|
265
|
+
this.availableOutgoingBitrate += observedPeerConnection.availableOutgoingBitrate;
|
|
452
266
|
|
|
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
|
-
}
|
|
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;
|
|
476
272
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
this.
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
}
|
|
488
|
-
this.
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
273
|
+
if (observedPeerConnection.usingTURN) {
|
|
274
|
+
this.usingTURN = true;
|
|
275
|
+
}
|
|
276
|
+
if (observedPeerConnection.usingTCP) {
|
|
277
|
+
this.usingTCP = true;
|
|
278
|
+
}
|
|
279
|
+
|
|
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
|
+
}
|
|
496
296
|
|
|
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);
|
|
297
|
+
sumOfRtts += observedPeerConnection.currentRttInMs;
|
|
298
|
+
++numberOfRttMeasurements;
|
|
299
|
+
}
|
|
514
300
|
}
|
|
515
301
|
|
|
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
|
-
});
|
|
302
|
+
for (const clientEvent of clientEventsPostBuffer) {
|
|
303
|
+
this._processClientEvent(clientEvent);
|
|
528
304
|
}
|
|
529
305
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
case CallEventType.CLIENT_JOINED: {
|
|
533
|
-
const lastJoined = this.joined;
|
|
306
|
+
// emit new attachments?
|
|
307
|
+
this.attachments = sample.attachments;
|
|
534
308
|
|
|
535
|
-
|
|
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;
|
|
536
344
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
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.`);
|
|
540
366
|
}
|
|
541
|
-
// in case we have a left event before the joined event
|
|
542
|
-
if (this.left && this.joined && this.left < this.joined) {
|
|
543
|
-
this.left = undefined;
|
|
544
|
-
}
|
|
545
|
-
break;
|
|
546
|
-
}
|
|
547
|
-
case CallEventType.CLIENT_LEFT: {
|
|
548
|
-
this.left = timestamp;
|
|
549
|
-
break;
|
|
550
367
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
368
|
+
logger.debug('Client %s joined at %o', this.clientId, event);
|
|
369
|
+
break;
|
|
370
|
+
}
|
|
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
|
+
}
|
|
379
|
+
|
|
558
380
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
381
|
+
logger.debug('Client %s left at %o', this.clientId, event);
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
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
|
+
|
|
566
398
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
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);
|
|
413
|
+
}
|
|
575
414
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
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
|
+
}
|
|
584
431
|
}
|
|
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}`);
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
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);
|
|
601
447
|
}
|
|
602
|
-
break;
|
|
603
448
|
}
|
|
449
|
+
break;
|
|
604
450
|
}
|
|
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);
|
|
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;
|
|
675
467
|
}
|
|
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);
|
|
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
|
+
}
|
|
482
|
+
}
|
|
483
|
+
break;
|
|
706
484
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
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
|
+
}
|
|
726
507
|
|
|
727
|
-
|
|
728
|
-
peerConnection.update(transport, sample.timestamp);
|
|
729
|
-
} catch (err) {
|
|
730
|
-
logger.error(`Error creating peer connection: ${(err as Error)?.message}`);
|
|
508
|
+
break;
|
|
731
509
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
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;
|
|
740
533
|
}
|
|
534
|
+
case ClientEventTypes.ICE_CONNECTION_STATE_CHANGED: {
|
|
535
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
741
536
|
|
|
742
|
-
|
|
743
|
-
|
|
537
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.iceConnectionState && typeof payload.iceConnectionState === 'string') {
|
|
538
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
744
539
|
|
|
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 ?? '');
|
|
540
|
+
if (observedPeerConnection) {
|
|
541
|
+
observedPeerConnection.iceConnectionState = payload.iceConnectionState;
|
|
542
|
+
observedPeerConnection.emit('iceconnectionstatechange', {
|
|
543
|
+
state: payload.iceConnectionState,
|
|
763
544
|
});
|
|
764
|
-
|
|
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);
|
|
765
549
|
}
|
|
766
550
|
}
|
|
767
|
-
|
|
768
|
-
logger.error(`Error creating inbound audio track: ${(err as Error)?.message}`);
|
|
551
|
+
break;
|
|
769
552
|
}
|
|
770
|
-
|
|
553
|
+
case ClientEventTypes.ICE_GATHERING_STATE_CHANGED: {
|
|
554
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
771
555
|
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
logger.warn(`InboundVideoTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
|
|
556
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.iceGatheringState && typeof payload.iceGatheringState === 'string') {
|
|
557
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
775
558
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
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;
|
|
783
571
|
}
|
|
572
|
+
case ClientEventTypes.PEER_CONNECTION_STATE_CHANGED: {
|
|
573
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
784
574
|
|
|
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);
|
|
575
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.peerConnectionState && typeof payload.peerConnectionState === 'string') {
|
|
576
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
797
577
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
inboundVideoTrack.remoteOutboundTrack = remoteOutboundTrack;
|
|
803
|
-
|
|
804
|
-
inboundVideoTrack.once('close', () => {
|
|
805
|
-
remoteOutboundTrack?.remoteInboundTracks.delete(inboundVideoTrack.trackId ?? '');
|
|
578
|
+
if (observedPeerConnection) {
|
|
579
|
+
observedPeerConnection.connectionState = payload.peerConnectionState;
|
|
580
|
+
observedPeerConnection.emit('connectionstatechange', {
|
|
581
|
+
state: payload.peerConnectionState,
|
|
806
582
|
});
|
|
807
|
-
|
|
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);
|
|
808
587
|
}
|
|
809
588
|
}
|
|
810
|
-
|
|
811
|
-
logger.error(`Error creating inbound video track: ${(err as Error)?.message}`);
|
|
589
|
+
break;
|
|
812
590
|
}
|
|
813
591
|
}
|
|
592
|
+
|
|
593
|
+
this.emit('clientEvent', event);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
public injectMetaData(metaData: ClientMetaData) {
|
|
597
|
+
if (this.closed) return;
|
|
598
|
+
|
|
599
|
+
if (!this._injections.clientMetaItems) this._injections.clientMetaItems = [];
|
|
814
600
|
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
logger.warn(`OutboundAudioTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
|
|
601
|
+
this._injections.clientMetaItems.push(metaData);
|
|
602
|
+
}
|
|
818
603
|
|
|
819
|
-
|
|
820
|
-
|
|
604
|
+
public injectEvent(event: ClientEvent) {
|
|
605
|
+
if (this.closed) return;
|
|
821
606
|
|
|
822
|
-
|
|
823
|
-
const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? this._createPeerConnection(track.peerConnectionId);
|
|
607
|
+
if (!this._injections.clientEvents) this._injections.clientEvents = [];
|
|
824
608
|
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
const outboundAudioTrack = peerConnection.outboundAudioTracks.get(track.trackId) ?? peerConnection.createOutboundAudioTrack({
|
|
828
|
-
trackId: track.trackId,
|
|
829
|
-
sfuStreamId: track.sfuStreamId,
|
|
830
|
-
});
|
|
609
|
+
this._injections.clientEvents.push(event);
|
|
610
|
+
}
|
|
831
611
|
|
|
832
|
-
|
|
612
|
+
public injectIssue(issue: ClientIssue) {
|
|
613
|
+
if (this.closed) return;
|
|
833
614
|
|
|
834
|
-
|
|
835
|
-
this.call.sfuStreamIdToOutboundAudioTrack.set(outboundAudioTrack.sfuStreamId, outboundAudioTrack);
|
|
836
|
-
}
|
|
615
|
+
if (!this._injections.clientIssues) this._injections.clientIssues = [];
|
|
837
616
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
}
|
|
617
|
+
this._injections.clientIssues.push(issue);
|
|
618
|
+
}
|
|
843
619
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
logger.warn(`OutboundVideoTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
|
|
620
|
+
public injectExtensionStat(stat: ExtensionStat) {
|
|
621
|
+
if (this.closed) return;
|
|
847
622
|
|
|
848
|
-
|
|
849
|
-
}
|
|
623
|
+
if (!this._injections.extensionStats) this._injections.extensionStats = [];
|
|
850
624
|
|
|
851
|
-
|
|
852
|
-
|
|
625
|
+
this._injections.extensionStats.push(stat);
|
|
626
|
+
}
|
|
853
627
|
|
|
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);
|
|
628
|
+
public injectAttachment(key: string, value: unknown) {
|
|
629
|
+
if (this.closed) return;
|
|
862
630
|
|
|
863
|
-
|
|
864
|
-
this.call.sfuStreamIdToOutboundVideoTrack.set(outboundVideoTrack.sfuStreamId, outboundVideoTrack);
|
|
865
|
-
}
|
|
631
|
+
if (!this._injections.attachments) this._injections.attachments = {};
|
|
866
632
|
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
}
|
|
633
|
+
this._injections.attachments[key] = value;
|
|
634
|
+
|
|
635
|
+
}
|
|
871
636
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
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;
|
|
876
644
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
logger.debug(`Peer connection ${iceLocalCandidate.peerConnectionId} not found for ice local candidate ${iceLocalCandidate.id}`);
|
|
881
|
-
continue;
|
|
645
|
+
case ClientMetaTypes.ENGINE: {
|
|
646
|
+
this.engine = parseJsonAs(metadata.payload);
|
|
647
|
+
break;
|
|
882
648
|
}
|
|
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;
|
|
649
|
+
case ClientMetaTypes.PLATFORM: {
|
|
650
|
+
this.platform = parseJsonAs(metadata.payload);
|
|
651
|
+
break;
|
|
891
652
|
}
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
logger.debug(`Peer connection ${iceRemoteCandidate.peerConnectionId} not found for ice remote candidate ${iceRemoteCandidate.id}`);
|
|
896
|
-
continue;
|
|
653
|
+
case ClientMetaTypes.OPERATION_SYSTEM: {
|
|
654
|
+
this.operationSystem = parseJsonAs(metadata.payload);
|
|
655
|
+
break;
|
|
897
656
|
}
|
|
898
|
-
|
|
899
|
-
peerConnection.ICE.addRemoteCandidate(iceRemoteCandidate, sample.timestamp);
|
|
900
657
|
}
|
|
901
658
|
|
|
902
|
-
|
|
903
|
-
|
|
659
|
+
this.call.observer.emit('client-metadata', this, metadata);
|
|
660
|
+
}
|
|
904
661
|
|
|
905
|
-
|
|
906
|
-
|
|
662
|
+
public addIssue(issue: ClientIssue) {
|
|
663
|
+
if (this.closed) return;
|
|
907
664
|
|
|
908
|
-
|
|
909
|
-
|
|
665
|
+
this.emit('issue', issue);
|
|
666
|
+
this.call.observer.emit('client-issue', this, issue);
|
|
667
|
+
}
|
|
910
668
|
|
|
911
|
-
|
|
912
|
-
|
|
669
|
+
public addExtensionStats(stats: ExtensionStat) {
|
|
670
|
+
this.call.observer.emit('client-extension-stats', this, stats);
|
|
671
|
+
this.emit('extensionStats', stats);
|
|
672
|
+
}
|
|
913
673
|
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
logger.warn(`DataChannel without peerConnectionId or dataChannelIdentifier: ${JSON.stringify(dataChannel)}`);
|
|
674
|
+
private _updatePeerConnection(sample: PeerConnectionSample): ObservedPeerConnection | undefined {
|
|
675
|
+
let observedPeerConnection = this.observedPeerConnections.get(sample.peerConnectionId);
|
|
917
676
|
|
|
918
|
-
|
|
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);
|
|
919
683
|
}
|
|
920
684
|
|
|
921
|
-
|
|
922
|
-
const peerConnection = this._peerConnections.get(dataChannel.peerConnectionId) ?? this._createPeerConnection(dataChannel.peerConnectionId);
|
|
685
|
+
observedPeerConnection = new ObservedPeerConnection(sample.peerConnectionId, this);
|
|
923
686
|
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
logger.error(`Error creating data channel: ${(err as Error)?.message}`);
|
|
931
|
-
}
|
|
687
|
+
observedPeerConnection.once('close', () => {
|
|
688
|
+
this.observedPeerConnections.delete(sample.peerConnectionId);
|
|
689
|
+
});
|
|
690
|
+
this.observedPeerConnections.set(sample.peerConnectionId, observedPeerConnection);
|
|
691
|
+
|
|
692
|
+
this.emit('newpeerconnection', observedPeerConnection);
|
|
932
693
|
}
|
|
933
694
|
|
|
934
|
-
|
|
935
|
-
if (0 < this.ωpendingPeerConnectionTimestamps.length) {
|
|
936
|
-
const newPendingTimestamps: PendingPeerConnectionTimestamp[] = [];
|
|
695
|
+
observedPeerConnection.accept(sample);
|
|
937
696
|
|
|
938
|
-
|
|
939
|
-
|
|
697
|
+
return observedPeerConnection;
|
|
698
|
+
}
|
|
940
699
|
|
|
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
|
-
}
|
|
700
|
+
private _mergeInjections(sample: ClientSample): ClientSample {
|
|
701
|
+
if (this.closed) return sample;
|
|
948
702
|
|
|
949
|
-
|
|
703
|
+
if (this._injections.clientEvents) {
|
|
704
|
+
if (!sample.clientEvents) sample.clientEvents = [];
|
|
705
|
+
sample.clientEvents.push(...this._injections.clientEvents);
|
|
706
|
+
|
|
707
|
+
this._injections.clientEvents = undefined;
|
|
950
708
|
}
|
|
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
709
|
|
|
972
|
-
|
|
710
|
+
if (this._injections.clientIssues) {
|
|
711
|
+
if (!sample.clientIssues) sample.clientIssues = [];
|
|
712
|
+
sample.clientIssues.push(...this._injections.clientIssues);
|
|
713
|
+
|
|
714
|
+
this._injections.clientIssues = undefined;
|
|
973
715
|
}
|
|
974
716
|
|
|
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;
|
|
717
|
+
if (this._injections.extensionStats) {
|
|
718
|
+
if (!sample.extensionStats) sample.extensionStats = [];
|
|
719
|
+
sample.extensionStats.push(...this._injections.extensionStats);
|
|
720
|
+
|
|
721
|
+
this._injections.extensionStats = undefined;
|
|
1021
722
|
}
|
|
1022
723
|
|
|
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
|
-
}
|
|
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;
|
|
1077
729
|
}
|
|
1078
730
|
|
|
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;
|
|
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;
|
|
1104
755
|
|
|
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;
|
|
756
|
+
// this.totalNumberOfIssues = 0;
|
|
1111
757
|
|
|
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);
|
|
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,
|
|
1166
783
|
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
}
|
|
784
|
+
// totalScoreSum: this.totalScoreSum,
|
|
785
|
+
// numberOfScoreMeasurements: this.numberOfScoreMeasurements,
|
|
786
|
+
// };
|
|
787
|
+
// }
|
|
788
|
+
}
|