Delete StreamDataCountersCallback from ReceiveStatistics

Bug: webrtc:10679
Change-Id: Ife6a4f598c5b70478244b15fc884f6a424d1505b
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/148521
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28841}
diff --git a/modules/rtp_rtcp/include/receive_statistics.h b/modules/rtp_rtcp/include/receive_statistics.h
index 65a78a2..669a087 100644
--- a/modules/rtp_rtcp/include/receive_statistics.h
+++ b/modules/rtp_rtcp/include/receive_statistics.h
@@ -57,10 +57,9 @@
  public:
   ~ReceiveStatistics() override = default;
 
-  static std::unique_ptr<ReceiveStatistics> Create(Clock* clock) {
-    return Create(clock, nullptr);
-  }
+  static std::unique_ptr<ReceiveStatistics> Create(Clock* clock);
 
+  RTC_DEPRECATED
   static std::unique_ptr<ReceiveStatistics> Create(
       Clock* clock,
       StreamDataCountersCallback* rtp_callback);
diff --git a/modules/rtp_rtcp/source/receive_statistics_impl.cc b/modules/rtp_rtcp/source/receive_statistics_impl.cc
index 99566b7..e617197 100644
--- a/modules/rtp_rtcp/source/receive_statistics_impl.cc
+++ b/modules/rtp_rtcp/source/receive_statistics_impl.cc
@@ -30,11 +30,9 @@
 
 StreamStatistician::~StreamStatistician() {}
 
-StreamStatisticianImpl::StreamStatisticianImpl(
-    uint32_t ssrc,
-    Clock* clock,
-    int max_reordering_threshold,
-    StreamDataCountersCallback* rtp_callback)
+StreamStatisticianImpl::StreamStatisticianImpl(uint32_t ssrc,
+                                               Clock* clock,
+                                               int max_reordering_threshold)
     : ssrc_(ssrc),
       clock_(clock),
       incoming_bitrate_(kStatisticsProcessIntervalMs,
@@ -49,15 +47,12 @@
       received_seq_max_(-1),
       last_report_inorder_packets_(0),
       last_report_old_packets_(0),
-      last_report_seq_max_(-1),
-      rtp_callback_(rtp_callback) {}
+      last_report_seq_max_(-1) {}
 
 StreamStatisticianImpl::~StreamStatisticianImpl() = default;
 
 void StreamStatisticianImpl::OnRtpPacket(const RtpPacketReceived& packet) {
-  StreamDataCounters counters = UpdateCounters(packet);
-  if (rtp_callback_)
-    rtp_callback_->DataCountersUpdated(counters, ssrc_);
+  UpdateCounters(packet);
 }
 
 bool StreamStatisticianImpl::UpdateOutOfOrder(const RtpPacketReceived& packet,
@@ -156,14 +151,8 @@
 
 void StreamStatisticianImpl::FecPacketReceived(
     const RtpPacketReceived& packet) {
-  StreamDataCounters counters;
-  {
-    rtc::CritScope cs(&stream_lock_);
-    receive_counters_.fec.AddPacket(packet);
-    counters = receive_counters_;
-  }
-  if (rtp_callback_)
-    rtp_callback_->DataCountersUpdated(counters, ssrc_);
+  rtc::CritScope cs(&stream_lock_);
+  receive_counters_.fec.AddPacket(packet);
 }
 
 void StreamStatisticianImpl::SetMaxReorderingThreshold(
@@ -332,10 +321,15 @@
   return time_diff_ms > rtp_time_stamp_diff_ms + max_delay_ms;
 }
 
+std::unique_ptr<ReceiveStatistics> ReceiveStatistics::Create(Clock* clock) {
+  return absl::make_unique<ReceiveStatisticsImpl>(clock);
+}
+
 std::unique_ptr<ReceiveStatistics> ReceiveStatistics::Create(
     Clock* clock,
     StreamDataCountersCallback* rtp_callback) {
-  return absl::make_unique<ReceiveStatisticsImpl>(clock, rtp_callback);
+  RTC_CHECK(rtp_callback == nullptr);
+  return Create(clock);
 }
 
 std::unique_ptr<ReceiveStatistics> ReceiveStatistics::Create(
@@ -343,16 +337,14 @@
     RtcpStatisticsCallback* rtcp_callback,
     StreamDataCountersCallback* rtp_callback) {
   RTC_CHECK(rtcp_callback == nullptr);
-  return Create(clock, rtp_callback);
+  RTC_CHECK(rtp_callback == nullptr);
+  return Create(clock);
 }
 
-ReceiveStatisticsImpl::ReceiveStatisticsImpl(
-    Clock* clock,
-    StreamDataCountersCallback* rtp_callback)
+ReceiveStatisticsImpl::ReceiveStatisticsImpl(Clock* clock)
     : clock_(clock),
       last_returned_ssrc_(0),
-      max_reordering_threshold_(kDefaultMaxReorderingThreshold),
-      rtp_stats_callback_(rtp_callback) {}
+      max_reordering_threshold_(kDefaultMaxReorderingThreshold) {}
 
 ReceiveStatisticsImpl::~ReceiveStatisticsImpl() {
   while (!statisticians_.empty()) {
@@ -391,8 +383,7 @@
   rtc::CritScope cs(&receive_statistics_lock_);
   StreamStatisticianImpl*& impl = statisticians_[ssrc];
   if (impl == nullptr) {  // new element
-    impl = new StreamStatisticianImpl(ssrc, clock_, max_reordering_threshold_,
-                                      rtp_stats_callback_);
+    impl = new StreamStatisticianImpl(ssrc, clock_, max_reordering_threshold_);
   }
   return impl;
 }
diff --git a/modules/rtp_rtcp/source/receive_statistics_impl.h b/modules/rtp_rtcp/source/receive_statistics_impl.h
index c49fd11..04030d4 100644
--- a/modules/rtp_rtcp/source/receive_statistics_impl.h
+++ b/modules/rtp_rtcp/source/receive_statistics_impl.h
@@ -29,8 +29,7 @@
  public:
   StreamStatisticianImpl(uint32_t ssrc,
                          Clock* clock,
-                         int max_reordering_threshold,
-                         StreamDataCountersCallback* rtp_callback);
+                         int max_reordering_threshold);
   ~StreamStatisticianImpl() override;
 
   // |reset| here and in next method restarts calculation of fraction_lost stat.
@@ -98,15 +97,11 @@
   uint32_t last_report_old_packets_ RTC_GUARDED_BY(&stream_lock_);
   int64_t last_report_seq_max_ RTC_GUARDED_BY(&stream_lock_);
   RtcpStatistics last_reported_statistics_ RTC_GUARDED_BY(&stream_lock_);
-
-  // stream_lock_ shouldn't be held when calling callbacks.
-  StreamDataCountersCallback* const rtp_callback_;
 };
 
 class ReceiveStatisticsImpl : public ReceiveStatistics {
  public:
-  ReceiveStatisticsImpl(Clock* clock,
-                        StreamDataCountersCallback* rtp_callback);
+  explicit ReceiveStatisticsImpl(Clock* clock);
 
   ~ReceiveStatisticsImpl() override;
 
@@ -134,8 +129,6 @@
   int max_reordering_threshold_ RTC_GUARDED_BY(receive_statistics_lock_);
   std::map<uint32_t, StreamStatisticianImpl*> statisticians_
       RTC_GUARDED_BY(receive_statistics_lock_);
-
-  StreamDataCountersCallback* const rtp_stats_callback_;
 };
 }  // namespace webrtc
 #endif  // MODULES_RTP_RTCP_SOURCE_RECEIVE_STATISTICS_IMPL_H_
