Handle Receiver Reference Time Report from multiple receivers.

Bug: webrtc:9122
Change-Id: I996f02da26b11a4829fda740fdd452470daf4d24
Reviewed-on: https://webrtc-review.googlesource.com/66781
Commit-Queue: Mirta Dvornicic <mirtad@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22871}
diff --git a/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc b/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc
index d9ee599..664e02b 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc
@@ -18,6 +18,7 @@
 namespace webrtc {
 namespace rtcp {
 constexpr uint8_t ExtendedReports::kPacketType;
+constexpr size_t ExtendedReports::kMaxNumberOfDlrrItems;
 // From RFC 3611: RTP Control Protocol Extended Reports (RTCP XR).
 //
 // Format for XR packets:
@@ -104,8 +105,13 @@
   rrtr_block_.emplace(rrtr);
 }
 
-void ExtendedReports::AddDlrrItem(const ReceiveTimeInfo& time_info) {
+bool ExtendedReports::AddDlrrItem(const ReceiveTimeInfo& time_info) {
+  if (dlrr_block_.sub_blocks().size() >= kMaxNumberOfDlrrItems) {
+    RTC_LOG(LS_WARNING) << "Reached maximum number of DLRR items.";
+    return false;
+  }
   dlrr_block_.AddDlrrItem(time_info);
+  return true;
 }
 
 void ExtendedReports::SetVoipMetric(const VoipMetric& voip_metric) {
diff --git a/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h b/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h
index a1da4dc..91794f8 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h
+++ b/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h
@@ -28,6 +28,7 @@
 class ExtendedReports : public RtcpPacket {
  public:
   static constexpr uint8_t kPacketType = 207;
+  static constexpr size_t kMaxNumberOfDlrrItems = 50;
 
   ExtendedReports();
   ~ExtendedReports() override;
@@ -38,7 +39,7 @@
   void SetSenderSsrc(uint32_t ssrc) { sender_ssrc_ = ssrc; }
 
   void SetRrtr(const Rrtr& rrtr);
-  void AddDlrrItem(const ReceiveTimeInfo& time_info);
+  bool AddDlrrItem(const ReceiveTimeInfo& time_info);
   void SetVoipMetric(const VoipMetric& voip_metric);
   void SetTargetBitrate(const TargetBitrate& target_bitrate);
 
diff --git a/modules/rtp_rtcp/source/rtcp_packet/extended_reports_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/extended_reports_unittest.cc
index 088b363..1e72d4a 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/extended_reports_unittest.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet/extended_reports_unittest.cc
@@ -18,6 +18,7 @@
 using testing::ElementsAre;
 using testing::ElementsAreArray;
 using testing::make_tuple;
+using testing::SizeIs;
 using webrtc::rtcp::Dlrr;
 using webrtc::rtcp::ExtendedReports;
 using webrtc::rtcp::ReceiveTimeInfo;
@@ -211,6 +212,18 @@
   EXPECT_THAT(parsed.dlrr().sub_blocks(), ElementsAre(kTimeInfo1, kTimeInfo2));
 }
 
+TEST_F(RtcpPacketExtendedReportsTest, CreateLimitsTheNumberOfDlrrSubBlocks) {
+  const ReceiveTimeInfo kTimeInfo = Rand<ReceiveTimeInfo>();
+  ExtendedReports xr;
+
+  for (size_t i = 0; i < ExtendedReports::kMaxNumberOfDlrrItems; ++i)
+    EXPECT_TRUE(xr.AddDlrrItem(kTimeInfo));
+  EXPECT_FALSE(xr.AddDlrrItem(kTimeInfo));
+
+  EXPECT_THAT(xr.dlrr().sub_blocks(),
+              SizeIs(ExtendedReports::kMaxNumberOfDlrrItems));
+}
+
 TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithVoipMetric) {
   const VoipMetric kVoipMetric = Rand<VoipMetric>();
 
@@ -228,15 +241,15 @@
   EXPECT_EQ(kVoipMetric, parsed.voip_metric());
 }
 
-TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithMultipleReportBlocks) {
+TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithMaximumReportBlocks) {
   const Rrtr kRrtr = Rand<Rrtr>();
-  const ReceiveTimeInfo kTimeInfo = Rand<ReceiveTimeInfo>();
   const VoipMetric kVoipMetric = Rand<VoipMetric>();
 
   ExtendedReports xr;
   xr.SetSenderSsrc(kSenderSsrc);
   xr.SetRrtr(kRrtr);
-  xr.AddDlrrItem(kTimeInfo);
+  for (size_t i = 0; i < ExtendedReports::kMaxNumberOfDlrrItems; ++i)
+    xr.AddDlrrItem(Rand<ReceiveTimeInfo>());
   xr.SetVoipMetric(kVoipMetric);
 
   rtc::Buffer packet = xr.Build();
@@ -247,7 +260,8 @@
 
   EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
   EXPECT_EQ(kRrtr, parsed.rrtr());
-  EXPECT_THAT(parsed.dlrr().sub_blocks(), ElementsAre(kTimeInfo));
+  EXPECT_THAT(parsed.dlrr().sub_blocks(),
+              ElementsAreArray(xr.dlrr().sub_blocks()));
   EXPECT_EQ(kVoipMetric, parsed.voip_metric());
 }
 
diff --git a/modules/rtp_rtcp/source/rtcp_receiver.cc b/modules/rtp_rtcp/source/rtcp_receiver.cc
index bd8e81b..abe135e 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver.cc
+++ b/modules/rtp_rtcp/source/rtcp_receiver.cc
@@ -57,6 +57,9 @@
 const int64_t kMaxWarningLogIntervalMs = 10000;
 const int64_t kRtcpMinFrameLengthMs = 17;
 
+// Maximum number of received RRTRs that will be stored.
+const size_t kMaxNumberOfStoredRrtrs = 200;
+
 }  // namespace
 
 struct RTCPReceiver::PacketInformation {
@@ -86,6 +89,22 @@
   std::map<uint32_t, TimedTmmbrItem> tmmbr;
 };
 
