Refactors send rate statistics in RtpSenderEgress

When FEC generation is moved to egress, we'll need to poll bitrates from
there instead of the RtpVideoSender. In preparation, refactoring some
getter methods.

For context, see https://webrtc-review.googlesource.com/c/src/+/173708

Bug: webrtc:11340
Change-Id: Ibc27362361ee9640d9fce676fc8e1093a579344f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/174202
Commit-Queue: Erik Språng <sprang@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#31214}
diff --git a/call/rtp_video_sender.cc b/call/rtp_video_sender.cc
index ffe2d61..8c31a84 100644
--- a/call/rtp_video_sender.cc
+++ b/call/rtp_video_sender.cc
@@ -836,16 +836,14 @@
   *sent_nack_rate_bps = 0;
   *sent_fec_rate_bps = 0;
   for (const RtpStreamSender& stream : rtp_streams_) {
-    uint32_t not_used = 0;
-    uint32_t module_nack_rate = 0;
     if (stream.fec_generator) {
       stream.fec_generator->SetProtectionParameters(*delta_params, *key_params);
       *sent_fec_rate_bps += stream.fec_generator->CurrentFecRate().bps();
     }
     *sent_video_rate_bps += stream.sender_video->VideoBitrateSent();
-    stream.rtp_rtcp->BitrateSent(&not_used, /*video_rate=*/nullptr,
-                                 /*fec_rate=*/nullptr, &module_nack_rate);
-    *sent_nack_rate_bps += module_nack_rate;
+    *sent_nack_rate_bps +=
+        stream.rtp_rtcp->GetSendRates()[RtpPacketMediaType::kRetransmission]
+            .bps<uint32_t>();
   }
   return 0;
 }
diff --git a/modules/rtp_rtcp/include/rtp_rtcp.h b/modules/rtp_rtcp/include/rtp_rtcp.h
index 598c09e..f91f0d1 100644
--- a/modules/rtp_rtcp/include/rtp_rtcp.h
+++ b/modules/rtp_rtcp/include/rtp_rtcp.h
@@ -285,12 +285,16 @@
   // bitrate estimate since the stream participates in the bitrate allocation.
   virtual void SetAsPartOfAllocation(bool part_of_allocation) = 0;
 
-  // Fetches the current send bitrates in bits/s.
+  // TODO(sprang): Remove when all call sites have been moved to
+  // GetSendRates(). Fetches the current send bitrates in bits/s.
   virtual void BitrateSent(uint32_t* total_rate,
                            uint32_t* video_rate,
                            uint32_t* fec_rate,
                            uint32_t* nack_rate) const = 0;
 
+  // Returns bitrate sent (post-pacing) per packet type.
+  virtual RtpSendRates GetSendRates() const = 0;
+
   virtual RTPSender* RtpSender() = 0;
   virtual const RTPSender* RtpSender() const = 0;
 
diff --git a/modules/rtp_rtcp/include/rtp_rtcp_defines.h b/modules/rtp_rtcp/include/rtp_rtcp_defines.h
index 48bb842..049ff5c 100644
--- a/modules/rtp_rtcp/include/rtp_rtcp_defines.h
+++ b/modules/rtp_rtcp/include/rtp_rtcp_defines.h
@@ -17,6 +17,7 @@
 #include <memory>
 #include <vector>
 
+#include "absl/algorithm/container.h"
 #include "absl/strings/string_view.h"
 #include "absl/types/optional.h"
 #include "absl/types/variant.h"
@@ -211,12 +212,15 @@
   virtual ~RtcpBandwidthObserver() {}
 };
 