diff --git a/modules/rtp_rtcp/source/receive_statistics_unittest.cc b/modules/rtp_rtcp/source/receive_statistics_unittest.cc
index 8b08ce4..44e53cf 100644
--- a/modules/rtp_rtcp/source/receive_statistics_unittest.cc
+++ b/modules/rtp_rtcp/source/receive_statistics_unittest.cc
@@ -68,8 +68,7 @@
 class ReceiveStatisticsTest : public ::testing::Test {
  public:
   ReceiveStatisticsTest()
-      : clock_(0),
-        receive_statistics_(ReceiveStatistics::Create(&clock_, nullptr)) {
+      : clock_(0), receive_statistics_(ReceiveStatistics::Create(&clock_)) {
     packet1_ = CreateRtpPacket(kSsrc1, kPacketSize1);
     packet2_ = CreateRtpPacket(kSsrc2, kPacketSize2);
   }
@@ -460,45 +459,8 @@
   EXPECT_EQ(0x20001u, statistics.extended_highest_sequence_number);
 }
 
-class RtpTestCallback : public StreamDataCountersCallback {
- public:
-  RtpTestCallback()
-      : StreamDataCountersCallback(), num_calls_(0), ssrc_(0), stats_() {}
-  ~RtpTestCallback() override = default;
-
-  void DataCountersUpdated(const StreamDataCounters& counters,
-                           uint32_t ssrc) override {
-    ssrc_ = ssrc;
-    stats_ = counters;
-    ++num_calls_;
-  }
-
-  void MatchPacketCounter(const RtpPacketCounter& expected,
-                          const RtpPacketCounter& actual) {
-    EXPECT_EQ(expected.payload_bytes, actual.payload_bytes);
-    EXPECT_EQ(expected.header_bytes, actual.header_bytes);
-    EXPECT_EQ(expected.padding_bytes, actual.padding_bytes);
-    EXPECT_EQ(expected.packets, actual.packets);
-  }
-
-  void Matches(uint32_t num_calls,
-               uint32_t ssrc,
-               const StreamDataCounters& expected) {
-    EXPECT_EQ(num_calls, num_calls_);
-    EXPECT_EQ(ssrc, ssrc_);
-    MatchPacketCounter(expected.transmitted, stats_.transmitted);
-    MatchPacketCounter(expected.retransmitted, stats_.retransmitted);
-    MatchPacketCounter(expected.fec, stats_.fec);
-  }
-
-  uint32_t num_calls_;
-  uint32_t ssrc_;
-  StreamDataCounters stats_;
-};
-
-TEST_F(ReceiveStatisticsTest, RtpCallbacks) {
-  RtpTestCallback callback;
-  receive_statistics_ = ReceiveStatistics::Create(&clock_, &callback);
+TEST_F(ReceiveStatisticsTest, StreamDataCounters) {
+  receive_statistics_ = ReceiveStatistics::Create(&clock_);
   receive_statistics_->EnableRetransmitDetection(kSsrc1, true);
 
   const size_t kHeaderLength = 20;
@@ -508,17 +470,17 @@
   RtpPacketReceived packet1 =
       CreateRtpPacket(kSsrc1, kHeaderLength, kPacketSize1, 0);
   receive_statistics_->OnRtpPacket(packet1);
-  StreamDataCounters expected;
-  expected.transmitted.payload_bytes = kPacketSize1;
-  expected.transmitted.header_bytes = kHeaderLength;
-  expected.transmitted.padding_bytes = 0;
-  expected.transmitted.packets = 1;
-  expected.retransmitted.payload_bytes = 0;
-  expected.retransmitted.header_bytes = 0;
-  expected.retransmitted.padding_bytes = 0;
-  expected.retransmitted.packets = 0;
-  expected.fec.packets = 0;
-  callback.Matches(1, kSsrc1, expected);
+  StreamDataCounters counters = receive_statistics_->GetStatistician(kSsrc1)
+                                    ->GetReceiveStreamDataCounters();
+  EXPECT_EQ(counters.transmitted.payload_bytes, kPacketSize1);
+  EXPECT_EQ(counters.transmitted.header_bytes, kHeaderLength);
+  EXPECT_EQ(counters.transmitted.padding_bytes, 0u);
+  EXPECT_EQ(counters.transmitted.packets, 1u);
+  EXPECT_EQ(counters.retransmitted.payload_bytes, 0u);
+  EXPECT_EQ(counters.retransmitted.header_bytes, 0u);
+  EXPECT_EQ(counters.retransmitted.padding_bytes, 0u);
+  EXPECT_EQ(counters.retransmitted.packets, 0u);
+  EXPECT_EQ(counters.fec.packets, 0u);
 
   // Another packet of size kPacketSize1 with 9 bytes padding.
   RtpPacketReceived packet2 =
@@ -526,77 +488,89 @@
   packet2.SetSequenceNumber(packet1.SequenceNumber() + 1);
   clock_.AdvanceTimeMilliseconds(5);
   receive_statistics_->OnRtpPacket(packet2);
-  expected.transmitted.payload_bytes = kPacketSize1 * 2;
-  expected.transmitted.header_bytes = kHeaderLength * 2;
-  expected.transmitted.padding_bytes = kPaddingLength;
-  expected.transmitted.packets = 2;
-  callback.Matches(2, kSsrc1, expected);
+  counters = receive_statistics_->GetStatistician(kSsrc1)
+                 ->GetReceiveStreamDataCounters();
+  EXPECT_EQ(counters.transmitted.payload_bytes, kPacketSize1 * 2);
+  EXPECT_EQ(counters.transmitted.header_bytes, kHeaderLength * 2);
+  EXPECT_EQ(counters.transmitted.padding_bytes, kPaddingLength);
+  EXPECT_EQ(counters.transmitted.packets, 2u);
 
   clock_.AdvanceTimeMilliseconds(5);
   // Retransmit last packet.
   receive_statistics_->OnRtpPacket(packet2);
-  expected.transmitted.payload_bytes = kPacketSize1 * 3;
-  expected.transmitted.header_bytes = kHeaderLength * 3;
-  expected.transmitted.padding_bytes = kPaddingLength * 2;
-  expected.transmitted.packets = 3;
-  expected.retransmitted.payload_bytes = kPacketSize1;
-  expected.retransmitted.header_bytes = kHeaderLength;
-  expected.retransmitted.padding_bytes = kPaddingLength;
-  expected.retransmitted.packets = 1;
-  callback.Matches(3, kSsrc1, expected);
+  counters = receive_statistics_->GetStatistician(kSsrc1)
+                 ->GetReceiveStreamDataCounters();
+  EXPECT_EQ(counters.transmitted.payload_bytes, kPacketSize1 * 3);
+  EXPECT_EQ(counters.transmitted.header_bytes, kHeaderLength * 3);
+  EXPECT_EQ(counters.transmitted.padding_bytes, kPaddingLength * 2);
+  EXPECT_EQ(counters.transmitted.packets, 3u);
+  EXPECT_EQ(counters.retransmitted.payload_bytes, kPacketSize1);
+  EXPECT_EQ(counters.retransmitted.header_bytes, kHeaderLength);
+  EXPECT_EQ(counters.retransmitted.padding_bytes, kPaddingLength);
+  EXPECT_EQ(counters.retransmitted.packets, 1u);
 
   // One FEC packet.
   packet1.SetSequenceNumber(packet2.SequenceNumber() + 1);
   clock_.AdvanceTimeMilliseconds(5);
   receive_statistics_->OnRtpPacket(packet1);
   receive_statistics_->FecPacketReceived(packet1);
-  expected.transmitted.payload_bytes = kPacketSize1 * 4;
-  expected.transmitted.header_bytes = kHeaderLength * 4;
-  expected.transmitted.packets = 4;
-  expected.fec.payload_bytes = kPacketSize1;
-  expected.fec.header_bytes = kHeaderLength;
-  expected.fec.packets = 1;
-  callback.Matches(5, kSsrc1, expected);
+  counters = receive_statistics_->GetStatistician(kSsrc1)
+                 ->GetReceiveStreamDataCounters();
+  EXPECT_EQ(counters.transmitted.payload_bytes, kPacketSize1 * 4);
+  EXPECT_EQ(counters.transmitted.header_bytes, kHeaderLength * 4);
+  EXPECT_EQ(counters.transmitted.packets, 4u);
+  EXPECT_EQ(counters.fec.payload_bytes, kPacketSize1);
+  EXPECT_EQ(counters.fec.header_bytes, kHeaderLength);
+  EXPECT_EQ(counters.fec.packets, 1u);
 }
 
 TEST_F(ReceiveStatisticsTest, LastPacketReceivedTimestamp) {
-  RtpTestCallback callback;
-  receive_statistics_ = ReceiveStatistics::Create(&clock_, &callback);
+  receive_statistics_ = ReceiveStatistics::Create(&clock_);
 
   clock_.AdvanceTimeMilliseconds(42);
   receive_statistics_->OnRtpPacket(packet1_);
-  EXPECT_EQ(42, callback.stats_.last_packet_received_timestamp_ms);
+  StreamDataCounters counters = receive_statistics_->GetStatistician(kSsrc1)
+                                    ->GetReceiveStreamDataCounters();
+
+  EXPECT_EQ(42, counters.last_packet_received_timestamp_ms);
 
   clock_.AdvanceTimeMilliseconds(3);
   receive_statistics_->OnRtpPacket(packet1_);
-  EXPECT_EQ(45, callback.stats_.last_packet_received_timestamp_ms);
+  counters = receive_statistics_->GetStatistician(kSsrc1)
+                 ->GetReceiveStreamDataCounters();
+  EXPECT_EQ(45, counters.last_packet_received_timestamp_ms);
 }
 
-TEST_F(ReceiveStatisticsTest, RtpCallbacksFecFirst) {
-  RtpTestCallback callback;
-  receive_statistics_ = ReceiveStatistics::Create(&clock_, &callback);
+TEST_F(ReceiveStatisticsTest, FecFirst) {
+  receive_statistics_ = ReceiveStatistics::Create(&clock_);
 
   const uint32_t kHeaderLength = 20;
   RtpPacketReceived packet =
       CreateRtpPacket(kSsrc1, kHeaderLength, kPacketSize1, 0);
   // If first packet is FEC, ignore it.
   receive_statistics_->FecPacketReceived(packet);
-  EXPECT_EQ(0u, callback.num_calls_);
+
+  EXPECT_EQ(receive_statistics_->GetStatistician(kSsrc1), nullptr);
 
   receive_statistics_->OnRtpPacket(packet);
-  StreamDataCounters expected;
-  expected.transmitted.payload_bytes = kPacketSize1;
-  expected.transmitted.header_bytes = kHeaderLength;
-  expected.transmitted.padding_bytes = 0;
-  expected.transmitted.packets = 1;
-  expected.fec.packets = 0;
-  callback.Matches(1, kSsrc1, expected);
+  StreamDataCounters counters = receive_statistics_->GetStatistician(kSsrc1)
+                                    ->GetReceiveStreamDataCounters();
+  EXPECT_EQ(counters.transmitted.payload_bytes, kPacketSize1);
+  EXPECT_EQ(counters.transmitted.header_bytes, kHeaderLength);
+  EXPECT_EQ(counters.transmitted.padding_bytes, 0u);
+  EXPECT_EQ(counters.transmitted.packets, 1u);
+  EXPECT_EQ(counters.fec.packets, 0u);
 
   receive_statistics_->FecPacketReceived(packet);
-  expected.fec.payload_bytes = kPacketSize1;
-  expected.fec.header_bytes = kHeaderLength;
-  expected.fec.packets = 1;
-  callback.Matches(2, kSsrc1, expected);
+  counters = receive_statistics_->GetStatistician(kSsrc1)
+                 ->GetReceiveStreamDataCounters();
+  EXPECT_EQ(counters.transmitted.payload_bytes, kPacketSize1);
+  EXPECT_EQ(counters.transmitted.header_bytes, kHeaderLength);
+  EXPECT_EQ(counters.transmitted.padding_bytes, 0u);
+  EXPECT_EQ(counters.transmitted.packets, 1u);
+  EXPECT_EQ(counters.fec.payload_bytes, kPacketSize1);
+  EXPECT_EQ(counters.fec.header_bytes, kHeaderLength);
+  EXPECT_EQ(counters.fec.packets, 1u);
 }
 
 }  // namespace
diff --git a/video/receive_statistics_proxy.cc b/video/receive_statistics_proxy.cc
index aaeed1b..4359b5d 100644
--- a/video/receive_statistics_proxy.cc
+++ b/video/receive_statistics_proxy.cc
@@ -118,15 +118,12 @@
   decode_thread_.Detach();
   network_thread_.Detach();
   stats_.ssrc = config_.rtp.remote_ssrc;
-  // TODO(brandtr): Replace |rtx_stats_| with a single instance of
-  // StreamDataCounters.
-  if (config_.rtp.rtx_ssrc) {
-    rtx_stats_[config_.rtp.rtx_ssrc] = StreamDataCounters();
-  }
 }
 
 void ReceiveStatisticsProxy::UpdateHistograms(
-    absl::optional<int> fraction_lost) {
+    absl::optional<int> fraction_lost,
+    const StreamDataCounters& rtp_stats,
+    const StreamDataCounters* rtx_stats) {
   // Not actually running on the decoder thread, but must be called after
   // DecoderThreadStopped, which detaches the thread checker. It is therefore
   // safe to access |qp_counters_|, which were updated on the decode thread
@@ -404,42 +401,42 @@
     }
   }
 
