Introduce GetRtpTimestampInfo() in TransformableFrameInterface.

Low-Coverage-Reason: TRIVIAL_CHANGE in api/frame_transformer_interface.h
Bug: chromium:524901718
Change-Id: Ic56cb7cf25ef5ed3e014b5cb77d4a2675471a72c
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/485781
Reviewed-by: Guido Urdaneta <guidou@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Leonardo Evi <evil@chromium.org>
Cr-Commit-Position: refs/heads/main@{#48108}
diff --git a/api/frame_transformer_interface.h b/api/frame_transformer_interface.h
index 9f4ed92..5dab9c1 100644
--- a/api/frame_transformer_interface.h
+++ b/api/frame_transformer_interface.h
@@ -16,6 +16,7 @@
 #include <optional>
 #include <span>
 #include <string>
+#include <variant>
 
 #include "api/ref_count.h"
 #include "api/scoped_refptr.h"
@@ -27,6 +28,17 @@
 
 namespace webrtc {
 
+struct RtpTimestampWithOffset {
+  uint32_t value;
+  operator uint32_t() const { return value; }  // NOLINT: explicit
+};
+struct RtpTimestampWithoutOffset {
+  uint32_t value;
+  operator uint32_t() const { return value; }  // NOLINT: explicit
+};
+using RtpTimestampInfo =
+    std::variant<RtpTimestampWithOffset, RtpTimestampWithoutOffset>;
+
 // Owns the frame payload data.
 class TransformableFrameInterface {
  public:
@@ -55,8 +67,14 @@
   virtual bool CanSetPayloadType() const { return false; }
   virtual void SetPayloadType(uint8_t payload_type) { RTC_DCHECK_NOTREACHED(); }
   virtual uint32_t GetSsrc() const = 0;
+  // The full RTP timestamp may not always be known. An example are frames not
+  // associated with a sender or receiver, where the random offset for RTP
+  // timestamp is not known. Use GetRtpTimestampInfo instead, which makes it
+  // possible to make a distinction between these two cases.
+  // TODO(https://bugs.webrtc.org/526671875): Deprecate and remove this method.
+  // [[deprecated("Use GetRtpTimestampInfo instead")]]
   virtual uint32_t GetTimestamp() const = 0;
-  virtual void SetRTPTimestamp(uint32_t timestamp) = 0;
+  virtual void SetRTPTimestamp(uint32_t rtp_timestamp_with_offset) = 0;
 
   // TODO(https://bugs.webrtc.org/373365537): Remove this once its usage is
   // removed from blink.
@@ -107,6 +125,11 @@
   // Accessible only if the absolute capture timestamp header extension is
   // enabled.
   virtual std::optional<TimeDelta> SenderCaptureTimeOffset() const = 0;
+
+  // Returns RtpTimestampWithOffset if the full RTP timestamp is known,
+  // or RtpTimestampWithoutOffset if the offset for the RTP timestamp is not
+  // known.
+  virtual RtpTimestampInfo GetRtpTimestampInfo() const = 0;
 };
 
 class TransformableVideoFrameInterface : public TransformableFrameInterface {
diff --git a/api/test/mock_transformable_audio_frame.h b/api/test/mock_transformable_audio_frame.h
index 6abb24a..49336c3 100644
--- a/api/test/mock_transformable_audio_frame.h
+++ b/api/test/mock_transformable_audio_frame.h
@@ -68,6 +68,7 @@
               SenderCaptureTimeOffset,
               (),
               (const, override));
+  MOCK_METHOD(RtpTimestampInfo, GetRtpTimestampInfo, (), (const, override));
 };
 
 }  // namespace webrtc
diff --git a/api/test/mock_transformable_frame.h b/api/test/mock_transformable_frame.h
index 804901d..b506fb9 100644
--- a/api/test/mock_transformable_frame.h
+++ b/api/test/mock_transformable_frame.h
@@ -29,6 +29,7 @@
  public:
   MockTransformableFrame() : TransformableFrameInterface(Passkey()) {}
 
+  MOCK_METHOD(RtpTimestampInfo, GetRtpTimestampInfo, (), (const, override));
   MOCK_METHOD(std::span<const uint8_t>, GetData, (), (const, override));
   MOCK_METHOD(void, SetData, (std::span<const uint8_t>), (override));
   MOCK_METHOD(uint8_t, GetPayloadType, (), (const, override));
