@observertc/observer-js 0.41.7 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/lib/ObservedCall.d.ts +10 -3
  2. package/lib/ObservedCall.d.ts.map +1 -1
  3. package/lib/ObservedCall.js +28 -0
  4. package/lib/ObservedClient.d.ts +4 -0
  5. package/lib/ObservedClient.d.ts.map +1 -1
  6. package/lib/ObservedClient.js +81 -32
  7. package/lib/ObservedInboundAudioTrack.d.ts +94 -0
  8. package/lib/ObservedInboundAudioTrack.d.ts.map +1 -0
  9. package/lib/ObservedInboundAudioTrack.js +215 -0
  10. package/lib/ObservedInboundVideoTrack.d.ts +98 -0
  11. package/lib/ObservedInboundVideoTrack.d.ts.map +1 -0
  12. package/lib/{ObservedInboundTrack.js → ObservedInboundVideoTrack.js} +53 -44
  13. package/lib/ObservedOutboundAudioTrack.d.ts +85 -0
  14. package/lib/ObservedOutboundAudioTrack.d.ts.map +1 -0
  15. package/lib/{ObservedOutboundTrack.js → ObservedOutboundAudioTrack.js} +35 -58
  16. package/lib/ObservedOutboundVideoTrack.d.ts +88 -0
  17. package/lib/ObservedOutboundVideoTrack.d.ts.map +1 -0
  18. package/lib/ObservedOutboundVideoTrack.js +204 -0
  19. package/lib/ObservedPeerConnection.d.ts +26 -16
  20. package/lib/ObservedPeerConnection.d.ts.map +1 -1
  21. package/lib/ObservedPeerConnection.js +157 -86
  22. package/lib/RemoteTrackAssigner.d.ts +14 -0
  23. package/lib/RemoteTrackAssigner.d.ts.map +1 -0
  24. package/lib/RemoteTrackAssigner.js +52 -0
  25. package/lib/common/CalculatedScore.d.ts +79 -0
  26. package/lib/common/CalculatedScore.d.ts.map +1 -0
  27. package/lib/common/CalculatedScore.js +155 -0
  28. package/lib/common/QualityScoreUtils.d.ts +1 -0
  29. package/lib/common/QualityScoreUtils.d.ts.map +1 -0
  30. package/lib/common/QualityScoreUtils.js +1 -0
  31. package/lib/common/utils.d.ts +1 -0
  32. package/lib/common/utils.d.ts.map +1 -1
  33. package/lib/common/utils.js +14 -1
  34. package/lib/index.d.ts +4 -2
  35. package/lib/index.d.ts.map +1 -1
  36. package/package.json +1 -1
  37. package/src/ObservedCall.ts +40 -4
  38. package/src/ObservedClient.ts +77 -17
  39. package/src/ObservedInboundAudioTrack.ts +336 -0
  40. package/src/{ObservedInboundTrack.ts → ObservedInboundVideoTrack.ts} +85 -66
  41. package/src/{ObservedOutboundTrack.ts → ObservedOutboundAudioTrack.ts} +59 -74
  42. package/src/ObservedOutboundVideoTrack.ts +326 -0
  43. package/src/ObservedPeerConnection.ts +205 -131
  44. package/src/RemoteTrackAssigner.ts +68 -0
  45. package/src/common/CalculatedScore.ts +180 -0
  46. package/src/common/QualityScoreUtils.ts +0 -0
  47. package/src/common/utils.ts +17 -1
  48. package/src/index.ts +4 -2
  49. package/src/monitors/CallSummaryMonitor.ts +3 -3
  50. package/lib/ObservedInboundTrack.d.ts +0 -96
  51. package/lib/ObservedInboundTrack.d.ts.map +0 -1
  52. package/lib/ObservedOutboundTrack.d.ts +0 -84
  53. package/lib/ObservedOutboundTrack.d.ts.map +0 -1
@@ -1,22 +1,27 @@
1
1
  import { EventEmitter } from 'events';
2
2
  import { PeerConnectionTransport } from '@observertc/sample-schemas-js';