-  StreamDataCounters rtp = stats_.rtp_stats;
-  StreamDataCounters rtx;
-  for (auto it : rtx_stats_)
-    rtx.Add(it.second);
-  StreamDataCounters rtp_rtx = rtp;
-  rtp_rtx.Add(rtx);
+  StreamDataCounters rtp_rtx_stats = rtp_stats;
+  if (rtx_stats)
+    rtp_rtx_stats.Add(*rtx_stats);
   int64_t elapsed_sec =
-      rtp_rtx.TimeSinceFirstPacketInMs(clock_->TimeInMilliseconds()) / 1000;
+      rtp_rtx_stats.TimeSinceFirstPacketInMs(clock_->TimeInMilliseconds()) /
+      1000;
   if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
     RTC_HISTOGRAM_COUNTS_10000(
         "WebRTC.Video.BitrateReceivedInKbps",
-        static_cast<int>(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
-                         1000));
-    int media_bitrate_kbs =
-        static_cast<int>(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000);
+        static_cast<int>(rtp_rtx_stats.transmitted.TotalBytes() * 8 /
+                         elapsed_sec / 1000));
+    int media_bitrate_kbs = static_cast<int>(rtp_stats.MediaPayloadBytes() * 8 /
+                                             elapsed_sec / 1000);
     RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.MediaBitrateReceivedInKbps",
                                media_bitrate_kbs);
     log_stream << "WebRTC.Video.MediaBitrateReceivedInKbps "
                << media_bitrate_kbs << '\n';
     RTC_HISTOGRAM_COUNTS_10000(
         "WebRTC.Video.PaddingBitrateReceivedInKbps",
-        static_cast<int>(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec /
-                         1000));
+        static_cast<int>(rtp_rtx_stats.transmitted.padding_bytes * 8 /
+                         elapsed_sec / 1000));
     RTC_HISTOGRAM_COUNTS_10000(
         "WebRTC.Video.RetransmittedBitrateReceivedInKbps",
-        static_cast<int>(rtp_rtx.retransmitted.TotalBytes() * 8 / elapsed_sec /
-                         1000));
-    if (!rtx_stats_.empty()) {
-      RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtxBitrateReceivedInKbps",
-                                 static_cast<int>(rtx.transmitted.TotalBytes() *
-                                                  8 / elapsed_sec / 1000));
+        static_cast<int>(rtp_rtx_stats.retransmitted.TotalBytes() * 8 /
+                         elapsed_sec / 1000));
+    if (rtx_stats) {
+      RTC_HISTOGRAM_COUNTS_10000(
+          "WebRTC.Video.RtxBitrateReceivedInKbps",
+          static_cast<int>(rtx_stats->transmitted.TotalBytes() * 8 /
+                           elapsed_sec / 1000));
     }
     if (config_.rtp.ulpfec_payload_type != -1) {
       RTC_HISTOGRAM_COUNTS_10000(
           "WebRTC.Video.FecBitrateReceivedInKbps",
-          static_cast<int>(rtp_rtx.fec.TotalBytes() * 8 / elapsed_sec / 1000));
+          static_cast<int>(rtp_rtx_stats.fec.TotalBytes() * 8 / elapsed_sec /
+                           1000));
     }
     const RtcpPacketTypeCounter& counters = stats_.rtcp_packet_type_counts;
     RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.NackPacketsSentPerMinute",