diff --git a/api/test/mock_transformable_video_frame.h b/api/test/mock_transformable_video_frame.h
index 8f418a3..9b1331e 100644
--- a/api/test/mock_transformable_video_frame.h
+++ b/api/test/mock_transformable_video_frame.h
@@ -28,6 +28,7 @@
 class MockTransformableVideoFrame : public TransformableVideoFrameInterface {
  public:
   MockTransformableVideoFrame() : TransformableVideoFrameInterface(Passkey()) {}
+  MOCK_METHOD(RtpTimestampInfo, GetRtpTimestampInfo, (), (const, override));
   MOCK_METHOD(std::span<const uint8_t>, GetData, (), (const, override));
   MOCK_METHOD(void, SetData, (std::span<const uint8_t> data), (override));
   MOCK_METHOD(uint32_t, GetTimestamp, (), (const, override));
diff --git a/audio/channel_receive_frame_transformer_delegate.cc b/audio/channel_receive_frame_transformer_delegate.cc
index 14240b0..8416115 100644
--- a/audio/channel_receive_frame_transformer_delegate.cc
+++ b/audio/channel_receive_frame_transformer_delegate.cc
@@ -17,6 +17,7 @@
 #include <span>
 #include <string>
 #include <utility>
+#include <variant>
 
 #include "absl/base/nullability.h"
 #include "api/frame_transformer_interface.h"
@@ -60,6 +61,9 @@
   uint8_t GetPayloadType() const override { return header_.payloadType; }
   uint32_t GetSsrc() const override { return ssrc_; }
   uint32_t GetTimestamp() const override { return header_.timestamp; }
+  RtpTimestampInfo GetRtpTimestampInfo() const override {
+    return RtpTimestampWithOffset{header_.timestamp};
+  }
   std::span<const uint32_t> GetContributingSources() const override {
     return std::span<const uint32_t>(header_.arrOfCSRCs, header_.numCSRCs);
   }
@@ -206,7 +210,10 @@
   if (frame->GetDirection() ==
       TransformableFrameInterface::Direction::kSender) {
     header.payloadType = transformed_frame->GetPayloadType();
-    header.timestamp = transformed_frame->GetTimestamp();
+    RTC_CHECK(std::holds_alternative<RtpTimestampWithOffset>(
+        transformed_frame->GetRtpTimestampInfo()));
+    header.timestamp = std::get<RtpTimestampWithOffset>(
+        transformed_frame->GetRtpTimestampInfo());
     header.ssrc = transformed_frame->GetSsrc();
     if (transformed_frame->AbsoluteCaptureTimestamp().has_value()) {
       header.extension.absolute_capture_time = AbsoluteCaptureTime();
diff --git a/audio/channel_receive_frame_transformer_delegate_unittest.cc b/audio/channel_receive_frame_transformer_delegate_unittest.cc
index 16e6792..78bfeff 100644
--- a/audio/channel_receive_frame_transformer_delegate_unittest.cc
+++ b/audio/channel_receive_frame_transformer_delegate_unittest.cc
@@ -14,6 +14,7 @@
 #include <memory>
 #include <span>
 #include <utility>
+#include <variant>
 
 #include "api/frame_transformer_factory.h"
 #include "api/frame_transformer_interface.h"
@@ -351,6 +352,50 @@
   EXPECT_EQ(audio_frame->AudioLevel(), 127u);
 }
 
+TEST(ChannelReceiveFrameTransformerDelegateTest, GetAndSetRtpTimestampInfo) {
+  test::RunLoop main_thread;
+  scoped_refptr<MockFrameTransformer> mock_frame_transformer =
+      make_ref_counted<NiceMock<MockFrameTransformer>>();
+  scoped_refptr<ChannelReceiveFrameTransformerDelegate> delegate =
+      make_ref_counted<ChannelReceiveFrameTransformerDelegate>(
+          /*receive_frame_callback=*/nullptr, mock_frame_transformer,
+          main_thread.task_queue());
+  delegate->Init();
+
+  const uint8_t data[] = {1, 2, 3, 4};
+  std::span<const uint8_t> packet(data, sizeof(data));
+  RTPHeader header;
+  header.timestamp = 987654u;
+
+  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);
+
+  ASSERT_TRUE(frame);
+  auto* audio_frame =
+      static_cast<TransformableAudioFrameInterface*>(frame.get());
+  EXPECT_TRUE(std::holds_alternative<RtpTimestampWithOffset>(
+      audio_frame->GetRtpTimestampInfo()));
+  EXPECT_EQ(
+      std::get<RtpTimestampWithOffset>(audio_frame->GetRtpTimestampInfo()),
+      987654u);
+
+  // Test the SetRTPTimestamp setter
+  uint32_t new_timestamp = 112233u;
+  audio_frame->SetRTPTimestamp(new_timestamp);
+  EXPECT_EQ(audio_frame->GetTimestamp(), new_timestamp);
+  EXPECT_TRUE(std::holds_alternative<RtpTimestampWithOffset>(
+      audio_frame->GetRtpTimestampInfo()));
+  EXPECT_EQ(
+      std::get<RtpTimestampWithOffset>(audio_frame->GetRtpTimestampInfo()),
+      new_timestamp);
+}
+
 TEST(ChannelReceiveFrameTransformerDelegateTest,
      ReceivingSenderFrameWithAudioValueSetsAudioLevelInHeader) {
   test::RunLoop main_thread;
diff --git a/audio/channel_send_frame_transformer_delegate.cc b/audio/channel_send_frame_transformer_delegate.cc
index 57079c3..dfe0f9f 100644
--- a/audio/channel_send_frame_transformer_delegate.cc
+++ b/audio/channel_send_frame_transformer_delegate.cc
@@ -155,6 +155,10 @@
     return std::nullopt;
   }
 
+  RtpTimestampInfo GetRtpTimestampInfo() const override {
+    return RtpTimestampWithOffset{rtp_timestamp_with_offset_};
+  }
+
  private:
   AudioFrameType frame_type_;
   uint8_t payload_type_;
diff --git a/audio/channel_send_frame_transformer_delegate_unittest.cc b/audio/channel_send_frame_transformer_delegate_unittest.cc
index d5e19c1..58c2933 100644
--- a/audio/channel_send_frame_transformer_delegate_unittest.cc
+++ b/audio/channel_send_frame_transformer_delegate_unittest.cc
@@ -15,6 +15,7 @@
 #include <optional>
 #include <span>
 #include <utility>
+#include <variant>
 #include <vector>
 
 #include "absl/memory/memory.h"
@@ -364,5 +365,22 @@
   EXPECT_EQ(frame->AudioLevel(), 127u);
 }
 