3
3
  import { ObservedClient } from './ObservedClient';
4
- import { ObservedInboundTrack, ObservedInboundTrackModel } from './ObservedInboundTrack';
5
- import { ObservedOutboundTrack, ObservedOutboundTrackModel } from './ObservedOutboundTrack';
6
4
  import { CallEventReport, PeerConnectionTransportReport } from '@observertc/report-schemas-js';
7
5
  import { ObservedICE } from './ObservedICE';
8
6
  import { ObservedDataChannel } from './ObservedDataChannel';
9
7
  import { PartialBy } from './common/utils';
8
+ import { ObservedInboundAudioTrack, ObservedInboundAudioTrackModel } from './ObservedInboundAudioTrack';
9
+ import { ObservedInboundVideoTrack, ObservedInboundVideoTrackModel } from './ObservedInboundVideoTrack';
10
+ import { ObservedOutboundAudioTrack, ObservedOutboundAudioTrackModel } from './ObservedOutboundAudioTrack';
11
+ import { ObservedOutboundVideoTrack, ObservedOutboundVideoTrackModel } from './ObservedOutboundVideoTrack';
12
+ import { CalculatedScore, calculateLatencyMOS } from './common/CalculatedScore';
13
+ import { ClientIssue } from './monitors/CallSummary';
10
14
 
11
15
  export type ObservedPeerConnectionEvents = {
12
16
  update: [{
13
17
  elapsedTimeInMs: number;
14
18
  }],
15
19
  close: [],
16
- newinboudaudiotrack: [ObservedInboundTrack<'audio'>],
17
- newinboudvideotrack: [ObservedInboundTrack<'video'>],
18
- newoutboundaudiotrack: [ObservedOutboundTrack<'audio'>],
19
- newoutboundvideotrack: [ObservedOutboundTrack<'video'>],
20
+ score: [CalculatedScore],
21
+ newinboudaudiotrack: [ObservedInboundAudioTrack],
22
+ newinboudvideotrack: [ObservedInboundVideoTrack],
23
+ newoutboundaudiotrack: [ObservedOutboundAudioTrack],
24
+ newoutboundvideotrack: [ObservedOutboundVideoTrack],
20
25
  newdatachannel: [ObservedDataChannel],
21
26
  };
22
27
 
