@observertc/observer-js 1.0.1-c3edea3.0 → 1.0.1-ec27289.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/lib/ObservedCall.d.ts +41 -7
  2. package/lib/ObservedCall.d.ts.map +1 -1
  3. package/lib/ObservedCall.js +125 -13
  4. package/lib/ObservedCallSummary.d.ts +18 -0
  5. package/lib/ObservedCallSummary.d.ts.map +1 -0
  6. package/lib/ObservedClient.d.ts +70 -11
  7. package/lib/ObservedClient.d.ts.map +1 -1
  8. package/lib/ObservedClient.js +394 -72
  9. package/lib/ObservedClientEventMonitor.d.ts +89 -0
  10. package/lib/ObservedClientEventMonitor.d.ts.map +1 -0
  11. package/lib/ObservedClientEventMonitor.js +247 -0
  12. package/lib/ObservedClientSummary.d.ts +23 -0
  13. package/lib/ObservedClientSummary.d.ts.map +1 -0
  14. package/lib/ObservedClientSummary.js +2 -0
  15. package/lib/ObservedDataChannel.d.ts +6 -0
  16. package/lib/ObservedDataChannel.d.ts.map +1 -1
  17. package/lib/ObservedDataChannel.js +30 -0
  18. package/lib/ObservedIceCandidatePair.d.ts +4 -0
  19. package/lib/ObservedIceCandidatePair.d.ts.map +1 -1
  20. package/lib/ObservedIceCandidatePair.js +28 -0
  21. package/lib/ObservedIceTransport.d.ts +4 -0
  22. package/lib/ObservedIceTransport.d.ts.map +1 -1
  23. package/lib/ObservedIceTransport.js +28 -0
  24. package/lib/ObservedInboundTrack.d.ts +2 -0
  25. package/lib/ObservedInboundTrack.d.ts.map +1 -1
  26. package/lib/ObservedInboundTrack.js +2 -0
  27. package/lib/ObservedOutboundTrack.d.ts +2 -0
  28. package/lib/ObservedOutboundTrack.d.ts.map +1 -1
  29. package/lib/ObservedOutboundTrack.js +2 -0
  30. package/lib/ObservedPeerConnection.d.ts +14 -2
  31. package/lib/ObservedPeerConnection.d.ts.map +1 -1
  32. package/lib/ObservedPeerConnection.js +106 -14
  33. package/lib/ObservedTURN.d.ts +31 -0
  34. package/lib/ObservedTURN.d.ts.map +1 -0
  35. package/lib/ObservedTURN.js +58 -0
  36. package/lib/ObservedTurnServer.d.ts +25 -0
  37. package/lib/ObservedTurnServer.d.ts.map +1 -0
  38. package/lib/ObservedTurnServer.js +59 -0
  39. package/lib/Observer.d.ts +38 -21
  40. package/lib/Observer.d.ts.map +1 -1
  41. package/lib/Observer.js +114 -40
  42. package/lib/ObserverSummary.d.ts +13 -0
  43. package/lib/ObserverSummary.d.ts.map +1 -0
  44. package/lib/ObserverSummary.js +2 -0
  45. package/lib/common/utils.d.ts +2 -1
  46. package/lib/common/utils.d.ts.map +1 -1
  47. package/lib/common/utils.js +11 -3
  48. package/lib/index.d.ts +5 -0
  49. package/lib/index.d.ts.map +1 -1
  50. package/lib/index.js +7 -1
  51. package/lib/schema/ClientEventTypes.d.ts +100 -0
  52. package/lib/schema/ClientEventTypes.d.ts.map +1 -0
  53. package/lib/schema/ClientEventTypes.js +38 -0
  54. package/lib/schema/{metaTypes.d.ts → ClientMetaTypes.d.ts} +2 -2
  55. package/lib/schema/ClientMetaTypes.d.ts.map +1 -0
  56. package/lib/schema/ClientMetaTypes.js +16 -0
  57. package/lib/updaters/CallUpdater.d.ts.map +1 -0
  58. package/lib/updaters/CallUpdater.js +2 -0
  59. package/lib/updaters/ObserverUpdater.d.ts +5 -0
  60. package/lib/updaters/ObserverUpdater.d.ts.map +1 -0
  61. package/lib/updaters/ObserverUpdater.js +2 -0
  62. package/lib/updaters/OnAllCallObserverUpdater_.d.ts +13 -0
  63. package/lib/updaters/OnAllCallObserverUpdater_.d.ts.map +1 -0
  64. package/lib/updaters/OnAllCallObserverUpdater_.js +38 -0
  65. package/lib/updaters/OnAllClientCallUpdater.d.ts +13 -0
  66. package/lib/updaters/OnAllClientCallUpdater.d.ts.map +1 -0
  67. package/lib/updaters/OnAllClientCallUpdater.js +37 -0
  68. package/lib/updaters/OnAnyCallObserverUpdater_.d.ts +11 -0
  69. package/lib/updaters/OnAnyCallObserverUpdater_.d.ts.map +1 -0
  70. package/lib/updaters/OnAnyCallObserverUpdater_.js +27 -0
  71. package/lib/updaters/OnAnyClientCallUpdater.d.ts +11 -0
  72. package/lib/updaters/OnAnyClientCallUpdater.d.ts.map +1 -0
  73. package/lib/updaters/OnAnyClientCallUpdater.js +27 -0
  74. package/lib/updaters/OnIntervalUpdater.d.ts +10 -0
  75. package/lib/updaters/OnIntervalUpdater.d.ts.map +1 -0
  76. package/lib/updaters/OnIntervalUpdater.js +17 -0
  77. package/lib/updaters/Updater.d.ts +6 -0
  78. package/lib/updaters/Updater.d.ts.map +1 -0
  79. package/lib/updaters/Updater.js +2 -0
  80. package/package.json +1 -1
  81. package/src/ObservedCall.ts +205 -16
  82. package/src/ObservedCallSummary.ts +22 -0
  83. package/src/ObservedClient.ts +492 -78
  84. package/src/ObservedClientEventMonitor.ts +301 -0
  85. package/src/ObservedClientSummary.ts +24 -0
  86. package/src/ObservedDataChannel.ts +32 -0
  87. package/src/ObservedIceCandidatePair.ts +26 -0
  88. package/src/ObservedIceTransport.ts +29 -0
  89. package/src/ObservedInboundTrack.ts +3 -0
  90. package/src/ObservedOutboundTrack.ts +3 -0
  91. package/src/ObservedPeerConnection.ts +120 -16
  92. package/src/ObservedTURN.ts +86 -0
  93. package/src/ObservedTurnServer.ts +72 -0
  94. package/src/Observer.ts +164 -64
  95. package/src/ObserverSummary.ts +15 -0
  96. package/src/common/utils.ts +12 -2
  97. package/src/index.ts +5 -0
  98. package/src/schema/ClientEventTypes.ts +112 -0
  99. package/src/schema/{metaTypes.ts → ClientMetaTypes.ts} +1 -1
  100. package/src/updaters/ObserverUpdater.ts +5 -0
  101. package/src/updaters/OnAllCallObserverUpdater_.ts +46 -0
  102. package/src/updaters/OnAllClientCallUpdater.ts +46 -0
  103. package/src/updaters/OnAnyCallObserverUpdater_.ts +32 -0
  104. package/src/updaters/OnAnyClientCallUpdater.ts +32 -0
  105. package/src/updaters/OnIntervalUpdater.ts +19 -0
  106. package/src/updaters/Updater.ts +5 -0
  107. package/tsconfig.json +1 -1
  108. package/lib/schema/eventTypes.d.ts +0 -33
  109. package/lib/schema/eventTypes.d.ts.map +0 -1
  110. package/lib/schema/eventTypes.js +0 -38
  111. package/lib/schema/metaTypes.d.ts.map +0 -1
  112. package/lib/schema/metaTypes.js +0 -16
  113. package/lib/utils/CallUpdater.d.ts.map +0 -1
  114. package/lib/utils/OnAllClientCallUpdater.d.ts +0 -16
  115. package/lib/utils/OnAllClientCallUpdater.d.ts.map +0 -1
  116. package/lib/utils/OnAllClientCallUpdater.js +0 -58
  117. package/lib/utils/onAnyClientCallUpdater.d.ts +0 -14
  118. package/lib/utils/onAnyClientCallUpdater.d.ts.map +0 -1
  119. package/lib/utils/onAnyClientCallUpdater.js +0 -51
  120. package/src/schema/eventTypes.ts +0 -36
  121. package/src/utils/OnAllClientCallUpdater.ts +0 -68
  122. package/src/utils/onAnyClientCallUpdater.ts +0 -59
  123. /package/lib/{utils/CallUpdater.js → ObservedCallSummary.js} +0 -0
  124. /package/lib/{utils → updaters}/CallUpdater.d.ts +0 -0
  125. /package/src/{utils → updaters}/CallUpdater.ts +0 -0
