Use DD encoder/decoder in RTC event log encoder/parser.

Bug: webrtc:14801
Change-Id: I7013c42765e81d147bf8284f8c29666e67fdb91f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/296765
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Commit-Queue: Philip Eliasson <philipel@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39929}
diff --git a/logging/BUILD.gn b/logging/BUILD.gn
index 71cb413..c7b020f 100644
--- a/logging/BUILD.gn
+++ b/logging/BUILD.gn
@@ -625,6 +625,8 @@
         "../rtc_base:rtc_base_tests_utils",
         "../rtc_base:timeutils",
         "../system_wrappers",
+        "../system_wrappers:field_trial",
+        "../test:field_trial",
         "../test:fileutils",
         "../test:test_support",
         "../test/logging:log_writer",
diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc
index 2e02f68..5d83c72 100644
--- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc
+++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc
@@ -13,6 +13,7 @@
 #include "absl/types/optional.h"
 #include "api/array_view.h"
 #include "api/network_state_predictor.h"
+#include "logging/rtc_event_log/dependency_descriptor_encoder_decoder.h"
 #include "logging/rtc_event_log/encoder/blob_encoding.h"
 #include "logging/rtc_event_log/encoder/delta_encoding.h"
 #include "logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h"
@@ -56,6 +57,7 @@
 #include "modules/rtp_rtcp/source/rtcp_packet/rtpfb.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
+#include "modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h"
 #include "modules/rtp_rtcp/source/rtp_header_extensions.h"
 #include "modules/rtp_rtcp/source/rtp_packet.h"
 #include "rtc_base/checks.h"
@@ -147,6 +149,8 @@
       proto_config->set_transport_sequence_number_id(extension.id);
     } else if (extension.uri == RtpExtension::kVideoRotationUri) {
       proto_config->set_video_rotation_id(extension.id);
+    } else if (extension.uri == RtpExtension::kDependencyDescriptorUri) {
+      proto_config->set_dependency_descriptor_id(extension.id);
     } else {
       ++unknown_extensions;
     }
@@ -457,6 +461,29 @@
     }
   }
 
+  {
+    // TODO(webrtc:14975) Remove this kill switch after DD in RTC event log has
+    //                    been rolled out.
+    if (!webrtc::field_trial::IsDisabled(
+            "WebRTC-RtcEventLogEncodeDependencyDescriptor")) {
+      std::vector<rtc::ArrayView<const uint8_t>> raw_dds(batch.size());
+      bool has_dd = false;
+      for (size_t i = 0; i < batch.size(); ++i) {
+        raw_dds[i] =
+            batch[i]
+                ->template GetRawExtension<RtpDependencyDescriptorExtension>();
+        has_dd |= !raw_dds[i].empty();
+      }
+      if (has_dd) {
+        if (auto dd_encoded =
+                RtcEventLogDependencyDescriptorEncoderDecoder::Encode(
+                    raw_dds)) {
+          *proto_batch->mutable_dependency_descriptor() = *dd_encoded;
+        }
+      }
+    }
+  }
+
   if (batch.size() == 1) {
     return;
   }
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 7039fe7..612f85bf 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
@@ -40,6 +40,7 @@
 #include "modules/rtp_rtcp/source/rtp_header_extensions.h"
 #include "rtc_base/fake_clock.h"
 #include "rtc_base/random.h"
+#include "test/field_trial.h"
 #include "test/gtest.h"
 
 namespace webrtc {
@@ -1291,6 +1292,20 @@
   TestRtpPackets<RtcEventRtpPacketOutgoing, LoggedRtpPacketOutgoing>();
 }
 
