/* * Copyright (c) 2020 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 "audio/voip/voip_core.h" #include "api/audio_codecs/builtin_audio_decoder_factory.h" #include "api/audio_codecs/builtin_audio_encoder_factory.h" #include "api/task_queue/default_task_queue_factory.h" #include "modules/audio_device/include/mock_audio_device.h" #include "modules/audio_processing/include/mock_audio_processing.h" #include "test/gtest.h" #include "test/mock_transport.h" #include "test/run_loop.h" namespace webrtc { namespace { using ::testing::NiceMock; using ::testing::Return; constexpr int kPcmuPayload = 0; constexpr int kPcmuSampleRateHz = 8000; constexpr int kDtmfEventDurationMs = 1000; constexpr DtmfEvent kDtmfEventCode = DtmfEvent::kDigitZero; class VoipCoreTest : public ::testing::Test { public: const SdpAudioFormat kPcmuFormat = {"pcmu", 8000, 1}; VoipCoreTest() { audio_device_ = test::MockAudioDeviceModule::CreateNice(); } void SetUp() override { auto encoder_factory = CreateBuiltinAudioEncoderFactory(); auto decoder_factory = CreateBuiltinAudioDecoderFactory(); rtc::scoped_refptr audio_processing = rtc::make_ref_counted>(); voip_core_ = std::make_unique( std::move(encoder_factory), std::move(decoder_factory), CreateDefaultTaskQueueFactory(), audio_device_, std::move(audio_processing)); } test::RunLoop run_loop_; std::unique_ptr voip_core_; NiceMock transport_; rtc::scoped_refptr audio_device_; }; // Validate expected API calls that involves with VoipCore. Some verification is // involved with checking mock audio device. TEST_F(VoipCoreTest, BasicVoipCoreOperation) { // Program mock as non-operational and ready to start. EXPECT_CALL(*audio_device_, Recording()).WillOnce(Return(false)); EXPECT_CALL(*audio_device_, Playing()).WillOnce(Return(false)); EXPECT_CALL(*audio_device_, InitRecording()).WillOnce(Return(0)); EXPECT_CALL(*audio_device_, InitPlayout()).WillOnce(Return(0)); EXPECT_CALL(*audio_device_, StartRecording()).WillOnce(Return(0)); EXPECT_CALL(*audio_device_, StartPlayout()).WillOnce(Return(0)); auto channel = voip_core_->CreateChannel(&transport_, 0xdeadc0de); EXPECT_EQ(voip_core_->SetSendCodec(channel, kPcmuPayload, kPcmuFormat), VoipResult::kOk); EXPECT_EQ( voip_core_->SetReceiveCodecs(channel, {{kPcmuPayload, kPcmuFormat}}), VoipResult::kOk); EXPECT_EQ(voip_core_->StartSend(channel), VoipResult::kOk); EXPECT_EQ(voip_core_->StartPlayout(channel), VoipResult::kOk); EXPECT_EQ(voip_core_->RegisterTelephoneEventType(channel, kPcmuPayload, kPcmuSampleRateHz), VoipResult::kOk); EXPECT_EQ( voip_core_->SendDtmfEvent(channel, kDtmfEventCode, kDtmfEventDurationMs), VoipResult::kOk); // Program mock as operational that is ready to be stopped. EXPECT_CALL(*audio_device_, Recording()).WillOnce(Return(true)); EXPECT_CALL(*audio_device_, Playing()).WillOnce(Return(true)); EXPECT_CALL(*audio_device_, StopRecording()).WillOnce(Return(0)); EXPECT_CALL(*audio_device_, StopPlayout()).WillOnce(Return(0)); EXPECT_EQ(voip_core_->StopSend(channel), VoipResult::kOk); EXPECT_EQ(voip_core_->StopPlayout(channel), VoipResult::kOk); EXPECT_EQ(voip_core_->ReleaseChannel(channel), VoipResult::kOk); } TEST_F(VoipCoreTest, ExpectFailToUseReleasedChannelId) { auto channel = voip_core_->CreateChannel(&transport_, 0xdeadc0de); // Release right after creation. EXPECT_EQ(voip_core_->ReleaseChannel(channel), VoipResult::kOk); // Now use released channel. EXPECT_EQ(voip_core_->SetSendCodec(channel, kPcmuPayload, kPcmuFormat), VoipResult::kInvalidArgument); EXPECT_EQ( voip_core_->SetReceiveCodecs(channel, {{kPcmuPayload, kPcmuFormat}}), VoipResult::kInvalidArgument); EXPECT_EQ(voip_core_->RegisterTelephoneEventType(channel, kPcmuPayload, kPcmuSampleRateHz), VoipResult::kInvalidArgument); EXPECT_EQ(voip_core_->StartSend(channel), VoipResult::kInvalidArgument); EXPECT_EQ(voip_core_->StartPlayout(channel), VoipResult::kInvalidArgument); EXPECT_EQ( voip_core_->SendDtmfEvent(channel, kDtmfEventCode, kDtmfEventDurationMs), VoipResult::kInvalidArgument); } TEST_F(VoipCoreTest, SendDtmfEventWithoutRegistering) { // Program mock as non-operational and ready to start send. EXPECT_CALL(*audio_device_, Recording()).WillOnce(Return(false)); EXPECT_CALL(*audio_device_, InitRecording()).WillOnce(Return(0)); EXPECT_CALL(*audio_device_, StartRecording()).WillOnce(Return(0)); auto channel = voip_core_->CreateChannel(&transport_, 0xdeadc0de); EXPECT_EQ(voip_core_->SetSendCodec(channel, kPcmuPayload, kPcmuFormat), VoipResult::kOk); EXPECT_EQ(voip_core_->StartSend(channel), VoipResult::kOk); // Send Dtmf event without registering beforehand, thus payload // type is not set and kFailedPrecondition is expected. EXPECT_EQ( voip_core_->SendDtmfEvent(channel, kDtmfEventCode, kDtmfEventDurationMs), VoipResult::kFailedPrecondition); // Program mock as sending and is ready to be stopped. EXPECT_CALL(*audio_device_, Recording()).WillOnce(Return(true)); EXPECT_CALL(*audio_device_, StopRecording()).WillOnce(Return(0)); EXPECT_EQ(voip_core_->StopSend(channel), VoipResult::kOk); EXPECT_EQ(voip_core_->ReleaseChannel(channel), VoipResult::kOk); } TEST_F(VoipCoreTest, SendDtmfEventWithoutStartSend) { auto channel = voip_core_->CreateChannel(&transport_, 0xdeadc0de); EXPECT_EQ(voip_core_->RegisterTelephoneEventType(channel, kPcmuPayload, kPcmuSampleRateHz), VoipResult::kOk); // Send Dtmf event without calling StartSend beforehand, thus // Dtmf events cannot be sent and kFailedPrecondition is expected. EXPECT_EQ( voip_core_->SendDtmfEvent(channel, kDtmfEventCode, kDtmfEventDurationMs), VoipResult::kFailedPrecondition); EXPECT_EQ(voip_core_->ReleaseChannel(channel), VoipResult::kOk); } TEST_F(VoipCoreTest, StartSendAndPlayoutWithoutSettingCodec) { auto channel = voip_core_->CreateChannel(&transport_, 0xdeadc0de); // Call StartSend and StartPlayout without setting send/receive // codec. Code should see that codecs aren't set and return false. EXPECT_EQ(voip_core_->StartSend(channel), VoipResult::kFailedPrecondition); EXPECT_EQ(voip_core_->StartPlayout(channel), VoipResult::kFailedPrecondition); EXPECT_EQ(voip_core_->ReleaseChannel(channel), VoipResult::kOk); } TEST_F(VoipCoreTest, StopSendAndPlayoutWithoutStarting) { auto channel = voip_core_->CreateChannel(&transport_, 0xdeadc0de); EXPECT_EQ(voip_core_->SetSendCodec(channel, kPcmuPayload, kPcmuFormat), VoipResult::kOk); EXPECT_EQ( voip_core_->SetReceiveCodecs(channel, {{kPcmuPayload, kPcmuFormat}}), VoipResult::kOk); // Call StopSend and StopPlayout without starting them in // the first place. Should see that it is already in the // stopped state and return true. EXPECT_EQ(voip_core_->StopSend(channel), VoipResult::kOk); EXPECT_EQ(voip_core_->StopPlayout(channel), VoipResult::kOk); EXPECT_EQ(voip_core_->ReleaseChannel(channel), VoipResult::kOk); } } // namespace } // namespace webrtc