Implement support for receiving feedback according to RFC 8888

Bug: webrtc:42225697
Change-Id: Ieb270b44da223436d2fd3fa353dc857f378ee88d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/365700
Commit-Queue: Per Kjellander <perkj@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#43305}
diff --git a/api/transport/BUILD.gn b/api/transport/BUILD.gn
index 5d34065..7769526 100644
--- a/api/transport/BUILD.gn
+++ b/api/transport/BUILD.gn
@@ -47,6 +47,7 @@
   ]
 
   deps = [
+    ":ecn_marking",
     "../../api:field_trials_view",
     "../../rtc_base/system:rtc_export",
     "../environment",
diff --git a/api/transport/network_types.h b/api/transport/network_types.h
index 57fa657..432b1fc 100644
--- a/api/transport/network_types.h
+++ b/api/transport/network_types.h
@@ -16,6 +16,7 @@
 #include <optional>
 #include <vector>
 
+#include "api/transport/ecn_marking.h"
 #include "api/units/data_rate.h"
 #include "api/units/data_size.h"
 #include "api/units/time_delta.h"
@@ -168,6 +169,7 @@
 
   SentPacket sent_packet;
   Timestamp receive_time = Timestamp::PlusInfinity();
+  EcnMarking ecn = EcnMarking::kNotEct;
 };
 
 struct RTC_EXPORT TransportPacketsFeedback {
diff --git a/call/rtp_transport_controller_send.cc b/call/rtp_transport_controller_send.cc
index 08b17c2..81754f9 100644
--- a/call/rtp_transport_controller_send.cc
+++ b/call/rtp_transport_controller_send.cc
@@ -48,7 +48,9 @@
 #include "modules/pacing/packet_router.h"
 #include "modules/rtp_rtcp/include/report_block_data.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/congestion_control_feedback.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
 #include "modules/rtp_rtcp/source/rtp_rtcp_interface.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/experiments/field_trial_parser.h"
@@ -650,6 +652,25 @@
   }
 }
 
+void RtpTransportControllerSend::OnCongestionControlFeedback(
+    Timestamp receive_time,
+    const rtcp::CongestionControlFeedback& feedback) {
+  RTC_DCHECK_RUN_ON(&sequence_checker_);
+  // TODO: bugs.webrtc.org/42225697 - update feedback demuxer for RFC 8888.
+  // Suggest feedback_demuxer_.OnTransportFeedback use TransportPacketFeedback
+  // instead. See usage in OnTransportFeedback.
+  std::optional<TransportPacketsFeedback> feedback_msg =
+      transport_feedback_adapter_.ProcessCongestionControlFeedback(
+          feedback, receive_time);
+  if (feedback_msg) {
+    if (controller_)
+      PostUpdates(controller_->OnTransportPacketsFeedback(*feedback_msg));
+
+    // Only update outstanding data if any packet is first time acked.
+    UpdateCongestedState();
+  }
+}
+
 void RtpTransportControllerSend::OnRemoteNetworkEstimate(
     NetworkStateEstimate estimate) {
   RTC_DCHECK_RUN_ON(&sequence_checker_);
diff --git a/call/rtp_transport_controller_send.h b/call/rtp_transport_controller_send.h
index 4725b38..51f8fae 100644
--- a/call/rtp_transport_controller_send.h
+++ b/call/rtp_transport_controller_send.h
@@ -48,6 +48,7 @@
 #include "modules/pacing/task_queue_paced_sender.h"
 #include "modules/rtp_rtcp/include/report_block_data.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/congestion_control_feedback.h"
 #include "rtc_base/experiments/field_trial_parser.h"
 #include "rtc_base/network_route.h"
 #include "rtc_base/rate_limiter.h"
@@ -129,6 +130,9 @@
   void OnRttUpdate(Timestamp receive_time, TimeDelta rtt) override;
   void OnTransportFeedback(Timestamp receive_time,
                            const rtcp::TransportFeedback& feedback) override;
+  void OnCongestionControlFeedback(
+      Timestamp receive_time,
+      const rtcp::CongestionControlFeedback& feedback) override;
 
   // Implements NetworkStateEstimateObserver interface
   void OnRemoteNetworkEstimate(NetworkStateEstimate estimate) override;
diff --git a/modules/congestion_controller/rtp/BUILD.gn b/modules/congestion_controller/rtp/BUILD.gn
index 600b156..9df7fc9 100644
--- a/modules/congestion_controller/rtp/BUILD.gn
+++ b/modules/congestion_controller/rtp/BUILD.gn
@@ -43,6 +43,7 @@
     "../../../api:sequence_checker",
     "../../../api/transport:network_control",
     "../../../api/units:data_size",
+    "../../../api/units:time_delta",
     "../../../api/units:timestamp",
     "../../../rtc_base:checks",
     "../../../rtc_base:logging",
@@ -54,6 +55,7 @@
     "../../../rtc_base/system:no_unique_address",
     "../../../system_wrappers",
     "../../../system_wrappers:field_trial",
+    "../../rtp_rtcp:ntp_time_util",
     "../../rtp_rtcp:rtp_rtcp_format",
     "//third_party/abseil-cpp/absl/algorithm:container",
   ]
@@ -71,6 +73,7 @@
       ":transport_feedback",
       "../:congestion_controller",
       "../../../api:array_view",
+      "../../../api/transport:ecn_marking",
       "../../../api/transport:network_control",
       "../../../api/units:data_size",
       "../../../api/units:time_delta",
@@ -78,6 +81,7 @@
       "../../../logging:mocks",
       "../../../rtc_base:buffer",
       "../../../rtc_base:checks",
+      "../../../rtc_base:logging",
       "../../../rtc_base:safe_conversions",
       "../../../rtc_base/network:sent_packet",
       "../../../system_wrappers",
@@ -85,6 +89,7 @@
       "../../../test:test_support",
       "../../pacing",
       "../../remote_bitrate_estimator",
+      "../../rtp_rtcp:ntp_time_util",
       "../../rtp_rtcp:rtp_rtcp_format",
       "//testing/gmock",
     ]
diff --git a/modules/congestion_controller/rtp/transport_feedback_adapter.cc b/modules/congestion_controller/rtp/transport_feedback_adapter.cc
index 553cf3f..2219645 100644
--- a/modules/congestion_controller/rtp/transport_feedback_adapter.cc
+++ b/modules/congestion_controller/rtp/transport_feedback_adapter.cc
@@ -13,17 +13,25 @@
 #include <stdlib.h>
 
 #include <algorithm>
+#include <cstdint>
 #include <optional>
 #include <utility>
 #include <vector>
 
+#include "absl/algorithm/container.h"
 #include "api/transport/network_types.h"
+#include "api/units/data_size.h"
+#include "api/units/time_delta.h"
 #include "api/units/timestamp.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/ntp_time_util.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/congestion_control_feedback.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
