diff --git a/pc/BUILD.gn b/pc/BUILD.gn index f31109af33..f29b558b41 100644 --- a/pc/BUILD.gn +++ b/pc/BUILD.gn @@ -874,6 +874,7 @@ if (rtc_include_tests && !build_with_chromium) { testonly = true sources = [ + "audio_rtp_receiver_unittest.cc", "channel_manager_unittest.cc", "channel_unittest.cc", "dtls_srtp_transport_unittest.cc", @@ -902,6 +903,7 @@ if (rtc_include_tests && !build_with_chromium) { } deps = [ + ":audio_rtp_receiver", ":libjingle_peerconnection", ":pc_test_utils", ":peerconnection", @@ -939,6 +941,7 @@ if (rtc_include_tests && !build_with_chromium) { "../rtc_base/third_party/sigslot", "../system_wrappers:metrics", "../test:field_trial", + "../test:test_common", "../test:test_main", "../test:test_support", "//third_party/abseil-cpp/absl/algorithm:container", @@ -1345,6 +1348,7 @@ if (rtc_include_tests && !build_with_chromium) { "test/mock_peer_connection_observers.h", "test/mock_rtp_receiver_internal.h", "test/mock_rtp_sender_internal.h", + "test/mock_voice_media_channel.h", "test/peer_connection_test_wrapper.cc", "test/peer_connection_test_wrapper.h", "test/rtc_stats_obtainer.h", diff --git a/pc/audio_rtp_receiver.cc b/pc/audio_rtp_receiver.cc index cfaee40480..7890d9b1e0 100644 --- a/pc/audio_rtp_receiver.cc +++ b/pc/audio_rtp_receiver.cc @@ -167,8 +167,10 @@ void AudioRtpReceiver::Stop() { worker_thread_->Invoke(RTC_FROM_HERE, [&]() { RTC_DCHECK_RUN_ON(worker_thread_); + if (media_channel_) SetOutputVolume_w(0.0); + SetMediaChannel_w(nullptr); }); } diff --git a/pc/audio_rtp_receiver_unittest.cc b/pc/audio_rtp_receiver_unittest.cc new file mode 100644 index 0000000000..1865115b2e --- /dev/null +++ b/pc/audio_rtp_receiver_unittest.cc @@ -0,0 +1,92 @@ +/* + * Copyright 2021 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "pc/audio_rtp_receiver.h" + +#include "media/base/media_channel.h" +#include "pc/test/mock_voice_media_channel.h" +#include "rtc_base/gunit.h" +#include "rtc_base/thread.h" +#include "test/gmock.h" +#include "test/gtest.h" + +using ::testing::_; +using ::testing::InvokeWithoutArgs; +using ::testing::Mock; + +static const int kTimeOut = 100; +static const double kDefaultVolume = 1; +static const double kVolume = 3.7; +static const uint32_t kSsrc = 3; + +namespace webrtc { +class AudioRtpReceiverTest : public ::testing::Test { + protected: + AudioRtpReceiverTest() + : worker_(rtc::Thread::Current()), + receiver_( + rtc::make_ref_counted(worker_, + std::string(), + std::vector(), + false)), + media_channel_(rtc::Thread::Current()) { + EXPECT_CALL(media_channel_, SetRawAudioSink(kSsrc, _)); + EXPECT_CALL(media_channel_, SetBaseMinimumPlayoutDelayMs(kSsrc, _)); + } + + ~AudioRtpReceiverTest() { + receiver_->SetMediaChannel(nullptr); + receiver_->Stop(); + } + + rtc::Thread* worker_; + rtc::scoped_refptr receiver_; + cricket::MockVoiceMediaChannel media_channel_; +}; + +TEST_F(AudioRtpReceiverTest, SetOutputVolumeIsCalled) { + std::atomic_int set_volume_calls(0); + + EXPECT_CALL(media_channel_, SetOutputVolume(kSsrc, kDefaultVolume)) + .WillOnce(InvokeWithoutArgs([&] { + set_volume_calls++; + return true; + })); + + receiver_->track(); + receiver_->track()->set_enabled(true); + receiver_->SetMediaChannel(&media_channel_); + receiver_->SetupMediaChannel(kSsrc); + + EXPECT_CALL(media_channel_, SetOutputVolume(kSsrc, kVolume)) + .WillOnce(InvokeWithoutArgs([&] { + set_volume_calls++; + return true; + })); + + receiver_->OnSetVolume(kVolume); + EXPECT_TRUE_WAIT(set_volume_calls == 2, kTimeOut); +} + +TEST_F(AudioRtpReceiverTest, VolumesSetBeforeStartingAreRespected) { + // Set the volume before setting the media channel. It should still be used + // as the initial volume. + receiver_->OnSetVolume(kVolume); + + receiver_->track()->set_enabled(true); + receiver_->SetMediaChannel(&media_channel_); + + // The previosly set initial volume should be propagated to the provided + // media_channel_ as soon as SetupMediaChannel is called. + EXPECT_CALL(media_channel_, SetOutputVolume(kSsrc, kVolume)); + + receiver_->SetupMediaChannel(kSsrc); +} +} // namespace webrtc diff --git a/pc/test/mock_voice_media_channel.h b/pc/test/mock_voice_media_channel.h new file mode 100644 index 0000000000..d6756b154e --- /dev/null +++ b/pc/test/mock_voice_media_channel.h @@ -0,0 +1,151 @@ +/* + * Copyright 2021 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef PC_TEST_MOCK_VOICE_MEDIA_CHANNEL_H_ +#define PC_TEST_MOCK_VOICE_MEDIA_CHANNEL_H_ + +#include +#include +#include + +#include "media/base/media_channel.h" +#include "rtc_base/gunit.h" +#include "test/gmock.h" +#include "test/gtest.h" + +using ::testing::InvokeWithoutArgs; +using ::testing::Mock; + +namespace cricket { +class MockVoiceMediaChannel : public VoiceMediaChannel { + public: + explicit MockVoiceMediaChannel(webrtc::TaskQueueBase* network_thread) + : VoiceMediaChannel(network_thread) {} + + MOCK_METHOD(void, SetInterface, (NetworkInterface * iface), (override)); + MOCK_METHOD(void, + OnPacketReceived, + (rtc::CopyOnWriteBuffer packet, int64_t packet_time_us), + (override)); + MOCK_METHOD(void, + OnPacketSent, + (const rtc::SentPacket& sent_packet), + (override)); + MOCK_METHOD(void, OnReadyToSend, (bool ready), (override)); + MOCK_METHOD(void, + OnNetworkRouteChanged, + (const std::string& transport_name, + const rtc::NetworkRoute& network_route), + (override)); + MOCK_METHOD(bool, AddSendStream, (const StreamParams& sp), (override)); + MOCK_METHOD(bool, RemoveSendStream, (uint32_t ssrc), (override)); + MOCK_METHOD(bool, AddRecvStream, (const StreamParams& sp), (override)); + MOCK_METHOD(bool, RemoveRecvStream, (uint32_t ssrc), (override)); + MOCK_METHOD(void, ResetUnsignaledRecvStream, (), (override)); + MOCK_METHOD(void, OnDemuxerCriteriaUpdatePending, (), (override)); + MOCK_METHOD(void, OnDemuxerCriteriaUpdateComplete, (), (override)); + MOCK_METHOD(int, GetRtpSendTimeExtnId, (), (const override)); + MOCK_METHOD( + void, + SetFrameEncryptor, + (uint32_t ssrc, + rtc::scoped_refptr frame_encryptor), + (override)); + MOCK_METHOD( + void, + SetFrameDecryptor, + (uint32_t ssrc, + rtc::scoped_refptr frame_decryptor), + (override)); + MOCK_METHOD(void, SetVideoCodecSwitchingEnabled, (bool enabled), (override)); + MOCK_METHOD(webrtc::RtpParameters, + GetRtpSendParameters, + (uint32_t ssrc), + (const override)); + MOCK_METHOD(webrtc::RTCError, + SetRtpSendParameters, + (uint32_t ssrc, const webrtc::RtpParameters& parameters), + (override)); + MOCK_METHOD( + void, + SetEncoderToPacketizerFrameTransformer, + (uint32_t ssrc, + rtc::scoped_refptr frame_transformer), + (override)); + MOCK_METHOD( + void, + SetDepacketizerToDecoderFrameTransformer, + (uint32_t ssrc, + rtc::scoped_refptr frame_transformer), + (override)); + + MOCK_METHOD(bool, + SetSendParameters, + (const AudioSendParameters& params), + (override)); + MOCK_METHOD(bool, + SetRecvParameters, + (const AudioRecvParameters& params), + (override)); + MOCK_METHOD(webrtc::RtpParameters, + GetRtpReceiveParameters, + (uint32_t ssrc), + (const override)); + MOCK_METHOD(webrtc::RtpParameters, + GetDefaultRtpReceiveParameters, + (), + (const override)); + MOCK_METHOD(void, SetPlayout, (bool playout), (override)); + MOCK_METHOD(void, SetSend, (bool send), (override)); + MOCK_METHOD(bool, + SetAudioSend, + (uint32_t ssrc, + bool enable, + const AudioOptions* options, + AudioSource* source), + (override)); + MOCK_METHOD(bool, + SetOutputVolume, + (uint32_t ssrc, double volume), + (override)); + MOCK_METHOD(bool, SetDefaultOutputVolume, (double volume), (override)); + MOCK_METHOD(bool, CanInsertDtmf, (), (override)); + MOCK_METHOD(bool, + InsertDtmf, + (uint32_t ssrc, int event, int duration), + (override)); + MOCK_METHOD(bool, + GetStats, + (VoiceMediaInfo * info, bool get_and_clear_legacy_stats), + (override)); + MOCK_METHOD(void, + SetRawAudioSink, + (uint32_t ssrc, std::unique_ptr sink), + (override)); + MOCK_METHOD(void, + SetDefaultRawAudioSink, + (std::unique_ptr sink), + (override)); + MOCK_METHOD(std::vector, + GetSources, + (uint32_t ssrc), + (const override)); + + MOCK_METHOD(bool, + SetBaseMinimumPlayoutDelayMs, + (uint32_t ssrc, int delay_ms), + (override)); + MOCK_METHOD(absl::optional, + GetBaseMinimumPlayoutDelayMs, + (uint32_t ssrc), + (const override)); +}; +} // namespace cricket + +#endif // PC_TEST_MOCK_VOICE_MEDIA_CHANNEL_H_