@@ -667,22 +664,6 @@
   stats_.c_name = std::string(cname);
 }
 
-void ReceiveStatisticsProxy::DataCountersUpdated(
-    const webrtc::StreamDataCounters& counters,
-    uint32_t ssrc) {
-  rtc::CritScope lock(&crit_);
-  if (ssrc == stats_.ssrc) {
-    stats_.rtp_stats = counters;
-  } else {
-    auto it = rtx_stats_.find(ssrc);
-    if (it != rtx_stats_.end()) {
-      it->second = counters;
-    } else {
-      RTC_NOTREACHED() << "Unexpected stream ssrc: " << ssrc;
-    }
-  }
-}
-
 void ReceiveStatisticsProxy::OnDecodedFrame(const VideoFrame& frame,
                                             absl::optional<uint8_t> qp,
                                             int32_t decode_time_ms,
diff --git a/video/receive_statistics_proxy.h b/video/receive_statistics_proxy.h
index fe93030..f1a9f1e 100644
--- a/video/receive_statistics_proxy.h
+++ b/video/receive_statistics_proxy.h
@@ -39,7 +39,6 @@
 class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback,
                                public RtcpCnameCallback,
                                public RtcpPacketTypeCounterObserver,
-                               public StreamDataCountersCallback,
                                public CallStatsObserver {
  public:
   ReceiveStatisticsProxy(const VideoReceiveStream::Config* config,
@@ -84,9 +83,6 @@
   void RtcpPacketTypesCounterUpdated(
       uint32_t ssrc,
       const RtcpPacketTypeCounter& packet_counter) override;
-  // Overrides StreamDataCountersCallback.
-  void DataCountersUpdated(const webrtc::StreamDataCounters& counters,
-                           uint32_t ssrc) override;
 
   // Implements CallStatsObserver.
   void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) override;
@@ -98,7 +94,9 @@
 
   // Produce histograms. Must be called after DecoderThreadStopped(), typically
   // at the end of the call.
-  void UpdateHistograms(absl::optional<int> fraction_lost);
+  void UpdateHistograms(absl::optional<int> fraction_lost,
+                        const StreamDataCounters& rtp_stats,
+                        const StreamDataCounters* rtx_stats);
 
  private:
   struct QpCounters {
@@ -147,6 +145,7 @@
   rtc::SampleCounter qp_sample_ RTC_GUARDED_BY(crit_);
   int num_bad_states_ RTC_GUARDED_BY(crit_);
   int num_certain_states_ RTC_GUARDED_BY(crit_);
+  // Note: The |stats_.rtp_stats| member is not used or populated by this class.
   mutable VideoReceiveStream::Stats stats_ RTC_GUARDED_BY(crit_);
   RateStatistics decode_fps_estimator_ RTC_GUARDED_BY(crit_);
   RateStatistics renders_fps_estimator_ RTC_GUARDED_BY(crit_);
@@ -166,7 +165,6 @@
       RTC_GUARDED_BY(crit_);
   MaxCounter freq_offset_counter_ RTC_GUARDED_BY(crit_);
   QpCounters qp_counters_ RTC_GUARDED_BY(decode_thread_);
-  std::map<uint32_t, StreamDataCounters> rtx_stats_ RTC_GUARDED_BY(crit_);
   int64_t avg_rtt_ms_ RTC_GUARDED_BY(crit_);
   mutable std::map<int64_t, size_t> frame_window_ RTC_GUARDED_BY(&crit_);
   VideoContentType last_content_type_ RTC_GUARDED_BY(&crit_);
diff --git a/video/receive_statistics_proxy_unittest.cc b/video/receive_statistics_proxy_unittest.cc
index 5a6a0ef..9834b3e 100644
--- a/video/receive_statistics_proxy_unittest.cc
+++ b/video/receive_statistics_proxy_unittest.cc
@@ -53,12 +53,6 @@
     return config;
   }
 
-  void InsertFirstRtpPacket(uint32_t ssrc) {
-    StreamDataCounters counters;
-    counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
-    statistics_proxy_->DataCountersUpdated(counters, ssrc);
-  }
-
   VideoFrame CreateFrame(int width, int height) {
     return CreateVideoFrame(width, height, 0);
   }
@@ -103,7 +97,8 @@
                                       VideoContentType::UNSPECIFIED);
     fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
   }
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.DecodedFramesPerSecond"));
   EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.DecodedFramesPerSecond", kFps));
 }
