diff options
Diffstat (limited to 'webrtc/modules/audio_processing/agc/agc_unittest.cc')
-rw-r--r-- | webrtc/modules/audio_processing/agc/agc_unittest.cc | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/webrtc/modules/audio_processing/agc/agc_unittest.cc b/webrtc/modules/audio_processing/agc/agc_unittest.cc new file mode 100644 index 0000000000..66a8a2b1b3 --- /dev/null +++ b/webrtc/modules/audio_processing/agc/agc_unittest.cc @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2012 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 "webrtc/modules/audio_processing/agc/agc.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include "webrtc/modules/interface/module_common_types.h" +#include "webrtc/test/testsupport/fileutils.h" +#include "webrtc/tools/agc/test_utils.h" + +using ::testing::_; +using ::testing::AllOf; +using ::testing::AtLeast; +using ::testing::Eq; +using ::testing::Gt; +using ::testing::InSequence; +using ::testing::Lt; +using ::testing::Mock; +using ::testing::SaveArg; + +namespace webrtc { +namespace { + +// The tested values depend on this assumed gain. +const int kMaxGain = 80; + +MATCHER_P(GtPointee, p, "") { return arg > *p; } +MATCHER_P(LtPointee, p, "") { return arg < *p; } + +class AgcChecker { + public: + MOCK_METHOD2(LevelChanged, void(int iterations, int level)); +}; + +class AgcTest : public ::testing::Test { + protected: + AgcTest() + : agc_(), + checker_(), + mic_level_(128) { + } + + // A gain of <= -100 will zero out the signal. + void RunAgc(int iterations, float gain_db) { + FILE* input_file = fopen( + test::ResourcePath("voice_engine/audio_long16", "pcm").c_str(), "rb"); + ASSERT_TRUE(input_file != NULL); + + AudioFrame frame; + frame.sample_rate_hz_ = 16000; + frame.num_channels_ = 1; + frame.samples_per_channel_ = frame.sample_rate_hz_ / 100; + const size_t length = frame.samples_per_channel_ * frame.num_channels_; + + float gain = Db2Linear(gain_db); + if (gain_db <= -100) { + gain = 0; + } + + for (int i = 0; i < iterations; ++i) { + ASSERT_EQ(length, fread(frame.data_, sizeof(int16_t), length, + input_file)); + SimulateMic(kMaxGain, mic_level_, &frame); + ApplyGainLinear(gain, &frame); + ASSERT_GE(agc_.Process(frame), 0); + + int mic_level = agc_.MicLevel(); + if (mic_level != mic_level_) { + printf("mic_level=%d\n", mic_level); + checker_.LevelChanged(i, mic_level); + } + mic_level_ = mic_level; + } + fclose(input_file); + } + + Agc agc_; + AgcChecker checker_; + // Stores mic level between multiple runs of RunAgc in one test. + int mic_level_; +}; + +TEST_F(AgcTest, UpwardsChangeIsLimited) { + { + InSequence seq; + EXPECT_CALL(checker_, LevelChanged(Lt(500), Eq(179))).Times(1); + EXPECT_CALL(checker_, LevelChanged(_, Gt(179))).Times(AtLeast(1)); + } + RunAgc(1000, -40); +} + +TEST_F(AgcTest, DownwardsChangeIsLimited) { + { + InSequence seq; + EXPECT_CALL(checker_, LevelChanged(Lt(500), Eq(77))).Times(1); + EXPECT_CALL(checker_, LevelChanged(_, Lt(77))).Times(AtLeast(1)); + } + RunAgc(1000, 40); +} + +TEST_F(AgcTest, MovesUpToMaxAndDownToMin) { + int last_level = 128; + EXPECT_CALL(checker_, LevelChanged(_, GtPointee(&last_level))) + .Times(AtLeast(2)) + .WillRepeatedly(SaveArg<1>(&last_level)); + RunAgc(1000, -30); + EXPECT_EQ(255, last_level); + Mock::VerifyAndClearExpectations(&checker_); + + EXPECT_CALL(checker_, LevelChanged(_, LtPointee(&last_level))) + .Times(AtLeast(2)) + .WillRepeatedly(SaveArg<1>(&last_level)); + RunAgc(1000, 50); + EXPECT_EQ(1, last_level); +} + +TEST_F(AgcTest, HandlesZeroSignal) { + int last_level = 128; + // Doesn't respond to a zero signal. + EXPECT_CALL(checker_, LevelChanged(_, _)).Times(0); + RunAgc(1000, -100); + Mock::VerifyAndClearExpectations(&checker_); + + // Reacts as usual afterwards. + EXPECT_CALL(checker_, LevelChanged(_, GtPointee(&last_level))) + .Times(AtLeast(2)) + .WillRepeatedly(SaveArg<1>(&last_level)); + RunAgc(500, -20); +} + +TEST_F(AgcTest, ReachesSteadyState) { + int last_level = 128; + EXPECT_CALL(checker_, LevelChanged(_, _)) + .Times(AtLeast(2)) + .WillRepeatedly(SaveArg<1>(&last_level)); + RunAgc(1000, -20); + Mock::VerifyAndClearExpectations(&checker_); + + // If the level changes, it should be in a narrow band around the previous + // adaptation. + EXPECT_CALL(checker_, LevelChanged(_, + AllOf(Gt(last_level * 0.95), Lt(last_level * 1.05)))) + .Times(AtLeast(0)); + RunAgc(1000, -20); +} + +// TODO(ajm): Add this test; requires measuring the signal RMS. +TEST_F(AgcTest, AdaptsToCorrectRMS) { +} + +} // namespace +} // namespace webrtc + |