+TEST_P(RtcEventLogEncoderTest,
+       RtcEventRtpPacketIncomingNoDependencyDescriptor) {
+  test::ScopedFieldTrials no_dd(
+      "WebRTC-RtcEventLogEncodeDependencyDescriptor/Disabled/");
+  TestRtpPackets<RtcEventRtpPacketIncoming, LoggedRtpPacketIncoming>();
+}
+
+TEST_P(RtcEventLogEncoderTest,
+       RtcEventRtpPacketOutgoingNoDependencyDescriptor) {
+  test::ScopedFieldTrials no_dd(
+      "WebRTC-RtcEventLogEncodeDependencyDescriptor/Disabled/");
+  TestRtpPackets<RtcEventRtpPacketOutgoing, LoggedRtpPacketOutgoing>();
+}
+
 // TODO(eladalon/terelius): Test with multiple events in the batch.
 TEST_P(RtcEventLogEncoderTest, RtcEventVideoReceiveStreamConfig) {
   uint32_t ssrc = prng_.Rand<uint32_t>();
diff --git a/logging/rtc_event_log/events/logged_rtp_rtcp.h b/logging/rtc_event_log/events/logged_rtp_rtcp.h
index c441dea..fe5fcfd 100644
--- a/logging/rtc_event_log/events/logged_rtp_rtcp.h
+++ b/logging/rtc_event_log/events/logged_rtp_rtcp.h
@@ -47,6 +47,8 @@
   Timestamp timestamp;
   // TODO(terelius): This allocates space for 15 CSRCs even if none are used.
   RTPHeader header;
+  // RTPHeader::extension is a mess, save DD wire format instead.
+  std::vector<uint8_t> dependency_descriptor_wire_format;
   size_t header_length;
   size_t total_length;
 };
diff --git a/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h b/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h
index 926dddd..66ea167 100644
--- a/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h
+++ b/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h
@@ -57,6 +57,10 @@
     return packet_.GetExtension<ExtensionTrait>(std::forward<Args>(args)...);
   }
   template <typename ExtensionTrait>
+  rtc::ArrayView<const uint8_t> GetRawExtension() const {
+    return packet_.GetRawExtension<ExtensionTrait>();
+  }
+  template <typename ExtensionTrait>
   bool HasExtension() const {
     return packet_.HasExtension<ExtensionTrait>();
   }
diff --git a/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h b/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h
index c7b7a09..4f4be04 100644
--- a/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h
+++ b/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h
@@ -58,6 +58,10 @@
     return packet_.GetExtension<ExtensionTrait>(std::forward<Args>(args)...);
   }
   template <typename ExtensionTrait>
+  rtc::ArrayView<const uint8_t> GetRawExtension() const {
+    return packet_.GetRawExtension<ExtensionTrait>();
+  }
+  template <typename ExtensionTrait>
   bool HasExtension() const {
     return packet_.HasExtension<ExtensionTrait>();
   }
diff --git a/logging/rtc_event_log/rtc_event_log2.proto b/logging/rtc_event_log/rtc_event_log2.proto
index 1cf5a06..658df6b 100644
--- a/logging/rtc_event_log/rtc_event_log2.proto
+++ b/logging/rtc_event_log/rtc_event_log2.proto
@@ -453,6 +453,7 @@
   optional int32 transport_sequence_number_id = 3;
   optional int32 video_rotation_id = 4;
   optional int32 audio_level_id = 5;
+  optional int32 dependency_descriptor_id = 6;
   // TODO(terelius): Add other header extensions like playout delay?
 }
 
diff --git a/logging/rtc_event_log/rtc_event_log_parser.cc b/logging/rtc_event_log/rtc_event_log_parser.cc
index a5e901d..75f2fde 100644
--- a/logging/rtc_event_log/rtc_event_log_parser.cc
+++ b/logging/rtc_event_log/rtc_event_log_parser.cc
@@ -25,6 +25,7 @@
 #include "api/rtc_event_log/rtc_event_log.h"
 #include "api/rtp_headers.h"
 #include "api/rtp_parameters.h"
+#include "logging/rtc_event_log/dependency_descriptor_encoder_decoder.h"
 #include "logging/rtc_event_log/encoder/blob_encoding.h"
 #include "logging/rtc_event_log/encoder/delta_encoding.h"
 #include "logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h"
@@ -35,6 +36,7 @@
 #include "modules/rtp_rtcp/include/rtp_cvo.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h"
 #include "modules/rtp_rtcp/source/rtp_header_extensions.h"
 #include "modules/rtp_rtcp/source/rtp_packet_received.h"
 #include "rtc_base/checks.h"
