@webex/plugin-meetings 3.3.1-next.1 → 3.3.1-next.11
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/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/mediaQualityMetrics/config.js +10 -6
- package/dist/mediaQualityMetrics/config.js.map +1 -1
- package/dist/meeting/index.js +9 -5
- package/dist/meeting/index.js.map +1 -1
- package/dist/statsAnalyzer/index.js +74 -26
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/statsAnalyzer/mqaUtil.js +34 -8
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
- package/dist/types/mediaQualityMetrics/config.d.ts +6 -0
- package/dist/types/statsAnalyzer/index.d.ts +14 -6
- package/dist/types/statsAnalyzer/mqaUtil.d.ts +17 -4
- package/dist/webinar/index.js +1 -1
- package/package.json +22 -22
- package/src/mediaQualityMetrics/config.ts +9 -3
- package/src/meeting/index.ts +6 -5
- package/src/statsAnalyzer/index.ts +78 -21
- package/src/statsAnalyzer/mqaUtil.ts +53 -5
- package/test/unit/spec/stats-analyzer/index.js +586 -312
|
@@ -16,6 +16,14 @@ const {assert} = chai;
|
|
|
16
16
|
chai.use(chaiAsPromised);
|
|
17
17
|
sinon.assert.expose(chai.assert, {prefix: ''});
|
|
18
18
|
|
|
19
|
+
const startStatsAnalyzer = async ({statsAnalyzer, mediaStatus, lastEmittedEvents = {}, pc}) => {
|
|
20
|
+
statsAnalyzer.updateMediaStatus(mediaStatus);
|
|
21
|
+
statsAnalyzer.startAnalyzer(pc);
|
|
22
|
+
statsAnalyzer.lastEmittedStartStopEvent = lastEmittedEvents;
|
|
23
|
+
|
|
24
|
+
await testUtils.flushPromises();
|
|
25
|
+
};
|
|
26
|
+
|
|
19
27
|
describe('plugin-meetings', () => {
|
|
20
28
|
describe('StatsAnalyzer', () => {
|
|
21
29
|
describe('parseStatsResult', () => {
|
|
@@ -29,10 +37,12 @@ describe('plugin-meetings', () => {
|
|
|
29
37
|
const networkQualityMonitor = new NetworkQualityMonitor(initialConfig);
|
|
30
38
|
|
|
31
39
|
statsAnalyzer = new StatsAnalyzer(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
{
|
|
41
|
+
config: initialConfig,
|
|
42
|
+
receiveSlotCallback: () => ({}),
|
|
43
|
+
networkQualityMonitor,
|
|
44
|
+
statsResults: defaultStats,
|
|
45
|
+
},
|
|
36
46
|
);
|
|
37
47
|
});
|
|
38
48
|
|
|
@@ -89,7 +99,7 @@ describe('plugin-meetings', () => {
|
|
|
89
99
|
requestedBitrate: 10000,
|
|
90
100
|
},
|
|
91
101
|
'audio-send',
|
|
92
|
-
true
|
|
102
|
+
true,
|
|
93
103
|
);
|
|
94
104
|
|
|
95
105
|
assert.strictEqual(statsAnalyzer.statsResults['audio-send'].send.headerBytesSent, 25000);
|
|
@@ -126,7 +136,7 @@ describe('plugin-meetings', () => {
|
|
|
126
136
|
requestedBitrate: 50000,
|
|
127
137
|
},
|
|
128
138
|
'video-send',
|
|
129
|
-
true
|
|
139
|
+
true,
|
|
130
140
|
);
|
|
131
141
|
|
|
132
142
|
assert.strictEqual(statsAnalyzer.statsResults['video-send'].send.headerBytesSent, 50000);
|
|
@@ -136,11 +146,11 @@ describe('plugin-meetings', () => {
|
|
|
136
146
|
assert.strictEqual(statsAnalyzer.statsResults['video-send'].send.requestedBitrate, 50000);
|
|
137
147
|
assert.strictEqual(
|
|
138
148
|
statsAnalyzer.statsResults['video-send'].send.totalRtxPacketsSent,
|
|
139
|
-
10
|
|
149
|
+
10,
|
|
140
150
|
);
|
|
141
151
|
assert.strictEqual(
|
|
142
152
|
statsAnalyzer.statsResults['video-send'].send.totalRtxBytesSent,
|
|
143
|
-
500
|
|
153
|
+
500,
|
|
144
154
|
);
|
|
145
155
|
});
|
|
146
156
|
|
|
@@ -183,12 +193,12 @@ describe('plugin-meetings', () => {
|
|
|
183
193
|
requestedBitrate: 10000,
|
|
184
194
|
},
|
|
185
195
|
'audio-recv-1',
|
|
186
|
-
false
|
|
196
|
+
false,
|
|
187
197
|
);
|
|
188
198
|
|
|
189
199
|
assert.strictEqual(
|
|
190
200
|
statsAnalyzer.statsResults['audio-recv-1'].recv.totalPacketsReceived,
|
|
191
|
-
12
|
|
201
|
+
12,
|
|
192
202
|
);
|
|
193
203
|
assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.fecPacketsDiscarded, 1);
|
|
194
204
|
assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.fecPacketsReceived, 1);
|
|
@@ -196,18 +206,18 @@ describe('plugin-meetings', () => {
|
|
|
196
206
|
assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.requestedBitrate, 10000);
|
|
197
207
|
assert.strictEqual(
|
|
198
208
|
statsAnalyzer.statsResults['audio-recv-1'].recv.headerBytesReceived,
|
|
199
|
-
250
|
|
209
|
+
250,
|
|
200
210
|
);
|
|
201
211
|
assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.audioLevel, 0);
|
|
202
212
|
assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.totalAudioEnergy, 133);
|
|
203
213
|
assert.strictEqual(
|
|
204
214
|
statsAnalyzer.statsResults['audio-recv-1'].recv.totalSamplesReceived,
|
|
205
|
-
300000
|
|
215
|
+
300000,
|
|
206
216
|
);
|
|
207
217
|
assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.totalSamplesDecoded, 0);
|
|
208
218
|
assert.strictEqual(
|
|
209
219
|
statsAnalyzer.statsResults['audio-recv-1'].recv.concealedSamples,
|
|
210
|
-
200000
|
|
220
|
+
200000,
|
|
211
221
|
);
|
|
212
222
|
});
|
|
213
223
|
|
|
@@ -243,7 +253,7 @@ describe('plugin-meetings', () => {
|
|
|
243
253
|
retransmittedPacketsReceived: 10,
|
|
244
254
|
},
|
|
245
255
|
'video-recv',
|
|
246
|
-
false
|
|
256
|
+
false,
|
|
247
257
|
);
|
|
248
258
|
|
|
249
259
|
assert.strictEqual(statsAnalyzer.statsResults['video-recv'].recv.totalPacketsReceived, 1500);
|
|
@@ -275,7 +285,7 @@ describe('plugin-meetings', () => {
|
|
|
275
285
|
type: 'media-source',
|
|
276
286
|
},
|
|
277
287
|
'audio-send',
|
|
278
|
-
true
|
|
288
|
+
true,
|
|
279
289
|
);
|
|
280
290
|
|
|
281
291
|
assert.strictEqual(statsAnalyzer.statsResults['audio-send'].send.audioLevel, 0.03);
|
|
@@ -322,15 +332,17 @@ describe('plugin-meetings', () => {
|
|
|
322
332
|
const networkQualityMonitor = new NetworkQualityMonitor(initialConfig);
|
|
323
333
|
|
|
324
334
|
statsAnalyzer = new StatsAnalyzer(
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
335
|
+
{
|
|
336
|
+
config: initialConfig,
|
|
337
|
+
receiveSlotCallback: () => ({}),
|
|
338
|
+
networkQualityMonitor,
|
|
339
|
+
statsResults: defaultStats,
|
|
340
|
+
},
|
|
329
341
|
);
|
|
330
342
|
|
|
331
343
|
sandBoxSpy = sandbox.spy(
|
|
332
344
|
statsAnalyzer.networkQualityMonitor,
|
|
333
|
-
'determineUplinkNetworkQuality'
|
|
345
|
+
'determineUplinkNetworkQuality',
|
|
334
346
|
);
|
|
335
347
|
});
|
|
336
348
|
|
|
@@ -347,7 +359,7 @@ describe('plugin-meetings', () => {
|
|
|
347
359
|
mediaType: 'video-send-1',
|
|
348
360
|
remoteRtpResults: statusResult,
|
|
349
361
|
statsAnalyzerCurrentStats: statsAnalyzer.statsResults,
|
|
350
|
-
})
|
|
362
|
+
}),
|
|
351
363
|
);
|
|
352
364
|
});
|
|
353
365
|
});
|
|
@@ -381,6 +393,24 @@ describe('plugin-meetings', () => {
|
|
|
381
393
|
};
|
|
382
394
|
};
|
|
383
395
|
|
|
396
|
+
const registerStatsAnalyzerEvents = (statsAnalyzer) => {
|
|
397
|
+
statsAnalyzer.on(EVENTS.LOCAL_MEDIA_STARTED, (data) => {
|
|
398
|
+
receivedEventsData.local.started = data;
|
|
399
|
+
});
|
|
400
|
+
statsAnalyzer.on(EVENTS.LOCAL_MEDIA_STOPPED, (data) => {
|
|
401
|
+
receivedEventsData.local.stopped = data;
|
|
402
|
+
});
|
|
403
|
+
statsAnalyzer.on(EVENTS.REMOTE_MEDIA_STARTED, (data) => {
|
|
404
|
+
receivedEventsData.remote.started = data;
|
|
405
|
+
});
|
|
406
|
+
statsAnalyzer.on(EVENTS.REMOTE_MEDIA_STOPPED, (data) => {
|
|
407
|
+
receivedEventsData.remote.stopped = data;
|
|
408
|
+
});
|
|
409
|
+
statsAnalyzer.on(EVENTS.MEDIA_QUALITY, ({data}) => {
|
|
410
|
+
mqeData = data;
|
|
411
|
+
});
|
|
412
|
+
};
|
|
413
|
+
|
|
384
414
|
before(() => {
|
|
385
415
|
LoggerConfig.set({enable: false});
|
|
386
416
|
LoggerProxy.set();
|
|
@@ -404,6 +434,7 @@ describe('plugin-meetings', () => {
|
|
|
404
434
|
type: 'outbound-rtp',
|
|
405
435
|
bytesSent: 1,
|
|
406
436
|
packetsSent: 0,
|
|
437
|
+
isRequested: true,
|
|
407
438
|
},
|
|
408
439
|
{
|
|
409
440
|
type: 'remote-inbound-rtp',
|
|
@@ -437,6 +468,8 @@ describe('plugin-meetings', () => {
|
|
|
437
468
|
fecPacketsReceived: 0,
|
|
438
469
|
packetsLost: 0,
|
|
439
470
|
packetsReceived: 0,
|
|
471
|
+
isRequested: true,
|
|
472
|
+
lastRequestedUpdateTimestamp: 0,
|
|
440
473
|
},
|
|
441
474
|
{
|
|
442
475
|
type: 'remote-outbound-rtp',
|
|
@@ -470,6 +503,8 @@ describe('plugin-meetings', () => {
|
|
|
470
503
|
bytesSent: 1,
|
|
471
504
|
framesSent: 0,
|
|
472
505
|
packetsSent: 0,
|
|
506
|
+
isRequested: true,
|
|
507
|
+
lastRequestedUpdateTimestamp: 0,
|
|
473
508
|
},
|
|
474
509
|
{
|
|
475
510
|
type: 'remote-inbound-rtp',
|
|
@@ -505,6 +540,10 @@ describe('plugin-meetings', () => {
|
|
|
505
540
|
framesReceived: 0,
|
|
506
541
|
packetsLost: 0,
|
|
507
542
|
packetsReceived: 0,
|
|
543
|
+
isRequested: true,
|
|
544
|
+
lastRequestedUpdateTimestamp: 0,
|
|
545
|
+
isActiveSpeaker: false,
|
|
546
|
+
lastActiveSpeakerUpdateTimestamp: 0,
|
|
508
547
|
},
|
|
509
548
|
{
|
|
510
549
|
type: 'remote-outbound-rtp',
|
|
@@ -538,6 +577,8 @@ describe('plugin-meetings', () => {
|
|
|
538
577
|
bytesSent: 1,
|
|
539
578
|
framesSent: 0,
|
|
540
579
|
packetsSent: 0,
|
|
580
|
+
isRequested: true,
|
|
581
|
+
lastRequestedUpdateTimestamp: 0,
|
|
541
582
|
},
|
|
542
583
|
{
|
|
543
584
|
type: 'remote-inbound-rtp',
|
|
@@ -573,6 +614,8 @@ describe('plugin-meetings', () => {
|
|
|
573
614
|
framesReceived: 0,
|
|
574
615
|
packetsLost: 0,
|
|
575
616
|
packetsReceived: 0,
|
|
617
|
+
isRequested: true,
|
|
618
|
+
lastRequestedUpdateTimestamp: 0,
|
|
576
619
|
},
|
|
577
620
|
{
|
|
578
621
|
type: 'remote-outbound-rtp',
|
|
@@ -622,23 +665,11 @@ describe('plugin-meetings', () => {
|
|
|
622
665
|
|
|
623
666
|
networkQualityMonitor = new NetworkQualityMonitor(initialConfig);
|
|
624
667
|
|
|
625
|
-
statsAnalyzer = new StatsAnalyzer(
|
|
626
|
-
|
|
627
|
-
statsAnalyzer.on(EVENTS.LOCAL_MEDIA_STARTED, (data) => {
|
|
628
|
-
receivedEventsData.local.started = data;
|
|
629
|
-
});
|
|
630
|
-
statsAnalyzer.on(EVENTS.LOCAL_MEDIA_STOPPED, (data) => {
|
|
631
|
-
receivedEventsData.local.stopped = data;
|
|
632
|
-
});
|
|
633
|
-
statsAnalyzer.on(EVENTS.REMOTE_MEDIA_STARTED, (data) => {
|
|
634
|
-
receivedEventsData.remote.started = data;
|
|
635
|
-
});
|
|
636
|
-
statsAnalyzer.on(EVENTS.REMOTE_MEDIA_STOPPED, (data) => {
|
|
637
|
-
receivedEventsData.remote.stopped = data;
|
|
638
|
-
});
|
|
639
|
-
statsAnalyzer.on(EVENTS.MEDIA_QUALITY, ({data}) => {
|
|
640
|
-
mqeData = data;
|
|
668
|
+
statsAnalyzer = new StatsAnalyzer({
|
|
669
|
+
config: initialConfig, receiveSlotCallback: () => receiveSlot, networkQualityMonitor,
|
|
641
670
|
});
|
|
671
|
+
|
|
672
|
+
registerStatsAnalyzerEvents(statsAnalyzer);
|
|
642
673
|
});
|
|
643
674
|
|
|
644
675
|
afterEach(() => {
|
|
@@ -646,20 +677,12 @@ describe('plugin-meetings', () => {
|
|
|
646
677
|
clock.restore();
|
|
647
678
|
});
|
|
648
679
|
|
|
649
|
-
const startStatsAnalyzer = async (mediaStatus, lastEmittedEvents) => {
|
|
650
|
-
statsAnalyzer.updateMediaStatus(mediaStatus);
|
|
651
|
-
statsAnalyzer.startAnalyzer(pc);
|
|
652
|
-
statsAnalyzer.lastEmittedStartStopEvent = lastEmittedEvents || {};
|
|
653
|
-
|
|
654
|
-
await testUtils.flushPromises();
|
|
655
|
-
};
|
|
656
|
-
|
|
657
680
|
const mergeProperties = (
|
|
658
681
|
target,
|
|
659
682
|
properties,
|
|
660
683
|
keyValue = 'fake-candidate-id',
|
|
661
684
|
matchKey = 'type',
|
|
662
|
-
matchValue = 'local-candidate'
|
|
685
|
+
matchValue = 'local-candidate',
|
|
663
686
|
) => {
|
|
664
687
|
for (let key in target) {
|
|
665
688
|
if (target.hasOwnProperty(key)) {
|
|
@@ -704,7 +727,15 @@ describe('plugin-meetings', () => {
|
|
|
704
727
|
};
|
|
705
728
|
|
|
706
729
|
it('emits LOCAL_MEDIA_STARTED and LOCAL_MEDIA_STOPPED events for audio', async () => {
|
|
707
|
-
await startStatsAnalyzer({
|
|
730
|
+
await startStatsAnalyzer({
|
|
731
|
+
statsAnalyzer,
|
|
732
|
+
pc,
|
|
733
|
+
mediaStatus: {
|
|
734
|
+
expected: {
|
|
735
|
+
sendAudio: true,
|
|
736
|
+
},
|
|
737
|
+
},
|
|
738
|
+
});
|
|
708
739
|
|
|
709
740
|
// check that we haven't received any events yet
|
|
710
741
|
checkReceivedEvent({expected: {}});
|
|
@@ -724,7 +755,7 @@ describe('plugin-meetings', () => {
|
|
|
724
755
|
});
|
|
725
756
|
|
|
726
757
|
it('emits LOCAL_MEDIA_STARTED and LOCAL_MEDIA_STOPPED events for video', async () => {
|
|
727
|
-
await startStatsAnalyzer({expected: {sendVideo: true}});
|
|
758
|
+
await startStatsAnalyzer({pc, statsAnalyzer, mediaStatus: {expected: {sendVideo: true}}});
|
|
728
759
|
|
|
729
760
|
// check that we haven't received any events yet
|
|
730
761
|
checkReceivedEvent({expected: {}});
|
|
@@ -744,7 +775,7 @@ describe('plugin-meetings', () => {
|
|
|
744
775
|
});
|
|
745
776
|
|
|
746
777
|
it('emits LOCAL_MEDIA_STARTED and LOCAL_MEDIA_STOPPED events for share', async () => {
|
|
747
|
-
await startStatsAnalyzer({expected: {sendShare: true}});
|
|
778
|
+
await startStatsAnalyzer({pc, statsAnalyzer, mediaStatus: {expected: {sendShare: true}}});
|
|
748
779
|
|
|
749
780
|
// check that we haven't received any events yet
|
|
750
781
|
checkReceivedEvent({expected: {}});
|
|
@@ -764,7 +795,7 @@ describe('plugin-meetings', () => {
|
|
|
764
795
|
});
|
|
765
796
|
|
|
766
797
|
it('emits REMOTE_MEDIA_STARTED and REMOTE_MEDIA_STOPPED events for audio', async () => {
|
|
767
|
-
await startStatsAnalyzer({expected: {receiveAudio: true}});
|
|
798
|
+
await startStatsAnalyzer({pc, statsAnalyzer, mediaStatus: {expected: {receiveAudio: true}}});
|
|
768
799
|
|
|
769
800
|
// check that we haven't received any events yet
|
|
770
801
|
checkReceivedEvent({expected: {}});
|
|
@@ -784,7 +815,7 @@ describe('plugin-meetings', () => {
|
|
|
784
815
|
});
|
|
785
816
|
|
|
786
817
|
it('emits REMOTE_MEDIA_STARTED and REMOTE_MEDIA_STOPPED events for video', async () => {
|
|
787
|
-
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
818
|
+
await startStatsAnalyzer({pc, statsAnalyzer, mediaStatus: {expected: {receiveVideo: true}}});
|
|
788
819
|
|
|
789
820
|
// check that we haven't received any events yet
|
|
790
821
|
checkReceivedEvent({expected: {}});
|
|
@@ -804,7 +835,7 @@ describe('plugin-meetings', () => {
|
|
|
804
835
|
});
|
|
805
836
|
|
|
806
837
|
it('emits REMOTE_MEDIA_STARTED and REMOTE_MEDIA_STOPPED events for share', async () => {
|
|
807
|
-
await startStatsAnalyzer({expected: {receiveShare: true}});
|
|
838
|
+
await startStatsAnalyzer({pc, statsAnalyzer, mediaStatus: {expected: {receiveShare: true}}});
|
|
808
839
|
|
|
809
840
|
// check that we haven't received any events yet
|
|
810
841
|
checkReceivedEvent({expected: {}});
|
|
@@ -824,7 +855,7 @@ describe('plugin-meetings', () => {
|
|
|
824
855
|
});
|
|
825
856
|
|
|
826
857
|
it('emits the correct MEDIA_QUALITY events', async () => {
|
|
827
|
-
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
858
|
+
await startStatsAnalyzer({pc, statsAnalyzer, mediaStatus: {expected: {receiveVideo: true}}});
|
|
828
859
|
|
|
829
860
|
await progressTime();
|
|
830
861
|
|
|
@@ -833,7 +864,7 @@ describe('plugin-meetings', () => {
|
|
|
833
864
|
});
|
|
834
865
|
|
|
835
866
|
it('emits the correct transportType in MEDIA_QUALITY events', async () => {
|
|
836
|
-
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
867
|
+
await startStatsAnalyzer({pc, statsAnalyzer, mediaStatus: {expected: {receiveVideo: true}}});
|
|
837
868
|
|
|
838
869
|
await progressTime();
|
|
839
870
|
|
|
@@ -847,7 +878,7 @@ describe('plugin-meetings', () => {
|
|
|
847
878
|
fakeStats.audio.receivers[0].report[4].relayProtocol = 'tls';
|
|
848
879
|
fakeStats.video.receivers[0].report[4].relayProtocol = 'tls';
|
|
849
880
|
|
|
850
|
-
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
881
|
+
await startStatsAnalyzer({pc, statsAnalyzer, mediaStatus: {expected: {receiveVideo: true}}});
|
|
851
882
|
|
|
852
883
|
await progressTime();
|
|
853
884
|
|
|
@@ -856,19 +887,19 @@ describe('plugin-meetings', () => {
|
|
|
856
887
|
});
|
|
857
888
|
|
|
858
889
|
it('emits the correct peripherals in MEDIA_QUALITY events', async () => {
|
|
859
|
-
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
890
|
+
await startStatsAnalyzer({pc, statsAnalyzer, mediaStatus: {expected: {receiveVideo: true}}});
|
|
860
891
|
|
|
861
892
|
await progressTime();
|
|
862
893
|
|
|
863
894
|
assert.strictEqual(
|
|
864
895
|
mqeData.intervalMetadata.peripherals.find((val) => val.name === MEDIA_DEVICES.MICROPHONE)
|
|
865
896
|
.information,
|
|
866
|
-
'fake-microphone'
|
|
897
|
+
'fake-microphone',
|
|
867
898
|
);
|
|
868
899
|
assert.strictEqual(
|
|
869
900
|
mqeData.intervalMetadata.peripherals.find((val) => val.name === MEDIA_DEVICES.CAMERA)
|
|
870
901
|
.information,
|
|
871
|
-
'fake-camera'
|
|
902
|
+
'fake-camera',
|
|
872
903
|
);
|
|
873
904
|
});
|
|
874
905
|
|
|
@@ -876,30 +907,33 @@ describe('plugin-meetings', () => {
|
|
|
876
907
|
fakeStats.audio.senders[0].localTrackLabel = undefined;
|
|
877
908
|
fakeStats.video.senders[0].localTrackLabel = undefined;
|
|
878
909
|
|
|
879
|
-
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
910
|
+
await startStatsAnalyzer({pc, statsAnalyzer, mediaStatus: {expected: {receiveVideo: true}}});
|
|
880
911
|
|
|
881
912
|
await progressTime();
|
|
882
913
|
|
|
883
914
|
assert.strictEqual(
|
|
884
915
|
mqeData.intervalMetadata.peripherals.find((val) => val.name === MEDIA_DEVICES.MICROPHONE)
|
|
885
916
|
.information,
|
|
886
|
-
_UNKNOWN_
|
|
917
|
+
_UNKNOWN_,
|
|
887
918
|
);
|
|
888
919
|
assert.strictEqual(
|
|
889
920
|
mqeData.intervalMetadata.peripherals.find((val) => val.name === MEDIA_DEVICES.CAMERA)
|
|
890
921
|
.information,
|
|
891
|
-
_UNKNOWN_
|
|
922
|
+
_UNKNOWN_,
|
|
892
923
|
);
|
|
893
924
|
});
|
|
894
925
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
await startStatsAnalyzer();
|
|
926
|
+
describe('frame rate reporting in stats analyzer', () => {
|
|
927
|
+
beforeEach(async () => {
|
|
928
|
+
await startStatsAnalyzer({pc, statsAnalyzer});
|
|
929
|
+
});
|
|
930
|
+
|
|
931
|
+
it('should report a zero frame rate for both transmitted and received video at the start', async () => {
|
|
898
932
|
assert.strictEqual(mqeData.videoTransmit[0].streams[0].common.transmittedFrameRate, 0);
|
|
899
933
|
assert.strictEqual(mqeData.videoReceive[0].streams[0].common.receivedFrameRate, 0);
|
|
900
934
|
});
|
|
901
935
|
|
|
902
|
-
it('
|
|
936
|
+
it('should accurately report the transmitted and received frame rate after video frames are processed', async () => {
|
|
903
937
|
fakeStats.video.senders[0].report[0].framesSent += 300;
|
|
904
938
|
fakeStats.video.receivers[0].report[0].framesReceived += 300;
|
|
905
939
|
await progressTime(MQA_INTERVAL);
|
|
@@ -910,9 +944,12 @@ describe('plugin-meetings', () => {
|
|
|
910
944
|
});
|
|
911
945
|
});
|
|
912
946
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
await startStatsAnalyzer();
|
|
947
|
+
describe('RTP packets count in stats analyzer', () => {
|
|
948
|
+
beforeEach(async () => {
|
|
949
|
+
await startStatsAnalyzer({pc, statsAnalyzer});
|
|
950
|
+
});
|
|
951
|
+
|
|
952
|
+
it('should report zero RTP packets for all streams at the start of the stats analyzer', async () => {
|
|
916
953
|
assert.strictEqual(mqeData.audioTransmit[0].common.rtpPackets, 0);
|
|
917
954
|
assert.strictEqual(mqeData.audioTransmit[0].streams[0].common.rtpPackets, 0);
|
|
918
955
|
assert.strictEqual(mqeData.audioReceive[0].common.rtpPackets, 0);
|
|
@@ -923,7 +960,7 @@ describe('plugin-meetings', () => {
|
|
|
923
960
|
assert.strictEqual(mqeData.videoReceive[0].streams[0].common.rtpPackets, 0);
|
|
924
961
|
});
|
|
925
962
|
|
|
926
|
-
it('after packets are sent', async () => {
|
|
963
|
+
it('should update the RTP packets count correctly after audio and video packets are sent', async () => {
|
|
927
964
|
fakeStats.audio.senders[0].report[0].packetsSent += 5;
|
|
928
965
|
fakeStats.video.senders[0].report[0].packetsSent += 5;
|
|
929
966
|
await progressTime(MQA_INTERVAL);
|
|
@@ -934,7 +971,7 @@ describe('plugin-meetings', () => {
|
|
|
934
971
|
assert.strictEqual(mqeData.videoTransmit[0].streams[0].common.rtpPackets, 5);
|
|
935
972
|
});
|
|
936
973
|
|
|
937
|
-
it('after packets are received', async () => {
|
|
974
|
+
it('should update the RTP packets count correctly after audio and video packets are received', async () => {
|
|
938
975
|
fakeStats.audio.senders[0].report[0].packetsSent += 10;
|
|
939
976
|
fakeStats.video.senders[0].report[0].packetsSent += 10;
|
|
940
977
|
fakeStats.audio.receivers[0].report[0].packetsReceived += 10;
|
|
@@ -948,38 +985,83 @@ describe('plugin-meetings', () => {
|
|
|
948
985
|
});
|
|
949
986
|
});
|
|
950
987
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
await startStatsAnalyzer();
|
|
988
|
+
describe('FEC packet reporting in stats analyzer', () => {
|
|
989
|
+
beforeEach(async () => {
|
|
990
|
+
await startStatsAnalyzer({pc, statsAnalyzer});
|
|
991
|
+
});
|
|
992
|
+
|
|
993
|
+
it('should initially report zero FEC packets at the start of the stats analyzer', async () => {
|
|
954
994
|
assert.strictEqual(mqeData.audioReceive[0].common.fecPackets, 0);
|
|
955
995
|
});
|
|
956
996
|
|
|
957
|
-
it('
|
|
997
|
+
it('should accurately report the count of FEC packets received', async () => {
|
|
958
998
|
fakeStats.audio.receivers[0].report[0].fecPacketsReceived += 5;
|
|
959
999
|
await progressTime(MQA_INTERVAL);
|
|
960
1000
|
|
|
961
1001
|
assert.strictEqual(mqeData.audioReceive[0].common.fecPackets, 5);
|
|
962
1002
|
});
|
|
963
1003
|
|
|
964
|
-
it('
|
|
1004
|
+
it('should accurately update and reset the FEC packet count based on received packets over MQA intervals', async () => {
|
|
965
1005
|
fakeStats.audio.receivers[0].report[0].fecPacketsReceived += 15;
|
|
966
|
-
fakeStats.audio.receivers[0].report[0].fecPacketsDiscarded += 5;
|
|
967
1006
|
await progressTime(MQA_INTERVAL);
|
|
1007
|
+
assert.strictEqual(mqeData.audioReceive[0].common.fecPackets, 15);
|
|
968
1008
|
|
|
969
|
-
|
|
1009
|
+
fakeStats.audio.receivers[0].report[0].fecPacketsReceived += 45;
|
|
1010
|
+
await progressTime(MQA_INTERVAL);
|
|
1011
|
+
assert.strictEqual(mqeData.audioReceive[0].common.fecPackets, 45);
|
|
1012
|
+
|
|
1013
|
+
await progressTime(MQA_INTERVAL);
|
|
1014
|
+
assert.strictEqual(mqeData.audioReceive[0].common.fecPackets, 0);
|
|
970
1015
|
});
|
|
971
1016
|
});
|
|
972
1017
|
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
await startStatsAnalyzer();
|
|
1018
|
+
describe('RTP recovered packets emission', async() => {
|
|
1019
|
+
beforeEach(async() => {
|
|
1020
|
+
await startStatsAnalyzer({pc, statsAnalyzer});
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
it('should initially report zero RTP recovered packets', async() => {
|
|
1024
|
+
assert.strictEqual(mqeData.audioReceive[0].common.rtpRecovered, 0);
|
|
1025
|
+
})
|
|
1026
|
+
|
|
1027
|
+
it('should report RTP recovered packets equal to FEC packets received', async() => {
|
|
1028
|
+
fakeStats.audio.receivers[0].report[0].fecPacketsReceived += 10;
|
|
1029
|
+
|
|
1030
|
+
await progressTime(MQA_INTERVAL);
|
|
1031
|
+
assert.strictEqual(mqeData.audioReceive[0].common.rtpRecovered, 10);
|
|
1032
|
+
})
|
|
1033
|
+
|
|
1034
|
+
it('should reset RTP recovered packets count after each interval', async () => {
|
|
1035
|
+
fakeStats.audio.receivers[0].report[0].fecPacketsReceived += 100;
|
|
1036
|
+
await progressTime(MQA_INTERVAL);
|
|
1037
|
+
assert.strictEqual(mqeData.audioReceive[0].common.rtpRecovered, 100);
|
|
1038
|
+
|
|
1039
|
+
await progressTime(MQA_INTERVAL);
|
|
1040
|
+
assert.strictEqual(mqeData.audioReceive[0].common.rtpRecovered, 0);
|
|
1041
|
+
})
|
|
1042
|
+
|
|
1043
|
+
it('should correctly calculate RTP recovered packets after discarding FEC packets', async () => {
|
|
1044
|
+
fakeStats.audio.receivers[0].report[0].fecPacketsReceived += 100;
|
|
1045
|
+
fakeStats.audio.receivers[0].report[0].fecPacketsDiscarded += 20;
|
|
1046
|
+
|
|
1047
|
+
await progressTime(MQA_INTERVAL);
|
|
1048
|
+
assert.strictEqual(mqeData.audioReceive[0].common.rtpRecovered, 80);
|
|
1049
|
+
})
|
|
1050
|
+
})
|
|
1051
|
+
|
|
1052
|
+
describe('packet loss metrics reporting in stats analyzer', () => {
|
|
1053
|
+
beforeEach(async () => {
|
|
1054
|
+
await startStatsAnalyzer({pc, statsAnalyzer});
|
|
1055
|
+
});
|
|
1056
|
+
|
|
1057
|
+
it('should report zero packet loss for both audio and video at the start of the stats analyzer', async () => {
|
|
976
1058
|
assert.strictEqual(mqeData.audioReceive[0].common.mediaHopByHopLost, 0);
|
|
977
1059
|
assert.strictEqual(mqeData.audioReceive[0].common.rtpHopByHopLost, 0);
|
|
978
1060
|
assert.strictEqual(mqeData.videoReceive[0].common.mediaHopByHopLost, 0);
|
|
979
1061
|
assert.strictEqual(mqeData.videoReceive[0].common.rtpHopByHopLost, 0);
|
|
980
1062
|
});
|
|
981
1063
|
|
|
982
|
-
it('after
|
|
1064
|
+
it('should update packet loss metrics correctly for both audio and video after packet loss is detected', async () => {
|
|
983
1065
|
fakeStats.audio.receivers[0].report[0].packetsLost += 5;
|
|
984
1066
|
fakeStats.video.receivers[0].report[0].packetsLost += 5;
|
|
985
1067
|
await progressTime(MQA_INTERVAL);
|
|
@@ -991,14 +1073,17 @@ describe('plugin-meetings', () => {
|
|
|
991
1073
|
});
|
|
992
1074
|
});
|
|
993
1075
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
await startStatsAnalyzer();
|
|
1076
|
+
describe('remote loss rate reporting in stats analyzer', () => {
|
|
1077
|
+
beforeEach(async () => {
|
|
1078
|
+
await startStatsAnalyzer({pc, statsAnalyzer});
|
|
1079
|
+
});
|
|
1080
|
+
|
|
1081
|
+
it('should report a zero remote loss rate for both audio and video at the start', async () => {
|
|
997
1082
|
assert.strictEqual(mqeData.audioTransmit[0].common.remoteLossRate, 0);
|
|
998
1083
|
assert.strictEqual(mqeData.videoTransmit[0].common.remoteLossRate, 0);
|
|
999
1084
|
});
|
|
1000
1085
|
|
|
1001
|
-
it('after packets are sent', async () => {
|
|
1086
|
+
it('should maintain a zero remote loss rate for both audio and video after packets are sent without loss', async () => {
|
|
1002
1087
|
fakeStats.audio.senders[0].report[0].packetsSent += 100;
|
|
1003
1088
|
fakeStats.video.senders[0].report[0].packetsSent += 100;
|
|
1004
1089
|
await progressTime(MQA_INTERVAL);
|
|
@@ -1007,7 +1092,7 @@ describe('plugin-meetings', () => {
|
|
|
1007
1092
|
assert.strictEqual(mqeData.videoTransmit[0].common.remoteLossRate, 0);
|
|
1008
1093
|
});
|
|
1009
1094
|
|
|
1010
|
-
it('
|
|
1095
|
+
it('should accurately calculate the remote loss rate for both audio and video after packet loss is detected', async () => {
|
|
1011
1096
|
fakeStats.audio.senders[0].report[0].packetsSent += 200;
|
|
1012
1097
|
fakeStats.audio.senders[0].report[1].packetsLost += 10;
|
|
1013
1098
|
fakeStats.video.senders[0].report[0].packetsSent += 200;
|
|
@@ -1020,7 +1105,7 @@ describe('plugin-meetings', () => {
|
|
|
1020
1105
|
});
|
|
1021
1106
|
|
|
1022
1107
|
it('has the correct localIpAddress set when the candidateType is host', async () => {
|
|
1023
|
-
await startStatsAnalyzer();
|
|
1108
|
+
await startStatsAnalyzer({pc, statsAnalyzer});
|
|
1024
1109
|
|
|
1025
1110
|
await progressTime();
|
|
1026
1111
|
assert.strictEqual(statsAnalyzer.getLocalIpAddress(), '');
|
|
@@ -1030,7 +1115,7 @@ describe('plugin-meetings', () => {
|
|
|
1030
1115
|
});
|
|
1031
1116
|
|
|
1032
1117
|
it('has the correct localIpAddress set when the candidateType is prflx and relayProtocol is set', async () => {
|
|
1033
|
-
await startStatsAnalyzer();
|
|
1118
|
+
await startStatsAnalyzer({pc, statsAnalyzer});
|
|
1034
1119
|
|
|
1035
1120
|
await progressTime();
|
|
1036
1121
|
assert.strictEqual(statsAnalyzer.getLocalIpAddress(), '');
|
|
@@ -1044,7 +1129,7 @@ describe('plugin-meetings', () => {
|
|
|
1044
1129
|
});
|
|
1045
1130
|
|
|
1046
1131
|
it('has the correct localIpAddress set when the candidateType is prflx and relayProtocol is not set', async () => {
|
|
1047
|
-
await startStatsAnalyzer();
|
|
1132
|
+
await startStatsAnalyzer({pc, statsAnalyzer});
|
|
1048
1133
|
|
|
1049
1134
|
await progressTime();
|
|
1050
1135
|
assert.strictEqual(statsAnalyzer.getLocalIpAddress(), '');
|
|
@@ -1058,7 +1143,7 @@ describe('plugin-meetings', () => {
|
|
|
1058
1143
|
});
|
|
1059
1144
|
|
|
1060
1145
|
it('has no localIpAddress set when the candidateType is invalid', async () => {
|
|
1061
|
-
await startStatsAnalyzer();
|
|
1146
|
+
await startStatsAnalyzer({pc, statsAnalyzer});
|
|
1062
1147
|
|
|
1063
1148
|
await progressTime();
|
|
1064
1149
|
assert.strictEqual(statsAnalyzer.getLocalIpAddress(), '');
|
|
@@ -1069,8 +1154,10 @@ describe('plugin-meetings', () => {
|
|
|
1069
1154
|
|
|
1070
1155
|
it('logs a message when audio send packets do not increase', async () => {
|
|
1071
1156
|
await startStatsAnalyzer(
|
|
1072
|
-
{
|
|
1073
|
-
|
|
1157
|
+
{
|
|
1158
|
+
statsAnalyzer, pc, mediaStatus: {expected: {sendAudio: true}},
|
|
1159
|
+
lastEmittedEvents: {audio: {local: EVENTS.LOCAL_MEDIA_STARTED}},
|
|
1160
|
+
},
|
|
1074
1161
|
);
|
|
1075
1162
|
|
|
1076
1163
|
// don't increase the packets when time progresses.
|
|
@@ -1078,15 +1165,17 @@ describe('plugin-meetings', () => {
|
|
|
1078
1165
|
|
|
1079
1166
|
assert(
|
|
1080
1167
|
loggerSpy.calledWith(
|
|
1081
|
-
'StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets sent'
|
|
1082
|
-
)
|
|
1168
|
+
'StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets sent',
|
|
1169
|
+
),
|
|
1083
1170
|
);
|
|
1084
1171
|
});
|
|
1085
1172
|
|
|
1086
1173
|
it('does not log a message when audio send packets increase', async () => {
|
|
1087
|
-
await startStatsAnalyzer(
|
|
1088
|
-
|
|
1089
|
-
|
|
1174
|
+
await startStatsAnalyzer({
|
|
1175
|
+
statsAnalyzer, pc,
|
|
1176
|
+
mediaStatus: {expected: {sendAudio: true}},
|
|
1177
|
+
lastEmittedEvents: {audio: {local: EVENTS.LOCAL_MEDIA_STOPPED}},
|
|
1178
|
+
},
|
|
1090
1179
|
);
|
|
1091
1180
|
|
|
1092
1181
|
fakeStats.audio.senders[0].report[0].packetsSent += 5;
|
|
@@ -1094,15 +1183,16 @@ describe('plugin-meetings', () => {
|
|
|
1094
1183
|
|
|
1095
1184
|
assert(
|
|
1096
1185
|
loggerSpy.neverCalledWith(
|
|
1097
|
-
'StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets sent'
|
|
1098
|
-
)
|
|
1186
|
+
'StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets sent',
|
|
1187
|
+
),
|
|
1099
1188
|
);
|
|
1100
1189
|
});
|
|
1101
1190
|
|
|
1102
1191
|
it('logs a message when video send packets do not increase', async () => {
|
|
1103
|
-
await startStatsAnalyzer(
|
|
1104
|
-
|
|
1105
|
-
|
|
1192
|
+
await startStatsAnalyzer({
|
|
1193
|
+
statsAnalyzer, pc, mediaStatus: {expected: {sendVideo: true}},
|
|
1194
|
+
lastEmittedEvents: {video: {local: EVENTS.LOCAL_MEDIA_STARTED}},
|
|
1195
|
+
},
|
|
1106
1196
|
);
|
|
1107
1197
|
|
|
1108
1198
|
// don't increase the packets when time progresses.
|
|
@@ -1110,31 +1200,42 @@ describe('plugin-meetings', () => {
|
|
|
1110
1200
|
|
|
1111
1201
|
assert(
|
|
1112
1202
|
loggerSpy.calledWith(
|
|
1113
|
-
'StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent'
|
|
1114
|
-
)
|
|
1203
|
+
'StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent',
|
|
1204
|
+
),
|
|
1115
1205
|
);
|
|
1116
1206
|
});
|
|
1117
1207
|
|
|
1118
1208
|
it('does not log a message when video send packets increase', async () => {
|
|
1119
1209
|
await startStatsAnalyzer(
|
|
1120
|
-
{
|
|
1121
|
-
|
|
1122
|
-
|
|
1210
|
+
{
|
|
1211
|
+
statsAnalyzer, pc,
|
|
1212
|
+
mediaStatus: {
|
|
1213
|
+
expected: {
|
|
1214
|
+
sendVideo: true,
|
|
1215
|
+
},
|
|
1216
|
+
},
|
|
1217
|
+
lastEmittedEvents: {
|
|
1218
|
+
video: {
|
|
1219
|
+
local: EVENTS.LOCAL_MEDIA_STOPPED,
|
|
1220
|
+
},
|
|
1221
|
+
},
|
|
1222
|
+
});
|
|
1123
1223
|
|
|
1124
1224
|
fakeStats.video.senders[0].report[0].packetsSent += 5;
|
|
1125
1225
|
await progressTime();
|
|
1126
1226
|
|
|
1127
1227
|
assert(
|
|
1128
1228
|
loggerSpy.neverCalledWith(
|
|
1129
|
-
'StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent'
|
|
1130
|
-
)
|
|
1229
|
+
'StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent',
|
|
1230
|
+
),
|
|
1131
1231
|
);
|
|
1132
1232
|
});
|
|
1133
1233
|
|
|
1134
1234
|
it('logs a message when share send packets do not increase', async () => {
|
|
1135
|
-
await startStatsAnalyzer(
|
|
1136
|
-
|
|
1137
|
-
|
|
1235
|
+
await startStatsAnalyzer({
|
|
1236
|
+
pc, mediaStatus: {expected: {sendShare: true}},
|
|
1237
|
+
lastEmittedEvents: {share: {local: EVENTS.LOCAL_MEDIA_STARTED}}, statsAnalyzer,
|
|
1238
|
+
},
|
|
1138
1239
|
);
|
|
1139
1240
|
|
|
1140
1241
|
// don't increase the packets when time progresses.
|
|
@@ -1142,15 +1243,16 @@ describe('plugin-meetings', () => {
|
|
|
1142
1243
|
|
|
1143
1244
|
assert(
|
|
1144
1245
|
loggerSpy.calledWith(
|
|
1145
|
-
'StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets sent'
|
|
1146
|
-
)
|
|
1246
|
+
'StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets sent',
|
|
1247
|
+
),
|
|
1147
1248
|
);
|
|
1148
1249
|
});
|
|
1149
1250
|
|
|
1150
1251
|
it('does not log a message when share send packets increase', async () => {
|
|
1151
|
-
await startStatsAnalyzer(
|
|
1152
|
-
|
|
1153
|
-
|
|
1252
|
+
await startStatsAnalyzer({
|
|
1253
|
+
pc, statsAnalyzer, mediaStatus: {expected: {sendShare: true}},
|
|
1254
|
+
lastEmittedEvents: {share: {local: EVENTS.LOCAL_MEDIA_STOPPED}},
|
|
1255
|
+
},
|
|
1154
1256
|
);
|
|
1155
1257
|
|
|
1156
1258
|
fakeStats.share.senders[0].report[0].packetsSent += 5;
|
|
@@ -1158,8 +1260,8 @@ describe('plugin-meetings', () => {
|
|
|
1158
1260
|
|
|
1159
1261
|
assert(
|
|
1160
1262
|
loggerSpy.neverCalledWith(
|
|
1161
|
-
'StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets sent'
|
|
1162
|
-
)
|
|
1263
|
+
'StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets sent',
|
|
1264
|
+
),
|
|
1163
1265
|
);
|
|
1164
1266
|
});
|
|
1165
1267
|
|
|
@@ -1172,7 +1274,7 @@ describe('plugin-meetings', () => {
|
|
|
1172
1274
|
id: '4',
|
|
1173
1275
|
};
|
|
1174
1276
|
|
|
1175
|
-
await startStatsAnalyzer();
|
|
1277
|
+
await startStatsAnalyzer({pc, statsAnalyzer});
|
|
1176
1278
|
|
|
1177
1279
|
// don't increase the packets when time progresses.
|
|
1178
1280
|
await progressTime();
|
|
@@ -1180,10 +1282,10 @@ describe('plugin-meetings', () => {
|
|
|
1180
1282
|
assert.neverCalledWith(
|
|
1181
1283
|
loggerSpy,
|
|
1182
1284
|
'StatsAnalyzer:index#processInboundRTPResult --> No packets received for receive slot id: "4" and csi: 2. Total packets received on slot: ',
|
|
1183
|
-
0
|
|
1285
|
+
0,
|
|
1184
1286
|
);
|
|
1185
1287
|
});
|
|
1186
|
-
}
|
|
1288
|
+
},
|
|
1187
1289
|
);
|
|
1188
1290
|
|
|
1189
1291
|
it(`logs a message if no packets are sent`, async () => {
|
|
@@ -1192,7 +1294,7 @@ describe('plugin-meetings', () => {
|
|
|
1192
1294
|
csi: 2,
|
|
1193
1295
|
id: '4',
|
|
1194
1296
|
};
|
|
1195
|
-
await startStatsAnalyzer();
|
|
1297
|
+
await startStatsAnalyzer({pc, statsAnalyzer});
|
|
1196
1298
|
|
|
1197
1299
|
// don't increase the packets when time progresses.
|
|
1198
1300
|
await progressTime();
|
|
@@ -1200,52 +1302,52 @@ describe('plugin-meetings', () => {
|
|
|
1200
1302
|
assert.calledWith(
|
|
1201
1303
|
loggerSpy,
|
|
1202
1304
|
'StatsAnalyzer:index#processInboundRTPResult --> No packets received for mediaType: video-recv-0, receive slot id: "4" and csi: 2. Total packets received on slot: ',
|
|
1203
|
-
0
|
|
1305
|
+
0,
|
|
1204
1306
|
);
|
|
1205
1307
|
|
|
1206
1308
|
assert.calledWith(
|
|
1207
1309
|
loggerSpy,
|
|
1208
1310
|
'StatsAnalyzer:index#processInboundRTPResult --> No frames received for mediaType: video-recv-0, receive slot id: "4" and csi: 2. Total frames received on slot: ',
|
|
1209
|
-
0
|
|
1311
|
+
0,
|
|
1210
1312
|
);
|
|
1211
1313
|
|
|
1212
1314
|
assert.calledWith(
|
|
1213
1315
|
loggerSpy,
|
|
1214
1316
|
'StatsAnalyzer:index#processInboundRTPResult --> No frames decoded for mediaType: video-recv-0, receive slot id: "4" and csi: 2. Total frames decoded on slot: ',
|
|
1215
|
-
0
|
|
1317
|
+
0,
|
|
1216
1318
|
);
|
|
1217
1319
|
|
|
1218
1320
|
assert.calledWith(
|
|
1219
1321
|
loggerSpy,
|
|
1220
1322
|
'StatsAnalyzer:index#processInboundRTPResult --> No packets received for mediaType: audio-recv-0, receive slot id: "4" and csi: 2. Total packets received on slot: ',
|
|
1221
|
-
0
|
|
1323
|
+
0,
|
|
1222
1324
|
);
|
|
1223
1325
|
|
|
1224
1326
|
assert.calledWith(
|
|
1225
1327
|
loggerSpy,
|
|
1226
1328
|
'StatsAnalyzer:index#processInboundRTPResult --> No packets received for mediaType: video-share-recv-0, receive slot id: "4" and csi: 2. Total packets received on slot: ',
|
|
1227
|
-
0
|
|
1329
|
+
0,
|
|
1228
1330
|
);
|
|
1229
1331
|
|
|
1230
1332
|
assert.calledWith(
|
|
1231
1333
|
loggerSpy,
|
|
1232
1334
|
'StatsAnalyzer:index#processInboundRTPResult --> No frames received for mediaType: video-share-recv-0, receive slot id: "4" and csi: 2. Total frames received on slot: ',
|
|
1233
|
-
0
|
|
1335
|
+
0,
|
|
1234
1336
|
);
|
|
1235
1337
|
assert.calledWith(
|
|
1236
1338
|
loggerSpy,
|
|
1237
1339
|
'StatsAnalyzer:index#processInboundRTPResult --> No frames decoded for mediaType: video-share-recv-0, receive slot id: "4" and csi: 2. Total frames decoded on slot: ',
|
|
1238
|
-
0
|
|
1340
|
+
0,
|
|
1239
1341
|
);
|
|
1240
1342
|
assert.calledWith(
|
|
1241
1343
|
loggerSpy,
|
|
1242
1344
|
'StatsAnalyzer:index#processInboundRTPResult --> No packets received for mediaType: audio-share-recv-0, receive slot id: "4" and csi: 2. Total packets received on slot: ',
|
|
1243
|
-
0
|
|
1345
|
+
0,
|
|
1244
1346
|
);
|
|
1245
1347
|
});
|
|
1246
1348
|
|
|
1247
1349
|
it(`does not log a message if receiveSlot is undefined`, async () => {
|
|
1248
|
-
await startStatsAnalyzer();
|
|
1350
|
+
await startStatsAnalyzer({pc, statsAnalyzer});
|
|
1249
1351
|
|
|
1250
1352
|
// don't increase the packets when time progresses.
|
|
1251
1353
|
await progressTime();
|
|
@@ -1253,12 +1355,12 @@ describe('plugin-meetings', () => {
|
|
|
1253
1355
|
assert.neverCalledWith(
|
|
1254
1356
|
loggerSpy,
|
|
1255
1357
|
'StatsAnalyzer:index#processInboundRTPResult --> No packets received for receive slot "". Total packets received on slot: ',
|
|
1256
|
-
0
|
|
1358
|
+
0,
|
|
1257
1359
|
);
|
|
1258
1360
|
});
|
|
1259
1361
|
|
|
1260
1362
|
it('has the correct number of senders and receivers (2)', async () => {
|
|
1261
|
-
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
1363
|
+
await startStatsAnalyzer({pc, statsAnalyzer, mediaStatus: {expected: {receiveVideo: true}}});
|
|
1262
1364
|
|
|
1263
1365
|
await progressTime();
|
|
1264
1366
|
|
|
@@ -1269,7 +1371,7 @@ describe('plugin-meetings', () => {
|
|
|
1269
1371
|
});
|
|
1270
1372
|
|
|
1271
1373
|
it('has one stream per sender/reciever', async () => {
|
|
1272
|
-
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
1374
|
+
await startStatsAnalyzer({pc, statsAnalyzer, mediaStatus: {expected: {receiveVideo: true}}});
|
|
1273
1375
|
|
|
1274
1376
|
await progressTime();
|
|
1275
1377
|
|
|
@@ -1456,7 +1558,7 @@ describe('plugin-meetings', () => {
|
|
|
1456
1558
|
framesDropped: 0,
|
|
1457
1559
|
},
|
|
1458
1560
|
h264CodecProfile: 'BP',
|
|
1459
|
-
isActiveSpeaker:
|
|
1561
|
+
isActiveSpeaker: false,
|
|
1460
1562
|
optimalFrameSize: 0,
|
|
1461
1563
|
receivedFrameSize: 3600,
|
|
1462
1564
|
receivedHeight: 720,
|
|
@@ -1490,7 +1592,7 @@ describe('plugin-meetings', () => {
|
|
|
1490
1592
|
framesDropped: 0,
|
|
1491
1593
|
},
|
|
1492
1594
|
h264CodecProfile: 'BP',
|
|
1493
|
-
isActiveSpeaker:
|
|
1595
|
+
isActiveSpeaker: false,
|
|
1494
1596
|
optimalFrameSize: 0,
|
|
1495
1597
|
receivedFrameSize: 3600,
|
|
1496
1598
|
receivedHeight: 720,
|
|
@@ -1529,7 +1631,7 @@ describe('plugin-meetings', () => {
|
|
|
1529
1631
|
},
|
|
1530
1632
|
});
|
|
1531
1633
|
|
|
1532
|
-
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
1634
|
+
await startStatsAnalyzer({pc, statsAnalyzer, mediaStatus: {expected: {receiveVideo: true}}});
|
|
1533
1635
|
|
|
1534
1636
|
await progressTime();
|
|
1535
1637
|
|
|
@@ -1554,7 +1656,7 @@ describe('plugin-meetings', () => {
|
|
|
1554
1656
|
framesDropped: 0,
|
|
1555
1657
|
},
|
|
1556
1658
|
h264CodecProfile: 'BP',
|
|
1557
|
-
isActiveSpeaker:
|
|
1659
|
+
isActiveSpeaker: false,
|
|
1558
1660
|
optimalFrameSize: 0,
|
|
1559
1661
|
receivedFrameSize: 3600,
|
|
1560
1662
|
receivedHeight: 720,
|
|
@@ -1586,7 +1688,7 @@ describe('plugin-meetings', () => {
|
|
|
1586
1688
|
framesDropped: 0,
|
|
1587
1689
|
},
|
|
1588
1690
|
h264CodecProfile: 'BP',
|
|
1589
|
-
isActiveSpeaker:
|
|
1691
|
+
isActiveSpeaker: false,
|
|
1590
1692
|
optimalFrameSize: 0,
|
|
1591
1693
|
receivedFrameSize: 3600,
|
|
1592
1694
|
receivedHeight: 720,
|
|
@@ -1618,7 +1720,7 @@ describe('plugin-meetings', () => {
|
|
|
1618
1720
|
framesDropped: 0,
|
|
1619
1721
|
},
|
|
1620
1722
|
h264CodecProfile: 'BP',
|
|
1621
|
-
isActiveSpeaker:
|
|
1723
|
+
isActiveSpeaker: false,
|
|
1622
1724
|
optimalFrameSize: 0,
|
|
1623
1725
|
receivedFrameSize: 3600,
|
|
1624
1726
|
receivedHeight: 720,
|
|
@@ -1633,186 +1735,358 @@ describe('plugin-meetings', () => {
|
|
|
1633
1735
|
]);
|
|
1634
1736
|
});
|
|
1635
1737
|
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1738
|
+
describe('stream count for simulcast', async () => {
|
|
1739
|
+
it('has three streams for video senders for simulcast', async () => {
|
|
1740
|
+
pc.getTransceiverStats = sinon.stub().resolves({
|
|
1741
|
+
audio: {
|
|
1742
|
+
senders: [fakeStats.audio.senders[0]],
|
|
1743
|
+
receivers: [fakeStats.audio.receivers[0]],
|
|
1744
|
+
},
|
|
1745
|
+
video: {
|
|
1746
|
+
senders: [
|
|
1747
|
+
{
|
|
1748
|
+
localTrackLabel: 'fake-camera',
|
|
1749
|
+
report: [
|
|
1750
|
+
{
|
|
1751
|
+
type: 'outbound-rtp',
|
|
1752
|
+
bytesSent: 1,
|
|
1753
|
+
framesSent: 0,
|
|
1754
|
+
packetsSent: 0,
|
|
1755
|
+
isRequested: true,
|
|
1756
|
+
},
|
|
1757
|
+
{
|
|
1758
|
+
type: 'outbound-rtp',
|
|
1759
|
+
bytesSent: 1,
|
|
1760
|
+
framesSent: 0,
|
|
1761
|
+
packetsSent: 1,
|
|
1762
|
+
isRequested: true,
|
|
1763
|
+
},
|
|
1764
|
+
{
|
|
1765
|
+
type: 'outbound-rtp',
|
|
1766
|
+
bytesSent: 1000,
|
|
1767
|
+
framesSent: 1,
|
|
1768
|
+
packetsSent: 0,
|
|
1769
|
+
isRequested: true,
|
|
1770
|
+
},
|
|
1771
|
+
{
|
|
1772
|
+
type: 'remote-inbound-rtp',
|
|
1773
|
+
packetsLost: 0,
|
|
1774
|
+
},
|
|
1775
|
+
{
|
|
1776
|
+
type: 'candidate-pair',
|
|
1777
|
+
state: 'succeeded',
|
|
1778
|
+
localCandidateId: 'fake-candidate-id',
|
|
1779
|
+
},
|
|
1780
|
+
{
|
|
1781
|
+
type: 'candidate-pair',
|
|
1782
|
+
state: 'failed',
|
|
1783
|
+
localCandidateId: 'bad-candidate-id',
|
|
1784
|
+
},
|
|
1785
|
+
{
|
|
1786
|
+
type: 'local-candidate',
|
|
1787
|
+
id: 'fake-candidate-id',
|
|
1788
|
+
protocol: 'tcp',
|
|
1789
|
+
},
|
|
1790
|
+
],
|
|
1791
|
+
},
|
|
1792
|
+
],
|
|
1793
|
+
receivers: [fakeStats.video.receivers[0]],
|
|
1794
|
+
},
|
|
1795
|
+
screenShareAudio: {
|
|
1796
|
+
senders: [fakeStats.audio.senders[0]],
|
|
1797
|
+
receivers: [fakeStats.audio.receivers[0]],
|
|
1798
|
+
},
|
|
1799
|
+
screenShareVideo: {
|
|
1800
|
+
senders: [fakeStats.video.senders[0]],
|
|
1801
|
+
receivers: [fakeStats.video.receivers[0]],
|
|
1802
|
+
},
|
|
1803
|
+
});
|
|
1700
1804
|
|
|
1701
|
-
|
|
1805
|
+
await startStatsAnalyzer({
|
|
1806
|
+
pc,
|
|
1807
|
+
statsAnalyzer,
|
|
1808
|
+
mediaStatus: {
|
|
1809
|
+
expected: {
|
|
1810
|
+
receiveVideo: true,
|
|
1811
|
+
},
|
|
1812
|
+
},
|
|
1813
|
+
});
|
|
1702
1814
|
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1815
|
+
await progressTime();
|
|
1816
|
+
|
|
1817
|
+
assert.deepEqual(mqeData.videoTransmit[0].streams, [
|
|
1818
|
+
{
|
|
1819
|
+
common: {
|
|
1820
|
+
codec: 'H264',
|
|
1821
|
+
csi: [],
|
|
1822
|
+
duplicateSsci: 0,
|
|
1823
|
+
requestedBitrate: 0,
|
|
1824
|
+
requestedFrames: 0,
|
|
1825
|
+
rtpPackets: 0,
|
|
1826
|
+
ssci: 0,
|
|
1827
|
+
transmittedBitrate: 0.13333333333333333,
|
|
1828
|
+
transmittedFrameRate: 0,
|
|
1829
|
+
},
|
|
1830
|
+
h264CodecProfile: 'BP',
|
|
1831
|
+
isAvatar: false,
|
|
1832
|
+
isHardwareEncoded: false,
|
|
1833
|
+
localConfigurationChanges: 2,
|
|
1834
|
+
maxFrameQp: 0,
|
|
1835
|
+
maxNoiseLevel: 0,
|
|
1836
|
+
minRegionQp: 0,
|
|
1837
|
+
remoteConfigurationChanges: 0,
|
|
1838
|
+
requestedFrameSize: 0,
|
|
1839
|
+
requestedKeyFrames: 0,
|
|
1840
|
+
transmittedFrameSize: 0,
|
|
1841
|
+
transmittedHeight: 0,
|
|
1842
|
+
transmittedKeyFrames: 0,
|
|
1843
|
+
transmittedKeyFramesClient: 0,
|
|
1844
|
+
transmittedKeyFramesConfigurationChange: 0,
|
|
1845
|
+
transmittedKeyFramesFeedback: 0,
|
|
1846
|
+
transmittedKeyFramesLocalDrop: 0,
|
|
1847
|
+
transmittedKeyFramesOtherLayer: 0,
|
|
1848
|
+
transmittedKeyFramesPeriodic: 0,
|
|
1849
|
+
transmittedKeyFramesSceneChange: 0,
|
|
1850
|
+
transmittedKeyFramesStartup: 0,
|
|
1851
|
+
transmittedKeyFramesUnknown: 0,
|
|
1852
|
+
transmittedWidth: 0,
|
|
1709
1853
|
requestedBitrate: 0,
|
|
1710
|
-
requestedFrames: 0,
|
|
1711
|
-
rtpPackets: 0,
|
|
1712
|
-
ssci: 0,
|
|
1713
|
-
transmittedBitrate: 0.13333333333333333,
|
|
1714
|
-
transmittedFrameRate: 0
|
|
1715
1854
|
},
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1855
|
+
{
|
|
1856
|
+
common: {
|
|
1857
|
+
codec: 'H264',
|
|
1858
|
+
csi: [],
|
|
1859
|
+
duplicateSsci: 0,
|
|
1860
|
+
requestedBitrate: 0,
|
|
1861
|
+
requestedFrames: 0,
|
|
1862
|
+
rtpPackets: 1,
|
|
1863
|
+
ssci: 0,
|
|
1864
|
+
transmittedBitrate: 0.13333333333333333,
|
|
1865
|
+
transmittedFrameRate: 0,
|
|
1866
|
+
},
|
|
1867
|
+
h264CodecProfile: 'BP',
|
|
1868
|
+
isAvatar: false,
|
|
1869
|
+
isHardwareEncoded: false,
|
|
1870
|
+
localConfigurationChanges: 2,
|
|
1871
|
+
maxFrameQp: 0,
|
|
1872
|
+
maxNoiseLevel: 0,
|
|
1873
|
+
minRegionQp: 0,
|
|
1874
|
+
remoteConfigurationChanges: 0,
|
|
1875
|
+
requestedFrameSize: 0,
|
|
1876
|
+
requestedKeyFrames: 0,
|
|
1877
|
+
transmittedFrameSize: 0,
|
|
1878
|
+
transmittedHeight: 0,
|
|
1879
|
+
transmittedKeyFrames: 0,
|
|
1880
|
+
transmittedKeyFramesClient: 0,
|
|
1881
|
+
transmittedKeyFramesConfigurationChange: 0,
|
|
1882
|
+
transmittedKeyFramesFeedback: 0,
|
|
1883
|
+
transmittedKeyFramesLocalDrop: 0,
|
|
1884
|
+
transmittedKeyFramesOtherLayer: 0,
|
|
1885
|
+
transmittedKeyFramesPeriodic: 0,
|
|
1886
|
+
transmittedKeyFramesSceneChange: 0,
|
|
1887
|
+
transmittedKeyFramesStartup: 0,
|
|
1888
|
+
transmittedKeyFramesUnknown: 0,
|
|
1889
|
+
transmittedWidth: 0,
|
|
1746
1890
|
requestedBitrate: 0,
|
|
1747
|
-
requestedFrames: 0,
|
|
1748
|
-
rtpPackets: 0,
|
|
1749
|
-
ssci: 0,
|
|
1750
|
-
transmittedBitrate: 0,
|
|
1751
|
-
transmittedFrameRate: 0,
|
|
1752
1891
|
},
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1892
|
+
{
|
|
1893
|
+
common: {
|
|
1894
|
+
codec: 'H264',
|
|
1895
|
+
csi: [],
|
|
1896
|
+
duplicateSsci: 0,
|
|
1897
|
+
requestedBitrate: 0,
|
|
1898
|
+
requestedFrames: 0,
|
|
1899
|
+
rtpPackets: 0,
|
|
1900
|
+
ssci: 0,
|
|
1901
|
+
transmittedBitrate: 133.33333333333334,
|
|
1902
|
+
transmittedFrameRate: 0,
|
|
1903
|
+
},
|
|
1904
|
+
h264CodecProfile: 'BP',
|
|
1905
|
+
isAvatar: false,
|
|
1906
|
+
isHardwareEncoded: false,
|
|
1907
|
+
localConfigurationChanges: 2,
|
|
1908
|
+
maxFrameQp: 0,
|
|
1909
|
+
maxNoiseLevel: 0,
|
|
1910
|
+
minRegionQp: 0,
|
|
1911
|
+
remoteConfigurationChanges: 0,
|
|
1912
|
+
requestedFrameSize: 0,
|
|
1913
|
+
requestedKeyFrames: 0,
|
|
1914
|
+
transmittedFrameSize: 0,
|
|
1915
|
+
transmittedHeight: 0,
|
|
1916
|
+
transmittedKeyFrames: 0,
|
|
1917
|
+
transmittedKeyFramesClient: 0,
|
|
1918
|
+
transmittedKeyFramesConfigurationChange: 0,
|
|
1919
|
+
transmittedKeyFramesFeedback: 0,
|
|
1920
|
+
transmittedKeyFramesLocalDrop: 0,
|
|
1921
|
+
transmittedKeyFramesOtherLayer: 0,
|
|
1922
|
+
transmittedKeyFramesPeriodic: 0,
|
|
1923
|
+
transmittedKeyFramesSceneChange: 0,
|
|
1924
|
+
transmittedKeyFramesStartup: 0,
|
|
1925
|
+
transmittedKeyFramesUnknown: 0,
|
|
1926
|
+
transmittedWidth: 0,
|
|
1783
1927
|
requestedBitrate: 0,
|
|
1784
|
-
requestedFrames: 0,
|
|
1785
|
-
rtpPackets: 1,
|
|
1786
|
-
ssci: 0,
|
|
1787
|
-
transmittedBitrate: 133.33333333333334,
|
|
1788
|
-
transmittedFrameRate: 0,
|
|
1789
1928
|
},
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1929
|
+
]);
|
|
1930
|
+
});
|
|
1931
|
+
});
|
|
1932
|
+
describe('active speaker status emission', async () => {
|
|
1933
|
+
beforeEach(async () => {
|
|
1934
|
+
await startStatsAnalyzer({pc, statsAnalyzer});
|
|
1935
|
+
performance.timeOrigin = 1;
|
|
1936
|
+
});
|
|
1937
|
+
|
|
1938
|
+
it('reports active speaker as true when the participant has been speaking', async () => {
|
|
1939
|
+
fakeStats.video.receivers[0].report[0].isActiveSpeaker = true;
|
|
1940
|
+
await progressTime(5 * MQA_INTERVAL);
|
|
1941
|
+
assert.strictEqual(mqeData.videoReceive[0].streams[0].isActiveSpeaker, true);
|
|
1942
|
+
});
|
|
1943
|
+
|
|
1944
|
+
it('reports active speaker as false when the participant has not spoken', async () => {
|
|
1945
|
+
fakeStats.video.receivers[0].report[0].isActiveSpeaker = false;
|
|
1946
|
+
await progressTime(5 * MQA_INTERVAL);
|
|
1947
|
+
assert.strictEqual(mqeData.videoReceive[0].streams[0].isActiveSpeaker, false);
|
|
1948
|
+
});
|
|
1949
|
+
|
|
1950
|
+
it('defaults to false when active speaker status is indeterminate', async () => {
|
|
1951
|
+
fakeStats.video.receivers[0].report[0].isActiveSpeaker = undefined;
|
|
1952
|
+
await progressTime(MQA_INTERVAL);
|
|
1953
|
+
assert.strictEqual(mqeData.videoReceive[0].streams[0].isActiveSpeaker, false);
|
|
1954
|
+
});
|
|
1955
|
+
|
|
1956
|
+
it('updates active speaker to true following a recent status change to speaking', async () => {
|
|
1957
|
+
fakeStats.video.receivers[0].report[0].isActiveSpeaker = false;
|
|
1958
|
+
fakeStats.video.receivers[0].report[0].lastActiveSpeakerUpdateTimestamp = performance.timeOrigin + performance.now() + (30 * 1000);
|
|
1959
|
+
await progressTime(MQA_INTERVAL);
|
|
1960
|
+
assert.strictEqual(mqeData.videoReceive[0].streams[0].isActiveSpeaker, true);
|
|
1961
|
+
await progressTime(MQA_INTERVAL);
|
|
1962
|
+
assert.strictEqual(mqeData.videoReceive[0].streams[0].isActiveSpeaker, false);
|
|
1963
|
+
});
|
|
1964
|
+
});
|
|
1965
|
+
describe('sends streams according to their is requested flag', async () => {
|
|
1966
|
+
|
|
1967
|
+
beforeEach(async () => {
|
|
1968
|
+
performance.timeOrigin = 0;
|
|
1969
|
+
await startStatsAnalyzer({pc, statsAnalyzer});
|
|
1970
|
+
});
|
|
1971
|
+
|
|
1972
|
+
it('should send a stream if it is requested', async () => {
|
|
1973
|
+
fakeStats.audio.senders[0].report[0].isRequested = true;
|
|
1974
|
+
await progressTime(MQA_INTERVAL);
|
|
1975
|
+
assert.strictEqual(mqeData.audioTransmit[0].streams.length, 1);
|
|
1976
|
+
});
|
|
1977
|
+
|
|
1978
|
+
it('should not sent a stream if its is requested flag is undefined', async () => {
|
|
1979
|
+
fakeStats.audio.senders[0].report[0].isRequested = undefined;
|
|
1980
|
+
await progressTime(MQA_INTERVAL);
|
|
1981
|
+
assert.strictEqual(mqeData.audioTransmit[0].streams.length, 0);
|
|
1982
|
+
});
|
|
1983
|
+
|
|
1984
|
+
it('should not send a stream if it is not requested', async () => {
|
|
1985
|
+
fakeStats.audio.receivers[0].report[0].isRequested = false;
|
|
1986
|
+
await progressTime(MQA_INTERVAL);
|
|
1987
|
+
assert.strictEqual(mqeData.audioReceive[0].streams.length, 0);
|
|
1988
|
+
});
|
|
1989
|
+
|
|
1990
|
+
it('should send the stream if it was recently requested', async () => {
|
|
1991
|
+
fakeStats.audio.receivers[0].report[0].lastRequestedUpdateTimestamp = performance.timeOrigin + performance.now() + (30 * 1000);
|
|
1992
|
+
fakeStats.audio.receivers[0].report[0].isRequested = false;
|
|
1993
|
+
await progressTime(MQA_INTERVAL);
|
|
1994
|
+
assert.strictEqual(mqeData.audioReceive[0].streams.length, 1);
|
|
1995
|
+
await progressTime(MQA_INTERVAL);
|
|
1996
|
+
assert.strictEqual(mqeData.audioReceive[0].streams.length, 0);
|
|
1997
|
+
});
|
|
1998
|
+
});
|
|
1999
|
+
|
|
2000
|
+
describe('window and screen size emission', async () => {
|
|
2001
|
+
beforeEach(async () => {
|
|
2002
|
+
await startStatsAnalyzer({pc, statsAnalyzer});
|
|
2003
|
+
});
|
|
2004
|
+
|
|
2005
|
+
it('should record the screen size from window.screen properties', async () => {
|
|
2006
|
+
sinon.stub(window.screen, 'width').get(() => 1280);
|
|
2007
|
+
sinon.stub(window.screen, 'height').get(() => 720);
|
|
2008
|
+
await progressTime(MQA_INTERVAL);
|
|
2009
|
+
assert.strictEqual(mqeData.intervalMetadata.screenWidth, 1280);
|
|
2010
|
+
assert.strictEqual(mqeData.intervalMetadata.screenHeight, 720);
|
|
2011
|
+
assert.strictEqual(mqeData.intervalMetadata.screenResolution, 3600);
|
|
2012
|
+
});
|
|
2013
|
+
|
|
2014
|
+
it('should record the initial app window size from window properties', async () => {
|
|
2015
|
+
sinon.stub(window, 'innerWidth').get(() => 720);
|
|
2016
|
+
sinon.stub(window, 'innerHeight').get(() => 360);
|
|
2017
|
+
await progressTime(MQA_INTERVAL);
|
|
2018
|
+
assert.strictEqual(mqeData.intervalMetadata.appWindowWidth, 720);
|
|
2019
|
+
assert.strictEqual(mqeData.intervalMetadata.appWindowHeight, 360);
|
|
2020
|
+
assert.strictEqual(mqeData.intervalMetadata.appWindowSize, 1013);
|
|
2021
|
+
|
|
2022
|
+
sinon.stub(window, 'innerWidth').get(() => 1080);
|
|
2023
|
+
sinon.stub(window, 'innerHeight').get(() => 720);
|
|
2024
|
+
await progressTime(MQA_INTERVAL);
|
|
2025
|
+
assert.strictEqual(mqeData.intervalMetadata.appWindowWidth, 1080);
|
|
2026
|
+
assert.strictEqual(mqeData.intervalMetadata.appWindowHeight, 720);
|
|
2027
|
+
assert.strictEqual(mqeData.intervalMetadata.appWindowSize, 3038);
|
|
2028
|
+
});
|
|
2029
|
+
});
|
|
2030
|
+
|
|
2031
|
+
describe('sends multistreamEnabled', async () => {
|
|
2032
|
+
it('false if StatsAnalyzer initialized with default value for isMultistream', async () => {
|
|
2033
|
+
await startStatsAnalyzer({pc, statsAnalyzer, mediaStatus: {expected: {receiveVideo: true}}});
|
|
2034
|
+
|
|
2035
|
+
await progressTime();
|
|
2036
|
+
|
|
2037
|
+
for (const data of [
|
|
2038
|
+
mqeData.audioTransmit,
|
|
2039
|
+
mqeData.audioReceive,
|
|
2040
|
+
mqeData.videoTransmit,
|
|
2041
|
+
mqeData.videoReceive,
|
|
2042
|
+
]) {
|
|
2043
|
+
assert.strictEqual(data[0].common.common.multistreamEnabled, false);
|
|
1814
2044
|
}
|
|
1815
|
-
|
|
2045
|
+
});
|
|
2046
|
+
|
|
2047
|
+
it('false if StatsAnalyzer initialized with false', async () => {
|
|
2048
|
+
statsAnalyzer = new StatsAnalyzer({
|
|
2049
|
+
config: initialConfig,
|
|
2050
|
+
receiveSlotCallback: () => receiveSlot,
|
|
2051
|
+
networkQualityMonitor,
|
|
2052
|
+
isMultistream: false,
|
|
2053
|
+
});
|
|
2054
|
+
registerStatsAnalyzerEvents(statsAnalyzer);
|
|
2055
|
+
await startStatsAnalyzer({pc, statsAnalyzer, mediaStatus: {expected: {receiveVideo: false}}});
|
|
2056
|
+
|
|
2057
|
+
await progressTime();
|
|
2058
|
+
|
|
2059
|
+
for (const data of [
|
|
2060
|
+
mqeData.audioTransmit,
|
|
2061
|
+
mqeData.audioReceive,
|
|
2062
|
+
mqeData.videoTransmit,
|
|
2063
|
+
mqeData.videoReceive,
|
|
2064
|
+
]) {
|
|
2065
|
+
assert.strictEqual(data[0].common.common.multistreamEnabled, false);
|
|
2066
|
+
}
|
|
2067
|
+
});
|
|
2068
|
+
|
|
2069
|
+
it('true if StatsAnalyzer initialized with multistream', async () => {
|
|
2070
|
+
statsAnalyzer = new StatsAnalyzer({
|
|
2071
|
+
config: initialConfig,
|
|
2072
|
+
receiveSlotCallback: () => receiveSlot,
|
|
2073
|
+
networkQualityMonitor,
|
|
2074
|
+
isMultistream: true,
|
|
2075
|
+
});
|
|
2076
|
+
registerStatsAnalyzerEvents(statsAnalyzer);
|
|
2077
|
+
await startStatsAnalyzer({pc, statsAnalyzer, mediaStatus: {expected: {receiveVideo: true}}});
|
|
2078
|
+
|
|
2079
|
+
await progressTime();
|
|
2080
|
+
|
|
2081
|
+
for (const data of [
|
|
2082
|
+
mqeData.audioTransmit,
|
|
2083
|
+
mqeData.audioReceive,
|
|
2084
|
+
mqeData.videoTransmit,
|
|
2085
|
+
mqeData.videoReceive,
|
|
2086
|
+
]) {
|
|
2087
|
+
assert.strictEqual(data[0].common.common.multistreamEnabled, true);
|
|
2088
|
+
}
|
|
2089
|
+
});
|
|
1816
2090
|
});
|
|
1817
2091
|
});
|
|
1818
2092
|
});
|