@@ -18,6 +18,7 @@ const ObservedRemoteInboundRtp_1 = require("./ObservedRemoteInboundRtp");
18
18
  const ObservedRemoteOutboundRtp_1 = require("./ObservedRemoteOutboundRtp");
19
19
  const ObservedInboundTrack_1 = require("./ObservedInboundTrack");
20
20
  const ObservedOutboundTrack_1 = require("./ObservedOutboundTrack");
21
+ const utils_1 = require("./common/utils");
21
22
  const logger = (0, logger_1.createLogger)('ObservedPeerConnection');
22
23
  class ObservedPeerConnection extends events_1.EventEmitter {
23
24
  peerConnectionId;
@@ -34,11 +35,15 @@ class ObservedPeerConnection extends events_1.EventEmitter {
34
35
  // timestamp of the PEER_CONNECTION_CLOSED event
35
36
  closedAt;
36
37
  updated = Date.now();
38
+ availableIncomingBitrate = 0;
39
+ availableOutgoingBitrate = 0;
37
40
  totalInboundPacketsLost = 0;
38
41
  totalInboundPacketsReceived = 0;
39
42
  totalOutboundPacketsSent = 0;
40
43
  totalDataChannelBytesSent = 0;
41
44
  totalDataChannelBytesReceived = 0;
45
+ totalDataChannelMessagesSent = 0;
46
+ totalDataChannelMessagesReceived = 0;
42
47
  totalSentAudioBytes = 0;
43
48
  totalSentVideoBytes = 0;
44
49
  totalSentAudioPackets = 0;
@@ -52,6 +57,8 @@ class ObservedPeerConnection extends events_1.EventEmitter {
52
57
  deltaOutboundPacketsSent = 0;
53
58
  deltaDataChannelBytesSent = 0;
54
59
  deltaDataChannelBytesReceived = 0;
60
+ deltaDataChannelMessagesSent = 0;
61
+ deltaDataChannelMessagesReceived = 0;
55
62
  deltaInboundReceivedBytes = 0;
56
63
  deltaOutboundSentBytes = 0;
57
64
  deltaReceivedAudioBytes = 0;
@@ -60,16 +67,19 @@ class ObservedPeerConnection extends events_1.EventEmitter {
60
67
  deltaReceivedVideoPackets = 0;
61
68
  deltaSentAudioBytes = 0;
62
69
  deltaSentVideoBytes = 0;
70
+ deltaTransportSentBytes = 0;
71
+ deltaTransportReceivedBytes = 0;
63
72
  receivingPacketsPerSecond = 0;
64
73
  sendingPacketsPerSecond = 0;
65
74
  sendingAudioBitrate = 0;
66
75
  sendingVideoBitrate = 0;
67
76
  receivingAudioBitrate = 0;
68
77
  receivingVideoBitrate = 0;
69
- avgRttInMs;
70
- avgJitter;
78
+ currentRttInMs;
79
+ currentJitter;
71
80
  usingTCP = false;
72
81
  usingTURN = false;
82
+ observedTurnServer;
73
83
  observedCertificates = new Map();
74
84
  observedCodecs = new Map();
75
85
  observedDataChannels = new Map();
@@ -142,6 +152,11 @@ class ObservedPeerConnection extends events_1.EventEmitter {
142
152
  return this.iceTransports.map((iceTransport) => iceTransport.getSelectedCandidatePair())
143
153
  .filter((pair) => pair !== undefined);
144
154
  }
155
+ get selectedIceCandiadtePairForTurn() {
156
+ return this.selectedIceCandidatePairs
157
+ .filter((pair) => pair.getLocalCandidate()?.candidateType === 'relay' &&
158
+ pair.getRemoteCandidate()?.url?.startsWith('turn:'));
159
+ }
145
160
  close() {
146
161
  if (this.closed)
147
162
  return;
@@ -161,12 +176,17 @@ class ObservedPeerConnection extends events_1.EventEmitter {
161
176
  this.observedPeerConnectionTransports.clear();
162
177
  this.observedRemoteInboundRtps.clear();
163
178
  this.observedRemoteOutboundRtps.clear();
179
+ this.client.call.observer.observedTURN.removePeerConnection(this);
180
+ if (!this.closedAt)
181
+ this.closedAt = Date.now();
164
182
  this.emit('close');
165
183
  }
166
184
  accept(sample) {
167
185
  if (this.closed)
168
186
  return;
169
187
  this._visited = true;
188
+ this.availableIncomingBitrate = 0;
189
+ this.availableOutgoingBitrate = 0;
170
190
  this.deltaInboundPacketsLost = 0;
171
191
  this.deltaInboundPacketsReceived = 0;
172
192
  this.deltaOutboundPacketsSent = 0;
@@ -180,6 +200,8 @@ class ObservedPeerConnection extends events_1.EventEmitter {
180
200
  this.deltaReceivedVideoPackets = 0;
181
201
  this.deltaSentAudioBytes = 0;
182
202
  this.deltaSentVideoBytes = 0;
203
+ this.deltaTransportReceivedBytes = 0;
204
+ this.deltaTransportSentBytes = 0;
183
205
  this.sendingAudioBitrate = 0;
184
206
  this.sendingVideoBitrate = 0;
185
207
  this.receivingAudioBitrate = 0;
@@ -187,6 +209,8 @@ class ObservedPeerConnection extends events_1.EventEmitter {
187
209
  const now = Date.now();
188
210
  const elapsedTimeInMs = now - this.updated;
189
211
  const elapsedTimeInSec = elapsedTimeInMs / 1000;
212
+ const rttMeasurementsInSec = [];
213
+ const jitterMeasurements = [];
190
214
  if (sample.certificates) {
191
215
  for (const certificate of sample.certificates) {
192
216
  this._updateCertificateStats(certificate);
@@ -199,7 +223,13 @@ class ObservedPeerConnection extends events_1.EventEmitter {
199
223
  }
200
224
  if (sample.dataChannels) {
201
225
  for (const dataChannel of sample.dataChannels) {
202
- this._updateDataChannelStats(dataChannel);
226
+ const observedDataChannel = this._updateDataChannelStats(dataChannel);
227
+ if (!observedDataChannel)
228
+ continue;
229
+ this.deltaDataChannelBytesSent += observedDataChannel.deltaBytesSent;
230
+ this.deltaDataChannelBytesReceived += observedDataChannel.deltaBytesReceived;
231
+ this.deltaDataChannelMessagesSent += observedDataChannel.deltaMessagesSent;
232
+ this.deltaDataChannelMessagesReceived += observedDataChannel.deltaMessagesReceived;
203
233
  }
204
234
  }
205
235
  if (sample.iceCandidates) {
@@ -209,12 +239,26 @@ class ObservedPeerConnection extends events_1.EventEmitter {
209
239
  }
210
240
  if (sample.iceCandidatePairs) {
211
241
  for (const iceCandidatePair of sample.iceCandidatePairs) {
212
- this._updateIceCandidatePairStats(iceCandidatePair);
242
+ const observedCandidatePair = this._updateIceCandidatePairStats(iceCandidatePair);
243
+ if (!observedCandidatePair)
244
+ continue;
245
+ if (observedCandidatePair.currentRoundTripTime) {
246
+ rttMeasurementsInSec.push(observedCandidatePair.currentRoundTripTime);
247
+ }
248
+ if (observedCandidatePair.availableIncomingBitrate) {
249
+ this.availableIncomingBitrate += observedCandidatePair.availableIncomingBitrate;
250
+ }
251
+ if (observedCandidatePair.availableOutgoingBitrate) {
252
+ this.availableOutgoingBitrate += observedCandidatePair.availableOutgoingBitrate;
253
+ }
213
254
  }
214
255
  }
215
256
  if (sample.iceTransports) {
216
257
  for (const iceTransport of sample.iceTransports) {
217
- this._updateIceTransportStats(iceTransport);
258
+ const observedIceTransport = this._updateIceTransportStats(iceTransport);
259
+ if (!observedIceTransport)
260
+ return;
261
+ observedIceTransport.bytesReceived;
218
262
  }
219
263
  }
220
264
  if (sample.inboundRtps) {
@@ -235,6 +279,9 @@ class ObservedPeerConnection extends events_1.EventEmitter {
235
279
  this.deltaReceivedVideoPackets += observedInboundRtp.deltaReceivedPackets;
236
280
  break;
237
281
  }
282
+ if (observedInboundRtp.jitter) {
283
+ jitterMeasurements.push(observedInboundRtp.jitter);
284
+ }
238
285
  }
239
286
  }
240
287
  if (sample.mediaPlayouts) {
@@ -268,12 +315,19 @@ class ObservedPeerConnection extends events_1.EventEmitter {
268
315
  }
269
316
  if (sample.peerConnectionTransports) {
270
317
  for (const peerConnectionTransport of sample.peerConnectionTransports) {
271
- this._updatePeerConnectionTransportStats(peerConnectionTransport);
318
+ const observedTransport = this._updatePeerConnectionTransportStats(peerConnectionTransport);
319
+ if (!observedTransport)
320
+ continue;
272
321
  }
273
322
  }
274
323
  if (sample.remoteInboundRtps) {
275
324
  for (const remoteInboundRtp of sample.remoteInboundRtps) {
276
- this._updateRemoteInboundRtpStats(remoteInboundRtp);
325
+ const observedRemoteInboundRtp = this._updateRemoteInboundRtpStats(remoteInboundRtp);
326
+ if (!observedRemoteInboundRtp)
327
+ continue;
328
+ if (observedRemoteInboundRtp.roundTripTime) {
329
+ rttMeasurementsInSec.push(observedRemoteInboundRtp.roundTripTime);
330
+ }
277
331
  }
278
332
  }
279
333
  if (sample.remoteOutboundRtps) {
@@ -300,6 +354,8 @@ class ObservedPeerConnection extends events_1.EventEmitter {
300
354
  this.totalOutboundPacketsSent += this.deltaOutboundPacketsSent;
301
355
  this.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
302
356
  this.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
357
+ this.totalDataChannelMessagesSent += this.deltaDataChannelMessagesSent;
358
+ this.totalDataChannelMessagesReceived += this.deltaDataChannelMessagesReceived;
303
359
  this.totalReceivedAudioBytes += this.deltaReceivedAudioBytes;
304
360
  this.totalReceivedVideoBytes += this.deltaReceivedVideoBytes;
305
361
  this.totalSentAudioBytes += this.deltaSentAudioBytes;
@@ -310,17 +366,53 @@ class ObservedPeerConnection extends events_1.EventEmitter {
310
366
  this.totalSentVideoPackets += this.deltaSentVideoBytes;
311
367
  this.receivingPacketsPerSecond = this.deltaInboundPacketsReceived / elapsedTimeInSec;
312
368
  this.sendingPacketsPerSecond = this.deltaOutboundPacketsSent / elapsedTimeInSec;
313
- this.sendingAudioBitrate = this.deltaSentAudioBytes * 8 / elapsedTimeInSec;
314
- this.sendingVideoBitrate = this.deltaSentVideoBytes * 8 / elapsedTimeInSec;
315
- this.receivingAudioBitrate = this.deltaReceivedAudioBytes * 8 / elapsedTimeInSec;
316
- this.receivingVideoBitrate = this.deltaReceivedVideoBytes * 8 / elapsedTimeInSec;
369
+ this.sendingAudioBitrate = (this.deltaSentAudioBytes * 8) / elapsedTimeInSec;
370
+ this.sendingVideoBitrate = (this.deltaSentVideoBytes * 8) / elapsedTimeInSec;
371
+ this.receivingAudioBitrate = (this.deltaReceivedAudioBytes * 8) / elapsedTimeInSec;
372
+ this.receivingVideoBitrate = (this.deltaReceivedVideoBytes * 8) / elapsedTimeInSec;
373
+ if (rttMeasurementsInSec.length > 0) {
374
+ this.currentRttInMs = (0, utils_1.getMedian)(rttMeasurementsInSec, false) * 1000;
375
+ }
376
+ else {
377
+ this.currentRttInMs = undefined;
378
+ }
379
+ if (jitterMeasurements.length > 0) {
380
+ this.currentJitter = (0, utils_1.getMedian)(jitterMeasurements, false);
381
+ }
382
+ else {
383
+ this.currentJitter = undefined;
384
+ }
385
+ const wasUsingTURN = this.usingTURN;
317
386
  const selectedIceCandidatePairs = this.selectedIceCandidatePairs;
318
- this.usingTCP = selectedIceCandidatePairs.some((pair) => pair.getLocalCandidate()?.protocol === 'tcp');
319
- this.usingTURN = selectedIceCandidatePairs.some((pair) => pair.getLocalCandidate()?.candidateType === 'relay') &&
320
- selectedIceCandidatePairs.some((pair) => pair.getRemoteCandidate()?.url?.startsWith('turn:'));
387
+ const selectedCandidatePairForTurn = [];
388
+ this.usingTCP = false;
389
+ this.usingTURN = false;
390
+ for (const selectedCandidatePair of selectedIceCandidatePairs) {
391
+ if (selectedCandidatePair.getLocalCandidate()?.protocol === 'tcp') {
392
+ this.usingTCP = true;
393
+ }
394
+ if (selectedCandidatePair.getLocalCandidate()?.candidateType === 'relay' && selectedCandidatePair.getRemoteCandidate()?.url?.startsWith('turn:')) {
395
+ selectedCandidatePairForTurn.push(selectedCandidatePair);
396
+ this.usingTURN = true;
397
+ }
398
+ this.deltaTransportReceivedBytes += selectedCandidatePair.deltaBytesReceived;
399
+ this.deltaTransportSentBytes += selectedCandidatePair.deltaBytesSent;
400
+ }
401
+ if (this.usingTURN) {
402
+ if (!this.observedTurnServer) {
403
+ this.observedTurnServer = this.client.call.observer.observedTURN.addPeerConnection(this);
404
+ }
405
+ this.observedTurnServer?.updateTurnUsage(...selectedCandidatePairForTurn);
406
+ }
407
+ else if (wasUsingTURN) {
408
+ if (!this.usingTURN) {
409
+ this.client.call.observer.observedTURN.removePeerConnection(this);
410
+ }
411
+ }
321
412
  this.calculatedScore.value = sample.score;
322
413
  this.updated = now;
323
414
  this._checkVisited();
415
+ this.emit('update');
324
416
  }
325
417
  _checkVisited() {
326
418
  for (const certificate of [...this.observedCertificates.values()]) {
@@ -0,0 +1,31 @@
1
+ /// <reference types="node" />
2
+ import { EventEmitter } from 'stream';
3
+ import { ObservedPeerConnection } from './ObservedPeerConnection';
4
+ import { ObservedTurnServer } from './ObservedTurnServer';
5
+ export type ObservedTURNEventMap = {
6
+ 'update': [ObservedTURN];
7
+ 'close': [];
8
+ };
9
+ export declare interface ObservedTURN {
10
+ on<U extends keyof ObservedTURNEventMap>(event: U, listener: (...args: ObservedTURNEventMap[U]) => void): this;
11
+ off<U extends keyof ObservedTURNEventMap>(event: U, listener: (...args: ObservedTURNEventMap[U]) => void): this;
12
+ once<U extends keyof ObservedTURNEventMap>(event: U, listener: (...args: ObservedTURNEventMap[U]) => void): this;
13
+ emit<U extends keyof ObservedTURNEventMap>(event: U, ...args: ObservedTURNEventMap[U]): boolean;
14
+ }
15
+ export declare class ObservedTURN extends EventEmitter {
16
+ totalBytesSent: number;
17
+ totalBytesReceived: number;
18
+ totalPacketsSent: number;
19
+ totalPacketsReceived: number;
20
+ packetsSentPerSecond: number;
21
+ packetsReceivedPerSecond: number;
22
+ outboundBitrate: number;
23
+ inboundBitrate: number;
24
+ numberOfClients: number;
25
+ readonly servers: Map<string, ObservedTurnServer>;
26
+ constructor();
27
+ update(): void;
28
+ addPeerConnection(peerConnection: ObservedPeerConnection): ObservedTurnServer | undefined;
29
+ removePeerConnection(peerConnection: ObservedPeerConnection): void;
30
+ }
31
+ //# sourceMappingURL=ObservedTURN.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ObservedTURN.d.ts","sourceRoot":"","sources":["../src/ObservedTURN.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAK1D,MAAM,MAAM,oBAAoB,GAAG;IAClC,QAAQ,EAAE,CAAC,YAAY,CAAC,CAAC;IACzB,OAAO,EAAE,EAAE,CAAC;CACZ,CAAA;AAED,MAAM,CAAC,OAAO,WAAW,YAAY;IACpC,EAAE,CAAC,CAAC,SAAS,MAAM,oBAAoB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,oBAAoB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAC/G,GAAG,CAAC,CAAC,SAAS,MAAM,oBAAoB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,oBAAoB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAChH,IAAI,CAAC,CAAC,SAAS,MAAM,oBAAoB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,oBAAoB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACjH,IAAI,CAAC,CAAC,SAAS,MAAM,oBAAoB,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;CAChG;AAED,qBAAa,YAAa,SAAQ,YAAY;IACtC,cAAc,SAAK;IACnB,kBAAkB,SAAK;IACvB,gBAAgB,SAAK;IACrB,oBAAoB,SAAK;IAEzB,oBAAoB,SAAK;IACzB,wBAAwB,SAAK;IAC7B,eAAe,SAAK;IACpB,cAAc,SAAK;IACnB,eAAe,SAAK;IAE3B,SAAgB,OAAO,kCAAyC;;IAOzD,MAAM;IAgBN,iBAAiB,CAAC,cAAc,EAAE,sBAAsB;IAyBxD,oBAAoB,CAAC,cAAc,EAAE,sBAAsB;CAMlE"}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ObservedTURN = void 0;
4
+ const stream_1 = require("stream");
5
+ const ObservedTurnServer_1 = require("./ObservedTurnServer");
6
+ const logger_1 = require("./common/logger");
7
+ const logger = (0, logger_1.createLogger)('ObservedTURN');
8
+ class ObservedTURN extends stream_1.EventEmitter {
9
+ totalBytesSent = 0;
10
+ totalBytesReceived = 0;
11
+ totalPacketsSent = 0;
12
+ totalPacketsReceived = 0;
13
+ packetsSentPerSecond = 0;
14
+ packetsReceivedPerSecond = 0;
15
+ outboundBitrate = 0;
16
+ inboundBitrate = 0;
17
+ numberOfClients = 0;
18
+ servers = new Map();
19
+ constructor() {
20
+ super();
21
+ }
22
+ update() {
23
+ const clientIds = new Set();
24
+ this.packetsReceivedPerSecond = 0;
25
+ this.packetsSentPerSecond = 0;
26
+ this.outboundBitrate = 0;
27
+ this.inboundBitrate = 0;
28
+ for (const server of this.servers.values()) {
29
+ server.update();
30
+ server.observedPeerConnections.forEach((pc) => clientIds.add(pc.client.clientId));
31
+ }
32
+ this.numberOfClients = clientIds.size;
33
+ }
34
+ addPeerConnection(peerConnection) {
35
+ const turnPairs = peerConnection.selectedIceCandidatePairs.filter((pair) => pair.getLocalCandidate()?.candidateType === 'relay' && pair.getRemoteCandidate()?.url?.startsWith('turn:'));
36
+ if (turnPairs.length !== 1) {
37
+ return (logger.warn(`Expected exactly one TURN pair, but found for peerconnection ${peerConnection.peerConnectionId}`, turnPairs.length), undefined);
38
+ }
39
+ const candidatePair = turnPairs[0];
40
+ const rawUrl = candidatePair.getRemoteCandidate()?.url;
41
+ if (!rawUrl) {
42
+ return (logger.warn(`No remote candidate URL found for peerconnection ${peerConnection.peerConnectionId}`), undefined);
43
+ }
44
+ const turnUrl = new URL(rawUrl);
45
+ const turnServerUrl = `${turnUrl.protocol}//${turnUrl.hostname}:${turnUrl.port}`;
46
+ let turnServer = this.servers.get(turnServerUrl);
47
+ if (!turnServer) {
48
+ turnServer = new ObservedTurnServer_1.ObservedTurnServer(turnServerUrl, this);
49
+ }
50
+ return turnServer;
51
+ }
52
+ removePeerConnection(peerConnection) {
53
+ for (const turnServer of this.servers.values()) {
54
+ turnServer.observedPeerConnections.delete(peerConnection.peerConnectionId);
55
+ }
56
+ }
57
+ }
58
+ exports.ObservedTURN = ObservedTURN;
@@ -0,0 +1,25 @@
1
+ import { ObservedIceCandidatePair } from './ObservedIceCandidatePair';
2
+ import { ObservedPeerConnection } from './ObservedPeerConnection';
3
+ import { ObservedTURN } from './ObservedTURN';
4
+ export declare class ObservedTurnServer {
5
+ readonly url: string;
6
+ readonly observedTURN: ObservedTURN;
7
+ totalBytesSent: number;
8
+ totalBytesReceived: number;
9
+ totalPacketsSent: number;
10
+ totalPacketsReceived: number;
11
+ packetsSentPerSecond: number;
12
+ packetsReceivedPerSecond: number;
13
+ outboundBitrate: number;
14
+ inboundBitrate: number;
15
+ deltaBytesSent: number;
16
+ deltaBytesReceived: number;
17
+ deltaPacketsSent: number;
18
+ deltaPacketsReceived: number;
19
+ readonly observedPeerConnections: Map<string, ObservedPeerConnection>;
20
+ updated: number;
21
+ constructor(url: string, observedTURN: ObservedTURN);
22
+ updateTurnUsage(...selectedcandidatepairs: ObservedIceCandidatePair[]): void;
23
+ update(): void;
24
+ }
25
+ //# sourceMappingURL=ObservedTurnServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ObservedTurnServer.d.ts","sourceRoot":"","sources":["../src/ObservedTurnServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,qBAAa,kBAAkB;aAqBb,GAAG,EAAE,MAAM;aACX,YAAY,EAAE,YAAY;IArBpC,cAAc,SAAK;IACnB,kBAAkB,SAAK;IACvB,gBAAgB,SAAK;IACrB,oBAAoB,SAAK;IAEzB,oBAAoB,SAAK;IACzB,wBAAwB,SAAK;IAC7B,eAAe,SAAK;IACpB,cAAc,SAAK;IAEnB,cAAc,SAAK;IACnB,kBAAkB,SAAK;IACvB,gBAAgB,SAAK;IACrB,oBAAoB,SAAK;IAEhC,SAAgB,uBAAuB,sCAA6C;IAE7E,OAAO,SAAc;gBAGX,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,YAAY;IAKpC,eAAe,CAAC,GAAG,sBAAsB,EAAE,wBAAwB,EAAE;IASrE,MAAM;CA+Bb"}
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ObservedTurnServer = void 0;
4
+ class ObservedTurnServer {
5
+ url;
6
+ observedTURN;
7
+ totalBytesSent = 0;
8
+ totalBytesReceived = 0;
9
+ totalPacketsSent = 0;
10
+ totalPacketsReceived = 0;
11
+ packetsSentPerSecond = 0;
12
+ packetsReceivedPerSecond = 0;
13
+ outboundBitrate = 0;
14
+ inboundBitrate = 0;
15
+ deltaBytesSent = 0;
16
+ deltaBytesReceived = 0;
17
+ deltaPacketsSent = 0;
18
+ deltaPacketsReceived = 0;
19
+ observedPeerConnections = new Map();
20
+ updated = Date.now();
21
+ constructor(url, observedTURN) {
22
+ this.url = url;
23
+ this.observedTURN = observedTURN;
24
+ }
25
+ updateTurnUsage(...selectedcandidatepairs) {
26
+ for (const selectedcandidatepair of selectedcandidatepairs) {
27
+ this.deltaBytesReceived += selectedcandidatepair.deltaBytesReceived;
28
+ this.deltaBytesSent += selectedcandidatepair.deltaBytesSent;
29
+ this.deltaPacketsReceived += selectedcandidatepair.deltaPacketsReceived;
30
+ this.deltaPacketsSent += selectedcandidatepair.deltaPacketsSent;
31
+ }
32
+ }
33
+ update() {
34
+ const now = Date.now();
35
+ const deltaInS = (now - this.updated) / 1000;
36
+ this.packetsSentPerSecond = this.deltaPacketsSent / deltaInS;
37
+ this.packetsReceivedPerSecond = this.deltaPacketsReceived / deltaInS;
38
+ this.outboundBitrate = (this.deltaBytesReceived * 8) / deltaInS;
39
+ this.inboundBitrate = (this.deltaBytesSent * 8) / deltaInS;
40
+ this.totalBytesSent += this.deltaBytesSent;
41
+ this.totalBytesReceived += this.deltaBytesReceived;
42
+ this.totalPacketsSent += this.deltaPacketsSent;
43
+ this.totalPacketsReceived += this.deltaPacketsReceived;
44
+ this.observedTURN.totalBytesSent += this.deltaBytesSent;
45
+ this.observedTURN.totalBytesReceived += this.deltaBytesReceived;
46
+ this.observedTURN.totalPacketsSent += this.deltaPacketsSent;
47
+ this.observedTURN.totalPacketsReceived += this.deltaPacketsReceived;
48
+ this.observedTURN.inboundBitrate += this.inboundBitrate;
49
+ this.observedTURN.outboundBitrate += this.outboundBitrate;
50
+ this.observedTURN.packetsReceivedPerSecond += this.packetsReceivedPerSecond;
51
+ this.observedTURN.packetsSentPerSecond += this.packetsSentPerSecond;
52
+ this.deltaBytesSent = 0;
53
+ this.deltaBytesReceived = 0;
54
+ this.deltaPacketsSent = 0;
55
+ this.deltaPacketsReceived = 0;
56
+ this.updated = now;
57
+ }
58
+ }
59
+ exports.ObservedTurnServer = ObservedTurnServer;
package/lib/Observer.d.ts CHANGED
@@ -1,17 +1,26 @@
1
1
  /// <reference types="node" />
2
- import { Middleware, MiddlewareProcessor } from './common/Middleware';
3
2
  import { ObservedCall, ObservedCallSettings } from './ObservedCall';
4
3
  import { EventEmitter } from 'events';
5
- import { ClientEvent, ClientMetaData, ClientIssue, ExtensionStat } from './schema/ClientSample';
4
+ import { ClientEvent, ClientMetaData, ClientIssue, ExtensionStat, ClientSample } from './schema/ClientSample';
6
5
  import { ObservedClient } from './ObservedClient';
6
+ import { ObservedTURN } from './ObservedTURN';
7
+ import { Detectors } from './detectors/Detectors';
8
+ import { Updater } from './updaters/Updater';
7
9
  export type ObserverEvents = {
10
+ 'client-event': [ObservedClient, ClientEvent];
11
+ 'call-updated': [ObservedCall];
12
+ 'client-issue': [ObservedClient, ClientIssue];
13
+ 'client-metadata': [ObservedClient, ClientMetaData];
14
+ 'client-extension-stats': [ObservedClient, ExtensionStat];
8
15
  'newcall': [ObservedCall];
16
+ 'update': [];
9
17
  'close': [];
10
18
  };
11
- export type ProcessorInputContext<T> = {
12
- call: ObservedCall;
13
- client: ObservedClient;
14
- data: T;
19
+ export type ObserverConfig = {
20
+ updatePolicy?: 'update-on-any-call-updated' | 'update-when-all-call-updated' | 'update-on-interval';
21
+ updateIntervalInMs?: number;
22
+ defaultCallUpdatePolicy?: ObservedCallSettings['updatePolicy'];
23
+ defaultCallUpdateIntervalInMs?: number;
15
24
  };
16
25
  export declare interface Observer {
17
26
  on<U extends keyof ObserverEvents>(event: U, listener: (...args: ObserverEvents[U]) => void): this;
@@ -20,25 +29,33 @@ export declare interface Observer {
20
29
  emit<U extends keyof ObserverEvents>(event: U, ...args: ObserverEvents[U]): boolean;
21
30
  }
22
31
  export declare class Observer extends EventEmitter {
23
- readonly processors: {
24
- events: MiddlewareProcessor<ProcessorInputContext<ClientEvent>>;
25
- metaData: MiddlewareProcessor<ProcessorInputContext<ClientMetaData>>;
26
- issues: MiddlewareProcessor<ProcessorInputContext<ClientIssue>>;
27
- extensionStats: MiddlewareProcessor<ProcessorInputContext<ExtensionStat>>;
28
- };
32
+ readonly config: ObserverConfig;
33
+ readonly detectors: Detectors;
34
+ readonly observedTURN: ObservedTURN;
29
35
  readonly observedCalls: Map<string, ObservedCall<Record<string, unknown>>>;
36
+ updater?: Updater;
30
37
  closed: boolean;
31
- constructor();
38
+ totalAddedCall: number;
39
+ totalRemovedCall: number;
40
+ totalRttLt50Measurements: number;
41
+ totalRttLt150Measurements: number;
42
+ totalRttLt300Measurements: number;
43
+ totalRttGtOrEq300Measurements: number;
44
+ totalClientIssues: number;
45
+ numberOfClientsUsingTurn: number;
46
+ numberOfClients: number;
47
+ numberOfInboundRtpStreams: number;
48
+ numberOfOutboundRtpStreams: number;
49
+ numberOfDataChannels: number;
50
+ numberOfPeerConnections: number;
51
+ get numberOfCalls(): number;
52
+ private _timer?;
53
+ constructor(config?: ObserverConfig);
32
54
  getObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(callId: string): ObservedCall<T> | undefined;
33
55
  createObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedCallSettings<T>): ObservedCall<T>;
34
- addClientEventMiddleware(...middlewares: Middleware<ProcessorInputContext<ClientEvent>>[]): Observer;
35
- removeClientEventMiddleware(...middlewares: Middleware<ProcessorInputContext<ClientEvent>>[]): Observer;
36
- addClientMetaDataMiddleware(...middlewares: Middleware<ProcessorInputContext<ClientMetaData>>[]): Observer;
37
- removeClientMetaDataMiddleware(...middlewares: Middleware<ProcessorInputContext<ClientMetaData>>[]): Observer;
38
- addClientIssueMiddleware(...middlewares: Middleware<ProcessorInputContext<ClientIssue>>[]): Observer;
39
- removeClientIssueMiddleware(...middlewares: Middleware<ProcessorInputContext<ClientIssue>>[]): Observer;
40
- addExtensionStatMiddleware(...middlewares: Middleware<ProcessorInputContext<ExtensionStat>>[]): Observer;
41
- removeExtensionStatMiddleware(...middlewares: Middleware<ProcessorInputContext<ExtensionStat>>[]): Observer;
42
56
  close(): void;
57
+ accept(sample: ClientSample): void;
58
+ update(): void;
59
+ private _onObservedCallUpdated;
43
60
  }
44
61
  //# sourceMappingURL=Observer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Observer.d.ts","sourceRoot":"","sources":["../src/Observer.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAChG,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAIlD,MAAM,MAAM,cAAc,GAAG;IAC5B,SAAS,EAAE,CAAC,YAAY,CAAC,CAAC;IAC1B,OAAO,EAAE,EAAE,CAAC;CACZ,CAAA;AAED,MAAM,MAAM,qBAAqB,CAAC,CAAC,IAAI;IACtC,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,EAAE,CAAC,CAAC;CACR,CAAA;AAED,MAAM,CAAC,OAAO,WAAW,QAAQ;IAChC,EAAE,CAAC,CAAC,SAAS,MAAM,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACnG,GAAG,CAAC,CAAC,SAAS,MAAM,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACpG,IAAI,CAAC,CAAC,SAAS,MAAM,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACrG,IAAI,CAAC,CAAC,SAAS,MAAM,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;CACpF;AAED,qBAAa,QAAS,SAAQ,YAAY;IACzC,SAAgB,UAAU;;;;;MAKxB;IAEF,SAAgB,aAAa,qDAAmC;IACzD,MAAM,UAAS;;IAQf,eAAe,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS;IAMzH,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpF,QAAQ,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAC/B,YAAY,CAAC,CAAC,CAAC;IAoBX,wBAAwB,CAAC,GAAG,WAAW,EAAE,UAAU,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC,EAAE,GAAG,QAAQ;IAOpG,2BAA2B,CAAC,GAAG,WAAW,EAAE,UAAU,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC,EAAE,GAAG,QAAQ;IAOvG,2BAA2B,CAAC,GAAG,WAAW,EAAE,UAAU,CAAC,qBAAqB,CAAC,cAAc,CAAC,CAAC,EAAE,GAAG,QAAQ;IAO1G,8BAA8B,CAAC,GAAG,WAAW,EAAE,UAAU,CAAC,qBAAqB,CAAC,cAAc,CAAC,CAAC,EAAE,GAAG,QAAQ;IAO7G,wBAAwB,CAAC,GAAG,WAAW,EAAE,UAAU,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC,EAAE,GAAG,QAAQ;IAOpG,2BAA2B,CAAC,GAAG,WAAW,EAAE,UAAU,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC,EAAE,GAAG,QAAQ;IAOvG,0BAA0B,CAAC,GAAG,WAAW,EAAE,UAAU,CAAC,qBAAqB,CAAC,aAAa,CAAC,CAAC,EAAE,GAAG,QAAQ;IAOxG,6BAA6B,CAAC,GAAG,WAAW,EAAE,UAAU,CAAC,qBAAqB,CAAC,aAAa,CAAC,CAAC,EAAE,GAAG,QAAQ;IAO3G,KAAK;CAUZ"}
1
+ {"version":3,"file":"Observer.d.ts","sourceRoot":"","sources":["../src/Observer.ts"],"names":[],"mappings":"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"}