+TEST(ChannelSendFrameTransformerDelegateTest, GetAndSetRtpTimestampInfo) {
+  std::unique_ptr<TransformableAudioFrameInterface> audio_frame = CreateFrame();
+  ASSERT_TRUE(audio_frame);
+
+  // Test the setter first
+  uint32_t new_timestamp = 789012u;
+  audio_frame->SetRTPTimestamp(new_timestamp);
+
+  // Test the getter after
+  EXPECT_EQ(audio_frame->GetTimestamp(), new_timestamp);
+  EXPECT_TRUE(std::holds_alternative<RtpTimestampWithOffset>(
+      audio_frame->GetRtpTimestampInfo()));
+  EXPECT_EQ(
+      std::get<RtpTimestampWithOffset>(audio_frame->GetRtpTimestampInfo()),
+      new_timestamp);
+}
+
 }  // namespace
 }  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate.cc b/modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate.cc
index c54f9f8..54441ab 100644
--- a/modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate.cc
@@ -89,6 +89,9 @@
   }
 
   uint32_t GetTimestamp() const override { return timestamp_; }
+  RtpTimestampInfo GetRtpTimestampInfo() const override {
+    return RtpTimestampWithOffset(timestamp_);
+  }
   void SetRTPTimestamp(uint32_t timestamp) override { timestamp_ = timestamp; }
 
   uint32_t GetSsrc() const override { return ssrc_; }
diff --git a/modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate_unittest.cc
index 332b53b..6238d09 100644
--- a/modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate_unittest.cc
@@ -18,6 +18,7 @@
 #include <span>
 #include <string>
 #include <utility>
+#include <variant>
 #include <vector>
 
 #include "api/frame_transformer_interface.h"
@@ -211,7 +212,13 @@
   EXPECT_EQ(clone->GetPayloadType(), video_frame.GetPayloadType());
   EXPECT_EQ(clone->GetMimeType(), video_frame.GetMimeType());
   EXPECT_EQ(clone->GetSsrc(), video_frame.GetSsrc());
-  EXPECT_EQ(clone->GetTimestamp(), video_frame.GetTimestamp());
+  EXPECT_TRUE(std::holds_alternative<RtpTimestampWithOffset>(
+      clone->GetRtpTimestampInfo()));
+  EXPECT_TRUE(std::holds_alternative<RtpTimestampWithOffset>(
+      video_frame.GetRtpTimestampInfo()));
+  EXPECT_EQ(
+      std::get<RtpTimestampWithOffset>(clone->GetRtpTimestampInfo()),
+      std::get<RtpTimestampWithOffset>(video_frame.GetRtpTimestampInfo()));
   EXPECT_EQ(clone->Metadata(), video_frame.Metadata());
   EXPECT_EQ(clone->Rid(), video_frame.Rid());
 }
