@observertc/observer-js 0.30.4-beta → 0.30.5-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.
@@ -47,6 +47,7 @@ export type ObservedClientEvents = {
47
47
  remoteCandidate: IceRemoteCandidate;
48
48
  }
49
49
  ];
50
+ usingturn: [boolean];
50
51
  };
51
52
  export declare interface ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> {
52
53
  on<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;
@@ -70,7 +71,11 @@ export declare class ObservedClient<AppData extends Record<string, unknown> = Re
70
71
  private _acceptedSample;
71
72
  private _processingSample;
72
73
  private _timeZoneOffsetInHours?;
73
- private _leaveReported;
74
+ private _left?;
75
+ private _numberOfAcceptedUpdates;
76
+ usingTURN: boolean;
77
+ availableOutgoingBitrate: number;
78
+ availableIncomingBitrate: number;
74
79
  totalInboundPacketsLost: number;
75
80
  totalInboundPacketsReceived: number;
76
81
  totalOutboundPacketsSent: number;
@@ -78,7 +83,7 @@ export declare class ObservedClient<AppData extends Record<string, unknown> = Re
78
83
  totalDataChannelBytesReceived: number;
79
84
  totalSentBytes: number;
80
85
  totalReceivedBytes: number;
81
- avgRttInS?: number;
86
+ avgRttInMs?: number;
82
87
  sendingBitrate?: number;
83
88
  receivingBitrate?: number;
84
89
  readonly mediaDevices: string[];
@@ -103,7 +108,9 @@ export declare class ObservedClient<AppData extends Record<string, unknown> = Re
103
108
  get platform(): Samples_ClientSample_Platform | undefined;
104
109
  get acceptedSample(): number;
105
110
  get updated(): number;
111
+ get numberOfAcceptedUpdates(): number;
106
112
  get uptimeInMs(): number;
113
+ get durationInMs(): number | undefined;
107
114
  get closed(): boolean;
108
115
  get peerConnections(): ReadonlyMap<string, ObservedPeerConnection>;
109
116
  close(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"ObservedClient.d.ts","sourceRoot":"","sources":["../src/ObservedClient.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ObservedClient.d.ts","sourceRoot":"","sources":["../src/ObservedClient.ts"],"names":[],"mappings":"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"}
@@ -78,7 +78,6 @@ class ObservedClient extends events_1.EventEmitter {
78
78
  if (config.addJoinAndDetachClientEvent) {
79
79
  call.reports.addCallEventReport((0, callEventReports_1.createClientJoinedEventReport)(call.serviceId, result.mediaUnitId, call.roomId, call.callId, result.clientId, result.joined, result.userId, result.marker));
80
80
  }
81
- result.once('close', () => result._addClientLeftReport());
82
81
  return result;
83
82
  });
84
83
  }
