@observertc/observer-js 0.30.5-beta → 0.40.0-beta

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 (58) hide show
  1. package/lib/CallSummary.d.ts +22 -0
  2. package/lib/CallSummary.d.ts.map +1 -0
  3. package/lib/ObservedCall.d.ts +6 -13
  4. package/lib/ObservedCall.d.ts.map +1 -1
  5. package/lib/ObservedCall.js +24 -104
  6. package/lib/ObservedClient.d.ts +16 -27
  7. package/lib/ObservedClient.d.ts.map +1 -1
  8. package/lib/ObservedClient.js +360 -523
  9. package/lib/ObservedInboundTrack.d.ts +3 -8
  10. package/lib/ObservedInboundTrack.d.ts.map +1 -1
  11. package/lib/ObservedInboundTrack.js +74 -154
  12. package/lib/ObservedOutboundTrack.d.ts +9 -8
  13. package/lib/ObservedOutboundTrack.d.ts.map +1 -1
  14. package/lib/ObservedOutboundTrack.js +76 -130
  15. package/lib/ObservedPeerConnection.d.ts +17 -15
  16. package/lib/ObservedPeerConnection.d.ts.map +1 -1
  17. package/lib/ObservedPeerConnection.js +64 -173
  18. package/lib/ObservedSfu.d.ts +14 -4
  19. package/lib/ObservedSfu.d.ts.map +1 -1
  20. package/lib/ObservedSfu.js +37 -50
  21. package/lib/Observer.d.ts +5 -6
  22. package/lib/Observer.d.ts.map +1 -1
  23. package/lib/Observer.js +28 -31
  24. package/lib/common/types.d.ts +0 -55
  25. package/lib/common/types.d.ts.map +1 -1
  26. package/lib/index.d.ts +5 -7
  27. package/lib/index.d.ts.map +1 -1
  28. package/package.json +1 -1
  29. package/src/CallSummary.ts +23 -0
  30. package/src/ObservedCall.ts +27 -87
  31. package/src/ObservedClient.ts +425 -582
  32. package/src/ObservedInboundTrack.ts +14 -65
  33. package/src/ObservedOutboundTrack.ts +32 -53
  34. package/src/ObservedPeerConnection.ts +55 -117
  35. package/src/ObservedSfu.ts +45 -27
  36. package/src/Observer.ts +11 -16
  37. package/src/common/types.ts +0 -69
  38. package/src/index.ts +5 -7
  39. package/lib/models/Models.d.ts +0 -642
  40. package/lib/models/Models.d.ts.map +0 -1
  41. package/lib/models/Models.js +0 -481
  42. package/lib/models/samples_pb.d.ts +0 -2452
  43. package/lib/models/samples_pb.d.ts.map +0 -1
  44. package/lib/models/samples_pb.js +0 -1495
  45. package/lib/storages/ObserverStorage.d.ts +0 -87
  46. package/lib/storages/ObserverStorage.d.ts.map +0 -1
  47. package/lib/storages/SimpleStorage.d.ts +0 -19
  48. package/lib/storages/SimpleStorage.d.ts.map +0 -1
  49. package/lib/storages/SimpleStorage.js +0 -106
  50. package/lib/storages/StorageProvider.d.ts +0 -16
  51. package/lib/storages/StorageProvider.d.ts.map +0 -1
  52. package/lib/storages/StorageProvider.js +0 -29
  53. package/src/models/Models.ts +0 -1103
  54. package/src/models/samples_pb.ts +0 -4061
  55. package/src/storages/ObserverStorage.ts +0 -99
  56. package/src/storages/SimpleStorage.ts +0 -120
  57. package/src/storages/StorageProvider.ts +0 -42
  58. /package/lib/{storages/ObserverStorage.js → CallSummary.js} +0 -0
@@ -1,27 +1,26 @@
1
- import { ClientSample, IceLocalCandidate, IceRemoteCandidate } from '@observertc/sample-schemas-js';
1
+ import { Browser, ClientSample, Engine, IceLocalCandidate, IceRemoteCandidate, OperationSystem, Platform } from '@observertc/sample-schemas-js';
2
2
  import { ObservedCall } from './ObservedCall';
3
- import * as Models from './models/Models';
4
- import { StorageProvider } from './storages/StorageProvider';
5
3
  import { EventEmitter } from 'events';
6
- import { createSingleExecutor } from './common/SingleExecutor';
7
4
  import { ObservedPeerConnection } from './ObservedPeerConnection';
8
5
  import { createLogger } from './common/logger';
9
6
  import { CallMetaType, createCallMetaReport } from './common/callMetaReports';
10
7
  // eslint-disable-next-line camelcase
11
- import { Samples_ClientSample_Browser, Samples_ClientSample_Engine, Samples_ClientSample_OperationSystem, Samples_ClientSample_Platform } from './models/samples_pb';
12
8
  import { isValidUuid } from './common/utils';
13
- import { createClientJoinedEventReport, createClientLeftEventReport } from './common/callEventReports';
9
+ import { createClientLeftEventReport } from './common/callEventReports';
14
10
  import { CallEventType } from './common/CallEventType';
15
11
 
16
12
  const logger = createLogger('ObservedClient');
17
13
 
