@webex/plugin-meetings 3.0.0-beta.75 → 3.0.0-beta.76

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.
@@ -28,6 +28,7 @@ import {
28
28
  getVideoSenderMqa,
29
29
  getVideoReceiverMqa,
30
30
  } from './mqaUtil';
31
+ import {ReceiveSlot} from '../multistream/receiveSlot';
31
32
 
32
33
  export const EVENTS = {
33
34
  MEDIA_QUALITY: 'MEDIA_QUALITY',
@@ -53,6 +54,8 @@ const emptyReceiver = {
53
54
  meanRoundTripTime: [],
54
55
  };
55
56
 
57
+ type ReceiveSlotCallback = (csi: number) => ReceiveSlot | undefined;
58
+
56
59
  /**
57
60
  * Stats Analyzer class that will emit events based on detected quality
58
61
  *
@@ -74,17 +77,20 @@ export class StatsAnalyzer extends EventsScope {
74
77
  statsInterval: NodeJS.Timeout;
75
78
  statsResults: any;
76
79
  statsStarted: any;
80
+ receiveSlotCallback: ReceiveSlotCallback;
77
81
 
78
82
  /**
79
83
  * Creates a new instance of StatsAnalyzer
80
84
  * @constructor
81
85
  * @public
82
86
  * @param {Object} config SDK Configuration Object
87
+ * @param {Function} receiveSlotCallback Callback used to access receive slots.
83
88
  * @param {Object} networkQualityMonitor class for assessing network characteristics (jitter, packetLoss, latency)
84
89
  * @param {Object} statsResults Default properties for stats
85
90
  */
86
91
  constructor(
87
92
  config: any,
93
+ receiveSlotCallback: ReceiveSlotCallback = () => undefined,
88
94
  networkQualityMonitor: object = {},
89
95
  statsResults: object = defaultStats
90
96
  ) {
@@ -98,6 +104,7 @@ export class StatsAnalyzer extends EventsScope {
98
104
  this.mqaSentCount = -1;
99
105
  this.lastMqaDataSent = {};
100
106
  this.lastEmittedStartStopEvent = {};
107
+ this.receiveSlotCallback = receiveSlotCallback;
101
108
  }
102
109
 
103
110
  /**
@@ -523,7 +530,8 @@ export class StatsAnalyzer extends EventsScope {
523
530
  currentStats.totalPacketsSent === 0
524
531
  ) {
525
532
  LoggerProxy.logger.info(
526
- `StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets sent`
533
+ `StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets sent`,
534
+ currentStats.totalPacketsSent
527
535
  );
528
536
  } else {
529
537
  if (
@@ -531,7 +539,8 @@ export class StatsAnalyzer extends EventsScope {
531
539
  currentStats.totalAudioEnergy === 0
532
540
  ) {
533
541
  LoggerProxy.logger.info(
534
- `StatsAnalyzer:index#compareLastStatsResult --> No audio Energy present`
542
+ `StatsAnalyzer:index#compareLastStatsResult --> No audio Energy present`,
543
+ currentStats.totalAudioEnergy
535
544
  );
536
545
  }
537
546
 
@@ -565,14 +574,16 @@ export class StatsAnalyzer extends EventsScope {
565
574
 
566
575
  if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
567
576
  LoggerProxy.logger.info(
568
- `StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets received`
577
+ `StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets received`,
578
+ currentPacketsReceived
569
579
  );
570
580
  } else if (
571
581
  currentSamplesReceived === previousSamplesReceived ||
572
582
  currentSamplesReceived === 0
573
583
  ) {
574
584
  LoggerProxy.logger.info(
575
- `StatsAnalyzer:index#compareLastStatsResult --> No audio samples received`
585
+ `StatsAnalyzer:index#compareLastStatsResult --> No audio samples received`,
586
+ currentSamplesReceived
576
587
  );
577
588
  }
578
589
 
@@ -589,7 +600,8 @@ export class StatsAnalyzer extends EventsScope {
589
600
  currentStats.totalPacketsSent === 0
590
601
  ) {
591
602
  LoggerProxy.logger.info(
592
- `StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent`
603
+ `StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent`,
604
+ currentStats.totalPacketsSent
593
605
  );
594
606
  } else {
595
607
  if (
@@ -597,7 +609,8 @@ export class StatsAnalyzer extends EventsScope {
597
609
  currentStats.framesEncoded === 0
598
610
  ) {
599
611
  LoggerProxy.logger.info(
600
- `StatsAnalyzer:index#compareLastStatsResult --> No video Frames Encoded`
612
+ `StatsAnalyzer:index#compareLastStatsResult --> No video Frames Encoded`,
613
+ currentStats.framesEncoded
601
614
  );
602
615
  }
603
616
 
@@ -607,7 +620,8 @@ export class StatsAnalyzer extends EventsScope {
607
620
  this.statsResults.resolutions['video-send'].send.framesSent === 0
608
621
  ) {
609
622
  LoggerProxy.logger.info(
610
- `StatsAnalyzer:index#compareLastStatsResult --> No video Frames sent`
623
+ `StatsAnalyzer:index#compareLastStatsResult --> No video Frames sent`,
624
+ this.statsResults.resolutions['video-send'].send.framesSent
611
625
  );
612
626
  }
613
627
  }
@@ -643,24 +657,28 @@ export class StatsAnalyzer extends EventsScope {
643
657
 
644
658
  if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
645
659
  LoggerProxy.logger.info(
646
- `StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets received`
660
+ `StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets received`,
661
+ currentPacketsReceived
647
662
  );
648
663
  } else {
649
664
  if (currentFramesReceived === previousFramesReceived || currentFramesReceived === 0) {
650
665
  LoggerProxy.logger.info(
651
- `StatsAnalyzer:index#compareLastStatsResult --> No video frames received`
666
+ `StatsAnalyzer:index#compareLastStatsResult --> No video frames received`,
667
+ currentFramesReceived
652
668
  );
653
669
  }
654
670
 
655
671
  if (currentFramesDecoded === previousFramesDecoded || currentFramesDecoded === 0) {
656
672
  LoggerProxy.logger.info(
657
- `StatsAnalyzer:index#compareLastStatsResult --> No video frames decoded`
673
+ `StatsAnalyzer:index#compareLastStatsResult --> No video frames decoded`,
674
+ currentFramesDecoded
658
675
  );
659
676
  }
660
677
 
661
678
  if (currentFramesDropped - previousFramesDropped > 10) {
662
679
  LoggerProxy.logger.info(
663
- `StatsAnalyzer:index#compareLastStatsResult --> video frames are getting dropped`
680
+ `StatsAnalyzer:index#compareLastStatsResult --> video frames are getting dropped`,
681
+ currentFramesDropped - previousFramesDropped
664
682
  );
665
683
  }
666
684
  }
@@ -679,7 +697,8 @@ export class StatsAnalyzer extends EventsScope {
679
697
  currentStats.totalPacketsSent === 0
680
698
  ) {
681
699
  LoggerProxy.logger.info(
682
- `StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets sent`
700
+ `StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets sent`,
701
+ currentStats.totalPacketsSent
683
702
  );
684
703
  } else {
685
704
  if (
@@ -687,7 +706,8 @@ export class StatsAnalyzer extends EventsScope {
687
706
  currentStats.framesEncoded === 0
688
707
  ) {
689
708
  LoggerProxy.logger.info(
690
- `StatsAnalyzer:index#compareLastStatsResult --> No share frames getting encoded`
709
+ `StatsAnalyzer:index#compareLastStatsResult --> No share frames getting encoded`,
710
+ currentStats.framesEncoded
691
711
  );
692
712
  }
693
713
 
@@ -697,7 +717,8 @@ export class StatsAnalyzer extends EventsScope {
697
717
  this.statsResults.resolutions['video-share-send'].send.framesSent === 0
698
718
  ) {
699
719
  LoggerProxy.logger.info(
700
- `StatsAnalyzer:index#compareLastStatsResult --> No share frames sent`
720
+ `StatsAnalyzer:index#compareLastStatsResult --> No share frames sent`,
721
+ this.statsResults.resolutions['video-share-send'].send.framesSent
701
722
  );
702
723
  }
703
724
  }
@@ -735,24 +756,28 @@ export class StatsAnalyzer extends EventsScope {
735
756
 
736
757
  if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
737
758
  LoggerProxy.logger.info(
738
- `StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets received`
759
+ `StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets received`,
760
+ currentPacketsReceived
739
761
  );
740
762
  } else {
741
763
  if (currentFramesReceived === previousFramesReceived || currentFramesReceived === 0) {
742
764
  LoggerProxy.logger.info(
743
- `StatsAnalyzer:index#compareLastStatsResult --> No share frames received`
765
+ `StatsAnalyzer:index#compareLastStatsResult --> No share frames received`,
766
+ currentFramesReceived
744
767
  );
745
768
  }
746
769
 
747
770
  if (currentFramesDecoded === previousFramesDecoded || currentFramesDecoded === 0) {
748
771
  LoggerProxy.logger.info(
749
- `StatsAnalyzer:index#compareLastStatsResult --> No share frames decoded`
772
+ `StatsAnalyzer:index#compareLastStatsResult --> No share frames decoded`,
773
+ currentFramesDecoded
750
774
  );
751
775
  }
752
776
 
753
777
  if (currentFramesDropped - previousFramesDropped > 10) {
754
778
  LoggerProxy.logger.info(
755
- `StatsAnalyzer:index#compareLastStatsResult --> share frames are getting dropped`
779
+ `StatsAnalyzer:index#compareLastStatsResult --> share frames are getting dropped`,
780
+ currentFramesDropped - previousFramesDropped
756
781
  );
757
782
  }
758
783
  }
@@ -933,6 +958,10 @@ export class StatsAnalyzer extends EventsScope {
933
958
 
934
959
  if (result.bytesReceived) {
935
960
  let kilobytes = 0;
961
+ const receiveSlot = this.receiveSlotCallback(result.ssrc);
962
+ const idAndCsi = receiveSlot
963
+ ? `id: "${receiveSlot.id || ''}"${receiveSlot.csi ? ` and csi: ${receiveSlot.csi}` : ''}`
964
+ : '';
936
965
 
937
966
  if (result.frameWidth && result.frameHeight) {
938
967
  this.statsResults.resolutions[mediaType][sendrecvType].width = result.frameWidth;
@@ -989,10 +1018,12 @@ export class StatsAnalyzer extends EventsScope {
989
1018
  result.packetsReceived;
990
1019
 
991
1020
  if (this.statsResults[mediaType][sendrecvType].packetsReceived === 0) {
992
- LoggerProxy.logger.info(
993
- `StatsAnalyzer:index#processInboundRTPResult --> No packets received for ${mediaType} `,
994
- this.statsResults[mediaType][sendrecvType].packetsReceived
995
- );
1021
+ if (receiveSlot) {
1022
+ LoggerProxy.logger.info(
1023
+ `StatsAnalyzer:index#processInboundRTPResult --> No packets received for receive slot ${idAndCsi}`,
1024
+ this.statsResults[mediaType][sendrecvType].packetsReceived
1025
+ );
1026
+ }
996
1027
  }
997
1028
 
998
1029
  // Check the over all packet Lost ratio
@@ -1004,7 +1035,7 @@ export class StatsAnalyzer extends EventsScope {
1004
1035
  : 0;
1005
1036
  if (this.statsResults[mediaType][sendrecvType].currentPacketLossRatio > 3) {
1006
1037
  LoggerProxy.logger.info(
1007
- 'StatsAnalyzer:index#processInboundRTPResult --> Packets getting lost from the receiver ',
1038
+ `StatsAnalyzer:index#processInboundRTPResult --> Packets getting lost from the receiver with slot ${idAndCsi}`,
1008
1039
  this.statsResults[mediaType][sendrecvType].currentPacketLossRatio
1009
1040
  );
1010
1041
  }
@@ -15,7 +15,7 @@ describe('ReceiveSlotManager', () => {
15
15
 
16
16
  beforeEach(() => {
17
17
  fakeWcmeSlot = {
18
- id: 'fake wcme slot',
18
+ id: {ssrc: 1},
19
19
  };
20
20
  fakeReceiveSlots = [];
21
21
  mockReceiveSlotCtor = sinon.stub(ReceiveSlotModule, 'ReceiveSlot').callsFake((mediaType) => {
@@ -23,6 +23,7 @@ describe('ReceiveSlotManager', () => {
23
23
  id: `fake sdk receive slot ${fakeReceiveSlots.length + 1}`,
24
24
  mediaType,
25
25
  findMemberId: sinon.stub(),
26
+ wcmeReceiveSlot: fakeWcmeSlot,
26
27
  };
27
28
 
28
29
  fakeReceiveSlots.push(fakeReceiveSlot);
@@ -168,7 +169,6 @@ describe('ReceiveSlotManager', () => {
168
169
  });
169
170
 
170
171
  describe('updateMemberIds', () => {
171
-
172
172
  it('calls findMemberId() on all allocated receive slots', async () => {
173
173
  const audioSlots: ReceiveSlot[] = [];
174
174
  const videoSlots: ReceiveSlot[] = [];
@@ -187,9 +187,17 @@ describe('ReceiveSlotManager', () => {
187
187
 
188
188
  assert.strictEqual(fakeReceiveSlots.length, audioSlots.length + videoSlots.length);
189
189
 
190
- fakeReceiveSlots.forEach(slot => {
190
+ fakeReceiveSlots.forEach((slot) => {
191
191
  assert.calledOnce(slot.findMemberId);
192
192
  });
193
193
  });
194
194
  });
195
+
196
+ describe('findReceiveSlotBySsrc', () => {
197
+ it('finds a receive slot with a specific id', async () => {
198
+ await receiveSlotManager.allocateSlot(MediaType.VideoMain);
199
+ assert.exists(receiveSlotManager.findReceiveSlotBySsrc(1));
200
+ assert.strictEqual(receiveSlotManager.findReceiveSlotBySsrc(2), undefined);
201
+ });
202
+ });
195
203
  });
@@ -53,7 +53,12 @@ describe('plugin-meetings', () => {
53
53
  beforeEach(() => {
54
54
  const networkQualityMonitor = new NetworkQualityMonitor(initialConfig);
55
55
 
56
- statsAnalyzer = new StatsAnalyzer(initialConfig, networkQualityMonitor, defaultStats);
56
+ statsAnalyzer = new StatsAnalyzer(
57
+ initialConfig,
58
+ () => ({}),
59
+ networkQualityMonitor,
60
+ defaultStats
61
+ );
57
62
 
58
63
  sandBoxSpy = sandbox.spy(
59
64
  statsAnalyzer.networkQualityMonitor,
@@ -188,7 +193,7 @@ describe('plugin-meetings', () => {
188
193
 
189
194
  networkQualityMonitor = new NetworkQualityMonitor(initialConfig);
190
195
 
191
- statsAnalyzer = new StatsAnalyzer(initialConfig, networkQualityMonitor);
196
+ statsAnalyzer = new StatsAnalyzer(initialConfig, () => ({}), networkQualityMonitor);
192
197
 
193
198
  statsAnalyzer.on(EVENTS.LOCAL_MEDIA_STARTED, (data) => {
194
199
  receivedEventsData.local.started = data;