@@ -117,7 +112,8 @@
                                       VideoContentType::UNSPECIFIED);
     fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
   }
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.DecodedFramesPerSecond"));
 }
 
@@ -525,7 +521,8 @@
   fake_clock_.AdvanceTimeMilliseconds(kTimeSec * 1000);
   // Need at least one frame to report stream lifetime.
   statistics_proxy_->OnCompleteFrame(true, 1000, VideoContentType::UNSPECIFIED);
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(1,
             metrics::NumSamples("WebRTC.Video.ReceiveStreamLifetimeInSeconds"));
   EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.ReceiveStreamLifetimeInSeconds",
@@ -537,7 +534,8 @@
   const int64_t kTimeSec = 3;
   fake_clock_.AdvanceTimeMilliseconds(kTimeSec * 1000);
   // No frames received.
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(0,
             metrics::NumSamples("WebRTC.Video.ReceiveStreamLifetimeInSeconds"));
 }
@@ -552,7 +550,6 @@
 
   StreamDataCounters counters;
   counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
-  statistics_proxy_->DataCountersUpdated(counters, config_.rtp.remote_ssrc);
 
   webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
 
@@ -560,7 +557,7 @@
     fake_clock_.AdvanceTimeMilliseconds(kBadFameIntervalMs);
     statistics_proxy_->OnRenderedFrame(frame);
   }
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, counters, nullptr);
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.BadCall.Any"));
   EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.BadCall.Any", 100));
 
