@webex/plugin-meetings 2.60.0-next.6 → 2.60.0-next.8
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.d.ts +0 -128
- package/dist/mediaQualityMetrics/config.js +1 -202
- package/dist/mediaQualityMetrics/config.js.map +1 -1
- package/dist/meeting/index.d.ts +5 -1
- package/dist/meeting/index.js +15 -8
- package/dist/meeting/index.js.map +1 -1
- package/dist/statsAnalyzer/index.d.ts +0 -10
- package/dist/statsAnalyzer/index.js +41 -154
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/statsAnalyzer/mqaUtil.js +21 -22
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
- package/dist/webinar/index.js +1 -1
- package/package.json +20 -20
- package/src/mediaQualityMetrics/config.ts +0 -135
- package/src/meeting/index.ts +16 -7
- package/src/statsAnalyzer/index.ts +49 -226
- package/src/statsAnalyzer/mqaUtil.ts +13 -21
- package/test/unit/spec/meeting/index.js +93 -2
|
@@ -103,7 +103,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
103
103
|
this.networkQualityMonitor = networkQualityMonitor;
|
|
104
104
|
this.correlationId = config.correlationId;
|
|
105
105
|
this.mqaSentCount = -1;
|
|
106
|
-
this.lastMqaDataSent = {
|
|
106
|
+
this.lastMqaDataSent = {};
|
|
107
107
|
this.lastEmittedStartStopEvent = {};
|
|
108
108
|
this.receiveSlotCallback = receiveSlotCallback;
|
|
109
109
|
this.successfulCandidatePair = {};
|
|
@@ -154,17 +154,14 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
154
154
|
Object.keys(this.statsResults).forEach((mediaType) => {
|
|
155
155
|
if (!this.lastMqaDataSent[mediaType]) {
|
|
156
156
|
this.lastMqaDataSent[mediaType] = {};
|
|
157
|
-
this.lastMqaDataSent.resolutions[mediaType] = {};
|
|
158
157
|
}
|
|
159
158
|
|
|
160
159
|
if (!this.lastMqaDataSent[mediaType].send && mediaType.includes('-send')) {
|
|
161
160
|
this.lastMqaDataSent[mediaType].send = {};
|
|
162
|
-
this.lastMqaDataSent.resolutions[mediaType].send = {};
|
|
163
161
|
}
|
|
164
162
|
|
|
165
163
|
if (!this.lastMqaDataSent[mediaType].recv && mediaType.includes('-recv')) {
|
|
166
164
|
this.lastMqaDataSent[mediaType].recv = {};
|
|
167
|
-
this.lastMqaDataSent.resolutions[mediaType].recv = {};
|
|
168
165
|
}
|
|
169
166
|
|
|
170
167
|
if (mediaType.includes('audio-send') || mediaType.includes('audio-share-send')) {
|
|
@@ -203,9 +200,6 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
203
200
|
newMqa.videoTransmit.push(videoSender);
|
|
204
201
|
|
|
205
202
|
this.lastMqaDataSent[mediaType].send = cloneDeep(this.statsResults[mediaType].send);
|
|
206
|
-
this.lastMqaDataSent.resolutions[mediaType].send = cloneDeep(
|
|
207
|
-
this.statsResults.resolutions[mediaType].send
|
|
208
|
-
);
|
|
209
203
|
} else if (mediaType.includes('video-recv') || mediaType.includes('video-share-recv')) {
|
|
210
204
|
const videoReceiver = cloneDeep(emptyVideoReceive);
|
|
211
205
|
|
|
@@ -218,9 +212,6 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
218
212
|
newMqa.videoReceive.push(videoReceiver);
|
|
219
213
|
|
|
220
214
|
this.lastMqaDataSent[mediaType].recv = cloneDeep(this.statsResults[mediaType].recv);
|
|
221
|
-
this.lastMqaDataSent.resolutions[mediaType].recv = cloneDeep(
|
|
222
|
-
this.statsResults.resolutions[mediaType].recv
|
|
223
|
-
);
|
|
224
215
|
}
|
|
225
216
|
});
|
|
226
217
|
|
|
@@ -359,26 +350,6 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
359
350
|
this.statsResults[type].recv = cloneDeep(emptyReceiver);
|
|
360
351
|
}
|
|
361
352
|
|
|
362
|
-
if (!this.statsResults.resolutions[type]) {
|
|
363
|
-
this.statsResults.resolutions[type] = {};
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
if (isSender && !this.statsResults.resolutions[type].send) {
|
|
367
|
-
this.statsResults.resolutions[type].send = cloneDeep(emptySender);
|
|
368
|
-
} else if (!isSender && !this.statsResults.resolutions[type].recv) {
|
|
369
|
-
this.statsResults.resolutions[type].recv = cloneDeep(emptyReceiver);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
if (!this.statsResults.internal[type]) {
|
|
373
|
-
this.statsResults.internal[type] = {};
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
if (isSender && !this.statsResults.internal[type].send) {
|
|
377
|
-
this.statsResults.internal[type].send = cloneDeep(emptySender);
|
|
378
|
-
} else if (!isSender && !this.statsResults.internal[type].recv) {
|
|
379
|
-
this.statsResults.internal[type].recv = cloneDeep(emptyReceiver);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
353
|
switch (getStatsResult.type) {
|
|
383
354
|
case 'outbound-rtp':
|
|
384
355
|
this.processOutboundRTPResult(getStatsResult, type);
|
|
@@ -386,13 +357,9 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
386
357
|
case 'inbound-rtp':
|
|
387
358
|
this.processInboundRTPResult(getStatsResult, type);
|
|
388
359
|
break;
|
|
389
|
-
case 'track':
|
|
390
|
-
this.processTrackResult(getStatsResult, type);
|
|
391
|
-
break;
|
|
392
360
|
case 'remote-inbound-rtp':
|
|
393
361
|
case 'remote-outbound-rtp':
|
|
394
|
-
|
|
395
|
-
this.compareSentAndReceived(getStatsResult, type, isSender);
|
|
362
|
+
this.compareSentAndReceived(getStatsResult, type);
|
|
396
363
|
break;
|
|
397
364
|
case 'remotecandidate':
|
|
398
365
|
case 'remote-candidate':
|
|
@@ -543,19 +510,6 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
543
510
|
.filter((key) => key.startsWith(keyPrefix))
|
|
544
511
|
.reduce((prev, cur) => prev + (this.lastStatsResults[cur]?.recv[value] || 0), 0);
|
|
545
512
|
|
|
546
|
-
const getCurrentResolutionsStatsTotals = (keyPrefix: string, value: string): number =>
|
|
547
|
-
Object.keys(this.statsResults)
|
|
548
|
-
.filter((key) => key.startsWith(keyPrefix))
|
|
549
|
-
.reduce((prev, cur) => prev + (this.statsResults.resolutions[cur]?.recv[value] || 0), 0);
|
|
550
|
-
|
|
551
|
-
const getPreviousResolutionsStatsTotals = (keyPrefix: string, value: string): number =>
|
|
552
|
-
Object.keys(this.statsResults)
|
|
553
|
-
.filter((key) => key.startsWith(keyPrefix))
|
|
554
|
-
.reduce(
|
|
555
|
-
(prev, cur) => prev + (this.lastStatsResults.resolutions[cur]?.recv[value] || 0),
|
|
556
|
-
0
|
|
557
|
-
);
|
|
558
|
-
|
|
559
513
|
if (this.meetingMediaStatus.expected.sendAudio && this.lastStatsResults['audio-send']) {
|
|
560
514
|
// compare audio stats sent
|
|
561
515
|
// NOTE: relies on there being only one sender.
|
|
@@ -652,13 +606,13 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
652
606
|
}
|
|
653
607
|
|
|
654
608
|
if (
|
|
655
|
-
this.statsResults
|
|
656
|
-
this.lastStatsResults
|
|
657
|
-
this.statsResults
|
|
609
|
+
this.statsResults['video-send'].send.framesSent ===
|
|
610
|
+
this.lastStatsResults['video-send'].send.framesSent ||
|
|
611
|
+
this.statsResults['video-send'].send.framesSent === 0
|
|
658
612
|
) {
|
|
659
613
|
LoggerProxy.logger.info(
|
|
660
614
|
`StatsAnalyzer:index#compareLastStatsResult --> No video Frames sent`,
|
|
661
|
-
this.statsResults
|
|
615
|
+
this.statsResults['video-send'].send.framesSent
|
|
662
616
|
);
|
|
663
617
|
}
|
|
664
618
|
}
|
|
@@ -673,24 +627,12 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
673
627
|
'video-recv',
|
|
674
628
|
'totalPacketsReceived'
|
|
675
629
|
);
|
|
676
|
-
const currentFramesReceived =
|
|
677
|
-
|
|
678
|
-
'framesReceived'
|
|
679
|
-
);
|
|
680
|
-
const previousFramesReceived = getPreviousResolutionsStatsTotals(
|
|
681
|
-
'video-recv',
|
|
682
|
-
'framesReceived'
|
|
683
|
-
);
|
|
630
|
+
const currentFramesReceived = getCurrentStatsTotals('video-recv', 'framesReceived');
|
|
631
|
+
const previousFramesReceived = getPreviousStatsTotals('video-recv', 'framesReceived');
|
|
684
632
|
const currentFramesDecoded = getCurrentStatsTotals('video-recv', 'framesDecoded');
|
|
685
633
|
const previousFramesDecoded = getPreviousStatsTotals('video-recv', 'framesDecoded');
|
|
686
|
-
const currentFramesDropped =
|
|
687
|
-
|
|
688
|
-
'framesDropped'
|
|
689
|
-
);
|
|
690
|
-
const previousFramesDropped = getPreviousResolutionsStatsTotals(
|
|
691
|
-
'video-recv',
|
|
692
|
-
'framesDropped'
|
|
693
|
-
);
|
|
634
|
+
const currentFramesDropped = getCurrentStatsTotals('video-recv', 'framesDropped');
|
|
635
|
+
const previousFramesDropped = getPreviousStatsTotals('video-recv', 'framesDropped');
|
|
694
636
|
|
|
695
637
|
if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
|
|
696
638
|
LoggerProxy.logger.info(
|
|
@@ -749,13 +691,13 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
749
691
|
}
|
|
750
692
|
|
|
751
693
|
if (
|
|
752
|
-
this.statsResults
|
|
753
|
-
this.lastStatsResults
|
|
754
|
-
this.statsResults
|
|
694
|
+
this.statsResults['video-share-send'].send.framesSent ===
|
|
695
|
+
this.lastStatsResults['video-share-send'].send.framesSent ||
|
|
696
|
+
this.statsResults['video-share-send'].send.framesSent === 0
|
|
755
697
|
) {
|
|
756
698
|
LoggerProxy.logger.info(
|
|
757
699
|
`StatsAnalyzer:index#compareLastStatsResult --> No share frames sent`,
|
|
758
|
-
this.statsResults
|
|
700
|
+
this.statsResults['video-share-send'].send.framesSent
|
|
759
701
|
);
|
|
760
702
|
}
|
|
761
703
|
}
|
|
@@ -772,24 +714,12 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
772
714
|
'video-share-recv',
|
|
773
715
|
'totalPacketsReceived'
|
|
774
716
|
);
|
|
775
|
-
const currentFramesReceived =
|
|
776
|
-
|
|
777
|
-
'framesReceived'
|
|
778
|
-
);
|
|
779
|
-
const previousFramesReceived = getPreviousResolutionsStatsTotals(
|
|
780
|
-
'video-share-recv',
|
|
781
|
-
'framesReceived'
|
|
782
|
-
);
|
|
717
|
+
const currentFramesReceived = getCurrentStatsTotals('video-share-recv', 'framesReceived');
|
|
718
|
+
const previousFramesReceived = getPreviousStatsTotals('video-share-recv', 'framesReceived');
|
|
783
719
|
const currentFramesDecoded = getCurrentStatsTotals('video-share-recv', 'framesDecoded');
|
|
784
720
|
const previousFramesDecoded = getPreviousStatsTotals('video-share-recv', 'framesDecoded');
|
|
785
|
-
const currentFramesDropped =
|
|
786
|
-
|
|
787
|
-
'framesDropped'
|
|
788
|
-
);
|
|
789
|
-
const previousFramesDropped = getPreviousResolutionsStatsTotals(
|
|
790
|
-
'video-share-recv',
|
|
791
|
-
'framesDropped'
|
|
792
|
-
);
|
|
721
|
+
const currentFramesDropped = getCurrentStatsTotals('video-share-recv', 'framesDropped');
|
|
722
|
+
const previousFramesDropped = getPreviousStatsTotals('video-share-recv', 'framesDropped');
|
|
793
723
|
|
|
794
724
|
if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
|
|
795
725
|
LoggerProxy.logger.info(
|
|
@@ -913,51 +843,20 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
913
843
|
const sendrecvType = STATS.SEND_DIRECTION;
|
|
914
844
|
|
|
915
845
|
if (result.bytesSent) {
|
|
916
|
-
|
|
846
|
+
const kilobytes = 0;
|
|
917
847
|
|
|
918
848
|
if (result.frameWidth && result.frameHeight) {
|
|
919
|
-
this.statsResults
|
|
920
|
-
this.statsResults
|
|
921
|
-
this.statsResults
|
|
922
|
-
this.statsResults
|
|
923
|
-
result.hugeFramesSent;
|
|
849
|
+
this.statsResults[mediaType][sendrecvType].width = result.frameWidth;
|
|
850
|
+
this.statsResults[mediaType][sendrecvType].height = result.frameHeight;
|
|
851
|
+
this.statsResults[mediaType][sendrecvType].framesSent = result.framesSent;
|
|
852
|
+
this.statsResults[mediaType][sendrecvType].hugeFramesSent = result.hugeFramesSent;
|
|
924
853
|
}
|
|
925
854
|
|
|
926
|
-
if (!this.statsResults.internal[mediaType][sendrecvType].prevBytesSent) {
|
|
927
|
-
this.statsResults.internal[mediaType][sendrecvType].prevBytesSent = result.bytesSent;
|
|
928
|
-
}
|
|
929
|
-
if (!this.statsResults.internal[mediaType][sendrecvType].framesEncoded) {
|
|
930
|
-
this.statsResults.internal[mediaType][sendrecvType].framesEncoded = result.framesEncoded;
|
|
931
|
-
}
|
|
932
|
-
if (!this.statsResults.internal[mediaType][sendrecvType].keyFramesEncoded) {
|
|
933
|
-
this.statsResults.internal[mediaType][sendrecvType].keyFramesEncoded =
|
|
934
|
-
result.keyFramesEncoded;
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
const bytes =
|
|
938
|
-
result.bytesSent - this.statsResults.internal[mediaType][sendrecvType].prevBytesSent;
|
|
939
|
-
|
|
940
|
-
this.statsResults.internal[mediaType][sendrecvType].prevBytesSent = result.bytesSent;
|
|
941
|
-
|
|
942
|
-
kilobytes = bytes / 1024;
|
|
943
|
-
|
|
944
855
|
this.statsResults[mediaType][sendrecvType].availableBandwidth = kilobytes.toFixed(1);
|
|
945
|
-
this.statsResults[mediaType].bytesSent = kilobytes;
|
|
946
|
-
|
|
947
|
-
this.statsResults[mediaType][sendrecvType].framesEncoded =
|
|
948
|
-
result.framesEncoded - this.statsResults.internal[mediaType][sendrecvType].framesEncoded;
|
|
949
|
-
this.statsResults[mediaType][sendrecvType].keyFramesEncoded =
|
|
950
|
-
result.keyFramesEncoded -
|
|
951
|
-
this.statsResults.internal[mediaType][sendrecvType].keyFramesEncoded;
|
|
952
|
-
this.statsResults.internal[mediaType].outboundRtpId = result.id;
|
|
953
|
-
|
|
954
|
-
if (!this.statsResults.internal[mediaType][sendrecvType].packetsSent) {
|
|
955
|
-
this.statsResults.internal[mediaType][sendrecvType].packetsSent = result.packetsSent;
|
|
956
|
-
}
|
|
957
856
|
|
|
958
|
-
this.statsResults[mediaType][sendrecvType].
|
|
959
|
-
|
|
960
|
-
this.statsResults
|
|
857
|
+
this.statsResults[mediaType][sendrecvType].framesEncoded = result.framesEncoded;
|
|
858
|
+
this.statsResults[mediaType][sendrecvType].keyFramesEncoded = result.keyFramesEncoded;
|
|
859
|
+
this.statsResults[mediaType][sendrecvType].packetsSent = result.packetsSent;
|
|
961
860
|
|
|
962
861
|
// Data saved to send MQA metrics
|
|
963
862
|
|
|
@@ -1001,74 +900,40 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
1001
900
|
: '';
|
|
1002
901
|
|
|
1003
902
|
if (result.frameWidth && result.frameHeight) {
|
|
1004
|
-
this.statsResults
|
|
1005
|
-
this.statsResults
|
|
1006
|
-
this.statsResults
|
|
1007
|
-
result.framesReceived;
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
|
-
if (!this.statsResults.internal[mediaType][sendrecvType].prevBytesReceived) {
|
|
1011
|
-
this.statsResults.internal[mediaType][sendrecvType].prevBytesReceived =
|
|
1012
|
-
result.bytesReceived;
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
if (!this.statsResults.internal[mediaType][sendrecvType].pliCount) {
|
|
1016
|
-
this.statsResults.internal[mediaType][sendrecvType].pliCount = result.pliCount;
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
if (!this.statsResults.internal[mediaType][sendrecvType].packetsLost) {
|
|
1020
|
-
this.statsResults.internal[mediaType][sendrecvType].packetsLost = result.packetsLost;
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
if (!this.statsResults.internal[mediaType][sendrecvType].totalPacketsReceived) {
|
|
1024
|
-
this.statsResults.internal[mediaType][sendrecvType].totalPacketsReceived =
|
|
1025
|
-
result.packetsReceived;
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
if (!this.statsResults.internal[mediaType][sendrecvType].lastPacketReceivedTimestamp) {
|
|
1029
|
-
this.statsResults.internal[mediaType][sendrecvType].lastPacketReceivedTimestamp =
|
|
1030
|
-
result.lastPacketReceivedTimestamp;
|
|
903
|
+
this.statsResults[mediaType][sendrecvType].width = result.frameWidth;
|
|
904
|
+
this.statsResults[mediaType][sendrecvType].height = result.frameHeight;
|
|
905
|
+
this.statsResults[mediaType][sendrecvType].framesReceived = result.framesReceived;
|
|
1031
906
|
}
|
|
1032
907
|
|
|
1033
908
|
const bytes =
|
|
1034
|
-
result.bytesReceived -
|
|
1035
|
-
this.statsResults.internal[mediaType][sendrecvType].prevBytesReceived;
|
|
1036
|
-
|
|
1037
|
-
this.statsResults.internal[mediaType][sendrecvType].prevBytesReceived = result.bytesReceived;
|
|
909
|
+
result.bytesReceived - this.statsResults[mediaType][sendrecvType].totalBytesReceived;
|
|
1038
910
|
|
|
1039
911
|
kilobytes = bytes / 1024;
|
|
1040
912
|
this.statsResults[mediaType][sendrecvType].availableBandwidth = kilobytes.toFixed(1);
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
result.packetsLost - this.statsResults.internal[mediaType][sendrecvType].packetsLost;
|
|
1047
|
-
if (this.statsResults[mediaType][sendrecvType].currentPacketsLost < 0) {
|
|
1048
|
-
this.statsResults[mediaType][sendrecvType].currentPacketsLost = 0;
|
|
913
|
+
|
|
914
|
+
let currentPacketsLost =
|
|
915
|
+
result.packetsLost - this.statsResults[mediaType][sendrecvType].totalPacketsLost;
|
|
916
|
+
if (currentPacketsLost < 0) {
|
|
917
|
+
currentPacketsLost = 0;
|
|
1049
918
|
}
|
|
1050
919
|
|
|
1051
|
-
|
|
1052
|
-
result.packetsReceived -
|
|
1053
|
-
|
|
1054
|
-
this.statsResults.internal[mediaType][sendrecvType].totalPacketsReceived =
|
|
1055
|
-
result.packetsReceived;
|
|
920
|
+
const currentPacketsReceived =
|
|
921
|
+
result.packetsReceived - this.statsResults[mediaType][sendrecvType].totalPacketsReceived;
|
|
922
|
+
this.statsResults[mediaType][sendrecvType].totalPacketsReceived = result.packetsReceived;
|
|
1056
923
|
|
|
1057
|
-
if (
|
|
924
|
+
if (currentPacketsReceived === 0) {
|
|
1058
925
|
if (receiveSlot) {
|
|
1059
926
|
LoggerProxy.logger.info(
|
|
1060
927
|
`StatsAnalyzer:index#processInboundRTPResult --> No packets received for receive slot ${idAndCsi}`,
|
|
1061
|
-
|
|
928
|
+
currentPacketsReceived
|
|
1062
929
|
);
|
|
1063
930
|
}
|
|
1064
931
|
}
|
|
1065
932
|
|
|
1066
933
|
// Check the over all packet Lost ratio
|
|
1067
934
|
this.statsResults[mediaType][sendrecvType].currentPacketLossRatio =
|
|
1068
|
-
|
|
1069
|
-
?
|
|
1070
|
-
(this.statsResults[mediaType][sendrecvType].packetsReceived +
|
|
1071
|
-
this.statsResults[mediaType][sendrecvType].currentPacketsLost)
|
|
935
|
+
currentPacketsLost > 0
|
|
936
|
+
? currentPacketsLost / (currentPacketsReceived + currentPacketsLost)
|
|
1072
937
|
: 0;
|
|
1073
938
|
if (this.statsResults[mediaType][sendrecvType].currentPacketLossRatio > 3) {
|
|
1074
939
|
LoggerProxy.logger.info(
|
|
@@ -1148,7 +1013,11 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
1148
1013
|
const sendRecvType = isSender ? STATS.SEND_DIRECTION : STATS.RECEIVE_DIRECTION;
|
|
1149
1014
|
const ipType = isRemote ? STATS.REMOTE : STATS.LOCAL;
|
|
1150
1015
|
|
|
1151
|
-
this.statsResults.
|
|
1016
|
+
if (!this.statsResults.candidates) {
|
|
1017
|
+
this.statsResults.candidates = {};
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
this.statsResults.candidates[result.id] = {
|
|
1152
1021
|
candidateType: result.candidateType,
|
|
1153
1022
|
ipAddress: result.ip, // TODO: add ports
|
|
1154
1023
|
portNumber: result.port,
|
|
@@ -1170,47 +1039,6 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
1170
1039
|
this.statsResults[type][sendRecvType].totalRoundTripTime = result.totalRoundTripTime;
|
|
1171
1040
|
};
|
|
1172
1041
|
|
|
1173
|
-
/**
|
|
1174
|
-
* Process Track results
|
|
1175
|
-
*
|
|
1176
|
-
* @private
|
|
1177
|
-
* @param {*} result
|
|
1178
|
-
* @param {*} mediaType
|
|
1179
|
-
* @returns {void}
|
|
1180
|
-
* @memberof StatsAnalyzer
|
|
1181
|
-
*/
|
|
1182
|
-
private processTrackResult(result: any, mediaType: any) {
|
|
1183
|
-
if (!result || result.type !== 'track') {
|
|
1184
|
-
return;
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
const sendrecvType =
|
|
1188
|
-
result.remoteSource === true ? STATS.RECEIVE_DIRECTION : STATS.SEND_DIRECTION;
|
|
1189
|
-
|
|
1190
|
-
if (sendrecvType === STATS.RECEIVE_DIRECTION) {
|
|
1191
|
-
this.statsResults.resolutions[mediaType][sendrecvType].framesReceived = result.framesReceived;
|
|
1192
|
-
this.statsResults.resolutions[mediaType][sendrecvType].framesDecoded = result.framesDecoded;
|
|
1193
|
-
this.statsResults.resolutions[mediaType][sendrecvType].framesDropped = result.framesDropped;
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
if (result.trackIdentifier && !mediaType.includes('audio')) {
|
|
1197
|
-
this.statsResults.resolutions[mediaType][sendrecvType].trackIdentifier =
|
|
1198
|
-
result.trackIdentifier;
|
|
1199
|
-
|
|
1200
|
-
const jitterBufferDelay = result && result.jitterBufferDelay;
|
|
1201
|
-
const jitterBufferEmittedCount = result && result.jitterBufferEmittedCount;
|
|
1202
|
-
|
|
1203
|
-
this.statsResults.resolutions[mediaType][sendrecvType].avgJitterDelay =
|
|
1204
|
-
jitterBufferEmittedCount && +jitterBufferDelay / +jitterBufferEmittedCount;
|
|
1205
|
-
|
|
1206
|
-
// Used to calculate the jitter
|
|
1207
|
-
this.statsResults.resolutions[mediaType][sendrecvType].jitterBufferDelay =
|
|
1208
|
-
result.jitterBufferDelay;
|
|
1209
|
-
this.statsResults.resolutions[mediaType][sendrecvType].jitterBufferEmittedCount =
|
|
1210
|
-
result.jitterBufferEmittedCount;
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
1042
|
/**
|
|
1215
1043
|
*
|
|
1216
1044
|
* @private
|
|
@@ -1221,20 +1049,15 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
1221
1049
|
*/
|
|
1222
1050
|
compareSentAndReceived(result, type) {
|
|
1223
1051
|
// Don't compare on transceivers without a sender.
|
|
1224
|
-
if (!type || !this.statsResults
|
|
1052
|
+
if (!type || !this.statsResults[type].send) {
|
|
1225
1053
|
return;
|
|
1226
1054
|
}
|
|
1227
1055
|
|
|
1228
1056
|
const mediaType = type;
|
|
1229
1057
|
|
|
1230
|
-
if (!this.statsResults.internal[mediaType].send.totalPacketsLostOnReceiver) {
|
|
1231
|
-
this.statsResults.internal[mediaType].send.totalPacketsLostOnReceiver = result.packetsLost;
|
|
1232
|
-
}
|
|
1233
|
-
|
|
1234
1058
|
const currentPacketLoss =
|
|
1235
|
-
result.packetsLost - this.statsResults
|
|
1059
|
+
result.packetsLost - this.statsResults[mediaType].send.totalPacketsLostOnReceiver;
|
|
1236
1060
|
|
|
1237
|
-
this.statsResults.internal[mediaType].send.totalPacketsLostOnReceiver = result.packetsLost;
|
|
1238
1061
|
this.statsResults[mediaType].send.packetsLostOnReceiver = currentPacketLoss;
|
|
1239
1062
|
this.statsResults[mediaType].send.totalPacketsLostOnReceiver = result.packetsLost;
|
|
1240
1063
|
|
|
@@ -134,12 +134,9 @@ export const getVideoReceiverMqa = ({videoReceiver, statsResults, lastMqaDataSen
|
|
|
134
134
|
const lastPacketsReceived = lastMqaDataSent[mediaType]?.[sendrecvType].totalPacketsReceived || 0;
|
|
135
135
|
const lastPacketsLost = lastMqaDataSent[mediaType]?.[sendrecvType].totalPacketsLost || 0;
|
|
136
136
|
const lastBytesReceived = lastMqaDataSent[mediaType]?.[sendrecvType].totalBytesReceived || 0;
|
|
137
|
-
const lastFramesReceived =
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
lastMqaDataSent.resolutions[mediaType]?.[sendrecvType].framesDecoded || 0;
|
|
141
|
-
const lastFramesDropped =
|
|
142
|
-
lastMqaDataSent.resolutions[mediaType]?.[sendrecvType].framesDropped || 0;
|
|
137
|
+
const lastFramesReceived = lastMqaDataSent[mediaType]?.[sendrecvType].framesReceived || 0;
|
|
138
|
+
const lastFramesDecoded = lastMqaDataSent[mediaType]?.[sendrecvType].framesDecoded || 0;
|
|
139
|
+
const lastFramesDropped = lastMqaDataSent[mediaType]?.[sendrecvType].framesDropped || 0;
|
|
143
140
|
const lastKeyFramesDecoded = lastMqaDataSent[mediaType]?.[sendrecvType].keyFramesDecoded || 0;
|
|
144
141
|
const lastPliCount = lastMqaDataSent[mediaType]?.[sendrecvType].totalPliCount || 0;
|
|
145
142
|
|
|
@@ -176,7 +173,6 @@ export const getVideoReceiverMqa = ({videoReceiver, statsResults, lastMqaDataSen
|
|
|
176
173
|
mean(statsResults[mediaType][sendrecvType].meanRemoteJitter) * 1000 || 0;
|
|
177
174
|
|
|
178
175
|
videoReceiver.streams[0].common.rtpJitter = videoReceiver.common.maxRemoteJitter;
|
|
179
|
-
// videoReceiver.streams[0].common.rtpJitter = (statsResults.resolutions[mediaType][sendrecvType].jitterBufferDelay - lastMqaDataSent.resolutions[mediaType]?.[sendrecvType].jitterBufferDelay) / (statsResults.resolutions[mediaType][sendrecvType].jitterBufferEmittedCount - lastMqaDataSent.resolutions[mediaType]?.[sendrecvType].jitterBufferEmittedCount) * 1000 || 0;
|
|
180
176
|
|
|
181
177
|
// Calculate the outgoing bitrate
|
|
182
178
|
const totalBytesReceivedInaMin =
|
|
@@ -189,9 +185,9 @@ export const getVideoReceiverMqa = ({videoReceiver, statsResults, lastMqaDataSen
|
|
|
189
185
|
|
|
190
186
|
// From tracks //TODO: calculate a proper one
|
|
191
187
|
const totalFrameReceivedInaMin =
|
|
192
|
-
statsResults
|
|
188
|
+
statsResults[mediaType][sendrecvType].framesReceived - lastFramesReceived;
|
|
193
189
|
const totalFrameDecodedInaMin =
|
|
194
|
-
statsResults
|
|
190
|
+
statsResults[mediaType][sendrecvType].framesDecoded - lastFramesDecoded;
|
|
195
191
|
|
|
196
192
|
videoReceiver.streams[0].common.receivedFrameRate = Math.round(
|
|
197
193
|
totalFrameReceivedInaMin ? totalFrameReceivedInaMin / 60 : 0
|
|
@@ -201,11 +197,9 @@ export const getVideoReceiverMqa = ({videoReceiver, statsResults, lastMqaDataSen
|
|
|
201
197
|
);
|
|
202
198
|
|
|
203
199
|
videoReceiver.streams[0].common.framesDropped =
|
|
204
|
-
statsResults
|
|
205
|
-
videoReceiver.streams[0].receivedHeight =
|
|
206
|
-
|
|
207
|
-
videoReceiver.streams[0].receivedWidth =
|
|
208
|
-
statsResults.resolutions[mediaType][sendrecvType].width || 0;
|
|
200
|
+
statsResults[mediaType][sendrecvType].framesDropped - lastFramesDropped;
|
|
201
|
+
videoReceiver.streams[0].receivedHeight = statsResults[mediaType][sendrecvType].height || 0;
|
|
202
|
+
videoReceiver.streams[0].receivedWidth = statsResults[mediaType][sendrecvType].width || 0;
|
|
209
203
|
videoReceiver.streams[0].receivedFrameSize =
|
|
210
204
|
(videoReceiver.streams[0].receivedHeight * videoReceiver.streams[0].receivedWidth) / 256;
|
|
211
205
|
|
|
@@ -223,9 +217,9 @@ export const getVideoSenderMqa = ({videoSender, statsResults, lastMqaDataSent, m
|
|
|
223
217
|
lastMqaDataSent[mediaType]?.[sendrecvType].totalPacketsLostOnReceiver || 0;
|
|
224
218
|
const lastBytesSent = lastMqaDataSent[mediaType]?.[sendrecvType].totalBytesSent || 0;
|
|
225
219
|
const lastKeyFramesEncoded =
|
|
226
|
-
lastMqaDataSent
|
|
220
|
+
lastMqaDataSent[mediaType]?.[sendrecvType].totalKeyFramesEncoded || 0;
|
|
227
221
|
const lastFirCount = lastMqaDataSent[mediaType]?.[sendrecvType].totalFirCount || 0;
|
|
228
|
-
const lastFramesSent = lastMqaDataSent
|
|
222
|
+
const lastFramesSent = lastMqaDataSent[mediaType]?.[sendrecvType].framesSent || 0;
|
|
229
223
|
const {csi} = statsResults[mediaType];
|
|
230
224
|
if (csi && !videoSender.streams[0].common.csi.includes(csi)) {
|
|
231
225
|
videoSender.streams[0].common.csi.push(csi);
|
|
@@ -281,15 +275,13 @@ export const getVideoSenderMqa = ({videoSender, statsResults, lastMqaDataSent, m
|
|
|
281
275
|
|
|
282
276
|
// From tracks //TODO: calculate a proper one
|
|
283
277
|
const totalFrameSentInaMin =
|
|
284
|
-
statsResults
|
|
278
|
+
statsResults[mediaType][sendrecvType].framesSent - (lastFramesSent || 0);
|
|
285
279
|
|
|
286
280
|
videoSender.streams[0].common.transmittedFrameRate = Math.round(
|
|
287
281
|
totalFrameSentInaMin ? totalFrameSentInaMin / 60 : 0
|
|
288
282
|
);
|
|
289
|
-
videoSender.streams[0].transmittedHeight =
|
|
290
|
-
|
|
291
|
-
videoSender.streams[0].transmittedWidth =
|
|
292
|
-
statsResults.resolutions[mediaType][sendrecvType].width || 0;
|
|
283
|
+
videoSender.streams[0].transmittedHeight = statsResults[mediaType][sendrecvType].height || 0;
|
|
284
|
+
videoSender.streams[0].transmittedWidth = statsResults[mediaType][sendrecvType].width || 0;
|
|
293
285
|
videoSender.streams[0].transmittedFrameSize =
|
|
294
286
|
(videoSender.streams[0].transmittedHeight * videoSender.streams[0].transmittedWidth) / 256;
|
|
295
287
|
};
|
|
@@ -7373,6 +7373,20 @@ describe('plugin-meetings', () => {
|
|
|
7373
7373
|
});
|
|
7374
7374
|
|
|
7375
7375
|
describe('#setPermissionTokenPayload', () => {
|
|
7376
|
+
|
|
7377
|
+
let now;
|
|
7378
|
+
let clock;
|
|
7379
|
+
|
|
7380
|
+
beforeEach(() => {
|
|
7381
|
+
now = Date.now();
|
|
7382
|
+
|
|
7383
|
+
// mock `new Date()` with constant `now`
|
|
7384
|
+
clock = sinon.useFakeTimers(now);
|
|
7385
|
+
});
|
|
7386
|
+
|
|
7387
|
+
afterEach(() => {
|
|
7388
|
+
clock.restore();
|
|
7389
|
+
})
|
|
7376
7390
|
it('sets correctly', () => {
|
|
7377
7391
|
assert.notOk(meeting.permissionTokenPayload);
|
|
7378
7392
|
|
|
@@ -7384,6 +7398,7 @@ describe('plugin-meetings', () => {
|
|
|
7384
7398
|
|
|
7385
7399
|
assert.calledOnce(jwtDecodeStub);
|
|
7386
7400
|
assert.deepEqual(meeting.permissionTokenPayload, permissionTokenPayloadData);
|
|
7401
|
+
assert.deepEqual(meeting.permissionTokenReceivedLocalTime, now);
|
|
7387
7402
|
});
|
|
7388
7403
|
});
|
|
7389
7404
|
|
|
@@ -10581,18 +10596,94 @@ describe('plugin-meetings', () => {
|
|
|
10581
10596
|
it('should return the expected positive exp', () => {
|
|
10582
10597
|
// set permission token as now + 1 sec
|
|
10583
10598
|
const expiryTime = now + 1000;
|
|
10584
|
-
meeting.permissionTokenPayload = {exp: (expiryTime).toString()};
|
|
10599
|
+
meeting.permissionTokenPayload = {exp: (expiryTime).toString(), iat: now};
|
|
10600
|
+
meeting.permissionTokenReceivedLocalTime = now;
|
|
10585
10601
|
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {timeLeft: 1, expiryTime: Number(expiryTime), currentTime: now});
|
|
10586
10602
|
});
|
|
10587
10603
|
|
|
10588
10604
|
it('should return the expected negative exp', () => {
|
|
10589
10605
|
// set permission token as now - 1 sec
|
|
10590
10606
|
const expiryTime = now - 1000;
|
|
10591
|
-
meeting.permissionTokenPayload = {exp: (expiryTime).toString()};
|
|
10607
|
+
meeting.permissionTokenPayload = {exp: (expiryTime).toString(), iat: now};
|
|
10608
|
+
meeting.permissionTokenReceivedLocalTime = now;
|
|
10592
10609
|
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {timeLeft: -1, expiryTime: Number(expiryTime), currentTime: now});
|
|
10593
10610
|
});
|
|
10611
|
+
|
|
10612
|
+
describe('#getPermissionTokenExpiryInfo with wrong current time which is in future', () => {
|
|
10613
|
+
let now;
|
|
10614
|
+
let clock;
|
|
10615
|
+
beforeEach(() => {
|
|
10616
|
+
// current time is 3 hours off
|
|
10617
|
+
now = Date.now() + 10800000;
|
|
10618
|
+
|
|
10619
|
+
// mock `new Date()` with constant `now`
|
|
10620
|
+
clock = sinon.useFakeTimers(now);
|
|
10621
|
+
});
|
|
10622
|
+
|
|
10623
|
+
afterEach(() => {
|
|
10624
|
+
clock.restore();
|
|
10625
|
+
})
|
|
10626
|
+
|
|
10627
|
+
it('should return the expected positive exp when client time is wrong', () => {
|
|
10628
|
+
const serverTime = Date.now();
|
|
10629
|
+
|
|
10630
|
+
// set permission token as now + 1 sec
|
|
10631
|
+
const expiryTime = serverTime + 1000;
|
|
10632
|
+
meeting.permissionTokenPayload = {exp: (expiryTime).toString(), iat: serverTime};
|
|
10633
|
+
meeting.permissionTokenReceivedLocalTime = now;
|
|
10634
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {timeLeft: 1, expiryTime: Number(expiryTime), currentTime: now});
|
|
10635
|
+
});
|
|
10636
|
+
|
|
10637
|
+
it('should return the expected negative exp when client time is wrong', () => {
|
|
10638
|
+
const serverTime = Date.now();
|
|
10639
|
+
// set permission token as now - 1 sec
|
|
10640
|
+
const expiryTime = serverTime - 1000;
|
|
10641
|
+
meeting.permissionTokenPayload = {exp: (expiryTime).toString(), iat: serverTime};
|
|
10642
|
+
meeting.permissionTokenReceivedLocalTime = now;
|
|
10643
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {timeLeft: -1, expiryTime: Number(expiryTime), currentTime: now});
|
|
10644
|
+
});
|
|
10645
|
+
|
|
10646
|
+
});
|
|
10647
|
+
|
|
10648
|
+
describe('#getPermissionTokenExpiryInfo with wrong current Time which is in the past', () => {
|
|
10649
|
+
let now;
|
|
10650
|
+
let clock;
|
|
10651
|
+
beforeEach(() => {
|
|
10652
|
+
// current time is 3 hours off
|
|
10653
|
+
now = Date.now() - 10800000;
|
|
10654
|
+
|
|
10655
|
+
// mock `new Date()` with constant `now`
|
|
10656
|
+
clock = sinon.useFakeTimers(now);
|
|
10657
|
+
});
|
|
10658
|
+
|
|
10659
|
+
afterEach(() => {
|
|
10660
|
+
clock.restore();
|
|
10661
|
+
})
|
|
10662
|
+
|
|
10663
|
+
it('should return the expected positive exp when client time is wrong', () => {
|
|
10664
|
+
const serverTime = Date.now();
|
|
10665
|
+
|
|
10666
|
+
// set permission token as now + 1 sec
|
|
10667
|
+
const expiryTime = serverTime + 1000;
|
|
10668
|
+
meeting.permissionTokenPayload = {exp: (expiryTime).toString(), iat: serverTime};
|
|
10669
|
+
meeting.permissionTokenReceivedLocalTime = now;
|
|
10670
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {timeLeft: 1, expiryTime: Number(expiryTime), currentTime: now});
|
|
10671
|
+
});
|
|
10672
|
+
|
|
10673
|
+
it('should return the expected negative exp when client time is wrong', () => {
|
|
10674
|
+
const serverTime = Date.now();
|
|
10675
|
+
// set permission token as now - 1 sec
|
|
10676
|
+
const expiryTime = serverTime - 1000;
|
|
10677
|
+
meeting.permissionTokenPayload = {exp: (expiryTime).toString(), iat: serverTime};
|
|
10678
|
+
meeting.permissionTokenReceivedLocalTime = now;
|
|
10679
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {timeLeft: -1, expiryTime: Number(expiryTime), currentTime: now});
|
|
10680
|
+
});
|
|
10681
|
+
|
|
10682
|
+
});
|
|
10594
10683
|
});
|
|
10595
10684
|
|
|
10685
|
+
|
|
10686
|
+
|
|
10596
10687
|
describe('#checkAndRefreshPermissionToken', () => {
|
|
10597
10688
|
it('should not fire refreshPermissionToken if permissionToken is not defined', async() => {
|
|
10598
10689
|
meeting.getPermissionTokenExpiryInfo = sinon.stub().returns(undefined)
|