+// Structure for storing received RRTR RTCP messages (RFC3611, section 4.4).
+struct RTCPReceiver::RrtrInformation {
+  RrtrInformation(uint32_t ssrc,
+                  uint32_t received_remote_mid_ntp_time,
+                  uint32_t local_receive_mid_ntp_time)
+      : ssrc(ssrc),
+        received_remote_mid_ntp_time(received_remote_mid_ntp_time),
+        local_receive_mid_ntp_time(local_receive_mid_ntp_time) {}
+
+  uint32_t ssrc;
+  // Received NTP timestamp in compact representation.
+  uint32_t received_remote_mid_ntp_time;
+  // NTP time when the report was received in compact representation.
+  uint32_t local_receive_mid_ntp_time;
+};
+
 struct RTCPReceiver::ReportBlockWithRtt {
   RTCPReportBlock report_block;
 
@@ -251,22 +270,26 @@
   return true;
 }
 
-bool RTCPReceiver::LastReceivedXrReferenceTimeInfo(
-    rtcp::ReceiveTimeInfo* info) const {
-  RTC_DCHECK(info);
+std::vector<rtcp::ReceiveTimeInfo>
+RTCPReceiver::ConsumeReceivedXrReferenceTimeInfo() {
   rtc::CritScope lock(&rtcp_receiver_lock_);
-  if (!last_received_xr_ntp_.Valid())
-    return false;
 
-  info->ssrc = remote_time_info_.ssrc;
-  info->last_rr = remote_time_info_.last_rr;
+  const size_t last_xr_rtis_size = std::min(
+      received_rrtrs_.size(), rtcp::ExtendedReports::kMaxNumberOfDlrrItems);
+  std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis;
+  last_xr_rtis.reserve(last_xr_rtis_size);
 
-  // Get the delay since last received report (RFC 3611).
-  uint32_t receive_time_ntp = CompactNtp(last_received_xr_ntp_);
-  uint32_t now_ntp = CompactNtp(clock_->CurrentNtpTime());
+  const uint32_t now_ntp = CompactNtp(clock_->CurrentNtpTime());
 
-  info->delay_since_last_rr = now_ntp - receive_time_ntp;
-  return true;
+  for (size_t i = 0; i < last_xr_rtis_size; ++i) {
+    RrtrInformation& rrtr = received_rrtrs_.front();
+    last_xr_rtis.emplace_back(rrtr.ssrc, rrtr.received_remote_mid_ntp_time,
+                              now_ntp - rrtr.local_receive_mid_ntp_time);
+    received_rrtrs_ssrc_it_.erase(rrtr.ssrc);
+    received_rrtrs_.pop_front();
+  }
+
+  return last_xr_rtis;
 }
 
 // We can get multiple receive reports when we receive the report from a CE.
@@ -673,6 +696,11 @@
 
   last_fir_.erase(bye.sender_ssrc());
   received_cnames_.erase(bye.sender_ssrc());
+  auto it = received_rrtrs_ssrc_it_.find(bye.sender_ssrc());
+  if (it != received_rrtrs_ssrc_it_.end()) {
+    received_rrtrs_.erase(it->second);
+    received_rrtrs_ssrc_it_.erase(it);
+  }
   xr_rr_rtt_ms_ = 0;
 }
 
