Use RateCounter for input/sent fps stats. Reports average of periodically computed stats over a call.

Intervals when video is paused is no longer included in the stats:
"WebRTC.Video.InputFramesPerSecond"
"WebRTC.Video.SentFramesPerSecond"

BUG=webrtc:5283

Review-Url: https://codereview.webrtc.org/2536743002
Cr-Commit-Position: refs/heads/master@{#15285}
diff --git a/webrtc/video/send_statistics_proxy.cc b/webrtc/video/send_statistics_proxy.cc
index b29884e..8c4dae5 100644
--- a/webrtc/video/send_statistics_proxy.cc
+++ b/webrtc/video/send_statistics_proxy.cc
@@ -106,7 +106,8 @@
       max_sent_width_per_timestamp_(0),
       max_sent_height_per_timestamp_(0),
       input_frame_rate_tracker_(100, 10u),
-      sent_frame_rate_tracker_(100, 10u),
+      input_fps_counter_(clock, nullptr, true),
+      sent_fps_counter_(clock, nullptr, true),
       first_rtcp_stats_time_ms_(-1),
       first_rtp_stats_time_ms_(-1),
       start_stats_(stats) {}
@@ -132,28 +133,38 @@
     const VideoSendStream::Stats& current_stats) {
   RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix);
   const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0;
+  const int kMinRequiredPeriodicSamples = 6;
   int in_width = input_width_counter_.Avg(kMinRequiredMetricsSamples);
   int in_height = input_height_counter_.Avg(kMinRequiredMetricsSamples);
-  int in_fps = round(input_frame_rate_tracker_.ComputeTotalRate());
   if (in_width != -1) {
     RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputWidthInPixels",
                                 in_width);
     RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputHeightInPixels",
                                 in_height);
-    RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "InputFramesPerSecond",
-                              in_fps);
   }
+  AggregatedStats in_fps = input_fps_counter_.GetStats();
+  if (in_fps.num_samples >= kMinRequiredPeriodicSamples) {
+    RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "InputFramesPerSecond",
+                              in_fps.average);
+    LOG(LS_INFO) << uma_prefix_ + "InputFramesPerSecond, " << in_fps.ToString();
+  }
+
   int sent_width = sent_width_counter_.Avg(kMinRequiredMetricsSamples);
   int sent_height = sent_height_counter_.Avg(kMinRequiredMetricsSamples);
-  int sent_fps = round(sent_frame_rate_tracker_.ComputeTotalRate());
   if (sent_width != -1) {
     RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentWidthInPixels",
                                 sent_width);
     RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentHeightInPixels",
                                 sent_height);
-    RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "SentFramesPerSecond",
-                              sent_fps);
   }