18
- export type ObservedClientConfig<AppData extends Record<string, unknown> = Record<string, unknown>> = {
19
- callId: string;
14
+ export type ObservedClientModel= {
20
15
  clientId: string;
21
16
  mediaUnitId: string;
22
- appData: AppData;
23
17
  overflowingProcessingThreshold?: number;
24
- joined?: number,
18
+ userId?: string,
19
+ marker?: string,
20
+ operationSystem?: OperationSystem,
21
+ engine?: Engine,
22
+ platform?: Platform,
23
+ browser?: Browser,
25
24
 
26
25
  /**
27
26
  * before client-monitor-js 3.4.0 the client joined event was generated by the observer, this flag is to keep the compatibility with the old behavior
@@ -32,7 +31,6 @@ export type ObservedClientConfig<AppData extends Record<string, unknown> = Recor
32
31
  export type ObservedClientEvents = {
33
32
  update: [],
34
33
  close: [],
35
- 'processing-sample-overflow': [],
36
34
  newpeerconnection: [ObservedPeerConnection],
37
35
  iceconnectionstatechange: [{
38
36
  peerConnection: ObservedPeerConnection,
@@ -63,61 +61,18 @@ export declare interface ObservedClient<AppData extends Record<string, unknown>
63
61
  }
64
62
 
65
63
  export class ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {
66
- public static async create<T extends Record<string, unknown> = Record<string, unknown>>(
67
- config: ObservedClientConfig<T>,
68
- call: ObservedCall,
69
- storageProvider: StorageProvider,
70
- ) {
71
- const { callId, clientId, mediaUnitId } = config;
72
-
73
- const model = new Models.Client({
74
- roomId: call.roomId,
75
- serviceId: call.serviceId,
76
- callId,
77
- clientId,
78
- mediaUnitId,
79
- peerConnectionIds: [],
80
- joined: BigInt(config.joined ?? Date.now()),
81
- });
82
-
83
- const result = new ObservedClient<T>(model, call, storageProvider, config.appData);
84
-
85
- const alreadyInserted = await storageProvider.clientStorage.insert(clientId, model);
86
-
87
- if (alreadyInserted) throw new Error(`Client with id ${clientId} already exists`);
88
-
89
- result._overflowingProcessingThreshold = config.overflowingProcessingThreshold ?? 0;
90
-
91
- if (config.addJoinAndDetachClientEvent) {
92
- call.reports.addCallEventReport(createClientJoinedEventReport(
93
- call.serviceId,
94
- result.mediaUnitId,
95
- call.roomId,
96
- call.callId,
97
- result.clientId,
98
- result.joined,
99
- result.userId,
100
- result.marker,
101
- ));
102
- }
103
-
104
- return result;
105
- }
106
-
107
- public created = Date.now();
64
+
65
+ public readonly created = Date.now();
66
+ public _updated = Date.now();
108
67
 
109
68
  private readonly _peerConnections = new Map<string, ObservedPeerConnection>();
110
- private readonly _execute = createSingleExecutor();
111
69
 
112
- private _overflowingProcessingThreshold = 0;
113
70
  private _closed = false;
114
- private _updated = Date.now();
71
+
115
72
  private _acceptedSample = 0;
116
- private _processingSample = 0;
117
73
  private _timeZoneOffsetInHours?: number;
118
74
  private _left?: number;
119
- private _numberOfAcceptedUpdates = 0;
120
-
75
+
121
76
  public usingTURN = false;
122
77
  public availableOutgoingBitrate = 0;
123
78
  public availableIncomingBitrate = 0;
@@ -140,20 +95,14 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
140
95
  public readonly ωpendingCreatedTracksTimestamp = new Map<string, number>();
141
96
  public readonly ωpendingCreatedPeerConnectionTimestamp = new Map<string, number>();
142
97
 
143
- private constructor(
144
- private readonly _model: Models.Client,
98
+ public constructor(
99
+ private readonly _model: ObservedClientModel,
145
100
  public readonly call: ObservedCall,
146
- private readonly _storageProvider: StorageProvider,
147
101
  public readonly appData: AppData
148
102
  ) {
149
103
  super();
150
104
  }
151
105
 
152
- public get joined(): number {
153
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
154
- return Number(this._model.joined!);
155
- }
156
-
157
106
  public get clientId(): string {
158
107
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
159
108
  return this._model.clientId!;
@@ -161,17 +110,17 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
161
110
 
162
111
  public get roomId() {
163
112
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
164
- return this._model.roomId!;
113
+ return this.call.roomId!;
165
114
  }
166
115
 
167
116
  public get serviceId() {
168
117
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
169
- return this._model.serviceId!;
118
+ return this.call.serviceId!;
170
119
  }
171
120
 
172
121
  public get callId() {
173
122
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
174
- return this._model.callId!;
123
+ return this.call.callId!;
175
124
  }
176
125
 
177
126
  public get mediaUnitId() {
@@ -219,20 +168,6 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
219
168
  return this._updated;
220
169
  }
221
170
 
222
- public get numberOfAcceptedUpdates() {
223
- return this._numberOfAcceptedUpdates;
224
- }
225
-
226
- public get uptimeInMs() {
227
- return this._updated - this.created;
228
- }
229
-
230
- public get durationInMs(): number | undefined {
231
- if (!this._left) return;
232
-
233
- return this._left - this.joined;
234
- }
235
-
236
171
  public get closed() {
237
172
  return this._closed;
238
173
  }
@@ -245,600 +180,518 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
245
180
  if (this._closed) return;
246
181
  this._closed = true;
247
182
 
248
- !this._left && this._addClientLeftReport();
183
+ if (!this._left) {
184
+ this._addClientLeftReport();
185
+ }
249
186
 
250
187
  Array.from(this._peerConnections.values()).forEach((peerConnection) => peerConnection.close());
251
188
 
252
- this._execute(() => this._storageProvider.clientStorage.remove(this.clientId))
253
- .catch(() => void 0)
254
- .finally(() => this.emit('close'));
189
+ this.emit('close');
255
190
  }
256
191
 
257
- public async accept(sample: ClientSample): Promise<void> {
192
+ public accept(sample: ClientSample): void {
258
193
  if (this._closed) throw new Error(`Client ${this.clientId} is closed`);
259
194
  if (sample.clientId && sample.clientId !== 'NULL' && sample.clientId !== this.clientId) {
260
195
  throw new Error(`Sample client id (${sample.clientId}) does not match the client id of the observed client (${this.clientId})`);
261
196
  }
262
197
  ++this._acceptedSample;
263
- ++this._processingSample;
264
198
 
265
- if (0 < this._overflowingProcessingThreshold && this._overflowingProcessingThreshold < this._processingSample) {
266
- this.emit('processing-sample-overflow');
199
+ for (const peerConnection of this._peerConnections.values()) {
200
+ if (peerConnection.closed) continue;
201
+ peerConnection.resetMetrics();
267
202
  }
268
203
 
269
- return this._execute(async () => {
270
- ++this._numberOfAcceptedUpdates;
271
-
272
- for (const peerConnection of this._peerConnections.values()) {
273
- if (peerConnection.closed) continue;
274
- peerConnection.resetMetrics();
275
- }
276
-
277
- let executeSave = false;
278
-
279
- if (this.userId !== sample.userId) {
280
- this._model.userId = sample.userId;
281
- executeSave = true;
282
- }
283
- if (this._model.marker !== sample.marker) {
284
- this._model.marker = sample.marker;
285
- executeSave = true;
286
- }
204
+ if (this.userId !== sample.userId) {
205
+ this._model.userId = sample.userId;
206
+ }
207
+ if (this._model.marker !== sample.marker) {
208
+ this._model.marker = sample.marker;
209
+ }
287
210
 
288
- if (this._timeZoneOffsetInHours !== sample.timeZoneOffsetInHours) {
289
- this._timeZoneOffsetInHours = sample.timeZoneOffsetInHours;
290
- executeSave = true;
291
- }
211
+ if (this._timeZoneOffsetInHours !== sample.timeZoneOffsetInHours) {
212
+ this._timeZoneOffsetInHours = sample.timeZoneOffsetInHours;
213
+ }
292
214
 
293
- if (sample.os && (
294
- this._model.operationSystem?.name !== sample.os.name ||
215
+ if (sample.os && (
216
+ this._model.operationSystem?.name !== sample.os.name ||
295
217
  this._model.operationSystem?.version !== sample.os.version ||
296
218
  this._model.operationSystem?.versionName !== sample.os.versionName
297
- )) {
298
- this._model.operationSystem = new Samples_ClientSample_OperationSystem({
299
- ...sample.os,
300
- });
219
+ )) {
220
+ this._model.operationSystem = sample.os;
301
221
 
302
- const callMetaReport = createCallMetaReport(
303
- this.serviceId,
304
- this.mediaUnitId,
305
- this.roomId,
306
- this.callId,
307
- this.clientId,
308
- {
309
- type: CallMetaType.OPERATION_SYSTEM,
310
- payload: sample.os,
311
- }, this.userId);
222
+ const callMetaReport = createCallMetaReport(
223
+ this.serviceId,
224
+ this.mediaUnitId,
225
+ this.roomId,
226
+ this.callId,
227
+ this.clientId,
228
+ {
229
+ type: CallMetaType.OPERATION_SYSTEM,
230
+ payload: sample.os,
231
+ }, this.userId);
312
232
 
313
- this.reports.addCallMetaReport(callMetaReport);
314
- executeSave = true;
315
- }
233
+ this.reports.addCallMetaReport(callMetaReport);
234
+ }
316
235
 
317
- if (sample.engine && (
318
- this._model.engine?.name !== sample.engine.name ||
236
+ if (sample.engine && (
237
+ this._model.engine?.name !== sample.engine.name ||
319
238
  this._model.engine?.version !== sample.engine.version
320
- )) {
321
- this._model.engine = new Samples_ClientSample_Engine({
322
- ...sample.engine,
323
- });
239
+ )) {
240
+ this._model.engine = sample.engine;
324
241
 
325
- const callMetaReport = createCallMetaReport(
326
- this.serviceId,
327
- this.mediaUnitId,
328
- this.roomId,
329
- this.callId,
330
- this.clientId,
331
- {
332
- type: CallMetaType.ENGINE,
333
- payload: sample.engine,
334
- }, this.userId);
242
+ const callMetaReport = createCallMetaReport(
243
+ this.serviceId,
244
+ this.mediaUnitId,
245
+ this.roomId,
246
+ this.callId,
247
+ this.clientId,
248
+ {
249
+ type: CallMetaType.ENGINE,
250
+ payload: sample.engine,
251
+ }, this.userId);
335
252
 
336
- this.reports.addCallMetaReport(callMetaReport);
337
- executeSave = true;
338
- }
253
+ this.reports.addCallMetaReport(callMetaReport);
254
+ }
339
255
 
340
- if (sample.platform && (
341
- this._model.platform?.model !== sample.platform.model ||
256
+ if (sample.platform && (
257
+ this._model.platform?.model !== sample.platform.model ||
342
258
  this._model.platform?.type !== sample.platform.type ||
343
259
  this._model.platform?.vendor !== sample.platform.vendor
344
- )) {
345
- this._model.platform = new Samples_ClientSample_Platform({
346
- ...sample.platform,
347
- });
260
+ )) {
261
+ this._model.platform = sample.platform;
348
262
 
349
- const callMetaReport = createCallMetaReport(
350
- this.serviceId,
351
- this.mediaUnitId,
352
- this.roomId,
353
- this.callId,
354
- this.clientId,
355
- {
356
- type: CallMetaType.PLATFORM,
357
- payload: sample.platform,
358
- }, this.userId);
263
+ const callMetaReport = createCallMetaReport(
264
+ this.serviceId,
265
+ this.mediaUnitId,
266
+ this.roomId,
267
+ this.callId,
268
+ this.clientId,
269
+ {
270
+ type: CallMetaType.PLATFORM,
271
+ payload: sample.platform,
272
+ }, this.userId);
359
273
 
360
- this.reports.addCallMetaReport(callMetaReport);
361
- executeSave = true;
362
- }
274
+ this.reports.addCallMetaReport(callMetaReport);
275
+ }
363
276
 
364
- if (sample.browser && (
365
- this._model.browser?.name !== sample.browser.name ||
277
+ if (sample.browser && (
278
+ this._model.browser?.name !== sample.browser.name ||
366
279
  this._model.browser?.version !== sample.browser.version
367
- )) {
368
- this._model.browser = new Samples_ClientSample_Browser({
369
- ...sample.browser,
370
- });
280
+ )) {
281
+ this._model.browser = sample.browser;
371
282
 
372
- const callMetaReport = createCallMetaReport(
373
- this.serviceId,
374
- this.mediaUnitId,
375
- this.roomId,
376
- this.callId,
377
- this.clientId,
378
- {
379
- type: CallMetaType.BROWSER,
380
- payload: sample.browser,
381
- }, this.userId);
283
+ const callMetaReport = createCallMetaReport(
284
+ this.serviceId,
285
+ this.mediaUnitId,
286
+ this.roomId,
287
+ this.callId,
288
+ this.clientId,
289
+ {
290
+ type: CallMetaType.BROWSER,
291
+ payload: sample.browser,
292
+ }, this.userId);
382
293
 
383
- this.reports.addCallMetaReport(callMetaReport);
384
- executeSave = true;
385
- }
386
-
387
- for (const mediaConstraint of sample.mediaConstraints ?? []) {
388
- const callMetaReport = createCallMetaReport(
389
- this.serviceId,
390
- this.mediaUnitId,
391
- this.roomId,
392
- this.callId,
393
- this.clientId,
394
- {
395
- type: CallMetaType.MEDIA_CONSTRAINT,
396
- payload: mediaConstraint,
397
- }, this.userId);
398
-
399
- this.reports.addCallMetaReport(callMetaReport);
400
- }
294
+ this.reports.addCallMetaReport(callMetaReport);
295
+ }
401
296
 
402
- for (const localSDP of sample.localSDPs ?? []) {
403
- const callMetaReport = createCallMetaReport(
404
- this.serviceId,
405
- this.mediaUnitId,
406
- this.roomId,
407
- this.callId,
408
- this.clientId,
409
- {
410
- type: CallMetaType.LOCAL_SDP,
411
- payload: localSDP,
412
- }, this.userId);
413
-
414
- this.reports.addCallMetaReport(callMetaReport);
415
- }
297
+ for (const mediaConstraint of sample.mediaConstraints ?? []) {
298
+ const callMetaReport = createCallMetaReport(
299
+ this.serviceId,
300
+ this.mediaUnitId,
301
+ this.roomId,
302
+ this.callId,
303
+ this.clientId,
304
+ {
305
+ type: CallMetaType.MEDIA_CONSTRAINT,
306
+ payload: mediaConstraint,
307
+ }, this.userId);
308
+
309
+ this.reports.addCallMetaReport(callMetaReport);
310
+ }
416
311
 
417
- for (const extensionStats of sample.extensionStats ?? []) {
418
- this.reports.addClientExtensionReport({
419
- serviceId: this.serviceId,
420
- mediaUnitId: this.mediaUnitId,
421
- roomId: this.roomId,
422
- callId: this.callId,
423
- clientId: this.clientId,
424
- userId: this.userId,
425
- timestamp: Date.now(),
426
- payload: extensionStats.payload,
427
- extensionType: extensionStats.type,
428
- });
429
- }
312
+ for (const localSDP of sample.localSDPs ?? []) {
313
+ const callMetaReport = createCallMetaReport(
314
+ this.serviceId,
315
+ this.mediaUnitId,
316
+ this.roomId,
317
+ this.callId,
318
+ this.clientId,
319
+ {
320
+ type: CallMetaType.LOCAL_SDP,
321
+ payload: localSDP,
322
+ }, this.userId);
323
+
324
+ this.reports.addCallMetaReport(callMetaReport);
325
+ }
430
326
 
431
- for (const { timestamp, ...callEvent } of sample.customCallEvents ?? []) {
432
- const peerConnection = this._peerConnections.get(callEvent.peerConnectionId ?? '');
433
-
434
- switch (callEvent.name) {
435
- case CallEventType.CLIENT_JOINED:
436
- if (timestamp) {
437
- this.created = timestamp;
438
- this._model.joined = BigInt(timestamp);
439
- await this._save();
440
- }
441
-
442
- break;
443
- case CallEventType.CLIENT_LEFT:
444
- this._left = timestamp ?? Date.now();
445
- break;
446
- case CallEventType.ICE_CONNECTION_STATE_CHANGED:
447
- peerConnection && callEvent.value && this.emit('iceconnectionstatechange', {
448
- peerConnection,
449
- state: callEvent.value,
450
- });
451
- break;
452
- case CallEventType.ICE_GATHERING_STATE_CHANGED:
453
- peerConnection && callEvent.value && this.emit('icegatheringstatechange', {
454
- peerConnection,
455
- state: callEvent.value,
456
- });
457
- break;
458
- case CallEventType.PEER_CONNECTION_STATE_CHANGED:
459
- peerConnection && callEvent.value && this.emit('connectionstatechange', {
460
- peerConnection,
461
- state: callEvent.value,
462
- });
463
- break;
464
- case CallEventType.PEER_CONNECTION_OPENED: {
465
- if (!callEvent.peerConnectionId) break;
466
- if (peerConnection) {
467
- peerConnection.created = timestamp ?? peerConnection.created;
468
- } else {
469
- this.ωpendingCreatedPeerConnectionTimestamp.set(callEvent.peerConnectionId, timestamp ?? Date.now());
470
- }
471
- break;
472
- }
473
- case CallEventType.MEDIA_TRACK_ADDED: {
474
- if (!callEvent.mediaTrackId) break;
475
- const track = peerConnection?.getTrack(callEvent.mediaTrackId);
476
-
477
- if (track) {
478
- track.created = timestamp ?? track.created;
479
- } else {
480
- this.ωpendingCreatedTracksTimestamp.set(callEvent.mediaTrackId, timestamp ?? Date.now());
481
- }
482
- }
327
+ for (const extensionStats of sample.extensionStats ?? []) {
328
+ this.reports.addClientExtensionReport({
329
+ serviceId: this.serviceId,
330
+ mediaUnitId: this.mediaUnitId,
331
+ roomId: this.roomId,
332
+ callId: this.callId,
333
+ clientId: this.clientId,
334
+ userId: this.userId,
335
+ timestamp: Date.now(),
336
+ payload: extensionStats.payload,
337
+ extensionType: extensionStats.type,
338
+ });
339
+ }
483
340
 
341
+ for (const { timestamp, ...callEvent } of sample.customCallEvents ?? []) {
342
+ switch (callEvent.name) {
343
+ case CallEventType.CLIENT_LEFT: {
344
+ this._left = timestamp;
345
+ break;
484
346
  }
485
-
486
- this.reports.addCallEventReport({
487
- serviceId: this.serviceId,
488
- mediaUnitId: this.mediaUnitId,
489
- roomId: this.roomId,
490
- callId: this.callId,
491
- clientId: this.clientId,
492
- userId: this.userId,
493
- timestamp: timestamp ?? Date.now(),
494
- ...callEvent,
495
- });
496
347
  }
348
+ this.reports.addCallEventReport({
349
+ serviceId: this.serviceId,
350
+ mediaUnitId: this.mediaUnitId,
351
+ roomId: this.roomId,
352
+ callId: this.callId,
353
+ clientId: this.clientId,
354
+ userId: this.userId,
355
+ timestamp: timestamp ?? Date.now(),
356
+ ...callEvent,
357
+ });
358
+ }
497
359
 
498
- for (const userMediaError of sample.userMediaErrors ?? []) {
499
- const callMetaReport = createCallMetaReport(
500
- this.serviceId,
501
- this.mediaUnitId,
502
- this.roomId,
503
- this.callId,
504
- this.clientId, {
505
- type: CallMetaType.USER_MEDIA_ERROR,
506
- payload: userMediaError,
507
- }, this.userId);
508
-
509
- this.reports.addCallMetaReport(callMetaReport);
510
- this.userMediaErrors.push(userMediaError);
511
- }
360
+ for (const userMediaError of sample.userMediaErrors ?? []) {
361
+ const callMetaReport = createCallMetaReport(
362
+ this.serviceId,
363
+ this.mediaUnitId,
364
+ this.roomId,
365
+ this.callId,
366
+ this.clientId, {
367
+ type: CallMetaType.USER_MEDIA_ERROR,
368
+ payload: userMediaError,
369
+ }, this.userId);
370
+
371
+ this.reports.addCallMetaReport(callMetaReport);
372
+ this.userMediaErrors.push(userMediaError);
373
+ }
512
374
 
513
- for (const certificate of sample.certificates ?? []) {
514
- const callMetaReport = createCallMetaReport(
515
- this.serviceId,
516
- this.mediaUnitId,
517
- this.roomId,
518
- this.callId,
519
- this.clientId, {
520
- type: CallMetaType.CERTIFICATE,
521
- payload: certificate,
522
- }, this.userId);
523
-
524
- this.reports.addCallMetaReport(callMetaReport);
525
- }
375
+ for (const certificate of sample.certificates ?? []) {
376
+ const callMetaReport = createCallMetaReport(
377
+ this.serviceId,
378
+ this.mediaUnitId,
379
+ this.roomId,
380
+ this.callId,
381
+ this.clientId, {
382
+ type: CallMetaType.CERTIFICATE,
383
+ payload: certificate,
384
+ }, this.userId);
385
+
386
+ this.reports.addCallMetaReport(callMetaReport);
387
+ }
526
388
 
527
- for (const codec of sample.codecs ?? []) {
528
- const callMetaReport = createCallMetaReport(
529
- this.serviceId,
530
- this.mediaUnitId,
531
- this.roomId,
532
- this.callId,
533
- this.clientId, {
534
- type: CallMetaType.CODEC,
535
- payload: codec,
536
- }, this.userId);
537
-
538
- this.reports.addCallMetaReport(callMetaReport);
539
- codec.mimeType && this.codecs.push(codec.mimeType);
540
- }
389
+ for (const codec of sample.codecs ?? []) {
390
+ const callMetaReport = createCallMetaReport(
391
+ this.serviceId,
392
+ this.mediaUnitId,
393
+ this.roomId,
394
+ this.callId,
395
+ this.clientId, {
396
+ type: CallMetaType.CODEC,
397
+ payload: codec,
398
+ }, this.userId);
399
+
400
+ this.reports.addCallMetaReport(callMetaReport);
401
+ codec.mimeType && this.codecs.push(codec.mimeType);
402
+ }
541
403
 
542
- for (const iceServer of sample.iceServers ?? []) {
543
- const callMetaReport = createCallMetaReport(
544
- this.serviceId,
545
- this.mediaUnitId,
546
- this.roomId,
547
- this.callId,
548
- this.clientId, {
549
- type: CallMetaType.ICE_SERVER,
550
- payload: iceServer,
551
- }, this.userId);
552
-
553
- this.reports.addCallMetaReport(callMetaReport);
554
- }
404
+ for (const iceServer of sample.iceServers ?? []) {
405
+ const callMetaReport = createCallMetaReport(
406
+ this.serviceId,
407
+ this.mediaUnitId,
408
+ this.roomId,
409
+ this.callId,
410
+ this.clientId, {
411
+ type: CallMetaType.ICE_SERVER,
412
+ payload: iceServer,
413
+ }, this.userId);
414
+
415
+ this.reports.addCallMetaReport(callMetaReport);
416
+ }
555
417
 
556
- for (const mediaDevice of sample.mediaDevices ?? []) {
557
- const callMetaReport = createCallMetaReport(
558
- this.serviceId,
559
- this.mediaUnitId,
560
- this.roomId,
561
- this.callId,
562
- this.clientId, {
563
- type: CallMetaType.MEDIA_DEVICE,
564
- payload: mediaDevice,
565
- }, this.userId);
566
-
567
- this.reports.addCallMetaReport(callMetaReport);
568
- mediaDevice.label && this.mediaDevices.push(mediaDevice.label);
569
- }
418
+ for (const mediaDevice of sample.mediaDevices ?? []) {
419
+ const callMetaReport = createCallMetaReport(
420
+ this.serviceId,
421
+ this.mediaUnitId,
422
+ this.roomId,
423
+ this.callId,
424
+ this.clientId, {
425
+ type: CallMetaType.MEDIA_DEVICE,
426
+ payload: mediaDevice,
427
+ }, this.userId);
428
+
429
+ this.reports.addCallMetaReport(callMetaReport);
430
+ mediaDevice.label && this.mediaDevices.push(mediaDevice.label);
431
+ }
570
432
 
571
- for (const mediaSource of sample.mediaSources ?? []) {
572
- const callMetaReport = createCallMetaReport(
573
- this.serviceId,
574
- this.mediaUnitId,
575
- this.roomId,
576
- this.callId,
577
- this.clientId, {
578
- type: CallMetaType.MEDIA_SOURCE,
579
- payload: mediaSource,
580
- }, this.userId);
581
-
582
- this.reports.addCallMetaReport(callMetaReport);
583
- }
433
+ for (const mediaSource of sample.mediaSources ?? []) {
434
+ const callMetaReport = createCallMetaReport(
435
+ this.serviceId,
436
+ this.mediaUnitId,
437
+ this.roomId,
438
+ this.callId,
439
+ this.clientId, {
440
+ type: CallMetaType.MEDIA_SOURCE,
441
+ payload: mediaSource,
442
+ }, this.userId);
443
+
444
+ this.reports.addCallMetaReport(callMetaReport);
445
+ }
584
446
 
585
- for (const transport of sample.pcTransports ?? []) {
586
- try {
587
- const peerConnection = this._peerConnections.get(transport.transportId) ?? await this._createPeerConnection(transport.peerConnectionId);
447
+ for (const transport of sample.pcTransports ?? []) {
448
+ try {
449
+ const peerConnection = this._peerConnections.get(transport.transportId) ?? this._createPeerConnection(transport.peerConnectionId);
588
450
 
589
- await peerConnection.update(transport, sample.timestamp);
590
- } catch (err) {
591
- logger.error(`Error creating peer connection: ${(err as Error)?.message}`);
592
- }
593
-
451
+ !peerConnection.label && transport.label && (peerConnection.label = transport.label);
452
+ peerConnection.update(transport, sample.timestamp);
453
+ } catch (err) {
454
+ logger.error(`Error creating peer connection: ${(err as Error)?.message}`);
594
455
  }
456
+
457
+ }
595
458
 
596
- for (const track of sample.inboundAudioTracks ?? []) {
597
- if (!track.peerConnectionId || !track.trackId) {
598
- logger.warn(`InboundAudioTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
459
+ for (const track of sample.inboundAudioTracks ?? []) {
460
+ if (!track.peerConnectionId || !track.trackId) {
461
+ logger.warn(`InboundAudioTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
599
462
 
600
- continue;
601
- }
463
+ continue;
464
+ }
602
465
 
603
- try {
604
- const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? await this._createPeerConnection(track.peerConnectionId);
466
+ try {
467
+ const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? this._createPeerConnection(track.peerConnectionId);
605
468
 
606
- if (!peerConnection) continue;
469
+ if (!peerConnection) continue;
607
470
 
608
- const inboundAudioTrack = peerConnection.inboundAudioTracks.get(track.trackId) ?? await peerConnection.createInboundAudioTrack({
609
- trackId: track.trackId,
610
- sfuStreamId: track.sfuStreamId,
611
- sfuSinkId: track.sfuSinkId,
612
- });
471
+ const inboundAudioTrack = peerConnection.inboundAudioTracks.get(track.trackId) ?? peerConnection.createInboundAudioTrack({
472
+ trackId: track.trackId,
473
+ sfuStreamId: track.sfuStreamId,
474
+ sfuSinkId: track.sfuSinkId,
475
+ });
613
476
 
614
- await inboundAudioTrack.update(track, sample.timestamp);
477
+ inboundAudioTrack.update(track, sample.timestamp);
615
478
 
616
- const remoteOutboundTrack = this.call.sfuStreamIdToOutboundAudioTrack.get(track.sfuStreamId ?? '');
479
+ const remoteOutboundTrack = this.call.sfuStreamIdToOutboundAudioTrack.get(track.sfuStreamId ?? '');
617
480
 
618
- if (remoteOutboundTrack && inboundAudioTrack.sfuStreamId && !remoteOutboundTrack.remoteInboundTracks.has(inboundAudioTrack.sfuStreamId)) {
619
- remoteOutboundTrack.connectInboundTrack(inboundAudioTrack);
620
- }
621
- } catch (err) {
622
- logger.error(`Error creating inbound audio track: ${(err as Error)?.message}`);
481
+ if (remoteOutboundTrack && inboundAudioTrack.sfuStreamId && !remoteOutboundTrack.remoteInboundTracks.has(inboundAudioTrack.sfuStreamId)) {
482
+ remoteOutboundTrack.connectInboundTrack(inboundAudioTrack);
623
483
  }
484
+ } catch (err) {
485
+ logger.error(`Error creating inbound audio track: ${(err as Error)?.message}`);
624
486
  }
487
+ }
625
488
 
626
- for (const track of sample.inboundVideoTracks ?? []) {
627
- if (!track.peerConnectionId || !track.trackId) {
628
- logger.warn(`InboundVideoTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
489
+ for (const track of sample.inboundVideoTracks ?? []) {
490
+ if (!track.peerConnectionId || !track.trackId) {
491
+ logger.warn(`InboundVideoTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
629
492
 
630
- continue;
631
- }
632
- if (isValidUuid(track.trackId) === false) {
633
- // mediasoup-probator trackId is not a valid UUID, no need to warn about it
634
- if (track.trackId === 'probator') continue;
635
- logger.warn(`InboundVideoTrack with invalid trackId: ${track.trackId}`);
636
- continue;
637
- }
493
+ continue;
494
+ }
495
+ if (isValidUuid(track.trackId) === false) {
496
+ // mediasoup-probator trackId is not a valid UUID, no need to warn about it
497
+ if (track.trackId === 'probator') continue;
498
+ logger.warn(`InboundVideoTrack with invalid trackId: ${track.trackId}`);
499
+ continue;
500
+ }
638
501
 
639
- try {
640
- const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? await this._createPeerConnection(track.peerConnectionId);
502
+ try {
503
+ const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? this._createPeerConnection(track.peerConnectionId);
641
504
 
642
- if (!peerConnection) continue;
505
+ if (!peerConnection) continue;
643
506
 
644
- const inboundVideoTrack = peerConnection.inboundVideoTracks.get(track.trackId) ?? await peerConnection.createInboundVideoTrack({
645
- trackId: track.trackId,
646
- sfuStreamId: track.sfuStreamId,
647
- sfuSinkId: track.sfuSinkId,
648
- });
507
+ const inboundVideoTrack = peerConnection.inboundVideoTracks.get(track.trackId) ?? peerConnection.createInboundVideoTrack({
508
+ trackId: track.trackId,
509
+ sfuStreamId: track.sfuStreamId,
510
+ sfuSinkId: track.sfuSinkId,
511
+ });
649
512
 
650
- await inboundVideoTrack.update(track, sample.timestamp);
513
+ inboundVideoTrack.update(track, sample.timestamp);
651
514
 
652
- const remoteOutboundTrack = this.call.sfuStreamIdToOutboundVideoTrack.get(inboundVideoTrack.sfuStreamId ?? '');
515
+ const remoteOutboundTrack = this.call.sfuStreamIdToOutboundVideoTrack.get(inboundVideoTrack.sfuStreamId ?? '');
653
516
 
654
- if (remoteOutboundTrack && inboundVideoTrack.sfuStreamId && !remoteOutboundTrack.remoteInboundTracks.has(inboundVideoTrack.sfuStreamId)) {
655
- remoteOutboundTrack.connectInboundTrack(inboundVideoTrack);
656
- }
657
- } catch (err) {
658
- logger.error(`Error creating inbound video track: ${(err as Error)?.message}`);
517
+ if (remoteOutboundTrack && inboundVideoTrack.sfuStreamId && !remoteOutboundTrack.remoteInboundTracks.has(inboundVideoTrack.sfuStreamId)) {
518
+ remoteOutboundTrack.connectInboundTrack(inboundVideoTrack);
659
519
  }
520
+ } catch (err) {
521
+ logger.error(`Error creating inbound video track: ${(err as Error)?.message}`);
660
522
  }
523
+ }
661
524
 
662
- for (const track of sample.outboundAudioTracks ?? []) {
663
- if (!track.peerConnectionId || !track.trackId) {
664
- logger.warn(`OutboundAudioTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
525
+ for (const track of sample.outboundAudioTracks ?? []) {
526
+ if (!track.peerConnectionId || !track.trackId) {
527
+ logger.warn(`OutboundAudioTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
665
528
 
666
- continue;
667
- }
529
+ continue;
530
+ }
668
531
 
669
- try {
670
- const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? await this._createPeerConnection(track.peerConnectionId);
532
+ try {
533
+ const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? this._createPeerConnection(track.peerConnectionId);
671
534
 
672
- if (!peerConnection) continue;
535
+ if (!peerConnection) continue;
673
536
 
674
- const outboundAudioTrack = peerConnection.outboundAudioTracks.get(track.trackId) ?? await peerConnection.createOutboundAudioTrack({
675
- trackId: track.trackId,
676
- sfuStreamId: track.sfuStreamId,
677
- });
678
-
679
- await outboundAudioTrack.update(track, sample.timestamp);
680
- } catch (err) {
681
- logger.error(`Error creating outbound audio track: ${(err as Error)?.message}`);
682
- }
683
-
537
+ const outboundAudioTrack = peerConnection.outboundAudioTracks.get(track.trackId) ?? peerConnection.createOutboundAudioTrack({
538
+ trackId: track.trackId,
539
+ sfuStreamId: track.sfuStreamId,
540
+ });
541
+
542
+ outboundAudioTrack.update(track, sample.timestamp);
543
+ } catch (err) {
544
+ logger.error(`Error creating outbound audio track: ${(err as Error)?.message}`);
684
545
  }
546
+
547
+ }
685
548
 
686
- for (const track of sample.outboundVideoTracks ?? []) {
687
- if (!track.peerConnectionId || !track.trackId) {
688
- logger.warn(`OutboundVideoTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
549
+ for (const track of sample.outboundVideoTracks ?? []) {
550
+ if (!track.peerConnectionId || !track.trackId) {
551
+ logger.warn(`OutboundVideoTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
689
552
 
690
- continue;
691
- }
553
+ continue;
554
+ }
692
555
 
693
- try {
694
- const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? await this._createPeerConnection(track.peerConnectionId);
556
+ try {
557
+ const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? this._createPeerConnection(track.peerConnectionId);
695
558
 
696
- if (!peerConnection) continue;
559
+ if (!peerConnection) continue;
697
560
 
698
- const outboundVideoTrack = peerConnection.outboundVideoTracks.get(track.trackId) ?? await peerConnection.createOutboundVideoTrack({
699
- trackId: track.trackId,
700
- sfuStreamId: track.sfuStreamId,
701
- });
561
+ const outboundVideoTrack = peerConnection.outboundVideoTracks.get(track.trackId) ?? peerConnection.createOutboundVideoTrack({
562
+ trackId: track.trackId,
563
+ sfuStreamId: track.sfuStreamId,
564
+ });
702
565
 
703
- await outboundVideoTrack.update(track, sample.timestamp);
566
+ outboundVideoTrack.update(track, sample.timestamp);
704
567
 
705
- } catch (err) {
706
- logger.error(`Error creating outbound video track: ${(err as Error)?.message}`);
707
- }
568
+ } catch (err) {
569
+ logger.error(`Error creating outbound video track: ${(err as Error)?.message}`);
708
570
  }
571
+ }
709
572
 
710
- for (const iceLocalCandidate of sample.iceLocalCandidates ?? []) {
711
- if (!iceLocalCandidate.peerConnectionId) {
712
- logger.warn(`Local ice candidate without peerConnectionId: ${JSON.stringify(iceLocalCandidate)}`);
713
- continue;
714
- }
715
- const peerConnection = this._peerConnections.get(iceLocalCandidate.peerConnectionId);
716
-
717
- if (!peerConnection) {
718
- logger.debug(`Peer connection ${iceLocalCandidate.peerConnectionId} not found for ice local candidate ${iceLocalCandidate.id}`);
719
- continue;
720
- }
573
+ for (const iceLocalCandidate of sample.iceLocalCandidates ?? []) {
574
+ if (!iceLocalCandidate.peerConnectionId) {
575
+ logger.warn(`Local ice candidate without peerConnectionId: ${JSON.stringify(iceLocalCandidate)}`);
576
+ continue;
577
+ }
578
+ const peerConnection = this._peerConnections.get(iceLocalCandidate.peerConnectionId);
721
579
 
722
- peerConnection.ICE.addLocalCandidate(iceLocalCandidate);
580
+ if (!peerConnection) {
581
+ logger.debug(`Peer connection ${iceLocalCandidate.peerConnectionId} not found for ice local candidate ${iceLocalCandidate.id}`);
582
+ continue;
723
583
  }
724
-
725
- for (const iceRemoteCandidate of sample.iceRemoteCandidates ?? []) {
726
- if (!iceRemoteCandidate.peerConnectionId) {
727
- logger.warn(`Remote ice candidate without peerConnectionId: ${JSON.stringify(iceRemoteCandidate)}`);
728
- continue;
729
- }
730
- const peerConnection = this._peerConnections.get(iceRemoteCandidate.peerConnectionId);
731
584
 
732
- if (!peerConnection) {
733
- logger.debug(`Peer connection ${iceRemoteCandidate.peerConnectionId} not found for ice remote candidate ${iceRemoteCandidate.id}`);
734
- continue;
735
- }
585
+ peerConnection.ICE.addLocalCandidate(iceLocalCandidate);
586
+ }
587
+
588
+ for (const iceRemoteCandidate of sample.iceRemoteCandidates ?? []) {
589
+ if (!iceRemoteCandidate.peerConnectionId) {
590
+ logger.warn(`Remote ice candidate without peerConnectionId: ${JSON.stringify(iceRemoteCandidate)}`);
591
+ continue;
592
+ }
593
+ const peerConnection = this._peerConnections.get(iceRemoteCandidate.peerConnectionId);
736
594
 
737
- peerConnection.ICE.addRemoteCandidate(iceRemoteCandidate);
595
+ if (!peerConnection) {
596
+ logger.debug(`Peer connection ${iceRemoteCandidate.peerConnectionId} not found for ice remote candidate ${iceRemoteCandidate.id}`);
597
+ continue;
738
598
  }
739
599
 
740
- for (const candidatePair of sample.iceCandidatePairs ?? []) {
741
- const peerConnection = this._peerConnections.get(candidatePair.peerConnectionId);
600
+ peerConnection.ICE.addRemoteCandidate(iceRemoteCandidate);
601
+ }
742
602
 
743
- if (!peerConnection) {
744
- logger.debug(`Peer connection ${candidatePair.peerConnectionId} not found for ice candidate pair ${candidatePair.localCandidateId}, ${candidatePair.remoteCandidateId}`);
603
+ for (const candidatePair of sample.iceCandidatePairs ?? []) {
604
+ const peerConnection = this._peerConnections.get(candidatePair.peerConnectionId);
745
605
 
746
- continue;
747
- }
606
+ if (!peerConnection) {
607
+ logger.debug(`Peer connection ${candidatePair.peerConnectionId} not found for ice candidate pair ${candidatePair.localCandidateId}, ${candidatePair.remoteCandidateId}`);
748
608
 
749
- peerConnection.ICE.update(candidatePair, sample.timestamp);
609
+ continue;
750
610
  }
751
611
 
752
- // close entries that are idle for too long
753
- if (this.call.observer.config.maxEntryIdleTimeInMs && this._updated < sample.timestamp) {
612
+ peerConnection.ICE.update(candidatePair, sample.timestamp);
613
+ }
754
614
 
755
- for (const peerConnection of this._peerConnections.values()) {
756
- if (this.call.observer.config.maxEntryIdleTimeInMs < sample.timestamp - peerConnection.updated) {
757
- logger.debug(`Closing peer connection ${peerConnection.peerConnectionId} due to inactivity`);
758
- peerConnection.close();
615
+ // close entries that are idle for too long
616
+ if (this.call.observer.config.maxEntryIdleTimeInMs && this._updated < sample.timestamp) {
759
617
 
760
- continue;
761
- }
762
- for (const track of peerConnection.inboundAudioTracks.values()) {
763
- if (this.call.observer.config.maxEntryIdleTimeInMs < sample.timestamp - track.updated) {
764
- logger.debug(`Closing inbound audio track ${track.trackId} due to inactivity`);
765
- track.close();
766
- }
618
+ for (const peerConnection of this._peerConnections.values()) {
619
+ if (this.call.observer.config.maxEntryIdleTimeInMs < sample.timestamp - peerConnection.updated) {
620
+ logger.debug(`Closing peer connection ${peerConnection.peerConnectionId} due to inactivity`);
621
+ peerConnection.close();
622
+
623
+ continue;
624
+ }
625
+ for (const track of peerConnection.inboundAudioTracks.values()) {
626
+ if (this.call.observer.config.maxEntryIdleTimeInMs < sample.timestamp - track.updated) {
627
+ logger.debug(`Closing inbound audio track ${track.trackId} due to inactivity`);
628
+ track.close();
767
629
  }
768
- for (const track of peerConnection.inboundVideoTracks.values()) {
769
- if (this.call.observer.config.maxEntryIdleTimeInMs < sample.timestamp - track.updated) {
770
- logger.debug(`Closing inbound video track ${track.trackId} due to inactivity`);
771
- track.close();
772
- }
630
+ }
631
+ for (const track of peerConnection.inboundVideoTracks.values()) {
632
+ if (this.call.observer.config.maxEntryIdleTimeInMs < sample.timestamp - track.updated) {
633
+ logger.debug(`Closing inbound video track ${track.trackId} due to inactivity`);
634
+ track.close();
773
635
  }
774
- for (const track of peerConnection.outboundAudioTracks.values()) {
775
- if (this.call.observer.config.maxEntryIdleTimeInMs < sample.timestamp - track.updated) {
776
- logger.debug(`Closing outbound audio track ${track.trackId} due to inactivity`);
777
- track.close();
778
- }
636
+ }
637
+ for (const track of peerConnection.outboundAudioTracks.values()) {
638
+ if (this.call.observer.config.maxEntryIdleTimeInMs < sample.timestamp - track.updated) {
639
+ logger.debug(`Closing outbound audio track ${track.trackId} due to inactivity`);
640
+ track.close();
779
641
  }
780
642
  }
781
643
  }
644
+ }
782
645
 
783
- // update metrics
784
- const wasUsingTURN = this.usingTURN;
785
-
786
- this.usingTURN = false;
787
- this.availableIncomingBitrate = 0;
788
- this.availableOutgoingBitrate = 0;
789
- this.totalSentBytes = 0;
790
- this.totalReceivedBytes = 0;
791
- this.totalOutboundPacketsSent = 0;
792
- this.totalInboundPacketsReceived = 0;
793
- this.totalInboundPacketsLost = 0;
794
- this.totalDataChannelBytesSent = 0;
795
- this.totalDataChannelBytesReceived = 0;
796
- this.sendingBitrate = 0;
797
- this.receivingBitrate = 0;
798
- let sumRttInMs = 0;
799
-
800
- for (const peerConnection of this._peerConnections.values()) {
801
- if (peerConnection.closed) continue;
802
- peerConnection.updateMetrics();
803
- this.totalSentBytes += peerConnection.totalSentAudioBytes + peerConnection.totalSentVideoBytes;
804
- this.totalReceivedBytes += peerConnection.totalReceivedAudioBytes + peerConnection.totalReceivedVideoBytes;
805
- this.totalOutboundPacketsSent += peerConnection.totalOutboundPacketsSent;
806
- this.totalInboundPacketsReceived += peerConnection.totalInboundPacketsReceived;
807
- this.totalInboundPacketsLost += peerConnection.totalInboundPacketsLost;
808
- this.totalDataChannelBytesSent += peerConnection.totalDataChannelBytesSent;
809
- this.totalDataChannelBytesReceived += peerConnection.totalDataChannelBytesReceived;
810
- this.sendingBitrate += peerConnection.sendingAudioBitrate + peerConnection.sendingVideoBitrate;
811
- this.receivingBitrate += peerConnection.receivingAudioBitrate + peerConnection.receivingVideoBitrate;
812
- this.availableIncomingBitrate += peerConnection.availableIncomingBitrate ?? 0;
813
- this.availableOutgoingBitrate += peerConnection.availableOutgoingBitrate ?? 0;
814
- sumRttInMs += peerConnection.avgRttInMs ?? 0;
815
-
816
- if (peerConnection.usingTURN) this.usingTURN = true;
817
- }
646
+ // update metrics
647
+ const wasUsingTURN = this.usingTURN;
648
+
649
+ this.usingTURN = false;
650
+ this.availableIncomingBitrate = 0;
651
+ this.availableOutgoingBitrate = 0;
652
+ this.totalSentBytes = 0;
653
+ this.totalReceivedBytes = 0;
654
+ this.totalOutboundPacketsSent = 0;
655
+ this.totalInboundPacketsReceived = 0;
656
+ this.totalInboundPacketsLost = 0;
657
+ this.totalDataChannelBytesSent = 0;
658
+ this.totalDataChannelBytesReceived = 0;
659
+ this.sendingBitrate = 0;
660
+ this.receivingBitrate = 0;
661
+ let sumRttInMs = 0;
662
+
663
+ for (const peerConnection of this._peerConnections.values()) {
664
+ if (peerConnection.closed) continue;
665
+ peerConnection.updateMetrics();
666
+ this.totalSentBytes += peerConnection.totalSentAudioBytes + peerConnection.totalSentVideoBytes;
667
+ this.totalReceivedBytes += peerConnection.totalReceivedAudioBytes + peerConnection.totalReceivedVideoBytes;
668
+ this.totalOutboundPacketsSent += peerConnection.totalOutboundPacketsSent;
669
+ this.totalInboundPacketsReceived += peerConnection.totalInboundPacketsReceived;
670
+ this.totalInboundPacketsLost += peerConnection.totalInboundPacketsLost;
671
+ this.totalDataChannelBytesSent += peerConnection.totalDataChannelBytesSent;
672
+ this.totalDataChannelBytesReceived += peerConnection.totalDataChannelBytesReceived;
673
+ this.sendingBitrate += peerConnection.sendingAudioBitrate + peerConnection.sendingVideoBitrate;
674
+ this.receivingBitrate += peerConnection.receivingAudioBitrate + peerConnection.receivingVideoBitrate;
675
+ this.availableIncomingBitrate += peerConnection.availableIncomingBitrate ?? 0;
676
+ this.availableOutgoingBitrate += peerConnection.availableOutgoingBitrate ?? 0;
677
+ sumRttInMs += peerConnection.avgRttInMs ?? 0;
678
+
679
+ if (peerConnection.usingTURN) this.usingTURN = true;
680
+ }
818
681
 
819
- this.avgRttInMs = this._peerConnections.size ? sumRttInMs / this._peerConnections.size : undefined;
682
+ this.avgRttInMs = this._peerConnections.size ? sumRttInMs / this._peerConnections.size : undefined;
820
683
 
821
- if (executeSave) await this._save();
822
- if (wasUsingTURN !== this.usingTURN) this.emit('usingturn', this.usingTURN);
684
+ if (wasUsingTURN !== this.usingTURN) this.emit('usingturn', this.usingTURN);
823
685
 
824
- this._updated = sample.timestamp;
825
- this.emit('update');
826
- }).finally(() => {
827
- --this._processingSample;
828
- });
686
+ this._updated = Date.now();
687
+ this.emit('update');
829
688
  }
830
689
 
831
- private async _createPeerConnection(peerConnectionId: string): Promise<ObservedPeerConnection> {
832
- const result = await ObservedPeerConnection.create({
690
+ private _createPeerConnection(peerConnectionId: string, label?: string): ObservedPeerConnection {
691
+ const result = new ObservedPeerConnection({
833
692
  peerConnectionId,
834
- }, this, this._storageProvider);
835
-
836
- const pendingTracksTimestamp = this.ωpendingCreatedTracksTimestamp.get(peerConnectionId);
837
-
838
- if (pendingTracksTimestamp) {
839
- result.created = pendingTracksTimestamp;
840
- this.ωpendingCreatedTracksTimestamp.delete(peerConnectionId);
841
- }
693
+ label,
694
+ }, this);
842
695
 
843
696
  const onNewSelectedCandidatePair = ({ localCandidate, remoteCandidate }: { localCandidate: IceLocalCandidate, remoteCandidate: IceRemoteCandidate }) => {
844
697
  this.emit('selectedcandidatepair', {
@@ -851,25 +704,15 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
851
704
  result.once('close', () => {
852
705
  result.ICE.off('new-selected-candidate-pair', onNewSelectedCandidatePair);
853
706
  this._peerConnections.delete(peerConnectionId);
854
- this._model.peerConnectionIds = this._model.peerConnectionIds.filter((id) => id !== peerConnectionId);
855
- this._save().catch(() => void 0);
856
707
  });
857
708
  result.ICE.on('new-selected-candidate-pair', onNewSelectedCandidatePair);
858
709
  this._peerConnections.set(peerConnectionId, result);
859
- this._model.peerConnectionIds.push(peerConnectionId);
860
- await this._save();
861
710
 
862
711
  this.emit('newpeerconnection', result);
863
712
 
864
713
  return result;
865
714
  }
866
715
 
867
- private async _save() {
868
- if (this._closed) throw new Error(`Client ${this.clientId} is closed`);
869
-
870
- return this._storageProvider.clientStorage.set(this.clientId, this._model);
871
- }
872
-
873
716
  private _addClientLeftReport() {
874
717
  if (this._left) return;
875
718
  this._left = Date.now();
@@ -880,7 +723,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
880
723
  this.roomId,
881
724
  this.callId,
882
725
  this.clientId,
883
- this.joined,
726
+ this._left,
884
727
  this.userId,
885
728
  this.marker,
886
729
  ));