@observertc/observer-js 0.30.3-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.
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { ClientSample } from '@observertc/sample-schemas-js';
2
+ import { ClientSample, IceLocalCandidate, IceRemoteCandidate } from '@observertc/sample-schemas-js';
3
3
  import { ObservedCall } from './ObservedCall';
4
4
  import { StorageProvider } from './storages/StorageProvider';
5
5
  import { EventEmitter } from 'events';
@@ -22,6 +22,32 @@ export type ObservedClientEvents = {
22
22
  close: [];
23
23
  'processing-sample-overflow': [];
24
24
  newpeerconnection: [ObservedPeerConnection];
25
+ iceconnectionstatechange: [
26
+ {
27
+ peerConnection: ObservedPeerConnection;
28
+ state: string;
29
+ }
30
+ ];
31
+ icegatheringstatechange: [
32
+ {
33
+ peerConnection: ObservedPeerConnection;
34
+ state: string;
35
+ }
36
+ ];
37
+ connectionstatechange: [
38
+ {
39
+ peerConnection: ObservedPeerConnection;
40
+ state: string;
41
+ }
42
+ ];
43
+ selectedcandidatepair: [
44
+ {
45
+ peerConnection: ObservedPeerConnection;
46
+ localCandidate: IceLocalCandidate;
47
+ remoteCandidate: IceRemoteCandidate;
48
+ }
49
+ ];
50
+ usingturn: [boolean];
25
51
  };