-enum class RtpPacketMediaType {
-  kAudio,                   // Audio media packets.
-  kVideo,                   // Video media packets.
-  kRetransmission,          // RTX (usually) packets send as response to NACK.
-  kForwardErrorCorrection,  // FEC packets.
-  kPadding                  // RTX or plain padding sent to maintain BWE.
+// NOTE! |kNumMediaTypes| must be kept in sync with RtpPacketMediaType!
+static constexpr size_t kNumMediaTypes = 5;
+enum class RtpPacketMediaType : size_t {
+  kAudio,                         // Audio media packets.
+  kVideo,                         // Video media packets.
+  kRetransmission,                // Retransmisions, sent as response to NACK.
+  kForwardErrorCorrection,        // FEC packets.
+  kPadding = kNumMediaTypes - 1,  // RTX or plain padding sent to maintain BWE.
+  // Again, don't forget to udate |kNumMediaTypes| if you add another value!
 };
 
 struct RtpPacketSendInfo {
@@ -382,6 +386,34 @@
   RtpPacketCounter fec;            // Number of redundancy packets/bytes.
 };
 
+class RtpSendRates {
+  template <std::size_t... Is>
+  constexpr std::array<DataRate, sizeof...(Is)> make_zero_array(
+      std::index_sequence<Is...>) {
+    return {{(static_cast<void>(Is), DataRate::Zero())...}};
+  }
+
+ public:
+  RtpSendRates()
+      : send_rates_(
+            make_zero_array(std::make_index_sequence<kNumMediaTypes>())) {}
+  RtpSendRates(const RtpSendRates& rhs) = default;
+  RtpSendRates& operator=(const RtpSendRates&) = default;
+
+  DataRate& operator[](RtpPacketMediaType type) {
+    return send_rates_[static_cast<size_t>(type)];
+  }
+  const DataRate& operator[](RtpPacketMediaType type) const {
+    return send_rates_[static_cast<size_t>(type)];
+  }
+  DataRate Sum() const {
+    return absl::c_accumulate(send_rates_, DataRate::Zero());
+  }
+
+ private:
+  std::array<DataRate, kNumMediaTypes> send_rates_;
+};
+
 // Callback, called whenever byte/packet counts have been updated.
 class StreamDataCountersCallback {
  public:
diff --git a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
index 4ad9820..5a333fe 100644
--- a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
+++ b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -95,6 +95,7 @@
                uint32_t* fec_rate,
                uint32_t* nack_rate),
               (const override));
+  MOCK_METHOD(RtpSendRates, GetSendRates, (), (const override));
   MOCK_METHOD(int,
               EstimatedReceiveBandwidth,
               (uint32_t * available_bandwidth),
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index 4f84b02..fb6f8a3 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -290,7 +290,7 @@
     state.media_bytes_sent = rtp_stats.transmitted.payload_bytes +
                              rtx_stats.transmitted.payload_bytes;
     state.send_bitrate =
-        rtp_sender_->packet_sender.SendBitrate().bps<uint32_t>();
+        rtp_sender_->packet_sender.GetSendRates().Sum().bps<uint32_t>();
   }
   state.module = this;
 
@@ -702,12 +702,17 @@
                                     uint32_t* video_rate,
                                     uint32_t* fec_rate,
                                     uint32_t* nack_rate) const {
-  *total_rate = rtp_sender_->packet_sender.SendBitrate().bps<uint32_t>();
+  RtpSendRates send_rates = rtp_sender_->packet_sender.GetSendRates();
+  *total_rate = send_rates.Sum().bps<uint32_t>();
   if (video_rate)
     *video_rate = 0;
   if (fec_rate)
     *fec_rate = 0;
-  *nack_rate = rtp_sender_->packet_sender.NackOverheadRate().bps<uint32_t>();
+  *nack_rate = send_rates[RtpPacketMediaType::kRetransmission].bps<uint32_t>();
+}
+
+RtpSendRates ModuleRtpRtcpImpl::GetSendRates() const {
+  return rtp_sender_->packet_sender.GetSendRates();
 }
 
 void ModuleRtpRtcpImpl::OnRequestSendReport() {
@@ -803,12 +808,13 @@
 
 DataRate ModuleRtpRtcpImpl::SendRate() const {
   RTC_DCHECK(rtp_sender_);
-  return rtp_sender_->packet_sender.SendBitrate();
+  return rtp_sender_->packet_sender.GetSendRates().Sum();
 }
 
 DataRate ModuleRtpRtcpImpl::NackOverheadRate() const {
   RTC_DCHECK(rtp_sender_);
-  return rtp_sender_->packet_sender.NackOverheadRate();
+  return rtp_sender_->packet_sender
+      .GetSendRates()[RtpPacketMediaType::kRetransmission];
 }
 
 }  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index 8bda0e0..debb433 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -264,6 +264,8 @@
                    uint32_t* fec_rate,
                    uint32_t* nackRate) const override;
 