+#include "rtc_base/network/sent_packet.h"
+#include "rtc_base/network_route.h"
 
 namespace webrtc {
 
@@ -114,9 +122,21 @@
     // TODO(sprang): Warn if erasing (too many) old items?
     if (history_.begin()->second.sent.sequence_number > last_ack_seq_num_)
       in_flight_.RemoveInFlightPacketBytes(history_.begin()->second);
+
+    const PacketFeedback& packet = history_.begin()->second;
+    rtp_to_transport_sequence_number_.erase(
+        {.ssrc = packet.ssrc,
+         .rtp_sequence_number = packet.rtp_sequence_number});
     history_.erase(history_.begin());
   }
-  history_.insert(std::make_pair(feedback.sent.sequence_number, feedback));
+  // Note that it can happen that the same SSRC and sequence number is sent
+  // again. e.g, audio retransmission.
+  rtp_to_transport_sequence_number_.emplace(
+      SsrcAndRtpSequencenumber(
+          {.ssrc = feedback.ssrc,
+           .rtp_sequence_number = feedback.rtp_sequence_number}),
+      feedback.sent.sequence_number);
+  history_.emplace(feedback.sent.sequence_number, feedback);
 }
 
 std::optional<SentPacket> TransportFeedbackAdapter::ProcessSentPacket(
@@ -170,12 +190,13 @@
   // Add timestamp deltas to a local time base selected on first packet arrival.
   // This won't be the true time base, but makes it easier to manually inspect
   // time stamps.
-  if (last_timestamp_.IsInfinite()) {
+  if (last_transport_feedback_base_time_.IsInfinite()) {
     current_offset_ = feedback_receive_time;
   } else {
     // TODO(srte): We shouldn't need to do rounding here.
-    const TimeDelta delta = feedback.GetBaseDelta(last_timestamp_)
-                                .RoundDownTo(TimeDelta::Millis(1));
+    const TimeDelta delta =
+        feedback.GetBaseDelta(last_transport_feedback_base_time_)
+            .RoundDownTo(TimeDelta::Millis(1));
     // Protect against assigning current_offset_ negative value.
     if (delta < Timestamp::Zero() - current_offset_) {
       RTC_LOG(LS_WARNING) << "Unexpected feedback timestamp received.";
@@ -184,7 +205,7 @@
       current_offset_ += delta;
     }
   }
-  last_timestamp_ = feedback.BaseTime();
+  last_transport_feedback_base_time_ = feedback.BaseTime();
 
   std::vector<PacketResult> packet_result_vector;
   packet_result_vector.reserve(feedback.GetPacketStatusCount());
@@ -230,6 +251,77 @@
 }
 
 std::optional<TransportPacketsFeedback>
+TransportFeedbackAdapter::ProcessCongestionControlFeedback(
+    const rtcp::CongestionControlFeedback& feedback,
+    Timestamp feedback_receive_time) {
+  if (feedback.packets().empty()) {
+    RTC_LOG(LS_INFO) << "Empty congestion control feedback packet received.";
+    return std::nullopt;
+  }
+  if (current_offset_.IsInfinite()) {
+    current_offset_ = feedback_receive_time;
+  }
+  TimeDelta feedback_delta = last_feedback_compact_ntp_time_
+                                 ? CompactNtpIntervalToTimeDelta(
+                                       feedback.report_timestamp_compact_ntp() -
+                                       *last_feedback_compact_ntp_time_)
+                                 : TimeDelta::Zero();
+  last_feedback_compact_ntp_time_ = feedback.report_timestamp_compact_ntp();
+  if (feedback_delta < TimeDelta::Zero()) {
+    RTC_LOG(LS_WARNING) << "Unexpected feedback ntp time delta "
+                        << feedback_delta << ".";
+    current_offset_ = feedback_receive_time;
+  } else {
+    current_offset_ += feedback_delta;
+  }
+
+  int ignored_packets = 0;
+  int failed_lookups = 0;
+  std::vector<PacketResult> packet_result_vector;
+  for (const rtcp::CongestionControlFeedback::PacketInfo& packet_info :
+       feedback.packets()) {
+    std::optional<PacketFeedback> packet_feedback = RetrievePacketFeedback(
+        {.ssrc = packet_info.ssrc,
+         .rtp_sequence_number = packet_info.sequence_number},
+        /*received=*/packet_info.arrival_time_offset.IsFinite());
+    if (!packet_feedback) {
+      ++failed_lookups;
+      continue;
+    }
+    if (packet_feedback->network_route != network_route_) {
+      ++ignored_packets;
+      continue;
+    }
+    PacketResult result;
+    result.sent_packet = packet_feedback->sent;
+    if (packet_info.arrival_time_offset.IsFinite()) {
+      result.receive_time = current_offset_ - packet_info.arrival_time_offset;
+    }
+    result.ecn = packet_info.ecn;
+    packet_result_vector.push_back(result);
+  }
+
+  if (failed_lookups > 0) {
+    RTC_LOG(LS_WARNING)
+        << "Failed to lookup send time for " << failed_lookups << " packet"
+        << (failed_lookups > 1 ? "s" : "")
+        << ". Packets reordered or send time history too small?";
+  }
+  if (ignored_packets > 0) {
+    RTC_LOG(LS_INFO) << "Ignoring " << ignored_packets
+                     << " packets because they were sent on a different route.";
+  }
+
+  // Feedback is expected to be sorted in send order.
+  absl::c_sort(packet_result_vector, [](const PacketResult& lhs,
+                                        const PacketResult& rhs) {
+    return lhs.sent_packet.sequence_number < rhs.sent_packet.sequence_number;
+  });
+  return ToTransportFeedback(std::move(packet_result_vector),
+                             feedback_receive_time);
+}
+
+std::optional<TransportPacketsFeedback>
 TransportFeedbackAdapter::ToTransportFeedback(
     std::vector<PacketResult> packet_results,
     Timestamp feedback_receive_time) {
@@ -254,22 +346,33 @@
 }
 
 std::optional<PacketFeedback> TransportFeedbackAdapter::RetrievePacketFeedback(
-    int64_t seq_num,
+    const SsrcAndRtpSequencenumber& key,
     bool received) {
-  if (seq_num > last_ack_seq_num_) {
+  auto it = rtp_to_transport_sequence_number_.find(key);
+  if (it == rtp_to_transport_sequence_number_.end()) {
+    return std::nullopt;
+  }
+  return RetrievePacketFeedback(it->second, received);
+}
+
+std::optional<PacketFeedback> TransportFeedbackAdapter::RetrievePacketFeedback(
+    int64_t transport_seq_num,
+    bool received) {
+  if (transport_seq_num > last_ack_seq_num_) {
     // Starts at history_.begin() if last_ack_seq_num_ < 0, since any
     // valid sequence number is >= 0.
     for (auto it = history_.upper_bound(last_ack_seq_num_);
-         it != history_.upper_bound(seq_num); ++it) {
+         it != history_.upper_bound(transport_seq_num); ++it) {
       in_flight_.RemoveInFlightPacketBytes(it->second);
     }
-    last_ack_seq_num_ = seq_num;
+    last_ack_seq_num_ = transport_seq_num;
   }
 
-  auto it = history_.find(seq_num);
+  auto it = history_.find(transport_seq_num);
   if (it == history_.end()) {
     RTC_LOG(LS_WARNING) << "Failed to lookup send time for packet with "
-                        << seq_num << ". Send time history too small?";
+                        << transport_seq_num
+                        << ". Send time history too small?";
     return std::nullopt;
   }
 
@@ -285,6 +388,9 @@
   if (received) {
     // Note: Lost packets are not removed from history because they might
     // be reported as received by a later feedback.
+    rtp_to_transport_sequence_number_.erase(
+        {.ssrc = packet_feedback.ssrc,
+         .rtp_sequence_number = packet_feedback.rtp_sequence_number});
     history_.erase(it);
   }
   return packet_feedback;
diff --git a/modules/congestion_controller/rtp/transport_feedback_adapter.h b/modules/congestion_controller/rtp/transport_feedback_adapter.h
index 4976a53..970c0f1 100644
--- a/modules/congestion_controller/rtp/transport_feedback_adapter.h
+++ b/modules/congestion_controller/rtp/transport_feedback_adapter.h
@@ -11,13 +11,19 @@
 #ifndef MODULES_CONGESTION_CONTROLLER_RTP_TRANSPORT_FEEDBACK_ADAPTER_H_
 #define MODULES_CONGESTION_CONTROLLER_RTP_TRANSPORT_FEEDBACK_ADAPTER_H_
 
+#include <cstddef>
+#include <cstdint>
 #include <map>
+#include <optional>
+#include <tuple>
 #include <vector>
 
-#include "api/sequence_checker.h"
 #include "api/transport/network_types.h"
+#include "api/units/data_size.h"
 #include "api/units/timestamp.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/congestion_control_feedback.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
 #include "rtc_base/network/sent_packet.h"
 #include "rtc_base/network_route.h"
 #include "rtc_base/numerics/sequence_number_unwrapper.h"
@@ -55,6 +61,11 @@
   std::map<rtc::NetworkRoute, DataSize, NetworkRouteComparator> in_flight_data_;
 };
 
+// TransportFeedbackAdapter converts RTCP feedback packets to RTCP agnostic per
+// packet send/receive information.
+// It supports rtcp::CongestionControlFeedback according to RFC 8888 and
+// rtcp::TransportFeedback according to
+// https://datatracker.ietf.org/doc/html/draft-holmer-rmcat-transport-wide-cc-extensions-01
 class TransportFeedbackAdapter {
  public:
   TransportFeedbackAdapter();
@@ -63,6 +74,7 @@
                  const PacedPacketInfo& pacing_info,
                  size_t overhead_bytes,
                  Timestamp creation_time);
+
   std::optional<SentPacket> ProcessSentPacket(
       const rtc::SentPacket& sent_packet);
 
@@ -70,6 +82,10 @@
       const rtcp::TransportFeedback& feedback,
       Timestamp feedback_receive_time);
 
+  std::optional<TransportPacketsFeedback> ProcessCongestionControlFeedback(
+      const rtcp::CongestionControlFeedback& feedback,
+      Timestamp feedback_receive_time);
+
   void SetNetworkRoute(const rtc::NetworkRoute& network_route);
 
   DataSize GetOutstandingData() const;
@@ -77,12 +93,22 @@
  private:
   enum class SendTimeHistoryStatus { kNotAdded, kOk, kDuplicate };
 
-  std::vector<PacketResult> ProcessTransportFeedbackInner(
-      const rtcp::TransportFeedback& feedback,
-      Timestamp feedback_receive_time);
+  struct SsrcAndRtpSequencenumber {
+    uint32_t ssrc;
+    uint16_t rtp_sequence_number;
 
-  std::optional<PacketFeedback> RetrievePacketFeedback(int64_t seq_num,
-                                                       bool received);
+    bool operator<(const SsrcAndRtpSequencenumber& other) const {
+      return std::tie(ssrc, rtp_sequence_number) <
+             std::tie(other.ssrc, other.rtp_sequence_number);
+    }
+  };
+
+  std::optional<PacketFeedback> RetrievePacketFeedback(
+      int64_t transport_seq_num,
+      bool received);
+  std::optional<PacketFeedback> RetrievePacketFeedback(
+      const SsrcAndRtpSequencenumber& key,
+      bool received);
   std::optional<TransportPacketsFeedback> ToTransportFeedback(
       std::vector<PacketResult> packet_results,
       Timestamp feedback_receive_time);
@@ -92,17 +118,24 @@
   Timestamp last_untracked_send_time_ = Timestamp::MinusInfinity();
   RtpSequenceNumberUnwrapper seq_num_unwrapper_;
 
-  std::map<int64_t, PacketFeedback> history_;
-
   // Sequence numbers are never negative, using -1 as it always < a real
   // sequence number.
   int64_t last_ack_seq_num_ = -1;
   InFlightBytesTracker in_flight_;
+  rtc::NetworkRoute network_route_;
 
   Timestamp current_offset_ = Timestamp::MinusInfinity();
-  Timestamp last_timestamp_ = Timestamp::MinusInfinity();
 
-  rtc::NetworkRoute network_route_;
+  // `last_transport_feedback_base_time` is only used for transport feedback to
+  // track base time.
+  Timestamp last_transport_feedback_base_time_ = Timestamp::MinusInfinity();
+  // Used by RFC 8888 congestion control feedback to track base time.
+  std::optional<uint32_t> last_feedback_compact_ntp_time_;
+
+  // Map SSRC and RTP sequence number to transport sequence number.
+  std::map<SsrcAndRtpSequencenumber, int64_t /*transport_sequence_number*/>
+      rtp_to_transport_sequence_number_;
+  std::map<int64_t, PacketFeedback> history_;
 };
 
 }  // namespace webrtc
