aboutsummaryrefslogtreecommitdiff
path: root/webrtc/modules/audio_processing/agc/agc_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'webrtc/modules/audio_processing/agc/agc_unittest.cc')
-rw-r--r--webrtc/modules/audio_processing/agc/agc_unittest.cc162
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
+