Add unit tests for ChannelReceiveFrameTransformerDelegate Verify cross-thread StartShortCircuiting and receive-thread Reset in ChannelReceiveFrameTransformerDelegate, and guard callback invocation when short-circuiting in Transform(). Bug: webrtc:11993 Change-Id: Ib79c07cced700353d5c2dcb1ecc9e46d15bc53a5 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/495020 Reviewed-by: Jakob Ivarsson‎ <jakobi@webrtc.org> Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org> Cr-Commit-Position: refs/heads/main@{#48628}
diff --git a/audio/channel_receive_frame_transformer_delegate.cc b/audio/channel_receive_frame_transformer_delegate.cc index 8416115..40372bc 100644 --- a/audio/channel_receive_frame_transformer_delegate.cc +++ b/audio/channel_receive_frame_transformer_delegate.cc
@@ -146,9 +146,11 @@ ReceiveFrameCallback receive_frame_callback, scoped_refptr<FrameTransformerInterface> frame_transformer, TaskQueueBase* absl_nonnull channel_receive_thread) - : receive_frame_callback_(receive_frame_callback), + : receive_frame_callback_(std::move(receive_frame_callback)), frame_transformer_(std::move(frame_transformer)), - channel_receive_thread_(channel_receive_thread) {} + channel_receive_thread_(channel_receive_thread) { + RTC_DCHECK(receive_frame_callback_); +} void ChannelReceiveFrameTransformerDelegate::Init() { RTC_DCHECK_RUN_ON(&sequence_checker_); @@ -171,7 +173,9 @@ Timestamp receive_time) { RTC_DCHECK_RUN_ON(&sequence_checker_); if (short_circuit_) { - receive_frame_callback_(packet, header, receive_time); + if (receive_frame_callback_) { + receive_frame_callback_(packet, header, receive_time); + } } else { frame_transformer_->Transform( std::make_unique<TransformableIncomingAudioFrame>(
diff --git a/audio/channel_receive_frame_transformer_delegate_unittest.cc b/audio/channel_receive_frame_transformer_delegate_unittest.cc index 67a46a0..c601226 100644 --- a/audio/channel_receive_frame_transformer_delegate_unittest.cc +++ b/audio/channel_receive_frame_transformer_delegate_unittest.cc
@@ -25,6 +25,7 @@ #include "api/test/mock_transformable_audio_frame.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" +#include "rtc_base/task_queue_for_test.h" #include "rtc_base/thread.h" #include "system_wrappers/include/ntp_time.h" #include "test/gmock.h" @@ -66,8 +67,7 @@ make_ref_counted<MockFrameTransformer>(); scoped_refptr<ChannelReceiveFrameTransformerDelegate> delegate = make_ref_counted<ChannelReceiveFrameTransformerDelegate>( - ChannelReceiveFrameTransformerDelegate::ReceiveFrameCallback(), - mock_frame_transformer, main_thread.task_queue()); + [](auto...) {}, mock_frame_transformer, main_thread.task_queue()); EXPECT_CALL(*mock_frame_transformer, RegisterTransformedFrameCallback); delegate->Init(); } @@ -81,8 +81,7 @@ make_ref_counted<MockFrameTransformer>(); scoped_refptr<ChannelReceiveFrameTransformerDelegate> delegate = make_ref_counted<ChannelReceiveFrameTransformerDelegate>( - ChannelReceiveFrameTransformerDelegate::ReceiveFrameCallback(), - mock_frame_transformer, main_thread.task_queue()); + [](auto...) {}, mock_frame_transformer, main_thread.task_queue()); EXPECT_CALL(*mock_frame_transformer, UnregisterTransformedFrameCallback); delegate->Reset(); } @@ -206,7 +205,7 @@ make_ref_counted<NiceMock<MockFrameTransformer>>(); scoped_refptr<ChannelReceiveFrameTransformerDelegate> delegate = make_ref_counted<ChannelReceiveFrameTransformerDelegate>( - /*receive_frame_callback=*/nullptr, mock_frame_transformer, + /*receive_frame_callback=*/[](auto...) {}, mock_frame_transformer, main_thread.task_queue()); scoped_refptr<TransformedFrameCallback> callback; EXPECT_CALL(*mock_frame_transformer, RegisterTransformedFrameCallback) @@ -243,7 +242,7 @@ make_ref_counted<NiceMock<MockFrameTransformer>>(); scoped_refptr<ChannelReceiveFrameTransformerDelegate> delegate = make_ref_counted<ChannelReceiveFrameTransformerDelegate>( - /*receive_frame_callback=*/nullptr, mock_frame_transformer, + /*receive_frame_callback=*/[](auto...) {}, mock_frame_transformer, main_thread.task_queue()); scoped_refptr<TransformedFrameCallback> callback; EXPECT_CALL(*mock_frame_transformer, RegisterTransformedFrameCallback) @@ -281,7 +280,7 @@ make_ref_counted<NiceMock<MockFrameTransformer>>(); scoped_refptr<ChannelReceiveFrameTransformerDelegate> delegate = make_ref_counted<ChannelReceiveFrameTransformerDelegate>( - /*receive_frame_callback=*/nullptr, mock_frame_transformer, + /*receive_frame_callback=*/[](auto...) {}, mock_frame_transformer, main_thread.task_queue()); scoped_refptr<TransformedFrameCallback> callback; EXPECT_CALL(*mock_frame_transformer, RegisterTransformedFrameCallback) @@ -324,7 +323,7 @@ make_ref_counted<NiceMock<MockFrameTransformer>>(); scoped_refptr<ChannelReceiveFrameTransformerDelegate> delegate = make_ref_counted<ChannelReceiveFrameTransformerDelegate>( - /*receive_frame_callback=*/nullptr, mock_frame_transformer, + /*receive_frame_callback=*/[](auto...) {}, mock_frame_transformer, main_thread.task_queue()); delegate->Init(); const uint8_t data[] = {1, 2, 3, 4}; @@ -358,7 +357,7 @@ make_ref_counted<NiceMock<MockFrameTransformer>>(); scoped_refptr<ChannelReceiveFrameTransformerDelegate> delegate = make_ref_counted<ChannelReceiveFrameTransformerDelegate>( - /*receive_frame_callback=*/nullptr, mock_frame_transformer, + /*receive_frame_callback=*/[](auto...) {}, mock_frame_transformer, main_thread.task_queue()); delegate->Init(); @@ -422,5 +421,47 @@ EXPECT_EQ(header.extension.audio_level()->level(), 111); } +TEST(ChannelReceiveFrameTransformerDelegateTest, + StartShortCircuitingFromAnotherThreadPostsToReceiveThread) { + test::RunLoop main_thread; + scoped_refptr<MockFrameTransformer> mock_frame_transformer = + make_ref_counted<NiceMock<MockFrameTransformer>>(); + MockChannelReceive mock_channel; + scoped_refptr<ChannelReceiveFrameTransformerDelegate> delegate = + make_ref_counted<ChannelReceiveFrameTransformerDelegate>( + mock_channel.callback(), mock_frame_transformer, + main_thread.task_queue()); + const uint8_t data[] = {1, 2, 3, 4}; + std::span<const uint8_t> packet(data, sizeof(data)); + RTPHeader header; + + TaskQueueForTest off_thread("ShortCircuitQueue"); + off_thread.SendTask([&]() { delegate->StartShortCircuiting(); }); + main_thread.Flush(); + + EXPECT_CALL(*mock_frame_transformer, Transform).Times(0); + EXPECT_CALL(mock_channel, ReceiveFrame); + delegate->Transform(packet, header, /*ssrc=*/1111, + /*codec_mime_type=*/"audio/opus", kFakeReceiveTimestamp); +} + +TEST(ChannelReceiveFrameTransformerDelegateTest, + ResetSafelyClearsCallbackOnReceiveThread) { + test::RunLoop main_thread; + scoped_refptr<MockFrameTransformer> mock_frame_transformer = + make_ref_counted<NiceMock<MockFrameTransformer>>(); + MockChannelReceive mock_channel; + scoped_refptr<ChannelReceiveFrameTransformerDelegate> delegate = + make_ref_counted<ChannelReceiveFrameTransformerDelegate>( + mock_channel.callback(), mock_frame_transformer, + main_thread.task_queue()); + + delegate->Reset(); + + EXPECT_CALL(mock_channel, ReceiveFrame).Times(0); + delegate->OnTransformedFrame(std::make_unique<MockTransformableAudioFrame>()); + main_thread.Flush(); +} + } // namespace } // namespace webrtc