diff --git a/modules/congestion_controller/rtp/transport_feedback_adapter_unittest.cc b/modules/congestion_controller/rtp/transport_feedback_adapter_unittest.cc
index e003506..ca7ebc3 100644
--- a/modules/congestion_controller/rtp/transport_feedback_adapter_unittest.cc
+++ b/modules/congestion_controller/rtp/transport_feedback_adapter_unittest.cc
@@ -14,37 +14,80 @@
 #include <cstdint>
 #include <memory>
 #include <optional>
+#include <utility>
 #include <vector>
 
 #include "api/array_view.h"
+#include "api/transport/ecn_marking.h"
 #include "api/transport/network_types.h"
 #include "api/units/data_size.h"
 #include "api/units/time_delta.h"
 #include "api/units/timestamp.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/ntp_time_util.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/congestion_control_feedback.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
 #include "rtc_base/buffer.h"
-#include "rtc_base/checks.h"
 #include "rtc_base/network/sent_packet.h"
+#include "system_wrappers/include/clock.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
 
 namespace webrtc {
-
 namespace {
 
+using ::testing::Bool;
 using ::testing::NotNull;
 using ::testing::SizeIs;
+using ::testing::TestParamInfo;
 
-constexpr uint32_t kSsrc = 8492;
 const PacedPacketInfo kPacingInfo0(0, 5, 2000);
-const PacedPacketInfo kPacingInfo1(1, 8, 4000);
-const PacedPacketInfo kPacingInfo2(2, 14, 7000);
-const PacedPacketInfo kPacingInfo3(3, 20, 10000);
-const PacedPacketInfo kPacingInfo4(4, 22, 10000);
 
-void ComparePacketFeedbackVectors(const std::vector<PacketResult>& truth,
+struct PacketTemplate {
+  uint32_t ssrc = 1;
+  int64_t transport_sequence_number = 0;
+  uint16_t rtp_sequence_number = 2;
+  RtpPacketMediaType media_type = RtpPacketMediaType::kVideo;
+  DataSize packet_size = DataSize::Bytes(100);
+
+  EcnMarking ecn = EcnMarking::kNotEct;
+  Timestamp send_timestamp = Timestamp::Millis(0);
+  PacedPacketInfo pacing_info;
+  Timestamp receive_timestamp = Timestamp::MinusInfinity();
+
+  bool is_audio = false;
+};
+
+std::vector<PacketTemplate> CreatePacketTemplates(
+    uint32_t number_of_ssrcs,
+    uint32_t packets_per_ssrc,
+    int64_t first_transport_sequence_number = 99) {
+  int64_t transport_sequence_number = first_transport_sequence_number;
+  Timestamp send_time = Timestamp::Millis(200);
+  Timestamp receive_time = Timestamp::Millis(100);
+  std::vector<PacketTemplate> packets;
+
+  for (uint32_t ssrc = 3; ssrc < 3 + number_of_ssrcs; ++ssrc) {
+    for (int rtp_sequence_number = ssrc * 10;
+         rtp_sequence_number < static_cast<int>(ssrc * 10 + packets_per_ssrc);
+         ++rtp_sequence_number) {
+      packets.push_back({
+          .ssrc = ssrc,
+          .transport_sequence_number = transport_sequence_number++,
+          .rtp_sequence_number = static_cast<uint16_t>(rtp_sequence_number),
+          .send_timestamp = send_time,
+          .pacing_info = kPacingInfo0,
+          .receive_timestamp = receive_time,
+      });
+      send_time += TimeDelta::Millis(10);
+      receive_time += TimeDelta::Millis(13);
+    }
+  }
+  return packets;
+}
+
+void ComparePacketFeedbackVectors(const std::vector<PacketTemplate>& truth,
                                   const std::vector<PacketResult>& input) {
   ASSERT_EQ(truth.size(), input.size());
   size_t len = truth.size();
@@ -55,106 +98,126 @@
   // base adjustment performed by the TransportFeedbackAdapter at the first
   // packet, the truth[x].arrival_time and input[x].arrival_time may not be
   // equal. However, the difference must be the same for all x.
-  TimeDelta arrival_time_delta = truth[0].receive_time - input[0].receive_time;
+  TimeDelta arrival_time_delta =
+      truth[0].receive_timestamp - input[0].receive_time;
   for (size_t i = 0; i < len; ++i) {
-    RTC_CHECK(truth[i].IsReceived());
+    EXPECT_EQ(truth[i].receive_timestamp.IsFinite(), input[i].IsReceived());
     if (input[i].IsReceived()) {
-      EXPECT_EQ(truth[i].receive_time - input[i].receive_time,
+      EXPECT_EQ(truth[i].receive_timestamp - input[i].receive_time,
                 arrival_time_delta);
     }
-    EXPECT_EQ(truth[i].sent_packet.send_time, input[i].sent_packet.send_time);
-    EXPECT_EQ(truth[i].sent_packet.sequence_number,
+    EXPECT_EQ(truth[i].send_timestamp, input[i].sent_packet.send_time);
+    EXPECT_EQ(truth[i].transport_sequence_number,
               input[i].sent_packet.sequence_number);
-    EXPECT_EQ(truth[i].sent_packet.size, input[i].sent_packet.size);
-    EXPECT_EQ(truth[i].sent_packet.pacing_info,
-              input[i].sent_packet.pacing_info);
-    EXPECT_EQ(truth[i].sent_packet.audio, input[i].sent_packet.audio);
+    EXPECT_EQ(truth[i].packet_size, input[i].sent_packet.size);
+    EXPECT_EQ(truth[i].pacing_info, input[i].sent_packet.pacing_info);
+    EXPECT_EQ(truth[i].is_audio, input[i].sent_packet.audio);
   }
 }
 
-rtcp::TransportFeedback BuildRtcpTransportFeedbackPacket(
-    rtc::ArrayView<const PacketResult> packets) {
-  rtcp::TransportFeedback feedback;
-  feedback.SetBase(packets[0].sent_packet.sequence_number,
-                   packets[0].receive_time);
+RtpPacketToSend CreatePacketToSend(PacketTemplate packet) {
+  RtpPacketToSend send_packet(nullptr);
+  send_packet.SetSsrc(packet.ssrc);
+  send_packet.SetPayloadSize(packet.packet_size.bytes() -
+                             send_packet.headers_size());
+  send_packet.SetSequenceNumber(packet.rtp_sequence_number);
+  send_packet.set_transport_sequence_number(packet.transport_sequence_number);
+  send_packet.set_packet_type(packet.is_audio ? RtpPacketMediaType::kAudio
+                                              : RtpPacketMediaType::kVideo);
 
-  for (const PacketResult& packet : packets) {
-    if (packet.receive_time.IsFinite()) {
-      EXPECT_TRUE(feedback.AddReceivedPacket(packet.sent_packet.sequence_number,
-                                             packet.receive_time));
+  return send_packet;
+}
+
+rtcp::TransportFeedback BuildRtcpTransportFeedbackPacket(
+    rtc::ArrayView<const PacketTemplate> packets) {
+  rtcp::TransportFeedback feedback;
+  feedback.SetBase(packets[0].transport_sequence_number,
+                   packets[0].receive_timestamp);
+
+  for (const PacketTemplate& packet : packets) {
+    if (packet.receive_timestamp.IsFinite()) {
+      EXPECT_TRUE(feedback.AddReceivedPacket(packet.transport_sequence_number,
+                                             packet.receive_timestamp));
     }
   }
   return feedback;
 }
 
-PacketResult CreatePacket(int64_t receive_time_ms,
-                          int64_t send_time_ms,
-                          int64_t sequence_number,
-                          size_t payload_size,
-                          const PacedPacketInfo& pacing_info) {
-  PacketResult res;
-  res.receive_time = Timestamp::Millis(receive_time_ms);
-  res.sent_packet.send_time = Timestamp::Millis(send_time_ms);
-  res.sent_packet.sequence_number = sequence_number;
-  res.sent_packet.size = DataSize::Bytes(payload_size);
-  res.sent_packet.pacing_info = pacing_info;
-  return res;
+rtcp::CongestionControlFeedback BuildRtcpCongestionControlFeedbackPacket(
+    rtc::ArrayView<const PacketTemplate> packets) {
+  // Assume the feedback was sent when the last packet was received.
+  Timestamp feedback_sent_time = Timestamp::MinusInfinity();
+  for (auto it = packets.crbegin(); it != packets.crend(); ++it) {
+    if (it->receive_timestamp.IsFinite()) {
+      feedback_sent_time = it->receive_timestamp;
+      break;
+    }
+  }
+
+  std::vector<rtcp::CongestionControlFeedback::PacketInfo> packet_infos;
+  for (const PacketTemplate& packet : packets) {
+    rtcp::CongestionControlFeedback::PacketInfo packet_info = {
+        .ssrc = packet.ssrc,
+        .sequence_number = packet.rtp_sequence_number,
+        .ecn = packet.ecn};
+    if (packet.receive_timestamp.IsFinite()) {
+      packet_info.arrival_time_offset =
+          feedback_sent_time - packet.receive_timestamp;
+    }
+    packet_infos.push_back(packet_info);
+  }
+
+  SimulatedClock clock(feedback_sent_time);
+  uint32_t compact_ntp =
+      CompactNtp(clock.ConvertTimestampToNtpTime(feedback_sent_time));
+  return rtcp::CongestionControlFeedback(std::move(packet_infos), compact_ntp);
 }
 
-RtpPacketToSend CreatePacketToSend(const PacketResult& packet,
-                                   uint32_t ssrc = kSsrc,
-                                   uint16_t rtp_sequence_number = 0) {
-  RtpPacketToSend send_packet(nullptr);
-  send_packet.SetSsrc(ssrc);
-  send_packet.SetPayloadSize(packet.sent_packet.size.bytes() -
-                             send_packet.headers_size());
-  send_packet.SetSequenceNumber(rtp_sequence_number);
-  send_packet.set_transport_sequence_number(packet.sent_packet.sequence_number);
-  send_packet.set_packet_type(packet.sent_packet.audio
-                                  ? RtpPacketMediaType::kAudio
-                                  : RtpPacketMediaType::kVideo);
-
-  return send_packet;
+Timestamp TimeNow() {
+  return Timestamp::Millis(1234);
 }
 
-class MockStreamFeedbackObserver : public webrtc::StreamFeedbackObserver {
- public:
-  MOCK_METHOD(void,
-              OnPacketFeedbackVector,
-              (std::vector<StreamPacketInfo> packet_feedback_vector),
-              (override));
-};
-
 }  // namespace
 
-class TransportFeedbackAdapterTest : public ::testing::Test {
+class TransportFeedbackAdapterTest : public ::testing::TestWithParam<bool> {
  public:
-  Timestamp TimeNow() const { return Timestamp::Millis(1234); }
+  bool UseRfc8888CongestionControlFeedback() const { return GetParam(); }
 
   std::optional<TransportPacketsFeedback> CreateAndProcessFeedback(
-      rtc::ArrayView<const PacketResult> packets,
+      rtc::ArrayView<const PacketTemplate> packets,
       TransportFeedbackAdapter& adapter) {
-    rtcp::TransportFeedback rtcp_feedback =
-        BuildRtcpTransportFeedbackPacket(packets);
-    return adapter.ProcessTransportFeedback(rtcp_feedback, TimeNow());
+    if (UseRfc8888CongestionControlFeedback()) {
+      rtcp::CongestionControlFeedback rtcp_feedback =
+          BuildRtcpCongestionControlFeedbackPacket(packets);
+      return adapter.ProcessCongestionControlFeedback(rtcp_feedback, TimeNow());
+    } else {
+      rtcp::TransportFeedback rtcp_feedback =
+          BuildRtcpTransportFeedbackPacket(packets);
+      return adapter.ProcessTransportFeedback(rtcp_feedback, TimeNow());
+    }
   }
 };
 
-TEST_F(TransportFeedbackAdapterTest, AdaptsFeedbackAndPopulatesSendTimes) {
-  TransportFeedbackAdapter adapter;
-  std::vector<PacketResult> packets;
-  packets.push_back(CreatePacket(100, 200, 0, 1500, kPacingInfo0));
-  packets.push_back(CreatePacket(110, 210, 1, 1500, kPacingInfo0));
-  packets.push_back(CreatePacket(120, 220, 2, 1500, kPacingInfo0));
-  packets.push_back(CreatePacket(130, 230, 3, 1500, kPacingInfo1));
-  packets.push_back(CreatePacket(140, 240, 4, 1500, kPacingInfo1));
+INSTANTIATE_TEST_SUITE_P(FeedbackFormats,
+                         TransportFeedbackAdapterTest,
+                         Bool(),
+                         [](TestParamInfo<bool> param) {
+                           if (param.param)
+                             return "CongestionControlFeedback";
+                           else
+                             return "TransportFeedback";
+                         });
 
-  for (const PacketResult& packet : packets) {
-    adapter.AddPacket(CreatePacketToSend(packet),
-                      packet.sent_packet.pacing_info,
+TEST_P(TransportFeedbackAdapterTest, AdaptsFeedbackAndPopulatesSendTimes) {
+  TransportFeedbackAdapter adapter;
+  std::vector<PacketTemplate> packets =
+      CreatePacketTemplates(/*number_of_ssrcs=*/2, /*packets_per_ssrc=*/3);
+
+  for (const PacketTemplate& packet : packets) {
+    adapter.AddPacket(CreatePacketToSend(packet), packet.pacing_info,
                       /*overhead=*/0u, TimeNow());
-    adapter.ProcessSentPacket(rtc::SentPacket(
-        packet.sent_packet.sequence_number, packet.sent_packet.send_time.ms()));
+    adapter.ProcessSentPacket(rtc::SentPacket(packet.transport_sequence_number,
+                                              packet.send_timestamp.ms()));
   }
 
   std::optional<TransportPacketsFeedback> adapted_feedback =
@@ -162,75 +225,63 @@
   ComparePacketFeedbackVectors(packets, adapted_feedback->packet_feedbacks);
 }
 
-TEST_F(TransportFeedbackAdapterTest, FeedbackVectorReportsUnreceived) {
+TEST_P(TransportFeedbackAdapterTest, FeedbackVectorReportsUnreceived) {
   TransportFeedbackAdapter adapter;
 
-  std::vector<PacketResult> sent_packets = {
-      CreatePacket(100, 220, 0, 1500, kPacingInfo0),
-      CreatePacket(110, 210, 1, 1500, kPacingInfo0),
-      CreatePacket(120, 220, 2, 1500, kPacingInfo0),
-      CreatePacket(130, 230, 3, 1500, kPacingInfo0),
-      CreatePacket(140, 240, 4, 1500, kPacingInfo0),
-      CreatePacket(150, 250, 5, 1500, kPacingInfo0),
-      CreatePacket(160, 260, 6, 1500, kPacingInfo0)};
-  for (const PacketResult& packet : sent_packets) {
-    adapter.AddPacket(CreatePacketToSend(packet),
-                      packet.sent_packet.pacing_info,
+  std::vector<PacketTemplate> sent_packets =
+      CreatePacketTemplates(/*number_of_ssrcs=*/2, /*packets_per_ssrc=*/3);
+
+  for (const PacketTemplate& packet : sent_packets) {
+    adapter.AddPacket(CreatePacketToSend(packet), packet.pacing_info,
                       /*overhead=*/0u, TimeNow());
-    adapter.ProcessSentPacket(rtc::SentPacket(
-        packet.sent_packet.sequence_number, packet.sent_packet.send_time.ms()));
+    adapter.ProcessSentPacket(rtc::SentPacket(packet.transport_sequence_number,
+                                              packet.send_timestamp.ms()));
   }
 
-  // Note: Important to include the last packet, as only unreceived packets in
-  // between received packets can be inferred.
-  std::vector<PacketResult> received_packets = {
-      sent_packets[0], sent_packets[2], sent_packets[6]};
-
+  // Note: Important to include the last packet per SSRC, as only unreceived
+  // packets in between received packets can be inferred.
+  sent_packets[1].receive_timestamp = Timestamp::PlusInfinity();
+  sent_packets[4].receive_timestamp = Timestamp::PlusInfinity();
   std::optional<TransportPacketsFeedback> adapted_feedback =
-      CreateAndProcessFeedback(received_packets, adapter);
+      CreateAndProcessFeedback(sent_packets, adapter);
 
   ComparePacketFeedbackVectors(sent_packets,
                                adapted_feedback->packet_feedbacks);
 }
 
-TEST_F(TransportFeedbackAdapterTest, HandlesDroppedPackets) {
+TEST_P(TransportFeedbackAdapterTest, HandlesDroppedPackets) {
   TransportFeedbackAdapter adapter;
 
-  std::vector<PacketResult> packets;
-  packets.push_back(CreatePacket(100, 200, 0, 1500, kPacingInfo0));
-  packets.push_back(CreatePacket(110, 210, 1, 1500, kPacingInfo1));
-  packets.push_back(CreatePacket(120, 220, 2, 1500, kPacingInfo2));
-  packets.push_back(CreatePacket(130, 230, 3, 1500, kPacingInfo3));
-  packets.push_back(CreatePacket(140, 240, 4, 1500, kPacingInfo4));
+  std::vector<PacketTemplate> packets =
+      CreatePacketTemplates(/*number_of_ssrcs=*/2, /*packets_per_ssrc=*/2,
+                            /*first_transport_sequence_number=*/0);
 
   const uint16_t kSendSideDropBefore = 1;
   const uint16_t kReceiveSideDropAfter = 3;
 
-  std::vector<PacketResult> sent_packets;
-  for (const PacketResult& packet : packets) {
-    if (packet.sent_packet.sequence_number >= kSendSideDropBefore) {
+  std::vector<PacketTemplate> sent_packets;
+  for (const PacketTemplate& packet : packets) {
+    if (packet.transport_sequence_number >= kSendSideDropBefore) {
       sent_packets.push_back(packet);
     }
   }
-  for (const PacketResult& packet : sent_packets) {
-    adapter.AddPacket(CreatePacketToSend(packet),
-                      packet.sent_packet.pacing_info,
+  for (const PacketTemplate& packet : sent_packets) {
+    adapter.AddPacket(CreatePacketToSend(packet), packet.pacing_info,
                       /*overhead=*/0u, TimeNow());
-    adapter.ProcessSentPacket(rtc::SentPacket(
-        packet.sent_packet.sequence_number, packet.sent_packet.send_time.ms()));
+    adapter.ProcessSentPacket(rtc::SentPacket(packet.transport_sequence_number,
+                                              packet.send_timestamp.ms()));
   }
 
-  std::vector<PacketResult> received_packets;
-  for (const PacketResult& packet : packets) {
-    if (packet.sent_packet.sequence_number <= kReceiveSideDropAfter) {
+  std::vector<PacketTemplate> received_packets;
+  for (const PacketTemplate& packet : packets) {
+    if (packet.transport_sequence_number <= kReceiveSideDropAfter) {
       received_packets.push_back(packet);
     }
   }
-
   std::optional<TransportPacketsFeedback> adapted_feedback =
       CreateAndProcessFeedback(received_packets, adapter);
 
-  std::vector<PacketResult> expected_packets(
+  std::vector<PacketTemplate> expected_packets(
       packets.begin() + kSendSideDropBefore,
       packets.begin() + kReceiveSideDropAfter + 1);
   // Packets that have timed out on the send-side have lost the
@@ -240,16 +291,17 @@
                                adapted_feedback->packet_feedbacks);
 }
 
-TEST_F(TransportFeedbackAdapterTest, FeedbackReportsIfPacketIsAudio) {
+TEST_P(TransportFeedbackAdapterTest, FeedbackReportsIfPacketIsAudio) {
   TransportFeedbackAdapter adapter;
 
-  PacketResult packets[] = {CreatePacket(100, 200, 0, 1500, kPacingInfo0)};
-  PacketResult& packet = packets[0];
-  packet.sent_packet.audio = true;
-  adapter.AddPacket(CreatePacketToSend(packet), packet.sent_packet.pacing_info,
+  PacketTemplate packets[] = {
+      {.receive_timestamp = TimeNow(), .is_audio = true}};
+  PacketTemplate& packet = packets[0];
+
+  adapter.AddPacket(CreatePacketToSend(packet), packet.pacing_info,
                     /*overhead=*/0u, TimeNow());
-  adapter.ProcessSentPacket(rtc::SentPacket(packet.sent_packet.sequence_number,
-                                            packet.sent_packet.send_time.ms()));
+  adapter.ProcessSentPacket(rtc::SentPacket(packet.transport_sequence_number,
+                                            packet.send_timestamp.ms()));
 
   std::optional<TransportPacketsFeedback> adapted_feedback =
       CreateAndProcessFeedback(packets, adapter);
@@ -257,59 +309,83 @@
   EXPECT_TRUE(adapted_feedback->packet_feedbacks[0].sent_packet.audio);
 }
 
-TEST_F(TransportFeedbackAdapterTest, SendTimeWrapsBothWays) {
+TEST_P(TransportFeedbackAdapterTest, ReceiveTimeWrapsBothWays) {
   TransportFeedbackAdapter adapter;
 
   TimeDelta kHighArrivalTime =
       rtcp::TransportFeedback::kDeltaTick * (1 << 8) * ((1 << 23) - 1);
-  std::vector<PacketResult> packets;
-  packets.push_back(CreatePacket(kHighArrivalTime.ms() + 64, 210, 0, 1500,
-                                 PacedPacketInfo()));
-  packets.push_back(CreatePacket(kHighArrivalTime.ms() - 64, 210, 1, 1500,
-                                 PacedPacketInfo()));
-  packets.push_back(
-      CreatePacket(kHighArrivalTime.ms(), 220, 2, 1500, PacedPacketInfo()));
 
-  for (const PacketResult& packet : packets) {
-    adapter.AddPacket(CreatePacketToSend(packet),
-                      packet.sent_packet.pacing_info,
+  std::vector<PacketTemplate> packets = {
+      {.transport_sequence_number = 0,
+       .rtp_sequence_number = 102,
+       .receive_timestamp =
+           Timestamp::Zero() + kHighArrivalTime + TimeDelta::Millis(64)},
+      {.transport_sequence_number = 1,
+       .rtp_sequence_number = 103,
+       .receive_timestamp =
+           Timestamp::Zero() + kHighArrivalTime - TimeDelta::Millis(64)},
+      {.transport_sequence_number = 2,
+       .rtp_sequence_number = 104,
+       .receive_timestamp = Timestamp::Zero() + kHighArrivalTime}};
+
+  for (const PacketTemplate& packet : packets) {
+    adapter.AddPacket(CreatePacketToSend(packet), packet.pacing_info,
                       /*overhead=*/0u, TimeNow());
-    adapter.ProcessSentPacket(rtc::SentPacket(
-        packet.sent_packet.sequence_number, packet.sent_packet.send_time.ms()));
+    adapter.ProcessSentPacket(rtc::SentPacket(packet.transport_sequence_number,
+                                              packet.send_timestamp.ms()));
   }
 
   for (size_t i = 0; i < packets.size(); ++i) {
-    std::vector<PacketResult> received_packets = {packets[i]};
+    std::vector<PacketTemplate> received_packets = {packets[i]};
 
-    rtcp::TransportFeedback feedback =
-        BuildRtcpTransportFeedbackPacket(received_packets);
-    rtc::Buffer raw_packet = feedback.Build();
-    std::unique_ptr<rtcp::TransportFeedback> parsed_feedback =
-        rtcp::TransportFeedback::ParseFrom(raw_packet.data(),
-                                           raw_packet.size());
-    ASSERT_THAT(parsed_feedback, NotNull());
-
-    std::optional<TransportPacketsFeedback> res =
-        adapter.ProcessTransportFeedback(*parsed_feedback, TimeNow());
-    ASSERT_TRUE(res.has_value());
-    ComparePacketFeedbackVectors(received_packets, res->packet_feedbacks);
+    std::optional<TransportPacketsFeedback> result;
+    if (UseRfc8888CongestionControlFeedback()) {
+      rtcp::CongestionControlFeedback feedback =
+          BuildRtcpCongestionControlFeedbackPacket(received_packets);
+      rtc::Buffer raw_packet = feedback.Build();
+      rtcp::CommonHeader header;
+      ASSERT_TRUE(header.Parse(raw_packet.data(), raw_packet.size()));
+      rtcp::CongestionControlFeedback parsed_feedback;
+      ASSERT_TRUE(parsed_feedback.Parse(header));
+      result =
+          adapter.ProcessCongestionControlFeedback(parsed_feedback, TimeNow());
+    } else {
+      rtcp::TransportFeedback feedback =
+          BuildRtcpTransportFeedbackPacket(received_packets);
+      rtc::Buffer raw_packet = feedback.Build();
+      std::unique_ptr<rtcp::TransportFeedback> parsed_feedback =
+          rtcp::TransportFeedback::ParseFrom(raw_packet.data(),
+                                             raw_packet.size());
+      ASSERT_THAT(parsed_feedback, NotNull());
+      result = adapter.ProcessTransportFeedback(*parsed_feedback, TimeNow());
+    }
+    ASSERT_TRUE(result.has_value());
+    ComparePacketFeedbackVectors(received_packets, result->packet_feedbacks);
   }
 }
 
-TEST_F(TransportFeedbackAdapterTest, HandlesArrivalReordering) {
+TEST_P(TransportFeedbackAdapterTest, HandlesArrivalReordering) {
   TransportFeedbackAdapter adapter;
 
-  std::vector<PacketResult> packets;
-  packets.push_back(CreatePacket(120, 200, 0, 1500, kPacingInfo0));
-  packets.push_back(CreatePacket(110, 210, 1, 1500, kPacingInfo0));
-  packets.push_back(CreatePacket(100, 220, 2, 1500, kPacingInfo0));
+  std::vector<PacketTemplate> packets = {
+      {.transport_sequence_number = 0,
+       .rtp_sequence_number = 101,
+       .send_timestamp = Timestamp::Millis(200),
+       .receive_timestamp = Timestamp::Millis(120)},
+      {.transport_sequence_number = 1,
+       .rtp_sequence_number = 102,
+       .send_timestamp = Timestamp::Millis(210),
+       .receive_timestamp = Timestamp::Millis(110)},
+      {.transport_sequence_number = 2,
+       .rtp_sequence_number = 103,
+       .send_timestamp = Timestamp::Millis(220),
+       .receive_timestamp = Timestamp::Millis(100)}};
 
-  for (const PacketResult& packet : packets) {
-    adapter.AddPacket(CreatePacketToSend(packet),
-                      packet.sent_packet.pacing_info,
+  for (const PacketTemplate& packet : packets) {
+    adapter.AddPacket(CreatePacketToSend(packet), packet.pacing_info,
                       /*overhead=*/0u, TimeNow());
-    adapter.ProcessSentPacket(rtc::SentPacket(
-        packet.sent_packet.sequence_number, packet.sent_packet.send_time.ms()));
+    adapter.ProcessSentPacket(rtc::SentPacket(packet.transport_sequence_number,
+                                              packet.send_timestamp.ms()));
   }
 
   // Adapter keeps the packets ordered by sequence number (which is itself
@@ -320,26 +396,163 @@
   ComparePacketFeedbackVectors(packets, adapted_feedback->packet_feedbacks);
 }
 
-TEST_F(TransportFeedbackAdapterTest, IgnoreDuplicatePacketSentCalls) {
+TEST_P(TransportFeedbackAdapterTest, IgnoreDuplicatePacketSentCalls) {
   TransportFeedbackAdapter adapter;
 
-  PacketResult packet = CreatePacket(100, 200, 0, 1500, kPacingInfo0);
-  RtpPacketToSend packet_to_send =
-      CreatePacketToSend(packet, kSsrc, /*rtp_sequence_number=*/0);
+  PacketTemplate packet = {};
   // Add a packet and then mark it as sent.
-  adapter.AddPacket(packet_to_send, packet.sent_packet.pacing_info, 0u,
+  adapter.AddPacket(CreatePacketToSend(packet), packet.pacing_info, 0u,
                     TimeNow());
   std::optional<SentPacket> sent_packet = adapter.ProcessSentPacket(
-      rtc::SentPacket(packet.sent_packet.sequence_number,
-                      packet.sent_packet.send_time.ms(), rtc::PacketInfo()));
+      rtc::SentPacket(packet.transport_sequence_number,
+                      packet.send_timestamp.ms(), rtc::PacketInfo()));
   EXPECT_TRUE(sent_packet.has_value());
 
   // Call ProcessSentPacket() again with the same sequence number. This packet
   // has already been marked as sent and the call should be ignored.
   std::optional<SentPacket> duplicate_packet = adapter.ProcessSentPacket(
-      rtc::SentPacket(packet.sent_packet.sequence_number,
-                      packet.sent_packet.send_time.ms(), rtc::PacketInfo()));
+      rtc::SentPacket(packet.transport_sequence_number,
+                      packet.send_timestamp.ms(), rtc::PacketInfo()));
   EXPECT_FALSE(duplicate_packet.has_value());
 }
 
+TEST_P(TransportFeedbackAdapterTest,
+       SendReceiveTimeDiffTimeContinuouseBetweenFeedback) {
+  TransportFeedbackAdapter adapter;
+
+  PacketTemplate packets[] = {{.transport_sequence_number = 1,
+                               .rtp_sequence_number = 101,
+                               .send_timestamp = Timestamp::Millis(100),
+                               .pacing_info = kPacingInfo0,
+                               .receive_timestamp = Timestamp::Millis(200)},
+                              {.transport_sequence_number = 2,
+                               .rtp_sequence_number = 102,
+                               .send_timestamp = Timestamp::Millis(110),
+                               .pacing_info = kPacingInfo0,
+                               .receive_timestamp = Timestamp::Millis(210)}};
+
+  for (const PacketTemplate& packet : packets) {
+    adapter.AddPacket(CreatePacketToSend(packet), packet.pacing_info,
+                      /*overhead=*/0u, TimeNow());
+
+    adapter.ProcessSentPacket(rtc::SentPacket(packet.transport_sequence_number,
+                                              packet.send_timestamp.ms()));
+  }
+
+  std::optional<TransportPacketsFeedback> adapted_feedback_1 =
+      CreateAndProcessFeedback(std::vector<PacketTemplate>({packets[0]}),
+                               adapter);
+  std::optional<TransportPacketsFeedback> adapted_feedback_2 =
+      CreateAndProcessFeedback(std::vector<PacketTemplate>({packets[1]}),
+                               adapter);
+
+  ASSERT_EQ(adapted_feedback_1->packet_feedbacks.size(),
+            adapted_feedback_2->packet_feedbacks.size());
+  ASSERT_THAT(adapted_feedback_1->packet_feedbacks, testing::SizeIs(1));
+  EXPECT_EQ((adapted_feedback_1->packet_feedbacks[0].receive_time -
+             adapted_feedback_1->packet_feedbacks[0].sent_packet.send_time)
+                .RoundTo(TimeDelta::Millis(1)),
+            (adapted_feedback_2->packet_feedbacks[0].receive_time -
+             adapted_feedback_2->packet_feedbacks[0].sent_packet.send_time)
+                .RoundTo(TimeDelta::Millis(1)));
+}
+
+TEST_P(TransportFeedbackAdapterTest, ProcessSentPacketIncreaseOutstandingData) {
+  TransportFeedbackAdapter adapter;
+
+  PacketTemplate packet_1 = {.transport_sequence_number = 1,
+                             .packet_size = DataSize::Bytes(200)};
+  PacketTemplate packet_2 = {.transport_sequence_number = 2,
+                             .packet_size = DataSize::Bytes(300)};
+  adapter.AddPacket(CreatePacketToSend(packet_1), packet_1.pacing_info,
+                    /*overhead=*/0u, TimeNow());
+  std::optional<SentPacket> sent_packet_1 =
+      adapter.ProcessSentPacket(rtc::SentPacket(
+          packet_1.transport_sequence_number, packet_1.send_timestamp.ms()));
+
+  ASSERT_TRUE(sent_packet_1.has_value());
+  EXPECT_EQ(sent_packet_1->sequence_number, packet_1.transport_sequence_number);
+  // Only one packet in flight.
+  EXPECT_EQ(sent_packet_1->data_in_flight, packet_1.packet_size);
+  EXPECT_EQ(adapter.GetOutstandingData(), packet_1.packet_size);
+
+  adapter.AddPacket(CreatePacketToSend(packet_2), packet_2.pacing_info,
+                    /*overhead=*/0u, TimeNow());
+  std::optional<SentPacket> sent_packet_2 =
+      adapter.ProcessSentPacket(rtc::SentPacket(
+          packet_2.transport_sequence_number, packet_2.send_timestamp.ms()));
+
+  ASSERT_TRUE(sent_packet_2.has_value());
+  // Two packets in flight.
+  EXPECT_EQ(sent_packet_2->data_in_flight,
+            packet_1.packet_size + packet_2.packet_size);
+
+  EXPECT_EQ(adapter.GetOutstandingData(),
+            packet_1.packet_size + packet_2.packet_size);
+}
+
+TEST_P(TransportFeedbackAdapterTest, TransportPacketFeedbackHasDataInFlight) {
+  TransportFeedbackAdapter adapter;
+
+  const PacketTemplate packets[] = {
+      {
+          .transport_sequence_number = 1,
+          .rtp_sequence_number = 101,
+          .packet_size = DataSize::Bytes(200),
+          .send_timestamp = Timestamp::Millis(100),
+          .pacing_info = kPacingInfo0,
+          .receive_timestamp = Timestamp::Millis(200),
+      },
+      {
+          .transport_sequence_number = 2,
+          .rtp_sequence_number = 102,
+          .packet_size = DataSize::Bytes(300),
+          .send_timestamp = Timestamp::Millis(110),
+          .pacing_info = kPacingInfo0,
+          .receive_timestamp = Timestamp::Millis(210),
+      }};
+
+  for (const PacketTemplate& packet : packets) {
+    adapter.AddPacket(CreatePacketToSend(packet), packet.pacing_info,
+                      /*overhead=*/0u, TimeNow());
+
+    adapter.ProcessSentPacket(rtc::SentPacket(packet.transport_sequence_number,
+                                              packet.send_timestamp.ms()));
+  }
+
+  std::optional<TransportPacketsFeedback> adapted_feedback_1 =
+      CreateAndProcessFeedback(rtc::MakeArrayView(&packets[0], 1), adapter);
+  std::optional<TransportPacketsFeedback> adapted_feedback_2 =
+      CreateAndProcessFeedback(rtc::MakeArrayView(&packets[1], 1), adapter);
+  EXPECT_EQ(adapted_feedback_1->data_in_flight, packets[1].packet_size);
+  EXPECT_EQ(adapted_feedback_2->data_in_flight, DataSize::Zero());
+}
+
+TEST(TransportFeedbackAdapterCongestionFeedbackTest,
+     CongestionControlFeedbackResultHasEcn) {
+  TransportFeedbackAdapter adapter;
+
+  PacketTemplate packet = {
+      .transport_sequence_number = 1,
+      .rtp_sequence_number = 101,
+      .packet_size = DataSize::Bytes(200),
+      .send_timestamp = Timestamp::Millis(100),
+      .pacing_info = kPacingInfo0,
+      .receive_timestamp = Timestamp::Millis(200),
+  };
+  adapter.AddPacket(CreatePacketToSend(packet), packet.pacing_info,
+                    /*overhead=*/0u, TimeNow());
+  adapter.ProcessSentPacket(rtc::SentPacket(packet.transport_sequence_number,
+                                            packet.send_timestamp.ms()));
+
+  packet.ecn = EcnMarking::kCe;
+  rtcp::CongestionControlFeedback rtcp_feedback =
+      BuildRtcpCongestionControlFeedbackPacket(rtc::MakeArrayView(&packet, 1));
+  std::optional<TransportPacketsFeedback> adapted_feedback =
+      adapter.ProcessCongestionControlFeedback(rtcp_feedback, TimeNow());
+
+  ASSERT_THAT(adapted_feedback->packet_feedbacks, SizeIs(1));
+  ASSERT_THAT(adapted_feedback->packet_feedbacks[0].ecn, EcnMarking::kCe);
+}
+
 }  // namespace webrtc
diff --git a/rtc_base/network_route.h b/rtc_base/network_route.h
index 17b43e5..3f678e3 100644
--- a/rtc_base/network_route.h
+++ b/rtc_base/network_route.h
@@ -88,6 +88,7 @@
   }
 
   bool operator==(const NetworkRoute& other) const;
+  bool operator!=(const NetworkRoute& other) { return !operator==(other); }
 };
 
 }  // namespace rtc