+  RtpSendRates GetSendRates() const override;
+
   void OnReceivedNack(
       const std::vector<uint16_t>& nack_sequence_numbers) override;
   void OnReceivedRtcpReportBlocks(
@@ -294,6 +296,7 @@
 
   Clock* clock() const { return clock_; }
 
+  // TODO(sprang): Remove when usage is gone.
   DataRate SendRate() const;
   DataRate NackOverheadRate() const;
 
diff --git a/modules/rtp_rtcp/source/rtp_sender_egress.cc b/modules/rtp_rtcp/source/rtp_sender_egress.cc
index a64a5bd..77803de 100644
--- a/modules/rtp_rtcp/source/rtp_sender_egress.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_egress.cc
@@ -79,9 +79,8 @@
       max_delay_it_(send_delays_.end()),
       sum_delays_ms_(0),
       total_packet_send_delay_ms_(0),
-      total_bitrate_sent_(kBitrateStatisticsWindowMs,
-                          RateStatistics::kBpsScale),
-      nack_bitrate_sent_(kBitrateStatisticsWindowMs, RateStatistics::kBpsScale),
+      send_rates_(kNumMediaTypes,
+                  {kBitrateStatisticsWindowMs, RateStatistics::kBpsScale}),
       rtp_sequence_number_map_(need_rtp_packet_infos_
                                    ? std::make_unique<RtpSequenceNumberMap>(
                                          kRtpSequenceNumberMapMaxEntries)
@@ -99,16 +98,20 @@
   if (is_audio_) {
 #if BWE_TEST_LOGGING_COMPILE_TIME_ENABLE
     BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "AudioTotBitrate_kbps", now_ms,
-                                    SendBitrate().kbps(), packet_ssrc);
-    BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "AudioNackBitrate_kbps", now_ms,
-                                    NackOverheadRate().kbps(), packet_ssrc);
+                                    GetSendRates().Sum().kbps(), packet_ssrc);
+    BWE_TEST_LOGGING_PLOT_WITH_SSRC(
+        1, "AudioNackBitrate_kbps", now_ms,
+        GetSendRates()[RtpPacketMediaType::kRetransmission].kbps(),
+        packet_ssrc);
 #endif
   } else {
 #if BWE_TEST_LOGGING_COMPILE_TIME_ENABLE
     BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoTotBitrate_kbps", now_ms,
-                                    SendBitrate().kbps(), packet_ssrc);
-    BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoNackBitrate_kbps", now_ms,
-                                    NackOverheadRate().kbps(), packet_ssrc);
+                                    GetSendRates().Sum().kbps(), packet_ssrc);
+    BWE_TEST_LOGGING_PLOT_WITH_SSRC(
+        1, "VideoNackBitrate_kbps", now_ms,
+        GetSendRates()[RtpPacketMediaType::kRetransmission].kbps(),
+        packet_ssrc);
 #endif
   }
 
@@ -203,21 +206,22 @@
     return;
 
   rtc::CritScope lock(&lock_);
