1/* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include "webrtc/modules/audio_processing/agc/agc.h" 12 13#include "gmock/gmock.h" 14#include "gtest/gtest.h" 15 16#include "webrtc/modules/include/module_common_types.h" 17#include "webrtc/test/testsupport/fileutils.h" 18#include "webrtc/tools/agc/test_utils.h" 19 20using ::testing::_; 21using ::testing::AllOf; 22using ::testing::AtLeast; 23using ::testing::Eq; 24using ::testing::Gt; 25using ::testing::InSequence; 26using ::testing::Lt; 27using ::testing::Mock; 28using ::testing::SaveArg; 29 30namespace webrtc { 31namespace { 32 33// The tested values depend on this assumed gain. 34const int kMaxGain = 80; 35 36MATCHER_P(GtPointee, p, "") { return arg > *p; } 37MATCHER_P(LtPointee, p, "") { return arg < *p; } 38 39class AgcChecker { 40 public: 41 MOCK_METHOD2(LevelChanged, void(int iterations, int level)); 42}; 43 44class AgcTest : public ::testing::Test { 45 protected: 46 AgcTest() 47 : agc_(), 48 checker_(), 49 mic_level_(128) { 50 } 51 52 // A gain of <= -100 will zero out the signal. 53 void RunAgc(int iterations, float gain_db) { 54 FILE* input_file = fopen( 55 test::ResourcePath("voice_engine/audio_long16", "pcm").c_str(), "rb"); 56 ASSERT_TRUE(input_file != NULL); 57 58 AudioFrame frame; 59 frame.sample_rate_hz_ = 16000; 60 frame.num_channels_ = 1; 61 frame.samples_per_channel_ = frame.sample_rate_hz_ / 100; 62 const size_t length = frame.samples_per_channel_ * frame.num_channels_; 63 64 float gain = Db2Linear(gain_db); 65 if (gain_db <= -100) { 66 gain = 0; 67 } 68 69 for (int i = 0; i < iterations; ++i) { 70 ASSERT_EQ(length, fread(frame.data_, sizeof(int16_t), length, 71 input_file)); 72 SimulateMic(kMaxGain, mic_level_, &frame); 73 ApplyGainLinear(gain, &frame); 74 ASSERT_GE(agc_.Process(frame), 0); 75 76 int mic_level = agc_.MicLevel(); 77 if (mic_level != mic_level_) { 78 printf("mic_level=%d\n", mic_level); 79 checker_.LevelChanged(i, mic_level); 80 } 81 mic_level_ = mic_level; 82 } 83 fclose(input_file); 84 } 85 86 Agc agc_; 87 AgcChecker checker_; 88 // Stores mic level between multiple runs of RunAgc in one test. 89 int mic_level_; 90}; 91 92TEST_F(AgcTest, UpwardsChangeIsLimited) { 93 { 94 InSequence seq; 95 EXPECT_CALL(checker_, LevelChanged(Lt(500), Eq(179))).Times(1); 96 EXPECT_CALL(checker_, LevelChanged(_, Gt(179))).Times(AtLeast(1)); 97 } 98 RunAgc(1000, -40); 99} 100 101TEST_F(AgcTest, DownwardsChangeIsLimited) { 102 { 103 InSequence seq; 104 EXPECT_CALL(checker_, LevelChanged(Lt(500), Eq(77))).Times(1); 105 EXPECT_CALL(checker_, LevelChanged(_, Lt(77))).Times(AtLeast(1)); 106 } 107 RunAgc(1000, 40); 108} 109 110TEST_F(AgcTest, MovesUpToMaxAndDownToMin) { 111 int last_level = 128; 112 EXPECT_CALL(checker_, LevelChanged(_, GtPointee(&last_level))) 113 .Times(AtLeast(2)) 114 .WillRepeatedly(SaveArg<1>(&last_level)); 115 RunAgc(1000, -30); 116 EXPECT_EQ(255, last_level); 117 Mock::VerifyAndClearExpectations(&checker_); 118 119 EXPECT_CALL(checker_, LevelChanged(_, LtPointee(&last_level))) 120 .Times(AtLeast(2)) 121 .WillRepeatedly(SaveArg<1>(&last_level)); 122 RunAgc(1000, 50); 123 EXPECT_EQ(1, last_level); 124} 125 126TEST_F(AgcTest, HandlesZeroSignal) { 127 int last_level = 128; 128 // Doesn't respond to a zero signal. 129 EXPECT_CALL(checker_, LevelChanged(_, _)).Times(0); 130 RunAgc(1000, -100); 131 Mock::VerifyAndClearExpectations(&checker_); 132 133 // Reacts as usual afterwards. 134 EXPECT_CALL(checker_, LevelChanged(_, GtPointee(&last_level))) 135 .Times(AtLeast(2)) 136 .WillRepeatedly(SaveArg<1>(&last_level)); 137 RunAgc(500, -20); 138} 139 140TEST_F(AgcTest, ReachesSteadyState) { 141 int last_level = 128; 142 EXPECT_CALL(checker_, LevelChanged(_, _)) 143 .Times(AtLeast(2)) 144 .WillRepeatedly(SaveArg<1>(&last_level)); 145 RunAgc(1000, -20); 146 Mock::VerifyAndClearExpectations(&checker_); 147 148 // If the level changes, it should be in a narrow band around the previous 149 // adaptation. 150 EXPECT_CALL(checker_, LevelChanged(_, 151 AllOf(Gt(last_level * 0.95), Lt(last_level * 1.05)))) 152 .Times(AtLeast(0)); 153 RunAgc(1000, -20); 154} 155 156// TODO(ajm): Add this test; requires measuring the signal RMS. 157TEST_F(AgcTest, AdaptsToCorrectRMS) { 158} 159 160} // namespace 161} // namespace webrtc 162 163