Send periodic TransportFeedback based on extension version

Today, behaviour is decided based on if transport sequence number v2 is
in the SDP answer. But it might be better to decide based on received
packets since it is valid to negotiate both extensions.

Another bonus With this solution is that Call does not need to know
about receive header exensions.
This is an alternative to https://webrtc-review.googlesource.com/c/src/+/291337

Bug: webrtc:7135
Change-Id: Ib75474127d6e2e2029557b8bb2528eaac66979f8
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/291525
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Johannes Kron <kron@webrtc.org>
Commit-Queue: Per Kjellander <perkj@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39226}
diff --git a/call/call.cc b/call/call.cc
index e676d7a..a849cd5 100644
--- a/call/call.cc
+++ b/call/call.cc
@@ -14,6 +14,7 @@
 
 #include <algorithm>
 #include <atomic>
+#include <cstdint>
 #include <map>
 #include <memory>
 #include <set>
@@ -50,6 +51,7 @@
 #include "modules/rtp_rtcp/include/flexfec_receiver.h"
 #include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
 #include "modules/rtp_rtcp/source/byte_io.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_util.h"
 #include "modules/video_coding/fec_controller_default.h"
@@ -73,13 +75,6 @@
 namespace webrtc {
 
 namespace {
-bool SendPeriodicFeedback(const std::vector<RtpExtension>& extensions) {
-  for (const auto& extension : extensions) {
-    if (extension.uri == RtpExtension::kTransportSequenceNumberV2Uri)
-      return false;
-  }
-  return true;
-}
 
 const int* FindKeyByValue(const std::map<int, int>& m, int v) {
   for (const auto& kv : m) {
@@ -1009,9 +1004,6 @@
   TRACE_EVENT0("webrtc", "Call::CreateVideoReceiveStream");
   RTC_DCHECK_RUN_ON(worker_thread_);
 
-  receive_side_cc_.SetSendPeriodicFeedback(
-      SendPeriodicFeedback(configuration.rtp.extensions));
-
   EnsureStarted();
 
   event_log_->Log(std::make_unique<RtcEventVideoReceiveStreamConfig>(
@@ -1469,24 +1461,17 @@
 void Call::NotifyBweOfReceivedPacket(const RtpPacketReceived& packet,
                                      MediaType media_type) {
   RTC_DCHECK_RUN_ON(worker_thread_);
-  RTPHeader header;
-  packet.GetHeader(&header);
 
   ReceivedPacket packet_msg;
   packet_msg.size = DataSize::Bytes(packet.payload_size());
   packet_msg.receive_time = packet.arrival_time();
-  if (header.extension.hasAbsoluteSendTime) {
-    packet_msg.send_time = header.extension.GetAbsoluteSendTimestamp();
+  uint32_t time_24;
+  if (packet.GetExtension<AbsoluteSendTime>(&time_24)) {
+    packet_msg.send_time = AbsoluteSendTime::ToTimestamp(time_24);
   }
   transport_send_->OnReceivedPacket(packet_msg);
 
-  // For audio, we only support send side BWE.
-  if (media_type == MediaType::VIDEO ||
-      header.extension.hasTransportSequenceNumber) {
-    receive_side_cc_.OnReceivedPacket(
-        packet.arrival_time().ms(),
-        packet.payload_size() + packet.padding_size(), header);
-  }
+  receive_side_cc_.OnReceivedPacket(packet, media_type);
 }
 
 bool Call::RegisterReceiveStream(uint32_t ssrc,
diff --git a/modules/congestion_controller/BUILD.gn b/modules/congestion_controller/BUILD.gn
index 33f5508..e814a63 100644
--- a/modules/congestion_controller/BUILD.gn
+++ b/modules/congestion_controller/BUILD.gn
@@ -27,6 +27,7 @@
   ]
 
   deps = [
+    "../../api:rtp_parameters",
     "../../api/transport:network_control",
     "../../api/units:data_rate",
     "../../api/units:time_delta",
diff --git a/modules/congestion_controller/include/receive_side_congestion_controller.h b/modules/congestion_controller/include/receive_side_congestion_controller.h
index 7696396..82f098c 100644
--- a/modules/congestion_controller/include/receive_side_congestion_controller.h
+++ b/modules/congestion_controller/include/receive_side_congestion_controller.h
@@ -20,6 +20,7 @@
 #include "modules/congestion_controller/remb_throttler.h"
 #include "modules/pacing/packet_router.h"
 #include "modules/remote_bitrate_estimator/remote_estimator_proxy.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
 #include "rtc_base/synchronization/mutex.h"
 #include "rtc_base/thread_annotations.h"
 
@@ -41,12 +42,13 @@
 
   ~ReceiveSideCongestionController() override {}
 
+  void OnReceivedPacket(const RtpPacketReceived& packet, MediaType media_type);
+
+  // TODO(perkj, bugs.webrtc.org/14859): Remove all usage. This method is
+  // currently not used by PeerConnections.
   virtual void OnReceivedPacket(int64_t arrival_time_ms,
                                 size_t payload_size,
                                 const RTPHeader& header);
-
-  void SetSendPeriodicFeedback(bool send_periodic_feedback);
-
   // Implements CallStatsObserver.
   void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) override;
 
diff --git a/modules/congestion_controller/receive_side_congestion_controller.cc b/modules/congestion_controller/receive_side_congestion_controller.cc
index e43b020..9352e50 100644
--- a/modules/congestion_controller/receive_side_congestion_controller.cc
+++ b/modules/congestion_controller/receive_side_congestion_controller.cc
@@ -10,6 +10,7 @@
 
 #include "modules/congestion_controller/include/receive_side_congestion_controller.h"
 
+#include "api/media_types.h"
 #include "api/units/data_rate.h"
 #include "modules/pacing/packet_router.h"
 #include "modules/remote_bitrate_estimator/include/bwe_defines.h"
@@ -90,6 +91,31 @@
       packets_since_absolute_send_time_(0) {}
 
 void ReceiveSideCongestionController::OnReceivedPacket(
+    const RtpPacketReceived& packet,
+    MediaType media_type) {
+  bool has_transport_sequence_number =
+      packet.HasExtension<TransportSequenceNumber>() ||
+      packet.HasExtension<TransportSequenceNumberV2>();
+  if (media_type == MediaType::AUDIO && !has_transport_sequence_number) {
+    // For audio, we only support send side BWE.
+    return;
+  }
+
+  if (has_transport_sequence_number) {
+    // Send-side BWE.
+    remote_estimator_proxy_.IncomingPacket(packet);
+  } else {
+    // Receive-side BWE.
+    MutexLock lock(&mutex_);
+    RTPHeader header;
+    packet.GetHeader(&header);
+    PickEstimatorFromHeader(header);
+    rbe_->IncomingPacket(packet.arrival_time().ms(),
+                         packet.payload_size() + packet.padding_size(), header);
+  }
+}
+
+void ReceiveSideCongestionController::OnReceivedPacket(
     int64_t arrival_time_ms,
     size_t payload_size,
     const RTPHeader& header) {
@@ -102,11 +128,6 @@
   }
 }
 
-void ReceiveSideCongestionController::SetSendPeriodicFeedback(
-    bool send_periodic_feedback) {
-  remote_estimator_proxy_.SetSendPeriodicFeedback(send_periodic_feedback);
-}
-
 void ReceiveSideCongestionController::OnBitrateChanged(int bitrate_bps) {
   remote_estimator_proxy_.OnBitrateChanged(bitrate_bps);
 }
diff --git a/modules/remote_bitrate_estimator/BUILD.gn b/modules/remote_bitrate_estimator/BUILD.gn
index 463530b..0f1e5b3 100644
--- a/modules/remote_bitrate_estimator/BUILD.gn
+++ b/modules/remote_bitrate_estimator/BUILD.gn
@@ -139,5 +139,6 @@
       "../pacing",
       "../rtp_rtcp:rtp_rtcp_format",
     ]
+    absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
   }
 }
diff --git a/modules/remote_bitrate_estimator/remote_estimator_proxy.cc b/modules/remote_bitrate_estimator/remote_estimator_proxy.cc
index 598279e..3672604 100644
--- a/modules/remote_bitrate_estimator/remote_estimator_proxy.cc
+++ b/modules/remote_bitrate_estimator/remote_estimator_proxy.cc
@@ -11,13 +11,16 @@
 #include "modules/remote_bitrate_estimator/remote_estimator_proxy.h"
 
 #include <algorithm>
+#include <cstdint>
 #include <limits>
 #include <memory>
 #include <utility>
 
+#include "absl/types/optional.h"
 #include "api/units/data_size.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/remote_estimate.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/numerics/safe_minmax.h"
@@ -80,6 +83,36 @@
   }
 }
 
+void RemoteEstimatorProxy::IncomingPacket(const RtpPacketReceived& packet) {
+  if (packet.arrival_time().IsInfinite()) {
+    RTC_LOG(LS_WARNING) << "Arrival time not set.";
+    return;
+  }
+  MutexLock lock(&lock_);
+  send_periodic_feedback_ = packet.HasExtension<TransportSequenceNumber>();
+
+  Packet internal_packet = {.arrival_time = packet.arrival_time(),
+                            .size = DataSize::Bytes(packet.size()),
+                            .ssrc = packet.Ssrc()};
+  uint16_t seqnum;
+  absl::optional<FeedbackRequest> feedback_request;
+  if (!packet.GetExtension<TransportSequenceNumber>(&seqnum)) {
+    if (!packet.GetExtension<TransportSequenceNumberV2>(&seqnum,
+                                                        &feedback_request)) {
+      RTC_DCHECK_NOTREACHED() << " Expected transport sequence number.";
+      return;
+    }
+  }
+  internal_packet.transport_sequence_number = seqnum;
+  internal_packet.feedback_request = feedback_request;
+
+  uint32_t send_time_24_bits;
+  if (packet.GetExtension<AbsoluteSendTime>(&send_time_24_bits)) {
+    internal_packet.absolute_send_time_24bits = send_time_24_bits;
+  }
+  IncomingPacket(internal_packet);
+}
+
 void RemoteEstimatorProxy::IncomingPacket(int64_t arrival_time_ms,
                                           size_t payload_size,
                                           const RTPHeader& header) {
@@ -98,11 +131,11 @@
   }
   packet.feedback_request = header.extension.feedback_request;
 
+  MutexLock lock(&lock_);
   IncomingPacket(packet);
 }
 
 void RemoteEstimatorProxy::IncomingPacket(Packet packet) {
-  MutexLock lock(&lock_);
   media_ssrc_ = packet.ssrc;
   int64_t seq = 0;
 
@@ -154,6 +187,8 @@
 TimeDelta RemoteEstimatorProxy::Process(Timestamp now) {
   MutexLock lock(&lock_);
   if (!send_periodic_feedback_) {
+    // If TransportSequenceNumberV2 has been received in one packet,
+    // PeriodicFeedback is disabled for the rest of the call.
     return TimeDelta::PlusInfinity();
   }
   Timestamp next_process_time = last_process_time_ + send_interval_;
@@ -189,12 +224,6 @@
   send_interval_ = send_interval;
 }
 
-void RemoteEstimatorProxy::SetSendPeriodicFeedback(
-    bool send_periodic_feedback) {
-  MutexLock lock(&lock_);
-  send_periodic_feedback_ = send_periodic_feedback;
-}
-
 void RemoteEstimatorProxy::SetTransportOverhead(DataSize overhead_per_packet) {
   MutexLock lock(&lock_);
   packet_overhead_ = overhead_per_packet;
diff --git a/modules/remote_bitrate_estimator/remote_estimator_proxy.h b/modules/remote_bitrate_estimator/remote_estimator_proxy.h
index 54257ea..a28e85c 100644
--- a/modules/remote_bitrate_estimator/remote_estimator_proxy.h
+++ b/modules/remote_bitrate_estimator/remote_estimator_proxy.h
@@ -26,6 +26,7 @@
 #include "modules/remote_bitrate_estimator/packet_arrival_map.h"
 #include "modules/rtp_rtcp/source/rtcp_packet.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
 #include "rtc_base/numerics/sequence_number_unwrapper.h"
 #include "rtc_base/synchronization/mutex.h"
 
@@ -44,16 +45,10 @@
                        NetworkStateEstimator* network_state_estimator);
   ~RemoteEstimatorProxy();
 
-  struct Packet {
-    Timestamp arrival_time;
-    DataSize size;
-    uint32_t ssrc;
-    absl::optional<uint32_t> absolute_send_time_24bits;
-    absl::optional<uint16_t> transport_sequence_number;
-    absl::optional<FeedbackRequest> feedback_request;
-  };
-  void IncomingPacket(Packet packet);
+  void IncomingPacket(const RtpPacketReceived& packet);
 
+  // TODO(perkj, bugs.webrtc.org/14859): Remove all usage. This method is
+  // currently not used by PeerConnections.
   void IncomingPacket(int64_t arrival_time_ms,
                       size_t payload_size,
                       const RTPHeader& header);
@@ -63,10 +58,19 @@
   TimeDelta Process(Timestamp now);
 
   void OnBitrateChanged(int bitrate);
-  void SetSendPeriodicFeedback(bool send_periodic_feedback);
   void SetTransportOverhead(DataSize overhead_per_packet);
 
  private:
+  struct Packet {
+    Timestamp arrival_time;
+    DataSize size;
+    uint32_t ssrc;
+    absl::optional<uint32_t> absolute_send_time_24bits;
+    absl::optional<uint16_t> transport_sequence_number;
+    absl::optional<FeedbackRequest> feedback_request;
+  };
+  void IncomingPacket(Packet packet) RTC_EXCLUSIVE_LOCKS_REQUIRED(&lock_);
+
   void MaybeCullOldPackets(int64_t sequence_number, Timestamp arrival_time)
       RTC_EXCLUSIVE_LOCKS_REQUIRED(&lock_);
   void SendPeriodicFeedbacks() RTC_EXCLUSIVE_LOCKS_REQUIRED(&lock_);
diff --git a/modules/remote_bitrate_estimator/remote_estimator_proxy_unittest.cc b/modules/remote_bitrate_estimator/remote_estimator_proxy_unittest.cc
index 437fd6f..c148ce6 100644
--- a/modules/remote_bitrate_estimator/remote_estimator_proxy_unittest.cc
+++ b/modules/remote_bitrate_estimator/remote_estimator_proxy_unittest.cc
@@ -10,9 +10,11 @@
 
 #include "modules/remote_bitrate_estimator/remote_estimator_proxy.h"
 
+#include <cstdint>
 #include <memory>
 #include <utility>
 
+#include "absl/types/optional.h"
 #include "api/transport/network_types.h"
 #include "api/transport/test/mock_network_control.h"
 #include "api/units/data_size.h"
@@ -20,6 +22,7 @@
 #include "api/units/timestamp.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_packet_received.h"
 #include "system_wrappers/include/clock.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
@@ -34,7 +37,6 @@
 using ::testing::Return;
 using ::testing::SizeIs;
 
-constexpr DataSize kDefaultPacketSize = DataSize::Bytes(100);
 constexpr uint32_t kMediaSsrc = 456;
 constexpr uint16_t kBaseSeq = 10;
 constexpr Timestamp kBaseTime = Timestamp::Millis(123);
@@ -81,15 +83,32 @@
         proxy_(feedback_sender_.AsStdFunction(), &network_state_estimator_) {}
 
  protected:
-  void IncomingPacket(
+  void IncomingPacket(uint16_t seq,
+                      Timestamp arrival_time,
+                      absl::optional<uint32_t> abs_send_time = absl::nullopt) {
+    RtpHeaderExtensionMap map;
+    map.Register<TransportSequenceNumber>(1);
+    map.Register<AbsoluteSendTime>(2);
+    RtpPacketReceived packet(&map, arrival_time);
+    packet.SetSsrc(kMediaSsrc);
+    packet.SetExtension<TransportSequenceNumber>(seq);
+    if (abs_send_time) {
+      packet.SetExtension<AbsoluteSendTime>(*abs_send_time);
+    }
+    proxy_.IncomingPacket(packet);
+  }
+
+  void IncomingPacketV2(
       uint16_t seq,
       Timestamp arrival_time,
       absl::optional<FeedbackRequest> feedback_request = absl::nullopt) {
-    proxy_.IncomingPacket({.arrival_time = arrival_time,
-                           .size = DataSize::Bytes(100),
-                           .ssrc = kMediaSsrc,
-                           .transport_sequence_number = seq,
-                           .feedback_request = feedback_request});
+    RtpHeaderExtensionMap map;
+    map.Register<TransportSequenceNumberV2>(1);
+    RtpPacketReceived packet(&map, arrival_time);
+    packet.SetSsrc(kMediaSsrc);
+    packet.SetExtension<webrtc::TransportSequenceNumberV2>(seq,
+                                                           feedback_request);
+    proxy_.IncomingPacket(packet);
   }
 
   void Process() {
@@ -453,22 +472,20 @@
 //////////////////////////////////////////////////////////////////////////////
 typedef RemoteEstimatorProxyTest RemoteEstimatorProxyOnRequestTest;
 TEST_F(RemoteEstimatorProxyOnRequestTest, DisablesPeriodicProcess) {
-  proxy_.SetSendPeriodicFeedback(false);
+  IncomingPacketV2(kBaseSeq, kBaseTime);
   EXPECT_EQ(proxy_.Process(clock_.CurrentTime()), TimeDelta::PlusInfinity());
 }
 
 TEST_F(RemoteEstimatorProxyOnRequestTest, ProcessDoesNotSendFeedback) {
-  proxy_.SetSendPeriodicFeedback(false);
-  IncomingPacket(kBaseSeq, kBaseTime);
+  IncomingPacketV2(kBaseSeq, kBaseTime);
   EXPECT_CALL(feedback_sender_, Call).Times(0);
   Process();
 }
 
 TEST_F(RemoteEstimatorProxyOnRequestTest, RequestSinglePacketFeedback) {
-  proxy_.SetSendPeriodicFeedback(false);
-  IncomingPacket(kBaseSeq, kBaseTime);
-  IncomingPacket(kBaseSeq + 1, kBaseTime + kMaxSmallDelta);
-  IncomingPacket(kBaseSeq + 2, kBaseTime + 2 * kMaxSmallDelta);
+  IncomingPacketV2(kBaseSeq, kBaseTime);
+  IncomingPacketV2(kBaseSeq + 1, kBaseTime + kMaxSmallDelta);
+  IncomingPacketV2(kBaseSeq + 2, kBaseTime + 2 * kMaxSmallDelta);
 
   EXPECT_CALL(feedback_sender_, Call)
       .WillOnce(Invoke(
@@ -487,15 +504,14 @@
 
   constexpr FeedbackRequest kSinglePacketFeedbackRequest = {
       /*include_timestamps=*/true, /*sequence_count=*/1};
-  IncomingPacket(kBaseSeq + 3, kBaseTime + 3 * kMaxSmallDelta,
-                 kSinglePacketFeedbackRequest);
+  IncomingPacketV2(kBaseSeq + 3, kBaseTime + 3 * kMaxSmallDelta,
+                   kSinglePacketFeedbackRequest);
 }
 
 TEST_F(RemoteEstimatorProxyOnRequestTest, RequestLastFivePacketFeedback) {
-  proxy_.SetSendPeriodicFeedback(false);
   int i = 0;
   for (; i < 10; ++i) {
-    IncomingPacket(kBaseSeq + i, kBaseTime + i * kMaxSmallDelta);
+    IncomingPacketV2(kBaseSeq + i, kBaseTime + i * kMaxSmallDelta);
   }
 
   EXPECT_CALL(feedback_sender_, Call)
@@ -520,17 +536,16 @@
 
   constexpr FeedbackRequest kFivePacketsFeedbackRequest = {
       /*include_timestamps=*/true, /*sequence_count=*/5};
-  IncomingPacket(kBaseSeq + i, kBaseTime + i * kMaxSmallDelta,
-                 kFivePacketsFeedbackRequest);
+  IncomingPacketV2(kBaseSeq + i, kBaseTime + i * kMaxSmallDelta,
+                   kFivePacketsFeedbackRequest);
 }
 
 TEST_F(RemoteEstimatorProxyOnRequestTest,
        RequestLastFivePacketFeedbackMissingPackets) {
-  proxy_.SetSendPeriodicFeedback(false);
   int i = 0;
   for (; i < 10; ++i) {
     if (i != 7 && i != 9)
-      IncomingPacket(kBaseSeq + i, kBaseTime + i * kMaxSmallDelta);
+      IncomingPacketV2(kBaseSeq + i, kBaseTime + i * kMaxSmallDelta);
   }
 
   EXPECT_CALL(feedback_sender_, Call)
@@ -552,8 +567,8 @@
 
   constexpr FeedbackRequest kFivePacketsFeedbackRequest = {
       /*include_timestamps=*/true, /*sequence_count=*/5};
-  IncomingPacket(kBaseSeq + i, kBaseTime + i * kMaxSmallDelta,
-                 kFivePacketsFeedbackRequest);
+  IncomingPacketV2(kBaseSeq + i, kBaseTime + i * kMaxSmallDelta,
+                   kFivePacketsFeedbackRequest);
 }
 
 TEST_F(RemoteEstimatorProxyTest, ReportsIncomingPacketToNetworkStateEstimator) {
@@ -564,16 +579,11 @@
   EXPECT_CALL(network_state_estimator_, OnReceivedPacket(_))
       .WillOnce(Invoke([&](const PacketResult& packet) {
         EXPECT_EQ(packet.receive_time, kBaseTime);
-        EXPECT_EQ(packet.sent_packet.size,
-                  kDefaultPacketSize + kPacketOverhead);
+        EXPECT_GT(packet.sent_packet.size, kPacketOverhead);
         first_send_timestamp = packet.sent_packet.send_time;
       }));
   // Incoming packet with abs sendtime but without transport sequence number.
-  proxy_.IncomingPacket(
-      {.arrival_time = kBaseTime,
-       .size = kDefaultPacketSize,
-       .ssrc = kMediaSsrc,
-       .absolute_send_time_24bits = AbsoluteSendTime::To24Bits(kBaseTime)});
+  IncomingPacket(kBaseSeq, kBaseTime, AbsoluteSendTime::To24Bits(kBaseTime));
 
   // Expect packet with older abs send time to be treated as sent at the same
   // time as the previous packet due to reordering.
@@ -583,12 +593,9 @@
         EXPECT_EQ(packet.sent_packet.send_time, first_send_timestamp);
       }));
 
-  proxy_.IncomingPacket(
-      {.arrival_time = kBaseTime,
-       .size = kDefaultPacketSize,
-       .ssrc = kMediaSsrc,
-       .absolute_send_time_24bits =
-           AbsoluteSendTime::To24Bits(kBaseTime - TimeDelta::Millis(12))});
+  IncomingPacket(kBaseSeq + 1, kBaseTime,
+                 /*abs_send_time=*/
+                 AbsoluteSendTime::To24Bits(kBaseTime - TimeDelta::Millis(12)));
 }
 
 TEST_F(RemoteEstimatorProxyTest, IncomingPacketHandlesWrapInAbsSendTime) {
@@ -606,11 +613,7 @@
         EXPECT_EQ(packet.receive_time, kBaseTime);
         first_send_timestamp = packet.sent_packet.send_time;
       }));