-  int64_t now_ms = clock_->TimeInMilliseconds();
-  bitrate_callback_->Notify(total_bitrate_sent_.Rate(now_ms).value_or(0),
-                            nack_bitrate_sent_.Rate(now_ms).value_or(0), ssrc_);
+  RtpSendRates send_rates = GetSendRates();
+  bitrate_callback_->Notify(
+      send_rates.Sum().bps(),
+      send_rates[RtpPacketMediaType::kRetransmission].bps(), ssrc_);
 }
 
-DataRate RtpSenderEgress::SendBitrate() const {
-  rtc::CritScope cs(&lock_);
-  return DataRate::BitsPerSec(
-      total_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0));
-}
-
-DataRate RtpSenderEgress::NackOverheadRate() const {
-  rtc::CritScope cs(&lock_);
-  return DataRate::BitsPerSec(
-      nack_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0));
+RtpSendRates RtpSenderEgress::GetSendRates() const {
+  rtc::CritScope lock(&lock_);
+  const int64_t now_ms = clock_->TimeInMilliseconds();
+  RtpSendRates current_rates;
+  for (size_t i = 0; i < kNumMediaTypes; ++i) {
+    RtpPacketMediaType type = static_cast<RtpPacketMediaType>(i);
+    current_rates[type] =
+        DataRate::BitsPerSec(send_rates_[i].Rate(now_ms).value_or(0));
+  }
+  return current_rates;
 }
 
 void RtpSenderEgress::GetDataCounters(StreamDataCounters* rtp_stats,
@@ -432,8 +436,6 @@
   StreamDataCounters* counters =
       packet.Ssrc() == rtx_ssrc_ ? &rtx_rtp_stats_ : &rtp_stats_;
 
-  total_bitrate_sent_.Update(packet.size(), now_ms);
-
   if (counters->first_packet_time_ms == -1) {
     counters->first_packet_time_ms = now_ms;
   }
@@ -444,10 +446,13 @@
 
   if (packet.packet_type() == RtpPacketMediaType::kRetransmission) {
     counters->retransmitted.AddPacket(packet);
-    nack_bitrate_sent_.Update(packet.size(), now_ms);
   }
   counters->transmitted.AddPacket(packet);
 
+  RTC_DCHECK(packet.packet_type().has_value());
+  send_rates_[static_cast<size_t>(*packet.packet_type())].Update(packet.size(),
+                                                                 now_ms);
+
   if (rtp_stats_callback_) {
     rtp_stats_callback_->DataCountersUpdated(*counters, packet.Ssrc());
   }
diff --git a/modules/rtp_rtcp/source/rtp_sender_egress.h b/modules/rtp_rtcp/source/rtp_sender_egress.h
index 1315340..298f57e 100644
--- a/modules/rtp_rtcp/source/rtp_sender_egress.h
+++ b/modules/rtp_rtcp/source/rtp_sender_egress.h
@@ -57,8 +57,7 @@
   absl::optional<uint32_t> FlexFecSsrc() const { return flexfec_ssrc_; }
 
   void ProcessBitrateAndNotifyObservers();
-  DataRate SendBitrate() const;
-  DataRate NackOverheadRate() const;
+  RtpSendRates GetSendRates() const;
   void GetDataCounters(StreamDataCounters* rtp_stats,
                        StreamDataCounters* rtx_stats) const;
 
@@ -129,8 +128,8 @@
   uint64_t total_packet_send_delay_ms_ RTC_GUARDED_BY(lock_);
   StreamDataCounters rtp_stats_ RTC_GUARDED_BY(lock_);
   StreamDataCounters rtx_rtp_stats_ RTC_GUARDED_BY(lock_);
-  RateStatistics total_bitrate_sent_ RTC_GUARDED_BY(lock_);
-  RateStatistics nack_bitrate_sent_ RTC_GUARDED_BY(lock_);
+  // One element per value in RtpPacketMediaType, with index matching value.
+  std::vector<RateStatistics> send_rates_ RTC_GUARDED_BY(lock_);
 
   // Maps sent packets' sequence numbers to a tuple consisting of:
   // 1. The timestamp, without the randomizing offset mandated by the RFC.