@whereby.com/media 1.3.5 → 1.3.7

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
@@ -613,8 +613,71 @@ function subscribeStats(subscription) {
613
613
  };
614
614
  }
615
615
 
616
- let subscriptions = [];
617
- let stopStats = null;
616
+ const badNetworkIssueDetector = {
617
+ id: "bad-network",
618
+ enabled: ({ hasLiveTrack, ssrcs }) => hasLiveTrack && ssrcs.length > 0,
619
+ check: ({ client, clients, kind, ssrcs }) => {
620
+ const hasPositiveBitrate = ssrcs.some((ssrc) => ssrc.bitrate > 0);
621
+ if (!hasPositiveBitrate && client.isLocalClient && kind === "video") {
622
+ const remoteClients = clients.filter((c) => !c.isLocalClient);
623
+ if (remoteClients.length > 0) {
624
+ return !remoteClients.every((c) => c.isAudioOnlyModeEnabled);
625
+ }
626
+ }
627
+ const ssrc0 = ssrcs[0];
628
+ if (!ssrc0) {
629
+ return false;
630
+ }
631
+ return (ssrc0.bitrate === 0 ||
632
+ ssrc0.lossRatio > 0.03 ||
633
+ (ssrc0.fractionLost || 0) > 0.03 ||
634
+ (!client.isPresentation && kind === "video" && ssrc0.bitrate < 30000) ||
635
+ (ssrc0.direction === "in" && ssrc0.pliRate > 2));
636
+ },
637
+ };
638
+ const dryTrackIssueDetector = {
639
+ id: "dry-track",
640
+ enabled: ({ hasLiveTrack, ssrcs }) => !!(hasLiveTrack && ssrcs),
641
+ check: ({ client, clients, ssrcs }) => {
642
+ let hasPositiveBitrate = false;
643
+ ssrcs.forEach((ssrc) => {
644
+ hasPositiveBitrate = hasPositiveBitrate || ssrc.bitrate > 0;
645
+ });
646
+ if (!hasPositiveBitrate && client.isLocalClient) {
647
+ const remoteClients = clients.filter((c) => !c.isLocalClient);
648
+ if (remoteClients.length > 0) {
649
+ return !remoteClients.every((c) => c.isAudioOnlyModeEnabled);
650
+ }
651
+ }
652
+ return !hasPositiveBitrate;
653
+ },
654
+ };
655
+ const noTrackIssueDetector = {
656
+ id: "no-track",
657
+ enabled: () => true,
658
+ check: ({ client, clients, kind, track }) => {
659
+ if (!track && !client.isLocalClient && kind === "video") {
660
+ const localClient = clients.find((c) => c.isLocalClient);
661
+ if (localClient) {
662
+ return !localClient.isAudioOnlyModeEnabled;
663
+ }
664
+ }
665
+ return !track;
666
+ },
667
+ };
668
+ const noTrackStatsIssueDetector = {
669
+ id: "no-track-stats",
670
+ enabled: ({ hasLiveTrack }) => hasLiveTrack,
671
+ check: ({ client, clients, kind, ssrcs }) => {
672
+ if (ssrcs.length === 0 && !client.isLocalClient && kind === "video") {
673
+ const localClient = clients.find((c) => c.isLocalClient);
674
+ if (localClient) {
675
+ return !localClient.isAudioOnlyModeEnabled;
676
+ }
677
+ }
678
+ return ssrcs.length === 0;
679
+ },
680
+ };
618
681
  const issueDetectors = [
619
682
  {
620
683
  id: "desync",
@@ -641,39 +704,28 @@ const issueDetectors = [
641
704
  return diff > 500;
642
705
  },
643
706
  },
644
- {
645
- id: "no-track",
646
- check: ({ track }) => !track,
647
- },
707
+ noTrackIssueDetector,
648
708
  {
649
709
  id: "ended-track",
650
- enabled: ({ track }) => track,
651
- check: ({ track }) => track.readyState === "ended",
652
- },
653
- {
654
- id: "no-track-stats",
655
- enabled: ({ hasLiveTrack }) => hasLiveTrack,
656
- check: ({ ssrc0 }) => !ssrc0,
657
- },
658
- {
659
- id: "dry-track",
660
- enabled: ({ hasLiveTrack, ssrc0 }) => hasLiveTrack && ssrc0,
661
- check: ({ ssrc0 }) => ssrc0.bitrate === 0,
710
+ enabled: ({ track }) => !!track,
711
+ check: ({ track }) => (track === null || track === void 0 ? void 0 : track.readyState) === "ended",
662
712
  },
713
+ noTrackStatsIssueDetector,
714
+ dryTrackIssueDetector,
663
715
  {
664
716
  id: "low-layer0-bitrate",
665
- enabled: ({ hasLiveTrack, ssrc0, kind, client, }) => hasLiveTrack && kind === "video" && ssrc0 && ssrc0.height && !client.isPresentation,
717
+ enabled: ({ hasLiveTrack, ssrc0, kind, client }) => hasLiveTrack && kind === "video" && ssrc0 && ssrc0.height && !client.isPresentation,
666
718
  check: ({ ssrc0 }) => ssrc0.height < 200 && ssrc0.bitrate < 30000,
667
719
  },
668
720
  {
669
721
  id: "quality-limitation-bw",
670
- enabled: ({ hasLiveTrack, stats, client, kind, }) => hasLiveTrack && client.isLocalClient && kind === "video" && stats,
671
- check: ({ stats }) => Object.values(stats.tracks).find((track) => Object.values(track.ssrcs).find((ssrc) => ssrc.qualityLimitationReason === "bandwidth")),
722
+ enabled: ({ hasLiveTrack, stats, client, kind }) => hasLiveTrack && client.isLocalClient && kind === "video" && stats,
723
+ check: ({ stats }) => !!Object.values(stats.tracks).find((track) => Object.values(track.ssrcs).find((ssrc) => ssrc.qualityLimitationReason === "bandwidth")),
672
724
  },
673
725
  {
674
726
  id: "quality-limitation-cpu",
675
- enabled: ({ hasLiveTrack, stats, client, kind, }) => hasLiveTrack && client.isLocalClient && kind === "video" && stats,
676
- check: ({ stats }) => Object.values(stats.tracks).find((track) => Object.values(track.ssrcs).find((ssrc) => ssrc.qualityLimitationReason === "cpu")),
727
+ enabled: ({ hasLiveTrack, stats, client, kind }) => hasLiveTrack && client.isLocalClient && kind === "video" && stats,
728
+ check: ({ stats }) => !!Object.values(stats.tracks).find((track) => Object.values(track.ssrcs).find((ssrc) => ssrc.qualityLimitationReason === "cpu")),
677
729
  },
678
730
  {
679
731
  id: "high-plirate",
@@ -707,23 +759,15 @@ const issueDetectors = [
707
759
  },
708
760
  {
709
761
  id: "fps-below-20",
710
- enabled: ({ hasLiveTrack, ssrc0, kind, client, }) => hasLiveTrack && ssrc0 && ssrc0.height && kind === "video" && !client.isPresentation,
762
+ enabled: ({ hasLiveTrack, ssrc0, kind, client }) => hasLiveTrack && ssrc0 && ssrc0.height && kind === "video" && !client.isPresentation,
711
763
  check: ({ ssrc0 }) => ssrc0.height > 180 && ssrc0.fps < 20,
712
764
  },
713
765
  {
714
766
  id: "fps-below-10",
715
- enabled: ({ hasLiveTrack, ssrc0, kind, client, }) => hasLiveTrack && ssrc0 && ssrc0.height && kind === "video" && !client.isPresentation,
767
+ enabled: ({ hasLiveTrack, ssrc0, kind, client }) => hasLiveTrack && ssrc0 && ssrc0.height && kind === "video" && !client.isPresentation,
716
768
  check: ({ ssrc0 }) => ssrc0.fps < 10,
717
769
  },
718
- {
719
- id: "bad-network",
720
- enabled: ({ hasLiveTrack, ssrc0 }) => hasLiveTrack && ssrc0,
721
- check: ({ ssrc0, kind, client }) => ssrc0.bitrate === 0 ||
722
- ssrc0.lossRatio > 0.03 ||
723
- (ssrc0.fractionLost || 0) > 0.03 ||
724
- (!client.isPresentation && kind === "video" && ssrc0.bitrate < 30000) ||
725
- (ssrc0.direction === "in" && ssrc0.pliRate > 2),
726
- },
770
+ badNetworkIssueDetector,
727
771
  {
728
772
  id: "cpu-pressure-serious",
729
773
  global: true,
@@ -752,6 +796,9 @@ const issueDetectors = [
752
796
  check: ({ ssrc0 }) => ssrc0.bitrate && ssrc0.direction === "in" && ssrc0.audioLevel >= 0.001 && ssrc0.audioAcceleration >= 0.1,
753
797
  },
754
798
  ];
799
+
800
+ let subscriptions = [];
801
+ let stopStats = null;
755
802
  const metrics = [
756
803
  {
757
804
  id: "bitrate",
@@ -760,17 +807,17 @@ const metrics = [
760
807
  },
761
808
  {
762
809
  id: "pixelrate",
763
- enabled: ({ hasLiveTrack, track, ssrc0, kind, }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
810
+ enabled: ({ hasLiveTrack, track, ssrc0, kind }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
764
811
  value: ({ trackStats }) => Object.values(trackStats.ssrcs).reduce((sum, ssrc) => sum + (ssrc.fps || 0) * (ssrc.width || 0) * (ssrc.height || 0), 0),
765
812
  },
766
813
  {
767
814
  id: "height",
768
- enabled: ({ hasLiveTrack, track, ssrc0, kind, }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
815
+ enabled: ({ hasLiveTrack, track, ssrc0, kind }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
769
816
  value: ({ trackStats }) => Object.values(trackStats.ssrcs).reduce((max, ssrc) => Math.max(max, ssrc.fps > 0 ? ssrc.height : 0), 0),
770
817
  },
771
818
  {
772
819
  id: "sourceHeight",
773
- enabled: ({ hasLiveTrack, track, ssrc0, kind, }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.sourceHeight && ssrc0.direction === "out",
820
+ enabled: ({ hasLiveTrack, track, ssrc0, kind }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.sourceHeight && ssrc0.direction === "out",
774
821
  value: ({ ssrc0 }) => ssrc0.sourceHeight,
775
822
  },
776
823
  {
@@ -803,7 +850,7 @@ const metrics = [
803
850
  },
804
851
  {
805
852
  id: "active",
806
- value: ({ hasLiveTrack, track, ssrc0 }) => hasLiveTrack && track && ssrc0 ? 1 : 0,
853
+ value: ({ hasLiveTrack, track, ssrc0 }) => (hasLiveTrack && track && ssrc0 ? 1 : 0),
807
854
  },
808
855
  {
809
856
  id: "cpu-pressure",
@@ -843,7 +890,7 @@ const metrics = [
843
890
  },
844
891
  {
845
892
  id: "qpf",
846
- enabled: ({ hasLiveTrack, track, ssrc0, kind, }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
893
+ enabled: ({ hasLiveTrack, track, ssrc0, kind }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
847
894
  value: ({ trackStats }) => Object.values(trackStats.ssrcs).reduce((sum, ssrc) => sum + (ssrc.qpf || 0), 0),
848
895
  },
849
896
  ];
@@ -893,13 +940,15 @@ function onUpdatedStats(statsByView, clients) {
893
940
  issuesAndMetricsByView[client.id] = issuesAndMetrics;
894
941
  }
895
942
  const track = (_b = client[kind]) === null || _b === void 0 ? void 0 : _b.track;
896
- const hasLiveTrack = track && track.readyState !== "ended";
943
+ const hasLiveTrack = !!track && track.readyState !== "ended";
897
944
  const trackStats = track && stats && stats.tracks[track.id];
898
- const ssrcs = trackStats &&
899
- Object.values(trackStats.ssrcs).sort((a, b) => (a.height || Number.MAX_SAFE_INTEGER) - (b.height || Number.MAX_SAFE_INTEGER));
900
- const ssrc0 = trackStats && ssrcs[0];
945
+ const ssrcs = trackStats
946
+ ? Object.values(trackStats.ssrcs).sort((a, b) => (a.height || Number.MAX_SAFE_INTEGER) - (b.height || Number.MAX_SAFE_INTEGER))
947
+ : [];
948
+ const ssrc0 = ssrcs[0];
901
949
  const checkData = {
902
950
  client,
951
+ clients,
903
952
  kind,
904
953
  track,
905
954
  trackStats,
@@ -978,13 +1027,12 @@ function onUpdatedStats(statsByView, clients) {
978
1027
  }
979
1028
  });
980
1029
  issueDetectors.forEach((issueDetector) => {
981
- var _a;
982
1030
  if (issueDetector.global && kind !== "global")
983
1031
  return;
984
1032
  if (!issueDetector.global && kind === "global")
985
1033
  return;
986
1034
  const issueKey = `${qualifierString}-${issueDetector.id}`;
987
- const enabled = issueDetector.enabled ? issueDetector.enabled(checkData) : true;
1035
+ const enabled = issueDetector.enabled(checkData);
988
1036
  let issueData = issuesAndMetrics.issues[issueKey];
989
1037
  let aggregatedIssueData = aggregatedIssues[issueKey];
990
1038
  if (enabled) {
@@ -1014,7 +1062,7 @@ function onUpdatedStats(statsByView, clients) {
1014
1062
  }
1015
1063
  aggregatedIssueData.ticks++;
1016
1064
  aggregatedIssueData.curTicks++;
1017
- const issueDetected = (_a = issueDetector.check) === null || _a === void 0 ? void 0 : _a.call(issueDetector, checkData);
1065
+ const issueDetected = issueDetector.check(checkData);
1018
1066
  if (issueDetected) {
1019
1067
  issueData.registered++;
1020
1068
  issueData.current++;
@@ -5293,15 +5341,14 @@ class VegaRtcManager {
5293
5341
  _internalSendWebcam() {
5294
5342
  return __awaiter(this, void 0, void 0, function* () {
5295
5343
  logger$1.info("_internalSendWebcam()");
5344
+ if (!this._webcamTrack ||
5345
+ this._webcamTrack.readyState === "ended" ||
5346
+ !this._sendTransport ||
5347
+ this._webcamProducer) {
5348
+ return;
5349
+ }
5296
5350
  this._webcamProducerPromise = (() => __awaiter(this, void 0, void 0, function* () {
5297
5351
  try {
5298
- if (!this._webcamTrack ||
5299
- this._webcamTrack.readyState === "ended" ||
5300
- !this._sendTransport ||
5301
- this._webcamProducer) {
5302
- this._webcamProducerPromise = null;
5303
- return;
5304
- }
5305
5352
  const currentPaused = this._webcamPaused;
5306
5353
  const producer = yield this._sendTransport.produce(Object.assign(Object.assign({ track: this._webcamTrack, disableTrackOnPause: false, stopTracks: false }, getMediaSettings("video", false, this._features)), { appData: {
5307
5354
  streamId: OUTBOUND_CAM_OUTBOUND_STREAM_ID,
@@ -5345,7 +5392,7 @@ class VegaRtcManager {
5345
5392
  logger$1.info("_replaceWebcamTrack()");
5346
5393
  if (!this._webcamTrack)
5347
5394
  return;
5348
- if (!this._webcamProducer && this._webcamTrack.enabled)
5395
+ if (this._sendTransport && !this._webcamProducer && this._webcamTrack.enabled)
5349
5396
  yield this._internalSendWebcam();
5350
5397
  if (!this._webcamTrack || !this._webcamProducer || this._webcamProducer.closed)
5351
5398
  return;
package/dist/index.mjs CHANGED
@@ -592,8 +592,71 @@ function subscribeStats(subscription) {
592
592
  };
593
593
  }
594
594
 
595
- let subscriptions = [];
596
- let stopStats = null;
595
+ const badNetworkIssueDetector = {
596
+ id: "bad-network",
597
+ enabled: ({ hasLiveTrack, ssrcs }) => hasLiveTrack && ssrcs.length > 0,
598
+ check: ({ client, clients, kind, ssrcs }) => {
599
+ const hasPositiveBitrate = ssrcs.some((ssrc) => ssrc.bitrate > 0);
600
+ if (!hasPositiveBitrate && client.isLocalClient && kind === "video") {
601
+ const remoteClients = clients.filter((c) => !c.isLocalClient);
602
+ if (remoteClients.length > 0) {
603
+ return !remoteClients.every((c) => c.isAudioOnlyModeEnabled);
604
+ }
605
+ }
606
+ const ssrc0 = ssrcs[0];
607
+ if (!ssrc0) {
608
+ return false;
609
+ }
610
+ return (ssrc0.bitrate === 0 ||
611
+ ssrc0.lossRatio > 0.03 ||
612
+ (ssrc0.fractionLost || 0) > 0.03 ||
613
+ (!client.isPresentation && kind === "video" && ssrc0.bitrate < 30000) ||
614
+ (ssrc0.direction === "in" && ssrc0.pliRate > 2));
615
+ },
616
+ };
617
+ const dryTrackIssueDetector = {
618
+ id: "dry-track",
619
+ enabled: ({ hasLiveTrack, ssrcs }) => !!(hasLiveTrack && ssrcs),
620
+ check: ({ client, clients, ssrcs }) => {
621
+ let hasPositiveBitrate = false;
622
+ ssrcs.forEach((ssrc) => {
623
+ hasPositiveBitrate = hasPositiveBitrate || ssrc.bitrate > 0;
624
+ });
625
+ if (!hasPositiveBitrate && client.isLocalClient) {
626
+ const remoteClients = clients.filter((c) => !c.isLocalClient);
627
+ if (remoteClients.length > 0) {
628
+ return !remoteClients.every((c) => c.isAudioOnlyModeEnabled);
629
+ }
630
+ }
631
+ return !hasPositiveBitrate;
632
+ },
633
+ };
634
+ const noTrackIssueDetector = {
635
+ id: "no-track",
636
+ enabled: () => true,
637
+ check: ({ client, clients, kind, track }) => {
638
+ if (!track && !client.isLocalClient && kind === "video") {
639
+ const localClient = clients.find((c) => c.isLocalClient);
640
+ if (localClient) {
641
+ return !localClient.isAudioOnlyModeEnabled;
642
+ }
643
+ }
644
+ return !track;
645
+ },
646
+ };
647
+ const noTrackStatsIssueDetector = {
648
+ id: "no-track-stats",
649
+ enabled: ({ hasLiveTrack }) => hasLiveTrack,
650
+ check: ({ client, clients, kind, ssrcs }) => {
651
+ if (ssrcs.length === 0 && !client.isLocalClient && kind === "video") {
652
+ const localClient = clients.find((c) => c.isLocalClient);
653
+ if (localClient) {
654
+ return !localClient.isAudioOnlyModeEnabled;
655
+ }
656
+ }
657
+ return ssrcs.length === 0;
658
+ },
659
+ };
597
660
  const issueDetectors = [
598
661
  {
599
662
  id: "desync",
@@ -620,39 +683,28 @@ const issueDetectors = [
620
683
  return diff > 500;
621
684
  },
622
685
  },
623
- {
624
- id: "no-track",
625
- check: ({ track }) => !track,
626
- },
686
+ noTrackIssueDetector,
627
687
  {
628
688
  id: "ended-track",
629
- enabled: ({ track }) => track,
630
- check: ({ track }) => track.readyState === "ended",
631
- },
632
- {
633
- id: "no-track-stats",
634
- enabled: ({ hasLiveTrack }) => hasLiveTrack,
635
- check: ({ ssrc0 }) => !ssrc0,
636
- },
637
- {
638
- id: "dry-track",
639
- enabled: ({ hasLiveTrack, ssrc0 }) => hasLiveTrack && ssrc0,
640
- check: ({ ssrc0 }) => ssrc0.bitrate === 0,
689
+ enabled: ({ track }) => !!track,
690
+ check: ({ track }) => (track === null || track === void 0 ? void 0 : track.readyState) === "ended",
641
691
  },
692
+ noTrackStatsIssueDetector,
693
+ dryTrackIssueDetector,
642
694
  {
643
695
  id: "low-layer0-bitrate",
644
- enabled: ({ hasLiveTrack, ssrc0, kind, client, }) => hasLiveTrack && kind === "video" && ssrc0 && ssrc0.height && !client.isPresentation,
696
+ enabled: ({ hasLiveTrack, ssrc0, kind, client }) => hasLiveTrack && kind === "video" && ssrc0 && ssrc0.height && !client.isPresentation,
645
697
  check: ({ ssrc0 }) => ssrc0.height < 200 && ssrc0.bitrate < 30000,
646
698
  },
647
699
  {
648
700
  id: "quality-limitation-bw",
649
- enabled: ({ hasLiveTrack, stats, client, kind, }) => hasLiveTrack && client.isLocalClient && kind === "video" && stats,
650
- check: ({ stats }) => Object.values(stats.tracks).find((track) => Object.values(track.ssrcs).find((ssrc) => ssrc.qualityLimitationReason === "bandwidth")),
701
+ enabled: ({ hasLiveTrack, stats, client, kind }) => hasLiveTrack && client.isLocalClient && kind === "video" && stats,
702
+ check: ({ stats }) => !!Object.values(stats.tracks).find((track) => Object.values(track.ssrcs).find((ssrc) => ssrc.qualityLimitationReason === "bandwidth")),
651
703
  },
652
704
  {
653
705
  id: "quality-limitation-cpu",
654
- enabled: ({ hasLiveTrack, stats, client, kind, }) => hasLiveTrack && client.isLocalClient && kind === "video" && stats,
655
- check: ({ stats }) => Object.values(stats.tracks).find((track) => Object.values(track.ssrcs).find((ssrc) => ssrc.qualityLimitationReason === "cpu")),
706
+ enabled: ({ hasLiveTrack, stats, client, kind }) => hasLiveTrack && client.isLocalClient && kind === "video" && stats,
707
+ check: ({ stats }) => !!Object.values(stats.tracks).find((track) => Object.values(track.ssrcs).find((ssrc) => ssrc.qualityLimitationReason === "cpu")),
656
708
  },
657
709
  {
658
710
  id: "high-plirate",
@@ -686,23 +738,15 @@ const issueDetectors = [
686
738
  },
687
739
  {
688
740
  id: "fps-below-20",
689
- enabled: ({ hasLiveTrack, ssrc0, kind, client, }) => hasLiveTrack && ssrc0 && ssrc0.height && kind === "video" && !client.isPresentation,
741
+ enabled: ({ hasLiveTrack, ssrc0, kind, client }) => hasLiveTrack && ssrc0 && ssrc0.height && kind === "video" && !client.isPresentation,
690
742
  check: ({ ssrc0 }) => ssrc0.height > 180 && ssrc0.fps < 20,
691
743
  },
692
744
  {
693
745
  id: "fps-below-10",
694
- enabled: ({ hasLiveTrack, ssrc0, kind, client, }) => hasLiveTrack && ssrc0 && ssrc0.height && kind === "video" && !client.isPresentation,
746
+ enabled: ({ hasLiveTrack, ssrc0, kind, client }) => hasLiveTrack && ssrc0 && ssrc0.height && kind === "video" && !client.isPresentation,
695
747
  check: ({ ssrc0 }) => ssrc0.fps < 10,
696
748
  },
697
- {
698
- id: "bad-network",
699
- enabled: ({ hasLiveTrack, ssrc0 }) => hasLiveTrack && ssrc0,
700
- check: ({ ssrc0, kind, client }) => ssrc0.bitrate === 0 ||
701
- ssrc0.lossRatio > 0.03 ||
702
- (ssrc0.fractionLost || 0) > 0.03 ||
703
- (!client.isPresentation && kind === "video" && ssrc0.bitrate < 30000) ||
704
- (ssrc0.direction === "in" && ssrc0.pliRate > 2),
705
- },
749
+ badNetworkIssueDetector,
706
750
  {
707
751
  id: "cpu-pressure-serious",
708
752
  global: true,
@@ -731,6 +775,9 @@ const issueDetectors = [
731
775
  check: ({ ssrc0 }) => ssrc0.bitrate && ssrc0.direction === "in" && ssrc0.audioLevel >= 0.001 && ssrc0.audioAcceleration >= 0.1,
732
776
  },
733
777
  ];
778
+
779
+ let subscriptions = [];
780
+ let stopStats = null;
734
781
  const metrics = [
735
782
  {
736
783
  id: "bitrate",
@@ -739,17 +786,17 @@ const metrics = [
739
786
  },
740
787
  {
741
788
  id: "pixelrate",
742
- enabled: ({ hasLiveTrack, track, ssrc0, kind, }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
789
+ enabled: ({ hasLiveTrack, track, ssrc0, kind }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
743
790
  value: ({ trackStats }) => Object.values(trackStats.ssrcs).reduce((sum, ssrc) => sum + (ssrc.fps || 0) * (ssrc.width || 0) * (ssrc.height || 0), 0),
744
791
  },
745
792
  {
746
793
  id: "height",
747
- enabled: ({ hasLiveTrack, track, ssrc0, kind, }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
794
+ enabled: ({ hasLiveTrack, track, ssrc0, kind }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
748
795
  value: ({ trackStats }) => Object.values(trackStats.ssrcs).reduce((max, ssrc) => Math.max(max, ssrc.fps > 0 ? ssrc.height : 0), 0),
749
796
  },
750
797
  {
751
798
  id: "sourceHeight",
752
- enabled: ({ hasLiveTrack, track, ssrc0, kind, }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.sourceHeight && ssrc0.direction === "out",
799
+ enabled: ({ hasLiveTrack, track, ssrc0, kind }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.sourceHeight && ssrc0.direction === "out",
753
800
  value: ({ ssrc0 }) => ssrc0.sourceHeight,
754
801
  },
755
802
  {
@@ -782,7 +829,7 @@ const metrics = [
782
829
  },
783
830
  {
784
831
  id: "active",
785
- value: ({ hasLiveTrack, track, ssrc0 }) => hasLiveTrack && track && ssrc0 ? 1 : 0,
832
+ value: ({ hasLiveTrack, track, ssrc0 }) => (hasLiveTrack && track && ssrc0 ? 1 : 0),
786
833
  },
787
834
  {
788
835
  id: "cpu-pressure",
@@ -822,7 +869,7 @@ const metrics = [
822
869
  },
823
870
  {
824
871
  id: "qpf",
825
- enabled: ({ hasLiveTrack, track, ssrc0, kind, }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
872
+ enabled: ({ hasLiveTrack, track, ssrc0, kind }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
826
873
  value: ({ trackStats }) => Object.values(trackStats.ssrcs).reduce((sum, ssrc) => sum + (ssrc.qpf || 0), 0),
827
874
  },
828
875
  ];
@@ -872,13 +919,15 @@ function onUpdatedStats(statsByView, clients) {
872
919
  issuesAndMetricsByView[client.id] = issuesAndMetrics;
873
920
  }
874
921
  const track = (_b = client[kind]) === null || _b === void 0 ? void 0 : _b.track;
875
- const hasLiveTrack = track && track.readyState !== "ended";
922
+ const hasLiveTrack = !!track && track.readyState !== "ended";
876
923
  const trackStats = track && stats && stats.tracks[track.id];
877
- const ssrcs = trackStats &&
878
- Object.values(trackStats.ssrcs).sort((a, b) => (a.height || Number.MAX_SAFE_INTEGER) - (b.height || Number.MAX_SAFE_INTEGER));
879
- const ssrc0 = trackStats && ssrcs[0];
924
+ const ssrcs = trackStats
925
+ ? Object.values(trackStats.ssrcs).sort((a, b) => (a.height || Number.MAX_SAFE_INTEGER) - (b.height || Number.MAX_SAFE_INTEGER))
926
+ : [];
927
+ const ssrc0 = ssrcs[0];
880
928
  const checkData = {
881
929
  client,
930
+ clients,
882
931
  kind,
883
932
  track,
884
933
  trackStats,
@@ -957,13 +1006,12 @@ function onUpdatedStats(statsByView, clients) {
957
1006
  }
958
1007
  });
959
1008
  issueDetectors.forEach((issueDetector) => {
960
- var _a;
961
1009
  if (issueDetector.global && kind !== "global")
962
1010
  return;
963
1011
  if (!issueDetector.global && kind === "global")
964
1012
  return;
965
1013
  const issueKey = `${qualifierString}-${issueDetector.id}`;
966
- const enabled = issueDetector.enabled ? issueDetector.enabled(checkData) : true;
1014
+ const enabled = issueDetector.enabled(checkData);
967
1015
  let issueData = issuesAndMetrics.issues[issueKey];
968
1016
  let aggregatedIssueData = aggregatedIssues[issueKey];
969
1017
  if (enabled) {
@@ -993,7 +1041,7 @@ function onUpdatedStats(statsByView, clients) {
993
1041
  }
994
1042
  aggregatedIssueData.ticks++;
995
1043
  aggregatedIssueData.curTicks++;
996
- const issueDetected = (_a = issueDetector.check) === null || _a === void 0 ? void 0 : _a.call(issueDetector, checkData);
1044
+ const issueDetected = issueDetector.check(checkData);
997
1045
  if (issueDetected) {
998
1046
  issueData.registered++;
999
1047
  issueData.current++;
@@ -5272,15 +5320,14 @@ class VegaRtcManager {
5272
5320
  _internalSendWebcam() {
5273
5321
  return __awaiter(this, void 0, void 0, function* () {
5274
5322
  logger$1.info("_internalSendWebcam()");
5323
+ if (!this._webcamTrack ||
5324
+ this._webcamTrack.readyState === "ended" ||
5325
+ !this._sendTransport ||
5326
+ this._webcamProducer) {
5327
+ return;
5328
+ }
5275
5329
  this._webcamProducerPromise = (() => __awaiter(this, void 0, void 0, function* () {
5276
5330
  try {
5277
- if (!this._webcamTrack ||
5278
- this._webcamTrack.readyState === "ended" ||
5279
- !this._sendTransport ||
5280
- this._webcamProducer) {
5281
- this._webcamProducerPromise = null;
5282
- return;
5283
- }
5284
5331
  const currentPaused = this._webcamPaused;
5285
5332
  const producer = yield this._sendTransport.produce(Object.assign(Object.assign({ track: this._webcamTrack, disableTrackOnPause: false, stopTracks: false }, getMediaSettings("video", false, this._features)), { appData: {
5286
5333
  streamId: OUTBOUND_CAM_OUTBOUND_STREAM_ID,
@@ -5324,7 +5371,7 @@ class VegaRtcManager {
5324
5371
  logger$1.info("_replaceWebcamTrack()");
5325
5372
  if (!this._webcamTrack)
5326
5373
  return;
5327
- if (!this._webcamProducer && this._webcamTrack.enabled)
5374
+ if (this._sendTransport && !this._webcamProducer && this._webcamTrack.enabled)
5328
5375
  yield this._internalSendWebcam();
5329
5376
  if (!this._webcamTrack || !this._webcamProducer || this._webcamProducer.closed)
5330
5377
  return;
@@ -592,8 +592,71 @@ function subscribeStats(subscription) {
592
592
  };
593
593
  }
594
594
 
595
- let subscriptions = [];
596
- let stopStats = null;
595
+ const badNetworkIssueDetector = {
596
+ id: "bad-network",
597
+ enabled: ({ hasLiveTrack, ssrcs }) => hasLiveTrack && ssrcs.length > 0,
598
+ check: ({ client, clients, kind, ssrcs }) => {
599
+ const hasPositiveBitrate = ssrcs.some((ssrc) => ssrc.bitrate > 0);
600
+ if (!hasPositiveBitrate && client.isLocalClient && kind === "video") {
601
+ const remoteClients = clients.filter((c) => !c.isLocalClient);
602
+ if (remoteClients.length > 0) {
603
+ return !remoteClients.every((c) => c.isAudioOnlyModeEnabled);
604
+ }
605
+ }
606
+ const ssrc0 = ssrcs[0];
607
+ if (!ssrc0) {
608
+ return false;
609
+ }
610
+ return (ssrc0.bitrate === 0 ||
611
+ ssrc0.lossRatio > 0.03 ||
612
+ (ssrc0.fractionLost || 0) > 0.03 ||
613
+ (!client.isPresentation && kind === "video" && ssrc0.bitrate < 30000) ||
614
+ (ssrc0.direction === "in" && ssrc0.pliRate > 2));
615
+ },
616
+ };
617
+ const dryTrackIssueDetector = {
618
+ id: "dry-track",
619
+ enabled: ({ hasLiveTrack, ssrcs }) => !!(hasLiveTrack && ssrcs),
620
+ check: ({ client, clients, ssrcs }) => {
621
+ let hasPositiveBitrate = false;
622
+ ssrcs.forEach((ssrc) => {
623
+ hasPositiveBitrate = hasPositiveBitrate || ssrc.bitrate > 0;
624
+ });
625
+ if (!hasPositiveBitrate && client.isLocalClient) {
626
+ const remoteClients = clients.filter((c) => !c.isLocalClient);
627
+ if (remoteClients.length > 0) {
628
+ return !remoteClients.every((c) => c.isAudioOnlyModeEnabled);
629
+ }
630
+ }
631
+ return !hasPositiveBitrate;
632
+ },
633
+ };
634
+ const noTrackIssueDetector = {
635
+ id: "no-track",
636
+ enabled: () => true,
637
+ check: ({ client, clients, kind, track }) => {
638
+ if (!track && !client.isLocalClient && kind === "video") {
639
+ const localClient = clients.find((c) => c.isLocalClient);
640
+ if (localClient) {
641
+ return !localClient.isAudioOnlyModeEnabled;
642
+ }
643
+ }
644
+ return !track;
645
+ },
646
+ };
647
+ const noTrackStatsIssueDetector = {
648
+ id: "no-track-stats",
649
+ enabled: ({ hasLiveTrack }) => hasLiveTrack,
650
+ check: ({ client, clients, kind, ssrcs }) => {
651
+ if (ssrcs.length === 0 && !client.isLocalClient && kind === "video") {
652
+ const localClient = clients.find((c) => c.isLocalClient);
653
+ if (localClient) {
654
+ return !localClient.isAudioOnlyModeEnabled;
655
+ }
656
+ }
657
+ return ssrcs.length === 0;
658
+ },
659
+ };
597
660
  const issueDetectors = [
598
661
  {
599
662
  id: "desync",
@@ -620,39 +683,28 @@ const issueDetectors = [
620
683
  return diff > 500;
621
684
  },
622
685
  },
623
- {
624
- id: "no-track",
625
- check: ({ track }) => !track,
626
- },
686
+ noTrackIssueDetector,
627
687
  {
628
688
  id: "ended-track",
629
- enabled: ({ track }) => track,
630
- check: ({ track }) => track.readyState === "ended",
631
- },
632
- {
633
- id: "no-track-stats",
634
- enabled: ({ hasLiveTrack }) => hasLiveTrack,
635
- check: ({ ssrc0 }) => !ssrc0,
636
- },
637
- {
638
- id: "dry-track",
639
- enabled: ({ hasLiveTrack, ssrc0 }) => hasLiveTrack && ssrc0,
640
- check: ({ ssrc0 }) => ssrc0.bitrate === 0,
689
+ enabled: ({ track }) => !!track,
690
+ check: ({ track }) => (track === null || track === void 0 ? void 0 : track.readyState) === "ended",
641
691
  },
692
+ noTrackStatsIssueDetector,
693
+ dryTrackIssueDetector,
642
694
  {
643
695
  id: "low-layer0-bitrate",
644
- enabled: ({ hasLiveTrack, ssrc0, kind, client, }) => hasLiveTrack && kind === "video" && ssrc0 && ssrc0.height && !client.isPresentation,
696
+ enabled: ({ hasLiveTrack, ssrc0, kind, client }) => hasLiveTrack && kind === "video" && ssrc0 && ssrc0.height && !client.isPresentation,
645
697
  check: ({ ssrc0 }) => ssrc0.height < 200 && ssrc0.bitrate < 30000,
646
698
  },
647
699
  {
648
700
  id: "quality-limitation-bw",
649
- enabled: ({ hasLiveTrack, stats, client, kind, }) => hasLiveTrack && client.isLocalClient && kind === "video" && stats,
650
- check: ({ stats }) => Object.values(stats.tracks).find((track) => Object.values(track.ssrcs).find((ssrc) => ssrc.qualityLimitationReason === "bandwidth")),
701
+ enabled: ({ hasLiveTrack, stats, client, kind }) => hasLiveTrack && client.isLocalClient && kind === "video" && stats,
702
+ check: ({ stats }) => !!Object.values(stats.tracks).find((track) => Object.values(track.ssrcs).find((ssrc) => ssrc.qualityLimitationReason === "bandwidth")),
651
703
  },
652
704
  {
653
705
  id: "quality-limitation-cpu",
654
- enabled: ({ hasLiveTrack, stats, client, kind, }) => hasLiveTrack && client.isLocalClient && kind === "video" && stats,
655
- check: ({ stats }) => Object.values(stats.tracks).find((track) => Object.values(track.ssrcs).find((ssrc) => ssrc.qualityLimitationReason === "cpu")),
706
+ enabled: ({ hasLiveTrack, stats, client, kind }) => hasLiveTrack && client.isLocalClient && kind === "video" && stats,
707
+ check: ({ stats }) => !!Object.values(stats.tracks).find((track) => Object.values(track.ssrcs).find((ssrc) => ssrc.qualityLimitationReason === "cpu")),
656
708
  },
657
709
  {
658
710
  id: "high-plirate",
@@ -686,23 +738,15 @@ const issueDetectors = [
686
738
  },
687
739
  {
688
740
  id: "fps-below-20",
689
- enabled: ({ hasLiveTrack, ssrc0, kind, client, }) => hasLiveTrack && ssrc0 && ssrc0.height && kind === "video" && !client.isPresentation,
741
+ enabled: ({ hasLiveTrack, ssrc0, kind, client }) => hasLiveTrack && ssrc0 && ssrc0.height && kind === "video" && !client.isPresentation,
690
742
  check: ({ ssrc0 }) => ssrc0.height > 180 && ssrc0.fps < 20,
691
743
  },
692
744
  {
693
745
  id: "fps-below-10",
694
- enabled: ({ hasLiveTrack, ssrc0, kind, client, }) => hasLiveTrack && ssrc0 && ssrc0.height && kind === "video" && !client.isPresentation,
746
+ enabled: ({ hasLiveTrack, ssrc0, kind, client }) => hasLiveTrack && ssrc0 && ssrc0.height && kind === "video" && !client.isPresentation,
695
747
  check: ({ ssrc0 }) => ssrc0.fps < 10,
696
748
  },
697
- {
698
- id: "bad-network",
699
- enabled: ({ hasLiveTrack, ssrc0 }) => hasLiveTrack && ssrc0,
700
- check: ({ ssrc0, kind, client }) => ssrc0.bitrate === 0 ||
701
- ssrc0.lossRatio > 0.03 ||
702
- (ssrc0.fractionLost || 0) > 0.03 ||
703
- (!client.isPresentation && kind === "video" && ssrc0.bitrate < 30000) ||
704
- (ssrc0.direction === "in" && ssrc0.pliRate > 2),
705
- },
749
+ badNetworkIssueDetector,
706
750
  {
707
751
  id: "cpu-pressure-serious",
708
752
  global: true,
@@ -731,6 +775,9 @@ const issueDetectors = [
731
775
  check: ({ ssrc0 }) => ssrc0.bitrate && ssrc0.direction === "in" && ssrc0.audioLevel >= 0.001 && ssrc0.audioAcceleration >= 0.1,
732
776
  },
733
777
  ];
778
+
779
+ let subscriptions = [];
780
+ let stopStats = null;
734
781
  const metrics = [
735
782
  {
736
783
  id: "bitrate",
@@ -739,17 +786,17 @@ const metrics = [
739
786
  },
740
787
  {
741
788
  id: "pixelrate",
742
- enabled: ({ hasLiveTrack, track, ssrc0, kind, }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
789
+ enabled: ({ hasLiveTrack, track, ssrc0, kind }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
743
790
  value: ({ trackStats }) => Object.values(trackStats.ssrcs).reduce((sum, ssrc) => sum + (ssrc.fps || 0) * (ssrc.width || 0) * (ssrc.height || 0), 0),
744
791
  },
745
792
  {
746
793
  id: "height",
747
- enabled: ({ hasLiveTrack, track, ssrc0, kind, }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
794
+ enabled: ({ hasLiveTrack, track, ssrc0, kind }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
748
795
  value: ({ trackStats }) => Object.values(trackStats.ssrcs).reduce((max, ssrc) => Math.max(max, ssrc.fps > 0 ? ssrc.height : 0), 0),
749
796
  },
750
797
  {
751
798
  id: "sourceHeight",
752
- enabled: ({ hasLiveTrack, track, ssrc0, kind, }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.sourceHeight && ssrc0.direction === "out",
799
+ enabled: ({ hasLiveTrack, track, ssrc0, kind }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.sourceHeight && ssrc0.direction === "out",
753
800
  value: ({ ssrc0 }) => ssrc0.sourceHeight,
754
801
  },
755
802
  {
@@ -782,7 +829,7 @@ const metrics = [
782
829
  },
783
830
  {
784
831
  id: "active",
785
- value: ({ hasLiveTrack, track, ssrc0 }) => hasLiveTrack && track && ssrc0 ? 1 : 0,
832
+ value: ({ hasLiveTrack, track, ssrc0 }) => (hasLiveTrack && track && ssrc0 ? 1 : 0),
786
833
  },
787
834
  {
788
835
  id: "cpu-pressure",
@@ -822,7 +869,7 @@ const metrics = [
822
869
  },
823
870
  {
824
871
  id: "qpf",
825
- enabled: ({ hasLiveTrack, track, ssrc0, kind, }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
872
+ enabled: ({ hasLiveTrack, track, ssrc0, kind }) => hasLiveTrack && kind === "video" && track && ssrc0 && ssrc0.height,
826
873
  value: ({ trackStats }) => Object.values(trackStats.ssrcs).reduce((sum, ssrc) => sum + (ssrc.qpf || 0), 0),
827
874
  },
828
875
  ];
@@ -872,13 +919,15 @@ function onUpdatedStats(statsByView, clients) {
872
919
  issuesAndMetricsByView[client.id] = issuesAndMetrics;
873
920
  }
874
921
  const track = (_b = client[kind]) === null || _b === void 0 ? void 0 : _b.track;
875
- const hasLiveTrack = track && track.readyState !== "ended";
922
+ const hasLiveTrack = !!track && track.readyState !== "ended";
876
923
  const trackStats = track && stats && stats.tracks[track.id];
877
- const ssrcs = trackStats &&
878
- Object.values(trackStats.ssrcs).sort((a, b) => (a.height || Number.MAX_SAFE_INTEGER) - (b.height || Number.MAX_SAFE_INTEGER));
879
- const ssrc0 = trackStats && ssrcs[0];
924
+ const ssrcs = trackStats
925
+ ? Object.values(trackStats.ssrcs).sort((a, b) => (a.height || Number.MAX_SAFE_INTEGER) - (b.height || Number.MAX_SAFE_INTEGER))
926
+ : [];
927
+ const ssrc0 = ssrcs[0];
880
928
  const checkData = {
881
929
  client,
930
+ clients,
882
931
  kind,
883
932
  track,
884
933
  trackStats,
@@ -957,13 +1006,12 @@ function onUpdatedStats(statsByView, clients) {
957
1006
  }
958
1007
  });
959
1008
  issueDetectors.forEach((issueDetector) => {
960
- var _a;
961
1009
  if (issueDetector.global && kind !== "global")
962
1010
  return;
963
1011
  if (!issueDetector.global && kind === "global")
964
1012
  return;
965
1013
  const issueKey = `${qualifierString}-${issueDetector.id}`;
966
- const enabled = issueDetector.enabled ? issueDetector.enabled(checkData) : true;
1014
+ const enabled = issueDetector.enabled(checkData);
967
1015
  let issueData = issuesAndMetrics.issues[issueKey];
968
1016
  let aggregatedIssueData = aggregatedIssues[issueKey];
969
1017
  if (enabled) {
@@ -993,7 +1041,7 @@ function onUpdatedStats(statsByView, clients) {
993
1041
  }
994
1042
  aggregatedIssueData.ticks++;
995
1043
  aggregatedIssueData.curTicks++;
996
- const issueDetected = (_a = issueDetector.check) === null || _a === void 0 ? void 0 : _a.call(issueDetector, checkData);
1044
+ const issueDetected = issueDetector.check(checkData);
997
1045
  if (issueDetected) {
998
1046
  issueData.registered++;
999
1047
  issueData.current++;
@@ -5272,15 +5320,14 @@ class VegaRtcManager {
5272
5320
  _internalSendWebcam() {
5273
5321
  return __awaiter(this, void 0, void 0, function* () {
5274
5322
  logger$1.info("_internalSendWebcam()");
5323
+ if (!this._webcamTrack ||
5324
+ this._webcamTrack.readyState === "ended" ||
5325
+ !this._sendTransport ||
5326
+ this._webcamProducer) {
5327
+ return;
5328
+ }
5275
5329
  this._webcamProducerPromise = (() => __awaiter(this, void 0, void 0, function* () {
5276
5330
  try {
5277
- if (!this._webcamTrack ||
5278
- this._webcamTrack.readyState === "ended" ||
5279
- !this._sendTransport ||
5280
- this._webcamProducer) {
5281
- this._webcamProducerPromise = null;
5282
- return;
5283
- }
5284
5331
  const currentPaused = this._webcamPaused;
5285
5332
  const producer = yield this._sendTransport.produce(Object.assign(Object.assign({ track: this._webcamTrack, disableTrackOnPause: false, stopTracks: false }, getMediaSettings("video", false, this._features)), { appData: {
5286
5333
  streamId: OUTBOUND_CAM_OUTBOUND_STREAM_ID,
@@ -5324,7 +5371,7 @@ class VegaRtcManager {
5324
5371
  logger$1.info("_replaceWebcamTrack()");
5325
5372
  if (!this._webcamTrack)
5326
5373
  return;
5327
- if (!this._webcamProducer && this._webcamTrack.enabled)
5374
+ if (this._sendTransport && !this._webcamProducer && this._webcamTrack.enabled)
5328
5375
  yield this._internalSendWebcam();
5329
5376
  if (!this._webcamTrack || !this._webcamProducer || this._webcamProducer.closed)
5330
5377
  return;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@whereby.com/media",
3
3
  "description": "Media library for Whereby",
4
- "version": "1.3.5",
4
+ "version": "1.3.7",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/whereby/sdk",
7
7
  "repository": {