@@ -39,7 +44,11 @@ export class ObservedPeerConnection extends EventEmitter {
39
44
  public visited = true;
40
45
 
41
46
  private _elapsedTimeSinceLastUpdate?: number;
47
+ private _statsTimestamp?: number;
48
+
49
+ public ωpendingIssuesForScores: ClientIssue[] = [];
42
50
 
51
+ public score?: CalculatedScore;
43
52
  public totalInboundPacketsLost = 0;
44
53
  public totalInboundPacketsReceived = 0;
45
54
  public totalOutboundPacketsSent = 0;
@@ -77,6 +86,7 @@ export class ObservedPeerConnection extends EventEmitter {
77
86
  public receivingVideoBitrate = 0;
78
87
 
79
88
  public avgRttInMs?: number;
89
+ public avgJitter?: number;
80
90
 
81
91
  private _closed = false;
82
92
  private _updated = Date.now();
@@ -84,10 +94,10 @@ export class ObservedPeerConnection extends EventEmitter {
84
94
  private _marker?: string;
85
95
 
86
96
  public readonly ICE = ObservedICE.create(this);
87
- private readonly _inboundAudioTracks = new Map<string, ObservedInboundTrack<'audio'>>();
88
- private readonly _inboundVideoTracks = new Map<string, ObservedInboundTrack<'video'>>();
89
- private readonly _outboundAudioTracks = new Map<string, ObservedOutboundTrack<'audio'>>();
90
- private readonly _outboundVideoTracks = new Map<string, ObservedOutboundTrack<'video'>>();
97
+ private readonly _inboundAudioTracks = new Map<string, ObservedInboundAudioTrack>();
98
+ private readonly _inboundVideoTracks = new Map<string, ObservedInboundVideoTrack>();
99
+ private readonly _outboundAudioTracks = new Map<string, ObservedOutboundAudioTrack>();
100
+ private readonly _outboundVideoTracks = new Map<string, ObservedOutboundVideoTrack>();
91
101
  private readonly _dataChannels = new Map<number, ObservedDataChannel>();
92
102
 
93
103
  public constructor(
@@ -155,19 +165,19 @@ export class ObservedPeerConnection extends EventEmitter {
155
165
  return this._updated;
156
166
  }
157
167
 
158
- public get inboundAudioTracks(): ReadonlyMap<string, ObservedInboundTrack<'audio'>> {
168
+ public get inboundAudioTracks(): ReadonlyMap<string, ObservedInboundAudioTrack> {
159
169
  return this._inboundAudioTracks;
160
170
  }
161
171
 
162
- public get inboundVideoTracks(): ReadonlyMap<string, ObservedInboundTrack<'video'>> {
172
+ public get inboundVideoTracks(): ReadonlyMap<string, ObservedInboundVideoTrack> {
163
173
  return this._inboundVideoTracks;
164
174
  }
165
175
 
166
- public get outboundAudioTracks(): ReadonlyMap<string, ObservedOutboundTrack<'audio'>> {
176
+ public get outboundAudioTracks(): ReadonlyMap<string, ObservedOutboundAudioTrack> {
167
177
  return this._outboundAudioTracks;
168
178
  }
169
179
 
170
- public get outboundVideoTracks(): ReadonlyMap<string, ObservedOutboundTrack<'video'>> {
180
+ public get outboundVideoTracks(): ReadonlyMap<string, ObservedOutboundVideoTrack> {
171
181
  return this._outboundVideoTracks;
172
182
  }
173
183
 
@@ -218,13 +228,19 @@ export class ObservedPeerConnection extends EventEmitter {
218
228
 
219
229
  Array.from(this._inboundAudioTracks.values()).forEach((track) => track.close());
220
230
  Array.from(this._inboundVideoTracks.values()).forEach((track) => track.close());
221
- Array.from(this._outboundAudioTracks.values()).forEach((track) => track.close());
222
- Array.from(this._outboundVideoTracks.values()).forEach((track) => track.close());
231
+ Array.from(this._outboundAudioTracks.values()).forEach((track) => {
232
+ this.client.call.sfuStreamIdToOutboundAudioTrack.delete(track.sfuStreamId ?? '');
233
+ track.close();
234
+ });
235
+ Array.from(this._outboundVideoTracks.values()).forEach((track) => {
236
+ this.client.call.sfuStreamIdToOutboundVideoTrack.delete(track.sfuStreamId ?? '');
237
+ track.close();
238
+ });
223
239
 
224
240
  this.emit('close');
225
241
  }
226
242
 
227
- public getTrack(trackId: string): ObservedInboundTrack<'audio'> | ObservedInboundTrack<'video'> | ObservedOutboundTrack<'audio'> | ObservedOutboundTrack<'video'> | undefined {
243
+ public getTrack(trackId: string): ObservedInboundAudioTrack | ObservedInboundVideoTrack | ObservedOutboundAudioTrack | ObservedOutboundVideoTrack | undefined {
228
244
  return this._inboundAudioTracks.get(trackId) ?? this._inboundVideoTracks.get(trackId) ?? this._outboundAudioTracks.get(trackId) ?? this._outboundVideoTracks.get(trackId);
229
245
  }
230
246
 
@@ -251,8 +267,119 @@ export class ObservedPeerConnection extends EventEmitter {
251
267
  this.ICE.resetMetrics();
252
268
  }
253
269
 
270
+ public update(sample: PeerConnectionTransport, timestamp: number) {
271
+ if (this._closed) return;
272
+ if (sample.peerConnectionId !== this._model.peerConnectionId) throw new Error(`TransportId mismatch. PeerConnectionId: ${ this._model.peerConnectionId } TransportId: ${ sample.transportId}`);
273
+
274
+ this._sample = sample;
275
+ if (this._model.label !== sample.label) {
276
+ this._model.label = sample.label;
277
+ }
278
+ const now = Date.now();
279
+ const report: PeerConnectionTransportReport = {
280
+ serviceId: this.client.call.serviceId,
281
+ roomId: this.client.call.roomId,
282
+ callId: this.client.call.callId,
283
+ clientId: this.client.clientId,
284
+ userId: this.client.userId,
285
+ mediaUnitId: this.client.mediaUnitId,
286
+ ...sample,
287
+ timestamp,
288
+ sampleSeq: -1, // deprecated
289
+ marker: this.marker,
290
+ };
291
+
292
+ this.reports.addPeerConnectionTransportReports(report);
293
+ this._elapsedTimeSinceLastUpdate = now - this._updated;
294
+ this.visited = true;
295
+ this._updated = now;
296
+ this._statsTimestamp = timestamp;
297
+ this.emit('update', {
298
+ elapsedTimeInMs: this._elapsedTimeSinceLastUpdate,
299
+ });
300
+ }
301
+
302
+ public createInboundAudioTrack(config: ObservedInboundAudioTrackModel): ObservedInboundAudioTrack {
303
+ if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
304
+
305
+ const result = new ObservedInboundAudioTrack(config, this);
306
+
307
+ result.on('close', () => {
308
+ this._inboundAudioTracks.delete(result.trackId);
309
+ });
310
+ this._inboundAudioTracks.set(result.trackId, result);
311
+
312
+ this.emit('newinboudaudiotrack', result);
313
+
314
+ return result;
315
+ }
316
+
317
+ public createInboundVideoTrack(config: ObservedInboundVideoTrackModel): ObservedInboundVideoTrack {
318
+ if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
319
+
320
+ const result = new ObservedInboundVideoTrack(config, this);
321
+
322
+ result.on('close', () => {
323
+ this._inboundVideoTracks.delete(result.trackId);
324
+ });
325
+ this._inboundVideoTracks.set(result.trackId, result);
326
+
327
+ this.emit('newinboudvideotrack', result);
328
+
329
+ return result;
330
+ }
331
+
332
+ public createOutboundAudioTrack(config: ObservedOutboundAudioTrackModel): ObservedOutboundAudioTrack {
333
+ if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
334
+
335
+ const result = new ObservedOutboundAudioTrack(config, this);
336
+
337
+ result.on('close', () => {
338
+ this._outboundAudioTracks.delete(result.trackId);
339
+ });
340
+ this._outboundAudioTracks.set(result.trackId, result);
341
+
342
+ this.emit('newoutboundaudiotrack', result);
343
+
344
+ return result;
345
+ }
346
+
347
+ public createOutboundVideoTrack(config: ObservedOutboundVideoTrackModel): ObservedOutboundVideoTrack {
348
+ if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
349
+
350
+ const result = new ObservedOutboundVideoTrack(config, this);
351
+
352
+ result.on('close', () => {
353
+ this._outboundVideoTracks.delete(result.trackId);
354
+ });
355
+ this._outboundVideoTracks.set(result.trackId, result);
356
+
357
+ this.emit('newoutboundvideotrack', result);
358
+
359
+ return result;
360
+ }
361
+
362
+ public createDataChannel(channelId: number) {
363
+ if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
364
+
365
+ const result = new ObservedDataChannel({
366
+ channelId,
367
+ }, this);
368
+
369
+ result.on('close', () => {
370
+ this._dataChannels.delete(result.channelId);
371
+ });
372
+ this._dataChannels.set(result.channelId, result);
373
+
374
+ this.emit('newdatachannel', result);
375
+
376
+ return result;
377
+ }
378
+
254
379
  public updateMetrics() {
255
380
  let sumRttInMs = 0;
381
+ let sumJitter = 0;
382
+ const trackScores: CalculatedScore[] = [];
256
383
 
257
384
  this._inboundAudioTracks.forEach((track) => {
258
385
  track.updateMetrics();
@@ -266,7 +393,10 @@ export class ObservedPeerConnection extends EventEmitter {
266
393
 
267
394
  this.receivingAudioBitrate += track.bitrate;
268
395
 
269
- sumRttInMs = (track.rttInMs ?? 0);
396
+ sumRttInMs += (track.rttInMs ?? 0);
397
+ sumJitter += (track.jitter ?? 0);
398
+
399
+ track.score && trackScores.push(track.score);
270
400
  });
271
401
 
272
402
  this._inboundVideoTracks.forEach((track) => {
@@ -281,7 +411,10 @@ export class ObservedPeerConnection extends EventEmitter {
281
411
 
282
412
  this.receivingVideoBitrate += track.bitrate;
283
413
 
284
- sumRttInMs = (track.rttInMs ?? 0);
414
+ sumRttInMs += (track.rttInMs ?? 0);
415
+ sumJitter += (track.jitter ?? 0);
416
+
417
+ track.score && trackScores.push(track.score);
285
418
  });
286
419
 
287
420
  this._outboundAudioTracks.forEach((track) => {
@@ -295,7 +428,10 @@ export class ObservedPeerConnection extends EventEmitter {
295
428
 
296
429
  this.sendingAudioBitrate += track.bitrate;
297
430
 
298
- sumRttInMs = (track.rttInMs ?? 0);
431
+ sumRttInMs += (track.rttInMs ?? 0);
432
+ sumJitter += (track.jitter ?? 0);
433
+
434
+ track.score && trackScores.push(track.score);
299
435
  });
300
436
 
301
437
  this._outboundVideoTracks.forEach((track) => {
@@ -309,7 +445,10 @@ export class ObservedPeerConnection extends EventEmitter {
309
445
 
310
446
  this.sendingVideoBitrate += track.bitrate;
311
447
 
312
- sumRttInMs = (track.rttInMs ?? 0);
448
+ sumRttInMs += (track.rttInMs ?? 0);
449
+ sumJitter += (track.jitter ?? 0);
450
+
451
+ track.score && trackScores.push(track.score);
313
452
  });
314
453
 
315
454
  this._dataChannels.forEach((channel) => {
@@ -320,6 +459,8 @@ export class ObservedPeerConnection extends EventEmitter {
320
459
  const iceRttInMs = this.ICE.stats?.currentRoundTripTime;
321
460
  let nrOfBelongings = this._inboundAudioTracks.size + this._inboundVideoTracks.size + this._outboundAudioTracks.size + this._outboundVideoTracks.size;
322
461
 
462
+ this.avgJitter = 0 < nrOfBelongings ? sumJitter / nrOfBelongings : undefined;
463
+
323
464
  if (iceRttInMs) {
324
465
  sumRttInMs += iceRttInMs;
325
466
  nrOfBelongings += 1;
@@ -347,125 +488,58 @@ export class ObservedPeerConnection extends EventEmitter {
347
488
  this.sendingPacketsPerSecond = 0;
348
489
  this.receivingPacketsPerSecond = 0;
349
490
  }
350
- }
351
-
352
- public update(sample: PeerConnectionTransport, timestamp: number) {
353
- if (this._closed) return;
354
- if (sample.peerConnectionId !== this._model.peerConnectionId) throw new Error(`TransportId mismatch. PeerConnectionId: ${ this._model.peerConnectionId } TransportId: ${ sample.transportId}`);
355
-
356
- this._sample = sample;
357
- if (this._model.label !== sample.label) {
358
- this._model.label = sample.label;
359
- }
360
- const now = Date.now();
361
- const report: PeerConnectionTransportReport = {
362
- serviceId: this.client.call.serviceId,
363
- roomId: this.client.call.roomId,
364
- callId: this.client.call.callId,
365
- clientId: this.client.clientId,
366
- userId: this.client.userId,
367
- mediaUnitId: this.client.mediaUnitId,
368
- ...sample,
369
- timestamp,
370
- sampleSeq: -1, // deprecated
371
- marker: this.marker,
372
- };
373
-
374
- this.reports.addPeerConnectionTransportReports(report);
375
- this._elapsedTimeSinceLastUpdate = now - this._updated;
376
- this.visited = true;
377
- this._updated = now;
378
- this.emit('update', {
379
- elapsedTimeInMs: this._elapsedTimeSinceLastUpdate,
380
- });
381
- }
382
-
383
- public createInboundAudioTrack(config: Omit<ObservedInboundTrackModel<'audio'>, 'kind'>): ObservedInboundTrack<'audio'> {
384
- if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
385
-
386
- const result = new ObservedInboundTrack<'audio'>({
387
- kind: 'audio',
388
- ...config,
389
- }, this);
390
-
391
- result.on('close', () => {
392
- this._inboundAudioTracks.delete(result.trackId);
393
- });
394
- this._inboundAudioTracks.set(result.trackId, result);
395
-
396
- this.emit('newinboudaudiotrack', result);
397
-
398
- return result;
399
- }
400
491
 
401
- public createInboundVideoTrack(config: Omit<ObservedInboundTrackModel<'video'>, 'kind'>): ObservedInboundTrack<'video'> {
402
- if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
403
-
404
- const result = new ObservedInboundTrack<'video'>({
405
- kind: 'video',
406
- ...config,
407
- }, this);
408
-
409
- result.on('close', () => {
410
- this._inboundVideoTracks.delete(result.trackId);
411
- });
412
- this._inboundVideoTracks.set(result.trackId, result);
413
-
414
- this.emit('newinboudvideotrack', result);
415
-
416
- return result;
492
+ // calculate quality score
493
+ this._updateQualityScore(trackScores);
417
494
  }
418
495
 
419
- public createOutboundAudioTrack(config: Omit<ObservedOutboundTrackModel<'audio'>, 'kind'>): ObservedOutboundTrack<'audio'> {
420
- if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
421
-
422
- const result = new ObservedOutboundTrack<'audio'>({
423
- kind: 'audio',
424
- ...config,
425
- }, this);
426
-
427
- result.on('close', () => {
428
- this._outboundAudioTracks.delete(result.trackId);
496
+ private _updateQualityScore(trackScores: CalculatedScore[]) {
497
+ const mosScore = calculateLatencyMOS({
498
+ avgJitter: this.avgJitter ?? 0,
499
+ rttInMs: this.avgRttInMs ?? 0,
500
+ packetsLoss: this.deltaInboundPacketsLost,
429
501
  });
430
- this._outboundAudioTracks.set(result.trackId, result);
431
-
432
- this.emit('newoutboundaudiotrack', result);
433
-
434
- return result;
435
- }
436
-
437
- public createOutboundVideoTrack(config: Omit<ObservedOutboundTrackModel<'video'>, 'kind'>): ObservedOutboundTrack<'video'> {
438
- if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
502
+ const score: CalculatedScore = {
503
+ remarks: [ {
504
+ severity: 'none',
505
+ text: `MOS score: ${mosScore}`,
506
+ } ],
507
+ score: mosScore / 10.0, // normalize between 0 and 2
508
+ timestamp: this._statsTimestamp ?? Date.now(),
509
+ };
439
510
 
440
- const result = new ObservedOutboundTrack<'video'>({
441
- kind: 'video',
442
- ...config,
443
- }, this);
444
-
445
- result.on('close', () => {
446
- this._outboundVideoTracks.delete(result.trackId);
447
- });
448
- this._outboundVideoTracks.set(result.trackId, result);
511
+ let sumTrackScores = 0;
449
512
 
450
- this.emit('newoutboundvideotrack', result);
451
-
452
- return result;
453
- }
454
-
455
- public createDataChannel(channelId: number) {
456
- if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
457
-
458
- const result = new ObservedDataChannel({
459
- channelId,
460
- }, this);
513
+ for (const trackScore of trackScores) {
514
+ sumTrackScores += trackScore.score;
515
+ }
461
516
 
462
- result.on('close', () => {
463
- this._dataChannels.delete(result.channelId);
517
+ score.score += sumTrackScores / trackScores.length;
518
+ score.remarks.push({
519
+ severity: 'none',
520
+ text: `Track scores: ${sumTrackScores / trackScores.length}`,
464
521
  });
465
- this._dataChannels.set(result.channelId, result);
466
522
 
467
- this.emit('newdatachannel', result);
523
+ for (const pendingScore of this.ωpendingIssuesForScores) {
524
+ switch (pendingScore.severity) {
525
+ case 'critical':
526
+ score.score = 0.0;
527
+ break;
528
+ case 'major':
529
+ score.score *= 0.5;
530
+ break;
531
+ case 'minor':
532
+ score.score *= 0.8;
533
+ break;
534
+ }
535
+ score.remarks.push({
536
+ severity: pendingScore.severity,
537
+ text: pendingScore.description ?? 'Issue occurred',
538
+ });
539
+ }
540
+ this.ωpendingIssuesForScores = [];
541
+ this.score = score;
468
542
 
469
- return result;
543
+ this.emit('score', score);
470
544
  }
471
545
  }
@@ -0,0 +1,68 @@
1
+ import { ObservedInboundAudioTrack } from './ObservedInboundAudioTrack';
2
+ import { ObservedInboundVideoTrack } from './ObservedInboundVideoTrack';
3
+ import { ObservedOutboundAudioTrack } from './ObservedOutboundAudioTrack';
4
+ import { ObservedOutboundVideoTrack } from './ObservedOutboundVideoTrack';
5
+
6
+ export class RemoteTrackAssigner {
7
+ public readonly sfuStreamIdToOutboundVideoTracks = new Map<string, ObservedOutboundVideoTrack>();
8
+ public readonly sfuStreamIdToOutboundAudioTracks = new Map<string, ObservedOutboundAudioTrack>();
9
+ public readonly pendingInboundVideoTracks = new Map<string, ObservedInboundVideoTrack[]>();
10
+ public readonly pendingInboundAudioTracks = new Map<string, ObservedInboundAudioTrack[]>();
11
+
12
+ public addOutboundAudioTrack(track: ObservedOutboundAudioTrack) {
13
+ const untilSfuStreamIdListener = () => {
14
+ if (!track.sfuStreamId) return;
15
+
16
+ this.sfuStreamIdToOutboundAudioTracks.set(track.sfuStreamId, track);
17
+ track.off('update', untilSfuStreamIdListener);
18
+
19
+ // we need to assign to the pending inbound tracks
20
+ };
21
+
22
+ track.on('update', untilSfuStreamIdListener);
23
+ untilSfuStreamIdListener();
24
+ }
25
+
26
+ public addOutboundVideoTrack(track: ObservedOutboundVideoTrack) {
27
+ const untilSfuStreamIdListener = () => {
28
+ if (!track.sfuStreamId) return;
29
+
30
+ this.sfuStreamIdToOutboundVideoTracks.set(track.sfuStreamId, track);
31
+ track.off('update', untilSfuStreamIdListener);
32
+
33
+ // we need to assign to the pending inbound tracks
34
+ };
35
+
36
+ track.on('update', untilSfuStreamIdListener);
37
+ untilSfuStreamIdListener();
38
+ }
39
+
40
+ public addInboundAudioTrack(track: ObservedInboundAudioTrack) {
41
+ const untilSfuStreamIdListener = () => {
42
+ if (!track.sfuStreamId) return;
43
+ const outboundTrack = this.sfuStreamIdToOutboundAudioTracks.get(track.sfuStreamId);
44
+
45
+ if (!outboundTrack) {
46
+ this.pendingInboundAudioTracks.set(
47
+ track.sfuStreamId,
48
+ (this.pendingInboundAudioTracks.get(track.sfuStreamId) || []).concat(track)
49
+ );
50
+
51
+ return;
52
+ }
53
+
54
+ if (outboundTrack) {
55
+ track.remoteOutboundTrack = outboundTrack;
56
+ } else {
57
+ this.pendingInboundAudioTracks.set(
58
+ track.sfuStreamId,
59
+ (this.pendingInboundAudioTracks.get(track.sfuStreamId) || []).concat(track)
60
+ );
61
+ }
62
+
63
+ };
64
+
65
+ track.on('update', untilSfuStreamIdListener);
66
+ }
67
+
68
+ }