@@ -297,6 +299,22 @@
   RTC_PARSE_CHECK_OR_RETURN(proto.has_header_size());
   RTC_PARSE_CHECK_OR_RETURN(proto.has_padding_size());
 
+  const size_t number_of_deltas =
+      proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
+  const size_t total_packets = number_of_deltas + 1;
+
+  std::vector<std::vector<uint8_t>> dependency_descriptor_wire_format(
+      total_packets);
+  if (proto.has_dependency_descriptor()) {
+    auto status_or_decoded =
+        RtcEventLogDependencyDescriptorEncoderDecoder::Decode(
+            proto.dependency_descriptor(), total_packets);
+    if (!status_or_decoded.ok()) {
+      return status_or_decoded.status();
+    }
+    dependency_descriptor_wire_format = status_or_decoded.value();
+  }
+
   // Base event
   {
     RTPHeader header;
@@ -342,13 +360,16 @@
     } else {
       RTC_PARSE_CHECK_OR_RETURN(!proto.has_voice_activity());
     }
-    (*rtp_packets_map)[header.ssrc].emplace_back(
+    LoggedType logged_packet(
         Timestamp::Millis(proto.timestamp_ms()), header, proto.header_size(),
         proto.payload_size() + header.headerLength + header.paddingLength);
+    if (!dependency_descriptor_wire_format[0].empty()) {
+      logged_packet.rtp.dependency_descriptor_wire_format =
+          dependency_descriptor_wire_format[0];
+    }
+    (*rtp_packets_map)[header.ssrc].push_back(std::move(logged_packet));
   }
 
-  const size_t number_of_deltas =
-      proto.has_number_of_deltas() ? proto.number_of_deltas() : 0u;
   if (number_of_deltas == 0) {
     return ParsedRtcEventLog::ParseStatus::Success();
   }
@@ -544,10 +565,15 @@
       RTC_PARSE_CHECK_OR_RETURN(voice_activity_values.size() <= i ||
                                 !voice_activity_values[i].has_value());
     }
-    (*rtp_packets_map)[header.ssrc].emplace_back(
-        Timestamp::Millis(timestamp_ms), header, header.headerLength,
-        payload_size_values[i].value() + header.headerLength +
-            header.paddingLength);
+    LoggedType logged_packet(Timestamp::Millis(timestamp_ms), header,
+                             header.headerLength,
+                             payload_size_values[i].value() +
+                                 header.headerLength + header.paddingLength);
+    if (!dependency_descriptor_wire_format[i + 1].empty()) {
+      logged_packet.rtp.dependency_descriptor_wire_format =
+          dependency_descriptor_wire_format[i + 1];
+    }
+    (*rtp_packets_map)[header.ssrc].push_back(std::move(logged_packet));
   }
   return ParsedRtcEventLog::ParseStatus::Success();
 }
@@ -888,6 +914,11 @@
     rtp_extensions.emplace_back(RtpExtension::kVideoRotationUri,
                                 proto_header_extensions.video_rotation_id());
   }
+  if (proto_header_extensions.has_dependency_descriptor_id()) {
+    rtp_extensions.emplace_back(
+        RtpExtension::kDependencyDescriptorUri,
+        proto_header_extensions.dependency_descriptor_id());
+  }
   return rtp_extensions;
 }
 // End of conversion functions.
@@ -972,8 +1003,9 @@
   constexpr int kPlayoutDelayDefaultId = 6;
   constexpr int kVideoContentTypeDefaultId = 7;
   constexpr int kVideoTimingDefaultId = 8;
+  constexpr int kDependencyDescriptorDefaultId = 9;
 
-  webrtc::RtpHeaderExtensionMap default_map;
+  webrtc::RtpHeaderExtensionMap default_map(/*extmap_allow_mixed=*/true);
   default_map.Register<AudioLevel>(kAudioLevelDefaultId);
   default_map.Register<TransmissionOffset>(kTimestampOffsetDefaultId);
   default_map.Register<AbsoluteSendTime>(kAbsSendTimeDefaultId);
