Home | History | Annotate | Download | only in agc
      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 
     20 using ::testing::_;
     21 using ::testing::AllOf;
     22 using ::testing::AtLeast;
     23 using ::testing::Eq;
     24 using ::testing::Gt;
     25 using ::testing::InSequence;
     26 using ::testing::Lt;
     27 using ::testing::Mock;
     28 using ::testing::SaveArg;
     29 
     30 namespace webrtc {
     31 namespace {
     32 
     33 // The tested values depend on this assumed gain.
     34 const int kMaxGain = 80;
     35 
     36 MATCHER_P(GtPointee, p, "") { return arg > *p; }
     37 MATCHER_P(LtPointee, p, "") { return arg < *p; }
     38 
     39 class AgcChecker {
     40  public:
     41   MOCK_METHOD2(LevelChanged, void(int iterations, int level));
     42 };
     43 
     44 class 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 
     92 TEST_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 
    101 TEST_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 
    110 TEST_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 
    126 TEST_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 
    140 TEST_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.
    157 TEST_F(AgcTest, AdaptsToCorrectRMS) {
    158 }
    159 
    160 }  // namespace
    161 }  // namespace webrtc
    162 
    163