Parse XR, FIR and PLI in rtc_event_log_parser.cc

Bug: webrtc:10312
Change-Id: I1b24e23f8002feef8a2ef928130ac6da19c3cd81
Reviewed-on: https://webrtc-review.googlesource.com/c/122580
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Mirta Dvornicic <mirtad@webrtc.org>
Commit-Queue: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26670}
diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc
index b5a3a30..796c6d4 100644
--- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc
+++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc
@@ -813,6 +813,121 @@
   }
 }
 
+TEST_P(RtcEventLogEncoderTest, RtcEventRtcpExtendedReports) {
+  if (force_repeated_fields_) {
+    return;
+  }
+
+  rtc::ScopedFakeClock fake_clock;
+  fake_clock.SetTimeMicros(static_cast<int64_t>(prng_.Rand<uint32_t>()) * 1000);
+
+  for (auto direction : {kIncomingPacket, kOutgoingPacket}) {
+    std::vector<rtcp::ExtendedReports> events(event_count_);
+    std::vector<int64_t> timestamps_us(event_count_);
+    for (size_t i = 0; i < event_count_; ++i) {
+      timestamps_us[i] = rtc::TimeMicros();
+      events[i] = gen_.NewExtendedReports();
+      rtc::Buffer buffer = events[i].Build();
+      if (direction == kIncomingPacket) {
+        history_.push_back(
+            absl::make_unique<RtcEventRtcpPacketIncoming>(buffer));
+      } else {
+        history_.push_back(
+            absl::make_unique<RtcEventRtcpPacketOutgoing>(buffer));
+      }
+      fake_clock.AdvanceTimeMicros(prng_.Rand(0, 1000) * 1000);
+    }
+
+    std::string encoded =
+        encoder_->EncodeBatch(history_.begin(), history_.end());
+    ASSERT_TRUE(parsed_log_.ParseString(encoded));
+
+    const auto& extended_reports = parsed_log_.extended_reports(direction);
+    ASSERT_EQ(extended_reports.size(), event_count_);
+
+    for (size_t i = 0; i < event_count_; ++i) {
+      verifier_.VerifyLoggedExtendedReports(timestamps_us[i], events[i],
+                                            extended_reports[i]);
+    }
+  }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRtcpFir) {
+  if (force_repeated_fields_) {
+    return;
+  }
+
+  rtc::ScopedFakeClock fake_clock;
+  fake_clock.SetTimeMicros(static_cast<int64_t>(prng_.Rand<uint32_t>()) * 1000);
+
+  for (auto direction : {kIncomingPacket, kOutgoingPacket}) {
+    std::vector<rtcp::Fir> events(event_count_);
+    std::vector<int64_t> timestamps_us(event_count_);
+    for (size_t i = 0; i < event_count_; ++i) {
+      timestamps_us[i] = rtc::TimeMicros();
+      events[i] = gen_.NewFir();
+      rtc::Buffer buffer = events[i].Build();
+      if (direction == kIncomingPacket) {
+        history_.push_back(
+            absl::make_unique<RtcEventRtcpPacketIncoming>(buffer));
+      } else {
+        history_.push_back(
+            absl::make_unique<RtcEventRtcpPacketOutgoing>(buffer));
+      }
+      fake_clock.AdvanceTimeMicros(prng_.Rand(0, 1000) * 1000);
+    }
+
+    std::string encoded =
+        encoder_->EncodeBatch(history_.begin(), history_.end());
+    ASSERT_TRUE(parsed_log_.ParseString(encoded));
+
+    const auto& firs = parsed_log_.firs(direction);
+    ASSERT_EQ(firs.size(), event_count_);
+
+    for (size_t i = 0; i < event_count_; ++i) {
+      verifier_.VerifyLoggedFir(timestamps_us[i], events[i], firs[i]);
+    }
+  }
+}
+
+TEST_P(RtcEventLogEncoderTest, RtcEventRtcpPli) {
+  if (force_repeated_fields_) {
+    return;
+  }
+
+  rtc::ScopedFakeClock fake_clock;
+  fake_clock.SetTimeMicros(static_cast<int64_t>(prng_.Rand<uint32_t>()) * 1000);
+
+  for (auto direction : {kIncomingPacket, kOutgoingPacket}) {
+    std::vector<rtcp::Pli> events(event_count_);
+    std::vector<int64_t> timestamps_us(event_count_);
+    for (size_t i = 0; i < event_count_; ++i) {
+      timestamps_us[i] = rtc::TimeMicros();
+      events[i] = gen_.NewPli();
+      rtc::Buffer buffer = events[i].Build();
+      if (direction == kIncomingPacket) {
+        history_.push_back(
+            absl::make_unique<RtcEventRtcpPacketIncoming>(buffer));
+      } else {
+        history_.push_back(
+            absl::make_unique<RtcEventRtcpPacketOutgoing>(buffer));
+      }
+      fake_clock.AdvanceTimeMicros(prng_.Rand(0, 1000) * 1000);
+    }
+
+    std::string encoded =
+        encoder_->EncodeBatch(history_.begin(), history_.end());
+    ASSERT_TRUE(parsed_log_.ParseString(encoded));
+
+    const auto& plis = parsed_log_.plis(direction);
+    ASSERT_EQ(plis.size(), event_count_);
+
+    for (size_t i = 0; i < event_count_; ++i) {
+      verifier_.VerifyLoggedPli(timestamps_us[i], events[i], plis[i]);
+    }
+  }
+}
+
 TEST_P(RtcEventLogEncoderTest, RtcEventRtcpNack) {
   if (force_repeated_fields_) {
     return;
diff --git a/logging/rtc_event_log/logged_events.h b/logging/rtc_event_log/logged_events.h
index 6fe6fe4..5bbfa53 100644
--- a/logging/rtc_event_log/logged_events.h
+++ b/logging/rtc_event_log/logged_events.h
@@ -25,8 +25,11 @@
 #include "logging/rtc_event_log/rtc_stream_config.h"
 #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
 #include "modules/remote_bitrate_estimator/include/bwe_defines.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/loss_notification.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/remb.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
@@ -334,6 +337,16 @@
   rtcp::SenderReport sr;
 };
 
+struct LoggedRtcpPacketExtendedReports {
+  LoggedRtcpPacketExtendedReports() = default;
+
+  int64_t log_time_us() const { return timestamp_us; }
+  int64_t log_time_ms() const { return timestamp_us / 1000; }
+
+  int64_t timestamp_us;
+  rtcp::ExtendedReports xr;
+};
+
 struct LoggedRtcpPacketRemb {
   LoggedRtcpPacketRemb() = default;
   LoggedRtcpPacketRemb(int64_t timestamp_us, const rtcp::Remb& remb)
@@ -358,6 +371,26 @@
   rtcp::Nack nack;
 };
 
+struct LoggedRtcpPacketFir {
+  LoggedRtcpPacketFir() = default;
+
+  int64_t log_time_us() const { return timestamp_us; }
+  int64_t log_time_ms() const { return timestamp_us / 1000; }
+
+  int64_t timestamp_us;
+  rtcp::Fir fir;
+};
+
+struct LoggedRtcpPacketPli {
+  LoggedRtcpPacketPli() = default;
+
+  int64_t log_time_us() const { return timestamp_us; }
+  int64_t log_time_ms() const { return timestamp_us / 1000; }
+
+  int64_t timestamp_us;
+  rtcp::Pli pli;
+};
+
 struct LoggedRtcpPacketTransportFeedback {
   LoggedRtcpPacketTransportFeedback() = default;
   LoggedRtcpPacketTransportFeedback(
diff --git a/logging/rtc_event_log/rtc_event_log_parser.cc b/logging/rtc_event_log/rtc_event_log_parser.cc
index 1bf99d2..3579f8e 100644
--- a/logging/rtc_event_log/rtc_event_log_parser.cc
+++ b/logging/rtc_event_log/rtc_event_log_parser.cc
@@ -803,11 +803,14 @@
     int64_t timestamp_us,
     const uint8_t* packet_begin,
     const uint8_t* packet_end,
-    std::vector<LoggedRtcpPacketTransportFeedback>* transport_feedback_list,
     std::vector<LoggedRtcpPacketSenderReport>* sr_list,
     std::vector<LoggedRtcpPacketReceiverReport>* rr_list,
+    std::vector<LoggedRtcpPacketExtendedReports>* xr_list,
     std::vector<LoggedRtcpPacketRemb>* remb_list,
     std::vector<LoggedRtcpPacketNack>* nack_list,
+    std::vector<LoggedRtcpPacketFir>* fir_list,
+    std::vector<LoggedRtcpPacketPli>* pli_list,
+    std::vector<LoggedRtcpPacketTransportFeedback>* transport_feedback_list,
     std::vector<LoggedRtcpPacketLossNotification>* loss_notification_list) {
   rtcp::CommonHeader header;
   for (const uint8_t* block = packet_begin; block < packet_end;
@@ -831,6 +834,26 @@
       if (parsed_block.rr.Parse(header)) {
         rr_list->push_back(std::move(parsed_block));
       }
+    } else if (header.type() == rtcp::ExtendedReports::kPacketType) {
+      LoggedRtcpPacketExtendedReports parsed_block;
+      parsed_block.timestamp_us = timestamp_us;
+      if (parsed_block.xr.Parse(header)) {
+        xr_list->push_back(std::move(parsed_block));
+      }
+    } else if (header.type() == rtcp::Fir::kPacketType &&
+               header.fmt() == rtcp::Fir::kFeedbackMessageType) {
+      LoggedRtcpPacketFir parsed_block;
+      parsed_block.timestamp_us = timestamp_us;
+      if (parsed_block.fir.Parse(header)) {
+        fir_list->push_back(std::move(parsed_block));
+      }
+    } else if (header.type() == rtcp::Pli::kPacketType &&
+               header.fmt() == rtcp::Pli::kFeedbackMessageType) {
+      LoggedRtcpPacketPli parsed_block;
+      parsed_block.timestamp_us = timestamp_us;
+      if (parsed_block.pli.Parse(header)) {
+        pli_list->push_back(std::move(parsed_block));
+      }
     } else if (header.type() == rtcp::Remb::kPacketType &&
                header.fmt() == rtcp::Remb::kFeedbackMessageType) {
       bool type_found = false;
@@ -1088,9 +1111,10 @@
     const int64_t timestamp_us = incoming.rtcp.timestamp_us;
     const uint8_t* packet_begin = incoming.rtcp.raw_data.data();
     const uint8_t* packet_end = packet_begin + incoming.rtcp.raw_data.size();
-    StoreRtcpBlocks(timestamp_us, packet_begin, packet_end,
-                    &incoming_transport_feedback_, &incoming_sr_, &incoming_rr_,
-                    &incoming_remb_, &incoming_nack_,
+    StoreRtcpBlocks(timestamp_us, packet_begin, packet_end, &incoming_sr_,
+                    &incoming_rr_, &incoming_xr_, &incoming_remb_,
+                    &incoming_nack_, &incoming_fir_, &incoming_pli_,
+                    &incoming_transport_feedback_,
                     &incoming_loss_notification_);
   }
 
@@ -1098,9 +1122,10 @@
     const int64_t timestamp_us = outgoing.rtcp.timestamp_us;
     const uint8_t* packet_begin = outgoing.rtcp.raw_data.data();
     const uint8_t* packet_end = packet_begin + outgoing.rtcp.raw_data.size();
-    StoreRtcpBlocks(timestamp_us, packet_begin, packet_end,
-                    &outgoing_transport_feedback_, &outgoing_sr_, &outgoing_rr_,
-                    &outgoing_remb_, &outgoing_nack_,
+    StoreRtcpBlocks(timestamp_us, packet_begin, packet_end, &outgoing_sr_,
+                    &outgoing_rr_, &outgoing_xr_, &outgoing_remb_,
+                    &outgoing_nack_, &outgoing_fir_, &outgoing_pli_,
+                    &outgoing_transport_feedback_,
                     &outgoing_loss_notification_);
   }
 
diff --git a/logging/rtc_event_log/rtc_event_log_parser.h b/logging/rtc_event_log/rtc_event_log_parser.h
index 3ed5d41..ad5d98f 100644
--- a/logging/rtc_event_log/rtc_event_log_parser.h
+++ b/logging/rtc_event_log/rtc_event_log_parser.h
@@ -434,6 +434,15 @@
     }
   }
 
+  const std::vector<LoggedRtcpPacketExtendedReports>& extended_reports(
+      PacketDirection direction) const {
+    if (direction == kIncomingPacket) {
+      return incoming_xr_;
+    } else {
+      return outgoing_xr_;
+    }
+  }
+
   const std::vector<LoggedRtcpPacketNack>& nacks(
       PacketDirection direction) const {
     if (direction == kIncomingPacket) {
@@ -452,6 +461,24 @@
     }
   }
 
+  const std::vector<LoggedRtcpPacketFir>& firs(
+      PacketDirection direction) const {
+    if (direction == kIncomingPacket) {
+      return incoming_fir_;
+    } else {
+      return outgoing_fir_;
+    }
+  }
+
+  const std::vector<LoggedRtcpPacketPli>& plis(
+      PacketDirection direction) const {
+    if (direction == kIncomingPacket) {
+      return incoming_pli_;
+    } else {
+      return outgoing_pli_;
+    }
+  }
+
   const std::vector<LoggedRtcpPacketTransportFeedback>& transport_feedbacks(
       PacketDirection direction) const {
     if (direction == kIncomingPacket) {
@@ -653,10 +680,16 @@
   std::vector<LoggedRtcpPacketReceiverReport> outgoing_rr_;
   std::vector<LoggedRtcpPacketSenderReport> incoming_sr_;
   std::vector<LoggedRtcpPacketSenderReport> outgoing_sr_;
+  std::vector<LoggedRtcpPacketExtendedReports> incoming_xr_;
+  std::vector<LoggedRtcpPacketExtendedReports> outgoing_xr_;
   std::vector<LoggedRtcpPacketNack> incoming_nack_;
   std::vector<LoggedRtcpPacketNack> outgoing_nack_;
   std::vector<LoggedRtcpPacketRemb> incoming_remb_;
   std::vector<LoggedRtcpPacketRemb> outgoing_remb_;
+  std::vector<LoggedRtcpPacketFir> incoming_fir_;
+  std::vector<LoggedRtcpPacketFir> outgoing_fir_;
+  std::vector<LoggedRtcpPacketPli> incoming_pli_;
+  std::vector<LoggedRtcpPacketPli> outgoing_pli_;
   std::vector<LoggedRtcpPacketTransportFeedback> incoming_transport_feedback_;
   std::vector<LoggedRtcpPacketTransportFeedback> outgoing_transport_feedback_;
   std::vector<LoggedRtcpPacketLossNotification> incoming_loss_notification_;
diff --git a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
index 10dd414..651e023 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
+++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
@@ -29,6 +29,9 @@
 #include "modules/remote_bitrate_estimator/include/bwe_defines.h"
 #include "modules/rtp_rtcp/include/rtp_cvo.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/rrtr.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h"
 #include "modules/rtp_rtcp/source/rtp_header_extensions.h"
 #include "modules/rtp_rtcp/source/rtp_packet_received.h"
 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
@@ -258,6 +261,29 @@
   return receiver_report;
 }
 
+rtcp::ExtendedReports EventGenerator::NewExtendedReports() {
+  rtcp::ExtendedReports extended_report;
+  extended_report.SetSenderSsrc(prng_.Rand<uint32_t>());
+
+  rtcp::Rrtr rrtr;
+  rrtr.SetNtp(NtpTime(prng_.Rand<uint32_t>(), prng_.Rand<uint32_t>()));
+  extended_report.SetRrtr(rrtr);
+
+  rtcp::ReceiveTimeInfo time_info(
+      prng_.Rand<uint32_t>(), prng_.Rand<uint32_t>(), prng_.Rand<uint32_t>());
+  extended_report.AddDlrrItem(time_info);
+
+  rtcp::TargetBitrate target_bitrate;
+  target_bitrate.AddTargetBitrate(/*spatial layer*/ prng_.Rand(0, 3),
+                                  /*temporal layer*/ prng_.Rand(0, 3),
+                                  /*bitrate kbps*/ prng_.Rand(0, 50000));
+  target_bitrate.AddTargetBitrate(/*spatial layer*/ prng_.Rand(4, 7),
+                                  /*temporal layer*/ prng_.Rand(4, 7),
+                                  /*bitrate kbps*/ prng_.Rand(0, 50000));
+  extended_report.SetTargetBitrate(target_bitrate);
+  return extended_report;
+}
+
 rtcp::Nack EventGenerator::NewNack() {
   rtcp::Nack nack;
   uint16_t base_seq_no = prng_.Rand<uint16_t>();
@@ -271,6 +297,23 @@
   return nack;
 }
 
+rtcp::Fir EventGenerator::NewFir() {
+  rtcp::Fir fir;
+  fir.SetSenderSsrc(prng_.Rand<uint32_t>());
+  fir.AddRequestTo(/*ssrc*/ prng_.Rand<uint32_t>(),
+                   /*seq num*/ prng_.Rand<uint8_t>());
+  fir.AddRequestTo(/*ssrc*/ prng_.Rand<uint32_t>(),
+                   /*seq num*/ prng_.Rand<uint8_t>());
+  return fir;
+}
+
+rtcp::Pli EventGenerator::NewPli() {
+  rtcp::Pli pli;
+  pli.SetSenderSsrc(prng_.Rand<uint32_t>());
+  pli.SetMediaSsrc(prng_.Rand<uint32_t>());
+  return pli;
+}
+
 rtcp::TransportFeedback EventGenerator::NewTransportFeedback() {
   rtcp::TransportFeedback transport_feedback;
   uint16_t base_seq_no = prng_.Rand<uint16_t>();
@@ -312,6 +355,9 @@
   enum class SupportedRtcpTypes {
     kSenderReport = 0,
     kReceiverReport,
+    kExtendedReports,
+    kFir,
+    kPli,
     kNack,
     kRemb,
     kTransportFeedback,
@@ -330,6 +376,21 @@
       rtc::Buffer buffer = receiver_report.Build();
       return absl::make_unique<RtcEventRtcpPacketIncoming>(buffer);
     }
+    case SupportedRtcpTypes::kExtendedReports: {
+      rtcp::ExtendedReports extended_report = NewExtendedReports();
+      rtc::Buffer buffer = extended_report.Build();
+      return absl::make_unique<RtcEventRtcpPacketIncoming>(buffer);
+    }
+    case SupportedRtcpTypes::kFir: {
+      rtcp::Fir fir = NewFir();
+      rtc::Buffer buffer = fir.Build();
+      return absl::make_unique<RtcEventRtcpPacketIncoming>(buffer);
+    }
+    case SupportedRtcpTypes::kPli: {
+      rtcp::Pli pli = NewPli();
+      rtc::Buffer buffer = pli.Build();
+      return absl::make_unique<RtcEventRtcpPacketIncoming>(buffer);
+    }
     case SupportedRtcpTypes::kNack: {
       rtcp::Nack nack = NewNack();
       rtc::Buffer buffer = nack.Build();
@@ -357,6 +418,9 @@
   enum class SupportedRtcpTypes {
     kSenderReport = 0,
     kReceiverReport,
+    kExtendedReports,
+    kFir,
+    kPli,
     kNack,
     kRemb,
     kTransportFeedback,
@@ -375,6 +439,21 @@
       rtc::Buffer buffer = receiver_report.Build();
       return absl::make_unique<RtcEventRtcpPacketOutgoing>(buffer);
     }
+    case SupportedRtcpTypes::kExtendedReports: {
+      rtcp::ExtendedReports extended_report = NewExtendedReports();
+      rtc::Buffer buffer = extended_report.Build();
+      return absl::make_unique<RtcEventRtcpPacketOutgoing>(buffer);
+    }
+    case SupportedRtcpTypes::kFir: {
+      rtcp::Fir fir = NewFir();
+      rtc::Buffer buffer = fir.Build();
+      return absl::make_unique<RtcEventRtcpPacketOutgoing>(buffer);
+    }
+    case SupportedRtcpTypes::kPli: {
+      rtcp::Pli pli = NewPli();
+      rtc::Buffer buffer = pli.Build();
+      return absl::make_unique<RtcEventRtcpPacketOutgoing>(buffer);
+    }
     case SupportedRtcpTypes::kNack: {
       rtcp::Nack nack = NewNack();
       rtc::Buffer buffer = nack.Build();
@@ -984,6 +1063,68 @@
   }
 }
 
+void EventVerifier::VerifyLoggedExtendedReports(
+    int64_t log_time_us,
+    const rtcp::ExtendedReports& original_xr,
+    const LoggedRtcpPacketExtendedReports& logged_xr) {
+  EXPECT_EQ(original_xr.sender_ssrc(), logged_xr.xr.sender_ssrc());
+
+  EXPECT_EQ(original_xr.rrtr().has_value(), logged_xr.xr.rrtr().has_value());
+  if (original_xr.rrtr().has_value() && logged_xr.xr.rrtr().has_value()) {
+    EXPECT_EQ(original_xr.rrtr()->ntp(), logged_xr.xr.rrtr()->ntp());
+  }
+
+  const auto& original_subblocks = original_xr.dlrr().sub_blocks();
+  const auto& logged_subblocks = logged_xr.xr.dlrr().sub_blocks();
+  ASSERT_EQ(original_subblocks.size(), logged_subblocks.size());
+  for (size_t i = 0; i < original_subblocks.size(); i++) {
+    EXPECT_EQ(original_subblocks[i].ssrc, logged_subblocks[i].ssrc);
+    EXPECT_EQ(original_subblocks[i].last_rr, logged_subblocks[i].last_rr);
+    EXPECT_EQ(original_subblocks[i].delay_since_last_rr,
+              logged_subblocks[i].delay_since_last_rr);
+  }
+
+  EXPECT_EQ(original_xr.target_bitrate().has_value(),
+            logged_xr.xr.target_bitrate().has_value());
+  if (original_xr.target_bitrate().has_value() &&
+      logged_xr.xr.target_bitrate().has_value()) {
+    const auto& original_bitrates =
+        original_xr.target_bitrate()->GetTargetBitrates();
+    const auto& logged_bitrates =
+        logged_xr.xr.target_bitrate()->GetTargetBitrates();
+    ASSERT_EQ(original_bitrates.size(), logged_bitrates.size());
+    for (size_t i = 0; i < original_bitrates.size(); i++) {
+      EXPECT_EQ(original_bitrates[i].spatial_layer,
+                logged_bitrates[i].spatial_layer);
+      EXPECT_EQ(original_bitrates[i].temporal_layer,
+                logged_bitrates[i].temporal_layer);
+      EXPECT_EQ(original_bitrates[i].target_bitrate_kbps,
+                logged_bitrates[i].target_bitrate_kbps);
+    }
+  }
+}
+
+void EventVerifier::VerifyLoggedFir(int64_t log_time_us,
+                                    const rtcp::Fir& original_fir,
+                                    const LoggedRtcpPacketFir& logged_fir) {
+  EXPECT_EQ(original_fir.sender_ssrc(), logged_fir.fir.sender_ssrc());
+
+  const auto& original_requests = original_fir.requests();
+  const auto& logged_requests = logged_fir.fir.requests();
+  ASSERT_EQ(original_requests.size(), logged_requests.size());
+  for (size_t i = 0; i < original_requests.size(); i++) {
+    EXPECT_EQ(original_requests[i].ssrc, logged_requests[i].ssrc);
+    EXPECT_EQ(original_requests[i].seq_nr, logged_requests[i].seq_nr);
+  }
+}
+
+void EventVerifier::VerifyLoggedPli(int64_t log_time_us,
+                                    const rtcp::Pli& original_pli,
+                                    const LoggedRtcpPacketPli& logged_pli) {
+  EXPECT_EQ(original_pli.sender_ssrc(), logged_pli.pli.sender_ssrc());
+  EXPECT_EQ(original_pli.media_ssrc(), logged_pli.pli.media_ssrc());
+}
+
 void EventVerifier::VerifyLoggedNack(int64_t log_time_us,
                                      const rtcp::Nack& original_nack,
                                      const LoggedRtcpPacketNack& logged_nack) {
diff --git a/logging/rtc_event_log/rtc_event_log_unittest_helper.h b/logging/rtc_event_log/rtc_event_log_unittest_helper.h
index b0e5117..ec03694 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest_helper.h
+++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.h
@@ -41,8 +41,13 @@
 #include "logging/rtc_event_log/rtc_event_log_parser.h"
 #include "logging/rtc_event_log/rtc_stream_config.h"
 #include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/loss_notification.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/remb.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
 #include "modules/rtp_rtcp/source/rtp_packet.h"
@@ -57,31 +62,18 @@
   explicit EventGenerator(uint64_t seed) : prng_(seed) {}
 
   std::unique_ptr<RtcEventAlrState> NewAlrState();
-
   std::unique_ptr<RtcEventAudioPlayout> NewAudioPlayout(uint32_t ssrc);
-
   std::unique_ptr<RtcEventAudioNetworkAdaptation> NewAudioNetworkAdaptation();
-
   std::unique_ptr<RtcEventBweUpdateDelayBased> NewBweUpdateDelayBased();
-
   std::unique_ptr<RtcEventBweUpdateLossBased> NewBweUpdateLossBased();
-
   std::unique_ptr<RtcEventDtlsTransportState> NewDtlsTransportState();
-
   std::unique_ptr<RtcEventDtlsWritableState> NewDtlsWritableState();
-
   std::unique_ptr<RtcEventProbeClusterCreated> NewProbeClusterCreated();
-
   std::unique_ptr<RtcEventProbeResultFailure> NewProbeResultFailure();
-
   std::unique_ptr<RtcEventProbeResultSuccess> NewProbeResultSuccess();
-
   std::unique_ptr<RtcEventIceCandidatePairConfig> NewIceCandidatePairConfig();
-
   std::unique_ptr<RtcEventIceCandidatePair> NewIceCandidatePair();
-
   std::unique_ptr<RtcEventRtcpPacketIncoming> NewRtcpPacketIncoming();
-
   std::unique_ptr<RtcEventRtcpPacketOutgoing> NewRtcpPacketOutgoing();
 
   std::unique_ptr<RtcEventGenericPacketSent> NewGenericPacketSent();
@@ -90,9 +82,12 @@
 
   rtcp::SenderReport NewSenderReport();
   rtcp::ReceiverReport NewReceiverReport();
+  rtcp::ExtendedReports NewExtendedReports();
   rtcp::Nack NewNack();
-  rtcp::TransportFeedback NewTransportFeedback();
   rtcp::Remb NewRemb();
+  rtcp::Fir NewFir();
+  rtcp::Pli NewPli();
+  rtcp::TransportFeedback NewTransportFeedback();
   rtcp::LossNotification NewLossNotification();
 
   // |all_configured_exts| determines whether the RTP packet exhibits all
@@ -253,6 +248,16 @@
       int64_t log_time_us,
       const rtcp::ReceiverReport& original_rr,
       const LoggedRtcpPacketReceiverReport& logged_rr);
+  void VerifyLoggedExtendedReports(
+      int64_t log_time_us,
+      const rtcp::ExtendedReports& original_xr,
+      const LoggedRtcpPacketExtendedReports& logged_xr);
+  void VerifyLoggedFir(int64_t log_time_us,
+                       const rtcp::Fir& original_fir,
+                       const LoggedRtcpPacketFir& logged_fir);
+  void VerifyLoggedPli(int64_t log_time_us,
+                       const rtcp::Pli& original_pli,
+                       const LoggedRtcpPacketPli& logged_pli);
   void VerifyLoggedNack(int64_t log_time_us,
                         const rtcp::Nack& original_nack,
                         const LoggedRtcpPacketNack& logged_nack);
diff --git a/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc b/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc
index 2b5f9ca..561503a 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc
@@ -44,7 +44,8 @@
 //  :             type-specific block contents                      :
 //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 ExtendedReports::ExtendedReports() : sender_ssrc_(0) {}
-ExtendedReports::~ExtendedReports() {}
+ExtendedReports::ExtendedReports(const ExtendedReports& xr) = default;
+ExtendedReports::~ExtendedReports() = default;
 
 bool ExtendedReports::Parse(const CommonHeader& packet) {
   RTC_DCHECK_EQ(packet.type(), kPacketType);
diff --git a/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h b/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h
index fd96769..4ae652c 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h
+++ b/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h
@@ -30,6 +30,7 @@
   static constexpr size_t kMaxNumberOfDlrrItems = 50;
 
   ExtendedReports();
+  ExtendedReports(const ExtendedReports& xr);
   ~ExtendedReports() override;
 
   // Parse assumes header is already parsed and validated.
diff --git a/modules/rtp_rtcp/source/rtcp_packet/fir.cc b/modules/rtp_rtcp/source/rtcp_packet/fir.cc
index 517e991..fd4a4c9 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/fir.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet/fir.cc
@@ -46,6 +46,8 @@
 
 Fir::Fir() = default;
 
+Fir::Fir(const Fir& fir) = default;
+
 Fir::~Fir() = default;
 
 bool Fir::Parse(const CommonHeader& packet) {
diff --git a/modules/rtp_rtcp/source/rtcp_packet/fir.h b/modules/rtp_rtcp/source/rtcp_packet/fir.h
index 6fbc54c..383dc96 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/fir.h
+++ b/modules/rtp_rtcp/source/rtcp_packet/fir.h
@@ -30,6 +30,7 @@
   };
 
   Fir();
+  Fir(const Fir& fir);
   ~Fir() override;
 
   // Parse assumes header is already parsed and validated.
diff --git a/modules/rtp_rtcp/source/rtcp_packet/pli.cc b/modules/rtp_rtcp/source/rtcp_packet/pli.cc
index 274eb6b..5b41aa5 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/pli.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet/pli.cc
@@ -33,6 +33,12 @@
 //  :            Feedback Control Information (FCI)                 :
 //  :                                                               :
 
+Pli::Pli() = default;
+
+Pli::Pli(const Pli& pli) = default;
+
+Pli::~Pli() = default;
+
 //
 // Picture loss indication (PLI) (RFC 4585).
 // FCI: no feedback control information.
diff --git a/modules/rtp_rtcp/source/rtcp_packet/pli.h b/modules/rtp_rtcp/source/rtcp_packet/pli.h
index fc3c20a..b9b9c45 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/pli.h
+++ b/modules/rtp_rtcp/source/rtcp_packet/pli.h
@@ -20,8 +20,9 @@
  public:
   static constexpr uint8_t kFeedbackMessageType = 1;
 
-  Pli() {}
-  ~Pli() override {}
+  Pli();
+  Pli(const Pli& pli);
+  ~Pli() override;
 
   bool Parse(const CommonHeader& packet);