+  AggregatedStats sent_fps = sent_fps_counter_.GetStats();
+  if (sent_fps.num_samples >= kMinRequiredPeriodicSamples) {
+    RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "SentFramesPerSecond",
+                              sent_fps.average);
+    LOG(LS_INFO) << uma_prefix_ + "SentFramesPerSecond, "
+                 << sent_fps.ToString();
+  }
+
   int encode_ms = encode_time_counter_.Avg(kMinRequiredMetricsSamples);
   if (encode_ms != -1) {
     RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "EncodeTimeInMs",
@@ -389,6 +400,11 @@
 void SendStatisticsProxy::OnSuspendChange(bool is_suspended) {
   rtc::CritScope lock(&crit_);
   stats_.suspended = is_suspended;
+  // Pause framerate stats.
+  if (is_suspended) {
+    uma_container_->input_fps_counter_.ProcessAndPause();
+    uma_container_->sent_fps_counter_.ProcessAndPause();
+  }
 }
 
 VideoSendStream::Stats SendStatisticsProxy::GetStats() {
@@ -541,7 +557,7 @@
   // are encoded before the next start.
   if (last_sent_frame_timestamp_ > 0 &&
       encoded_image._timeStamp != last_sent_frame_timestamp_) {
-    uma_container_->sent_frame_rate_tracker_.AddSamples(1);
+    uma_container_->sent_fps_counter_.Add(1);
     uma_container_->sent_width_counter_.Add(
         uma_container_->max_sent_width_per_timestamp_);
     uma_container_->sent_height_counter_.Add(
@@ -566,6 +582,7 @@
 void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
   rtc::CritScope lock(&crit_);
   uma_container_->input_frame_rate_tracker_.AddSamples(1);
+  uma_container_->input_fps_counter_.Add(1);
   uma_container_->input_width_counter_.Add(width);
   uma_container_->input_height_counter_.Add(height);
   uma_container_->cpu_limited_frame_counter_.Add(stats_.cpu_limited_resolution);
diff --git a/webrtc/video/send_statistics_proxy.h b/webrtc/video/send_statistics_proxy.h
index fff2d8d..803fb61 100644
--- a/webrtc/video/send_statistics_proxy.h
+++ b/webrtc/video/send_statistics_proxy.h
@@ -26,6 +26,7 @@
 #include "webrtc/system_wrappers/include/clock.h"
 #include "webrtc/video/overuse_frame_detector.h"
 #include "webrtc/video/report_block_stats.h"
+#include "webrtc/video/stats_counter.h"
 #include "webrtc/video/vie_encoder.h"
 #include "webrtc/video_send_stream.h"
 
@@ -187,7 +188,8 @@
     SampleCounter delay_counter_;
     SampleCounter max_delay_counter_;
     rtc::RateTracker input_frame_rate_tracker_;
-    rtc::RateTracker sent_frame_rate_tracker_;
+    RateCounter input_fps_counter_;
+    RateCounter sent_fps_counter_;
     int64_t first_rtcp_stats_time_ms_;
     int64_t first_rtp_stats_time_ms_;
     ReportBlockStats report_block_stats_;
diff --git a/webrtc/video/send_statistics_proxy_unittest.cc b/webrtc/video/send_statistics_proxy_unittest.cc
index f88d026..aa7c14f 100644
--- a/webrtc/video/send_statistics_proxy_unittest.cc
+++ b/webrtc/video/send_statistics_proxy_unittest.cc
@@ -26,7 +26,9 @@
 const uint32_t kFirstRtxSsrc = 18;
 const uint32_t kSecondRtxSsrc = 43;
 const uint32_t kFlexFecSsrc = 55;
-
+const int kFpsPeriodicIntervalMs = 2000;
+const int kWidth = 640;
+const int kHeight = 480;
 const int kQpIdx0 = 21;
 const int kQpIdx1 = 39;
 }  // namespace
@@ -353,9 +355,6 @@
 }
 
 TEST_F(SendStatisticsProxyTest, SwitchContentTypeUpdatesHistograms) {
-  const int kWidth = 640;
-  const int kHeight = 480;
-
   for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
     statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
 
@@ -371,10 +370,110 @@
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputWidthInPixels"));
 }
 
-TEST_F(SendStatisticsProxyTest, CpuLimitedResolutionUpdated) {
-  const int kWidth = 640;
-  const int kHeight = 480;
+TEST_F(SendStatisticsProxyTest, InputResolutionHistogramsAreUpdated) {
+  for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
+    statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
 
+  statistics_proxy_.reset();
+  EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputWidthInPixels"));
+  EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.InputWidthInPixels", kWidth));
+  EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputHeightInPixels"));
+  EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.InputHeightInPixels", kHeight));
+}
+
+TEST_F(SendStatisticsProxyTest, SentResolutionHistogramsAreUpdated) {
+  EncodedImage encoded_image;
+  encoded_image._encodedWidth = kWidth;
+  encoded_image._encodedHeight = kHeight;
+  for (int i = 0; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
+    encoded_image._timeStamp = i + 1;
+    statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
+  }
+  statistics_proxy_.reset();
+  EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SentWidthInPixels"));
+  EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SentWidthInPixels", kWidth));
+  EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SentHeightInPixels"));
+  EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SentHeightInPixels", kHeight));
+}
+
+TEST_F(SendStatisticsProxyTest, InputFpsHistogramIsUpdated) {
+  const int kFps = 20;
+  const int kMinPeriodicSamples = 6;
+  int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000;
+  for (int i = 0; i <= frames; ++i) {
+    fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
+    statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
+  }
+  statistics_proxy_.reset();
+  EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputFramesPerSecond"));
+  EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.InputFramesPerSecond", kFps));
+}
+
+TEST_F(SendStatisticsProxyTest, SentFpsHistogramIsUpdated) {
+  EncodedImage encoded_image;
+  const int kFps = 20;
+  const int kMinPeriodicSamples = 6;
+  int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000 + 1;
+  for (int i = 0; i <= frames; ++i) {
+    fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
+    encoded_image._timeStamp = i + 1;
+    statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
+  }
+  statistics_proxy_.reset();
+  EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SentFramesPerSecond"));
+  EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SentFramesPerSecond", kFps));
+}
+
+TEST_F(SendStatisticsProxyTest, InputFpsHistogramExcludesSuspendedTime) {
+  const int kFps = 20;
+  const int kSuspendTimeMs = 10000;
+  const int kMinPeriodicSamples = 6;
+  int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000;
+  for (int i = 0; i < frames; ++i) {
+    fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
+    statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
+  }
+  // Suspend.
+  statistics_proxy_->OnSuspendChange(true);
+  fake_clock_.AdvanceTimeMilliseconds(kSuspendTimeMs);
+
+  for (int i = 0; i < frames; ++i) {
+    fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
+    statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
+  }
+  // Suspended time interval should not affect the framerate.
+  statistics_proxy_.reset();
+  EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputFramesPerSecond"));
+  EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.InputFramesPerSecond", kFps));
+}
+
+TEST_F(SendStatisticsProxyTest, SentFpsHistogramExcludesSuspendedTime) {
+  EncodedImage encoded_image;
+  const int kFps = 20;
+  const int kSuspendTimeMs = 10000;
+  const int kMinPeriodicSamples = 6;
+  int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000;
+  for (int i = 0; i <= frames; ++i) {
+    fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
+    encoded_image._timeStamp = i + 1;
+    statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
+  }
+  // Suspend.
+  statistics_proxy_->OnSuspendChange(true);
+  fake_clock_.AdvanceTimeMilliseconds(kSuspendTimeMs);
+
+  for (int i = 0; i <= frames; ++i) {
+    fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
+    encoded_image._timeStamp = i + 1;
+    statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
+  }
+  // Suspended time interval should not affect the framerate.
+  statistics_proxy_.reset();
+  EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SentFramesPerSecond"));
+  EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SentFramesPerSecond", kFps));
+}
+
+TEST_F(SendStatisticsProxyTest, CpuLimitedResolutionUpdated) {
   for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
     statistics_proxy_->OnIncomingFrame(kWidth, kHeight);