Move RTP stats histograms from VieChannel to SendStatisticsProxy.

Also slice for screensharing.

BUG=
R=mflodman@webrtc.org, pbos@webrtc.org

Review URL: https://codereview.webrtc.org/1734933002 .

Cr-Commit-Position: refs/heads/master@{#11822}
diff --git a/webrtc/common_types.h b/webrtc/common_types.h
index 16174dc..191d9aa 100644
--- a/webrtc/common_types.h
+++ b/webrtc/common_types.h
@@ -11,6 +11,7 @@
 #ifndef WEBRTC_COMMON_TYPES_H_
 #define WEBRTC_COMMON_TYPES_H_
 
+#include <assert.h>
 #include <stddef.h>
 #include <string.h>
 
@@ -791,6 +792,17 @@
     packets += other.packets;
   }
 
+  void Subtract(const RtpPacketCounter& other) {
+    assert(header_bytes >= other.header_bytes);
+    header_bytes -= other.header_bytes;
+    assert(payload_bytes >= other.payload_bytes);
+    payload_bytes -= other.payload_bytes;
+    assert(padding_bytes >= other.padding_bytes);
+    padding_bytes -= other.padding_bytes;
+    assert(packets >= other.packets);
+    packets -= other.packets;
+  }
+
   void AddPacket(size_t packet_length, const RTPHeader& header) {
     ++packets;
     header_bytes += header.headerLength;
@@ -825,6 +837,18 @@
     }
   }
 
+  void Subtract(const StreamDataCounters& other) {
+    transmitted.Subtract(other.transmitted);
+    retransmitted.Subtract(other.retransmitted);
+    fec.Subtract(other.fec);
+    if (other.first_packet_time_ms != -1 &&
+        (other.first_packet_time_ms > first_packet_time_ms ||
+         first_packet_time_ms == -1)) {
+      // Use youngest time.
+      first_packet_time_ms = other.first_packet_time_ms;
+    }
+  }
+
   int64_t TimeSinceFirstPacketInMs(int64_t now_ms) const {
     return (first_packet_time_ms == -1) ? -1 : (now_ms - first_packet_time_ms);
   }
diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc
index 94a87d8..2a88e28 100644
--- a/webrtc/video/end_to_end_tests.cc
+++ b/webrtc/video/end_to_end_tests.cc
@@ -2246,20 +2246,19 @@
   EXPECT_EQ(1, test::NumHistogramSamples(video_prefix + "EncodeTimeInMs"));
   EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.DecodeTimeInMs"));
 
-  EXPECT_EQ(1, test::NumHistogramSamples(
-      "WebRTC.Video.BitrateSentInKbps"));
+  EXPECT_EQ(1, test::NumHistogramSamples(video_prefix + "BitrateSentInKbps"));
   EXPECT_EQ(1, test::NumHistogramSamples(
       "WebRTC.Video.BitrateReceivedInKbps"));
-  EXPECT_EQ(1, test::NumHistogramSamples(
-      "WebRTC.Video.MediaBitrateSentInKbps"));
+  EXPECT_EQ(1,
+            test::NumHistogramSamples(video_prefix + "MediaBitrateSentInKbps"));
   EXPECT_EQ(1, test::NumHistogramSamples(
       "WebRTC.Video.MediaBitrateReceivedInKbps"));
-  EXPECT_EQ(1, test::NumHistogramSamples(
-      "WebRTC.Video.PaddingBitrateSentInKbps"));
+  EXPECT_EQ(
+      1, test::NumHistogramSamples(video_prefix + "PaddingBitrateSentInKbps"));
   EXPECT_EQ(1, test::NumHistogramSamples(
       "WebRTC.Video.PaddingBitrateReceivedInKbps"));
-  EXPECT_EQ(1, test::NumHistogramSamples(
-      "WebRTC.Video.RetransmittedBitrateSentInKbps"));
+  EXPECT_EQ(1, test::NumHistogramSamples(video_prefix +
+                                         "RetransmittedBitrateSentInKbps"));
   EXPECT_EQ(1, test::NumHistogramSamples(
       "WebRTC.Video.RetransmittedBitrateReceivedInKbps"));
 