-  proxy_.IncomingPacket({.arrival_time = kBaseTime,
-                         .size = kDefaultPacketSize,
-                         .ssrc = kMediaSsrc,
-                         .absolute_send_time_24bits = kFirstAbsSendTime,
-                         .transport_sequence_number = kBaseSeq});
+  IncomingPacket(kBaseSeq, kBaseTime, kFirstAbsSendTime);
 
   EXPECT_CALL(network_state_estimator_, OnReceivedPacket(_))
       .WillOnce(Invoke([first_send_timestamp,
@@ -619,21 +622,14 @@
         EXPECT_EQ(packet.sent_packet.send_time.ms(),
                   (first_send_timestamp + kExpectedAbsSendTimeDelta).ms());
       }));
-  proxy_.IncomingPacket({.arrival_time = kBaseTime + TimeDelta::Millis(123),
-                         .size = kDefaultPacketSize,
-                         .ssrc = kMediaSsrc,
-                         .absolute_send_time_24bits = kSecondAbsSendTime,
-                         .transport_sequence_number = kBaseSeq + 1});
+  IncomingPacket(kBaseSeq + 1, kBaseTime + TimeDelta::Millis(123),
+                 kSecondAbsSendTime);
 }
 
 TEST_F(RemoteEstimatorProxyTest, SendTransportFeedbackAndNetworkStateUpdate) {
-  proxy_.IncomingPacket(
-      {.arrival_time = kBaseTime,
-       .size = kDefaultPacketSize,
-       .ssrc = kMediaSsrc,
-       .absolute_send_time_24bits =
-           AbsoluteSendTime::To24Bits(kBaseTime - TimeDelta::Millis(1)),
-       .transport_sequence_number = kBaseSeq});
+  IncomingPacket(kBaseSeq, kBaseTime,
+                 AbsoluteSendTime::To24Bits(kBaseTime - TimeDelta::Millis(1)));
+
   EXPECT_CALL(network_state_estimator_, GetCurrentEstimate())
       .WillOnce(Return(NetworkStateEstimate()));
   EXPECT_CALL(feedback_sender_, Call(SizeIs(2)));
diff --git a/modules/rtp_rtcp/source/rtp_header_extensions.h b/modules/rtp_rtcp/source/rtp_header_extensions.h
index d80e0da..04b2cd6 100644
--- a/modules/rtp_rtcp/source/rtp_header_extensions.h
+++ b/modules/rtp_rtcp/source/rtp_header_extensions.h
@@ -13,6 +13,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <cstdint>
 #include <string>
 #include <vector>
 
@@ -49,6 +50,11 @@
     RTC_DCHECK_LT(time6x18, 1 << 24);
     return static_cast<uint32_t>(time6x18);
   }
+
+  static constexpr Timestamp ToTimestamp(uint32_t time_24bits) {
+    RTC_DCHECK_LT(time_24bits, (1 << 24));
+    return Timestamp::Micros((time_24bits* int64_t{1'000'000}) >> 18);
+  }
 };
 
 class AbsoluteCaptureTimeExtension {