@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.
Files changed (40) hide show
  1. package/lib/ObservedCall.d.ts +0 -16
  2. package/lib/ObservedCall.d.ts.map +1 -1
  3. package/lib/ObservedCall.js +7 -36
  4. package/lib/ObservedCallEventMonitor.d.ts +3 -0
  5. package/lib/ObservedCallEventMonitor.d.ts.map +1 -1
  6. package/lib/ObservedCallEventMonitor.js +7 -0
  7. package/lib/ObservedClient.d.ts +3 -18
  8. package/lib/ObservedClient.d.ts.map +1 -1
  9. package/lib/ObservedClient.js +105 -41
  10. package/lib/ObservedInboundTrack.d.ts +2 -0
  11. package/lib/ObservedInboundTrack.d.ts.map +1 -1
  12. package/lib/ObservedInboundTrack.js +32 -0
  13. package/lib/ObservedOutboundTrack.d.ts +2 -0
  14. package/lib/ObservedOutboundTrack.d.ts.map +1 -1
  15. package/lib/ObservedOutboundTrack.js +5 -0
  16. package/lib/ObservedPeerConnection.d.ts +3 -3
  17. package/lib/ObservedPeerConnection.d.ts.map +1 -1
  18. package/lib/ObservedPeerConnection.js +15 -0
  19. package/lib/Observer.d.ts +2 -5
  20. package/lib/Observer.d.ts.map +1 -1
  21. package/lib/Observer.js +4 -10
  22. package/lib/ObserverEventMonitor.d.ts +3 -0
  23. package/lib/ObserverEventMonitor.d.ts.map +1 -1
  24. package/lib/ObserverEventMonitor.js +7 -0
  25. package/lib/Reports.d.ts +85 -0
  26. package/lib/Reports.d.ts.map +1 -0
  27. package/lib/Reports.js +2 -0
  28. package/lib/index.d.ts +1 -0
  29. package/lib/index.d.ts.map +1 -1
  30. package/package.json +1 -1
  31. package/src/ObservedCall.ts +8 -42
  32. package/src/ObservedCallEventMonitor.ts +10 -0
  33. package/src/ObservedClient.ts +122 -46
  34. package/src/ObservedInboundTrack.ts +32 -2
  35. package/src/ObservedOutboundTrack.ts +8 -0
  36. package/src/ObservedPeerConnection.ts +19 -3
  37. package/src/Observer.ts +7 -10
  38. package/src/ObserverEventMonitor.ts +10 -0
  39. package/src/Reports.ts +87 -0
  40. package/src/index.ts +4 -0
@@ -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.totalInboundPacketsLost += this.deltaInboundPacketsLost;
327
- this.totalInboundPacketsReceived += this.deltaInboundPacketsReceived;
328
- this.totalOutboundPacketsSent += this.deltaOutboundPacketsSent;
329
- this.totalReceivedAudioBytes += this.deltaReceivedAudioBytes;
330
- this.totalReceivedVideoBytes += this.deltaReceivedVideoBytes;
331
- this.totalSentAudioBytes += this.deltaSentAudioBytes;
332
- this.totalSentVideoBytes += this.deltaSentVideoBytes;
333
- this.totalReceivedBytes += this.deltaTransportReceivedBytes;
334
- this.totalSentBytes += this.deltaTransportSentBytes;
335
- this.totalRttLt50Measurements += this.deltaRttLt50Measurements;
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.totalReceivedVideoBytes * 8) / (elapsedInSeconds);
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
- observedPeerConnection = new ObservedPeerConnection(sample.peerConnectionId, this);
705
-
706
- observedPeerConnection.once('close', () => {
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
- this.observedPeerConnections.set(sample.peerConnectionId, observedPeerConnection);
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', observedPeerConnection);
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?: string;
132
- public iceConnectionState?: string;
133
- public iceGatheringState?: string;
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
- this.totalRttLt50Measurements += call.deltaRttLt50Measurements;
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';