26
52
  export declare interface ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> {
27
53
  on<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;
@@ -45,7 +71,11 @@ export declare class ObservedClient<AppData extends Record<string, unknown> = Re
45
71
  private _acceptedSample;
46
72
  private _processingSample;
47
73
  private _timeZoneOffsetInHours?;
48
- private _leaveReported;
74
+ private _left?;
75
+ private _numberOfAcceptedUpdates;
76
+ usingTURN: boolean;
77
+ availableOutgoingBitrate: number;
78
+ availableIncomingBitrate: number;
49
79
  totalInboundPacketsLost: number;
50
80
  totalInboundPacketsReceived: number;
51
81
  totalOutboundPacketsSent: number;
@@ -53,7 +83,7 @@ export declare class ObservedClient<AppData extends Record<string, unknown> = Re
53
83
  totalDataChannelBytesReceived: number;
54
84
  totalSentBytes: number;
55
85
  totalReceivedBytes: number;
56
- avgRttInS?: number;
86
+ avgRttInMs?: number;
57
87
  sendingBitrate?: number;
58
88
  receivingBitrate?: number;
59
89
  readonly mediaDevices: string[];
@@ -78,7 +108,9 @@ export declare class ObservedClient<AppData extends Record<string, unknown> = Re
78
108
  get platform(): Samples_ClientSample_Platform | undefined;
79
109
  get acceptedSample(): number;
80
110
  get updated(): number;
111
+ get numberOfAcceptedUpdates(): number;
81
112
  get uptimeInMs(): number;
113
+ get durationInMs(): number | undefined;
82
114
  get closed(): boolean;
83
115
  get peerConnections(): ReadonlyMap<string, ObservedPeerConnection>;
84
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,24 +295,37 @@ 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
- peerConnection && callEvent.value && peerConnection.emit('iceconnectionstatechange', callEvent.value);
313
+ peerConnection && callEvent.value && this.emit('iceconnectionstatechange', {
314
+ peerConnection,
315
+ state: callEvent.value,
316
+ });
298
317
  break;
299
318
  case CallEventType_1.CallEventType.ICE_GATHERING_STATE_CHANGED:
300
- peerConnection && callEvent.value && peerConnection.emit('icegatheringstatechange', callEvent.value);
319
+ peerConnection && callEvent.value && this.emit('icegatheringstatechange', {
320
+ peerConnection,
321
+ state: callEvent.value,
322
+ });
301
323
  break;
302
324
  case CallEventType_1.CallEventType.PEER_CONNECTION_STATE_CHANGED:
303
- peerConnection && callEvent.value && peerConnection.emit('connectionstatechange', callEvent.value);
325
+ peerConnection && callEvent.value && this.emit('connectionstatechange', {
326
+ peerConnection,
327
+ state: callEvent.value,
328
+ });
304
329
  break;
305
330
  case CallEventType_1.CallEventType.PEER_CONNECTION_OPENED: {
306
331
  if (!callEvent.peerConnectionId)
@@ -375,7 +400,7 @@ class ObservedClient extends events_1.EventEmitter {
375
400
  for (const transport of (_x = sample.pcTransports) !== null && _x !== void 0 ? _x : []) {
376
401
  try {
377
402
  const peerConnection = (_y = this._peerConnections.get(transport.transportId)) !== null && _y !== void 0 ? _y : yield this._createPeerConnection(transport.peerConnectionId);
378
- peerConnection.update(transport, sample.timestamp);
403
+ yield peerConnection.update(transport, sample.timestamp);
379
404
  }
380
405
  catch (err) {
381
406
  logger.error(`Error creating peer connection: ${err === null || err === void 0 ? void 0 : err.message}`);
@@ -535,6 +560,10 @@ class ObservedClient extends events_1.EventEmitter {
535
560
  }
536
561
  }
537
562
  // update metrics
563
+ const wasUsingTURN = this.usingTURN;
564
+ this.usingTURN = false;
565
+ this.availableIncomingBitrate = 0;
566
+ this.availableOutgoingBitrate = 0;
538
567
  this.totalSentBytes = 0;
539
568
  this.totalReceivedBytes = 0;
540
569
  this.totalOutboundPacketsSent = 0;
@@ -544,7 +573,7 @@ class ObservedClient extends events_1.EventEmitter {
544
573
  this.totalDataChannelBytesReceived = 0;
545
574
  this.sendingBitrate = 0;
546
575
  this.receivingBitrate = 0;
547
- let sumRttInS = 0;
576
+ let sumRttInMs = 0;
548
577
  for (const peerConnection of this._peerConnections.values()) {
549
578
  if (peerConnection.closed)
550
579
  continue;
@@ -558,11 +587,17 @@ class ObservedClient extends events_1.EventEmitter {
558
587
  this.totalDataChannelBytesReceived += peerConnection.totalDataChannelBytesReceived;
559
588
  this.sendingBitrate += peerConnection.sendingAudioBitrate + peerConnection.sendingVideoBitrate;
560
589
  this.receivingBitrate += peerConnection.receivingAudioBitrate + peerConnection.receivingVideoBitrate;
561
- 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;
562
595
  }
563
- this.avgRttInS = this._peerConnections.size ? sumRttInS / this._peerConnections.size : -1;
596
+ this.avgRttInMs = this._peerConnections.size ? sumRttInMs / this._peerConnections.size : undefined;
564
597
  if (executeSave)
565
598
  yield this._save();
599
+ if (wasUsingTURN !== this.usingTURN)
600
+ this.emit('usingturn', this.usingTURN);
566
601
  this._updated = sample.timestamp;
567
602
  this.emit('update');
568
603
  })).finally(() => {
@@ -580,11 +615,20 @@ class ObservedClient extends events_1.EventEmitter {
580
615
  result.created = pendingTracksTimestamp;
581
616
  this.ωpendingCreatedTracksTimestamp.delete(peerConnectionId);
582
617
  }
618
+ const onNewSelectedCandidatePair = ({ localCandidate, remoteCandidate }) => {
619
+ this.emit('selectedcandidatepair', {
620
+ peerConnection: result,
621
+ localCandidate,
622
+ remoteCandidate,
623
+ });
624
+ };
583
625
  result.once('close', () => {
626
+ result.ICE.off('new-selected-candidate-pair', onNewSelectedCandidatePair);
584
627
  this._peerConnections.delete(peerConnectionId);
585
628
  this._model.peerConnectionIds = this._model.peerConnectionIds.filter((id) => id !== peerConnectionId);
586
629
  this._save().catch(() => void 0);
587
630
  });
631
+ result.ICE.on('new-selected-candidate-pair', onNewSelectedCandidatePair);
588
632
  this._peerConnections.set(peerConnectionId, result);
589
633
  this._model.peerConnectionIds.push(peerConnectionId);
590
634
  yield this._save();
@@ -600,9 +644,9 @@ class ObservedClient extends events_1.EventEmitter {
600
644
  });
601
645
  }
602
646
  _addClientLeftReport() {
603
- if (this._leaveReported)
647
+ if (this._left)
604
648
  return;
605
- this._leaveReported = true;
649
+ this._left = Date.now();
606
650
  this.reports.addCallEventReport((0, callEventReports_1.createClientLeftEventReport)(this.serviceId, this.mediaUnitId, this.roomId, this.callId, this.clientId, this.joined, this.userId, this.marker));
607
651
  }
608
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';
@@ -13,9 +13,6 @@ export type ObservedPeerConnectionEvents = {
13
13
  newinboudvideotrack: [ObservedInboundTrack<'video'>];
14
14
  newoutboundaudiotrack: [ObservedOutboundTrack<'audio'>];
15
15
  newoutboundvideotrack: [ObservedOutboundTrack<'video'>];
16
- iceconnectionstatechange: [string];
17
- icegatheringstatechange: [string];
18
- connectionstatechange: [string];
19
16
  };
20
17
  export type ObservedPeerConnectionConfig = {
21
18
  peerConnectionId: string;
@@ -63,12 +60,10 @@ export declare class ObservedPeerConnection extends EventEmitter {
63
60
  sendingVideoBitrate: number;
64
61
  receivingAudioBitrate: number;
65
62
  receivingVideoBitrate: number;
66
- avgRttInS?: number;
63
+ avgRttInMs?: number;
67
64
  private _closed;
68
65
  private _updated;
69
66
  private _sample?;
70
- private _selectedLocalIceCandidate?;
71
- private _selectedRemoteIceCandidate?;
72
67
  readonly ICE: ObservedICE;
73
68
  private readonly _inboundAudioTracks;
74
69
  private readonly _inboundVideoTracks;
@@ -76,12 +71,14 @@ export declare class ObservedPeerConnection extends EventEmitter {
76
71
  private readonly _outboundVideoTracks;
77
72
  private readonly _execute;
78
73
  private constructor();
74
+ get label(): string | undefined;
75
+ get usingTURN(): boolean;
76
+ get availableOutgoingBitrate(): number | undefined;
77
+ get availableIncomingBitrate(): number | undefined;
79
78
  get peerConnectionId(): string;
80
79
  get reports(): import("./ReportsCollector").ReportsCollector;
81
80
  get stats(): ObservedPeerConnectionStats | undefined;
82
81
  get updated(): number;
83
- get selectedLocalIceCandidate(): IceLocalCandidate | undefined;
84
- get selectedRemoteIceCandidate(): IceRemoteCandidate | undefined;
85
82
  get inboundAudioTracks(): ReadonlyMap<string, ObservedInboundTrack<'audio'>>;
86
83
  get inboundVideoTracks(): ReadonlyMap<string, ObservedInboundTrack<'video'>>;
87
84
  get outboundAudioTracks(): ReadonlyMap<string, ObservedOutboundTrack<'audio'>>;
@@ -92,8 +89,7 @@ export declare class ObservedPeerConnection extends EventEmitter {
92
89
  getTrack(trackId: string): ObservedInboundTrack<'audio'> | ObservedInboundTrack<'video'> | ObservedOutboundTrack<'audio'> | ObservedOutboundTrack<'video'> | undefined;
93
90
  resetMetrics(): void;
94
91
  updateMetrics(): void;
95
- update(sample: PeerConnectionTransport, timestamp: number): void;
96
- updateSelectedCandidate(localCandidate: IceLocalCandidate, remoteCandidate: IceRemoteCandidate): void;
92
+ update(sample: PeerConnectionTransport, timestamp: number): Promise<void>;
97
93
  createInboundAudioTrack(config: Omit<ObservedInboundTrackConfig<'audio'>, 'kind'>): Promise<ObservedInboundTrack<'audio'>>;
98
94
  createInboundVideoTrack(config: Omit<ObservedInboundTrackConfig<'video'>, 'kind'>): Promise<ObservedInboundTrack<'video'>>;
99
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.3-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",
@@ -1,4 +1,4 @@
1
- import { ClientSample } from '@observertc/sample-schemas-js';
1
+ import { ClientSample, IceLocalCandidate, IceRemoteCandidate } from '@observertc/sample-schemas-js';
2
2
  import { ObservedCall } from './ObservedCall';
3
3
  import * as Models from './models/Models';
4
4
  import { StorageProvider } from './storages/StorageProvider';
@@ -34,6 +34,24 @@ export type ObservedClientEvents = {
34
34
  close: [],
35
35
  'processing-sample-overflow': [],
36
36
  newpeerconnection: [ObservedPeerConnection],
37
+ iceconnectionstatechange: [{
38
+ peerConnection: ObservedPeerConnection,
39
+ state: string,
40
+ }],
41
+ icegatheringstatechange: [{
42
+ peerConnection: ObservedPeerConnection,
43
+ state: string,
44
+ }],
45
+ connectionstatechange: [{
46
+ peerConnection: ObservedPeerConnection,
47
+ state: string,
48
+ }],
49
+ selectedcandidatepair: [{
50
+ peerConnection: ObservedPeerConnection,
51
+ localCandidate: IceLocalCandidate,
52
+ remoteCandidate: IceRemoteCandidate,
53
+ }],
54
+ usingturn: [boolean],
37
55
  };
38
56
 
39
57
  export declare interface ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> {
@@ -83,8 +101,6 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
83
101
  ));
84
102
  }
85
103
 
86
- result.once('close', () => result._addClientLeftReport());
87
-
88
104
  return result;
89
105
  }
90
106
 
@@ -99,8 +115,12 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
99
115
  private _acceptedSample = 0;
100
116
  private _processingSample = 0;
101
117
  private _timeZoneOffsetInHours?: number;
102
- private _leaveReported = false;
118
+ private _left?: number;
119
+ private _numberOfAcceptedUpdates = 0;
103
120
 
121
+ public usingTURN = false;
122
+ public availableOutgoingBitrate = 0;
123
+ public availableIncomingBitrate = 0;
104
124
  public totalInboundPacketsLost = 0;
105
125
  public totalInboundPacketsReceived = 0;
106
126
  public totalOutboundPacketsSent = 0;
@@ -109,7 +129,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
109
129
  public totalSentBytes = 0;
110
130
  public totalReceivedBytes = 0;
111
131
 
112
- public avgRttInS?: number;
132
+ public avgRttInMs?: number;
113
133
  public sendingBitrate?: number;
114
134
  public receivingBitrate?: number;
115
135
 
@@ -119,7 +139,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
119
139
 
120
140
  public readonly ωpendingCreatedTracksTimestamp = new Map<string, number>();
121
141
  public readonly ωpendingCreatedPeerConnectionTimestamp = new Map<string, number>();
122
-
142
+
123
143
  private constructor(
124
144
  private readonly _model: Models.Client,
125
145
  public readonly call: ObservedCall,
@@ -199,10 +219,20 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
199
219
  return this._updated;
200
220
  }
201
221
 
222
+ public get numberOfAcceptedUpdates() {
223
+ return this._numberOfAcceptedUpdates;
224
+ }
225
+
202
226
  public get uptimeInMs() {
203
227
  return this._updated - this.created;
204
228
  }
205
229
 
230
+ public get durationInMs(): number | undefined {
231
+ if (!this._left) return;
232
+
233
+ return this._left - this.joined;
234
+ }
235
+
206
236
  public get closed() {
207
237
  return this._closed;
208
238
  }
@@ -215,6 +245,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
215
245
  if (this._closed) return;
216
246
  this._closed = true;
217
247
 
248
+ !this._left && this._addClientLeftReport();
249
+
218
250
  Array.from(this._peerConnections.values()).forEach((peerConnection) => peerConnection.close());
219
251
 
220
252
  this._execute(() => this._storageProvider.clientStorage.remove(this.clientId))
@@ -235,6 +267,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
235
267
  }
236
268
 
237
269
  return this._execute(async () => {
270
+ ++this._numberOfAcceptedUpdates;
271
+
238
272
  for (const peerConnection of this._peerConnections.values()) {
239
273
  if (peerConnection.closed) continue;
240
274
  peerConnection.resetMetrics();
@@ -399,19 +433,33 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
399
433
 
400
434
  switch (callEvent.name) {
401
435
  case CallEventType.CLIENT_JOINED:
402
- this.created = timestamp ?? this.created;
436
+ if (timestamp) {
437
+ this.created = timestamp;
438
+ this._model.joined = BigInt(timestamp);
439
+ await this._save();
440
+ }
441
+
403
442
  break;
404
443
  case CallEventType.CLIENT_LEFT:
405
- this._leaveReported = true;
444
+ this._left = timestamp ?? Date.now();
406
445
  break;
407
446
  case CallEventType.ICE_CONNECTION_STATE_CHANGED:
408
- peerConnection && callEvent.value && peerConnection.emit('iceconnectionstatechange', callEvent.value);
447
+ peerConnection && callEvent.value && this.emit('iceconnectionstatechange', {
448
+ peerConnection,
449
+ state: callEvent.value,
450
+ });
409
451
  break;
410
452
  case CallEventType.ICE_GATHERING_STATE_CHANGED:
411
- peerConnection && callEvent.value && peerConnection.emit('icegatheringstatechange', callEvent.value);
453
+ peerConnection && callEvent.value && this.emit('icegatheringstatechange', {
454
+ peerConnection,
455
+ state: callEvent.value,
456
+ });
412
457
  break;
413
458
  case CallEventType.PEER_CONNECTION_STATE_CHANGED:
414
- peerConnection && callEvent.value && peerConnection.emit('connectionstatechange', callEvent.value);
459
+ peerConnection && callEvent.value && this.emit('connectionstatechange', {
460
+ peerConnection,
461
+ state: callEvent.value,
462
+ });
415
463
  break;
416
464
  case CallEventType.PEER_CONNECTION_OPENED: {
417
465
  if (!callEvent.peerConnectionId) break;
@@ -538,7 +586,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
538
586
  try {
539
587
  const peerConnection = this._peerConnections.get(transport.transportId) ?? await this._createPeerConnection(transport.peerConnectionId);
540
588
 
541
- peerConnection.update(transport, sample.timestamp);
589
+ await peerConnection.update(transport, sample.timestamp);
542
590
  } catch (err) {
543
591
  logger.error(`Error creating peer connection: ${(err as Error)?.message}`);
544
592
  }
@@ -733,6 +781,11 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
733
781
  }
734
782
 
735
783
  // update metrics
784
+ const wasUsingTURN = this.usingTURN;
785
+
786
+ this.usingTURN = false;
787
+ this.availableIncomingBitrate = 0;
788
+ this.availableOutgoingBitrate = 0;
736
789
  this.totalSentBytes = 0;
737
790
  this.totalReceivedBytes = 0;
738
791
  this.totalOutboundPacketsSent = 0;
@@ -742,7 +795,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
742
795
  this.totalDataChannelBytesReceived = 0;
743
796
  this.sendingBitrate = 0;
744
797
  this.receivingBitrate = 0;
745
- let sumRttInS = 0;
798
+ let sumRttInMs = 0;
746
799
 
747
800
  for (const peerConnection of this._peerConnections.values()) {
748
801
  if (peerConnection.closed) continue;
@@ -756,12 +809,17 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
756
809
  this.totalDataChannelBytesReceived += peerConnection.totalDataChannelBytesReceived;
757
810
  this.sendingBitrate += peerConnection.sendingAudioBitrate + peerConnection.sendingVideoBitrate;
758
811
  this.receivingBitrate += peerConnection.receivingAudioBitrate + peerConnection.receivingVideoBitrate;
759
- 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;
760
817
  }
761
818
 
762
- this.avgRttInS = this._peerConnections.size ? sumRttInS / this._peerConnections.size : -1;
819
+ this.avgRttInMs = this._peerConnections.size ? sumRttInMs / this._peerConnections.size : undefined;
763
820
 
764
821
  if (executeSave) await this._save();
822
+ if (wasUsingTURN !== this.usingTURN) this.emit('usingturn', this.usingTURN);
765
823
 
766
824
  this._updated = sample.timestamp;
767
825
  this.emit('update');
@@ -782,11 +840,21 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
782
840
  this.ωpendingCreatedTracksTimestamp.delete(peerConnectionId);
783
841
  }
784
842
 
843
+ const onNewSelectedCandidatePair = ({ localCandidate, remoteCandidate }: { localCandidate: IceLocalCandidate, remoteCandidate: IceRemoteCandidate }) => {
844
+ this.emit('selectedcandidatepair', {
845
+ peerConnection: result,
846
+ localCandidate,
847
+ remoteCandidate,
848
+ });
849
+ };
850
+
785
851
  result.once('close', () => {
852
+ result.ICE.off('new-selected-candidate-pair', onNewSelectedCandidatePair);
786
853
  this._peerConnections.delete(peerConnectionId);
787
854
  this._model.peerConnectionIds = this._model.peerConnectionIds.filter((id) => id !== peerConnectionId);
788
855
  this._save().catch(() => void 0);
789
856
  });
857
+ result.ICE.on('new-selected-candidate-pair', onNewSelectedCandidatePair);
790
858
  this._peerConnections.set(peerConnectionId, result);
791
859
  this._model.peerConnectionIds.push(peerConnectionId);
792
860
  await this._save();
@@ -803,8 +871,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
803
871
  }
804
872
 
805
873
  private _addClientLeftReport() {
806
- if (this._leaveReported) return;
807
- this._leaveReported = true;
874
+ if (this._left) return;
875
+ this._left = Date.now();
808
876
 
809
877
  this.reports.addCallEventReport(createClientLeftEventReport(
810
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';
@@ -16,10 +16,6 @@ export type ObservedPeerConnectionEvents = {
16
16
  newinboudvideotrack: [ObservedInboundTrack<'video'>],
17
17
  newoutboundaudiotrack: [ObservedOutboundTrack<'audio'>],
18
18
  newoutboundvideotrack: [ObservedOutboundTrack<'video'>],
19
-
20
- iceconnectionstatechange: [string],
21
- icegatheringstatechange: [string],
22
- connectionstatechange: [string],
23
19
  };
24
20
 
25
21
  export type ObservedPeerConnectionConfig = {
@@ -92,13 +88,11 @@ export class ObservedPeerConnection extends EventEmitter {
92
88
  public receivingAudioBitrate = 0;
93
89
  public receivingVideoBitrate = 0;
94
90
 
95
- public avgRttInS?: number;
91
+ public avgRttInMs?: number;
96
92
 
97
93
  private _closed = false;
98
94
  private _updated = Date.now();
99
95
  private _sample?: ObservedPeerConnectionStats;
100
- private _selectedLocalIceCandidate?: IceLocalCandidate;
101
- private _selectedRemoteIceCandidate?: IceRemoteCandidate;
102
96
 
103
97
  public readonly ICE = ObservedICE.create(this);
104
98
  private readonly _inboundAudioTracks = new Map<string, ObservedInboundTrack<'audio'>>();
@@ -115,6 +109,22 @@ export class ObservedPeerConnection extends EventEmitter {
115
109
  super();
116
110
  }
117
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
+
118
128
  public get peerConnectionId(): string {
119
129
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
120
130
  return this._model.peerConnectionId!;
@@ -132,14 +142,6 @@ export class ObservedPeerConnection extends EventEmitter {
132
142
  return this._updated;
133
143
  }
134
144
 
135
- public get selectedLocalIceCandidate() {
136
- return this._selectedLocalIceCandidate;
137
- }
138
-
139
- public get selectedRemoteIceCandidate() {
140
- return this._selectedRemoteIceCandidate;
141
- }
142
-
143
145
  public get inboundAudioTracks(): ReadonlyMap<string, ObservedInboundTrack<'audio'>> {
144
146
  return this._inboundAudioTracks;
145
147
  }
@@ -216,7 +218,7 @@ export class ObservedPeerConnection extends EventEmitter {
216
218
  this.receivingAudioBitrate = 0;
217
219
  this.receivingVideoBitrate = 0;
218
220
 
219
- let sumRttInS = 0;
221
+ let sumRttInMs = 0;
220
222
 
221
223
  this._inboundAudioTracks.forEach((track) => {
222
224
  this.deltaInboundLostPackets += track.deltaLostPackets;
@@ -233,7 +235,7 @@ export class ObservedPeerConnection extends EventEmitter {
233
235
  this.totalReceivedAudioBytes += track.totalBytesReceived;
234
236
  this.totalReceivedAudioPacktes += track.totalReceivedPackets;
235
237
 
236
- sumRttInS = (track.rttInMs ?? 0) / 1000.0;
238
+ sumRttInMs = (track.rttInMs ?? 0);
237
239
  });
238
240
 
239
241
  this._inboundVideoTracks.forEach((track) => {
@@ -251,7 +253,7 @@ export class ObservedPeerConnection extends EventEmitter {
251
253
  this.totalReceivedVideoBytes += track.totalBytesReceived;
252
254
  this.totalReceivedVideoPackets += track.totalReceivedPackets;
253
255
 
254
- sumRttInS = (track.rttInMs ?? 0) / 1000.0;
256
+ sumRttInMs = (track.rttInMs ?? 0);
255
257
  });
256
258
 
257
259
  this._outboundAudioTracks.forEach((track) => {
@@ -267,7 +269,7 @@ export class ObservedPeerConnection extends EventEmitter {
267
269
  this.totalSentAudioBytes += track.totalSentBytes;
268
270
  this.totalSentAudioPackets += track.totalSentPackets;
269
271
 
270
- sumRttInS = (track.rttInMs ?? 0) / 1000.0;
272
+ sumRttInMs = (track.rttInMs ?? 0);
271
273
  });
272
274
 
273
275
  this._outboundVideoTracks.forEach((track) => {
@@ -283,19 +285,27 @@ export class ObservedPeerConnection extends EventEmitter {
283
285
  this.totalSentVideoBytes += track.totalSentBytes;
284
286
  this.totalSentVideoPackets += track.totalSentPackets;
285
287
 
286
- sumRttInS = (track.rttInMs ?? 0) / 1000.0;
288
+ sumRttInMs = (track.rttInMs ?? 0);
287
289
  });
290
+ const iceRttInMs = this.ICE.stats?.currentRoundTripTime;
291
+ let nrOfBelongings = this._inboundAudioTracks.size + this._inboundVideoTracks.size + this._outboundAudioTracks.size + this._outboundVideoTracks.size;
288
292
 
289
- const nrOfBelongings = this._inboundAudioTracks.size + this._inboundVideoTracks.size + this._outboundAudioTracks.size + this._outboundVideoTracks.size;
290
-
291
- 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;
292
298
  }
293
299
 
294
- public update(sample: PeerConnectionTransport, timestamp: number) {
300
+ public async update(sample: PeerConnectionTransport, timestamp: number) {
295
301
  if (this._closed) return;
296
302
  if (sample.peerConnectionId !== this._model.peerConnectionId) throw new Error(`TransportId mismatch. PeerConnectionId: ${ this._model.peerConnectionId } TransportId: ${ sample.transportId}`);
297
303
 
298
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
+ }
299
309
 
300
310
  const report: PeerConnectionTransportReport = {
301
311
  serviceId: this.client.call.serviceId,
@@ -315,11 +325,6 @@ export class ObservedPeerConnection extends EventEmitter {
315
325
  this.emit('update');
316
326
  }
317
327
 
318
- public updateSelectedCandidate(localCandidate: IceLocalCandidate, remoteCandidate: IceRemoteCandidate) {
319
- this._selectedLocalIceCandidate = localCandidate;
320
- this._selectedRemoteIceCandidate = remoteCandidate;
321
- }
322
-
323
328
  public async createInboundAudioTrack(config: Omit<ObservedInboundTrackConfig<'audio'>, 'kind'>): Promise<ObservedInboundTrack<'audio'>> {
324
329
  if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
325
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
+ }