@@ -698,9 +726,23 @@
 
 void RTCPReceiver::HandleXrReceiveReferenceTime(uint32_t sender_ssrc,
                                                 const rtcp::Rrtr& rrtr) {
-  remote_time_info_.ssrc = sender_ssrc;
-  remote_time_info_.last_rr = CompactNtp(rrtr.ntp());
-  last_received_xr_ntp_ = clock_->CurrentNtpTime();
+  uint32_t received_remote_mid_ntp_time = CompactNtp(rrtr.ntp());
+  uint32_t local_receive_mid_ntp_time = CompactNtp(clock_->CurrentNtpTime());
+
+  auto it = received_rrtrs_ssrc_it_.find(sender_ssrc);
+  if (it != received_rrtrs_ssrc_it_.end()) {
+    it->second->received_remote_mid_ntp_time = received_remote_mid_ntp_time;
+    it->second->local_receive_mid_ntp_time = local_receive_mid_ntp_time;
+  } else {
+    if (received_rrtrs_.size() < kMaxNumberOfStoredRrtrs) {
+      received_rrtrs_.emplace_back(sender_ssrc, received_remote_mid_ntp_time,
+                                   local_receive_mid_ntp_time);
+      received_rrtrs_ssrc_it_[sender_ssrc] = std::prev(received_rrtrs_.end());
+    } else {
+      RTC_LOG(LS_WARNING) << "Discarding received RRTR for ssrc " << sender_ssrc
+                          << ", reached maximum number of stored RRTRs.";
+    }
+  }
 }
 
 void RTCPReceiver::HandleXrDlrrReportBlock(const rtcp::ReceiveTimeInfo& rti) {
diff --git a/modules/rtp_rtcp/source/rtcp_receiver.h b/modules/rtp_rtcp/source/rtcp_receiver.h
index c3de36c..c868837 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver.h
+++ b/modules/rtp_rtcp/source/rtcp_receiver.h
@@ -11,6 +11,7 @@
 #ifndef MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_
 #define MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_
 
+#include <list>
 #include <map>
 #include <set>
 #include <string>
@@ -77,7 +78,7 @@
            uint32_t* rtcp_arrival_time_frac,
            uint32_t* rtcp_timestamp) const;
 