@@ -983,6 +1015,8 @@
   default_map.Register<PlayoutDelayLimits>(kPlayoutDelayDefaultId);
   default_map.Register<VideoContentTypeExtension>(kVideoContentTypeDefaultId);
   default_map.Register<VideoTimingExtension>(kVideoTimingDefaultId);
+  default_map.Register<RtpDependencyDescriptorExtension>(
+      kDependencyDescriptorDefaultId);
   return default_map;
 }
 
diff --git a/logging/rtc_event_log/rtc_event_log_unittest.cc b/logging/rtc_event_log/rtc_event_log_unittest.cc
index 314bfd9..3730a08 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest.cc
+++ b/logging/rtc_event_log/rtc_event_log_unittest.cc
@@ -45,6 +45,7 @@
 #include "logging/rtc_event_log/rtc_event_log_unittest_helper.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/rtp_dependency_descriptor_extension.h"
 #include "modules/rtp_rtcp/source/rtp_header_extensions.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/fake_clock.h"
@@ -228,7 +229,9 @@
     do {
       ssrc = prng_.Rand<uint32_t>();
     } while (SsrcUsed(ssrc, incoming_extensions_));
-    RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
+    RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap(
+        /*configure_all=*/false,
+        /*excluded_extensions=*/{RtpDependencyDescriptorExtension::kId});
     incoming_extensions_.emplace_back(ssrc, extensions);
     auto event = gen_.NewAudioReceiveStreamConfig(ssrc, extensions);
     event_log->Log(event->Copy());
@@ -245,7 +248,9 @@
     do {
       ssrc = prng_.Rand<uint32_t>();
     } while (SsrcUsed(ssrc, outgoing_extensions_));
-    RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
+    RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap(
+        /*configure_all=*/false,
+        /*excluded_extensions=*/{RtpDependencyDescriptorExtension::kId});
     outgoing_extensions_.emplace_back(ssrc, extensions);
     auto event = gen_.NewAudioSendStreamConfig(ssrc, extensions);
     event_log->Log(event->Copy());
@@ -263,6 +268,10 @@
   RtpHeaderExtensionMap all_extensions =
       ParsedRtcEventLog::GetDefaultHeaderExtensionMap();
 
+  if (std::get<2>(GetParam()) == RtcEventLog::EncodingType::Legacy) {
+    all_extensions.Deregister(RtpDependencyDescriptorExtension::Uri());
+  }
+
   clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
   uint32_t ssrc = prng_.Rand<uint32_t>();
   incoming_extensions_.emplace_back(ssrc, all_extensions);
@@ -274,7 +283,12 @@
     do {
       ssrc = prng_.Rand<uint32_t>();
     } while (SsrcUsed(ssrc, incoming_extensions_));
-    RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
+    std::vector<RTPExtensionType> excluded_extensions;
+    if (std::get<2>(GetParam()) == RtcEventLog::EncodingType::Legacy) {
+      excluded_extensions.push_back(RtpDependencyDescriptorExtension::kId);
+    }
+    RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap(
+        /*configure_all=*/false, excluded_extensions);
     incoming_extensions_.emplace_back(ssrc, extensions);
     auto new_event = gen_.NewVideoReceiveStreamConfig(ssrc, extensions);
     event_log->Log(new_event->Copy());
@@ -292,6 +306,10 @@
   RtpHeaderExtensionMap all_extensions =
       ParsedRtcEventLog::GetDefaultHeaderExtensionMap();
 
+  if (std::get<2>(GetParam()) == RtcEventLog::EncodingType::Legacy) {
+    all_extensions.Deregister(RtpDependencyDescriptorExtension::Uri());
+  }
+
   clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
   uint32_t ssrc = prng_.Rand<uint32_t>();
   outgoing_extensions_.emplace_back(ssrc, all_extensions);
@@ -303,7 +321,12 @@
     do {
       ssrc = prng_.Rand<uint32_t>();
     } while (SsrcUsed(ssrc, outgoing_extensions_));