diff --git a/webrtc/video/send_statistics_proxy.cc b/webrtc/video/send_statistics_proxy.cc
index 729c775..6407cdc 100644
--- a/webrtc/video/send_statistics_proxy.cc
+++ b/webrtc/video/send_statistics_proxy.cc
@@ -98,10 +98,26 @@
       input_frame_rate_tracker_(100u, 10u),
       sent_frame_rate_tracker_(100u, 10u),
       first_rtcp_stats_time_ms_(-1),
+      first_rtp_stats_time_ms_(-1),
       start_stats_(stats) {}
 
 SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {}
 
+void AccumulateRtpStats(const VideoSendStream::Stats& stats,
+                        const VideoSendStream::Config& config,
+                        StreamDataCounters* total_rtp_stats,
+                        StreamDataCounters* rtx_stats) {
+  for (auto it : stats.substreams) {
+    const std::vector<uint32_t> rtx_ssrcs = config.rtp.rtx.ssrcs;
+    if (std::find(rtx_ssrcs.begin(), rtx_ssrcs.end(), it.first) !=
+        rtx_ssrcs.end()) {
+      rtx_stats->Add(it.second.rtp_stats);
+    } else {
+      total_rtp_stats->Add(it.second.rtp_stats);
+    }
+  }
+}
+
 void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
     const VideoSendStream::Config& config,
     const VideoSendStream::Stats& current_stats) {
@@ -223,6 +239,51 @@
       }
     }
   }
+
+  if (first_rtp_stats_time_ms_ != -1) {
+    int64_t elapsed_sec =
+        (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000;
+    if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
+      StreamDataCounters rtp;
+      StreamDataCounters rtx;
+      AccumulateRtpStats(current_stats, config, &rtp, &rtx);
+      StreamDataCounters start_rtp;
+      StreamDataCounters start_rtx;
+      AccumulateRtpStats(start_stats_, config, &start_rtp, &start_rtx);
+      rtp.Subtract(start_rtp);
+      rtx.Subtract(start_rtx);
+      StreamDataCounters rtp_rtx = rtp;
+      rtp_rtx.Add(rtx);
+
+      RTC_HISTOGRAMS_COUNTS_10000(
+          kIndex, uma_prefix_ + "BitrateSentInKbps",
+          static_cast<int>(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
+                           1000));
+      RTC_HISTOGRAMS_COUNTS_10000(
+          kIndex, uma_prefix_ + "MediaBitrateSentInKbps",
+          static_cast<int>(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000));
+      RTC_HISTOGRAMS_COUNTS_10000(
+          kIndex, uma_prefix_ + "PaddingBitrateSentInKbps",
+          static_cast<int>(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec /
+                           1000));
+      RTC_HISTOGRAMS_COUNTS_10000(
+          kIndex, uma_prefix_ + "RetransmittedBitrateSentInKbps",
+          static_cast<int>(rtp_rtx.retransmitted.TotalBytes() * 8 /
+                           elapsed_sec / 1000));
+      if (!config.rtp.rtx.ssrcs.empty()) {
+        RTC_HISTOGRAMS_COUNTS_10000(
+            kIndex, uma_prefix_ + "RtxBitrateSentInKbps",
+            static_cast<int>(rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
+                             1000));
+      }
+      if (config.rtp.fec.red_payload_type != -1) {
+        RTC_HISTOGRAMS_COUNTS_10000(kIndex,
+                                    uma_prefix_ + "FecBitrateSentInKbps",
+                                    static_cast<int>(rtp_rtx.fec.TotalBytes() *
+                                                     8 / elapsed_sec / 1000));
+      }
+    }
+  }
 }
 
 void SendStatisticsProxy::SetContentType(
@@ -429,6 +490,8 @@
       << "DataCountersUpdated reported for unknown ssrc: " << ssrc;
 
   stats->rtp_stats = counters;
+  if (uma_container_->first_rtp_stats_time_ms_ == -1)
+    uma_container_->first_rtp_stats_time_ms_ = clock_->TimeInMilliseconds();
 }
 
 void SendStatisticsProxy::Notify(const BitrateStatistics& total_stats,
diff --git a/webrtc/video/send_statistics_proxy.h b/webrtc/video/send_statistics_proxy.h
index 0d0d0e0..24a09b0 100644
--- a/webrtc/video/send_statistics_proxy.h
+++ b/webrtc/video/send_statistics_proxy.h
@@ -169,6 +169,7 @@
     rtc::RateTracker input_frame_rate_tracker_;
     rtc::RateTracker sent_frame_rate_tracker_;
     int64_t first_rtcp_stats_time_ms_;
+    int64_t first_rtp_stats_time_ms_;
     ReportBlockStats report_block_stats_;
     const VideoSendStream::Stats start_stats_;
   };
