/* * Copyright (c) 2015 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 "testing/gtest/include/gtest/gtest.h" #include "webrtc/base/random.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/base/timeutils.h" #include "webrtc/system_wrappers/include/sleep.h" #include "webrtc/test/channel_transport/channel_transport.h" #include "webrtc/test/testsupport/fileutils.h" #include "webrtc/voice_engine/test/auto_test/voe_standard_test.h" namespace { const char kIp[] = "127.0.0.1"; const int kPort = 1234; const webrtc::CodecInst kCodecInst = {120, "opus", 48000, 960, 2, 64000}; } // namespace namespace voetest { using webrtc::Random; using webrtc::test::VoiceChannelTransport; // This test allows a check on the output signal in an end-to-end call. class OutputTest { public: OutputTest(int16_t lower_bound, int16_t upper_bound); ~OutputTest(); void Start(); void EnableOutputCheck(); void DisableOutputCheck(); void SetOutputBound(int16_t lower_bound, int16_t upper_bound); void Mute(); void Unmute(); void SetBitRate(int rate); private: // This class checks all output values and count the number of samples that // go out of a defined range. class VoEOutputCheckMediaProcess : public VoEMediaProcess { public: VoEOutputCheckMediaProcess(int16_t lower_bound, int16_t upper_bound); void set_enabled(bool enabled) { enabled_ = enabled; } void Process(int channel, ProcessingTypes type, int16_t audio10ms[], size_t length, int samplingFreq, bool isStereo) override; private: bool enabled_; int16_t lower_bound_; int16_t upper_bound_; }; VoETestManager manager_; VoEOutputCheckMediaProcess output_checker_; int channel_; }; OutputTest::OutputTest(int16_t lower_bound, int16_t upper_bound) : output_checker_(lower_bound, upper_bound) { EXPECT_TRUE(manager_.Init()); manager_.GetInterfaces(); VoEBase* base = manager_.BasePtr(); VoECodec* codec = manager_.CodecPtr(); VoENetwork* network = manager_.NetworkPtr(); EXPECT_EQ(0, base->Init()); channel_ = base->CreateChannel(); // |network| will take care of the life time of |transport|. VoiceChannelTransport* transport = new VoiceChannelTransport(network, channel_); EXPECT_EQ(0, transport->SetSendDestination(kIp, kPort)); EXPECT_EQ(0, transport->SetLocalReceiver(kPort)); EXPECT_EQ(0, codec->SetSendCodec(channel_, kCodecInst)); EXPECT_EQ(0, codec->SetOpusDtx(channel_, true)); EXPECT_EQ(0, manager_.VolumeControlPtr()->SetSpeakerVolume(255)); manager_.ExternalMediaPtr()->RegisterExternalMediaProcessing( channel_, ProcessingTypes::kPlaybackPerChannel, output_checker_); } OutputTest::~OutputTest() { EXPECT_EQ(0, manager_.NetworkPtr()->DeRegisterExternalTransport(channel_)); EXPECT_EQ(0, manager_.ReleaseInterfaces()); } void OutputTest::Start() { const std::string file_name = webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"); const webrtc::FileFormats kInputFormat = webrtc::kFileFormatPcm32kHzFile; ASSERT_EQ(0, manager_.FilePtr()->StartPlayingFileAsMicrophone( channel_, file_name.c_str(), true, false, kInputFormat, 1.0)); VoEBase* base = manager_.BasePtr(); ASSERT_EQ(0, base->StartPlayout(channel_)); ASSERT_EQ(0, base->StartSend(channel_)); } void OutputTest::EnableOutputCheck() { output_checker_.set_enabled(true); } void OutputTest::DisableOutputCheck() { output_checker_.set_enabled(false); } void OutputTest::Mute() { manager_.VolumeControlPtr()->SetInputMute(channel_, true); } void OutputTest::Unmute() { manager_.VolumeControlPtr()->SetInputMute(channel_, false); } void OutputTest::SetBitRate(int rate) { manager_.CodecPtr()->SetBitRate(channel_, rate); } OutputTest::VoEOutputCheckMediaProcess::VoEOutputCheckMediaProcess( int16_t lower_bound, int16_t upper_bound) : enabled_(false), lower_bound_(lower_bound), upper_bound_(upper_bound) {} void OutputTest::VoEOutputCheckMediaProcess::Process(int channel, ProcessingTypes type, int16_t* audio10ms, size_t length, int samplingFreq, bool isStereo) { if (!enabled_) return; const int num_channels = isStereo ? 2 : 1; for (size_t i = 0; i < length; ++i) { for (int c = 0; c < num_channels; ++c) { ASSERT_GE(audio10ms[i * num_channels + c], lower_bound_); ASSERT_LE(audio10ms[i * num_channels + c], upper_bound_); } } } // This test checks if the Opus does not produce high noise (noise pump) when // DTX is enabled. The microphone is toggled on and off, and values of the // output signal during muting should be bounded. // We do not run this test on bots. Developers that want to see the result // and/or listen to sound quality can run this test manually. TEST(OutputTest, DISABLED_OpusDtxHasNoNoisePump) { const int kRuntimeMs = 20000; const uint32_t kUnmuteTimeMs = 1000; const int kCheckAfterMute = 2000; const uint32_t kCheckTimeMs = 2000; const int kMinOpusRate = 6000; const int kMaxOpusRate = 64000; #if defined(OPUS_FIXED_POINT) const int16_t kDtxBoundForSilence = 20; #else const int16_t kDtxBoundForSilence = 2; #endif OutputTest test(-kDtxBoundForSilence, kDtxBoundForSilence); Random random(1234ull); uint32_t start_time = rtc::Time(); test.Start(); while (rtc::TimeSince(start_time) < kRuntimeMs) { webrtc::SleepMs(random.Rand(kUnmuteTimeMs - kUnmuteTimeMs / 10, kUnmuteTimeMs + kUnmuteTimeMs / 10)); test.Mute(); webrtc::SleepMs(kCheckAfterMute); test.EnableOutputCheck(); webrtc::SleepMs(random.Rand(kCheckTimeMs - kCheckTimeMs / 10, kCheckTimeMs + kCheckTimeMs / 10)); test.DisableOutputCheck(); test.SetBitRate(random.Rand(kMinOpusRate, kMaxOpusRate)); test.Unmute(); } } } // namespace voetest