Wire up RTCP XR target bitrate in rtp/rtcp module

This is breakout of the rtcp parts of
https://codereview.webrtc.org/2531383002/

BUG=webrtc:6301

Review-Url: https://codereview.webrtc.org/2546713002
Cr-Commit-Position: refs/heads/master@{#15358}
diff --git a/webrtc/modules/rtp_rtcp/include/rtp_rtcp.h b/webrtc/modules/rtp_rtcp/include/rtp_rtcp.h
index bb9e1f2..b0f5075 100644
--- a/webrtc/modules/rtp_rtcp/include/rtp_rtcp.h
+++ b/webrtc/modules/rtp_rtcp/include/rtp_rtcp.h
@@ -424,6 +424,8 @@
   // BWE feedback packets.
   virtual bool SendFeedbackPacket(const rtcp::TransportFeedback& packet) = 0;
 
+  virtual void SetVideoBitrateAllocation(const BitrateAllocation& bitrate) = 0;
+
   // **************************************************************************
   // Audio
   // **************************************************************************
diff --git a/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h b/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h
index a8128ea..567fa0b 100644
--- a/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h
+++ b/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h
@@ -102,6 +102,7 @@
   kRtcpXrReceiverReferenceTime = 0x40000,
   kRtcpXrDlrrReportBlock = 0x80000,
   kRtcpTransportFeedback = 0x100000,
+  kRtcpXrTargetBitrate = 0x200000
 };
 
 enum KeyFrameRequestMethod { kKeyFrameReqPliRtcp, kKeyFrameReqFirRtcp };
diff --git a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
index 37ead5b..0e81e4dc 100644
--- a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
+++ b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -204,6 +204,7 @@
                void(StreamDataCountersCallback*));
   MOCK_CONST_METHOD0(GetSendChannelRtpStatisticsCallback,
                      StreamDataCountersCallback*(void));
+  MOCK_METHOD1(SetVideoBitrateAllocation, void(const BitrateAllocation&));
   // Members.
   unsigned int remote_ssrc_;
 };
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
index 2f4d393..c47e060 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
@@ -42,6 +42,12 @@
 
 namespace webrtc {
 
+namespace {
+const uint32_t kRtcpAnyExtendedReports =
+    kRtcpXrVoipMetric | kRtcpXrReceiverReferenceTime | kRtcpXrDlrrReportBlock |
+    kRtcpXrTargetBitrate;
+}  // namespace
+
 NACKStringBuilder::NACKStringBuilder()
     : stream_(""), count_(0), prevNack_(0), consecutive_(false) {}
 
@@ -197,10 +203,7 @@
   builders_[kRtcpTmmbr] = &RTCPSender::BuildTMMBR;
   builders_[kRtcpTmmbn] = &RTCPSender::BuildTMMBN;
   builders_[kRtcpNack] = &RTCPSender::BuildNACK;
-  builders_[kRtcpXrVoipMetric] = &RTCPSender::BuildVoIPMetric;
-  builders_[kRtcpXrReceiverReferenceTime] =
-      &RTCPSender::BuildReceiverReferenceTime;
-  builders_[kRtcpXrDlrrReportBlock] = &RTCPSender::BuildDlrr;
+  builders_[kRtcpAnyExtendedReports] = &RTCPSender::BuildExtendedReports;
 }
 
 RTCPSender::~RTCPSender() {}
@@ -692,44 +695,47 @@
   return std::unique_ptr<rtcp::RtcpPacket>(bye);
 }
 
