Add helper classes to send and receive abs-capture-time extensions.

This change adds helper classes to manipulate Absolute Capture Time header extensions. Both classes support the "timestamp interpolation" optimization.

Bug: webrtc:10739
Change-Id: I08eff46eb8910842a6dbaa3288b976004fabe1c7
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/149801
Commit-Queue: Chen Xing <chxg@google.com>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28936}
diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn
index 3608bae..3d6c0e7 100644
--- a/modules/rtp_rtcp/BUILD.gn
+++ b/modules/rtp_rtcp/BUILD.gn
@@ -131,6 +131,10 @@
     "include/rtp_header_parser.h",
     "include/rtp_rtcp.h",
     "include/ulpfec_receiver.h",
+    "source/absolute_capture_time_receiver.cc",
+    "source/absolute_capture_time_receiver.h",
+    "source/absolute_capture_time_sender.cc",
+    "source/absolute_capture_time_sender.h",
     "source/dtmf_queue.cc",
     "source/dtmf_queue.h",
     "source/fec_private_tables_bursty.cc",
@@ -224,6 +228,8 @@
     "../../api/rtc_event_log",
     "../../api/transport:field_trial_based_config",
     "../../api/transport:webrtc_key_value_config",
+    "../../api/units:time_delta",
+    "../../api/units:timestamp",
     "../../api/video:video_bitrate_allocation",
     "../../api/video:video_bitrate_allocator",
     "../../api/video:video_frame",