@@ -96,7 +95,10 @@ class ObservedClient extends events_1.EventEmitter {
96
95
  this._updated = Date.now();
97
96
  this._acceptedSample = 0;
98
97
  this._processingSample = 0;
99
- this._leaveReported = false;
98
+ this._numberOfAcceptedUpdates = 0;
99
+ this.usingTURN = false;
100
+ this.availableOutgoingBitrate = 0;
101
+ this.availableIncomingBitrate = 0;
100
102
  this.totalInboundPacketsLost = 0;
101
103
  this.totalInboundPacketsReceived = 0;
102
104
  this.totalOutboundPacketsSent = 0;
@@ -164,9 +166,17 @@ class ObservedClient extends events_1.EventEmitter {
164
166
  get updated() {
165
167
  return this._updated;
166
168
  }
169
+ get numberOfAcceptedUpdates() {
170
+ return this._numberOfAcceptedUpdates;
171
+ }
167
172
  get uptimeInMs() {
168
173
  return this._updated - this.created;
169
174
  }
175
+ get durationInMs() {
176
+ if (!this._left)
177
+ return;
178
+ return this._left - this.joined;
179
+ }
170
180
  get closed() {
171
181
  return this._closed;
172
182
  }
@@ -177,6 +187,7 @@ class ObservedClient extends events_1.EventEmitter {
177
187
  if (this._closed)
178
188
  return;
179
189
  this._closed = true;
190
+ !this._left && this._addClientLeftReport();
180
191
  Array.from(this._peerConnections.values()).forEach((peerConnection) => peerConnection.close());
181
192
  this._execute(() => this._storageProvider.clientStorage.remove(this.clientId))
182
193
  .catch(() => void 0)
@@ -195,7 +206,8 @@ class ObservedClient extends events_1.EventEmitter {
195
206
  this.emit('processing-sample-overflow');
196
207
  }
197
208
  return this._execute(() => __awaiter(this, void 0, void 0, function* () {
198
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16;
209
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18;
210
+ ++this._numberOfAcceptedUpdates;
199
211
  for (const peerConnection of this._peerConnections.values()) {
200
212
  if (peerConnection.closed)
201
213
  continue;
@@ -283,15 +295,19 @@ class ObservedClient extends events_1.EventEmitter {
283
295
  extensionType: extensionStats.type,
284
296
  });
285
297
  }
286
- for (let _17 of (_p = sample.customCallEvents) !== null && _p !== void 0 ? _p : []) {
287
- const { timestamp } = _17, callEvent = __rest(_17, ["timestamp"]);
298
+ for (let _19 of (_p = sample.customCallEvents) !== null && _p !== void 0 ? _p : []) {
299
+ const { timestamp } = _19, callEvent = __rest(_19, ["timestamp"]);
288
300
  const peerConnection = this._peerConnections.get((_q = callEvent.peerConnectionId) !== null && _q !== void 0 ? _q : '');
289
301
  switch (callEvent.name) {
290
302
  case CallEventType_1.CallEventType.CLIENT_JOINED:
291
- this.created = timestamp !== null && timestamp !== void 0 ? timestamp : this.created;
303
+ if (timestamp) {
304
+ this.created = timestamp;
305
+ this._model.joined = BigInt(timestamp);
306
+ yield this._save();
307
+ }
292
308
  break;
293
309
  case CallEventType_1.CallEventType.CLIENT_LEFT:
294
- this._leaveReported = true;
310
+ this._left = timestamp !== null && timestamp !== void 0 ? timestamp : Date.now();
295
311
  break;
296
312
  case CallEventType_1.CallEventType.ICE_CONNECTION_STATE_CHANGED:
297
313
  peerConnection && callEvent.value && this.emit('iceconnectionstatechange', {
@@ -384,7 +400,7 @@ class ObservedClient extends events_1.EventEmitter {
384
400
  for (const transport of (_x = sample.pcTransports) !== null && _x !== void 0 ? _x : []) {
385
401
  try {
386
402
  const peerConnection = (_y = this._peerConnections.get(transport.transportId)) !== null && _y !== void 0 ? _y : yield this._createPeerConnection(transport.peerConnectionId);
387
- peerConnection.update(transport, sample.timestamp);
403
+ yield peerConnection.update(transport, sample.timestamp);
388
404
  }
389
405
  catch (err) {
390
406
  logger.error(`Error creating peer connection: ${err === null || err === void 0 ? void 0 : err.message}`);
@@ -544,6 +560,10 @@ class ObservedClient extends events_1.EventEmitter {
544
560
  }
545
561
  }
546
562
  // update metrics
563
+ const wasUsingTURN = this.usingTURN;
564
+ this.usingTURN = false;
565
+ this.availableIncomingBitrate = 0;
566
+ this.availableOutgoingBitrate = 0;
547
567
  this.totalSentBytes = 0;
548
568
  this.totalReceivedBytes = 0;
549
569
  this.totalOutboundPacketsSent = 0;
@@ -553,7 +573,7 @@ class ObservedClient extends events_1.EventEmitter {
553
573
  this.totalDataChannelBytesReceived = 0;
554
574
  this.sendingBitrate = 0;
555
575
  this.receivingBitrate = 0;
556
- let sumRttInS = 0;
576
+ let sumRttInMs = 0;
557
577
  for (const peerConnection of this._peerConnections.values()) {
558
578
  if (peerConnection.closed)
559
579
  continue;
@@ -567,11 +587,17 @@ class ObservedClient extends events_1.EventEmitter {
567
587
  this.totalDataChannelBytesReceived += peerConnection.totalDataChannelBytesReceived;
568
588
  this.sendingBitrate += peerConnection.sendingAudioBitrate + peerConnection.sendingVideoBitrate;
569
589
  this.receivingBitrate += peerConnection.receivingAudioBitrate + peerConnection.receivingVideoBitrate;
570
- sumRttInS += (_16 = peerConnection.avgRttInS) !== null && _16 !== void 0 ? _16 : 0;
590
+ this.availableIncomingBitrate += (_16 = peerConnection.availableIncomingBitrate) !== null && _16 !== void 0 ? _16 : 0;
591
+ this.availableOutgoingBitrate += (_17 = peerConnection.availableOutgoingBitrate) !== null && _17 !== void 0 ? _17 : 0;
592
+ sumRttInMs += (_18 = peerConnection.avgRttInMs) !== null && _18 !== void 0 ? _18 : 0;
593
+ if (peerConnection.usingTURN)
594
+ this.usingTURN = true;
571
595
  }
572
- this.avgRttInS = this._peerConnections.size ? sumRttInS / this._peerConnections.size : -1;
596
+ this.avgRttInMs = this._peerConnections.size ? sumRttInMs / this._peerConnections.size : undefined;
573
597
  if (executeSave)
574
598
  yield this._save();
599
+ if (wasUsingTURN !== this.usingTURN)
600
+ this.emit('usingturn', this.usingTURN);
575
601
  this._updated = sample.timestamp;
576
602
  this.emit('update');
577
603
  })).finally(() => {
@@ -618,9 +644,9 @@ class ObservedClient extends events_1.EventEmitter {
618
644
  });
619
645
  }
620
646
  _addClientLeftReport() {
621
- if (this._leaveReported)
647
+ if (this._left)
622
648
  return;
623
- this._leaveReported = true;
649
+ this._left = Date.now();
624
650
  this.reports.addCallEventReport((0, callEventReports_1.createClientLeftEventReport)(this.serviceId, this.mediaUnitId, this.roomId, this.callId, this.clientId, this.joined, this.userId, this.marker));
625
651
  }
626
652
  }
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import { EventEmitter } from 'events';
3
3
  import { StorageProvider } from './storages/StorageProvider';
4
- import { IceLocalCandidate, IceRemoteCandidate, PeerConnectionTransport } from '@observertc/sample-schemas-js';
4
+ import { PeerConnectionTransport } from '@observertc/sample-schemas-js';
5
5
  import { ObservedClient } from './ObservedClient';
6
6
  import { ObservedInboundTrack, ObservedInboundTrackConfig } from './ObservedInboundTrack';
7
7
  import { ObservedOutboundTrack, ObservedOutboundTrackConfig } from './ObservedOutboundTrack';
@@ -60,12 +60,10 @@ export declare class ObservedPeerConnection extends EventEmitter {
60
60
  sendingVideoBitrate: number;
61
61
  receivingAudioBitrate: number;
62
62
  receivingVideoBitrate: number;
63
- avgRttInS?: number;
63
+ avgRttInMs?: number;
64
64
  private _closed;
65
65
  private _updated;
66
66
  private _sample?;
67
- private _selectedLocalIceCandidate?;
68
- private _selectedRemoteIceCandidate?;
69
67
  readonly ICE: ObservedICE;
70
68
  private readonly _inboundAudioTracks;
71
69
  private readonly _inboundVideoTracks;
@@ -73,12 +71,14 @@ export declare class ObservedPeerConnection extends EventEmitter {
73
71
  private readonly _outboundVideoTracks;
74
72
  private readonly _execute;
75
73
  private constructor();
74
+ get label(): string | undefined;
75
+ get usingTURN(): boolean;
76
+ get availableOutgoingBitrate(): number | undefined;
77
+ get availableIncomingBitrate(): number | undefined;
76
78
  get peerConnectionId(): string;
77
79
  get reports(): import("./ReportsCollector").ReportsCollector;
78
80
  get stats(): ObservedPeerConnectionStats | undefined;
79
81
  get updated(): number;
80
- get selectedLocalIceCandidate(): IceLocalCandidate | undefined;
81
- get selectedRemoteIceCandidate(): IceRemoteCandidate | undefined;
82
82
  get inboundAudioTracks(): ReadonlyMap<string, ObservedInboundTrack<'audio'>>;
83
83
  get inboundVideoTracks(): ReadonlyMap<string, ObservedInboundTrack<'video'>>;
84
84
  get outboundAudioTracks(): ReadonlyMap<string, ObservedOutboundTrack<'audio'>>;
@@ -89,8 +89,7 @@ export declare class ObservedPeerConnection extends EventEmitter {
89
89
  getTrack(trackId: string): ObservedInboundTrack<'audio'> | ObservedInboundTrack<'video'> | ObservedOutboundTrack<'audio'> | ObservedOutboundTrack<'video'> | undefined;
90
90
  resetMetrics(): void;
91
91
  updateMetrics(): void;
92
- update(sample: PeerConnectionTransport, timestamp: number): void;
93
- updateSelectedCandidate(localCandidate: IceLocalCandidate, remoteCandidate: IceRemoteCandidate): void;
92
+ update(sample: PeerConnectionTransport, timestamp: number): Promise<void>;
94
93
  createInboundAudioTrack(config: Omit<ObservedInboundTrackConfig<'audio'>, 'kind'>): Promise<ObservedInboundTrack<'audio'>>;
95
94
  createInboundVideoTrack(config: Omit<ObservedInboundTrackConfig<'video'>, 'kind'>): Promise<ObservedInboundTrack<'video'>>;
96
95
  createOutboundAudioTrack(config: Omit<ObservedOutboundTrackConfig<'audio'>, 'kind'>): Promise<ObservedOutboundTrack<'audio'>>;
@@ -1 +1 @@
1
- {"version":3,"file":"ObservedPeerConnection.d.ts","sourceRoot":"","sources":["../src/ObservedPeerConnection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ObservedPeerConnection.d.ts","sourceRoot":"","sources":["../src/ObservedPeerConnection.ts"],"names":[],"mappings":"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"}
@@ -100,6 +100,21 @@ class ObservedPeerConnection extends events_1.EventEmitter {
100
100
  this._outboundVideoTracks = new Map();
101
101
  this._execute = (0, SingleExecutor_1.createSingleExecutor)();
102
102
  }
103
+ get label() {
104
+ return this._model.label;
105
+ }
106
+ get usingTURN() {
107
+ var _a, _b;
108
+ return ((_b = (_a = this.ICE.selectedRemoteCandidate) === null || _a === void 0 ? void 0 : _a.candidateType) === null || _b === void 0 ? void 0 : _b.toLowerCase()) === 'relay';
109
+ }
110
+ get availableOutgoingBitrate() {
111
+ var _a;
112
+ return (_a = this.ICE.stats) === null || _a === void 0 ? void 0 : _a.availableOutgoingBitrate;
113
+ }
114
+ get availableIncomingBitrate() {
115
+ var _a;
116
+ return (_a = this.ICE.stats) === null || _a === void 0 ? void 0 : _a.availableIncomingBitrate;
117
+ }
103
118
  get peerConnectionId() {
104
119
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
105
120
  return this._model.peerConnectionId;
@@ -113,12 +128,6 @@ class ObservedPeerConnection extends events_1.EventEmitter {
113
128
  get updated() {
114
129
  return this._updated;
115
130
  }
116
- get selectedLocalIceCandidate() {
117
- return this._selectedLocalIceCandidate;
118
- }
119
- get selectedRemoteIceCandidate() {
120
- return this._selectedRemoteIceCandidate;
121
- }
122
131
  get inboundAudioTracks() {
123
132
  return this._inboundAudioTracks;
124
133
  }
@@ -169,6 +178,7 @@ class ObservedPeerConnection extends events_1.EventEmitter {
169
178
  this._outboundVideoTracks.forEach((track) => track.resetMetrics());
170
179
  }
171
180
  updateMetrics() {
181
+ var _a;
172
182
  this.totalInboundPacketsLost = 0;
173
183
  this.totalInboundPacketsReceived = 0;
174
184
  this.totalOutboundPacketsSent = 0;
@@ -182,7 +192,7 @@ class ObservedPeerConnection extends events_1.EventEmitter {
182
192
  this.sendingVideoBitrate = 0;
183
193
  this.receivingAudioBitrate = 0;
184
194
  this.receivingVideoBitrate = 0;
185
- let sumRttInS = 0;
195
+ let sumRttInMs = 0;
186
196
  this._inboundAudioTracks.forEach((track) => {
187
197
  var _a;
188
198
  this.deltaInboundLostPackets += track.deltaLostPackets;
@@ -195,7 +205,7 @@ class ObservedPeerConnection extends events_1.EventEmitter {
195
205
  this.totalInboundPacketsReceived += track.totalReceivedPackets;
196
206
  this.totalReceivedAudioBytes += track.totalBytesReceived;
197
207
  this.totalReceivedAudioPacktes += track.totalReceivedPackets;
198
- sumRttInS = ((_a = track.rttInMs) !== null && _a !== void 0 ? _a : 0) / 1000.0;
208
+ sumRttInMs = ((_a = track.rttInMs) !== null && _a !== void 0 ? _a : 0);
199
209
  });
200
210
  this._inboundVideoTracks.forEach((track) => {
201
211
  var _a;
@@ -209,7 +219,7 @@ class ObservedPeerConnection extends events_1.EventEmitter {
209
219
  this.totalInboundPacketsReceived += track.totalReceivedPackets;
210
220
  this.totalReceivedVideoBytes += track.totalBytesReceived;
211
221
  this.totalReceivedVideoPackets += track.totalReceivedPackets;
212
- sumRttInS = ((_a = track.rttInMs) !== null && _a !== void 0 ? _a : 0) / 1000.0;
222
+ sumRttInMs = ((_a = track.rttInMs) !== null && _a !== void 0 ? _a : 0);
213
223
  });
214
224
  this._outboundAudioTracks.forEach((track) => {
215
225
  var _a;
@@ -221,7 +231,7 @@ class ObservedPeerConnection extends events_1.EventEmitter {
221
231
  this.totalOutboundPacketsSent += track.totalSentPackets;
222
232
  this.totalSentAudioBytes += track.totalSentBytes;
223
233
  this.totalSentAudioPackets += track.totalSentPackets;
224
- sumRttInS = ((_a = track.rttInMs) !== null && _a !== void 0 ? _a : 0) / 1000.0;
234
+ sumRttInMs = ((_a = track.rttInMs) !== null && _a !== void 0 ? _a : 0);
225
235
  });
226
236
  this._outboundVideoTracks.forEach((track) => {
227
237
  var _a;
@@ -233,25 +243,32 @@ class ObservedPeerConnection extends events_1.EventEmitter {
233
243
  this.totalOutboundPacketsSent += track.totalSentPackets;
234
244
  this.totalSentVideoBytes += track.totalSentBytes;
235
245
  this.totalSentVideoPackets += track.totalSentPackets;
236
- sumRttInS = ((_a = track.rttInMs) !== null && _a !== void 0 ? _a : 0) / 1000.0;
246
+ sumRttInMs = ((_a = track.rttInMs) !== null && _a !== void 0 ? _a : 0);
237
247
  });
238
- const nrOfBelongings = this._inboundAudioTracks.size + this._inboundVideoTracks.size + this._outboundAudioTracks.size + this._outboundVideoTracks.size;
239
- this.avgRttInS = 0 < nrOfBelongings ? sumRttInS / nrOfBelongings : undefined;
248
+ const iceRttInMs = (_a = this.ICE.stats) === null || _a === void 0 ? void 0 : _a.currentRoundTripTime;
249
+ let nrOfBelongings = this._inboundAudioTracks.size + this._inboundVideoTracks.size + this._outboundAudioTracks.size + this._outboundVideoTracks.size;
250
+ if (iceRttInMs) {
251
+ sumRttInMs += iceRttInMs;
252
+ nrOfBelongings += 1;
253
+ }
254
+ this.avgRttInMs = 0 < nrOfBelongings ? sumRttInMs / nrOfBelongings : undefined;
240
255
  }
241
256
  update(sample, timestamp) {
242
- if (this._closed)
243
- return;
244
- if (sample.peerConnectionId !== this._model.peerConnectionId)
245
- throw new Error(`TransportId mismatch. PeerConnectionId: ${this._model.peerConnectionId} TransportId: ${sample.transportId}`);
246
- this._sample = sample;
247
- const report = Object.assign(Object.assign({ serviceId: this.client.call.serviceId, roomId: this.client.call.roomId, callId: this.client.call.callId, clientId: this.client.clientId, userId: this.client.userId, mediaUnitId: this.client.mediaUnitId }, sample), { timestamp, sampleSeq: -1 });
248
- this.reports.addPeerConnectionTransportReports(report);
249
- this._updated = timestamp;
250
- this.emit('update');
251
- }
252
- updateSelectedCandidate(localCandidate, remoteCandidate) {
253
- this._selectedLocalIceCandidate = localCandidate;
254
- this._selectedRemoteIceCandidate = remoteCandidate;
257
+ return __awaiter(this, void 0, void 0, function* () {
258
+ if (this._closed)
259
+ return;
260
+ if (sample.peerConnectionId !== this._model.peerConnectionId)
261
+ throw new Error(`TransportId mismatch. PeerConnectionId: ${this._model.peerConnectionId} TransportId: ${sample.transportId}`);
262
+ this._sample = sample;
263
+ if (this._model.label !== sample.label) {
264
+ this._model.label = sample.label;
265
+ yield this._save().catch(() => void 0);
266
+ }
267
+ const report = Object.assign(Object.assign({ serviceId: this.client.call.serviceId, roomId: this.client.call.roomId, callId: this.client.call.callId, clientId: this.client.clientId, userId: this.client.userId, mediaUnitId: this.client.mediaUnitId }, sample), { timestamp, sampleSeq: -1 });
268
+ this.reports.addPeerConnectionTransportReports(report);
269
+ this._updated = timestamp;
270
+ this.emit('update');
271
+ });
255
272
  }
256
273
  createInboundAudioTrack(config) {
257
274
  return __awaiter(this, void 0, void 0, function* () {
@@ -0,0 +1,26 @@
1
+ /// <reference types="node" />
2
+ import { EventEmitter } from 'events';
3
+ import { Observer } from './Observer';
4
+ export type ObservedSfuConfig<AppData extends Record<string, unknown> = Record<string, unknown>> = {
5
+ serviceId: string;
6
+ sfuId: string;
7
+ joined?: number;
8
+ appData: AppData;
9
+ };
10
+ export type ObservedSfuEvents = {
11
+ update: [];
12
+ close: [];
13
+ };
14
+ export declare interface ObservedSfu {
15
+ on<U extends keyof ObservedSfuEvents>(event: U, listener: (...args: ObservedSfuEvents[U]) => void): this;
16
+ off<U extends keyof ObservedSfuEvents>(event: U, listener: (...args: ObservedSfuEvents[U]) => void): this;
17
+ once<U extends keyof ObservedSfuEvents>(event: U, listener: (...args: ObservedSfuEvents[U]) => void): this;
18
+ emit<U extends keyof ObservedSfuEvents>(event: U, ...args: ObservedSfuEvents[U]): boolean;
19
+ }
20
+ export declare class ObservedSfu<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {
21
+ private readonly _model;
22
+ readonly appData: AppData;
23
+ static create<T extends Record<string, unknown> = Record<string, unknown>>(config: ObservedSfuConfig<T>, observer: Observer): Promise<ObservedSfu<T>>;
24
+ private constructor();
25
+ }
26
+ //# sourceMappingURL=ObservedSfu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ObservedSfu.d.ts","sourceRoot":"","sources":["../src/ObservedSfu.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,MAAM,iBAAiB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IAClG,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,MAAM,EAAE,EAAE,CAAC;IACX,KAAK,EAAE,EAAE,CAAC;CACV,CAAC;AAEF,MAAM,CAAC,OAAO,WAAW,WAAW;IACnC,EAAE,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACzG,GAAG,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1G,IAAI,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAC3G,IAAI,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;CAC1F;AAED,qBAAa,WAAW,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAE,SAAQ,YAAY;IAyB9G,OAAO,CAAC,QAAQ,CAAC,MAAM;aACP,OAAO,EAAE,OAAO;WAzBb,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrF,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAC5B,QAAQ,EAAE,QAAQ;IAqBnB,OAAO;CAOP"}
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.ObservedSfu = void 0;
36
+ const events_1 = require("events");
37
+ const Models = __importStar(require("./models/Models"));
38
+ class ObservedSfu extends events_1.EventEmitter {
39
+ static create(config, observer) {
40
+ var _a;
41
+ return __awaiter(this, void 0, void 0, function* () {
42
+ const model = new Models.Sfu({
43
+ serviceId: config.serviceId,
44
+ sfuId: config.sfuId,
45
+ sfuTransportIds: [],
46
+ joined: BigInt((_a = config.joined) !== null && _a !== void 0 ? _a : Date.now()),
47
+ });
48
+ const result = new ObservedSfu(model, config.appData);
49
+ const alreadyInserted = yield observer.storage.sfuStorage.insert(config.sfuId, model);
50
+ if (alreadyInserted)
51
+ throw new Error(`Sfu with id ${config.sfuId} already exists`);
52
+ return result;
53
+ });
54
+ }
55
+ constructor(_model, appData) {
56
+ super();
57
+ this._model = _model;
58
+ this.appData = appData;
59
+ }
60
+ }
61
+ exports.ObservedSfu = ObservedSfu;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@observertc/observer-js",
3
- "version": "0.30.4-beta",
3
+ "version": "0.30.5-beta",
4
4
  "description": "Server Side NodeJS Library for processing ObserveRTC Samples",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -51,6 +51,7 @@ export type ObservedClientEvents = {
51
51
  localCandidate: IceLocalCandidate,
52
52
  remoteCandidate: IceRemoteCandidate,
53
53
  }],
54
+ usingturn: [boolean],
54
55
  };
55
56
 
56
57
  export declare interface ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> {
@@ -100,8 +101,6 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
100
101
  ));
101
102
  }
102
103
 
103
- result.once('close', () => result._addClientLeftReport());
104
-
105
104
  return result;
106
105
  }
107
106
 
@@ -116,8 +115,12 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
116
115
  private _acceptedSample = 0;
117
116
  private _processingSample = 0;
118
117
  private _timeZoneOffsetInHours?: number;
119
- private _leaveReported = false;
118
+ private _left?: number;
119
+ private _numberOfAcceptedUpdates = 0;
120
120
 
121
+ public usingTURN = false;
122
+ public availableOutgoingBitrate = 0;
123
+ public availableIncomingBitrate = 0;
121
124
  public totalInboundPacketsLost = 0;
122
125
  public totalInboundPacketsReceived = 0;
123
126
  public totalOutboundPacketsSent = 0;
@@ -126,7 +129,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
126
129
  public totalSentBytes = 0;
127
130
  public totalReceivedBytes = 0;
128
131
 
129
- public avgRttInS?: number;
132
+ public avgRttInMs?: number;
130
133
  public sendingBitrate?: number;
131
134
  public receivingBitrate?: number;
132
135
 
@@ -136,7 +139,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
136
139
 
137
140
  public readonly ωpendingCreatedTracksTimestamp = new Map<string, number>();
138
141
  public readonly ωpendingCreatedPeerConnectionTimestamp = new Map<string, number>();
139
-
142
+
140
143
  private constructor(
141
144
  private readonly _model: Models.Client,
142
145
  public readonly call: ObservedCall,
@@ -216,10 +219,20 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
216
219
  return this._updated;
217
220
  }
218
221
 
222
+ public get numberOfAcceptedUpdates() {
223
+ return this._numberOfAcceptedUpdates;
224
+ }
225
+
219
226
  public get uptimeInMs() {
220
227
  return this._updated - this.created;
221
228
  }
222
229
 
230
+ public get durationInMs(): number | undefined {
231
+ if (!this._left) return;
232
+
233
+ return this._left - this.joined;
234
+ }
235
+
223
236
  public get closed() {
224
237
  return this._closed;
225
238
  }
@@ -232,6 +245,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
232
245
  if (this._closed) return;
233
246
  this._closed = true;
234
247
 
248
+ !this._left && this._addClientLeftReport();
249
+
235
250
  Array.from(this._peerConnections.values()).forEach((peerConnection) => peerConnection.close());
236
251
 
237
252
  this._execute(() => this._storageProvider.clientStorage.remove(this.clientId))
@@ -252,6 +267,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
252
267
  }
253
268
 
254
269
  return this._execute(async () => {
270
+ ++this._numberOfAcceptedUpdates;
271
+
255
272
  for (const peerConnection of this._peerConnections.values()) {
256
273
  if (peerConnection.closed) continue;
257
274
  peerConnection.resetMetrics();
@@ -416,10 +433,15 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
416
433
 
417
434
  switch (callEvent.name) {
418
435
  case CallEventType.CLIENT_JOINED:
419
- this.created = timestamp ?? this.created;
436
+ if (timestamp) {
437
+ this.created = timestamp;
438
+ this._model.joined = BigInt(timestamp);
439
+ await this._save();
440
+ }
441
+
420
442
  break;
421
443
  case CallEventType.CLIENT_LEFT:
422
- this._leaveReported = true;
444
+ this._left = timestamp ?? Date.now();
423
445
  break;
424
446
  case CallEventType.ICE_CONNECTION_STATE_CHANGED:
425
447
  peerConnection && callEvent.value && this.emit('iceconnectionstatechange', {
@@ -564,7 +586,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
564
586
  try {
565
587
  const peerConnection = this._peerConnections.get(transport.transportId) ?? await this._createPeerConnection(transport.peerConnectionId);
566
588
 
567
- peerConnection.update(transport, sample.timestamp);
589
+ await peerConnection.update(transport, sample.timestamp);
568
590
  } catch (err) {
569
591
  logger.error(`Error creating peer connection: ${(err as Error)?.message}`);
570
592
  }
@@ -759,6 +781,11 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
759
781
  }
760
782
 
761
783
  // update metrics
784
+ const wasUsingTURN = this.usingTURN;
785
+
786
+ this.usingTURN = false;
787
+ this.availableIncomingBitrate = 0;
788
+ this.availableOutgoingBitrate = 0;
762
789
  this.totalSentBytes = 0;
763
790
  this.totalReceivedBytes = 0;
764
791
  this.totalOutboundPacketsSent = 0;
@@ -768,7 +795,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
768
795
  this.totalDataChannelBytesReceived = 0;
769
796
  this.sendingBitrate = 0;
770
797
  this.receivingBitrate = 0;
771
- let sumRttInS = 0;
798
+ let sumRttInMs = 0;
772
799
 
773
800
  for (const peerConnection of this._peerConnections.values()) {
774
801
  if (peerConnection.closed) continue;
@@ -782,12 +809,17 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
782
809
  this.totalDataChannelBytesReceived += peerConnection.totalDataChannelBytesReceived;
783
810
  this.sendingBitrate += peerConnection.sendingAudioBitrate + peerConnection.sendingVideoBitrate;
784
811
  this.receivingBitrate += peerConnection.receivingAudioBitrate + peerConnection.receivingVideoBitrate;
785
- sumRttInS += peerConnection.avgRttInS ?? 0;
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;
786
817
  }
787
818
 
788
- this.avgRttInS = this._peerConnections.size ? sumRttInS / this._peerConnections.size : -1;
819
+ this.avgRttInMs = this._peerConnections.size ? sumRttInMs / this._peerConnections.size : undefined;
789
820
 
790
821
  if (executeSave) await this._save();
822
+ if (wasUsingTURN !== this.usingTURN) this.emit('usingturn', this.usingTURN);
791
823
 
792
824
  this._updated = sample.timestamp;
793
825
  this.emit('update');
@@ -839,8 +871,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
839
871
  }
840
872
 
841
873
  private _addClientLeftReport() {
842
- if (this._leaveReported) return;
843
- this._leaveReported = true;
874
+ if (this._left) return;
875
+ this._left = Date.now();
844
876
 
845
877
  this.reports.addCallEventReport(createClientLeftEventReport(
846
878
  this.serviceId,
@@ -147,7 +147,7 @@ export class ObservedICE extends EventEmitter {
147
147
  if (!candidatePair.nominated) return;
148
148
 
149
149
  this._stats = candidatePair;
150
-
150
+
151
151
  if (
152
152
  candidatePair.localCandidateId &&
153
153
  candidatePair.localCandidateId !== this._selectedLocalCandidateId &&
@@ -1,7 +1,7 @@
1
1
  import { EventEmitter } from 'events';
2
2
  import * as Models from './models/Models';
3
3
  import { StorageProvider } from './storages/StorageProvider';
4
- import { IceLocalCandidate, IceRemoteCandidate, PeerConnectionTransport } from '@observertc/sample-schemas-js';
4
+ import { PeerConnectionTransport } from '@observertc/sample-schemas-js';
5
5
  import { ObservedClient } from './ObservedClient';
6
6
  import { ObservedInboundTrack, ObservedInboundTrackConfig } from './ObservedInboundTrack';
7
7
  import { ObservedOutboundTrack, ObservedOutboundTrackConfig } from './ObservedOutboundTrack';
@@ -88,13 +88,11 @@ export class ObservedPeerConnection extends EventEmitter {
88
88
  public receivingAudioBitrate = 0;
89
89
  public receivingVideoBitrate = 0;
90
90
 
91
- public avgRttInS?: number;
91
+ public avgRttInMs?: number;
92
92
 
93
93
  private _closed = false;
94
94
  private _updated = Date.now();
95
95
  private _sample?: ObservedPeerConnectionStats;
96
- private _selectedLocalIceCandidate?: IceLocalCandidate;
97
- private _selectedRemoteIceCandidate?: IceRemoteCandidate;
98
96
 
99
97
  public readonly ICE = ObservedICE.create(this);
100
98
  private readonly _inboundAudioTracks = new Map<string, ObservedInboundTrack<'audio'>>();
@@ -111,6 +109,22 @@ export class ObservedPeerConnection extends EventEmitter {
111
109
  super();
112
110
  }
113
111
 
112
+ public get label() {
113
+ return this._model.label;
114
+ }
115
+
116
+ public get usingTURN() {
117
+ return this.ICE.selectedRemoteCandidate?.candidateType?.toLowerCase() === 'relay';
118
+ }
119
+
120
+ public get availableOutgoingBitrate() {
121
+ return this.ICE.stats?.availableOutgoingBitrate;
122
+ }
123
+
124
+ public get availableIncomingBitrate() {
125
+ return this.ICE.stats?.availableIncomingBitrate;
126
+ }
127
+
114
128
  public get peerConnectionId(): string {
115
129
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
116
130
  return this._model.peerConnectionId!;
@@ -128,14 +142,6 @@ export class ObservedPeerConnection extends EventEmitter {
128
142
  return this._updated;
129
143
  }
130
144
 
131
- public get selectedLocalIceCandidate() {
132
- return this._selectedLocalIceCandidate;
133
- }
134
-
135
- public get selectedRemoteIceCandidate() {
136
- return this._selectedRemoteIceCandidate;
137
- }
138
-
139
145
  public get inboundAudioTracks(): ReadonlyMap<string, ObservedInboundTrack<'audio'>> {
140
146
  return this._inboundAudioTracks;
141
147
  }
@@ -212,7 +218,7 @@ export class ObservedPeerConnection extends EventEmitter {
212
218
  this.receivingAudioBitrate = 0;
213
219
  this.receivingVideoBitrate = 0;
214
220
 
215
- let sumRttInS = 0;
221
+ let sumRttInMs = 0;
216
222
 
217
223
  this._inboundAudioTracks.forEach((track) => {
218
224
  this.deltaInboundLostPackets += track.deltaLostPackets;
@@ -229,7 +235,7 @@ export class ObservedPeerConnection extends EventEmitter {
229
235
  this.totalReceivedAudioBytes += track.totalBytesReceived;
230
236
  this.totalReceivedAudioPacktes += track.totalReceivedPackets;
231
237
 
232
- sumRttInS = (track.rttInMs ?? 0) / 1000.0;
238
+ sumRttInMs = (track.rttInMs ?? 0);
233
239
  });
234
240
 
235
241
  this._inboundVideoTracks.forEach((track) => {
@@ -247,7 +253,7 @@ export class ObservedPeerConnection extends EventEmitter {
247
253
  this.totalReceivedVideoBytes += track.totalBytesReceived;
248
254
  this.totalReceivedVideoPackets += track.totalReceivedPackets;
249
255
 
250
- sumRttInS = (track.rttInMs ?? 0) / 1000.0;
256
+ sumRttInMs = (track.rttInMs ?? 0);
251
257
  });
252
258
 
253
259
  this._outboundAudioTracks.forEach((track) => {
@@ -263,7 +269,7 @@ export class ObservedPeerConnection extends EventEmitter {
263
269
  this.totalSentAudioBytes += track.totalSentBytes;
264
270
  this.totalSentAudioPackets += track.totalSentPackets;
265
271
 
266
- sumRttInS = (track.rttInMs ?? 0) / 1000.0;
272
+ sumRttInMs = (track.rttInMs ?? 0);
267
273
  });
268
274
 
269
275
  this._outboundVideoTracks.forEach((track) => {
@@ -279,19 +285,27 @@ export class ObservedPeerConnection extends EventEmitter {
279
285
  this.totalSentVideoBytes += track.totalSentBytes;
280
286
  this.totalSentVideoPackets += track.totalSentPackets;
281
287
 
282
- sumRttInS = (track.rttInMs ?? 0) / 1000.0;
288
+ sumRttInMs = (track.rttInMs ?? 0);
283
289
  });
290
+ const iceRttInMs = this.ICE.stats?.currentRoundTripTime;
291
+ let nrOfBelongings = this._inboundAudioTracks.size + this._inboundVideoTracks.size + this._outboundAudioTracks.size + this._outboundVideoTracks.size;
284
292
 
285
- const nrOfBelongings = this._inboundAudioTracks.size + this._inboundVideoTracks.size + this._outboundAudioTracks.size + this._outboundVideoTracks.size;
286
-
287
- this.avgRttInS = 0 < nrOfBelongings ? sumRttInS / nrOfBelongings : undefined;
293
+ if (iceRttInMs) {
294
+ sumRttInMs += iceRttInMs;
295
+ nrOfBelongings += 1;
296
+ }
297
+ this.avgRttInMs = 0 < nrOfBelongings ? sumRttInMs / nrOfBelongings : undefined;
288
298
  }
289
299
 
290
- public update(sample: PeerConnectionTransport, timestamp: number) {
300
+ public async update(sample: PeerConnectionTransport, timestamp: number) {
291
301
  if (this._closed) return;
292
302
  if (sample.peerConnectionId !== this._model.peerConnectionId) throw new Error(`TransportId mismatch. PeerConnectionId: ${ this._model.peerConnectionId } TransportId: ${ sample.transportId}`);
293
303
 
294
304
  this._sample = sample;
305
+ if (this._model.label !== sample.label) {
306
+ this._model.label = sample.label;
307
+ await this._save().catch(() => void 0);
308
+ }
295
309
 
296
310
  const report: PeerConnectionTransportReport = {
297
311
  serviceId: this.client.call.serviceId,
@@ -311,11 +325,6 @@ export class ObservedPeerConnection extends EventEmitter {
311
325
  this.emit('update');
312
326
  }
313
327
 
314
- public updateSelectedCandidate(localCandidate: IceLocalCandidate, remoteCandidate: IceRemoteCandidate) {
315
- this._selectedLocalIceCandidate = localCandidate;
316
- this._selectedRemoteIceCandidate = remoteCandidate;
317
- }
318
-
319
328
  public async createInboundAudioTrack(config: Omit<ObservedInboundTrackConfig<'audio'>, 'kind'>): Promise<ObservedInboundTrack<'audio'>> {
320
329
  if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
321
330
 
@@ -0,0 +1,55 @@
1
+ import { EventEmitter } from 'events';
2
+ import * as Models from './models/Models';
3
+ import { Observer } from './Observer';
4
+
5
+ export type ObservedSfuConfig<AppData extends Record<string, unknown> = Record<string, unknown>> = {
6
+ serviceId: string;
7
+ sfuId: string;
8
+ joined?: number;
9
+ appData: AppData;
10
+ };
11
+
12
+ export type ObservedSfuEvents = {
13
+ update: [],
14
+ close: [],
15
+ };
16
+
17
+ export declare interface ObservedSfu {
18
+ on<U extends keyof ObservedSfuEvents>(event: U, listener: (...args: ObservedSfuEvents[U]) => void): this;
19
+ off<U extends keyof ObservedSfuEvents>(event: U, listener: (...args: ObservedSfuEvents[U]) => void): this;
20
+ once<U extends keyof ObservedSfuEvents>(event: U, listener: (...args: ObservedSfuEvents[U]) => void): this;
21
+ emit<U extends keyof ObservedSfuEvents>(event: U, ...args: ObservedSfuEvents[U]): boolean;
22
+ }
23
+
24
+ export class ObservedSfu<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {
25
+ public static async create<T extends Record<string, unknown> = Record<string, unknown>>(
26
+ config: ObservedSfuConfig<T>,
27
+ observer: Observer,
28
+ // reportsCollector: ReportsCollector,
29
+ ) {
30
+ const model = new Models.Sfu({
31
+ serviceId: config.serviceId,
32
+ sfuId: config.sfuId,
33
+ sfuTransportIds: [],
34
+ joined: BigInt(config.joined ?? Date.now()),
35
+ });
36
+ const result = new ObservedSfu(
37
+ model,
38
+ config.appData,
39
+ );
40
+
41
+ const alreadyInserted = await observer.storage.sfuStorage.insert(config.sfuId, model);
42
+
43
+ if (alreadyInserted) throw new Error(`Sfu with id ${config.sfuId} already exists`);
44
+
45
+ return result;
46
+ }
47
+
48
+ private constructor(
49
+ private readonly _model: Models.Sfu,
50
+ public readonly appData: AppData,
51
+ ) {
52
+ super();
53
+ }
54
+
55
+ }