diff --git a/webrtc/video/send_statistics_proxy_unittest.cc b/webrtc/video/send_statistics_proxy_unittest.cc
index c112013..b3da5e9 100644
--- a/webrtc/video/send_statistics_proxy_unittest.cc
+++ b/webrtc/video/send_statistics_proxy_unittest.cc
@@ -47,6 +47,7 @@
     config.rtp.ssrcs.push_back(kSecondSsrc);
     config.rtp.rtx.ssrcs.push_back(kFirstRtxSsrc);
     config.rtp.rtx.ssrcs.push_back(kSecondRtxSsrc);
+    config.rtp.fec.red_payload_type = 17;
     return config;
   }
 
@@ -525,4 +526,136 @@
           "WebRTC.Video.Screenshare.UniqueNackRequestsReceivedInPercent"));
 }
 
+TEST_F(SendStatisticsProxyTest, ResetsRtpCountersOnContentChange) {
+  StreamDataCountersCallback* proxy =
+      static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
+  StreamDataCounters counters;
+  StreamDataCounters rtx_counters;
+  counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
+  proxy->DataCountersUpdated(counters, kFirstSsrc);
+  proxy->DataCountersUpdated(counters, kSecondSsrc);
+  proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc);
+  proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc);
+
+  counters.transmitted.header_bytes = 400;
+  counters.transmitted.packets = 20;
+  counters.transmitted.padding_bytes = 1000;
+  counters.transmitted.payload_bytes = 2000;
+
+  counters.retransmitted.header_bytes = 40;
+  counters.retransmitted.packets = 2;
+  counters.retransmitted.padding_bytes = 100;
+  counters.retransmitted.payload_bytes = 200;
+
+  counters.fec = counters.retransmitted;
+
+  rtx_counters.transmitted = counters.transmitted;
+
+  fake_clock_.AdvanceTimeMilliseconds(1000 * metrics::kMinRunTimeInSeconds);
+  proxy->DataCountersUpdated(counters, kFirstSsrc);
+  proxy->DataCountersUpdated(counters, kSecondSsrc);
+  proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc);
+  proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc);
+
+  // Changing content type causes histograms to be reported.
+  statistics_proxy_->SetContentType(VideoEncoderConfig::ContentType::kScreen);
+
+  EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.BitrateSentInKbps"));
+  EXPECT_EQ(static_cast<int>((counters.transmitted.TotalBytes() * 4 * 8) /
+                             metrics::kMinRunTimeInSeconds / 1000),
+            test::LastHistogramSample("WebRTC.Video.BitrateSentInKbps"));
+
+  EXPECT_EQ(1,
+            test::NumHistogramSamples("WebRTC.Video.MediaBitrateSentInKbps"));
+  EXPECT_EQ(static_cast<int>((counters.MediaPayloadBytes() * 2 * 8) /
+                             metrics::kMinRunTimeInSeconds / 1000),
+            test::LastHistogramSample("WebRTC.Video.MediaBitrateSentInKbps"));
+
+  EXPECT_EQ(1,
+            test::NumHistogramSamples("WebRTC.Video.PaddingBitrateSentInKbps"));
+  EXPECT_EQ(static_cast<int>((counters.transmitted.padding_bytes * 4 * 8) /
+                             metrics::kMinRunTimeInSeconds / 1000),
+            test::LastHistogramSample("WebRTC.Video.PaddingBitrateSentInKbps"));
+
+  EXPECT_EQ(1, test::NumHistogramSamples(
+                   "WebRTC.Video.RetransmittedBitrateSentInKbps"));
+  EXPECT_EQ(
+      static_cast<int>((counters.retransmitted.TotalBytes() * 2 * 8) /
+                       metrics::kMinRunTimeInSeconds / 1000),
+      test::LastHistogramSample("WebRTC.Video.RetransmittedBitrateSentInKbps"));
+
+  EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.RtxBitrateSentInKbps"));
+  EXPECT_EQ(static_cast<int>((rtx_counters.transmitted.TotalBytes() * 2 * 8) /
+                             metrics::kMinRunTimeInSeconds / 1000),
+            test::LastHistogramSample("WebRTC.Video.RtxBitrateSentInKbps"));
+
+  EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.FecBitrateSentInKbps"));
+  EXPECT_EQ(static_cast<int>((rtx_counters.fec.TotalBytes() * 2 * 8) /
+                             metrics::kMinRunTimeInSeconds / 1000),
+            test::LastHistogramSample("WebRTC.Video.FecBitrateSentInKbps"));
+
+  // New start time but same counter values.
+  proxy->DataCountersUpdated(counters, kFirstSsrc);
+  proxy->DataCountersUpdated(counters, kSecondSsrc);
+  proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc);
+  proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc);
+
+  // Double counter values, this should result in the same counts as before but
+  // with new histogram names.
+  StreamDataCounters new_counters = counters;
+  new_counters.Add(counters);
+  StreamDataCounters new_rtx_counters = rtx_counters;
+  new_rtx_counters.Add(rtx_counters);
+
+  fake_clock_.AdvanceTimeMilliseconds(1000 * metrics::kMinRunTimeInSeconds);
+  proxy->DataCountersUpdated(new_counters, kFirstSsrc);
+  proxy->DataCountersUpdated(new_counters, kSecondSsrc);
+  proxy->DataCountersUpdated(new_rtx_counters, kFirstRtxSsrc);
+  proxy->DataCountersUpdated(new_rtx_counters, kSecondRtxSsrc);
+
+  SetUp();  // Reset stats proxy also causes histograms to be reported.
+
+  EXPECT_EQ(1, test::NumHistogramSamples(
+                   "WebRTC.Video.Screenshare.BitrateSentInKbps"));
+  EXPECT_EQ(
+      static_cast<int>((counters.transmitted.TotalBytes() * 4 * 8) /
+                       metrics::kMinRunTimeInSeconds / 1000),
+      test::LastHistogramSample("WebRTC.Video.Screenshare.BitrateSentInKbps"));
+
+  EXPECT_EQ(1, test::NumHistogramSamples(
+                   "WebRTC.Video.Screenshare.MediaBitrateSentInKbps"));
+  EXPECT_EQ(static_cast<int>((counters.MediaPayloadBytes() * 2 * 8) /
+                             metrics::kMinRunTimeInSeconds / 1000),
+            test::LastHistogramSample(
+                "WebRTC.Video.Screenshare.MediaBitrateSentInKbps"));
+
+  EXPECT_EQ(1, test::NumHistogramSamples(
+                   "WebRTC.Video.Screenshare.PaddingBitrateSentInKbps"));
+  EXPECT_EQ(static_cast<int>((counters.transmitted.padding_bytes * 4 * 8) /
+                             metrics::kMinRunTimeInSeconds / 1000),
+            test::LastHistogramSample(
+                "WebRTC.Video.Screenshare.PaddingBitrateSentInKbps"));
+
+  EXPECT_EQ(1, test::NumHistogramSamples(
+                   "WebRTC.Video.Screenshare.RetransmittedBitrateSentInKbps"));
+  EXPECT_EQ(static_cast<int>((counters.retransmitted.TotalBytes() * 2 * 8) /
+                             metrics::kMinRunTimeInSeconds / 1000),
+            test::LastHistogramSample(
+                "WebRTC.Video.Screenshare.RetransmittedBitrateSentInKbps"));
+
+  EXPECT_EQ(1, test::NumHistogramSamples(
+                   "WebRTC.Video.Screenshare.RtxBitrateSentInKbps"));
+  EXPECT_EQ(static_cast<int>((rtx_counters.transmitted.TotalBytes() * 2 * 8) /
+                             metrics::kMinRunTimeInSeconds / 1000),
+            test::LastHistogramSample(
+                "WebRTC.Video.Screenshare.RtxBitrateSentInKbps"));
+
+  EXPECT_EQ(1, test::NumHistogramSamples(
+                   "WebRTC.Video.Screenshare.FecBitrateSentInKbps"));
+  EXPECT_EQ(static_cast<int>((rtx_counters.fec.TotalBytes() * 2 * 8) /
+                             metrics::kMinRunTimeInSeconds / 1000),
+            test::LastHistogramSample(
+                "WebRTC.Video.Screenshare.FecBitrateSentInKbps"));
+}
+
 }  // namespace webrtc