@@ -573,7 +570,7 @@
 }
 
 TEST_F(ReceiveStatisticsProxyTest, PacketLossHistogramIsUpdated) {
-  statistics_proxy_->UpdateHistograms(10);
+  statistics_proxy_->UpdateHistograms(10, StreamDataCounters(), nullptr);
   EXPECT_EQ(0,
             metrics::NumSamples("WebRTC.Video.ReceivedPacketsLostInPercent"));
 
@@ -582,7 +579,7 @@
 
   // Min run time has passed.
   fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
-  statistics_proxy_->UpdateHistograms(10);
+  statistics_proxy_->UpdateHistograms(10, StreamDataCounters(), nullptr);
   EXPECT_EQ(1,
             metrics::NumSamples("WebRTC.Video.ReceivedPacketsLostInPercent"));
   EXPECT_EQ(
@@ -603,7 +600,8 @@
   const double kFreqKhz = 90.0;
   for (int i = 0; i < kMinRequiredSamples; ++i)
     statistics_proxy_->OnSyncOffsetUpdated(kSyncOffsetMs, kFreqKhz);
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AVSyncOffsetInMs"));
   EXPECT_EQ(1,
             metrics::NumEvents("WebRTC.Video.AVSyncOffsetInMs", kSyncOffsetMs));
@@ -622,7 +620,8 @@
   fake_clock_.AdvanceTimeMilliseconds(kFreqOffsetProcessIntervalInMs);
   // Process interval passed, max diff: 4.
   statistics_proxy_->OnSyncOffsetUpdated(kSyncOffsetMs, kFreqKhz);
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   // Average reported: (2 + 4) / 2 = 3.
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.RtpToNtpFreqOffsetInKhz"));
   EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.RtpToNtpFreqOffsetInKhz", 3));
@@ -634,7 +633,8 @@
   for (int i = 0; i < kMinRequiredSamples; ++i)
     statistics_proxy_->OnPreDecode(kVideoCodecVP8, kQp);
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Decoded.Vp8.Qp"));
   EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.Decoded.Vp8.Qp", kQp));
 }
@@ -645,7 +645,8 @@
   for (int i = 0; i < kMinRequiredSamples - 1; ++i)
     statistics_proxy_->OnPreDecode(kVideoCodecVP8, kQp);
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.Decoded.Vp8.Qp"));
 }
 