-    RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
+    std::vector<RTPExtensionType> excluded_extensions;
+    if (std::get<2>(GetParam()) == RtcEventLog::EncodingType::Legacy) {
+      excluded_extensions.push_back(RtpDependencyDescriptorExtension::kId);
+    }
+    RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap(
+        /*configure_all=*/false, excluded_extensions);
     outgoing_extensions_.emplace_back(ssrc, extensions);
     auto event = gen_.NewVideoSendStreamConfig(ssrc, extensions);
     event_log->Log(event->Copy());
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 9d2e115..b378e8f 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
+++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
@@ -35,12 +35,14 @@
 #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_dependency_descriptor_extension.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"
 #include "rtc_base/buffer.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/time_utils.h"
+#include "system_wrappers/include/field_trial.h"
 #include "system_wrappers/include/ntp_time.h"
 #include "test/gtest.h"
 
@@ -58,8 +60,8 @@
 constexpr int kMaxCsrcs = 3;
 
 // Maximum serialized size of a header extension, including 1 byte ID.
-constexpr int kMaxExtensionSizeBytes = 4;
-constexpr int kMaxNumExtensions = 5;
+constexpr int kMaxExtensionSizeBytes = 10;
+constexpr int kMaxNumExtensions = 6;
 
 constexpr ExtensionPair kExtensions[kMaxNumExtensions] = {
     {RTPExtensionType::kRtpExtensionTransmissionTimeOffset,
@@ -70,7 +72,9 @@
      RtpExtension::kTransportSequenceNumberUri},
     {RTPExtensionType::kRtpExtensionAudioLevel, RtpExtension::kAudioLevelUri},
     {RTPExtensionType::kRtpExtensionVideoRotation,
-     RtpExtension::kVideoRotationUri}};
+     RtpExtension::kVideoRotationUri},
+    {RTPExtensionType::kRtpExtensionDependencyDescriptor,
+     RtpExtension::kDependencyDescriptorUri}};
 
 template <typename T>
 void ShuffleInPlace(Random* prng, rtc::ArrayView<T> array) {
@@ -614,6 +618,15 @@
     rtp_packet->SetExtension<TransportSequenceNumber>(prng_.Rand<uint16_t>());
   }
 
+  if (extension_map.IsRegistered(RtpDependencyDescriptorExtension::kId) &&
+      (all_configured_exts || prng_.Rand<bool>())) {
+    std::vector<uint8_t> raw_data(3 + prng_.Rand(6));
+    for (uint8_t& d : raw_data) {
+      d = prng_.Rand<uint8_t>();
+    }
+    rtp_packet->SetRawExtension<RtpDependencyDescriptorExtension>(raw_data);
+  }
+
   RTC_CHECK_LE(rtp_packet->headers_size() + payload_size, IP_PACKET_SIZE);
 
   uint8_t* payload = rtp_packet->AllocatePayload(payload_size);
@@ -675,8 +688,7 @@
                                                               1 - padding_size -
                                                               kMaxHeaderSize));
 
-  RtpPacketToSend rtp_packet(&extension_map,
-                             kMaxHeaderSize + payload_size + padding_size);
+  RtpPacketToSend rtp_packet(&extension_map);
   RandomizeRtpPacket(payload_size, padding_size, ssrc, extension_map,
                      &rtp_packet, all_configured_exts);
 