diff --git a/webrtc/video/vie_channel.cc b/webrtc/video/vie_channel.cc
index 3099286..2b601ed 100644
--- a/webrtc/video/vie_channel.cc
+++ b/webrtc/video/vie_channel.cc
@@ -163,7 +163,6 @@
 }
 
 ViEChannel::~ViEChannel() {
-  UpdateHistograms();
   // Make sure we don't get more callbacks from the RTP module.
   module_process_thread_->DeRegisterModule(
       vie_receiver_.GetReceiveStatistics());
@@ -177,52 +176,6 @@
   }
 }
 
-void ViEChannel::UpdateHistograms() {
-  if (sender_) {
-    StreamDataCounters rtp;
-    StreamDataCounters rtx;
-    GetSendStreamDataCounters(&rtp, &rtx);
-    StreamDataCounters rtp_rtx = rtp;
-    rtp_rtx.Add(rtx);
-    int64_t elapsed_sec = rtp_rtx.TimeSinceFirstPacketInMs(
-                              Clock::GetRealTimeClock()->TimeInMilliseconds()) /
-                          1000;
-    if (elapsed_sec > metrics::kMinRunTimeInSeconds) {
-      RTC_HISTOGRAM_COUNTS_100000(
-          "WebRTC.Video.BitrateSentInKbps",
-          static_cast<int>(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
-                           1000));
-      RTC_HISTOGRAM_COUNTS_10000(
-          "WebRTC.Video.MediaBitrateSentInKbps",
-          static_cast<int>(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000));
-      RTC_HISTOGRAM_COUNTS_10000(
-          "WebRTC.Video.PaddingBitrateSentInKbps",
-          static_cast<int>(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec /
-                           1000));
-      RTC_HISTOGRAM_COUNTS_10000(
-          "WebRTC.Video.RetransmittedBitrateSentInKbps",
-          static_cast<int>(rtp_rtx.retransmitted.TotalBytes() * 8 /
-                           elapsed_sec / 1000));
-      if (rtp_rtcp_modules_[0]->RtxSendStatus() != kRtxOff) {
-        RTC_HISTOGRAM_COUNTS_10000(
-            "WebRTC.Video.RtxBitrateSentInKbps",
-            static_cast<int>(rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
-                             1000));
-      }
-      bool fec_enabled = false;
-      uint8_t pltype_red;
-      uint8_t pltype_fec;
-      rtp_rtcp_modules_[0]->GenericFECStatus(&fec_enabled, &pltype_red,
-                                             &pltype_fec);
-      if (fec_enabled) {
-        RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FecBitrateSentInKbps",
-                                   static_cast<int>(rtp_rtx.fec.TotalBytes() *
-                                                    8 / elapsed_sec / 1000));
-      }
-    }
-  }
-}
-
 int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec,
                                  bool new_stream) {
   RTC_DCHECK(sender_);
diff --git a/webrtc/video/vie_channel.h b/webrtc/video/vie_channel.h
index 2cb623c..afb8d89 100644
--- a/webrtc/video/vie_channel.h
+++ b/webrtc/video/vie_channel.h
@@ -200,8 +200,6 @@
   // Compute NACK list parameters for the buffering mode.
   int GetRequiredNackListSize(int target_delay_ms);
 
-  void UpdateHistograms();
-
   // ViEChannel exposes methods that allow to modify observers and callbacks
   // to be modified. Such an API-style is cumbersome to implement and maintain
   // at all the levels when comparing to only setting them at construction. As