-  bool LastReceivedXrReferenceTimeInfo(rtcp::ReceiveTimeInfo* info) const;
+  std::vector<rtcp::ReceiveTimeInfo> ConsumeReceivedXrReferenceTimeInfo();
 
   // Get rtt.
   int32_t RTT(uint32_t remote_ssrc,
@@ -115,6 +116,7 @@
  private:
   struct PacketInformation;
   struct TmmbrInformation;
+  struct RrtrInformation;
   struct ReportBlockWithRtt;
   struct LastFirStatus;
   // RTCP report blocks mapped by remote SSRC.
@@ -226,10 +228,13 @@
   // When did we receive the last send report.
   NtpTime last_received_sr_ntp_ RTC_GUARDED_BY(rtcp_receiver_lock_);
 
-  // Received XR receive time report.
-  rtcp::ReceiveTimeInfo remote_time_info_;
-  // Time when the report was received.
-  NtpTime last_received_xr_ntp_;
+  // Received RRTR information in ascending receive time order.
+  std::list<RrtrInformation> received_rrtrs_
+      RTC_GUARDED_BY(rtcp_receiver_lock_);
+  // Received RRTR information mapped by remote ssrc.
+  std::map<uint32_t, std::list<RrtrInformation>::iterator>
+      received_rrtrs_ssrc_it_ RTC_GUARDED_BY(rtcp_receiver_lock_);
+
   // Estimated rtt, zero when there is no valid estimate.
   bool xr_rrtr_status_ RTC_GUARDED_BY(rtcp_receiver_lock_);
   int64_t xr_rr_rtt_ms_;
diff --git a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
index 5faf7ed..3c3c4b3 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
+++ b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
@@ -620,6 +620,21 @@
   EXPECT_EQ(2u, received_blocks.size());
 }
 
+TEST_F(RtcpReceiverTest, InjectByePacketRemovesReferenceTimeInfo) {
+  rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  rtcp::Rrtr rrtr;
+  rrtr.SetNtp(NtpTime(0x10203, 0x40506));
+  xr.SetRrtr(rrtr);
+  InjectRtcpPacket(xr);
+
+  rtcp::Bye bye;
+  bye.SetSenderSsrc(kSenderSsrc);
+  InjectRtcpPacket(bye);
+
+  EXPECT_THAT(rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo(), IsEmpty());
+}
+
 TEST_F(RtcpReceiverTest, InjectPliPacket) {
   rtcp::Pli pli;
   pli.SetMediaSsrc(kReceiverMainSsrc);
@@ -706,19 +721,17 @@
   xr.SetSenderSsrc(kSenderSsrc);
   xr.SetRrtr(rrtr);
 
-  ReceiveTimeInfo rrtime;
-  EXPECT_FALSE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&rrtime));
+  std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
+      rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+  EXPECT_THAT(last_xr_rtis, IsEmpty());
 
   InjectRtcpPacket(xr);
 
-  EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&rrtime));
-  EXPECT_EQ(rrtime.ssrc, kSenderSsrc);
-  EXPECT_EQ(rrtime.last_rr, CompactNtp(kNtp));
-  EXPECT_EQ(0U, rrtime.delay_since_last_rr);
-
-  system_clock_.AdvanceTimeMilliseconds(1500);
-  EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&rrtime));
-  EXPECT_NEAR(1500, CompactNtpRttToMs(rrtime.delay_since_last_rr), 1);
+  last_xr_rtis = rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+  ASSERT_THAT(last_xr_rtis, SizeIs(1));
+  EXPECT_EQ(kSenderSsrc, last_xr_rtis[0].ssrc);
+  EXPECT_EQ(CompactNtp(kNtp), last_xr_rtis[0].last_rr);
+  EXPECT_EQ(0U, last_xr_rtis[0].delay_since_last_rr);
 }
 
 TEST_F(RtcpReceiverTest, ExtendedReportsDlrrPacketNotToUsIgnored) {
@@ -788,8 +801,9 @@
 
   InjectRtcpPacket(xr);
 
-  ReceiveTimeInfo rrtime;
-  EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&rrtime));
+  std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
+      rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+  EXPECT_THAT(last_xr_rtis, SizeIs(1));
   int64_t rtt_ms = 0;
   EXPECT_TRUE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms));
 }