@@ -234,7 +241,13 @@
   EXPECT_EQ(clone->GetPayloadType(), video_frame.GetPayloadType());
   EXPECT_EQ(clone->GetMimeType(), video_frame.GetMimeType());
   EXPECT_EQ(clone->GetSsrc(), video_frame.GetSsrc());
-  EXPECT_EQ(clone->GetTimestamp(), video_frame.GetTimestamp());
+  EXPECT_TRUE(std::holds_alternative<RtpTimestampWithOffset>(
+      clone->GetRtpTimestampInfo()));
+  EXPECT_TRUE(std::holds_alternative<RtpTimestampWithOffset>(
+      video_frame.GetRtpTimestampInfo()));
+  EXPECT_EQ(
+      std::get<RtpTimestampWithOffset>(clone->GetRtpTimestampInfo()),
+      std::get<RtpTimestampWithOffset>(video_frame.GetRtpTimestampInfo()));
   EXPECT_EQ(clone->Metadata(), video_frame.Metadata());
   EXPECT_EQ(clone->Rid(), video_frame.Rid());
 }
diff --git a/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate.cc b/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate.cc
index fdb4773..1b4ea9ec 100644
--- a/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate.cc
+++ b/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate.cc
@@ -66,6 +66,9 @@
   uint8_t GetPayloadType() const override { return frame_->PayloadType(); }
   uint32_t GetSsrc() const override { return Metadata().GetSsrc(); }
   uint32_t GetTimestamp() const override { return frame_->RtpTimestamp(); }
+  RtpTimestampInfo GetRtpTimestampInfo() const override {
+    return RtpTimestampWithOffset(frame_->RtpTimestamp());
+  }
   void SetRTPTimestamp(uint32_t timestamp) override {
     frame_->SetRtpTimestamp(timestamp);
   }
diff --git a/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate_unittest.cc b/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate_unittest.cc
index 03b2821..fde9c61 100644
--- a/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate_unittest.cc
@@ -15,6 +15,7 @@
 #include <optional>
 #include <span>
 #include <utility>
+#include <variant>
 #include <vector>
 
 #include "absl/memory/memory.h"
@@ -443,5 +444,49 @@
   delegate->TransformFrame(CreateRtpFrameObject());
 }
 
+TEST(RtpVideoStreamReceiverFrameTransformerDelegateTest,
+     GetAndSetRtpTimestampInfo) {
+  TaskQueueForTest task_queue;
+  TestRtpVideoFrameReceiver receiver;
+  auto mock_frame_transformer =
+      make_ref_counted<NiceMock<MockFrameTransformer>>();
+  SimulatedClock clock(0);
+  auto delegate =
+      make_ref_counted<RtpVideoStreamReceiverFrameTransformerDelegate>(
+          &receiver, &clock, mock_frame_transformer, task_queue.Get(), 1111);
+  delegate->Init();
+
+  RTPVideoHeader video_header;
+  uint32_t timestamp = 987654u;
+
+  EXPECT_CALL(*mock_frame_transformer, Transform)
+      .WillOnce([&](std::unique_ptr<TransformableFrameInterface>
+                        transformable_frame) {
+        auto frame =
+            absl::WrapUnique(static_cast<TransformableVideoFrameInterface*>(
+                transformable_frame.release()));
+        ASSERT_TRUE(frame);
+        EXPECT_TRUE(std::holds_alternative<RtpTimestampWithOffset>(
+            frame->GetRtpTimestampInfo()));
+        EXPECT_EQ(
+            std::get<RtpTimestampWithOffset>(frame->GetRtpTimestampInfo()),
+            timestamp);
+
+        // Test the SetRTPTimestamp setter
+        uint32_t new_timestamp = 112233u;
+        frame->SetRTPTimestamp(new_timestamp);
+        EXPECT_EQ(frame->GetTimestamp(), new_timestamp);
+        EXPECT_TRUE(std::holds_alternative<RtpTimestampWithOffset>(
+            frame->GetRtpTimestampInfo()));
+        EXPECT_EQ(
+            std::get<RtpTimestampWithOffset>(frame->GetRtpTimestampInfo()),
+            new_timestamp);
+      });
+
+  auto frame_object = CreateRtpFrameObject(video_header, /*csrcs=*/{});
+  frame_object->SetRtpTimestamp(timestamp);
+  delegate->TransformFrame(std::move(frame_object));
+}
+
 }  // namespace
 }  // namespace webrtc