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