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 <herre@google.com>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Palak Agarwal <agpalak@google.com>
Cr-Commit-Position: refs/heads/main@{#40583}
diff --git a/audio/channel_receive_frame_transformer_delegate.cc b/audio/channel_receive_frame_transformer_delegate.cc
index 54e08f7..2d2893b 100644
--- a/audio/channel_receive_frame_transformer_delegate.cc
+++ b/audio/channel_receive_frame_transformer_delegate.cc
@@ -112,11 +112,30 @@
RTC_DCHECK_RUN_ON(&sequence_checker_);
if (!receive_frame_callback_)
return;
- RTC_CHECK_EQ(frame->GetDirection(),
- TransformableFrameInterface::Direction::kReceiver);
- auto* transformed_frame =
- static_cast<TransformableIncomingAudioFrame*>(frame.get());
- receive_frame_callback_(transformed_frame->GetData(),
- transformed_frame->Header());
+
+ RTPHeader header;
+ if (frame->GetDirection() ==
+ TransformableFrameInterface::Direction::kSender) {
+ auto* transformed_frame =
+ static_cast<TransformableAudioFrameInterface*>(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<TransformableIncomingAudioFrame*>(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 e31dd9f..b08dcff 100644
--- a/audio/channel_receive_frame_transformer_delegate_unittest.cc
+++ b/audio/channel_receive_frame_transformer_delegate_unittest.cc
@@ -13,6 +13,7 @@
#include <memory>
#include <utility>
+#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 @@
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<MockFrameTransformer> mock_frame_transformer =
+ rtc::make_ref_counted<NiceMock<MockFrameTransformer>>();
+ MockChannelReceive mock_channel;
+ rtc::scoped_refptr<ChannelReceiveFrameTransformerDelegate> delegate =
+ rtc::make_ref_counted<ChannelReceiveFrameTransformerDelegate>(
+ mock_channel.callback(), 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));
+ RTPHeader header;
+ EXPECT_CALL(mock_channel, ReceiveFrame(ElementsAre(1, 2, 3, 4), _));
+ ON_CALL(*mock_frame_transformer, Transform)
+ .WillByDefault([&callback](
+ std::unique_ptr<TransformableFrameInterface> frame) {
+ auto* transformed_frame =
+ static_cast<TransformableAudioFrameInterface*>(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.