|
@@ -515,6 +515,41 @@ export default class AvgRTPStatsReporter {
|
515
|
515
|
this._avgLocalScreenFPS
|
516
|
516
|
= new AverageStatReport('stat_avg_framerate_screen_local');
|
517
|
517
|
|
|
518
|
+ /**
|
|
519
|
+ * Average pixels for remote screen streaming videos (reported only if
|
|
520
|
+ * not a <tt>NaN</tt>).
|
|
521
|
+ * @type {AverageStatReport}
|
|
522
|
+ * @private
|
|
523
|
+ */
|
|
524
|
+ this._avgRemoteCameraPixels
|
|
525
|
+ = new AverageStatReport('stat_avg_pixels_remote');
|
|
526
|
+
|
|
527
|
+ /**
|
|
528
|
+ * Average pixels for remote screen streaming videos (reported only if
|
|
529
|
+ * not a <tt>NaN</tt>).
|
|
530
|
+ * @type {AverageStatReport}
|
|
531
|
+ * @private
|
|
532
|
+ */
|
|
533
|
+ this._avgRemoteScreenPixels
|
|
534
|
+ = new AverageStatReport('stat_avg_pixels_screen_remote');
|
|
535
|
+
|
|
536
|
+ /**
|
|
537
|
+ * Average pixels for local video (camera)
|
|
538
|
+ * @type {AverageStatReport}
|
|
539
|
+ * @private
|
|
540
|
+ */
|
|
541
|
+ this._avgLocalCameraPixels
|
|
542
|
+ = new AverageStatReport('stat_avg_pixels_local');
|
|
543
|
+
|
|
544
|
+ /**
|
|
545
|
+ * Average pixels for local screen streaming video (reported only if not
|
|
546
|
+ * a <tt>NaN</tt>).
|
|
547
|
+ * @type {AverageStatReport}
|
|
548
|
+ * @private
|
|
549
|
+ */
|
|
550
|
+ this._avgLocalScreenPixels
|
|
551
|
+ = new AverageStatReport('stat_avg_pixels_screen_local');
|
|
552
|
+
|
518
|
553
|
/**
|
519
|
554
|
* Average connection quality as defined by
|
520
|
555
|
* the {@link ConnectionQuality} module.
|
|
@@ -594,6 +629,7 @@ export default class AvgRTPStatsReporter {
|
594
|
629
|
const bandwidth = data.bandwidth;
|
595
|
630
|
const packetLoss = data.packetLoss;
|
596
|
631
|
const frameRate = data.framerate;
|
|
632
|
+ const resolution = data.resolution;
|
597
|
633
|
|
598
|
634
|
if (!bitrate) {
|
599
|
635
|
logger.error('No "bitrate"');
|
|
@@ -610,6 +646,10 @@ export default class AvgRTPStatsReporter {
|
610
|
646
|
} else if (!frameRate) {
|
611
|
647
|
logger.error('No "framerate"');
|
612
|
648
|
|
|
649
|
+ return;
|
|
650
|
+ } else if (!resolution) {
|
|
651
|
+ logger.error('No resolution');
|
|
652
|
+
|
613
|
653
|
return;
|
614
|
654
|
}
|
615
|
655
|
|
|
@@ -646,6 +686,24 @@ export default class AvgRTPStatsReporter {
|
646
|
686
|
frameRate, true /* local */, VideoType.DESKTOP));
|
647
|
687
|
}
|
648
|
688
|
|
|
689
|
+ if (resolution) {
|
|
690
|
+ this._avgRemoteCameraPixels.addNext(
|
|
691
|
+ this._calculateAvgVideoPixels(
|
|
692
|
+ resolution, false /* remote */, VideoType.CAMERA));
|
|
693
|
+
|
|
694
|
+ this._avgRemoteScreenPixels.addNext(
|
|
695
|
+ this._calculateAvgVideoPixels(
|
|
696
|
+ resolution, false /* remote */, VideoType.DESKTOP));
|
|
697
|
+
|
|
698
|
+ this._avgLocalCameraPixels.addNext(
|
|
699
|
+ this._calculateAvgVideoPixels(
|
|
700
|
+ resolution, true /* local */, VideoType.CAMERA));
|
|
701
|
+
|
|
702
|
+ this._avgLocalScreenPixels.addNext(
|
|
703
|
+ this._calculateAvgVideoPixels(
|
|
704
|
+ resolution, true /* local */, VideoType.DESKTOP));
|
|
705
|
+ }
|
|
706
|
+
|
649
|
707
|
this._sampleIdx += 1;
|
650
|
708
|
|
651
|
709
|
if (this._sampleIdx >= this._n) {
|
|
@@ -686,6 +744,15 @@ export default class AvgRTPStatsReporter {
|
686
|
744
|
this._avgLocalScreenFPS.appendReport(batchReport);
|
687
|
745
|
}
|
688
|
746
|
|
|
747
|
+ this._avgRemoteCameraPixels.appendReport(batchReport);
|
|
748
|
+ if (!isNaN(this._avgRemoteScreenPixels.calculate())) {
|
|
749
|
+ this._avgRemoteScreenPixels.appendReport(batchReport);
|
|
750
|
+ }
|
|
751
|
+ this._avgLocalCameraPixels.appendReport(batchReport);
|
|
752
|
+ if (!isNaN(this._avgLocalScreenPixels.calculate())) {
|
|
753
|
+ this._avgLocalScreenPixels.appendReport(batchReport);
|
|
754
|
+ }
|
|
755
|
+
|
689
|
756
|
this._avgCQ.appendReport(batchReport);
|
690
|
757
|
|
691
|
758
|
Statistics.analytics.sendEvent(AVG_RTP_STATS_EVENT, batchReport);
|
|
@@ -694,6 +761,102 @@ export default class AvgRTPStatsReporter {
|
694
|
761
|
}
|
695
|
762
|
}
|
696
|
763
|
|
|
764
|
+ /**
|
|
765
|
+ * Calculates average number of pixels for the report
|
|
766
|
+ *
|
|
767
|
+ * @param {map} peerResolutions a map of peer resolutions
|
|
768
|
+ * @param {boolean} isLocal if the average is to be calculated for the local
|
|
769
|
+ * video or <tt>false</tt> if for remote videos.
|
|
770
|
+ * @param {VideoType} videoType
|
|
771
|
+ * @return {number|NaN} average number of pixels or <tt>NaN</tt> if there
|
|
772
|
+ * are no samples.
|
|
773
|
+ * @private
|
|
774
|
+ */
|
|
775
|
+ _calculateAvgVideoPixels(peerResolutions, isLocal, videoType) {
|
|
776
|
+ let peerPixelsSum = 0;
|
|
777
|
+ let peerCount = 0;
|
|
778
|
+ const myID = this._conference.myUserId();
|
|
779
|
+
|
|
780
|
+ for (const peerID of Object.keys(peerResolutions)) {
|
|
781
|
+ if (isLocal ? peerID === myID : peerID !== myID) {
|
|
782
|
+ const participant
|
|
783
|
+ = isLocal
|
|
784
|
+ ? null : this._conference.getParticipantById(peerID);
|
|
785
|
+ const videosResolution = peerResolutions[peerID];
|
|
786
|
+
|
|
787
|
+ // Do not continue without participant for non local peerID
|
|
788
|
+ if ((isLocal || participant) && videosResolution) {
|
|
789
|
+ const peerAvgPixels = this._calculatePeerAvgVideoPixels(
|
|
790
|
+ videosResolution, participant, videoType);
|
|
791
|
+
|
|
792
|
+ if (!isNaN(peerAvgPixels)) {
|
|
793
|
+ peerPixelsSum += peerAvgPixels;
|
|
794
|
+ peerCount += 1;
|
|
795
|
+ }
|
|
796
|
+ }
|
|
797
|
+ }
|
|
798
|
+ }
|
|
799
|
+
|
|
800
|
+ return peerPixelsSum / peerCount;
|
|
801
|
+ }
|
|
802
|
+
|
|
803
|
+ /**
|
|
804
|
+ * Calculate average pixels for either remote or local participant
|
|
805
|
+ * @param {object} videos maps resolution per video SSRC
|
|
806
|
+ * @param {JitsiParticipant|null} participant remote participant or
|
|
807
|
+ * <tt>null</tt> for local video pixels calculation.
|
|
808
|
+ * @param {VideoType} videoType the type of the video for which an average
|
|
809
|
+ * will be calculated.
|
|
810
|
+ * @return {number|NaN} average video pixels of all participant's videos or
|
|
811
|
+ * <tt>NaN</tt> if currently not available
|
|
812
|
+ * @private
|
|
813
|
+ */
|
|
814
|
+ _calculatePeerAvgVideoPixels(videos, participant, videoType) {
|
|
815
|
+ let ssrcs = Object.keys(videos).map(ssrc => Number(ssrc));
|
|
816
|
+ let videoTracks = null;
|
|
817
|
+
|
|
818
|
+ // NOTE that this method is supposed to be called for the stats
|
|
819
|
+ // received from the current peerconnection.
|
|
820
|
+ const tpc = this._conference.getActivePeerConnection();
|
|
821
|
+
|
|
822
|
+ if (participant) {
|
|
823
|
+ videoTracks = participant.getTracksByMediaType(MediaType.VIDEO);
|
|
824
|
+ if (videoTracks) {
|
|
825
|
+ ssrcs
|
|
826
|
+ = ssrcs.filter(
|
|
827
|
+ ssrc => videoTracks.find(
|
|
828
|
+ track => !track.isMuted()
|
|
829
|
+ && track.getSSRC() === ssrc
|
|
830
|
+ && track.videoType === videoType));
|
|
831
|
+ }
|
|
832
|
+ } else {
|
|
833
|
+ videoTracks = this._conference.getLocalTracks(MediaType.VIDEO);
|
|
834
|
+ ssrcs
|
|
835
|
+ = ssrcs.filter(
|
|
836
|
+ ssrc => videoTracks.find(
|
|
837
|
+ track => !track.isMuted()
|
|
838
|
+ && tpc.getLocalSSRC(track) === ssrc
|
|
839
|
+ && track.videoType === videoType));
|
|
840
|
+ }
|
|
841
|
+
|
|
842
|
+ let peerPixelsSum = 0;
|
|
843
|
+ let peerSsrcCount = 0;
|
|
844
|
+
|
|
845
|
+ for (const ssrc of ssrcs) {
|
|
846
|
+ const peerSsrcPixels
|
|
847
|
+ = Number(videos[ssrc].height) * Number(videos[ssrc].width);
|
|
848
|
+
|
|
849
|
+ // FPS is reported as 0 for users with no video
|
|
850
|
+ if (!isNaN(peerSsrcPixels) && peerSsrcPixels > 0) {
|
|
851
|
+ peerPixelsSum += peerSsrcPixels;
|
|
852
|
+ peerSsrcCount += 1;
|
|
853
|
+ }
|
|
854
|
+ }
|
|
855
|
+
|
|
856
|
+ return peerPixelsSum / peerSsrcCount;
|
|
857
|
+ }
|
|
858
|
+
|
|
859
|
+
|
697
|
860
|
/**
|
698
|
861
|
* Calculates average FPS for the report
|
699
|
862
|
* @param {go figure} frameRate
|
|
@@ -822,6 +985,11 @@ export default class AvgRTPStatsReporter {
|
822
|
985
|
this._avgLocalFPS.reset();
|
823
|
986
|
this._avgLocalScreenFPS.reset();
|
824
|
987
|
|
|
988
|
+ this._avgRemoteCameraPixels.reset();
|
|
989
|
+ this._avgRemoteScreenPixels.reset();
|
|
990
|
+ this._avgLocalCameraPixels.reset();
|
|
991
|
+ this._avgLocalScreenPixels.reset();
|
|
992
|
+
|
825
|
993
|
this._avgCQ.reset();
|
826
|
994
|
|
827
|
995
|
this._sampleIdx = 0;
|