@@ -385,6 +391,8 @@
     testonly = true
 
     sources = [
+      "source/absolute_capture_time_receiver_unittest.cc",
+      "source/absolute_capture_time_sender_unittest.cc",
       "source/byte_io_unittest.cc",
       "source/fec_private_tables_bursty_unittest.cc",
       "source/flexfec_header_reader_writer_unittest.cc",
diff --git a/modules/rtp_rtcp/source/absolute_capture_time_receiver.cc b/modules/rtp_rtcp/source/absolute_capture_time_receiver.cc
new file mode 100644
index 0000000..62f300d
--- /dev/null
+++ b/modules/rtp_rtcp/source/absolute_capture_time_receiver.cc
@@ -0,0 +1,150 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/rtp_rtcp/source/absolute_capture_time_receiver.h"
+
+#include <limits>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+constexpr Timestamp kInvalidLastReceiveTime = Timestamp::MinusInfinity();
+}  // namespace
+
+constexpr TimeDelta AbsoluteCaptureTimeReceiver::kInterpolationMaxInterval;
+
+AbsoluteCaptureTimeReceiver::AbsoluteCaptureTimeReceiver(Clock* clock)
+    : clock_(clock),
+      remote_to_local_clock_offset_(absl::nullopt),
+      last_receive_time_(kInvalidLastReceiveTime) {}
+
+uint32_t AbsoluteCaptureTimeReceiver::GetSource(
+    uint32_t ssrc,
+    rtc::ArrayView<const uint32_t> csrcs) {
+  if (csrcs.empty()) {
+    return ssrc;
+  }
+
+  return csrcs[0];
+}
+
+void AbsoluteCaptureTimeReceiver::SetRemoteToLocalClockOffset(
+    absl::optional<int64_t> value_q32x32) {
+  rtc::CritScope cs(&crit_);
+
+  remote_to_local_clock_offset_ = value_q32x32;
+}
+
+absl::optional<AbsoluteCaptureTime>
+AbsoluteCaptureTimeReceiver::OnReceivePacket(
+    uint32_t source,
+    uint32_t rtp_timestamp,
+    uint32_t rtp_clock_frequency,
+    const absl::optional<AbsoluteCaptureTime>& received_extension) {
+  const Timestamp receive_time = clock_->CurrentTime();
+
+  rtc::CritScope cs(&crit_);
+
+  AbsoluteCaptureTime extension;
+  if (received_extension == absl::nullopt) {
+    if (!ShouldInterpolateExtension(receive_time, source, rtp_timestamp,
+                                    rtp_clock_frequency)) {
+      last_receive_time_ = kInvalidLastReceiveTime;
+      return absl::nullopt;
+    }
+
+    extension.absolute_capture_timestamp = InterpolateAbsoluteCaptureTimestamp(
+        rtp_timestamp, rtp_clock_frequency, last_rtp_timestamp_,
+        last_absolute_capture_timestamp_);
+    extension.estimated_capture_clock_offset =
+        last_estimated_capture_clock_offset_;
+  } else {
+    last_source_ = source;
+    last_rtp_timestamp_ = rtp_timestamp;
+    last_rtp_clock_frequency_ = rtp_clock_frequency;
+    last_absolute_capture_timestamp_ =
+        received_extension->absolute_capture_timestamp;
+    last_estimated_capture_clock_offset_ =
+        received_extension->estimated_capture_clock_offset;
+
+    last_receive_time_ = receive_time;
+
+    extension = *received_extension;
+  }
+
+  extension.estimated_capture_clock_offset = AdjustEstimatedCaptureClockOffset(
+      extension.estimated_capture_clock_offset);
+
+  return extension;
+}
+
+uint64_t AbsoluteCaptureTimeReceiver::InterpolateAbsoluteCaptureTimestamp(
+    uint32_t rtp_timestamp,
+    uint32_t rtp_clock_frequency,
+    uint32_t last_rtp_timestamp,
+    uint64_t last_absolute_capture_timestamp) {
+  RTC_DCHECK_GT(rtp_clock_frequency, 0);
+
+  return last_absolute_capture_timestamp +
+         static_cast<int64_t>(
+             rtc::dchecked_cast<uint64_t>(rtp_timestamp - last_rtp_timestamp)
+             << 32) /
+             rtp_clock_frequency;
+}
+
+bool AbsoluteCaptureTimeReceiver::ShouldInterpolateExtension(
+    Timestamp receive_time,
+    uint32_t source,
+    uint32_t rtp_timestamp,
+    uint32_t rtp_clock_frequency) const {
+  // Shouldn't if we don't have a previously received extension stored.
+  if (last_receive_time_ == kInvalidLastReceiveTime) {
+    return false;
+  }
+
+  // Shouldn't if the last received extension is too old.
+  if ((receive_time - last_receive_time_) > kInterpolationMaxInterval) {
+    return false;
+  }
+
+  // Shouldn't if the source has changed.
+  if (last_source_ != source) {
+    return false;
+  }
+
+  // Shouldn't if the RTP clock frequency has changed.
+  if (last_rtp_clock_frequency_ != rtp_clock_frequency) {
+    return false;
+  }
+
+  // Shouldn't if the RTP clock frequency is invalid.
+  if (rtp_clock_frequency <= 0) {
+    return false;
+  }
+
+  return true;
+}
+
+absl::optional<int64_t>
+AbsoluteCaptureTimeReceiver::AdjustEstimatedCaptureClockOffset(
+    absl::optional<int64_t> received_value) const {
+  if (received_value == absl::nullopt ||
+      remote_to_local_clock_offset_ == absl::nullopt) {
+    return absl::nullopt;
+  }
+
+  // Do calculations as "unsigned" to make overflows deterministic.
+  return static_cast<uint64_t>(*received_value) +
+         static_cast<uint64_t>(*remote_to_local_clock_offset_);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/absolute_capture_time_receiver.h b/modules/rtp_rtcp/source/absolute_capture_time_receiver.h
new file mode 100644
index 0000000..10f9539
--- /dev/null
+++ b/modules/rtp_rtcp/source/absolute_capture_time_receiver.h
@@ -0,0 +1,100 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_RECEIVER_H_
+#define MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_RECEIVER_H_
+
+#include "api/array_view.h"
+#include "api/rtp_headers.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+#include "rtc_base/critical_section.h"
+#include "rtc_base/thread_annotations.h"
+#include "system_wrappers/include/clock.h"
+
+namespace webrtc {
+
+//
+// Helper class for receiving the |AbsoluteCaptureTime| header extension.
+//
+// Supports the "timestamp interpolation" optimization:
+//   A receiver SHOULD memorize the capture system (i.e. CSRC/SSRC), capture
+//   timestamp, and RTP timestamp of the most recently received abs-capture-time
+//   packet on each received stream. It can then use that information, in
+//   combination with RTP timestamps of packets without abs-capture-time, to
+//   extrapolate missing capture timestamps.
+//
+// See: https://webrtc.org/experiments/rtp-hdrext/abs-capture-time/
+//
+class AbsoluteCaptureTimeReceiver {
+ public:
+  static constexpr TimeDelta kInterpolationMaxInterval =
+      TimeDelta::Millis<5000>();
+
+  explicit AbsoluteCaptureTimeReceiver(Clock* clock);
+
+  // Returns the source (i.e. SSRC or CSRC) of the capture system.
+  static uint32_t GetSource(uint32_t ssrc,
+                            rtc::ArrayView<const uint32_t> csrcs);
+
+  // Sets the NTP clock offset between the sender system (which may be different
+  // from the capture system) and the local system. This information is normally
+  // provided by passing half the value of the Round-Trip Time estimation given
+  // by RTCP sender reports (see DLSR/DLRR).
+  //
+  // Note that the value must be in Q32.32-formatted fixed-point seconds.
+  void SetRemoteToLocalClockOffset(absl::optional<int64_t> value_q32x32);
+
+  // Returns a received header extension, an interpolated header extension, or
+  // |absl::nullopt| if it's not possible to interpolate a header extension.
+  absl::optional<AbsoluteCaptureTime> OnReceivePacket(
+      uint32_t source,
+      uint32_t rtp_timestamp,
+      uint32_t rtp_clock_frequency,
+      const absl::optional<AbsoluteCaptureTime>& received_extension);
+
+ private:
+  friend class AbsoluteCaptureTimeSender;
+
+  static uint64_t InterpolateAbsoluteCaptureTimestamp(
+      uint32_t rtp_timestamp,
+      uint32_t rtp_clock_frequency,
+      uint32_t last_rtp_timestamp,
+      uint64_t last_absolute_capture_timestamp);
+
+  bool ShouldInterpolateExtension(Timestamp receive_time,
+                                  uint32_t source,
+                                  uint32_t rtp_timestamp,
+                                  uint32_t rtp_clock_frequency) const
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
+
+  absl::optional<int64_t> AdjustEstimatedCaptureClockOffset(
+      absl::optional<int64_t> received_value) const
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
+
+  Clock* const clock_;
+
+  rtc::CriticalSection crit_;
+
+  absl::optional<int64_t> remote_to_local_clock_offset_ RTC_GUARDED_BY(crit_);
+
+  Timestamp last_receive_time_ RTC_GUARDED_BY(crit_);
+
+  uint32_t last_source_ RTC_GUARDED_BY(crit_);
+  uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(crit_);
+  uint32_t last_rtp_clock_frequency_ RTC_GUARDED_BY(crit_);
+  uint64_t last_absolute_capture_timestamp_ RTC_GUARDED_BY(crit_);
+  absl::optional<int64_t> last_estimated_capture_clock_offset_
+      RTC_GUARDED_BY(crit_);
+};  // AbsoluteCaptureTimeReceiver
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_RECEIVER_H_
diff --git a/modules/rtp_rtcp/source/absolute_capture_time_receiver_unittest.cc b/modules/rtp_rtcp/source/absolute_capture_time_receiver_unittest.cc
new file mode 100644
index 0000000..ecf2567
--- /dev/null
+++ b/modules/rtp_rtcp/source/absolute_capture_time_receiver_unittest.cc
@@ -0,0 +1,416 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/rtp_rtcp/source/absolute_capture_time_receiver.h"
+
+#include "system_wrappers/include/ntp_time.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+TEST(AbsoluteCaptureTimeReceiverTest, GetSourceWithoutCsrcs) {
+  constexpr uint32_t kSsrc = 12;
+
+  EXPECT_EQ(AbsoluteCaptureTimeReceiver::GetSource(kSsrc, nullptr), kSsrc);
+}
+
+TEST(AbsoluteCaptureTimeReceiverTest, GetSourceWithCsrcs) {
+  constexpr uint32_t kSsrc = 12;
+  constexpr uint32_t kCsrcs[] = {34, 56, 78, 90};
+
+  EXPECT_EQ(AbsoluteCaptureTimeReceiver::GetSource(kSsrc, kCsrcs), kCsrcs[0]);
+}
+
+TEST(AbsoluteCaptureTimeReceiverTest, ReceiveExtensionReturnsExtension) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9020), absl::nullopt};
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeReceiver receiver(&clock);
+
+  receiver.SetRemoteToLocalClockOffset(0);
+
+  EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
+                                     kRtpClockFrequency, kExtension0),
+            kExtension0);
+
+  EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp1,
+                                     kRtpClockFrequency, kExtension1),
+            kExtension1);
+}
+
+TEST(AbsoluteCaptureTimeReceiverTest, ReceiveNoExtensionReturnsNoExtension) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 = absl::nullopt;
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeReceiver receiver(&clock);
+
+  receiver.SetRemoteToLocalClockOffset(0);
+
+  EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
+                                     kRtpClockFrequency, kExtension0),
+            absl::nullopt);
+
+  EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp1,
+                                     kRtpClockFrequency, kExtension1),
+            absl::nullopt);
+}
+
+TEST(AbsoluteCaptureTimeReceiverTest, InterpolateLaterPacketArrivingLater) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
+  constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 = absl::nullopt;
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeReceiver receiver(&clock);
+
+  receiver.SetRemoteToLocalClockOffset(0);
+
+  EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
+                                     kRtpClockFrequency, kExtension0),
+            kExtension0);
+
+  absl::optional<AbsoluteCaptureTime> extension = receiver.OnReceivePacket(
+      kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1);
+  EXPECT_TRUE(extension.has_value());
+  EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
+            UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 20);
+  EXPECT_EQ(extension->estimated_capture_clock_offset,
+            kExtension0->estimated_capture_clock_offset);
+
+  extension = receiver.OnReceivePacket(kSource, kRtpTimestamp2,
+                                       kRtpClockFrequency, kExtension2);
+  EXPECT_TRUE(extension.has_value());
+  EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
+            UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 40);
+  EXPECT_EQ(extension->estimated_capture_clock_offset,
+            kExtension0->estimated_capture_clock_offset);
+}
+
+TEST(AbsoluteCaptureTimeReceiverTest, InterpolateEarlierPacketArrivingLater) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 - 1280;
+  constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 - 2560;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 = absl::nullopt;
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeReceiver receiver(&clock);
+
+  receiver.SetRemoteToLocalClockOffset(0);
+
+  EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
+                                     kRtpClockFrequency, kExtension0),
+            kExtension0);
+
+  absl::optional<AbsoluteCaptureTime> extension = receiver.OnReceivePacket(
+      kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1);
+  EXPECT_TRUE(extension.has_value());
+  EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
+            UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) - 20);
+  EXPECT_EQ(extension->estimated_capture_clock_offset,
+            kExtension0->estimated_capture_clock_offset);
+
+  extension = receiver.OnReceivePacket(kSource, kRtpTimestamp2,
+                                       kRtpClockFrequency, kExtension2);
+  EXPECT_TRUE(extension.has_value());
+  EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
+            UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) - 40);
+  EXPECT_EQ(extension->estimated_capture_clock_offset,
+            kExtension0->estimated_capture_clock_offset);
+}
+
+TEST(AbsoluteCaptureTimeReceiverTest,
+     InterpolateLaterPacketArrivingLaterWithRtpTimestampWrapAround) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = ~uint32_t{0} - 79;
+  constexpr uint32_t kRtpTimestamp1 = 1280 - 80;
+  constexpr uint32_t kRtpTimestamp2 = 2560 - 80;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 = absl::nullopt;
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeReceiver receiver(&clock);
+
+  receiver.SetRemoteToLocalClockOffset(0);
+
+  EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
+                                     kRtpClockFrequency, kExtension0),
+            kExtension0);
+
+  absl::optional<AbsoluteCaptureTime> extension = receiver.OnReceivePacket(
+      kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1);
+  EXPECT_TRUE(extension.has_value());
+  EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
+            UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 20);
+  EXPECT_EQ(extension->estimated_capture_clock_offset,
+            kExtension0->estimated_capture_clock_offset);
+
+  extension = receiver.OnReceivePacket(kSource, kRtpTimestamp2,
+                                       kRtpClockFrequency, kExtension2);
+  EXPECT_TRUE(extension.has_value());
+  EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
+            UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 40);
+  EXPECT_EQ(extension->estimated_capture_clock_offset,
+            kExtension0->estimated_capture_clock_offset);
+}
+
+TEST(AbsoluteCaptureTimeReceiverTest,
+     InterpolateEarlierPacketArrivingLaterWithRtpTimestampWrapAround) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = 799;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 - 1280;
+  constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 - 2560;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 = absl::nullopt;
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeReceiver receiver(&clock);
+
+  receiver.SetRemoteToLocalClockOffset(0);
+
+  EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
+                                     kRtpClockFrequency, kExtension0),
+            kExtension0);
+
+  absl::optional<AbsoluteCaptureTime> extension = receiver.OnReceivePacket(
+      kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1);
+  EXPECT_TRUE(extension.has_value());
+  EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
+            UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) - 20);
+  EXPECT_EQ(extension->estimated_capture_clock_offset,
+            kExtension0->estimated_capture_clock_offset);
+
+  extension = receiver.OnReceivePacket(kSource, kRtpTimestamp2,
+                                       kRtpClockFrequency, kExtension2);
+  EXPECT_TRUE(extension.has_value());
+  EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
+            UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) - 40);
+  EXPECT_EQ(extension->estimated_capture_clock_offset,
+            kExtension0->estimated_capture_clock_offset);
+}
+
+TEST(AbsoluteCaptureTimeReceiverTest,
+     SkipEstimatedCaptureClockOffsetIfRemoteToLocalClockOffsetIsUnknown) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
+  constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 = absl::nullopt;
+  static const absl::optional<int64_t> kRemoteToLocalClockOffset2 =
+      Int64MsToQ32x32(-7000007);
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeReceiver receiver(&clock);
+
+  receiver.SetRemoteToLocalClockOffset(0);
+
+  EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
+                                     kRtpClockFrequency, kExtension0),
+            kExtension0);
+
+  receiver.SetRemoteToLocalClockOffset(absl::nullopt);
+
+  absl::optional<AbsoluteCaptureTime> extension = receiver.OnReceivePacket(
+      kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1);
+  EXPECT_TRUE(extension.has_value());
+  EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
+            UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 20);
+  EXPECT_EQ(extension->estimated_capture_clock_offset, absl::nullopt);
+
+  receiver.SetRemoteToLocalClockOffset(kRemoteToLocalClockOffset2);
+
+  extension = receiver.OnReceivePacket(kSource, kRtpTimestamp2,
+                                       kRtpClockFrequency, kExtension2);
+  EXPECT_TRUE(extension.has_value());
+  EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
+            UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 40);
+  EXPECT_EQ(extension->estimated_capture_clock_offset,
+            *kExtension0->estimated_capture_clock_offset +
+                *kRemoteToLocalClockOffset2);
+}
+
+TEST(AbsoluteCaptureTimeReceiverTest, SkipInterpolateIfTooLate) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
+  constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp1 + 1280;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 = absl::nullopt;
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeReceiver receiver(&clock);
+
+  receiver.SetRemoteToLocalClockOffset(0);
+
+  EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
+                                     kRtpClockFrequency, kExtension0),
+            kExtension0);
+
+  clock.AdvanceTime(AbsoluteCaptureTimeReceiver::kInterpolationMaxInterval);
+
+  EXPECT_TRUE(receiver
+                  .OnReceivePacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
+                                   kExtension1)
+                  .has_value());
+
+  clock.AdvanceTimeMilliseconds(1);
+
+  EXPECT_FALSE(receiver
+                   .OnReceivePacket(kSource, kRtpTimestamp2, kRtpClockFrequency,
+                                    kExtension2)
+                   .has_value());
+}
+
+TEST(AbsoluteCaptureTimeReceiverTest, SkipInterpolateIfSourceChanged) {
+  constexpr uint32_t kSource0 = 1337;
+  constexpr uint32_t kSource1 = 1338;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeReceiver receiver(&clock);
+
+  receiver.SetRemoteToLocalClockOffset(0);
+
+  EXPECT_EQ(receiver.OnReceivePacket(kSource0, kRtpTimestamp0,
+                                     kRtpClockFrequency, kExtension0),
+            kExtension0);
+
+  EXPECT_FALSE(receiver
+                   .OnReceivePacket(kSource1, kRtpTimestamp1,
+                                    kRtpClockFrequency, kExtension1)
+                   .has_value());
+}
+
+TEST(AbsoluteCaptureTimeReceiverTest,
+     SkipInterpolateIfRtpClockFrequencyChanged) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency0 = 64000;
+  constexpr uint32_t kRtpClockFrequency1 = 32000;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 640;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeReceiver receiver(&clock);
+
+  receiver.SetRemoteToLocalClockOffset(0);
+
+  EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
+                                     kRtpClockFrequency0, kExtension0),
+            kExtension0);
+
+  EXPECT_FALSE(receiver
+                   .OnReceivePacket(kSource, kRtpTimestamp1,
+                                    kRtpClockFrequency1, kExtension1)
+                   .has_value());
+}
+
+TEST(AbsoluteCaptureTimeReceiverTest,
+     SkipInterpolateIfRtpClockFrequencyIsInvalid) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency = 0;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 640;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeReceiver receiver(&clock);
+
+  receiver.SetRemoteToLocalClockOffset(0);
+
+  EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
+                                     kRtpClockFrequency, kExtension0),
+            kExtension0);
+
+  EXPECT_FALSE(receiver
+                   .OnReceivePacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
+                                    kExtension1)
+                   .has_value());
+}
+
+TEST(AbsoluteCaptureTimeReceiverTest, SkipInterpolateIsSticky) {
+  constexpr uint32_t kSource0 = 1337;
+  constexpr uint32_t kSource1 = 1338;
+  constexpr uint32_t kSource2 = 1337;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
+  constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp1 + 1280;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 = absl::nullopt;
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeReceiver receiver(&clock);
+
+  receiver.SetRemoteToLocalClockOffset(0);
+
+  EXPECT_EQ(receiver.OnReceivePacket(kSource0, kRtpTimestamp0,
+                                     kRtpClockFrequency, kExtension0),
+            kExtension0);
+
+  EXPECT_FALSE(receiver
+                   .OnReceivePacket(kSource1, kRtpTimestamp1,
+                                    kRtpClockFrequency, kExtension1)
+                   .has_value());
+
+  EXPECT_FALSE(receiver
+                   .OnReceivePacket(kSource2, kRtpTimestamp2,
+                                    kRtpClockFrequency, kExtension2)
+                   .has_value());
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/absolute_capture_time_sender.cc b/modules/rtp_rtcp/source/absolute_capture_time_sender.cc
new file mode 100644
index 0000000..f614c0c
--- /dev/null
+++ b/modules/rtp_rtcp/source/absolute_capture_time_sender.cc
@@ -0,0 +1,124 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/rtp_rtcp/source/absolute_capture_time_sender.h"
+
+#include <limits>
+
+#include "modules/rtp_rtcp/source/absolute_capture_time_receiver.h"
+#include "system_wrappers/include/ntp_time.h"
+
+namespace webrtc {
+namespace {
+
+constexpr Timestamp kInvalidLastSendTime = Timestamp::MinusInfinity();
+
+}  // namespace
+
+constexpr TimeDelta AbsoluteCaptureTimeSender::kInterpolationMaxInterval;
+constexpr TimeDelta AbsoluteCaptureTimeSender::kInterpolationMaxError;
+
+static_assert(
+    AbsoluteCaptureTimeReceiver::kInterpolationMaxInterval >=
+        AbsoluteCaptureTimeSender::kInterpolationMaxInterval,
+    "Receivers should be as willing to interpolate timestamps as senders.");
+
+AbsoluteCaptureTimeSender::AbsoluteCaptureTimeSender(Clock* clock)
+    : clock_(clock), last_send_time_(kInvalidLastSendTime) {}
+
+uint32_t AbsoluteCaptureTimeSender::GetSource(
+    uint32_t ssrc,
+    rtc::ArrayView<const uint32_t> csrcs) {
+  return AbsoluteCaptureTimeReceiver::GetSource(ssrc, csrcs);
+}
+
+absl::optional<AbsoluteCaptureTime> AbsoluteCaptureTimeSender::OnSendPacket(
+    uint32_t source,
+    uint32_t rtp_timestamp,
+    uint32_t rtp_clock_frequency,
+    uint64_t absolute_capture_timestamp,
+    absl::optional<int64_t> estimated_capture_clock_offset) {
+  const Timestamp send_time = clock_->CurrentTime();
+
+  rtc::CritScope cs(&crit_);
+
+  if (!ShouldSendExtension(send_time, source, rtp_timestamp,
+                           rtp_clock_frequency, absolute_capture_timestamp,
+                           estimated_capture_clock_offset)) {
+    return absl::nullopt;
+  }
+
+  last_source_ = source;
+  last_rtp_timestamp_ = rtp_timestamp;
+  last_rtp_clock_frequency_ = rtp_clock_frequency;
+  last_absolute_capture_timestamp_ = absolute_capture_timestamp;
+  last_estimated_capture_clock_offset_ = estimated_capture_clock_offset;
+
+  last_send_time_ = send_time;
+
+  AbsoluteCaptureTime extension;
+  extension.absolute_capture_timestamp = absolute_capture_timestamp;
+  extension.estimated_capture_clock_offset = estimated_capture_clock_offset;
+  return extension;
+}
+
+bool AbsoluteCaptureTimeSender::ShouldSendExtension(
+    Timestamp send_time,
+    uint32_t source,
+    uint32_t rtp_timestamp,
+    uint32_t rtp_clock_frequency,
+    uint64_t absolute_capture_timestamp,
+    absl::optional<int64_t> estimated_capture_clock_offset) const {
+  // Should if we've never sent anything before.
+  if (last_send_time_ == kInvalidLastSendTime) {
+    return true;
+  }
+
+  // Should if the last sent extension is too old.
+  if ((send_time - last_send_time_) > kInterpolationMaxInterval) {
+    return true;
+  }
+
+  // Should if the source has changed.
+  if (last_source_ != source) {
+    return true;
+  }
+
+  // Should if the RTP clock frequency has changed.
+  if (last_rtp_clock_frequency_ != rtp_clock_frequency) {
+    return true;
+  }
+
+  // Should if the RTP clock frequency is invalid.
+  if (rtp_clock_frequency <= 0) {
+    return true;
+  }
+
+  // Should if the estimated capture clock offset has changed.
+  if (last_estimated_capture_clock_offset_ != estimated_capture_clock_offset) {
+    return true;
+  }
+
+  // Should if interpolation would introduce too much error.
+  const uint64_t interpolated_absolute_capture_timestamp =
+      AbsoluteCaptureTimeReceiver::InterpolateAbsoluteCaptureTimestamp(
+          rtp_timestamp, rtp_clock_frequency, last_rtp_timestamp_,
+          last_absolute_capture_timestamp_);
+  const int64_t interpolation_error_ms = UQ32x32ToInt64Ms(std::min(
+      interpolated_absolute_capture_timestamp - absolute_capture_timestamp,
+      absolute_capture_timestamp - interpolated_absolute_capture_timestamp));
+  if (interpolation_error_ms > kInterpolationMaxError.ms()) {
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/absolute_capture_time_sender.h b/modules/rtp_rtcp/source/absolute_capture_time_sender.h
new file mode 100644
index 0000000..86158a8
--- /dev/null
+++ b/modules/rtp_rtcp/source/absolute_capture_time_sender.h
@@ -0,0 +1,88 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_SENDER_H_
+#define MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_SENDER_H_
+
+#include "api/array_view.h"
+#include "api/rtp_headers.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+#include "rtc_base/critical_section.h"
+#include "rtc_base/thread_annotations.h"
+#include "system_wrappers/include/clock.h"
+
+namespace webrtc {
+
+//
+// Helper class for sending the |AbsoluteCaptureTime| header extension.
+//
+// Supports the "timestamp interpolation" optimization:
+//   A sender SHOULD save bandwidth by not sending abs-capture-time with every
+//   RTP packet. It SHOULD still send them at regular intervals (e.g. every
+//   second) to help mitigate the impact of clock drift and packet loss. Mixers
+//   SHOULD always send abs-capture-time with the first RTP packet after
+//   changing capture system.
+//
+//   Timestamp interpolation works fine as long as there’s reasonably low
+//   NTP/RTP clock drift. This is not always true. Senders that detect “jumps”
+//   between its NTP and RTP clock mappings SHOULD send abs-capture-time with
+//   the first RTP packet after such a thing happening.
+//
+// See: https://webrtc.org/experiments/rtp-hdrext/abs-capture-time/
+//
+class AbsoluteCaptureTimeSender {
+ public:
+  static constexpr TimeDelta kInterpolationMaxInterval =
+      TimeDelta::Millis<1000>();
+  static constexpr TimeDelta kInterpolationMaxError = TimeDelta::Millis<1>();
+
+  explicit AbsoluteCaptureTimeSender(Clock* clock);
+
+  // Returns the source (i.e. SSRC or CSRC) of the capture system.
+  static uint32_t GetSource(uint32_t ssrc,
+                            rtc::ArrayView<const uint32_t> csrcs);
+
+  // Returns a header extension to be sent, or |absl::nullopt| if the header
+  // extension shouldn't be sent.
+  absl::optional<AbsoluteCaptureTime> OnSendPacket(
+      uint32_t source,
+      uint32_t rtp_timestamp,
+      uint32_t rtp_clock_frequency,
+      uint64_t absolute_capture_timestamp,
+      absl::optional<int64_t> estimated_capture_clock_offset);
+
+ private:
+  bool ShouldSendExtension(
+      Timestamp send_time,
+      uint32_t source,
+      uint32_t rtp_timestamp,
+      uint32_t rtp_clock_frequency,
+      uint64_t absolute_capture_timestamp,
+      absl::optional<int64_t> estimated_capture_clock_offset) const
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
+
+  Clock* const clock_;
+
+  rtc::CriticalSection crit_;
+
+  Timestamp last_send_time_ RTC_GUARDED_BY(crit_);
+
+  uint32_t last_source_ RTC_GUARDED_BY(crit_);
+  uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(crit_);
+  uint32_t last_rtp_clock_frequency_ RTC_GUARDED_BY(crit_);
+  uint64_t last_absolute_capture_timestamp_ RTC_GUARDED_BY(crit_);
+  absl::optional<int64_t> last_estimated_capture_clock_offset_
+      RTC_GUARDED_BY(crit_);
+};  // AbsoluteCaptureTimeSender
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_SENDER_H_
diff --git a/modules/rtp_rtcp/source/absolute_capture_time_sender_unittest.cc b/modules/rtp_rtcp/source/absolute_capture_time_sender_unittest.cc
new file mode 100644
index 0000000..db3fc75
--- /dev/null
+++ b/modules/rtp_rtcp/source/absolute_capture_time_sender_unittest.cc
@@ -0,0 +1,374 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/rtp_rtcp/source/absolute_capture_time_sender.h"
+
+#include "system_wrappers/include/ntp_time.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+TEST(AbsoluteCaptureTimeSenderTest, GetSourceWithoutCsrcs) {
+  constexpr uint32_t kSsrc = 12;
+
+  EXPECT_EQ(AbsoluteCaptureTimeSender::GetSource(kSsrc, nullptr), kSsrc);
+}
+
+TEST(AbsoluteCaptureTimeSenderTest, GetSourceWithCsrcs) {
+  constexpr uint32_t kSsrc = 12;
+  constexpr uint32_t kCsrcs[] = {34, 56, 78, 90};
+
+  EXPECT_EQ(AbsoluteCaptureTimeSender::GetSource(kSsrc, kCsrcs), kCsrcs[0]);
+}
+
+TEST(AbsoluteCaptureTimeSenderTest, InterpolateLaterPacketSentLater) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
+  constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)};
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeSender sender(&clock);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency,
+                                kExtension0->absolute_capture_timestamp,
+                                kExtension0->estimated_capture_clock_offset),
+            kExtension0);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
+                                kExtension1->absolute_capture_timestamp,
+                                kExtension1->estimated_capture_clock_offset),
+            absl::nullopt);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency,
+                                kExtension2->absolute_capture_timestamp,
+                                kExtension2->estimated_capture_clock_offset),
+            absl::nullopt);
+}
+
+TEST(AbsoluteCaptureTimeSenderTest, InterpolateEarlierPacketSentLater) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 - 1280;
+  constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 - 2560;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 - 20), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 - 40), Int64MsToQ32x32(-350)};
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeSender sender(&clock);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency,
+                                kExtension0->absolute_capture_timestamp,
+                                kExtension0->estimated_capture_clock_offset),
+            kExtension0);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
+                                kExtension1->absolute_capture_timestamp,
+                                kExtension1->estimated_capture_clock_offset),
+            absl::nullopt);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency,
+                                kExtension2->absolute_capture_timestamp,
+                                kExtension2->estimated_capture_clock_offset),
+            absl::nullopt);
+}
+
+TEST(AbsoluteCaptureTimeSenderTest,
+     InterpolateLaterPacketSentLaterWithRtpTimestampWrapAround) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = ~uint32_t{0} - 79;
+  constexpr uint32_t kRtpTimestamp1 = 1280 - 80;
+  constexpr uint32_t kRtpTimestamp2 = 2560 - 80;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)};
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeSender sender(&clock);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency,
+                                kExtension0->absolute_capture_timestamp,
+                                kExtension0->estimated_capture_clock_offset),
+            kExtension0);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
+                                kExtension1->absolute_capture_timestamp,
+                                kExtension1->estimated_capture_clock_offset),
+            absl::nullopt);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency,
+                                kExtension2->absolute_capture_timestamp,
+                                kExtension2->estimated_capture_clock_offset),
+            absl::nullopt);
+}
+
+TEST(AbsoluteCaptureTimeSenderTest,
+     InterpolateEarlierPacketSentLaterWithRtpTimestampWrapAround) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = 799;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 - 1280;
+  constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 - 2560;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 - 20), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 - 40), Int64MsToQ32x32(-350)};
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeSender sender(&clock);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency,
+                                kExtension0->absolute_capture_timestamp,
+                                kExtension0->estimated_capture_clock_offset),
+            kExtension0);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
+                                kExtension1->absolute_capture_timestamp,
+                                kExtension1->estimated_capture_clock_offset),
+            absl::nullopt);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency,
+                                kExtension2->absolute_capture_timestamp,
+                                kExtension2->estimated_capture_clock_offset),
+            absl::nullopt);
+}
+
+TEST(AbsoluteCaptureTimeSenderTest, SkipInterpolateIfTooLate) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
+  constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)};
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeSender sender(&clock);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency,
+                                kExtension0->absolute_capture_timestamp,
+                                kExtension0->estimated_capture_clock_offset),
+            kExtension0);
+
+  clock.AdvanceTime(AbsoluteCaptureTimeSender::kInterpolationMaxInterval);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
+                                kExtension1->absolute_capture_timestamp,
+                                kExtension1->estimated_capture_clock_offset),
+            absl::nullopt);
+
+  clock.AdvanceTimeMicroseconds(1);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency,
+                                kExtension2->absolute_capture_timestamp,
+                                kExtension2->estimated_capture_clock_offset),
+            kExtension2);
+}
+
+TEST(AbsoluteCaptureTimeSenderTest, SkipInterpolateIfSourceChanged) {
+  constexpr uint32_t kSource0 = 1337;
+  constexpr uint32_t kSource1 = 1338;
+  constexpr uint32_t kSource2 = 1338;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
+  constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)};
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeSender sender(&clock);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource0, kRtpTimestamp0, kRtpClockFrequency,
+                                kExtension0->absolute_capture_timestamp,
+                                kExtension0->estimated_capture_clock_offset),
+            kExtension0);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource1, kRtpTimestamp1, kRtpClockFrequency,
+                                kExtension1->absolute_capture_timestamp,
+                                kExtension1->estimated_capture_clock_offset),
+            kExtension1);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource2, kRtpTimestamp2, kRtpClockFrequency,
+                                kExtension2->absolute_capture_timestamp,
+                                kExtension2->estimated_capture_clock_offset),
+            absl::nullopt);
+}
+
+TEST(AbsoluteCaptureTimeSenderTest, SkipInterpolateIfRtpClockFrequencyChanged) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency0 = 64000;
+  constexpr uint32_t kRtpClockFrequency1 = 32000;
+  constexpr uint32_t kRtpClockFrequency2 = 32000;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 640;
+  constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 1280;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)};
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeSender sender(&clock);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency0,
+                                kExtension0->absolute_capture_timestamp,
+                                kExtension0->estimated_capture_clock_offset),
+            kExtension0);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency1,
+                                kExtension1->absolute_capture_timestamp,
+                                kExtension1->estimated_capture_clock_offset),
+            kExtension1);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency2,
+                                kExtension2->absolute_capture_timestamp,
+                                kExtension2->estimated_capture_clock_offset),
+            absl::nullopt);
+}
+
+TEST(AbsoluteCaptureTimeSenderTest,
+     SkipInterpolateIfRtpClockFrequencyIsInvalid) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency0 = 0;
+  constexpr uint32_t kRtpClockFrequency1 = 0;
+  constexpr uint32_t kRtpClockFrequency2 = 0;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0;
+  constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)};
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeSender sender(&clock);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency0,
+                                kExtension0->absolute_capture_timestamp,
+                                kExtension0->estimated_capture_clock_offset),
+            kExtension0);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency1,
+                                kExtension1->absolute_capture_timestamp,
+                                kExtension1->estimated_capture_clock_offset),
+            kExtension1);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency2,
+                                kExtension2->absolute_capture_timestamp,
+                                kExtension2->estimated_capture_clock_offset),
+            kExtension2);
+}
+
+TEST(AbsoluteCaptureTimeSenderTest,
+     SkipInterpolateIfEstimatedCaptureClockOffsetChanged) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
+  constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(370)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), absl::nullopt};
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeSender sender(&clock);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency,
+                                kExtension0->absolute_capture_timestamp,
+                                kExtension0->estimated_capture_clock_offset),
+            kExtension0);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
+                                kExtension1->absolute_capture_timestamp,
+                                kExtension1->estimated_capture_clock_offset),
+            kExtension1);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency,
+                                kExtension2->absolute_capture_timestamp,
+                                kExtension2->estimated_capture_clock_offset),
+            kExtension2);
+}
+
+TEST(AbsoluteCaptureTimeSenderTest,
+     SkipInterpolateIfTooMuchInterpolationError) {
+  constexpr uint32_t kSource = 1337;
+  constexpr uint32_t kRtpClockFrequency = 64000;
+  constexpr uint32_t kRtpTimestamp0 = 1020300000;
+  constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
+  constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560;
+  static const absl::optional<AbsoluteCaptureTime> kExtension0 =
+      AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension1 =
+      AbsoluteCaptureTime{
+          Int64MsToUQ32x32(
+              9000 + 20 +
+              AbsoluteCaptureTimeSender::kInterpolationMaxError.ms()),
+          Int64MsToQ32x32(-350)};
+  static const absl::optional<AbsoluteCaptureTime> kExtension2 =
+      AbsoluteCaptureTime{
+          Int64MsToUQ32x32(
+              9000 + 40 +
+              AbsoluteCaptureTimeSender::kInterpolationMaxError.ms() + 1),
+          Int64MsToQ32x32(-350)};
+
+  SimulatedClock clock(0);
+  AbsoluteCaptureTimeSender sender(&clock);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency,
+                                kExtension0->absolute_capture_timestamp,
+                                kExtension0->estimated_capture_clock_offset),
+            kExtension0);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
+                                kExtension1->absolute_capture_timestamp,
+                                kExtension1->estimated_capture_clock_offset),
+            absl::nullopt);
+
+  EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency,
+                                kExtension2->absolute_capture_timestamp,
+                                kExtension2->estimated_capture_clock_offset),
+            kExtension2);
+}
+
+}  // namespace webrtc