Add support for the Absolute Capture Timestamp extension to TransformableAudioFrameInterface

Bug: chromium:391114797
Change-Id: Iad09ed3b509ce7874c44cd17c1e87b6945b14b07
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/377121
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Jakob Ivarsson‎ <jakobi@webrtc.org>
Commit-Queue: Guido Urdaneta <guidou@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#43893}
diff --git a/api/BUILD.gn b/api/BUILD.gn
index 010695a..e2d2a3b 100644
--- a/api/BUILD.gn
+++ b/api/BUILD.gn
@@ -410,6 +410,7 @@
     ":scoped_refptr",
     "../rtc_base:refcount",
     "../rtc_base/system:rtc_export",
+    "units:time_delta",
     "units:timestamp",
     "video:encoded_frame",
     "video:video_frame_metadata",
diff --git a/api/frame_transformer_interface.h b/api/frame_transformer_interface.h
index 7133efa..63df71c 100644
--- a/api/frame_transformer_interface.h
+++ b/api/frame_transformer_interface.h
@@ -19,6 +19,7 @@
 #include "api/array_view.h"
 #include "api/ref_count.h"
 #include "api/scoped_refptr.h"
+#include "api/units/time_delta.h"
 #include "api/units/timestamp.h"
 #include "api/video/video_frame_metadata.h"
 #include "rtc_base/system/rtc_export.h"
@@ -99,6 +100,7 @@
 
   virtual const std::optional<uint16_t> SequenceNumber() const = 0;
 
+  // TODO(crbug.com/391114797): Delete this function.
   virtual std::optional<uint64_t> AbsoluteCaptureTimestamp() const = 0;
 
   enum class FrameType { kEmptyFrame, kAudioFrameSpeech, kAudioFrameCN };
@@ -115,6 +117,21 @@
   // Timestamp at which the packet has been first seen on the network interface.
   // Only defined for received audio packet.
   virtual std::optional<Timestamp> ReceiveTime() const = 0;
+
+  // Timestamp at which the frame was captured in the capturer system.
+  // The timestamp is expressed in the capturer system's clock relative to the
+  // NTP epoch (January 1st 1970 00:00 UTC)
+  // Accessible only if the absolute capture timestamp header extension is
+  // enabled.
+  virtual std::optional<Timestamp> CaptureTime() const = 0;
+
+  // Offset between the sender system's clock and the capturer system's clock.
+  // Can be used to express the capture time in the local system's clock as
+  // long as the local system can determine the offset between its local clock
+  // and the sender system's clock.
+  // Accessible only if the absolute capture timestamp header extension is
+  // enabled.
+  virtual std::optional<TimeDelta> SenderCaptureTimeOffset() const = 0;
 };
 
 // Objects implement this interface to be notified with the transformed frame.
diff --git a/api/test/mock_transformable_audio_frame.h b/api/test/mock_transformable_audio_frame.h
index d2100e6..762a9dc 100644
--- a/api/test/mock_transformable_audio_frame.h
+++ b/api/test/mock_transformable_audio_frame.h
@@ -56,6 +56,11 @@
   MOCK_METHOD(std::optional<uint8_t>, AudioLevel, (), (const, override));
 
   MOCK_METHOD(std::optional<Timestamp>, ReceiveTime, (), (const, override));
+  MOCK_METHOD(std::optional<Timestamp>, CaptureTime, (), (const, override));
+  MOCK_METHOD(std::optional<TimeDelta>,
+              SenderCaptureTimeOffset,
+              (),
+              (const, override));
 };
 
 }  // namespace webrtc
diff --git a/audio/channel_receive_frame_transformer_delegate.cc b/audio/channel_receive_frame_transformer_delegate.cc
index d82925a..27d4161 100644
--- a/audio/channel_receive_frame_transformer_delegate.cc
+++ b/audio/channel_receive_frame_transformer_delegate.cc
@@ -22,9 +22,11 @@
 #include "api/scoped_refptr.h"
 #include "api/sequence_checker.h"
 #include "api/task_queue/task_queue_base.h"
+#include "api/units/time_delta.h"
 #include "api/units/timestamp.h"
 #include "rtc_base/buffer.h"
 #include "rtc_base/string_encode.h"
+#include "system_wrappers/include/ntp_time.h"
 
 namespace webrtc {
 
@@ -96,6 +98,25 @@
                : std::optional<Timestamp>(receive_time_);
   }
 
+  std::optional<Timestamp> CaptureTime() const override {
+    if (header_.extension.absolute_capture_time) {
+      return Timestamp::Micros(UQ32x32ToInt64Us(
+          header_.extension.absolute_capture_time->absolute_capture_timestamp));
+    }
+    return std::nullopt;
+  }
+
+  std::optional<TimeDelta> SenderCaptureTimeOffset() const override {
+    if (header_.extension.absolute_capture_time &&
+        header_.extension.absolute_capture_time
+            ->estimated_capture_clock_offset) {
+      return TimeDelta::Micros(
+          UQ32x32ToInt64Us(*header_.extension.absolute_capture_time
+                                ->estimated_capture_clock_offset));
+    }
+    return std::nullopt;
+  }
+
  private:
   rtc::Buffer payload_;
   RTPHeader header_;
