@whereby.com/media 1.4.2 → 1.5.1

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.
package/dist/index.cjs CHANGED
@@ -31,6 +31,62 @@ function _interopNamespaceDefault(e) {
31
31
 
32
32
  var sdpTransform__namespace = /*#__PURE__*/_interopNamespaceDefault(sdpTransform);
33
33
 
34
+ const debugOn = process.env.NODE_ENV === "development" || new URLSearchParams(window.location.search).has("debug");
35
+ class Logger {
36
+ constructor() {
37
+ this._isEnabled = false;
38
+ this._debugger = null;
39
+ this._isEnabled = debugOn;
40
+ }
41
+ isEnabled() {
42
+ return this._isEnabled;
43
+ }
44
+ enable() {
45
+ this._isEnabled = true;
46
+ }
47
+ disable() {
48
+ this._isEnabled = false;
49
+ }
50
+ info(...params) {
51
+ if (!this._isEnabled) {
52
+ return;
53
+ }
54
+ return console.info(...params);
55
+ }
56
+ warn(...params) {
57
+ if (!this._isEnabled) {
58
+ return;
59
+ }
60
+ return console.warn(...params);
61
+ }
62
+ error(...params) {
63
+ if (!this._isEnabled) {
64
+ return;
65
+ }
66
+ return console.error(...params);
67
+ }
68
+ withDebugLogger(myDebugger = null) {
69
+ this._debugger = myDebugger;
70
+ return this;
71
+ }
72
+ debug(...params) {
73
+ if (!this._isEnabled || !this._debugger) {
74
+ return;
75
+ }
76
+ const suppliedParams = [];
77
+ params.forEach((param) => {
78
+ if (typeof param === "function") {
79
+ const suppliedParam = param();
80
+ suppliedParams.push(suppliedParam);
81
+ }
82
+ else {
83
+ suppliedParams.push(param);
84
+ }
85
+ });
86
+ this._debugger.print(...suppliedParams);
87
+ }
88
+ }
89
+
34
90
  /******************************************************************************
35
91
  Copyright (c) Microsoft Corporation.
36
92
 
@@ -63,34 +119,6 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
63
119
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
64
120
  };
65
121
 
66
- let peerConnections = [];
67
- let peerConnectionCounter = 0;
68
- const peerConnectionData = new WeakMap();
69
- const removePeerConnection = (pc) => {
70
- peerConnections = peerConnections.filter((old) => old !== pc);
71
- };
72
- if (window.RTCPeerConnection) {
73
- const OriginalRTCPeerConnection = window.RTCPeerConnection;
74
- function PatchedRTCPeerConnection(rtcConfig) {
75
- const pc = new OriginalRTCPeerConnection(rtcConfig);
76
- peerConnections.push(pc);
77
- peerConnectionData.set(pc, { index: peerConnectionCounter++ });
78
- const onConnectionStateChange = () => {
79
- if (pc.connectionState === "closed") {
80
- removePeerConnection(pc);
81
- pc.removeEventListener("connectionstatechange", onConnectionStateChange);
82
- }
83
- };
84
- pc.addEventListener("connectionstatechange", onConnectionStateChange);
85
- return pc;
86
- }
87
- PatchedRTCPeerConnection.prototype = OriginalRTCPeerConnection.prototype;
88
- window.RTCPeerConnection = PatchedRTCPeerConnection;
89
- }
90
- const getCurrentPeerConnections = () => peerConnections;
91
- const getPeerConnectionIndex = (pc) => { var _a; return (_a = peerConnectionData.get(pc)) === null || _a === void 0 ? void 0 : _a.index; };
92
- const setPeerConnectionsForTests = (pcs) => (peerConnections = pcs);
93
-
94
122
  function captureCandidatePairInfoMetrics(cpMetrics, currentCptats, prevCptats, timeDiff, report) {
95
123
  const bytesReceivedDiff = currentCptats.bytesReceived - ((prevCptats === null || prevCptats === void 0 ? void 0 : prevCptats.bytesReceived) || 0);
96
124
  const bytesSentDiff = currentCptats.bytesSent - ((prevCptats === null || prevCptats === void 0 ? void 0 : prevCptats.bytesSent) || 0);
@@ -252,119 +280,34 @@ function captureVideoSsrcMetrics(ssrcMetrics, currentSsrcStats, prevSsrcStats, t
252
280
  }
253
281
  }
254
282
 
255
- const debugOn = process.env.NODE_ENV === "development" || new URLSearchParams(window.location.search).has("debug");
256
- class Logger {
257
- constructor() {
258
- this._isEnabled = false;
259
- this._debugger = null;
260
- this._isEnabled = debugOn;
261
- }
262
- isEnabled() {
263
- return this._isEnabled;
264
- }
265
- enable() {
266
- this._isEnabled = true;
267
- }
268
- disable() {
269
- this._isEnabled = false;
270
- }
271
- info(...params) {
272
- if (!this._isEnabled) {
273
- return;
274
- }
275
- return console.info(...params);
276
- }
277
- warn(...params) {
278
- if (!this._isEnabled) {
279
- return;
280
- }
281
- return console.warn(...params);
282
- }
283
- error(...params) {
284
- if (!this._isEnabled) {
285
- return;
286
- }
287
- return console.error(...params);
288
- }
289
- withDebugLogger(myDebugger = null) {
290
- this._debugger = myDebugger;
291
- return this;
292
- }
293
- debug(...params) {
294
- if (!this._isEnabled || !this._debugger) {
295
- return;
296
- }
297
- const suppliedParams = [];
298
- params.forEach((param) => {
299
- if (typeof param === "function") {
300
- const suppliedParam = param();
301
- suppliedParams.push(suppliedParam);
302
- }
303
- else {
304
- suppliedParams.push(param);
283
+ let peerConnections = [];
284
+ let peerConnectionCounter = 0;
285
+ const peerConnectionData = new WeakMap();
286
+ const removePeerConnection = (pc) => {
287
+ peerConnections = peerConnections.filter((old) => old !== pc);
288
+ };
289
+ if (window.RTCPeerConnection) {
290
+ const OriginalRTCPeerConnection = window.RTCPeerConnection;
291
+ function PatchedRTCPeerConnection(rtcConfig) {
292
+ const pc = new OriginalRTCPeerConnection(rtcConfig);
293
+ peerConnections.push(pc);
294
+ peerConnectionData.set(pc, { index: peerConnectionCounter++ });
295
+ const onConnectionStateChange = () => {
296
+ if (pc.connectionState === "closed") {
297
+ removePeerConnection(pc);
298
+ pc.removeEventListener("connectionstatechange", onConnectionStateChange);
305
299
  }
306
- });
307
- this._debugger.print(...suppliedParams);
300
+ };
301
+ pc.addEventListener("connectionstatechange", onConnectionStateChange);
302
+ return pc;
308
303
  }
304
+ PatchedRTCPeerConnection.prototype = OriginalRTCPeerConnection.prototype;
305
+ window.RTCPeerConnection = PatchedRTCPeerConnection;
309
306
  }
307
+ const getCurrentPeerConnections = () => peerConnections;
308
+ const getPeerConnectionIndex = (pc) => { var _a; return (_a = peerConnectionData.get(pc)) === null || _a === void 0 ? void 0 : _a.index; };
309
+ const setPeerConnectionsForTests = (pcs) => (peerConnections = pcs);
310
310
 
311
- const logger$a = new Logger();
312
- const STATS_INTERVAL = 2000;
313
- let getClients = () => [];
314
- const setClientProvider = (provider) => (getClients = provider);
315
- const statsByView = {};
316
- const getStats = () => {
317
- return Object.assign({}, statsByView);
318
- };
319
- let subscriptions$1 = [];
320
- let currentMonitor = null;
321
- const getUpdatedStats = () => currentMonitor === null || currentMonitor === void 0 ? void 0 : currentMonitor.getUpdatedStats();
322
- const getOrCreateSsrcMetricsContainer = (time, pcIndex, clientId, trackId, ssrc) => {
323
- let viewStats = statsByView[clientId];
324
- if (!viewStats) {
325
- viewStats = { tracks: {}, startTime: time, updated: time };
326
- statsByView[clientId] = viewStats;
327
- }
328
- viewStats.updated = time;
329
- let trackStats = viewStats.tracks[trackId];
330
- if (!trackStats) {
331
- trackStats = { ssrcs: {}, startTime: time, updated: time };
332
- viewStats.tracks[trackId] = trackStats;
333
- }
334
- trackStats.updated = time;
335
- let ssrcStats = trackStats.ssrcs[ssrc];
336
- if (!ssrcStats) {
337
- ssrcStats = {
338
- startTime: time,
339
- updated: time,
340
- pcIndex,
341
- };
342
- trackStats.ssrcs[ssrc] = ssrcStats;
343
- }
344
- ssrcStats.updated = time;
345
- return ssrcStats;
346
- };
347
- const removeNonUpdatedStats = (time) => {
348
- Object.entries(statsByView).forEach(([viewId, viewStats]) => {
349
- if (viewStats.updated < time) {
350
- delete statsByView[viewId];
351
- }
352
- else {
353
- Object.entries(viewStats.tracks).forEach(([trackId, trackStats]) => {
354
- if (trackStats.updated < time) {
355
- delete viewStats.tracks[trackId];
356
- }
357
- else {
358
- Object.entries(trackStats.ssrcs).forEach(([ssrc, ssrcStats]) => {
359
- if (ssrcStats.updated < time) {
360
- delete trackStats.ssrcs[ssrc];
361
- }
362
- });
363
- }
364
- });
365
- }
366
- });
367
- };
368
311
  const pcDataByPc = new WeakMap();
369
312
  const getPeerConnectionsWithStatsReports = () => Promise.all(getCurrentPeerConnections().map((pc) => __awaiter(void 0, void 0, void 0, function* () {
370
313
  let pcData = pcDataByPc.get(pc);
@@ -424,59 +367,74 @@ const getPeerConnectionsWithStatsReports = () => Promise.all(getCurrentPeerConne
424
367
  return [pc, [], pcData];
425
368
  }
426
369
  })));
427
- let originTrialActivated = false;
428
- function activateComputePressureOriginTrial() {
429
- if (originTrialActivated)
430
- return;
431
- const otMeta = document.createElement("meta");
432
- otMeta.httpEquiv = "origin-trial";
433
- if (/hereby\.dev/.test(document.location.hostname)) {
434
- otMeta.content =
435
- "AkSNPHJw6EK08X0QU7kORnK9NABzRLAC7dqfXOwk5JwFAQG4Ey7WxLXxsnhieCgC1QHUdevE2EFICy7uBGDANwUAAABqeyJvcmlnaW4iOiJodHRwczovL2hlcmVieS5kZXY6NDQ0MyIsImZlYXR1cmUiOiJDb21wdXRlUHJlc3N1cmVfdjIiLCJleHBpcnkiOjE3MTY5NDA3OTksImlzU3ViZG9tYWluIjp0cnVlfQ==";
370
+
371
+ const getOrCreateSsrcMetricsContainer = (statsByView, time, pcIndex, clientId, trackId, ssrc) => {
372
+ let viewStats = statsByView[clientId];
373
+ if (!viewStats) {
374
+ viewStats = { tracks: {}, startTime: time, updated: time };
375
+ statsByView[clientId] = viewStats;
436
376
  }
437
- else {
438
- otMeta.content =
439
- "Asc2wu8KpSx648i932NICteQDFcB05yl2QUUSHD7AQo8JGP2Fp6FF91TvYVJBsKGzLMH349rysPw5q9tqPC/PAUAAABqeyJvcmlnaW4iOiJodHRwczovL3doZXJlYnkuY29tOjQ0MyIsImZlYXR1cmUiOiJDb21wdXRlUHJlc3N1cmVfdjIiLCJleHBpcnkiOjE3MTY5NDA3OTksImlzU3ViZG9tYWluIjp0cnVlfQ==";
377
+ viewStats.updated = time;
378
+ let trackStats = viewStats.tracks[trackId];
379
+ if (!trackStats) {
380
+ trackStats = { ssrcs: {}, startTime: time, updated: time };
381
+ viewStats.tracks[trackId] = trackStats;
440
382
  }
441
- document.head.append(otMeta);
442
- originTrialActivated = true;
443
- }
444
- function startStatsMonitor({ interval }) {
445
- let nextTimeout = 0;
446
- activateComputePressureOriginTrial();
447
- let pressureObserver;
448
- let lastPressureObserverRecord;
449
- try {
450
- if ("PressureObserver" in window) {
451
- pressureObserver = new window.PressureObserver((records) => (lastPressureObserverRecord = records.pop()), {
452
- sampleRate: 1,
383
+ trackStats.updated = time;
384
+ let ssrcStats = trackStats.ssrcs[ssrc];
385
+ if (!ssrcStats) {
386
+ ssrcStats = {
387
+ startTime: time,
388
+ updated: time,
389
+ pcIndex,
390
+ };
391
+ trackStats.ssrcs[ssrc] = ssrcStats;
392
+ }
393
+ ssrcStats.updated = time;
394
+ return ssrcStats;
395
+ };
396
+ const removeNonUpdatedStats = (statsByView, time) => {
397
+ Object.entries(statsByView).forEach(([viewId, viewStats]) => {
398
+ if (viewStats.updated < time) {
399
+ delete statsByView[viewId];
400
+ }
401
+ else {
402
+ Object.entries(viewStats.tracks).forEach(([trackId, trackStats]) => {
403
+ if (trackStats.updated < time) {
404
+ delete viewStats.tracks[trackId];
405
+ }
406
+ else {
407
+ Object.entries(trackStats.ssrcs).forEach(([ssrc, ssrcStats]) => {
408
+ if (ssrcStats.updated < time) {
409
+ delete trackStats.ssrcs[ssrc];
410
+ }
411
+ });
412
+ }
453
413
  });
454
- pressureObserver.observe("cpu");
455
414
  }
456
- }
457
- catch (ex) {
458
- logger$a.warn("Failed to observe CPU pressure", ex);
459
- }
460
- let lastUpdateTime = 0;
461
- const collectStats = (immediate) => __awaiter(this, void 0, void 0, function* () {
415
+ });
416
+ };
417
+ function collectStats(state, { logger, interval }, immediate) {
418
+ return __awaiter(this, void 0, void 0, function* () {
419
+ const collectStatsBound = collectStats.bind(null, state, { interval, logger });
462
420
  try {
463
- const clients = getClients();
421
+ const clients = state.getClients();
464
422
  const defaultClient = clients.find((c) => c.isLocalClient && !c.isPresentation) || { id: "unknown" };
465
- let defaultViewStats = statsByView[defaultClient.id];
423
+ let defaultViewStats = state.statsByView[defaultClient.id];
466
424
  if (!defaultViewStats) {
467
425
  defaultViewStats = { tracks: {}, candidatePairs: {}, pressure: null };
468
- statsByView[defaultClient.id] = defaultViewStats;
426
+ state.statsByView[defaultClient.id] = defaultViewStats;
469
427
  }
470
- defaultViewStats.pressure = lastPressureObserverRecord;
471
- const timeSinceLastUpdate = Date.now() - lastUpdateTime;
428
+ defaultViewStats.pressure = state.lastPressureObserverRecord;
429
+ const timeSinceLastUpdate = Date.now() - state.lastUpdateTime;
472
430
  if (timeSinceLastUpdate < 400) {
473
431
  if (immediate)
474
- return statsByView;
475
- subscriptions$1.forEach((subscription) => { var _a; return (_a = subscription.onUpdatedStats) === null || _a === void 0 ? void 0 : _a.call(subscription, statsByView, clients); });
476
- nextTimeout = setTimeout(collectStats, interval || STATS_INTERVAL);
432
+ return state.statsByView;
433
+ state.subscriptions.forEach((subscription) => { var _a; return (_a = subscription.onUpdatedStats) === null || _a === void 0 ? void 0 : _a.call(subscription, state.statsByView, clients); });
434
+ state.nextTimeout = setTimeout(collectStatsBound, interval);
477
435
  return;
478
436
  }
479
- lastUpdateTime = Date.now();
437
+ state.lastUpdateTime = Date.now();
480
438
  (yield getPeerConnectionsWithStatsReports()).forEach(([pc, report, pcData]) => {
481
439
  const pcIndex = getPeerConnectionIndex(pc);
482
440
  if (pc.connectionState === "closed") {
@@ -487,20 +445,17 @@ function startStatsMonitor({ interval }) {
487
445
  pcData.currentSSRCs = {};
488
446
  report.forEach((currentRtcStats) => {
489
447
  var _a, _b;
490
- if (currentRtcStats.type === "candidate-pair" &&
491
- /inprogress|succeeded/.test(currentRtcStats.state)) {
448
+ if (currentRtcStats.type === "candidate-pair" && /inprogress|succeeded/.test(currentRtcStats.state)) {
492
449
  const prevRtcStats = (_a = pcData._oldReport) === null || _a === void 0 ? void 0 : _a.get(currentRtcStats.id);
493
- const timeDiff = prevRtcStats
494
- ? currentRtcStats.timestamp - prevRtcStats.timestamp
495
- : STATS_INTERVAL;
450
+ const timeDiff = prevRtcStats ? currentRtcStats.timestamp - prevRtcStats.timestamp : interval;
496
451
  const cpId = pcIndex + ":" + currentRtcStats.id;
497
452
  let cpMetrics = defaultViewStats.candidatePairs[cpId];
498
453
  if (!cpMetrics) {
499
- cpMetrics = { startTime: lastUpdateTime, id: cpId };
454
+ cpMetrics = { startTime: state.lastUpdateTime, id: cpId };
500
455
  defaultViewStats.candidatePairs[cpId] = cpMetrics;
501
456
  }
502
457
  captureCandidatePairInfoMetrics(cpMetrics, currentRtcStats, prevRtcStats, timeDiff, report);
503
- cpMetrics.lastRtcStatsTime = lastUpdateTime;
458
+ cpMetrics.lastRtcStatsTime = state.lastUpdateTime;
504
459
  }
505
460
  if (currentRtcStats.type === "inbound-rtp" || currentRtcStats.type === "outbound-rtp") {
506
461
  const kind = currentRtcStats.mediaType || currentRtcStats.kind;
@@ -528,10 +483,8 @@ function startStatsMonitor({ interval }) {
528
483
  prevRtcStats = null;
529
484
  }
530
485
  }
531
- const timeDiff = prevRtcStats
532
- ? currentRtcStats.timestamp - prevRtcStats.timestamp
533
- : STATS_INTERVAL;
534
- const ssrcMetrics = getOrCreateSsrcMetricsContainer(lastUpdateTime, pcIndex, client.id, trackId, ssrc);
486
+ const timeDiff = prevRtcStats ? currentRtcStats.timestamp - prevRtcStats.timestamp : interval;
487
+ const ssrcMetrics = getOrCreateSsrcMetricsContainer(state.statsByView, state.lastUpdateTime, pcIndex, client.id, trackId, ssrc);
535
488
  captureSsrcInfo(ssrcMetrics, currentRtcStats, prevRtcStats, timeDiff, report);
536
489
  captureCommonSsrcMetrics(ssrcMetrics, currentRtcStats, prevRtcStats, timeDiff, report);
537
490
  if (kind === "video") {
@@ -548,7 +501,7 @@ function startStatsMonitor({ interval }) {
548
501
  .forEach((ssrc) => {
549
502
  const clientId = pcData.previousSSRCs[ssrc];
550
503
  if (clientId) {
551
- const clientView = statsByView[clientId];
504
+ const clientView = state.statsByView[clientId];
552
505
  if (clientView) {
553
506
  Object.values(clientView.tracks).forEach((trackStats) => {
554
507
  if (trackStats.ssrcs[ssrc]) {
@@ -559,55 +512,127 @@ function startStatsMonitor({ interval }) {
559
512
  }
560
513
  });
561
514
  });
562
- removeNonUpdatedStats(lastUpdateTime);
515
+ removeNonUpdatedStats(state.statsByView, state.lastUpdateTime);
563
516
  Object.entries(defaultViewStats.candidatePairs).forEach(([cpKey, cp]) => {
564
- const active = cp.lastRtcStatsTime === lastUpdateTime;
517
+ const active = cp.lastRtcStatsTime === state.lastUpdateTime;
565
518
  cp.active = active;
566
519
  if (!active) {
567
520
  cp.state = "old/inactive";
568
521
  if (!cp.inactiveFromTime)
569
- cp.inactiveFromTime = lastUpdateTime;
522
+ cp.inactiveFromTime = state.lastUpdateTime;
570
523
  else {
571
- if (lastUpdateTime - cp.inactiveFromTime > 4000) {
524
+ if (state.lastUpdateTime - cp.inactiveFromTime > 4000) {
572
525
  delete defaultViewStats.candidatePairs[cpKey];
573
526
  }
574
527
  }
575
528
  }
576
529
  });
577
530
  if (immediate) {
578
- return statsByView;
531
+ return state.statsByView;
579
532
  }
580
533
  else {
581
- subscriptions$1.forEach((subscription) => { var _a; return (_a = subscription.onUpdatedStats) === null || _a === void 0 ? void 0 : _a.call(subscription, statsByView, clients); });
534
+ state.subscriptions.forEach((subscription) => { var _a; return (_a = subscription.onUpdatedStats) === null || _a === void 0 ? void 0 : _a.call(subscription, state.statsByView, clients); });
582
535
  }
583
536
  }
584
537
  catch (ex) {
585
- logger$a.warn(ex);
538
+ logger.warn(ex);
586
539
  }
587
- nextTimeout = setTimeout(collectStats, interval || STATS_INTERVAL);
540
+ state.nextTimeout = setTimeout(collectStatsBound, interval);
588
541
  });
589
- setTimeout(collectStats, interval || STATS_INTERVAL);
590
- return {
591
- stop: () => {
592
- clearTimeout(nextTimeout);
593
- if (pressureObserver)
594
- pressureObserver.unobserve("cpu");
542
+ }
543
+
544
+ const REGISTERED_TRIALS = {};
545
+ function registerOriginTrials(trials, registeredTrials = REGISTERED_TRIALS, document = window.document) {
546
+ trials.forEach(({ hostnamePattern, token }) => {
547
+ const key = `${hostnamePattern}-${token}`;
548
+ if (registeredTrials[key]) {
549
+ return;
550
+ }
551
+ if (hostnamePattern.test(document.location.hostname)) {
552
+ const otMeta = document.createElement("meta");
553
+ otMeta.httpEquiv = "origin-trial";
554
+ otMeta.content = token;
555
+ document.head.append(otMeta);
556
+ registeredTrials[key] = true;
557
+ }
558
+ });
559
+ }
560
+
561
+ const CPU_OBSERVER_OPTIONS = {
562
+ sampleRate: 1,
563
+ originTrials: [
564
+ {
565
+ hostnamePattern: /hereby\.dev/,
566
+ token: "AkSNPHJw6EK08X0QU7kORnK9NABzRLAC7dqfXOwk5JwFAQG4Ey7WxLXxsnhieCgC1QHUdevE2EFICy7uBGDANwUAAABqeyJvcmlnaW4iOiJodHRwczovL2hlcmVieS5kZXY6NDQ0MyIsImZlYXR1cmUiOiJDb21wdXRlUHJlc3N1cmVfdjIiLCJleHBpcnkiOjE3MTY5NDA3OTksImlzU3ViZG9tYWluIjp0cnVlfQ==",
567
+ },
568
+ {
569
+ hostnamePattern: /whereby\.com/,
570
+ token: "Asc2wu8KpSx648i932NICteQDFcB05yl2QUUSHD7AQo8JGP2Fp6FF91TvYVJBsKGzLMH349rysPw5q9tqPC/PAUAAABqeyJvcmlnaW4iOiJodHRwczovL3doZXJlYnkuY29tOjQ0MyIsImZlYXR1cmUiOiJDb21wdXRlUHJlc3N1cmVfdjIiLCJleHBpcnkiOjE3MTY5NDA3OTksImlzU3ViZG9tYWluIjp0cnVlfQ==",
595
571
  },
572
+ ],
573
+ };
574
+ function startCpuObserver(cb, { sampleRate, originTrials } = CPU_OBSERVER_OPTIONS, window = globalThis.window) {
575
+ registerOriginTrials(originTrials);
576
+ let pressureObserver;
577
+ if ("PressureObserver" in window) {
578
+ pressureObserver = new window.PressureObserver(cb, { sampleRate });
579
+ pressureObserver.observe("cpu", { sampleInterval: sampleRate * 1000 });
580
+ return {
581
+ stop: () => {
582
+ pressureObserver.unobserve("cpu");
583
+ },
584
+ };
585
+ }
586
+ }
587
+
588
+ const STATE = {
589
+ currentMonitor: null,
590
+ getClients: () => [],
591
+ lastUpdateTime: 0,
592
+ statsByView: {},
593
+ subscriptions: [],
594
+ };
595
+ const OPTIONS = {
596
+ interval: 2000,
597
+ logger: new Logger(),
598
+ };
599
+ const getStats = () => {
600
+ return Object.assign({}, STATE.statsByView);
601
+ };
602
+ const getUpdatedStats = () => { var _a; return (_a = STATE.currentMonitor) === null || _a === void 0 ? void 0 : _a.getUpdatedStats(); };
603
+ const setClientProvider = (provider) => (STATE.getClients = provider);
604
+ function startStatsMonitor(state, { interval, logger }) {
605
+ const collectStatsBound = collectStats.bind(null, state, { interval, logger });
606
+ let cpuObserver;
607
+ try {
608
+ cpuObserver = startCpuObserver((records) => (state.lastPressureObserverRecord = records.pop()));
609
+ }
610
+ catch (ex) {
611
+ logger.warn("Failed to observe CPU pressure", ex);
612
+ }
613
+ setTimeout(collectStatsBound, interval);
614
+ return {
596
615
  getUpdatedStats: () => {
597
- return collectStats(true);
616
+ return collectStatsBound(true);
617
+ },
618
+ stop: () => {
619
+ clearTimeout(state.nextTimeout);
620
+ if (cpuObserver)
621
+ cpuObserver.stop();
598
622
  },
599
623
  };
600
624
  }
601
- function subscribeStats(subscription) {
602
- subscriptions$1.push(subscription);
603
- if (!currentMonitor)
604
- currentMonitor = startStatsMonitor({});
625
+ function subscribeStats(subscription, options = OPTIONS, state = STATE) {
626
+ state.subscriptions.push(subscription);
627
+ if (!state.currentMonitor)
628
+ state.currentMonitor = startStatsMonitor(state, options);
605
629
  return {
606
630
  stop() {
607
- subscriptions$1 = subscriptions$1.filter((s) => s !== subscription);
608
- if (!subscriptions$1.length) {
609
- currentMonitor === null || currentMonitor === void 0 ? void 0 : currentMonitor.stop();
610
- currentMonitor = null;
631
+ var _a;
632
+ state.subscriptions = state.subscriptions.filter((s) => s !== subscription);
633
+ if (!state.subscriptions.length) {
634
+ (_a = state.currentMonitor) === null || _a === void 0 ? void 0 : _a.stop();
635
+ state.currentMonitor = null;
611
636
  }
612
637
  },
613
638
  };
@@ -4992,13 +5017,9 @@ class VegaRtcManager {
4992
5017
  }
4993
5018
  _connect() {
4994
5019
  const host = this._features.sfuServerOverrideHost || [this._sfuServer.url];
4995
- const searchParams = new URLSearchParams({
4996
- clientId: this._selfId,
4997
- organizationId: this._room.organizationId,
4998
- roomName: this._room.name,
4999
- eventClaim: this._room.isClaimed ? this._eventClaim : null,
5000
- lowBw: "true",
5001
- });
5020
+ const searchParams = new URLSearchParams(Object.assign({ clientId: this._selfId, organizationId: this._room.organizationId, roomName: this._room.name, eventClaim: this._room.isClaimed ? this._eventClaim : null, lowBw: "true" }, Object.keys(this._features || {})
5021
+ .filter((featureKey) => this._features[featureKey] && /^sfu/.test(featureKey))
5022
+ .reduce((prev, current) => (Object.assign(Object.assign({}, prev), { [current]: this._features[current] })), {})));
5002
5023
  const queryString = searchParams.toString();
5003
5024
  const wsUrl = `wss://${host}?${queryString}`;
5004
5025
  this._vegaConnection = new VegaConnection(wsUrl);
package/dist/index.d.cts CHANGED
@@ -16,10 +16,45 @@ declare function startPerformanceMonitor({ onMetricsUpdated, onTerminated, isHid
16
16
  updateHidden: () => void;
17
17
  };
18
18
 
19
- declare const setClientProvider: (provider: any) => any;
19
+ declare class Logger {
20
+ _isEnabled: boolean;
21
+ _debugger: any;
22
+ constructor();
23
+ isEnabled(): boolean;
24
+ enable(): void;
25
+ disable(): void;
26
+ info(...params: any[]): void;
27
+ warn(...params: any[]): void;
28
+ error(...params: any[]): void;
29
+ withDebugLogger(myDebugger?: null): this;
30
+ debug(...params: any[]): void;
31
+ }
32
+
33
+ interface StatsMonitor {
34
+ getUpdatedStats: () => any;
35
+ stop: () => void;
36
+ }
37
+ interface StatsSubscription {
38
+ onUpdatedStats: (statsByView: any, clients: any) => void;
39
+ }
40
+ interface StatsMonitorState {
41
+ currentMonitor: StatsMonitor | null;
42
+ getClients: () => any[];
43
+ lastPressureObserverRecord?: any;
44
+ lastUpdateTime: number;
45
+ nextTimeout?: NodeJS.Timeout;
46
+ pressureObserver?: any;
47
+ statsByView: any;
48
+ subscriptions: StatsSubscription[];
49
+ }
50
+ interface StatsMonitorOptions {
51
+ interval: number;
52
+ logger: Pick<Logger, "debug" | "error" | "info" | "warn">;
53
+ }
20
54
  declare const getStats: () => any;
21
55
  declare const getUpdatedStats: () => any;
22
- declare function subscribeStats(subscription: any): {
56
+ declare const setClientProvider: (provider: any) => any;
57
+ declare function subscribeStats(subscription: StatsSubscription, options?: StatsMonitorOptions, state?: StatsMonitorState): {
23
58
  stop(): void;
24
59
  };
25
60
 
@@ -429,20 +464,6 @@ declare const ipRegex: {
429
464
  }): RegExp;
430
465
  };
431
466
 
432
- declare class Logger {
433
- _isEnabled: boolean;
434
- _debugger: any;
435
- constructor();
436
- isEnabled(): boolean;
437
- enable(): void;
438
- disable(): void;
439
- info(...params: any[]): void;
440
- warn(...params: any[]): void;
441
- error(...params: any[]): void;
442
- withDebugLogger(myDebugger?: null): this;
443
- debug(...params: any[]): void;
444
- }
445
-
446
467
  declare const getMediaSettings: (kind: string, isScreenShare: boolean, features: any) => {
447
468
  encodings: {}[];
448
469
  };
@@ -1359,4 +1380,4 @@ declare class RtcStream {
1359
1380
  static getTypeFromId(id: string): string;
1360
1381
  }
1361
1382
 
1362
- export { type AddSpotlightRequest, type AudioEnableRequest, type AudioEnableRequestedEvent, type AudioEnabledEvent, BandwidthTester, type ChatMessage, type ClientKickedEvent, type ClientLeftEvent, type ClientMetadataPayload, type ClientMetadataReceivedEvent, type ClientRole, type CloudRecordingStartedEvent, type Credentials, EVENTS, type GetConstraintsOptions, type GetDeviceDataResult, type GetMediaConstraintsOptions, type GetStreamOptions, type GetStreamResult, type GetUpdatedDevicesResult, type IdentifyDeviceRequest, type JoinRoomRequest, KNOCK_MESSAGES, KalmanFilter, type KnockAcceptedEvent, type KnockRejectedEvent, type KnockRoomRequest, type KnockerLeftEvent, Logger, MAXIMUM_TURN_BANDWIDTH, MAXIMUM_TURN_BANDWIDTH_UNLIMITED, MEDIA_JITTER_BUFFER_TARGET, type NewClientEvent, NoDevicesError, P2pRtcManager, PROTOCOL_ERRORS, PROTOCOL_EVENTS, PROTOCOL_REQUESTS, PROTOCOL_RESPONSES, RELAY_MESSAGES, ReconnectManager, type RemoveSpotlightRequest, type RoleName, type RoomJoinedEvent, type RoomKnockedEvent, type RoomLockedEvent, type RoomSessionEndedEvent, type RtcClientConnectionStatusChangedPayload, RtcEventNames, type RtcEvents, type RtcLocalStreamTrackAddedPayload, type RtcLocalStreamTrackRemovedPayload, type RtcManager, type RtcManagerCreatedPayload, RtcManagerDispatcher, RtcStream, type RtcStreamAddedPayload, STREAM_TYPES, type ScreenshareStartedEvent, type ScreenshareStoppedEvent, type SendClientMetadataRequest, ServerSocket, Session, SfuV2Parser, type SignalClient, type SignalEvents, type SignalKnocker, type SignalRequests, type SocketConf, type SocketManager, type Spotlight, type SpotlightAddedEvent, type SpotlightRemovedEvent, TYPES, VegaConnection, VegaMediaQualityMonitor, VegaRtcManager, type VideoEnabledEvent, addAbsCaptureTimeExtMap, addExtMap, assert, buildDeviceList, calculateStd, captureAudioSsrcMetrics, captureCandidatePairInfoMetrics, captureCommonSsrcMetrics, captureSsrcInfo, captureVideoSsrcMetrics, changeMediaDirection, compareLocalDevices, createACFCalculator, createMicAnalyser, createWorker, deprioritizeH264, detectMicrophoneNotWorking, enumerate, filterMidExtension, filterMsidSemantic, fromLocation, generateByteString, getConstraints, getCurrentPeerConnections, getDeviceData, getDisplayMedia, getHandler, getIssuesAndMetrics, getMediaConstraints, getMediaSettings, getOptimalBitrate, getPeerConnectionIndex, getStats, getStream, getStream2, getUpdatedDevices, getUpdatedStats, getUserMedia, hasGetDisplayMedia, ipRegex, isMobile, isRelayed, maybeRejectNoH264, maybeTurnOnly, modifyMediaCapabilities, removePeerConnection, replaceSSRCs, replaceTracksInStream, _default as rtcManagerEvents, rtcStats, setClientProvider, setCodecPreferenceSDP, setPeerConnectionsForTests, setVideoBandwidthUsingSetParameters, standardDeviation, startPerformanceMonitor, stopStreamTracks, subscribeIssues, subscribeStats, variance };
1383
+ export { type AddSpotlightRequest, type AudioEnableRequest, type AudioEnableRequestedEvent, type AudioEnabledEvent, BandwidthTester, type ChatMessage, type ClientKickedEvent, type ClientLeftEvent, type ClientMetadataPayload, type ClientMetadataReceivedEvent, type ClientRole, type CloudRecordingStartedEvent, type Credentials, EVENTS, type GetConstraintsOptions, type GetDeviceDataResult, type GetMediaConstraintsOptions, type GetStreamOptions, type GetStreamResult, type GetUpdatedDevicesResult, type IdentifyDeviceRequest, type JoinRoomRequest, KNOCK_MESSAGES, KalmanFilter, type KnockAcceptedEvent, type KnockRejectedEvent, type KnockRoomRequest, type KnockerLeftEvent, Logger, MAXIMUM_TURN_BANDWIDTH, MAXIMUM_TURN_BANDWIDTH_UNLIMITED, MEDIA_JITTER_BUFFER_TARGET, type NewClientEvent, NoDevicesError, P2pRtcManager, PROTOCOL_ERRORS, PROTOCOL_EVENTS, PROTOCOL_REQUESTS, PROTOCOL_RESPONSES, RELAY_MESSAGES, ReconnectManager, type RemoveSpotlightRequest, type RoleName, type RoomJoinedEvent, type RoomKnockedEvent, type RoomLockedEvent, type RoomSessionEndedEvent, type RtcClientConnectionStatusChangedPayload, RtcEventNames, type RtcEvents, type RtcLocalStreamTrackAddedPayload, type RtcLocalStreamTrackRemovedPayload, type RtcManager, type RtcManagerCreatedPayload, RtcManagerDispatcher, RtcStream, type RtcStreamAddedPayload, STREAM_TYPES, type ScreenshareStartedEvent, type ScreenshareStoppedEvent, type SendClientMetadataRequest, ServerSocket, Session, SfuV2Parser, type SignalClient, type SignalEvents, type SignalKnocker, type SignalRequests, type SocketConf, type SocketManager, type Spotlight, type SpotlightAddedEvent, type SpotlightRemovedEvent, type StatsMonitorOptions, type StatsMonitorState, TYPES, VegaConnection, VegaMediaQualityMonitor, VegaRtcManager, type VideoEnabledEvent, addAbsCaptureTimeExtMap, addExtMap, assert, buildDeviceList, calculateStd, captureAudioSsrcMetrics, captureCandidatePairInfoMetrics, captureCommonSsrcMetrics, captureSsrcInfo, captureVideoSsrcMetrics, changeMediaDirection, compareLocalDevices, createACFCalculator, createMicAnalyser, createWorker, deprioritizeH264, detectMicrophoneNotWorking, enumerate, filterMidExtension, filterMsidSemantic, fromLocation, generateByteString, getConstraints, getCurrentPeerConnections, getDeviceData, getDisplayMedia, getHandler, getIssuesAndMetrics, getMediaConstraints, getMediaSettings, getOptimalBitrate, getPeerConnectionIndex, getStats, getStream, getStream2, getUpdatedDevices, getUpdatedStats, getUserMedia, hasGetDisplayMedia, ipRegex, isMobile, isRelayed, maybeRejectNoH264, maybeTurnOnly, modifyMediaCapabilities, removePeerConnection, replaceSSRCs, replaceTracksInStream, _default as rtcManagerEvents, rtcStats, setClientProvider, setCodecPreferenceSDP, setPeerConnectionsForTests, setVideoBandwidthUsingSetParameters, standardDeviation, startPerformanceMonitor, stopStreamTracks, subscribeIssues, subscribeStats, variance };