@observertc/observer-js 1.0.0-beta.2 → 1.0.0-beta.3
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/lib/ObservedCall.d.ts +0 -16
- package/lib/ObservedCall.d.ts.map +1 -1
- package/lib/ObservedCall.js +7 -36
- package/lib/ObservedCallEventMonitor.d.ts +3 -0
- package/lib/ObservedCallEventMonitor.d.ts.map +1 -1
- package/lib/ObservedCallEventMonitor.js +7 -0
- package/lib/ObservedClient.d.ts +3 -18
- package/lib/ObservedClient.d.ts.map +1 -1
- package/lib/ObservedClient.js +105 -41
- package/lib/ObservedInboundTrack.d.ts +2 -0
- package/lib/ObservedInboundTrack.d.ts.map +1 -1
- package/lib/ObservedInboundTrack.js +32 -0
- package/lib/ObservedOutboundTrack.d.ts +2 -0
- package/lib/ObservedOutboundTrack.d.ts.map +1 -1
- package/lib/ObservedOutboundTrack.js +5 -0
- package/lib/ObservedPeerConnection.d.ts +3 -3
- package/lib/ObservedPeerConnection.d.ts.map +1 -1
- package/lib/ObservedPeerConnection.js +15 -0
- package/lib/Observer.d.ts +2 -5
- package/lib/Observer.d.ts.map +1 -1
- package/lib/Observer.js +4 -10
- package/lib/ObserverEventMonitor.d.ts +3 -0
- package/lib/ObserverEventMonitor.d.ts.map +1 -1
- package/lib/ObserverEventMonitor.js +7 -0
- package/lib/Reports.d.ts +85 -0
- package/lib/Reports.d.ts.map +1 -0
- package/lib/Reports.js +2 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ObservedCall.ts +8 -42
- package/src/ObservedCallEventMonitor.ts +10 -0
- package/src/ObservedClient.ts +122 -46
- package/src/ObservedInboundTrack.ts +32 -2
- package/src/ObservedOutboundTrack.ts +8 -0
- package/src/ObservedPeerConnection.ts +19 -3
- package/src/Observer.ts +7 -10
- package/src/ObserverEventMonitor.ts +10 -0
- package/src/Reports.ts +87 -0
- package/src/index.ts +4 -0
package/src/ObservedClient.ts
CHANGED
|
@@ -10,6 +10,9 @@ import { ClientMetaTypes } from './schema/ClientMetaTypes';
|
|
|
10
10
|
import { parseJsonAs } from './common/utils';
|
|
11
11
|
import { CalculatedScore } from './scores/CalculatedScore';
|
|
12
12
|
import { Detectors } from './detectors/Detectors';
|
|
13
|
+
import { ClientReport, TrackReport } from './Reports';
|
|
14
|
+
import { ObservedInboundTrack } from './ObservedInboundTrack';
|
|
15
|
+
import { ObservedOutboundTrack } from './ObservedOutboundTrack';
|
|
13
16
|
|
|
14
17
|
const logger = createLogger('ObservedClient');
|
|
15
18
|
|
|
@@ -33,6 +36,8 @@ export type ObservedClientEvents = {
|
|
|
33
36
|
clientEvent: [ClientEvent];
|
|
34
37
|
|
|
35
38
|
newpeerconnection: [ObservedPeerConnection];
|
|
39
|
+
|
|
40
|
+
trackreport: [TrackReport];
|
|
36
41
|
};
|
|
37
42
|
|
|
38
43
|
export declare interface ObservedClient {
|
|
@@ -77,20 +82,24 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
77
82
|
public availableOutgoingBitrate = 0;
|
|
78
83
|
public availableIncomingBitrate = 0;
|
|
79
84
|
|
|
80
|
-
public totalInboundPacketsLost = 0;
|
|
81
|
-
public totalInboundPacketsReceived = 0;
|
|
82
|
-
public totalOutboundPacketsSent = 0;
|
|
83
|
-
public totalDataChannelBytesSent = 0;
|
|
84
|
-
public totalDataChannelBytesReceived = 0;
|
|
85
|
-
public totalDataChannelMessagesSent = 0;
|
|
86
|
-
public totalDataChannelMessagesReceived = 0;
|
|
87
|
-
public totalReceivedAudioBytes = 0;
|
|
88
|
-
public totalReceivedVideoBytes = 0;
|
|
89
|
-
public totalSentAudioBytes = 0;
|
|
90
|
-
public totalSentVideoBytes = 0;
|
|
91
|
-
public totalSentBytes = 0;
|
|
92
|
-
public totalReceivedBytes = 0;
|
|
93
|
-
|
|
85
|
+
// public totalInboundPacketsLost = 0;
|
|
86
|
+
// public totalInboundPacketsReceived = 0;
|
|
87
|
+
// public totalOutboundPacketsSent = 0;
|
|
88
|
+
// public totalDataChannelBytesSent = 0;
|
|
89
|
+
// public totalDataChannelBytesReceived = 0;
|
|
90
|
+
// public totalDataChannelMessagesSent = 0;
|
|
91
|
+
// public totalDataChannelMessagesReceived = 0;
|
|
92
|
+
// public totalReceivedAudioBytes = 0;
|
|
93
|
+
// public totalReceivedVideoBytes = 0;
|
|
94
|
+
// public totalSentAudioBytes = 0;
|
|
95
|
+
// public totalSentVideoBytes = 0;
|
|
96
|
+
// public totalSentBytes = 0;
|
|
97
|
+
// public totalReceivedBytes = 0;
|
|
98
|
+
// public totalRttLt50Measurements = 0;
|
|
99
|
+
// public totalRttLt150Measurements = 0;
|
|
100
|
+
// public totalRttLt300Measurements = 0;
|
|
101
|
+
// public totalRttGtOrEq300Measurements = 0;
|
|
102
|
+
|
|
94
103
|
public deltaReceivedAudioBytes = 0;
|
|
95
104
|
public deltaReceivedVideoBytes = 0;
|
|
96
105
|
public deltaSentAudioBytes = 0;
|
|
@@ -124,15 +133,13 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
124
133
|
public numberOfOutboundTracks = 0;
|
|
125
134
|
public numberOfDataChannels = 0;
|
|
126
135
|
|
|
127
|
-
public totalRttLt50Measurements = 0;
|
|
128
|
-
public totalRttLt150Measurements = 0;
|
|
129
|
-
public totalRttLt300Measurements = 0;
|
|
130
|
-
public totalRttGtOrEq300Measurements = 0;
|
|
131
136
|
public deltaNumberOfIssues = 0;
|
|
132
137
|
|
|
133
138
|
public totalScoreSum = 0;
|
|
134
139
|
public numberOfScoreMeasurements = 0;
|
|
135
|
-
public totalNumberOfIssues = 0;
|
|
140
|
+
// public totalNumberOfIssues = 0;
|
|
141
|
+
|
|
142
|
+
public readonly report: ClientReport;
|
|
136
143
|
|
|
137
144
|
public readonly mediaDevices: MetaData.MediaDeviceInfo[] = [];
|
|
138
145
|
public issues: ClientIssue[] = [];
|
|
@@ -152,6 +159,44 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
152
159
|
this.settings = {
|
|
153
160
|
closeClientIfIdleForMs: settings.closeClientIfIdleForMs,
|
|
154
161
|
};
|
|
162
|
+
|
|
163
|
+
this.report = {
|
|
164
|
+
callId: this.call.callId,
|
|
165
|
+
clientId: this.clientId,
|
|
166
|
+
rttDistribution: {
|
|
167
|
+
gtOrEq300ms: 0,
|
|
168
|
+
lt50ms: 0,
|
|
169
|
+
lt150ms: 0,
|
|
170
|
+
lt300ms: 0,
|
|
171
|
+
count: 0,
|
|
172
|
+
sum: 0,
|
|
173
|
+
},
|
|
174
|
+
scoreDistribution: {
|
|
175
|
+
'0': 0,
|
|
176
|
+
'1': 0,
|
|
177
|
+
'2': 0,
|
|
178
|
+
'3': 0,
|
|
179
|
+
'4': 0,
|
|
180
|
+
'5': 0,
|
|
181
|
+
count: 0,
|
|
182
|
+
sum: 0,
|
|
183
|
+
},
|
|
184
|
+
issues: {},
|
|
185
|
+
totalAudioBytesReceived: 0,
|
|
186
|
+
totalVideoBytesReceived: 0,
|
|
187
|
+
totalAudioBytesSent: 0,
|
|
188
|
+
totalVideoBytesSent: 0,
|
|
189
|
+
totalDataChannelBytesReceived: 0,
|
|
190
|
+
totalDataChannelBytesSent: 0,
|
|
191
|
+
totalDataChannelMessagesReceived: 0,
|
|
192
|
+
totalDataChannelMessagesSent: 0,
|
|
193
|
+
totalInboundRtpBytesReceived: 0,
|
|
194
|
+
totalInboundRtpPacketsLost: 0,
|
|
195
|
+
totalInboundRtpPacketsReceived: 0,
|
|
196
|
+
totalOutboundRtpBytesSent: 0,
|
|
197
|
+
totalOutboundRtpPacketsSent: 0,
|
|
198
|
+
totalNumberOfIssues: 0,
|
|
199
|
+
};
|
|
155
200
|
}
|
|
156
201
|
|
|
157
202
|
public get numberOfPeerConnections() {
|
|
@@ -299,13 +344,19 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
299
344
|
}
|
|
300
345
|
if (observedPeerConnection.currentRttInMs < 50) {
|
|
301
346
|
this.deltaRttLt50Measurements += 1;
|
|
347
|
+
this.report.rttDistribution.lt50ms += 1;
|
|
302
348
|
} else if (observedPeerConnection.currentRttInMs < 150) {
|
|
303
349
|
this.deltaRttLt150Measurements += 1;
|
|
350
|
+
this.report.rttDistribution.lt150ms += 1;
|
|
304
351
|
} else if (observedPeerConnection.currentRttInMs < 300) {
|
|
305
352
|
this.deltaRttLt300Measurements += 1;
|
|
353
|
+
this.report.rttDistribution.lt300ms += 1;
|
|
306
354
|
} else if (300 <= observedPeerConnection.currentRttInMs) {
|
|
307
355
|
this.deltaRttGtOrEq300Measurements += 1;
|
|
356
|
+
this.report.rttDistribution.gtOrEq300ms += 1;
|
|
308
357
|
}
|
|
358
|
+
this.report.rttDistribution.count += 1;
|
|
359
|
+
this.report.rttDistribution.sum += observedPeerConnection.currentRttInMs;
|
|
309
360
|
|
|
310
361
|
sumOfRtts += observedPeerConnection.currentRttInMs;
|
|
311
362
|
++numberOfRttMeasurements;
|
|
@@ -319,32 +370,37 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
319
370
|
// emit new attachments?
|
|
320
371
|
this.attachments = sample.attachments;
|
|
321
372
|
|
|
322
|
-
this.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
|
|
323
|
-
this.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
|
|
324
|
-
this.totalDataChannelMessagesReceived += this.deltaDataChannelMessagesReceived;
|
|
325
|
-
this.totalDataChannelMessagesSent += this.deltaDataChannelMessagesSent;
|
|
326
|
-
this.
|
|
327
|
-
this.
|
|
328
|
-
this.
|
|
329
|
-
this.
|
|
330
|
-
this.
|
|
331
|
-
this.
|
|
332
|
-
this.
|
|
333
|
-
this.
|
|
334
|
-
this.
|
|
335
|
-
this.
|
|
336
|
-
this.totalRttLt150Measurements += this.deltaRttLt150Measurements;
|
|
337
|
-
this.totalRttLt300Measurements += this.deltaRttLt300Measurements;
|
|
338
|
-
this.totalRttGtOrEq300Measurements += this.deltaRttGtOrEq300Measurements;
|
|
339
|
-
this.totalNumberOfIssues += this.deltaNumberOfIssues;
|
|
373
|
+
this.report.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
|
|
374
|
+
this.report.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
|
|
375
|
+
this.report.totalDataChannelMessagesReceived += this.deltaDataChannelMessagesReceived;
|
|
376
|
+
this.report.totalDataChannelMessagesSent += this.deltaDataChannelMessagesSent;
|
|
377
|
+
this.report.totalInboundRtpPacketsLost += this.deltaInboundPacketsLost;
|
|
378
|
+
this.report.totalInboundRtpPacketsReceived += this.deltaInboundPacketsReceived;
|
|
379
|
+
this.report.totalOutboundRtpPacketsSent += this.deltaOutboundPacketsSent;
|
|
380
|
+
this.report.totalAudioBytesReceived += this.deltaReceivedAudioBytes;
|
|
381
|
+
this.report.totalVideoBytesReceived += this.deltaReceivedVideoBytes;
|
|
382
|
+
this.report.totalAudioBytesSent += this.deltaSentAudioBytes;
|
|
383
|
+
this.report.totalVideoBytesSent += this.deltaSentVideoBytes;
|
|
384
|
+
this.report.totalInboundRtpBytesReceived += this.deltaTransportReceivedBytes;
|
|
385
|
+
this.report.totalOutboundRtpBytesSent += this.deltaTransportSentBytes;
|
|
386
|
+
this.report.totalNumberOfIssues += this.deltaNumberOfIssues;
|
|
340
387
|
|
|
341
388
|
this.receivingAudioBitrate = (this.deltaReceivedAudioBytes * 8) / (elapsedInSeconds);
|
|
342
|
-
this.receivingVideoBitrate = (this.
|
|
389
|
+
this.receivingVideoBitrate = (this.deltaReceivedVideoBytes * 8) / (elapsedInSeconds);
|
|
343
390
|
this.sendingAudioBitrate = (this.deltaSentAudioBytes * 8) / (elapsedInSeconds);
|
|
344
391
|
this.sendingVideoBitrate = (this.deltaSentVideoBytes * 8) / (elapsedInSeconds);
|
|
345
392
|
this.currentAvgRttInMs = 0 < numberOfRttMeasurements ? sumOfRtts / numberOfRttMeasurements : undefined;
|
|
346
393
|
|
|
347
394
|
this.calculatedScore.value = sample.score;
|
|
395
|
+
|
|
396
|
+
if (sample.score !== undefined) {
|
|
397
|
+
const bucket = Math.floor(sample.score).toString() as '0' | '1' | '2' | '3' | '4' | '5';
|
|
398
|
+
|
|
399
|
+
this.report.scoreDistribution[bucket] = (this.report.scoreDistribution[bucket] ?? 0) + 1;
|
|
400
|
+
this.report.scoreDistribution.count += 1;
|
|
401
|
+
this.report.scoreDistribution.sum += sample.score;
|
|
402
|
+
}
|
|
403
|
+
|
|
348
404
|
this.detectors.update();
|
|
349
405
|
|
|
350
406
|
this.lastSampleTimestamp = sample.timestamp;
|
|
@@ -557,7 +613,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
557
613
|
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
558
614
|
|
|
559
615
|
if (observedPeerConnection) {
|
|
560
|
-
observedPeerConnection.iceConnectionState = payload.iceConnectionState;
|
|
616
|
+
observedPeerConnection.iceConnectionState = payload.iceConnectionState as 'new' | 'checking' | 'connected' | 'completed' | 'failed' | 'disconnected' | 'closed';
|
|
561
617
|
observedPeerConnection.emit('iceconnectionstatechange', {
|
|
562
618
|
state: payload.iceConnectionState,
|
|
563
619
|
});
|
|
@@ -576,7 +632,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
576
632
|
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
577
633
|
|
|
578
634
|
if (observedPeerConnection) {
|
|
579
|
-
observedPeerConnection.iceGatheringState = payload.iceGatheringState;
|
|
635
|
+
observedPeerConnection.iceGatheringState = payload.iceGatheringState as 'new' | 'gathering' | 'complete';
|
|
580
636
|
observedPeerConnection.emit('icegatheringstatechange', {
|
|
581
637
|
state: payload.iceGatheringState,
|
|
582
638
|
});
|
|
@@ -595,7 +651,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
595
651
|
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
596
652
|
|
|
597
653
|
if (observedPeerConnection) {
|
|
598
|
-
observedPeerConnection.connectionState = payload.peerConnectionState;
|
|
654
|
+
observedPeerConnection.connectionState = payload.peerConnectionState as 'new' | 'connecting' | 'connected' | 'disconnected' | 'failed' | 'closed';
|
|
599
655
|
observedPeerConnection.emit('connectionstatechange', {
|
|
600
656
|
state: payload.peerConnectionState,
|
|
601
657
|
});
|
|
@@ -681,6 +737,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
681
737
|
public addIssue(issue: ClientIssue) {
|
|
682
738
|
if (this.closed) return;
|
|
683
739
|
|
|
740
|
+
this.report.issues[issue.type] = (this.report.issues[issue.type] ?? 0) + 1;
|
|
741
|
+
|
|
684
742
|
this.emit('issue', issue);
|
|
685
743
|
this.call.observer.emit('client-issue', this, issue);
|
|
686
744
|
}
|
|
@@ -701,14 +759,32 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
701
759
|
), void 0);
|
|
702
760
|
}
|
|
703
761
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
762
|
+
const newObservedPeerConnection = new ObservedPeerConnection(sample.peerConnectionId, this);
|
|
763
|
+
const onInboundTrackRemoved = (track: ObservedInboundTrack) => {
|
|
764
|
+
this.emit('trackreport', {
|
|
765
|
+
direction: 'inbound',
|
|
766
|
+
...track.report,
|
|
767
|
+
});
|
|
768
|
+
};
|
|
769
|
+
const onOutboundTrackRemoved = (track: ObservedOutboundTrack) => {
|
|
770
|
+
this.emit('trackreport', {
|
|
771
|
+
direction: 'outbound',
|
|
772
|
+
...track.report,
|
|
773
|
+
});
|
|
774
|
+
};
|
|
775
|
+
|
|
776
|
+
newObservedPeerConnection.once('close', () => {
|
|
777
|
+
newObservedPeerConnection?.off('removed-inbound-track', onInboundTrackRemoved);
|
|
778
|
+
newObservedPeerConnection?.off('removed-outbound-track', onOutboundTrackRemoved);
|
|
707
779
|
this.observedPeerConnections.delete(sample.peerConnectionId);
|
|
708
780
|
});
|
|
709
|
-
|
|
781
|
+
newObservedPeerConnection.on('removed-inbound-track', onInboundTrackRemoved);
|
|
782
|
+
newObservedPeerConnection.on('removed-outbound-track', onOutboundTrackRemoved);
|
|
783
|
+
this.observedPeerConnections.set(sample.peerConnectionId, newObservedPeerConnection);
|
|
710
784
|
|
|
711
|
-
this.emit('newpeerconnection',
|
|
785
|
+
this.emit('newpeerconnection', newObservedPeerConnection);
|
|
786
|
+
|
|
787
|
+
observedPeerConnection = newObservedPeerConnection;
|
|
712
788
|
}
|
|
713
789
|
|
|
714
790
|
observedPeerConnection.accept(sample);
|
|
@@ -5,6 +5,7 @@ import { Detectors } from './detectors/Detectors';
|
|
|
5
5
|
import { ObservedPeerConnection } from './ObservedPeerConnection';
|
|
6
6
|
import { ObservedInboundRtp } from './ObservedInboundRtp';
|
|
7
7
|
import { ObservedMediaPlayout } from './ObservedMediaPlayout';
|
|
8
|
+
import { InboundTrackReport } from './Reports';
|
|
8
9
|
|
|
9
10
|
export class ObservedInboundTrack implements InboundTrackSample {
|
|
10
11
|
public readonly detectors: Detectors;
|
|
@@ -13,6 +14,7 @@ export class ObservedInboundTrack implements InboundTrackSample {
|
|
|
13
14
|
value: undefined,
|
|
14
15
|
};
|
|
15
16
|
public appData?: Record<string, unknown>;
|
|
17
|
+
public report: InboundTrackReport;
|
|
16
18
|
|
|
17
19
|
private _visited = false;
|
|
18
20
|
|
|
@@ -32,6 +34,21 @@ export class ObservedInboundTrack implements InboundTrackSample {
|
|
|
32
34
|
private readonly _mediaPlayout?: ObservedMediaPlayout,
|
|
33
35
|
) {
|
|
34
36
|
this.detectors = new Detectors();
|
|
37
|
+
|
|
38
|
+
this.report = {
|
|
39
|
+
trackId: this.id,
|
|
40
|
+
kind: this.kind,
|
|
41
|
+
fractionLostDistribution: {
|
|
42
|
+
gtOrEq050: 0,
|
|
43
|
+
lt001: 0,
|
|
44
|
+
lt005: 0,
|
|
45
|
+
lt010: 0,
|
|
46
|
+
lt020: 0,
|
|
47
|
+
lt050: 0,
|
|
48
|
+
count: 0,
|
|
49
|
+
sum: 0,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
35
52
|
}
|
|
36
53
|
|
|
37
54
|
public get score() {
|
|
@@ -68,8 +85,21 @@ export class ObservedInboundTrack implements InboundTrackSample {
|
|
|
68
85
|
this.timestamp = stats.timestamp;
|
|
69
86
|
this.calculatedScore.value = stats.score;
|
|
70
87
|
this.attachments = stats.attachments;
|
|
71
|
-
|
|
88
|
+
|
|
89
|
+
const fl = this._inboundRtp?.fractionLost;
|
|
90
|
+
|
|
91
|
+
if (fl !== undefined) {
|
|
92
|
+
if (fl < 0.01) this.report.fractionLostDistribution.lt001 += 1;
|
|
93
|
+
else if (fl < 0.05) this.report.fractionLostDistribution.lt005 += 1;
|
|
94
|
+
else if (fl < 0.1) this.report.fractionLostDistribution.lt010 += 1;
|
|
95
|
+
else if (fl < 0.2) this.report.fractionLostDistribution.lt020 += 1;
|
|
96
|
+
else if (fl < 0.5) this.report.fractionLostDistribution.lt050 += 1;
|
|
97
|
+
else this.report.fractionLostDistribution.gtOrEq050 += 1;
|
|
98
|
+
|
|
99
|
+
this.report.fractionLostDistribution.count += 1;
|
|
100
|
+
this.report.fractionLostDistribution.sum += fl;
|
|
101
|
+
}
|
|
102
|
+
|
|
72
103
|
this.detectors.update();
|
|
73
104
|
}
|
|
74
|
-
|
|
75
105
|
}
|
|
@@ -5,11 +5,14 @@ import { Detectors } from './detectors/Detectors';
|
|
|
5
5
|
import { ObservedPeerConnection } from './ObservedPeerConnection';
|
|
6
6
|
import { ObservedOutboundRtp } from './ObservedOutboundRtp';
|
|
7
7
|
import { ObservedMediaSource } from './ObservedMediaSource';
|
|
8
|
+
import { OutboundTrackReport } from './Reports';
|
|
8
9
|
|
|
9
10
|
export class ObservedOutboundTrack implements OutboundTrackSample {
|
|
10
11
|
public readonly detectors: Detectors;
|
|
11
12
|
private _visited = false;
|
|
12
13
|
public appData?: Record<string, unknown>;
|
|
14
|
+
public readonly report: OutboundTrackReport;
|
|
15
|
+
|
|
13
16
|
public readonly calculatedScore: CalculatedScore = {
|
|
14
17
|
weight: 1,
|
|
15
18
|
value: undefined,
|
|
@@ -30,6 +33,11 @@ export class ObservedOutboundTrack implements OutboundTrackSample {
|
|
|
30
33
|
private readonly _outboundRtps?: ObservedOutboundRtp[],
|
|
31
34
|
private readonly _mediaSource?: ObservedMediaSource,
|
|
32
35
|
) {
|
|
36
|
+
this.report = {
|
|
37
|
+
trackId: this.id,
|
|
38
|
+
kind: this.kind as 'audio' | 'video',
|
|
39
|
+
};
|
|
40
|
+
|
|
33
41
|
this.detectors = new Detectors();
|
|
34
42
|
}
|
|
35
43
|
|
|
@@ -128,9 +128,9 @@ export class ObservedPeerConnection extends EventEmitter {
|
|
|
128
128
|
public closedAt?: number;
|
|
129
129
|
public updated = Date.now();
|
|
130
130
|
|
|
131
|
-
public connectionState?:
|
|
132
|
-
public iceConnectionState?:
|
|
133
|
-
public iceGatheringState?:
|
|
131
|
+
public connectionState?: 'new' | 'connecting' | 'connected' | 'disconnected' | 'failed' | 'closed';
|
|
132
|
+
public iceConnectionState?: 'new' | 'checking' | 'connected' | 'completed' | 'failed' | 'disconnected' | 'closed';
|
|
133
|
+
public iceGatheringState?: 'new' | 'gathering' | 'complete';
|
|
134
134
|
|
|
135
135
|
public availableIncomingBitrate = 0;
|
|
136
136
|
public availableOutgoingBitrate = 0;
|
|
@@ -286,6 +286,22 @@ export class ObservedPeerConnection extends EventEmitter {
|
|
|
286
286
|
if (this.closed) return;
|
|
287
287
|
this.closed = true;
|
|
288
288
|
|
|
289
|
+
this.observedCertificates.forEach((cert) => this.emit('removed-certificate', cert));
|
|
290
|
+
this.observedCodecs.forEach((codec) => this.emit('removed-codec', codec));
|
|
291
|
+
this.observedDataChannels.forEach((dc) => this.emit('removed-data-channel', dc));
|
|
292
|
+
this.observedIceCandidates.forEach((candidate) => this.emit('removed-ice-candidate', candidate));
|
|
293
|
+
this.observedIceCandidatesPair.forEach((pair) => this.emit('removed-ice-candidate-pair', pair));
|
|
294
|
+
this.observedIceTransports.forEach((transport) => this.emit('removed-ice-transport', transport));
|
|
295
|
+
this.observedInboundRtps.forEach((rtp) => this.emit('removed-inbound-rtp', rtp));
|
|
296
|
+
this.observedInboundTracks.forEach((track) => this.emit('removed-inbound-track', track));
|
|
297
|
+
this.observedMediaPlayouts.forEach((playout) => this.emit('removed-media-playout', playout));
|
|
298
|
+
this.observedMediaSources.forEach((source) => this.emit('removed-media-source', source));
|
|
299
|
+
this.observedOutboundRtps.forEach((rtp) => this.emit('removed-outbound-rtp', rtp));
|
|
300
|
+
this.observedOutboundTracks.forEach((track) => this.emit('removed-outbound-track', track));
|
|
301
|
+
this.observedPeerConnectionTransports.forEach((transport) => this.emit('removed-peer-connection-transport', transport));
|
|
302
|
+
this.observedRemoteInboundRtps.forEach((rtp) => this.emit('removed-remote-inbound-rtp', rtp));
|
|
303
|
+
this.observedRemoteOutboundRtps.forEach((rtp) => this.emit('removed-remote-outbound-rtp', rtp));
|
|
304
|
+
|
|
289
305
|
this.observedCertificates.clear();
|
|
290
306
|
this.observedCodecs.clear();
|
|
291
307
|
this.observedDataChannels.clear();
|
package/src/Observer.ts
CHANGED
|
@@ -31,6 +31,8 @@ export type ObserverConfig<AppData extends Record<string, unknown> = Record<stri
|
|
|
31
31
|
defaultCallUpdatePolicy?: ObservedCallSettings['updatePolicy'],
|
|
32
32
|
defaultCallUpdateIntervalInMs?: number,
|
|
33
33
|
appData?: AppData,
|
|
34
|
+
closeClientIfIdleForMs?: number,
|
|
35
|
+
closeCallIfEmptyForMs?: number,
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
export declare interface Observer {
|
|
@@ -51,11 +53,6 @@ export class Observer<AppData extends Record<string, unknown> = Record<string, u
|
|
|
51
53
|
|
|
52
54
|
public totalAddedCall = 0;
|
|
53
55
|
public totalRemovedCall = 0;
|
|
54
|
-
public totalRttLt50Measurements = 0;
|
|
55
|
-
public totalRttLt150Measurements = 0;
|
|
56
|
-
public totalRttLt300Measurements = 0;
|
|
57
|
-
public totalRttGtOrEq300Measurements = 0;
|
|
58
|
-
public totalClientIssues = 0;
|
|
59
56
|
|
|
60
57
|
public numberOfClientsUsingTurn = 0;
|
|
61
58
|
public numberOfClients = 0;
|
|
@@ -125,6 +122,10 @@ export class Observer<AppData extends Record<string, unknown> = Record<string, u
|
|
|
125
122
|
settings.updatePolicy = this.config.defaultCallUpdatePolicy;
|
|
126
123
|
settings.updateIntervalInMs = this.config.defaultCallUpdateIntervalInMs;
|
|
127
124
|
}
|
|
125
|
+
if (!settings.closeCallIfEmptyForMs) {
|
|
126
|
+
settings.closeCallIfEmptyForMs = this.config.closeCallIfEmptyForMs;
|
|
127
|
+
}
|
|
128
|
+
|
|
128
129
|
const observedCall = new ObservedCall(settings, this);
|
|
129
130
|
const onCallUpdated = () => this._onObservedCallUpdated(observedCall);
|
|
130
131
|
|
|
@@ -211,11 +212,7 @@ export class Observer<AppData extends Record<string, unknown> = Record<string, u
|
|
|
211
212
|
}
|
|
212
213
|
|
|
213
214
|
private _onObservedCallUpdated(call: ObservedCall) {
|
|
214
|
-
|
|
215
|
-
this.totalRttLt150Measurements += call.deltaRttLt150Measurements;
|
|
216
|
-
this.totalRttLt300Measurements += call.deltaRttLt300Measurements;
|
|
217
|
-
this.totalRttGtOrEq300Measurements += call.deltaRttGtOrEq300Measurements;
|
|
218
|
-
this.totalClientIssues += call.deltaNumberOfIssues;
|
|
215
|
+
call;
|
|
219
216
|
}
|
|
220
217
|
|
|
221
218
|
public createEventMonitor<CTX = unknown>(ctx?: CTX): ObserverEventMonitor<CTX> {
|
|
@@ -14,6 +14,7 @@ import { ObservedOutboundRtp } from './ObservedOutboundRtp';
|
|
|
14
14
|
import { ObservedOutboundTrack } from './ObservedOutboundTrack';
|
|
15
15
|
import { ObservedPeerConnection } from './ObservedPeerConnection';
|
|
16
16
|
import { Observer } from './Observer';
|
|
17
|
+
import { TrackReport } from './Reports';
|
|
17
18
|
import { ClientEvent, ClientIssue, ClientMetaData, ClientSample, ExtensionStat } from './schema/ClientSample';
|
|
18
19
|
|
|
19
20
|
export class ObserverEventMonitor<Context> {
|
|
@@ -160,6 +161,8 @@ export class ObserverEventMonitor<Context> {
|
|
|
160
161
|
public onMediaSourceRemoved?: (mediaSource: ObservedMediaSource, ctx: Context) => void;
|
|
161
162
|
public onMediaSourceUpdated?: (mediaSource: ObservedMediaSource, ctx: Context) => void;
|
|
162
163
|
|
|
164
|
+
public onTrackReport?: (report: TrackReport, observedClient: ObservedClient, ctx: Context) => void;
|
|
165
|
+
|
|
163
166
|
private _onCallAdded(call: ObservedCall) {
|
|
164
167
|
const onCallEmpty = () => this.onCallEmpty?.(call, this.context);
|
|
165
168
|
const onCallNotEmpty = () => this.onCallNotEmpty?.(call, this.context);
|
|
@@ -192,6 +195,7 @@ export class ObserverEventMonitor<Context> {
|
|
|
192
195
|
const onUserMediaError = (error: string) => this._onUserMediaError(observedClient, error);
|
|
193
196
|
const onClientUpdated = (...args: ObservedClientEvents['update']) => this.onClientUpdated?.(observedClient, args[0], this.context);
|
|
194
197
|
const onClientEvent = (event: ClientEvent) => this.onClientEvent?.(observedClient, event, this.context);
|
|
198
|
+
const onTrackReport = (report: TrackReport) => this._onTrackReport(report, observedClient);
|
|
195
199
|
|
|
196
200
|
observedClient.once('close', () => {
|
|
197
201
|
observedClient.off('newpeerconnection', this._onPeerConnconnectionAdded);
|
|
@@ -205,6 +209,7 @@ export class ObserverEventMonitor<Context> {
|
|
|
205
209
|
observedClient.off('extensionStats', onClientExtensionStats);
|
|
206
210
|
observedClient.off('update', onClientUpdated);
|
|
207
211
|
observedClient.off('clientEvent', onClientEvent);
|
|
212
|
+
observedClient.off('trackreport', onTrackReport);
|
|
208
213
|
|
|
209
214
|
this.onClientClosed?.(observedClient, this.context);
|
|
210
215
|
});
|
|
@@ -220,6 +225,7 @@ export class ObserverEventMonitor<Context> {
|
|
|
220
225
|
observedClient.on('extensionStats', onClientExtensionStats);
|
|
221
226
|
observedClient.on('update', onClientUpdated);
|
|
222
227
|
observedClient.on('clientEvent', onClientEvent);
|
|
228
|
+
observedClient.on('trackreport', onTrackReport);
|
|
223
229
|
|
|
224
230
|
this.onClientAdded?.(observedClient, this.context);
|
|
225
231
|
}
|
|
@@ -548,4 +554,8 @@ export class ObserverEventMonitor<Context> {
|
|
|
548
554
|
private _onUsingTurn(observedClient: ObservedClient, usingTurn: boolean) {
|
|
549
555
|
this.onClientUsingTurn?.(observedClient, usingTurn, this.context);
|
|
550
556
|
}
|
|
557
|
+
|
|
558
|
+
private _onTrackReport(report: TrackReport, observedClient: ObservedClient) {
|
|
559
|
+
this.onTrackReport?.(report, observedClient, this.context);
|
|
560
|
+
}
|
|
551
561
|
}
|
package/src/Reports.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export type InboundAudioTrackReport = {
|
|
2
|
+
trackId: string,
|
|
3
|
+
fractionLostDistribution: {
|
|
4
|
+
lt001: number;
|
|
5
|
+
lt005: number;
|
|
6
|
+
lt010: number;
|
|
7
|
+
lt020: number;
|
|
8
|
+
lt050: number;
|
|
9
|
+
gtOrEq050: number;
|
|
10
|
+
count: number;
|
|
11
|
+
sum: number;
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type InboundVideoTrackReport = {
|
|
16
|
+
trackId: string,
|
|
17
|
+
fractionLostDistribution: {
|
|
18
|
+
lt001: number;
|
|
19
|
+
lt005: number;
|
|
20
|
+
lt010: number;
|
|
21
|
+
lt020: number;
|
|
22
|
+
lt050: number;
|
|
23
|
+
gtOrEq050: number;
|
|
24
|
+
count: number;
|
|
25
|
+
sum: number;
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type OutboundAudioTrackReport = {
|
|
30
|
+
trackId: string,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type OutboundVideoTrackReport = {
|
|
34
|
+
trackId: string,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type InboundTrackReport = ({ kind: 'audio' } & InboundAudioTrackReport)
|
|
38
|
+
| ({ kind: 'video' } & InboundVideoTrackReport);
|
|
39
|
+
|
|
40
|
+
export type OutboundTrackReport = ({ kind: 'audio' } & OutboundAudioTrackReport)
|
|
41
|
+
| ({ kind: 'video' } & OutboundVideoTrackReport);
|
|
42
|
+
|
|
43
|
+
export type TrackReport = ({ direction: 'inbound' } & InboundTrackReport)
|
|
44
|
+
| ({ direction: 'outbound' } & OutboundTrackReport);
|
|
45
|
+
|
|
46
|
+
export type ClientReport = {
|
|
47
|
+
callId: string;
|
|
48
|
+
clientId: string;
|
|
49
|
+
|
|
50
|
+
totalDataChannelBytesReceived: number;
|
|
51
|
+
totalDataChannelBytesSent: number;
|
|
52
|
+
totalDataChannelMessagesReceived: number;
|
|
53
|
+
totalDataChannelMessagesSent: number;
|
|
54
|
+
totalInboundRtpPacketsReceived: number;
|
|
55
|
+
totalInboundRtpPacketsLost: number;
|
|
56
|
+
totalInboundRtpBytesReceived: number;
|
|
57
|
+
totalOutboundRtpPacketsSent: number;
|
|
58
|
+
totalOutboundRtpBytesSent: number;
|
|
59
|
+
totalAudioBytesReceived: number;
|
|
60
|
+
totalVideoBytesReceived: number;
|
|
61
|
+
totalAudioBytesSent: number;
|
|
62
|
+
totalVideoBytesSent: number;
|
|
63
|
+
totalNumberOfIssues: number;
|
|
64
|
+
|
|
65
|
+
issues: Record<string, number>;
|
|
66
|
+
|
|
67
|
+
rttDistribution: {
|
|
68
|
+
lt50ms: number;
|
|
69
|
+
lt150ms: number;
|
|
70
|
+
lt300ms: number;
|
|
71
|
+
gtOrEq300ms: number;
|
|
72
|
+
count: number;
|
|
73
|
+
sum: number;
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
scoreDistribution: {
|
|
77
|
+
'0': number;
|
|
78
|
+
'1': number;
|
|
79
|
+
'2': number;
|
|
80
|
+
'3': number;
|
|
81
|
+
'4': number;
|
|
82
|
+
'5': number;
|
|
83
|
+
|
|
84
|
+
count: number;
|
|
85
|
+
sum: number;
|
|
86
|
+
}
|
|
87
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -26,3 +26,7 @@ export { ScoreCalculator } from './scores/ScoreCalculator';
|
|
|
26
26
|
export { ObservedClientEventMonitor } from './ObservedClientEventMonitor';
|
|
27
27
|
export { ObserverEventMonitor } from './ObserverEventMonitor';
|
|
28
28
|
export { Middleware } from './common/Middleware';
|
|
29
|
+
export type {
|
|
30
|
+
TrackReport,
|
|
31
|
+
ClientReport,
|
|
32
|
+
} from './Reports';
|