ReportBlockData and observer added, for stats collection in future CLs.

The ReportBlockData contains information about a ReportBlock and
additional data such as RTT. This will be used for the calculation of
RTCRemoteInboundRtpStreamStats, see full picture here:
https://webrtc-review.googlesource.com/c/src/+/134107

ReportBlockData is a class version of the previously internal struct
RTCPReceiver::ReportBlockWithRtt.
- The new name makes sense even if we add more info to it, which will
  be needed for future metrics.
- The new location is modules/rtp_rtcp/include/report_block_data.h.

The RTCPReceiver allows obtaining the ReportBlockData in two ways:
1. Using a ReportBlockDataObserver that is notified on receiving a
   report block.
2. Using the GetLatestReportBlockData().

Both codepaths will be needed; video stats uses observers and audio
stats uses polling.

Further plumbing will be done in follow-up CLs.

Bug: webrtc:10455, webrtc:10456
Change-Id: Ic9e5b4f451b5f4b203efcd6fa3bbf9736487e1f4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/136584
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27961}
diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn
index cf5ef59..02c7207 100644
--- a/modules/rtp_rtcp/BUILD.gn
+++ b/modules/rtp_rtcp/BUILD.gn
@@ -11,6 +11,7 @@
 rtc_source_set("rtp_rtcp_format") {
   visibility = [ "*" ]
   public = [
+    "include/report_block_data.h",
     "include/rtcp_statistics.h",
     "include/rtp_cvo.h",
     "include/rtp_header_extension_map.h",
@@ -50,6 +51,7 @@
     "source/rtp_packet_to_send.h",
   ]
   sources = [
+    "include/report_block_data.cc",
     "include/rtp_rtcp_defines.cc",
     "source/rtcp_packet.cc",
     "source/rtcp_packet/app.cc",
@@ -446,6 +448,7 @@
       "../../api:scoped_refptr",
       "../../api:transport_api",
       "../../api/transport:field_trial_based_config",
+      "../../api/units:timestamp",
       "../../api/video:video_bitrate_allocation",
       "../../api/video:video_bitrate_allocator",
       "../../api/video:video_codec_constants",
diff --git a/modules/rtp_rtcp/include/report_block_data.cc b/modules/rtp_rtcp/include/report_block_data.cc
new file mode 100644
index 0000000..ec4d9d8
--- /dev/null
+++ b/modules/rtp_rtcp/include/report_block_data.cc
@@ -0,0 +1,44 @@
+/*
+ *  Copyright 2019 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/rtp_rtcp/include/report_block_data.h"
+
+namespace webrtc {
+
+ReportBlockData::ReportBlockData()
+    : report_block_(),
+      report_block_timestamp_utc_us_(0),
+      last_rtt_ms_(0),
+      min_rtt_ms_(0),
+      max_rtt_ms_(0),
+      sum_rtt_ms_(0),
+      num_rtts_(0) {}
+
+double ReportBlockData::AvgRttMs() const {
+  return num_rtts_ ? static_cast<double>(sum_rtt_ms_) / num_rtts_ : 0.0;
+}
+
+void ReportBlockData::SetReportBlock(RTCPReportBlock report_block,
+                                     int64_t report_block_timestamp_utc_us) {
+  report_block_ = report_block;
+  report_block_timestamp_utc_us_ = report_block_timestamp_utc_us;
+}
+
+void ReportBlockData::AddRoundTripTimeSample(int64_t rtt_ms) {
+  if (rtt_ms > max_rtt_ms_)
+    max_rtt_ms_ = rtt_ms;
+  if (num_rtts_ == 0 || rtt_ms < min_rtt_ms_)
+    min_rtt_ms_ = rtt_ms;
+  last_rtt_ms_ = rtt_ms;
+  sum_rtt_ms_ += rtt_ms;
+  ++num_rtts_;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/include/report_block_data.h b/modules/rtp_rtcp/include/report_block_data.h
new file mode 100644
index 0000000..2c4533a
--- /dev/null
+++ b/modules/rtp_rtcp/include/report_block_data.h
@@ -0,0 +1,59 @@
+/*
+ *  Copyright 2019 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_RTP_RTCP_INCLUDE_REPORT_BLOCK_DATA_H_
+#define MODULES_RTP_RTCP_INCLUDE_REPORT_BLOCK_DATA_H_
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+
+namespace webrtc {
+
+class ReportBlockData {
+ public:
+  ReportBlockData();
+
+  const RTCPReportBlock& report_block() const { return report_block_; }
+  int64_t report_block_timestamp_utc_us() const {
+    return report_block_timestamp_utc_us_;
+  }
+  int64_t last_rtt_ms() const { return last_rtt_ms_; }
+  int64_t min_rtt_ms() const { return min_rtt_ms_; }
+  int64_t max_rtt_ms() const { return max_rtt_ms_; }
+  int64_t sum_rtt_ms() const { return sum_rtt_ms_; }
+  size_t num_rtts() const { return num_rtts_; }
+  bool has_rtt() const { return num_rtts_ != 0; }
+
+  double AvgRttMs() const;
+
+  void SetReportBlock(RTCPReportBlock report_block,
+                      int64_t report_block_timestamp_utc_us);
+  void AddRoundTripTimeSample(int64_t rtt_ms);
+
+ private:
+  RTCPReportBlock report_block_;
+  int64_t report_block_timestamp_utc_us_;
+
+  int64_t last_rtt_ms_;
+  int64_t min_rtt_ms_;
+  int64_t max_rtt_ms_;
+  int64_t sum_rtt_ms_;
+  size_t num_rtts_;
+};
+
+class ReportBlockDataObserver {
+ public:
+  virtual ~ReportBlockDataObserver() = default;
+
+  virtual void OnReportBlockDataUpdated(ReportBlockData report_block_data) = 0;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_INCLUDE_REPORT_BLOCK_DATA_H_
diff --git a/modules/rtp_rtcp/source/rtcp_receiver.cc b/modules/rtp_rtcp/source/rtcp_receiver.cc
index 0c1c326..c791434 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver.cc
+++ b/modules/rtp_rtcp/source/rtcp_receiver.cc
@@ -42,6 +42,7 @@
 #include "modules/rtp_rtcp/source/tmmbr_help.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
+#include "rtc_base/time_utils.h"
 #include "rtc_base/trace_event.h"
 #include "system_wrappers/include/ntp_time.h"
 
@@ -69,7 +70,9 @@
 
   uint32_t remote_ssrc = 0;
   std::vector<uint16_t> nack_sequence_numbers;
+  // TODO(hbos): Remove |report_blocks| in favor of |report_block_datas|.
   ReportBlockList report_blocks;
+  std::vector<ReportBlockData> report_block_datas;
   int64_t rtt_ms = 0;
   uint32_t receiver_estimated_max_bitrate_bps = 0;
   std::unique_ptr<rtcp::TransportFeedback> transport_feedback;
@@ -108,16 +111,6 @@
   uint32_t local_receive_mid_ntp_time;
 };
 
-struct RTCPReceiver::ReportBlockWithRtt {
-  RTCPReportBlock report_block;
-
-  int64_t last_rtt_ms = 0;
-  int64_t min_rtt_ms = 0;
-  int64_t max_rtt_ms = 0;
-  int64_t sum_rtt_ms = 0;
-  size_t num_rtts = 0;
-};
-
 struct RTCPReceiver::LastFirStatus {
   LastFirStatus(int64_t now_ms, uint8_t sequence_number)
       : request_ms(now_ms), sequence_number(sequence_number) {}
@@ -154,6 +147,7 @@
       last_received_rb_ms_(0),
       last_increased_sequence_number_ms_(0),
       stats_callback_(nullptr),
+      report_block_data_observer_(nullptr),
       packet_type_counter_observer_(packet_type_counter_observer),
       num_skipped_packets_(0),
       last_skipped_packets_warning_ms_(clock->TimeInMilliseconds()) {
@@ -213,22 +207,24 @@
   if (it_info == it->second.end())
     return -1;
 
-  const ReportBlockWithRtt* report_block = &it_info->second;
+  const ReportBlockData* report_block_data = &it_info->second;
 
-  if (report_block->num_rtts == 0)
+  if (report_block_data->num_rtts() == 0)
     return -1;
 
   if (last_rtt_ms)
-    *last_rtt_ms = report_block->last_rtt_ms;
+    *last_rtt_ms = report_block_data->last_rtt_ms();
 
-  if (avg_rtt_ms)
-    *avg_rtt_ms = report_block->sum_rtt_ms / report_block->num_rtts;
+  if (avg_rtt_ms) {
+    *avg_rtt_ms =
+        report_block_data->sum_rtt_ms() / report_block_data->num_rtts();
+  }
 
   if (min_rtt_ms)
-    *min_rtt_ms = report_block->min_rtt_ms;
+    *min_rtt_ms = report_block_data->min_rtt_ms();
 
   if (max_rtt_ms)
-    *max_rtt_ms = report_block->max_rtt_ms;
+    *max_rtt_ms = report_block_data->max_rtt_ms();
 
   return 0;
 }
@@ -307,10 +303,19 @@
   rtc::CritScope lock(&rtcp_receiver_lock_);
   for (const auto& reports_per_receiver : received_report_blocks_)
     for (const auto& report : reports_per_receiver.second)
-      receive_blocks->push_back(report.second.report_block);
+      receive_blocks->push_back(report.second.report_block());
   return 0;
 }
 
+std::vector<ReportBlockData> RTCPReceiver::GetLatestReportBlockData() const {
+  std::vector<ReportBlockData> result;
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+  for (const auto& reports_per_receiver : received_report_blocks_)
+    for (const auto& report : reports_per_receiver.second)
+      result.push_back(report.second);
+  return result;
+}
+
 bool RTCPReceiver::ParseCompoundPacket(const uint8_t* packet_begin,
                                        const uint8_t* packet_end,
                                        PacketInformation* packet_information) {
@@ -483,26 +488,26 @@
 
   last_received_rb_ms_ = clock_->TimeInMilliseconds();
 
-  ReportBlockWithRtt* report_block_info =
+  ReportBlockData* report_block_data =
       &received_report_blocks_[report_block.source_ssrc()][remote_ssrc];
-  report_block_info->report_block.sender_ssrc = remote_ssrc;
-  report_block_info->report_block.source_ssrc = report_block.source_ssrc();
-  report_block_info->report_block.fraction_lost = report_block.fraction_lost();
-  report_block_info->report_block.packets_lost =
-      report_block.cumulative_lost_signed();
+  RTCPReportBlock rtcp_report_block;
+  rtcp_report_block.sender_ssrc = remote_ssrc;
+  rtcp_report_block.source_ssrc = report_block.source_ssrc();
+  rtcp_report_block.fraction_lost = report_block.fraction_lost();
+  rtcp_report_block.packets_lost = report_block.cumulative_lost_signed();
   if (report_block.extended_high_seq_num() >
-      report_block_info->report_block.extended_highest_sequence_number) {
+      report_block_data->report_block().extended_highest_sequence_number) {
     // We have successfully delivered new RTP packets to the remote side after
     // the last RR was sent from the remote side.
     last_increased_sequence_number_ms_ = clock_->TimeInMilliseconds();
   }
-  report_block_info->report_block.extended_highest_sequence_number =
+  rtcp_report_block.extended_highest_sequence_number =
       report_block.extended_high_seq_num();
-  report_block_info->report_block.jitter = report_block.jitter();
-  report_block_info->report_block.delay_since_last_sender_report =
+  rtcp_report_block.jitter = report_block.jitter();
+  rtcp_report_block.delay_since_last_sender_report =
       report_block.delay_since_last_sr();
-  report_block_info->report_block.last_sender_report_timestamp =
-      report_block.last_sr();
+  rtcp_report_block.last_sender_report_timestamp = report_block.last_sr();
+  report_block_data->SetReportBlock(rtcp_report_block, rtc::TimeUTCMicros());
 
   int64_t rtt_ms = 0;
   uint32_t send_time_ntp = report_block.last_sr();
@@ -527,21 +532,14 @@
     uint32_t rtt_ntp = receive_time_ntp - delay_ntp - send_time_ntp;
     // Convert to 1/1000 seconds (milliseconds).
     rtt_ms = CompactNtpRttToMs(rtt_ntp);
-    if (rtt_ms > report_block_info->max_rtt_ms)
-      report_block_info->max_rtt_ms = rtt_ms;
-
-    if (report_block_info->num_rtts == 0 ||
-        rtt_ms < report_block_info->min_rtt_ms)
-      report_block_info->min_rtt_ms = rtt_ms;
-
-    report_block_info->last_rtt_ms = rtt_ms;
-    report_block_info->sum_rtt_ms += rtt_ms;
-    ++report_block_info->num_rtts;
+    report_block_data->AddRoundTripTimeSample(rtt_ms);
 
     packet_information->rtt_ms = rtt_ms;
   }
 
-  packet_information->report_blocks.push_back(report_block_info->report_block);
+  packet_information->report_blocks.push_back(
+      report_block_data->report_block());
+  packet_information->report_block_datas.push_back(*report_block_data);
 }
 
 RTCPReceiver::TmmbrInformation* RTCPReceiver::FindOrCreateTmmbrInfo(
@@ -975,6 +973,12 @@
   return stats_callback_;
 }
 
+void RTCPReceiver::SetReportBlockDataObserver(
+    ReportBlockDataObserver* observer) {
+  rtc::CritScope cs(&feedbacks_lock_);
+  report_block_data_observer_ = observer;
+}
+
 // Holding no Critical section.
 void RTCPReceiver::TriggerCallbacksFromRtcpPacket(
     const PacketInformation& packet_information) {
@@ -1085,6 +1089,13 @@
         stats_callback_->StatisticsUpdated(stats, report_block.source_ssrc);
       }
     }
+    if (report_block_data_observer_) {
+      for (const auto& report_block_data :
+           packet_information.report_block_datas) {
+        report_block_data_observer_->OnReportBlockDataUpdated(
+            report_block_data);
+      }
+    }
   }
 }
 
diff --git a/modules/rtp_rtcp/source/rtcp_receiver.h b/modules/rtp_rtcp/source/rtcp_receiver.h
index afc3f96..e971c15 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver.h
+++ b/modules/rtp_rtcp/source/rtcp_receiver.h
@@ -17,6 +17,7 @@
 #include <string>
 #include <vector>
 
+#include "modules/rtp_rtcp/include/report_block_data.h"
 #include "modules/rtp_rtcp/include/rtcp_statistics.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "modules/rtp_rtcp/source/rtcp_nack_stats.h"
@@ -94,6 +95,11 @@
 
   // Get statistics.
   int32_t StatisticsReceived(std::vector<RTCPReportBlock>* receiveBlocks) const;
+  // A snapshot of Report Blocks with additional data of interest to statistics.
+  // Within this list, the sender-source SSRC pair is unique and per-pair the
+  // ReportBlockData represents the latest Report Block that was received for
+  // that pair.
+  std::vector<ReportBlockData> GetLatestReportBlockData() const;
 
   // Returns true if we haven't received an RTCP RR for several RTCP
   // intervals, but only triggers true once.
@@ -114,17 +120,17 @@
 
   void RegisterRtcpStatisticsCallback(RtcpStatisticsCallback* callback);
   RtcpStatisticsCallback* GetRtcpStatisticsCallback();
+  void SetReportBlockDataObserver(ReportBlockDataObserver* observer);
 
  private:
   struct PacketInformation;
   struct TmmbrInformation;
   struct RrtrInformation;
-  struct ReportBlockWithRtt;
   struct LastFirStatus;
   // RTCP report blocks mapped by remote SSRC.
-  using ReportBlockInfoMap = std::map<uint32_t, ReportBlockWithRtt>;
+  using ReportBlockDataMap = std::map<uint32_t, ReportBlockData>;
   // RTCP report blocks map mapped by source SSRC.
-  using ReportBlockMap = std::map<uint32_t, ReportBlockInfoMap>;
+  using ReportBlockMap = std::map<uint32_t, ReportBlockDataMap>;
 
   bool ParseCompoundPacket(const uint8_t* packet_begin,
                            const uint8_t* packet_end,
@@ -262,6 +268,11 @@
   int64_t last_increased_sequence_number_ms_;
 
   RtcpStatisticsCallback* stats_callback_ RTC_GUARDED_BY(feedbacks_lock_);
+  // TODO(hbos): Remove RtcpStatisticsCallback in favor of
+  // ReportBlockDataObserver; the ReportBlockData contains a superset of the
+  // RtcpStatistics data.
+  ReportBlockDataObserver* report_block_data_observer_
+      RTC_GUARDED_BY(feedbacks_lock_);
 
   RtcpPacketTypeCounterObserver* const packet_type_counter_observer_;
   RtcpPacketTypeCounter packet_type_counter_;
diff --git a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
index 332495d..c966470 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
+++ b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
@@ -11,8 +11,10 @@
 #include <memory>
 
 #include "api/array_view.h"
+#include "api/units/timestamp.h"
 #include "api/video/video_bitrate_allocation.h"
 #include "api/video/video_bitrate_allocator.h"
+#include "modules/rtp_rtcp/include/report_block_data.h"
 #include "modules/rtp_rtcp/mocks/mock_rtcp_bandwidth_observer.h"
 #include "modules/rtp_rtcp/source/byte_io.h"
 #include "modules/rtp_rtcp/source/rtcp_packet.h"
@@ -34,6 +36,7 @@
 #include "modules/rtp_rtcp/source/rtcp_receiver.h"
 #include "modules/rtp_rtcp/source/time_util.h"
 #include "rtc_base/arraysize.h"
+#include "rtc_base/fake_clock.h"
 #include "rtc_base/random.h"
 #include "system_wrappers/include/ntp_time.h"
 #include "test/gmock.h"
@@ -42,10 +45,12 @@
 namespace webrtc {
 namespace {
 
+using rtcp::ReceiveTimeInfo;
 using ::testing::_;
 using ::testing::AllOf;
 using ::testing::ElementsAreArray;
 using ::testing::Field;
+using ::testing::InSequence;
 using ::testing::IsEmpty;
 using ::testing::NiceMock;
 using ::testing::Property;
@@ -53,7 +58,6 @@
 using ::testing::StrEq;
 using ::testing::StrictMock;
 using ::testing::UnorderedElementsAre;
-using rtcp::ReceiveTimeInfo;
 
 class MockRtcpPacketTypeCounterObserver : public RtcpPacketTypeCounterObserver {
  public:
@@ -82,6 +86,11 @@
   MOCK_METHOD2(CNameChanged, void(const char*, uint32_t));
 };
 
+class MockReportBlockDataObserverImpl : public ReportBlockDataObserver {
+ public:
+  MOCK_METHOD1(OnReportBlockDataUpdated, void(ReportBlockData));
+};
+
 class MockTransportFeedbackObserver : public TransportFeedbackObserver {
  public:
   MOCK_METHOD1(OnAddPacket, void(const RtpPacketSendInfo&));
@@ -1176,6 +1185,201 @@
   InjectRtcpPacket(rr2);
 }
 
+TEST_F(RtcpReceiverTest,
+       VerifyBlockAndTimestampObtainedFromReportBlockDataObserver) {
+  MockReportBlockDataObserverImpl observer;
+  rtcp_receiver_.SetReportBlockDataObserver(&observer);
+
+  const uint8_t kFractionLoss = 3;
+  const uint32_t kCumulativeLoss = 7;
+  const uint32_t kJitter = 9;
+  const uint16_t kSequenceNumber = 1234;
+  const int64_t kUtcNowUs = 42;
+
+  // The "report_block_timestamp_utc_us" is obtained from the global UTC clock
+  // (not the simulcated |system_clock_|) and requires a scoped fake clock.
+  rtc::ScopedFakeClock fake_clock;
+  fake_clock.SetTime(Timestamp::us(kUtcNowUs));
+
+  rtcp::ReportBlock rtcp_block;
+  rtcp_block.SetMediaSsrc(kReceiverMainSsrc);
+  rtcp_block.SetExtHighestSeqNum(kSequenceNumber);
+  rtcp_block.SetFractionLost(kFractionLoss);
+  rtcp_block.SetCumulativeLost(kCumulativeLoss);
+  rtcp_block.SetJitter(kJitter);
+
+  rtcp::ReceiverReport rtcp_report;
+  rtcp_report.SetSenderSsrc(kSenderSsrc);
+  rtcp_report.AddReportBlock(rtcp_block);
+  EXPECT_CALL(observer, OnReportBlockDataUpdated)
+      .WillOnce([&](ReportBlockData report_block_data) {
+        const auto& report_block = report_block_data.report_block();
+        EXPECT_EQ(rtcp_block.source_ssrc(), report_block.source_ssrc);
+        EXPECT_EQ(kSenderSsrc, report_block.sender_ssrc);
+        EXPECT_EQ(rtcp_block.fraction_lost(), report_block.fraction_lost);
+        EXPECT_EQ(rtcp_block.cumulative_lost_signed(),
+                  report_block.packets_lost);
+        EXPECT_EQ(rtcp_block.extended_high_seq_num(),
+                  report_block.extended_highest_sequence_number);
+        EXPECT_EQ(rtcp_block.jitter(), report_block.jitter);
+        EXPECT_EQ(kUtcNowUs, report_block_data.report_block_timestamp_utc_us());
+        // No RTT is calculated in this test.
+        EXPECT_EQ(0u, report_block_data.num_rtts());
+      });
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks);
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport);
+  InjectRtcpPacket(rtcp_report);
+}
+
+TEST_F(RtcpReceiverTest, VerifyRttObtainedFromReportBlockDataObserver) {
+  MockReportBlockDataObserverImpl observer;
+  rtcp_receiver_.SetReportBlockDataObserver(&observer);
+
+  const int64_t kRttMs = 120;
+  const uint32_t kDelayNtp = 123000;
+  const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
+
+  uint32_t sent_ntp =
+      CompactNtp(TimeMicrosToNtp(system_clock_.TimeInMicroseconds()));
+  system_clock_.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
+
+  rtcp::SenderReport sr;
+  sr.SetSenderSsrc(kSenderSsrc);
+  rtcp::ReportBlock block;
+  block.SetMediaSsrc(kReceiverMainSsrc);
+  block.SetLastSr(sent_ntp);
+  block.SetDelayLastSr(kDelayNtp);
+  sr.AddReportBlock(block);
+  block.SetMediaSsrc(kReceiverExtraSsrc);
+  block.SetLastSr(0);
+  sr.AddReportBlock(block);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks);
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport);
+  InSequence sequence;
+  EXPECT_CALL(observer, OnReportBlockDataUpdated)
+      .WillOnce([&](ReportBlockData report_block_data) {
+        EXPECT_EQ(kReceiverMainSsrc,
+                  report_block_data.report_block().source_ssrc);
+        EXPECT_EQ(1u, report_block_data.num_rtts());
+        EXPECT_EQ(kRttMs, report_block_data.min_rtt_ms());
+        EXPECT_EQ(kRttMs, report_block_data.max_rtt_ms());
+        EXPECT_EQ(kRttMs, report_block_data.sum_rtt_ms());
+        EXPECT_EQ(kRttMs, report_block_data.last_rtt_ms());
+      });
+  EXPECT_CALL(observer, OnReportBlockDataUpdated)
+      .WillOnce([](ReportBlockData report_block_data) {
+        EXPECT_EQ(kReceiverExtraSsrc,
+                  report_block_data.report_block().source_ssrc);
+        EXPECT_EQ(0u, report_block_data.num_rtts());
+      });
+  InjectRtcpPacket(sr);
+}
+
+TEST_F(RtcpReceiverTest, GetReportBlockDataAfterOneReportBlock) {
+  const uint16_t kSequenceNumber = 1234;
+
+  rtcp::ReportBlock rtcp_block;
+  rtcp_block.SetMediaSsrc(kReceiverMainSsrc);
+  rtcp_block.SetExtHighestSeqNum(kSequenceNumber);
+
+  rtcp::ReceiverReport rtcp_report;
+  rtcp_report.SetSenderSsrc(kSenderSsrc);
+  rtcp_report.AddReportBlock(rtcp_block);
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks);
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport);
+  InjectRtcpPacket(rtcp_report);
+
+  auto report_block_datas = rtcp_receiver_.GetLatestReportBlockData();
+  ASSERT_THAT(report_block_datas, SizeIs(1));
+  EXPECT_EQ(kReceiverMainSsrc,
+            report_block_datas[0].report_block().source_ssrc);
+  EXPECT_EQ(
+      kSequenceNumber,
+      report_block_datas[0].report_block().extended_highest_sequence_number);
+}
+
+TEST_F(RtcpReceiverTest, GetReportBlockDataAfterTwoReportBlocksOfSameSsrc) {
+  const uint16_t kSequenceNumber1 = 1234;
+  const uint16_t kSequenceNumber2 = 1235;
+
+  rtcp::ReportBlock rtcp_block1;
+  rtcp_block1.SetMediaSsrc(kReceiverMainSsrc);
+  rtcp_block1.SetExtHighestSeqNum(kSequenceNumber1);
+
+  rtcp::ReceiverReport rtcp_report1;
+  rtcp_report1.SetSenderSsrc(kSenderSsrc);
+  rtcp_report1.AddReportBlock(rtcp_block1);
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks);
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport);
+  InjectRtcpPacket(rtcp_report1);
+
+  // Inject a report block with an increased the sequence number for the same
+  // source SSRC.
+  rtcp::ReportBlock rtcp_block2;
+  rtcp_block2.SetMediaSsrc(kReceiverMainSsrc);
+  rtcp_block2.SetExtHighestSeqNum(kSequenceNumber2);
+
+  rtcp::ReceiverReport rtcp_report2;
+  rtcp_report2.SetSenderSsrc(kSenderSsrc);
+  rtcp_report2.AddReportBlock(rtcp_block2);
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks);
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport);
+  InjectRtcpPacket(rtcp_report2);
+
+  // Only the latest block should be returned.
+  auto report_block_datas = rtcp_receiver_.GetLatestReportBlockData();
+  ASSERT_THAT(report_block_datas, SizeIs(1));
+  EXPECT_EQ(kReceiverMainSsrc,
+            report_block_datas[0].report_block().source_ssrc);
+  EXPECT_EQ(
+      kSequenceNumber2,
+      report_block_datas[0].report_block().extended_highest_sequence_number);
+}
+
+TEST_F(RtcpReceiverTest,
+       GetReportBlockDataAfterTwoReportBlocksOfDifferentSsrcs) {
+  const uint16_t kSequenceNumber1 = 1234;
+  const uint16_t kSequenceNumber2 = 42;
+
+  rtcp::ReportBlock rtcp_block1;
+  rtcp_block1.SetMediaSsrc(kReceiverMainSsrc);
+  rtcp_block1.SetExtHighestSeqNum(kSequenceNumber1);
+
+  rtcp::ReceiverReport rtcp_report1;
+  rtcp_report1.SetSenderSsrc(kSenderSsrc);
+  rtcp_report1.AddReportBlock(rtcp_block1);
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks);
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport);
+  InjectRtcpPacket(rtcp_report1);
+
+  // Inject a report block for a different source SSRC.
+  rtcp::ReportBlock rtcp_block2;
+  rtcp_block2.SetMediaSsrc(kReceiverExtraSsrc);
+  rtcp_block2.SetExtHighestSeqNum(kSequenceNumber2);
+
+  rtcp::ReceiverReport rtcp_report2;
+  rtcp_report2.SetSenderSsrc(kSenderSsrc);
+  rtcp_report2.AddReportBlock(rtcp_block2);
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks);
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport);
+  InjectRtcpPacket(rtcp_report2);
+
+  // Both report blocks should be returned.
+  auto report_block_datas = rtcp_receiver_.GetLatestReportBlockData();
+  ASSERT_THAT(report_block_datas, SizeIs(2));
+  EXPECT_EQ(kReceiverMainSsrc,
+            report_block_datas[0].report_block().source_ssrc);
+  EXPECT_EQ(
+      kSequenceNumber1,
+      report_block_datas[0].report_block().extended_highest_sequence_number);
+  EXPECT_EQ(kReceiverExtraSsrc,
+            report_block_datas[1].report_block().source_ssrc);
+  EXPECT_EQ(
+      kSequenceNumber2,
+      report_block_datas[1].report_block().extended_highest_sequence_number);
+}
+
 TEST_F(RtcpReceiverTest, ReceivesTransportFeedback) {
   rtcp::TransportFeedback packet;
   packet.SetMediaSsrc(kReceiverMainSsrc);