@@ -653,7 +654,8 @@
   for (int i = 0; i < kMinRequiredSamples; ++i)
     statistics_proxy_->OnPreDecode(kVideoCodecVP8, -1);
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.Decoded.Vp8.Qp"));
 }
 
@@ -670,7 +672,8 @@
   EXPECT_EQ(kMinRequiredSamples - 1,
             statistics_proxy_->GetStats().frame_counts.delta_frames);
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.KeyFramesReceivedInPermille"));
 }
 
@@ -687,7 +690,8 @@
   EXPECT_EQ(kMinRequiredSamples,
             statistics_proxy_->GetStats().frame_counts.delta_frames);
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.KeyFramesReceivedInPermille"));
   EXPECT_EQ(1,
             metrics::NumEvents("WebRTC.Video.KeyFramesReceivedInPermille", 0));
@@ -709,7 +713,8 @@
   EXPECT_EQ(kMinRequiredSamples,
             statistics_proxy_->GetStats().frame_counts.delta_frames);
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.KeyFramesReceivedInPermille"));
   EXPECT_EQ(
       1, metrics::NumEvents("WebRTC.Video.KeyFramesReceivedInPermille", 500));
@@ -729,7 +734,8 @@
         kMinPlayoutDelayMs, kRenderDelayMs);
   }
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.DecodeTimeInMs"));
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.JitterBufferDelayInMs"));
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.TargetDelayInMs"));
@@ -751,7 +757,8 @@
         kMinPlayoutDelayMs, kRenderDelayMs);
   }
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.JitterBufferDelayInMs"));
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.TargetDelayInMs"));
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.CurrentDelayInMs"));
@@ -807,7 +814,8 @@
   for (int i = 0; i < kMinRequiredSamples - 1; ++i)
     statistics_proxy_->OnRenderedFrame(CreateFrame(kWidth, kHeight));
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.ReceivedWidthInPixels"));
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.ReceivedHeightInPixels"));
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.RenderFramesPerSecond"));
@@ -818,7 +826,8 @@
   for (int i = 0; i < kMinRequiredSamples; ++i)
     statistics_proxy_->OnRenderedFrame(CreateFrame(kWidth, kHeight));
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.ReceivedWidthInPixels"));
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.ReceivedHeightInPixels"));
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.RenderFramesPerSecond"));
@@ -840,7 +849,8 @@
 
   // Min run time has passed.
   fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000));
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
   EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer", 0));
   EXPECT_EQ(0, metrics::NumSamples(
@@ -860,7 +870,8 @@
   // Min run time has not passed.
   fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000) -
                                       1);
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
   EXPECT_EQ(0, metrics::NumSamples(
                    "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
@@ -874,7 +885,8 @@
 
   // Min run time has passed. No rendered frames.
   fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000));
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
   EXPECT_EQ(0, metrics::NumSamples(
                    "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
@@ -891,7 +903,8 @@
 
   // Min run time has passed.
   fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000));
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
   EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer", 100));
   EXPECT_EQ(1, metrics::NumSamples(
@@ -914,7 +927,8 @@
 
   // Min run time has passed.
   fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000));
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
   EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer", 50));
   EXPECT_EQ(1, metrics::NumSamples(
@@ -925,21 +939,24 @@
 
 TEST_F(ReceiveStatisticsProxyTest,
        RtcpHistogramsNotUpdatedIfMinRuntimeHasNotPassed) {
-  InsertFirstRtpPacket(kRemoteSsrc);
+  StreamDataCounters data_counters;
+  data_counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
+
   fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000) -
                                       1);
 
   RtcpPacketTypeCounter counter;
   statistics_proxy_->RtcpPacketTypesCounterUpdated(kRemoteSsrc, counter);
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, data_counters, nullptr);
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.FirPacketsSentPerMinute"));
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.PliPacketsSentPerMinute"));
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.NackPacketsSentPerMinute"));
 }
 
 TEST_F(ReceiveStatisticsProxyTest, RtcpHistogramsAreUpdated) {
-  InsertFirstRtpPacket(kRemoteSsrc);
+  StreamDataCounters data_counters;
+  data_counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
   fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
 
   const uint32_t kFirPackets = 100;
@@ -952,7 +969,7 @@
   counter.nack_packets = kNackPackets;
   statistics_proxy_->RtcpPacketTypesCounterUpdated(kRemoteSsrc, counter);
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, data_counters, nullptr);
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.FirPacketsSentPerMinute"));
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.PliPacketsSentPerMinute"));
   EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.NackPacketsSentPerMinute"));
@@ -1044,7 +1061,8 @@
   fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
   statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   const int kExpectedInterFrame =
       (kInterFrameDelayMs * (kMinRequiredSamples - 1) +
        kInterFrameDelayMs * 2) /
