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