@@ -686,28 +698,41 @@
 }
 
 RtpHeaderExtensionMap EventGenerator::NewRtpHeaderExtensionMap(
-    bool configure_all) {
+    bool configure_all,
+    const std::vector<RTPExtensionType>& excluded_extensions) {
   RtpHeaderExtensionMap extension_map;
   std::vector<int> id(RtpExtension::kOneByteHeaderExtensionMaxId -
                       RtpExtension::kMinId + 1);
   std::iota(id.begin(), id.end(), RtpExtension::kMinId);
   ShuffleInPlace(&prng_, rtc::ArrayView<int>(id));
 
-  if (configure_all || prng_.Rand<bool>()) {
+  auto not_excluded = [&](RTPExtensionType type) -> bool {
+    return !absl::c_linear_search(excluded_extensions, type);
+  };
+
+  if (not_excluded(AudioLevel::kId) && (configure_all || prng_.Rand<bool>())) {
     extension_map.Register<AudioLevel>(id[0]);
   }
-  if (configure_all || prng_.Rand<bool>()) {
+  if (not_excluded(TransmissionOffset::kId) &&
+      (configure_all || prng_.Rand<bool>())) {
     extension_map.Register<TransmissionOffset>(id[1]);
   }
-  if (configure_all || prng_.Rand<bool>()) {
+  if (not_excluded(AbsoluteSendTime::kId) &&
+      (configure_all || prng_.Rand<bool>())) {
     extension_map.Register<AbsoluteSendTime>(id[2]);
   }
-  if (configure_all || prng_.Rand<bool>()) {
+  if (not_excluded(VideoOrientation::kId) &&
+      (configure_all || prng_.Rand<bool>())) {
     extension_map.Register<VideoOrientation>(id[3]);
   }
-  if (configure_all || prng_.Rand<bool>()) {
+  if (not_excluded(TransportSequenceNumber::kId) &&
+      (configure_all || prng_.Rand<bool>())) {
     extension_map.Register<TransportSequenceNumber>(id[4]);
   }
+  if (not_excluded(RtpDependencyDescriptorExtension::kId) &&
+      (configure_all || prng_.Rand<bool>())) {
+    extension_map.Register<RtpDependencyDescriptorExtension>(id[5]);
+  }
 
   return extension_map;
 }
@@ -1006,6 +1031,27 @@
   }
 }
 
+template <typename Event>
+void VerifyLoggedDependencyDescriptor(const Event& packet,
+                                      const std::vector<uint8_t>& logged_dd) {
+  if (webrtc::field_trial::IsDisabled(
+          "WebRTC-RtcEventLogEncodeDependencyDescriptor")) {
+    EXPECT_TRUE(logged_dd.empty());
+  } else {
+    rtc::ArrayView<const uint8_t> original =
+        packet.template GetRawExtension<RtpDependencyDescriptorExtension>();
+    EXPECT_EQ(logged_dd.size(), original.size());
+    bool dd_is_same = true;
+    for (size_t i = 0; i < logged_dd.size(); ++i) {
+      dd_is_same = logged_dd[i] == original[i];
+      if (!dd_is_same) {
+        break;
+      }
+    }
+    EXPECT_TRUE(dd_is_same);
+  }
+}
+
 void EventVerifier::VerifyLoggedRouteChangeEvent(
     const RtcEventRouteChange& original_event,
     const LoggedRouteChangeEvent& logged_event) const {
@@ -1039,6 +1085,8 @@
             logged_event.rtp.header.paddingLength);
 
   VerifyLoggedRtpHeader(original_event, logged_event.rtp.header);
+  VerifyLoggedDependencyDescriptor(
+      original_event, logged_event.rtp.dependency_descriptor_wire_format);
 }
 
 void EventVerifier::VerifyLoggedRtpPacketOutgoing(
@@ -1059,6 +1107,8 @@
   // someone has a strong reason to keep it, it'll be removed.
 
   VerifyLoggedRtpHeader(original_event, logged_event.rtp.header);
+  VerifyLoggedDependencyDescriptor(
+      original_event, logged_event.rtp.dependency_descriptor_wire_format);
 }
 
 void EventVerifier::VerifyLoggedGenericPacketSent(
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 7b863fd..950a622 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest_helper.h
+++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.h
@@ -15,6 +15,7 @@
 #include <stdint.h>
 
 #include <memory>
+#include <vector>
 
 #include "logging/rtc_event_log/events/rtc_event_alr_state.h"
 #include "logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h"
@@ -124,8 +125,11 @@
       bool all_configured_exts = true);
 
   // `configure_all` determines whether all supported extensions are configured,
-  // or a random subset.
-  RtpHeaderExtensionMap NewRtpHeaderExtensionMap(bool configure_all = false);
+  // or a random subset. Extensions in `excluded_extensions` will always be
+  // excluded.
+  RtpHeaderExtensionMap NewRtpHeaderExtensionMap(
+      bool configure_all = false,
+      const std::vector<RTPExtensionType>& excluded_extensions = {});
 
   std::unique_ptr<RtcEventAudioReceiveStreamConfig> NewAudioReceiveStreamConfig(
       uint32_t ssrc,