-std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildReceiverReferenceTime(
+std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildExtendedReports(
     const RtcpContext& ctx) {
-
-  rtcp::ExtendedReports* xr = new rtcp::ExtendedReports();
+  std::unique_ptr<rtcp::ExtendedReports> xr(new rtcp::ExtendedReports());
   xr->SetSenderSsrc(ssrc_);
 
-  rtcp::Rrtr rrtr;
-  rrtr.SetNtp(NtpTime(ctx.ntp_sec_, ctx.ntp_frac_));
+  if (!sending_ && xr_send_receiver_reference_time_enabled_) {
+    rtcp::Rrtr rrtr;
+    rrtr.SetNtp(NtpTime(ctx.ntp_sec_, ctx.ntp_frac_));
+    xr->SetRrtr(rrtr);
+  }
 
-  xr->SetRrtr(rrtr);
+  if (ctx.feedback_state_.has_last_xr_rr) {
+    xr->AddDlrrItem(ctx.feedback_state_.last_xr_rr);
+  }
 
-  // TODO(sprang): Merge XR report sending to contain all of RRTR, DLRR, VOIP?
+  if (video_bitrate_allocation_) {
+    rtcp::TargetBitrate target_bitrate;
 
-  return std::unique_ptr<rtcp::RtcpPacket>(xr);
-}
+    for (int sl = 0; sl < kMaxSpatialLayers; ++sl) {
+      for (int tl = 0; tl < kMaxTemporalStreams; ++tl) {
+        uint32_t layer_bitrate_bps =
+            video_bitrate_allocation_->GetBitrate(sl, tl);
+        if (layer_bitrate_bps > 0)
+          target_bitrate.AddTargetBitrate(sl, tl, layer_bitrate_bps / 1000);
+      }
+    }
 
-std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildDlrr(
-    const RtcpContext& ctx) {
-  rtcp::ExtendedReports* xr = new rtcp::ExtendedReports();
-  xr->SetSenderSsrc(ssrc_);
-  RTC_DCHECK(ctx.feedback_state_.has_last_xr_rr);
-  xr->AddDlrrItem(ctx.feedback_state_.last_xr_rr);
+    xr->SetTargetBitrate(target_bitrate);
+    video_bitrate_allocation_.reset();
+  }
 
-  return std::unique_ptr<rtcp::RtcpPacket>(xr);
-}
+  if (xr_voip_metric_) {
+    rtcp::VoipMetric voip;
+    voip.SetMediaSsrc(remote_ssrc_);
+    voip.SetVoipMetric(*xr_voip_metric_);
+    xr_voip_metric_.reset();
 
-std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildVoIPMetric(
-    const RtcpContext& context) {
-  rtcp::ExtendedReports* xr = new rtcp::ExtendedReports();
-  xr->SetSenderSsrc(ssrc_);
+    xr->SetVoipMetric(voip);
+  }
 
-  rtcp::VoipMetric voip;
-  voip.SetMediaSsrc(remote_ssrc_);
-  voip.SetVoipMetric(xr_voip_metric_);
-
-  xr->SetVoipMetric(voip);
-
-  return std::unique_ptr<rtcp::RtcpPacket>(xr);
+  return std::move(xr);
 }
 
 int32_t RTCPSender::SendRTCP(const FeedbackState& feedback_state,
@@ -794,7 +800,8 @@
     auto it = report_flags_.begin();
     while (it != report_flags_.end()) {
       auto builder_it = builders_.find(it->type);
-      RTC_DCHECK(builder_it != builders_.end());
+      RTC_DCHECK(builder_it != builders_.end())
+          << "Could not find builder for packet type " << it->type;
       if (it->is_volatile) {
         report_flags_.erase(it++);
       } else {
@@ -849,10 +856,10 @@
     SetFlag(kRtcpSdes, true);
 
   if (generate_report) {
-    if (!sending_ && xr_send_receiver_reference_time_enabled_)
-      SetFlag(kRtcpXrReceiverReferenceTime, true);
-    if (feedback_state.has_last_xr_rr)
-      SetFlag(kRtcpXrDlrrReportBlock, true);
+    if ((!sending_ && xr_send_receiver_reference_time_enabled_) ||
+        feedback_state.has_last_xr_rr || video_bitrate_allocation_) {
+      SetFlag(kRtcpAnyExtendedReports, true);
+    }
 
     // generate next time to send an RTCP report
     uint32_t minIntervalMs = RTCP_INTERVAL_AUDIO_MS;
@@ -959,9 +966,9 @@
 
 int32_t RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) {
   rtc::CritScope lock(&critical_section_rtcp_sender_);
-  memcpy(&xr_voip_metric_, VoIPMetric, sizeof(RTCPVoIPMetric));
+  xr_voip_metric_.emplace(*VoIPMetric);
 
-  SetFlag(kRtcpXrVoipMetric, true);
+  SetFlag(kRtcpAnyExtendedReports, true);
   return 0;
 }
 
@@ -981,8 +988,12 @@
   SetFlag(kRtcpTmmbn, true);
 }
 
-void RTCPSender::SetFlag(RTCPPacketType type, bool is_volatile) {
-  report_flags_.insert(ReportFlag(type, is_volatile));
+void RTCPSender::SetFlag(uint32_t type, bool is_volatile) {
+  if (type & kRtcpAnyExtendedReports) {
+    report_flags_.insert(ReportFlag(kRtcpAnyExtendedReports, is_volatile));
+  } else {
+    report_flags_.insert(ReportFlag(type, is_volatile));
+  }
 }
 
 void RTCPSender::SetFlags(const std::set<RTCPPacketType>& types,
@@ -991,11 +1002,11 @@
     SetFlag(type, is_volatile);
 }
 
-bool RTCPSender::IsFlagPresent(RTCPPacketType type) const {
+bool RTCPSender::IsFlagPresent(uint32_t type) const {
   return report_flags_.find(ReportFlag(type, false)) != report_flags_.end();
 }
 
-bool RTCPSender::ConsumeFlag(RTCPPacketType type, bool forced) {
+bool RTCPSender::ConsumeFlag(uint32_t type, bool forced) {
   auto it = report_flags_.find(ReportFlag(type, false));
   if (it == report_flags_.end())
     return false;
@@ -1012,6 +1023,12 @@
   return true;
 }
 
+void RTCPSender::SetVideoBitrateAllocation(const BitrateAllocation& bitrate) {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  video_bitrate_allocation_.emplace(bitrate);
+  SetFlag(kRtcpAnyExtendedReports, true);
+}
+
 bool RTCPSender::SendFeedbackPacket(const rtcp::TransportFeedback& packet) {
   class Sender : public rtcp::RtcpPacket::PacketReadyCallback {
    public:
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender.h b/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
index f596766..a8bd275 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
@@ -21,6 +21,7 @@
 #include "webrtc/api/call/transport.h"
 #include "webrtc/base/constructormagic.h"
 #include "webrtc/base/criticalsection.h"
+#include "webrtc/base/optional.h"
 #include "webrtc/base/random.h"
 #include "webrtc/base/thread_annotations.h"
 #include "webrtc/modules/remote_bitrate_estimator/include/bwe_defines.h"
@@ -150,6 +151,7 @@
   void SetCsrcs(const std::vector<uint32_t>& csrcs);
 
   void SetTargetBitrate(unsigned int target_bitrate);
+  void SetVideoBitrateAllocation(const BitrateAllocation& bitrate);
   bool SendFeedbackPacket(const rtcp::TransportFeedback& packet);
 
  private:
@@ -180,7 +182,8 @@
       EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
   std::unique_ptr<rtcp::RtcpPacket> BuildAPP(const RtcpContext& context)
       EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
-  std::unique_ptr<rtcp::RtcpPacket> BuildVoIPMetric(const RtcpContext& context)
+  std::unique_ptr<rtcp::RtcpPacket> BuildExtendedReports(
+      const RtcpContext& context)
       EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
   std::unique_ptr<rtcp::RtcpPacket> BuildBYE(const RtcpContext& context)
       EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
@@ -192,11 +195,6 @@
       EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
   std::unique_ptr<rtcp::RtcpPacket> BuildNACK(const RtcpContext& context)
       EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
-  std::unique_ptr<rtcp::RtcpPacket> BuildReceiverReferenceTime(
-      const RtcpContext& context)
-      EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
-  std::unique_ptr<rtcp::RtcpPacket> BuildDlrr(const RtcpContext& context)
-      EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
 
  private:
   const bool audio_;
@@ -257,7 +255,8 @@
       GUARDED_BY(critical_section_rtcp_sender_);
 
   // XR VoIP metric
-  RTCPVoIPMetric xr_voip_metric_ GUARDED_BY(critical_section_rtcp_sender_);
+  rtc::Optional<RTCPVoIPMetric> xr_voip_metric_
+      GUARDED_BY(critical_section_rtcp_sender_);
 
   RtcpPacketTypeCounterObserver* const packet_type_counter_observer_;
   RtcpPacketTypeCounter packet_type_counter_
@@ -265,22 +264,25 @@
 
   RTCPUtility::NackStats nack_stats_ GUARDED_BY(critical_section_rtcp_sender_);
 
-  void SetFlag(RTCPPacketType type, bool is_volatile)
+  rtc::Optional<BitrateAllocation> video_bitrate_allocation_
+      GUARDED_BY(critical_section_rtcp_sender_);
+
+  void SetFlag(uint32_t type, bool is_volatile)
       EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
   void SetFlags(const std::set<RTCPPacketType>& types, bool is_volatile)
       EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
-  bool IsFlagPresent(RTCPPacketType type) const
+  bool IsFlagPresent(uint32_t type) const
       EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
-  bool ConsumeFlag(RTCPPacketType type, bool forced = false)
+  bool ConsumeFlag(uint32_t type, bool forced = false)
       EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
   bool AllVolatileFlagsConsumed() const
       EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
   struct ReportFlag {
-    ReportFlag(RTCPPacketType type, bool is_volatile)
+    ReportFlag(uint32_t type, bool is_volatile)
         : type(type), is_volatile(is_volatile) {}
     bool operator<(const ReportFlag& flag) const { return type < flag.type; }
     bool operator==(const ReportFlag& flag) const { return type == flag.type; }
-    const RTCPPacketType type;
+    const uint32_t type;
     const bool is_volatile;
   };
 
@@ -288,7 +290,8 @@
 
   typedef std::unique_ptr<rtcp::RtcpPacket> (RTCPSender::*BuilderFunc)(
       const RtcpContext&);
-  std::map<RTCPPacketType, BuilderFunc> builders_;
+  // Map from RTCPPacketType to builder.
+  std::map<uint32_t, BuilderFunc> builders_;
 
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RTCPSender);
 };
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_sender_unittest.cc
index a09d67a..8346ad4 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_sender_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender_unittest.cc
@@ -821,4 +821,39 @@
   EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpBye));
 }
 
+TEST_F(RtcpSenderTest, SendXrWithTargetBitrate) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  const size_t kNumSpatialLayers = 2;
+  const size_t kNumTemporalLayers = 2;
+  BitrateAllocation allocation;
+  for (size_t sl = 0; sl < kNumSpatialLayers; ++sl) {
+    uint32_t start_bitrate_bps = (sl + 1) * 100000;
+    for (size_t tl = 0; tl < kNumTemporalLayers; ++tl)
+      allocation.SetBitrate(sl, tl, start_bitrate_bps + (tl * 20000));
+  }
+  rtcp_sender_->SetVideoBitrateAllocation(allocation);
+
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
+  EXPECT_EQ(1, parser()->xr()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
+  const rtc::Optional<rtcp::TargetBitrate>& target_bitrate =
+      parser()->xr()->target_bitrate();
+  ASSERT_TRUE(target_bitrate);
+  const std::vector<rtcp::TargetBitrate::BitrateItem>& bitrates =
+      target_bitrate->GetTargetBitrates();
+  EXPECT_EQ(kNumSpatialLayers * kNumTemporalLayers, bitrates.size());
+
+  for (size_t sl = 0; sl < kNumSpatialLayers; ++sl) {
+    uint32_t start_bitrate_bps = (sl + 1) * 100000;
+    for (size_t tl = 0; tl < kNumTemporalLayers; ++tl) {
+      size_t index = (sl * kNumSpatialLayers) + tl;
+      const rtcp::TargetBitrate::BitrateItem& item = bitrates[index];
+      EXPECT_EQ(sl, item.spatial_layer);
+      EXPECT_EQ(tl, item.temporal_layer);
+      EXPECT_EQ(start_bitrate_bps + (tl * 20000),
+                item.target_bitrate_kbps * 1000);
+    }
+  }
+}
+
 }  // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index 339e4f0..b80c8da 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -953,4 +953,9 @@
     ModuleRtpRtcpImpl::GetSendChannelRtpStatisticsCallback() const {
   return rtp_sender_.GetRtpStatisticsCallback();
 }
+
+void ModuleRtpRtcpImpl::SetVideoBitrateAllocation(
+    const BitrateAllocation& bitrate) {
+  rtcp_sender_.SetVideoBitrateAllocation(bitrate);
+}
 }  // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index 4808a4e..bd978d0 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -313,6 +313,8 @@
       const ReportBlockList& report_blocks) override;
   void OnRequestSendReport() override;
 
+  void SetVideoBitrateAllocation(const BitrateAllocation& bitrate) override;
+
  protected:
   bool UpdateRTCPReceiveInformationTimers();