@@ -813,8 +827,9 @@
   InjectRtcpPacket(packet);
 
   // Validate Rrtr was received and processed.
-  ReceiveTimeInfo rrtime;
-  EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&rrtime));
+  std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
+      rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+  EXPECT_THAT(last_xr_rtis, SizeIs(1));
   // Validate Dlrr report wasn't processed.
   int64_t rtt_ms = 0;
   EXPECT_FALSE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms));
@@ -869,12 +884,11 @@
   EXPECT_EQ(1, rtt_ms);
 }
 
-TEST_F(RtcpReceiverTest, LastReceivedXrReferenceTimeInfoInitiallyFalse) {
-  ReceiveTimeInfo info;
-  EXPECT_FALSE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&info));
+TEST_F(RtcpReceiverTest, ConsumeReceivedXrReferenceTimeInfoInitiallyEmpty) {
+  EXPECT_THAT(rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo(), IsEmpty());
 }
 
-TEST_F(RtcpReceiverTest, GetLastReceivedExtendedReportsReferenceTimeInfo) {
+TEST_F(RtcpReceiverTest, ConsumeReceivedXrReferenceTimeInfo) {
   const NtpTime kNtp(0x10203, 0x40506);
   const uint32_t kNtpMid = CompactNtp(kNtp);
 
@@ -886,15 +900,69 @@
 
   InjectRtcpPacket(xr);
 
-  ReceiveTimeInfo info;
-  EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&info));
-  EXPECT_EQ(kSenderSsrc, info.ssrc);
-  EXPECT_EQ(kNtpMid, info.last_rr);
-  EXPECT_EQ(0U, info.delay_since_last_rr);
-
   system_clock_.AdvanceTimeMilliseconds(1000);
