From f263e1eb038e195d16b7c1b15cdfb6db82b32e4d Mon Sep 17 00:00:00 2001 From: Palak Agarwal Date: Fri, 18 Aug 2023 14:09:53 +0200 Subject: [PATCH] Support receiving cloned encoded audio frames Bug: chromium:1464860 Change-Id: I01b2d768fcf5aef09b32304a8f9fe0b00ca32357 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/316320 Reviewed-by: Tony Herre Reviewed-by: Harald Alvestrand Commit-Queue: Palak Agarwal Cr-Commit-Position: refs/heads/main@{#40583} --- ...nnel_receive_frame_transformer_delegate.cc | 31 ++++++++++++---- ...ive_frame_transformer_delegate_unittest.cc | 36 +++++++++++++++++++ 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/audio/channel_receive_frame_transformer_delegate.cc b/audio/channel_receive_frame_transformer_delegate.cc index 54e08f7dea..2d2893b8f7 100644 --- a/audio/channel_receive_frame_transformer_delegate.cc +++ b/audio/channel_receive_frame_transformer_delegate.cc @@ -112,11 +112,30 @@ void ChannelReceiveFrameTransformerDelegate::ReceiveFrame( RTC_DCHECK_RUN_ON(&sequence_checker_); if (!receive_frame_callback_) return; - RTC_CHECK_EQ(frame->GetDirection(), - TransformableFrameInterface::Direction::kReceiver); - auto* transformed_frame = - static_cast(frame.get()); - receive_frame_callback_(transformed_frame->GetData(), - transformed_frame->Header()); + + RTPHeader header; + if (frame->GetDirection() == + TransformableFrameInterface::Direction::kSender) { + auto* transformed_frame = + static_cast(frame.get()); + header.payloadType = transformed_frame->GetPayloadType(); + header.timestamp = transformed_frame->GetTimestamp(); + header.ssrc = transformed_frame->GetSsrc(); + if (transformed_frame->AbsoluteCaptureTimestamp().has_value()) { + header.extension.absolute_capture_time = AbsoluteCaptureTime(); + header.extension.absolute_capture_time->absolute_capture_timestamp = + transformed_frame->AbsoluteCaptureTimestamp().value(); + } + } else { + auto* transformed_frame = + static_cast(frame.get()); + header = transformed_frame->Header(); + } + + // TODO(crbug.com/1464860): Take an explicit struct with the required + // information rather than the RTPHeader to make it easier to + // construct the required information when injecting transformed frames not + // originally from this receiver. + receive_frame_callback_(frame->GetData(), header); } } // namespace webrtc diff --git a/audio/channel_receive_frame_transformer_delegate_unittest.cc b/audio/channel_receive_frame_transformer_delegate_unittest.cc index e31dd9f876..b08dcff78d 100644 --- a/audio/channel_receive_frame_transformer_delegate_unittest.cc +++ b/audio/channel_receive_frame_transformer_delegate_unittest.cc @@ -13,6 +13,7 @@ #include #include +#include "audio/channel_send_frame_transformer_delegate.h" #include "test/gmock.h" #include "test/gtest.h" #include "test/mock_frame_transformer.h" @@ -21,6 +22,8 @@ namespace webrtc { namespace { +using ::testing::_; +using ::testing::ElementsAre; using ::testing::NiceMock; using ::testing::SaveArg; @@ -94,6 +97,39 @@ TEST(ChannelReceiveFrameTransformerDelegateTest, rtc::ThreadManager::ProcessAllMessageQueuesForTesting(); } +// Test that when the delegate receives a Outgoing frame from the frame +// transformer, it passes it to the channel using the ReceiveFrameCallback. +TEST(ChannelReceiveFrameTransformerDelegateTest, + TransformRunsChannelReceiveCallbackForSenderFrame) { + rtc::AutoThread main_thread; + rtc::scoped_refptr mock_frame_transformer = + rtc::make_ref_counted>(); + MockChannelReceive mock_channel; + rtc::scoped_refptr delegate = + rtc::make_ref_counted( + mock_channel.callback(), mock_frame_transformer, + rtc::Thread::Current()); + rtc::scoped_refptr 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 packet(data, sizeof(data)); + RTPHeader header; + EXPECT_CALL(mock_channel, ReceiveFrame(ElementsAre(1, 2, 3, 4), _)); + ON_CALL(*mock_frame_transformer, Transform) + .WillByDefault([&callback]( + std::unique_ptr frame) { + auto* transformed_frame = + static_cast(frame.get()); + callback->OnTransformedFrame(CloneSenderAudioFrame(transformed_frame)); + }); + delegate->Transform(packet, header, 1111 /*ssrc*/); + rtc::ThreadManager::ProcessAllMessageQueuesForTesting(); +} + // Test that if the delegate receives a transformed frame after it has been // reset, it does not run the ReceiveFrameCallback, as the channel is destroyed // after resetting the delegate.