@@ -1083,7 +1101,8 @@
   fake_clock_.AdvanceTimeMilliseconds(10 * kInterFrameDelayMs);
   statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   const int kExpectedInterFrame = kInterFrameDelayMs * 2;
   if (videocontenttypehelpers::IsScreenshare(content_type_)) {
     EXPECT_EQ(kExpectedInterFrame,
@@ -1108,7 +1127,8 @@
 
   // |kMinRequiredSamples| samples, and thereby intervals, is required. That
   // means we're one frame short of having a valid data set.
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.InterframeDelayInMs"));
   EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs"));
   EXPECT_EQ(
@@ -1137,7 +1157,8 @@
   fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
   statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   if (videocontenttypehelpers::IsScreenshare(content_type_)) {
     EXPECT_EQ(
         1, metrics::NumSamples("WebRTC.Video.Screenshare.InterframeDelayInMs"));
@@ -1176,7 +1197,8 @@
   statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
   statistics_proxy_->OnRenderedFrame(frame);
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   const int kExpectedTimeBetweenFreezes =
       kInterFrameDelayMs * (kMinRequiredSamples - 1);
   const int kExpectedNumberFreezesPerMinute = 60 * 1000 / kCallDurationMs;
@@ -1226,7 +1248,8 @@
   statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
   statistics_proxy_->OnRenderedFrame(frame);
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   double kSumSquaredFrameDurationSecs =
       (kMinRequiredSamples - 1) *
       (kFrameDurationMs / 1000.0 * kFrameDurationMs / 1000.0);
@@ -1266,7 +1289,8 @@
     fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
   }
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   // Average of two playback intervals.
   const int kExpectedTimeBetweenFreezes =
       kInterFrameDelayMs * kMinRequiredSamples * 2;
@@ -1299,7 +1323,8 @@
     fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
   }
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   // No freezes should be detected, as all long inter-frame delays were pauses.
   if (videocontenttypehelpers::IsScreenshare(content_type_)) {
     EXPECT_EQ(-1, metrics::MinSample(
@@ -1331,7 +1356,8 @@
   // Extra last frame.
   statistics_proxy_->OnRenderedFrame(frame_sd);
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   const int kExpectedTimeInHdPercents = 33;
   if (videocontenttypehelpers::IsScreenshare(content_type_)) {
     EXPECT_EQ(
@@ -1365,7 +1391,8 @@
   statistics_proxy_->OnDecodedFrame(frame, kHighQp, 0, content_type_);
   statistics_proxy_->OnRenderedFrame(frame);
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   const int kExpectedTimeInHdPercents = 66;
   if (videocontenttypehelpers::IsScreenshare(content_type_)) {
     EXPECT_EQ(kExpectedTimeInHdPercents,
@@ -1398,7 +1425,8 @@
   statistics_proxy_->OnRenderedFrame(frame_ld);
   fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
 
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   const int kExpectedDownscales = 30;  // 2 per 4 seconds = 30 per minute.
   if (videocontenttypehelpers::IsScreenshare(content_type_)) {
     EXPECT_EQ(
@@ -1423,7 +1451,8 @@
     statistics_proxy_->OnDecodedFrame(frame, kLowQp, kDecodeMs, content_type_);
     fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
   }
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
   EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.DecodeTimeInMs", kDecodeMs));
 }
 
@@ -1447,7 +1476,8 @@
     fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs2);
     statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type);
   }
-  statistics_proxy_->UpdateHistograms(absl::nullopt);
+  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
+                                      nullptr);
 
   if (videocontenttypehelpers::IsScreenshare(content_type)) {
     EXPECT_EQ(
diff --git a/video/video_receive_stream.cc b/video/video_receive_stream.cc
index 3a50bc9..ef1ac85 100644
--- a/video/video_receive_stream.cc
+++ b/video/video_receive_stream.cc
@@ -193,7 +193,7 @@
       call_stats_(call_stats),
       source_tracker_(clock_),
       stats_proxy_(&config_, clock_),
-      rtp_receive_statistics_(ReceiveStatistics::Create(clock_, &stats_proxy_)),
+      rtp_receive_statistics_(ReceiveStatistics::Create(clock_)),
       timing_(timing),
       video_receiver_(clock_, timing_.get()),
       rtp_video_stream_receiver_(clock_,
@@ -464,6 +464,7 @@
       rtp_receive_statistics_->GetStatistician(stats.ssrc);
   if (statistician) {
     statistician->GetStatistics(&stats.rtcp_stats, /*reset=*/false);
+    stats.rtp_stats = statistician->GetReceiveStreamDataCounters();
     stats.total_bitrate_bps = statistician->BitrateReceived();
   }
   if (config_.rtp.rtx_ssrc) {
@@ -477,12 +478,24 @@
 
 void VideoReceiveStream::UpdateHistograms() {
   absl::optional<int> fraction_lost;
+  StreamDataCounters rtp_stats;
   StreamStatistician* statistician =
       rtp_receive_statistics_->GetStatistician(config_.rtp.remote_ssrc);
   if (statistician) {
     fraction_lost = statistician->GetFractionLostInPercent();
+    rtp_stats = statistician->GetReceiveStreamDataCounters();
   }
-  stats_proxy_.UpdateHistograms(fraction_lost);
+  if (config_.rtp.rtx_ssrc) {
+    StreamStatistician* rtx_statistician =
+        rtp_receive_statistics_->GetStatistician(config_.rtp.rtx_ssrc);
+    if (rtx_statistician) {
+      StreamDataCounters rtx_stats =
+          rtx_statistician->GetReceiveStreamDataCounters();
+      stats_proxy_.UpdateHistograms(fraction_lost, rtp_stats, &rtx_stats);
+      return;
+    }
+  }
+  stats_proxy_.UpdateHistograms(fraction_lost, rtp_stats, nullptr);
 }
 
 void VideoReceiveStream::AddSecondarySink(RtpPacketSinkInterface* sink) {