-  EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&info));
-  EXPECT_EQ(65536U, info.delay_since_last_rr);
+
+  std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
+      rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+  ASSERT_THAT(last_xr_rtis, SizeIs(1));
+  EXPECT_EQ(kSenderSsrc, last_xr_rtis[0].ssrc);
+  EXPECT_EQ(kNtpMid, last_xr_rtis[0].last_rr);
+  EXPECT_EQ(65536U, last_xr_rtis[0].delay_since_last_rr);
+}
+
+TEST_F(RtcpReceiverTest,
+       ReceivedRrtrFromSameSsrcUpdatesReceivedReferenceTimeInfo) {
+  const NtpTime kNtp1(0x10203, 0x40506);
+  const NtpTime kNtp2(0x11223, 0x44556);
+  const int64_t kDelayMs = 2000;
+
+  rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  rtcp::Rrtr rrtr1;
+  rrtr1.SetNtp(kNtp1);
+  xr.SetRrtr(rrtr1);
+  InjectRtcpPacket(xr);
+  system_clock_.AdvanceTimeMilliseconds(kDelayMs);
+  rtcp::Rrtr rrtr2;
+  rrtr2.SetNtp(kNtp2);
+  xr.SetRrtr(rrtr2);
+  InjectRtcpPacket(xr);
+  system_clock_.AdvanceTimeMilliseconds(kDelayMs);
+
+  std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
+      rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+  ASSERT_THAT(last_xr_rtis, SizeIs(1));
+  EXPECT_EQ(kSenderSsrc, last_xr_rtis[0].ssrc);
+  EXPECT_EQ(CompactNtp(kNtp2), last_xr_rtis[0].last_rr);
+  EXPECT_EQ(kDelayMs * 65536 / 1000, last_xr_rtis[0].delay_since_last_rr);
+}
+
+TEST_F(RtcpReceiverTest, StoresLastReceivedRrtrPerSsrc) {
+  const size_t kNumBufferedReports = 1;
+  const size_t kNumReports =
+      rtcp::ExtendedReports::kMaxNumberOfDlrrItems + kNumBufferedReports;
+  for (size_t i = 0; i < kNumReports; ++i) {
+    rtcp::ExtendedReports xr;
+    xr.SetSenderSsrc(i * 100);
+    rtcp::Rrtr rrtr;
+    rrtr.SetNtp(NtpTime(i * 200, i * 300));
+    xr.SetRrtr(rrtr);
+    InjectRtcpPacket(xr);
+    system_clock_.AdvanceTimeMilliseconds(1000);
+  }
+
+  std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
+      rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+  ASSERT_THAT(last_xr_rtis,
+              SizeIs(rtcp::ExtendedReports::kMaxNumberOfDlrrItems));
+  for (size_t i = 0; i < rtcp::ExtendedReports::kMaxNumberOfDlrrItems; ++i) {
+    EXPECT_EQ(i * 100, last_xr_rtis[i].ssrc);
+    EXPECT_EQ(CompactNtp(NtpTime(i * 200, i * 300)), last_xr_rtis[i].last_rr);
+    EXPECT_EQ(65536U * (kNumReports - i), last_xr_rtis[i].delay_since_last_rr);
+  }
+
+  last_xr_rtis = rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+  ASSERT_THAT(last_xr_rtis, SizeIs(kNumBufferedReports));
 }
 
 TEST_F(RtcpReceiverTest, ReceiveReportTimeout) {
diff --git a/modules/rtp_rtcp/source/rtcp_sender.cc b/modules/rtp_rtcp/source/rtcp_sender.cc
index 415de95..6b266cb 100644
--- a/modules/rtp_rtcp/source/rtcp_sender.cc
+++ b/modules/rtp_rtcp/source/rtcp_sender.cc
@@ -85,9 +85,14 @@
       last_rr_ntp_secs(0),
       last_rr_ntp_frac(0),
       remote_sr(0),
-      has_last_xr_rr(false),
       module(nullptr) {}
 
+RTCPSender::FeedbackState::FeedbackState(const FeedbackState&) = default;
+
+RTCPSender::FeedbackState::FeedbackState(FeedbackState&&) = default;
+
+RTCPSender::FeedbackState::~FeedbackState() = default;
+
 class PacketContainer : public rtcp::CompoundPacket {
  public:
   PacketContainer(Transport* transport, RtcEventLog* event_log)
@@ -644,8 +649,8 @@
     xr->SetRrtr(rrtr);
   }
 
-  if (ctx.feedback_state_.has_last_xr_rr) {
-    xr->AddDlrrItem(ctx.feedback_state_.last_xr_rr);
+  for (const rtcp::ReceiveTimeInfo& rti : ctx.feedback_state_.last_xr_rtis) {
+    xr->AddDlrrItem(rti);
   }
 
   if (video_bitrate_allocation_) {
@@ -791,7 +796,7 @@
 
   if (generate_report) {
     if ((!sending_ && xr_send_receiver_reference_time_enabled_) ||
-        feedback_state.has_last_xr_rr || video_bitrate_allocation_) {
+        !feedback_state.last_xr_rtis.empty() || video_bitrate_allocation_) {
       SetFlag(kRtcpAnyExtendedReports, true);
     }
 
diff --git a/modules/rtp_rtcp/source/rtcp_sender.h b/modules/rtp_rtcp/source/rtcp_sender.h
index 134a6fb..f6cb55e 100644
--- a/modules/rtp_rtcp/source/rtcp_sender.h
+++ b/modules/rtp_rtcp/source/rtcp_sender.h
@@ -59,6 +59,10 @@
  public:
   struct FeedbackState {
     FeedbackState();
+    FeedbackState(const FeedbackState&);
+    FeedbackState(FeedbackState&&);
+
+    ~FeedbackState();
 
     uint32_t packets_sent;
     size_t media_bytes_sent;
@@ -68,8 +72,7 @@
     uint32_t last_rr_ntp_frac;
     uint32_t remote_sr;
 
-    bool has_last_xr_rr;
-    rtcp::ReceiveTimeInfo last_xr_rr;
+    std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis;
 
     // Used when generating TMMBR.
     ModuleRtpRtcpImpl* module;
diff --git a/modules/rtp_rtcp/source/rtcp_sender_unittest.cc b/modules/rtp_rtcp/source/rtcp_sender_unittest.cc
index 7742374..9851332 100644
--- a/modules/rtp_rtcp/source/rtcp_sender_unittest.cc
+++ b/modules/rtp_rtcp/source/rtcp_sender_unittest.cc
@@ -24,6 +24,7 @@
 using ::testing::_;
 using ::testing::ElementsAre;
 using ::testing::Invoke;
+using ::testing::SizeIs;
 
 namespace webrtc {
 
@@ -608,22 +609,47 @@
 TEST_F(RtcpSenderTest, SendXrWithDlrr) {
   rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
   RTCPSender::FeedbackState feedback_state = rtp_rtcp_impl_->GetFeedbackState();
-  feedback_state.has_last_xr_rr = true;
   rtcp::ReceiveTimeInfo last_xr_rr;
   last_xr_rr.ssrc = 0x11111111;
   last_xr_rr.last_rr = 0x22222222;
   last_xr_rr.delay_since_last_rr = 0x33333333;
-  feedback_state.last_xr_rr = last_xr_rr;
+  feedback_state.last_xr_rtis.push_back(last_xr_rr);
   EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state, kRtcpReport));
   EXPECT_EQ(1, parser()->xr()->num_packets());
   EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
-  EXPECT_EQ(1U, parser()->xr()->dlrr().sub_blocks().size());
+  ASSERT_THAT(parser()->xr()->dlrr().sub_blocks(), SizeIs(1));
   EXPECT_EQ(last_xr_rr.ssrc, parser()->xr()->dlrr().sub_blocks()[0].ssrc);
   EXPECT_EQ(last_xr_rr.last_rr, parser()->xr()->dlrr().sub_blocks()[0].last_rr);
   EXPECT_EQ(last_xr_rr.delay_since_last_rr,
             parser()->xr()->dlrr().sub_blocks()[0].delay_since_last_rr);
 }
 
+TEST_F(RtcpSenderTest, SendXrWithMultipleDlrrSubBlocks) {
+  const size_t kNumReceivers = 2;
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  RTCPSender::FeedbackState feedback_state = rtp_rtcp_impl_->GetFeedbackState();
+  for (size_t i = 0; i < kNumReceivers; ++i) {
+    rtcp::ReceiveTimeInfo last_xr_rr;
+    last_xr_rr.ssrc = i;
+    last_xr_rr.last_rr = (i + 1) * 100;
+    last_xr_rr.delay_since_last_rr = (i + 2) * 200;
+    feedback_state.last_xr_rtis.push_back(last_xr_rr);
+  }
+
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state, kRtcpReport));
+  EXPECT_EQ(1, parser()->xr()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
+  ASSERT_THAT(parser()->xr()->dlrr().sub_blocks(), SizeIs(kNumReceivers));
+  for (size_t i = 0; i < kNumReceivers; ++i) {
+    EXPECT_EQ(feedback_state.last_xr_rtis[i].ssrc,
+              parser()->xr()->dlrr().sub_blocks()[i].ssrc);
+    EXPECT_EQ(feedback_state.last_xr_rtis[i].last_rr,
+              parser()->xr()->dlrr().sub_blocks()[i].last_rr);
+    EXPECT_EQ(feedback_state.last_xr_rtis[i].delay_since_last_rr,
+              parser()->xr()->dlrr().sub_blocks()[i].delay_since_last_rr);
+  }
+}
+
 TEST_F(RtcpSenderTest, SendXrWithRrtr) {
   rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
   EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), false));
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index 45983a0..22e399d 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -377,8 +377,7 @@
                   &state.last_rr_ntp_frac,
                   &state.remote_sr);
 
-  state.has_last_xr_rr =
-      rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&state.last_xr_rr);
+  state.last_xr_rtis = rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
 
   return state;
 }