diff --git a/audio/channel_receive_frame_transformer_delegate_unittest.cc b/audio/channel_receive_frame_transformer_delegate_unittest.cc
index 32e56c4..dad1f63 100644
--- a/audio/channel_receive_frame_transformer_delegate_unittest.cc
+++ b/audio/channel_receive_frame_transformer_delegate_unittest.cc
@@ -24,6 +24,7 @@
 #include "api/test/mock_transformable_audio_frame.h"
 #include "api/units/timestamp.h"
 #include "rtc_base/thread.h"
+#include "system_wrappers/include/ntp_time.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
 
@@ -193,7 +194,7 @@
 }
 
 TEST(ChannelReceiveFrameTransformerDelegateTest,
-     AudioLevelAbsentWithoutExtension) {
+     AudioLevelAndCaptureTimeAbsentWithoutExtension) {
   rtc::AutoThread main_thread;
   rtc::scoped_refptr<MockFrameTransformer> mock_frame_transformer =
       rtc::make_ref_counted<NiceMock<MockFrameTransformer>>();
@@ -223,6 +224,8 @@
   auto* audio_frame =
       static_cast<TransformableAudioFrameInterface*>(frame.get());
   EXPECT_FALSE(audio_frame->AudioLevel());
+  EXPECT_FALSE(audio_frame->CaptureTime());
+  EXPECT_FALSE(audio_frame->SenderCaptureTimeOffset());
   EXPECT_EQ(audio_frame->Type(),
             TransformableAudioFrameInterface::FrameType::kAudioFrameCN);
 }
@@ -265,5 +268,48 @@
             TransformableAudioFrameInterface::FrameType::kAudioFrameSpeech);
 }
 
+TEST(ChannelReceiveFrameTransformerDelegateTest,
+     CaptureTimePresentWithExtension) {
+  rtc::AutoThread main_thread;
+  rtc::scoped_refptr<MockFrameTransformer> mock_frame_transformer =
+      rtc::make_ref_counted<NiceMock<MockFrameTransformer>>();
+  rtc::scoped_refptr<ChannelReceiveFrameTransformerDelegate> delegate =
+      rtc::make_ref_counted<ChannelReceiveFrameTransformerDelegate>(
+          /*receive_frame_callback=*/nullptr, mock_frame_transformer,
+          rtc::Thread::Current());
+  rtc::scoped_refptr<TransformedFrameCallback> callback;
+  EXPECT_CALL(*mock_frame_transformer, RegisterTransformedFrameCallback)
+      .WillOnce(SaveArg<0>(&callback));
+  delegate->Init();
+  ASSERT_TRUE(callback);
+
+  const uint8_t data[] = {1, 2, 3, 4};
+  rtc::ArrayView<const uint8_t> packet(data, sizeof(data));
+  Timestamp capture_time = Timestamp::Millis(1234);
+  TimeDelta sender_capture_time_offset = TimeDelta::Millis(56);
+  AbsoluteCaptureTime absolute_capture_time = {
+      .absolute_capture_timestamp = Int64MsToUQ32x32(capture_time.ms()),
+      .estimated_capture_clock_offset =
+          Int64MsToUQ32x32(sender_capture_time_offset.ms())};
+  RTPHeader header;
+  header.extension.absolute_capture_time = absolute_capture_time;
+
+  std::unique_ptr<TransformableFrameInterface> frame;
+  ON_CALL(*mock_frame_transformer, Transform)
+      .WillByDefault(
+          [&](std::unique_ptr<TransformableFrameInterface> transform_frame) {
+            frame = std::move(transform_frame);
+          });
+  delegate->Transform(packet, header, /*ssrc=*/1111, /*mimeType=*/"audio/opus",
+                      kFakeReceiveTimestamp);
+
+  EXPECT_TRUE(frame);
+  auto* audio_frame =
+      static_cast<TransformableAudioFrameInterface*>(frame.get());
+  EXPECT_EQ(*audio_frame->CaptureTime(), capture_time);
+  EXPECT_EQ(*audio_frame->SenderCaptureTimeOffset(),
+            sender_capture_time_offset);
+}
+
 }  // namespace
 }  // namespace webrtc
diff --git a/audio/channel_send_frame_transformer_delegate.cc b/audio/channel_send_frame_transformer_delegate.cc
index dacbfcd..53d8648 100644
--- a/audio/channel_send_frame_transformer_delegate.cc
+++ b/audio/channel_send_frame_transformer_delegate.cc
@@ -13,6 +13,9 @@
 #include <utility>
 #include <vector>
 
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+
 namespace webrtc {
 namespace {
 
@@ -110,6 +113,10 @@
   }
 
   std::optional<Timestamp> ReceiveTime() const override { return std::nullopt; }
+  std::optional<Timestamp> CaptureTime() const override { return std::nullopt; }
+  std::optional<TimeDelta> SenderCaptureTimeOffset() const override {
+    return std::nullopt;
+  }
 
  private:
   AudioFrameType frame_type_;