blob: 73ea55d06c70c3c56a3ea604ff7f0fdd5ca38940 [file] [log] [blame]
/*
* Copyright (c) 2013 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 "modules/audio_processing/agc/agc_manager_direct.h"
#include "common_types.h" // NOLINT(build/include)
#include "modules/audio_processing/agc/mock_agc.h"
#include "modules/audio_processing/include/mock_audio_processing.h"
#include "test/gmock.h"
#include "test/gtest.h"
using ::testing::_;
using ::testing::AtLeast;
using ::testing::DoAll;
using ::testing::Return;
using ::testing::SetArgPointee;
namespace webrtc {
namespace {
const int kSampleRateHz = 32000;
const int kNumChannels = 1;
const int kSamplesPerChannel = kSampleRateHz / 100;
const int kInitialVolume = 128;
constexpr int kClippedMin = 165; // Arbitrary, but different from the default.
const float kAboveClippedThreshold = 0.2f;
class TestVolumeCallbacks : public VolumeCallbacks {
public:
TestVolumeCallbacks() : volume_(0) {}
void SetMicVolume(int volume) override { volume_ = volume; }
int GetMicVolume() override { return volume_; }
private:
int volume_;
};
} // namespace
class AgcManagerDirectTest : public ::testing::Test {
protected:
AgcManagerDirectTest()
: agc_(new MockAgc),
manager_(agc_, &gctrl_, &volume_, kInitialVolume, kClippedMin) {
ExpectInitialize();
manager_.Initialize();
}
void FirstProcess() {
EXPECT_CALL(*agc_, Reset()).Times(AtLeast(1));
EXPECT_CALL(*agc_, GetRmsErrorDb(_)).WillOnce(Return(false));
CallProcess(1);
}
void SetVolumeAndProcess(int volume) {
volume_.SetMicVolume(volume);
FirstProcess();
}
void ExpectCheckVolumeAndReset(int volume) {
volume_.SetMicVolume(volume);
EXPECT_CALL(*agc_, Reset());
}
void ExpectInitialize() {
EXPECT_CALL(gctrl_, set_mode(GainControl::kFixedDigital));
EXPECT_CALL(gctrl_, set_target_level_dbfs(2));
EXPECT_CALL(gctrl_, set_compression_gain_db(7));
EXPECT_CALL(gctrl_, enable_limiter(true));
}
void CallProcess(int num_calls) {
for (int i = 0; i < num_calls; ++i) {
EXPECT_CALL(*agc_, Process(_, _, _)).WillOnce(Return());
manager_.Process(nullptr, kSamplesPerChannel, kSampleRateHz);
}
}
void CallPreProc(int num_calls) {
for (int i = 0; i < num_calls; ++i) {
manager_.AnalyzePreProcess(nullptr, kNumChannels, kSamplesPerChannel);
}
}
MockAgc* agc_;
test::MockGainControl gctrl_;
TestVolumeCallbacks volume_;
AgcManagerDirect manager_;
};
TEST_F(AgcManagerDirectTest, StartupMinVolumeConfigurationIsRespected) {
FirstProcess();
EXPECT_EQ(kInitialVolume, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, MicVolumeResponseToRmsError) {
FirstProcess();
// Compressor default; no residual error.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(5), Return(true)));
CallProcess(1);
// Inside the compressor's window; no change of volume.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(10), Return(true)));
CallProcess(1);
// Above the compressor's window; volume should be increased.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(11), Return(true)));
CallProcess(1);
EXPECT_EQ(130, volume_.GetMicVolume());
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(20), Return(true)));
CallProcess(1);
EXPECT_EQ(168, volume_.GetMicVolume());
// Inside the compressor's window; no change of volume.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(5), Return(true)));
CallProcess(1);
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(0), Return(true)));
CallProcess(1);
// Below the compressor's window; volume should be decreased.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(-1), Return(true)));
CallProcess(1);
EXPECT_EQ(167, volume_.GetMicVolume());
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(-1), Return(true)));
CallProcess(1);
EXPECT_EQ(163, volume_.GetMicVolume());
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(-9), Return(true)));
CallProcess(1);
EXPECT_EQ(129, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, MicVolumeIsLimited) {
FirstProcess();
// Maximum upwards change is limited.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(30), Return(true)));
CallProcess(1);
EXPECT_EQ(183, volume_.GetMicVolume());
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(30), Return(true)));
CallProcess(1);
EXPECT_EQ(243, volume_.GetMicVolume());
// Won't go higher than the maximum.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(30), Return(true)));
CallProcess(1);
EXPECT_EQ(255, volume_.GetMicVolume());
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(-1), Return(true)));
CallProcess(1);
EXPECT_EQ(254, volume_.GetMicVolume());
// Maximum downwards change is limited.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(-40), Return(true)));
CallProcess(1);
EXPECT_EQ(194, volume_.GetMicVolume());
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(-40), Return(true)));
CallProcess(1);
EXPECT_EQ(137, volume_.GetMicVolume());
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(-40), Return(true)));
CallProcess(1);
EXPECT_EQ(88, volume_.GetMicVolume());
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(-40), Return(true)));
CallProcess(1);
EXPECT_EQ(54, volume_.GetMicVolume());
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(-40), Return(true)));
CallProcess(1);
EXPECT_EQ(33, volume_.GetMicVolume());
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(-40), Return(true)));
CallProcess(1);
EXPECT_EQ(18, volume_.GetMicVolume());
// Won't go lower than the minimum.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(-40), Return(true)));
CallProcess(1);
EXPECT_EQ(12, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, CompressorStepsTowardsTarget) {
FirstProcess();
// Compressor default; no call to set_compression_gain_db.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(5), Return(true)))
.WillRepeatedly(Return(false));
EXPECT_CALL(gctrl_, set_compression_gain_db(_)).Times(0);
CallProcess(20);
// Moves slowly upwards.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(9), Return(true)))
.WillRepeatedly(Return(false));
EXPECT_CALL(gctrl_, set_compression_gain_db(_)).Times(0);
CallProcess(19);
EXPECT_CALL(gctrl_, set_compression_gain_db(8)).WillOnce(Return(0));
CallProcess(1);
EXPECT_CALL(gctrl_, set_compression_gain_db(_)).Times(0);
CallProcess(19);
EXPECT_CALL(gctrl_, set_compression_gain_db(9)).WillOnce(Return(0));
CallProcess(1);
EXPECT_CALL(gctrl_, set_compression_gain_db(_)).Times(0);
CallProcess(20);
// Moves slowly downward, then reverses before reaching the original target.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(5), Return(true)))
.WillRepeatedly(Return(false));
EXPECT_CALL(gctrl_, set_compression_gain_db(_)).Times(0);
CallProcess(19);
EXPECT_CALL(gctrl_, set_compression_gain_db(8)).WillOnce(Return(0));
CallProcess(1);
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(9), Return(true)))
.WillRepeatedly(Return(false));
EXPECT_CALL(gctrl_, set_compression_gain_db(_)).Times(0);
CallProcess(19);
EXPECT_CALL(gctrl_, set_compression_gain_db(9)).WillOnce(Return(0));
CallProcess(1);
EXPECT_CALL(gctrl_, set_compression_gain_db(_)).Times(0);
CallProcess(20);
}
TEST_F(AgcManagerDirectTest, CompressorErrorIsDeemphasized) {
FirstProcess();
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(10), Return(true)))
.WillRepeatedly(Return(false));
CallProcess(19);
EXPECT_CALL(gctrl_, set_compression_gain_db(8)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(9)).WillOnce(Return(0));
CallProcess(1);
EXPECT_CALL(gctrl_, set_compression_gain_db(_)).Times(0);
CallProcess(20);
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(0), Return(true)))
.WillRepeatedly(Return(false));
CallProcess(19);
EXPECT_CALL(gctrl_, set_compression_gain_db(8)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(7)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(6)).WillOnce(Return(0));
CallProcess(1);
EXPECT_CALL(gctrl_, set_compression_gain_db(_)).Times(0);
CallProcess(20);
}
TEST_F(AgcManagerDirectTest, CompressorReachesMaximum) {
FirstProcess();
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(10), Return(true)))
.WillOnce(DoAll(SetArgPointee<0>(10), Return(true)))
.WillOnce(DoAll(SetArgPointee<0>(10), Return(true)))
.WillOnce(DoAll(SetArgPointee<0>(10), Return(true)))
.WillRepeatedly(Return(false));
CallProcess(19);
EXPECT_CALL(gctrl_, set_compression_gain_db(8)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(9)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(10)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(11)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(12)).WillOnce(Return(0));
CallProcess(1);
}
TEST_F(AgcManagerDirectTest, CompressorReachesMinimum) {
FirstProcess();
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(0), Return(true)))
.WillOnce(DoAll(SetArgPointee<0>(0), Return(true)))
.WillOnce(DoAll(SetArgPointee<0>(0), Return(true)))
.WillOnce(DoAll(SetArgPointee<0>(0), Return(true)))
.WillRepeatedly(Return(false));
CallProcess(19);
EXPECT_CALL(gctrl_, set_compression_gain_db(6)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(5)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(4)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(3)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(2)).WillOnce(Return(0));
CallProcess(1);
}
TEST_F(AgcManagerDirectTest, NoActionWhileMuted) {
manager_.SetCaptureMuted(true);
manager_.Process(nullptr, kSamplesPerChannel, kSampleRateHz);
}
TEST_F(AgcManagerDirectTest, UnmutingChecksVolumeWithoutRaising) {
FirstProcess();
manager_.SetCaptureMuted(true);
manager_.SetCaptureMuted(false);
ExpectCheckVolumeAndReset(127);
// SetMicVolume should not be called.
EXPECT_CALL(*agc_, GetRmsErrorDb(_)).WillOnce(Return(false));
CallProcess(1);
EXPECT_EQ(127, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, UnmutingRaisesTooLowVolume) {
FirstProcess();
manager_.SetCaptureMuted(true);
manager_.SetCaptureMuted(false);
ExpectCheckVolumeAndReset(11);
EXPECT_CALL(*agc_, GetRmsErrorDb(_)).WillOnce(Return(false));
CallProcess(1);
EXPECT_EQ(12, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, ManualLevelChangeResultsInNoSetMicCall) {
FirstProcess();
// Change outside of compressor's range, which would normally trigger a call
// to SetMicVolume.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(11), Return(true)));
// When the analog volume changes, the gain controller is reset.
EXPECT_CALL(*agc_, Reset()).Times(AtLeast(1));
// GetMicVolume returns a value outside of the quantization slack, indicating
// a manual volume change.
ASSERT_NE(volume_.GetMicVolume(), 154);
volume_.SetMicVolume(154);
CallProcess(1);
EXPECT_EQ(154, volume_.GetMicVolume());
// Do the same thing, except downwards now.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(-1), Return(true)));
volume_.SetMicVolume(100);
EXPECT_CALL(*agc_, Reset()).Times(AtLeast(1));
CallProcess(1);
EXPECT_EQ(100, volume_.GetMicVolume());
// And finally verify the AGC continues working without a manual change.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(-1), Return(true)));
CallProcess(1);
EXPECT_EQ(99, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, RecoveryAfterManualLevelChangeFromMax) {
FirstProcess();
// Force the mic up to max volume. Takes a few steps due to the residual
// gain limitation.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(30), Return(true)));
CallProcess(1);
EXPECT_EQ(183, volume_.GetMicVolume());
CallProcess(1);
EXPECT_EQ(243, volume_.GetMicVolume());
CallProcess(1);
EXPECT_EQ(255, volume_.GetMicVolume());
// Manual change does not result in SetMicVolume call.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(-1), Return(true)));
volume_.SetMicVolume(50);
EXPECT_CALL(*agc_, Reset()).Times(AtLeast(1));
CallProcess(1);
EXPECT_EQ(50, volume_.GetMicVolume());
// Continues working as usual afterwards.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(20), Return(true)));
CallProcess(1);
EXPECT_EQ(69, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, RecoveryAfterManualLevelChangeBelowMin) {
FirstProcess();
// Manual change below min.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(-1), Return(true)));
// Don't set to zero, which will cause AGC to take no action.
volume_.SetMicVolume(1);
EXPECT_CALL(*agc_, Reset()).Times(AtLeast(1));
CallProcess(1);
EXPECT_EQ(1, volume_.GetMicVolume());
// Continues working as usual afterwards.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(11), Return(true)));
CallProcess(1);
EXPECT_EQ(2, volume_.GetMicVolume());
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(30), Return(true)));
CallProcess(1);
EXPECT_EQ(11, volume_.GetMicVolume());
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(20), Return(true)));
CallProcess(1);
EXPECT_EQ(18, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, NoClippingHasNoImpact) {
FirstProcess();
EXPECT_CALL(*agc_, AnalyzePreproc(_, _)).WillRepeatedly(Return(0));
CallPreProc(100);
EXPECT_EQ(128, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, ClippingUnderThresholdHasNoImpact) {
FirstProcess();
EXPECT_CALL(*agc_, AnalyzePreproc(_, _)).WillOnce(Return(0.099));
CallPreProc(1);
EXPECT_EQ(128, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, ClippingLowersVolume) {
SetVolumeAndProcess(255);
EXPECT_CALL(*agc_, AnalyzePreproc(_, _)).WillOnce(Return(0.101));
EXPECT_CALL(*agc_, Reset()).Times(AtLeast(1));
CallPreProc(1);
EXPECT_EQ(240, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, WaitingPeriodBetweenClippingChecks) {
SetVolumeAndProcess(255);
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillOnce(Return(kAboveClippedThreshold));
EXPECT_CALL(*agc_, Reset()).Times(AtLeast(1));
CallPreProc(1);
EXPECT_EQ(240, volume_.GetMicVolume());
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillRepeatedly(Return(kAboveClippedThreshold));
EXPECT_CALL(*agc_, Reset()).Times(0);
CallPreProc(300);
EXPECT_EQ(240, volume_.GetMicVolume());
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillOnce(Return(kAboveClippedThreshold));
EXPECT_CALL(*agc_, Reset()).Times(AtLeast(1));
CallPreProc(1);
EXPECT_EQ(225, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, ClippingLoweringIsLimited) {
SetVolumeAndProcess(180);
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillOnce(Return(kAboveClippedThreshold));
EXPECT_CALL(*agc_, Reset()).Times(AtLeast(1));
CallPreProc(1);
EXPECT_EQ(kClippedMin, volume_.GetMicVolume());
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillRepeatedly(Return(kAboveClippedThreshold));
EXPECT_CALL(*agc_, Reset()).Times(0);
CallPreProc(1000);
EXPECT_EQ(kClippedMin, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, ClippingMaxIsRespectedWhenEqualToLevel) {
SetVolumeAndProcess(255);
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillOnce(Return(kAboveClippedThreshold));
EXPECT_CALL(*agc_, Reset()).Times(AtLeast(1));
CallPreProc(1);
EXPECT_EQ(240, volume_.GetMicVolume());
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(30), Return(true)));
CallProcess(10);
EXPECT_EQ(240, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, ClippingMaxIsRespectedWhenHigherThanLevel) {
SetVolumeAndProcess(200);
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillOnce(Return(kAboveClippedThreshold));
EXPECT_CALL(*agc_, Reset()).Times(AtLeast(1));
CallPreProc(1);
EXPECT_EQ(185, volume_.GetMicVolume());
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(40), Return(true)));
CallProcess(1);
EXPECT_EQ(240, volume_.GetMicVolume());
CallProcess(10);
EXPECT_EQ(240, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, MaxCompressionIsIncreasedAfterClipping) {
SetVolumeAndProcess(210);
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillOnce(Return(kAboveClippedThreshold));
EXPECT_CALL(*agc_, Reset()).Times(AtLeast(1));
CallPreProc(1);
EXPECT_EQ(195, volume_.GetMicVolume());
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(11), Return(true)))
.WillOnce(DoAll(SetArgPointee<0>(11), Return(true)))
.WillOnce(DoAll(SetArgPointee<0>(11), Return(true)))
.WillOnce(DoAll(SetArgPointee<0>(11), Return(true)))
.WillOnce(DoAll(SetArgPointee<0>(11), Return(true)))
.WillRepeatedly(Return(false));
CallProcess(19);
EXPECT_CALL(gctrl_, set_compression_gain_db(8)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(9)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(10)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(11)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(12)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(13)).WillOnce(Return(0));
CallProcess(1);
// Continue clipping until we hit the maximum surplus compression.
CallPreProc(300);
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillOnce(Return(kAboveClippedThreshold));
EXPECT_CALL(*agc_, Reset()).Times(AtLeast(1));
CallPreProc(1);
EXPECT_EQ(180, volume_.GetMicVolume());
CallPreProc(300);
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillOnce(Return(kAboveClippedThreshold));
EXPECT_CALL(*agc_, Reset()).Times(AtLeast(1));
CallPreProc(1);
EXPECT_EQ(kClippedMin, volume_.GetMicVolume());
// Current level is now at the minimum, but the maximum allowed level still
// has more to decrease.
CallPreProc(300);
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillOnce(Return(kAboveClippedThreshold));
CallPreProc(1);
CallPreProc(300);
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillOnce(Return(kAboveClippedThreshold));
CallPreProc(1);
CallPreProc(300);
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillOnce(Return(kAboveClippedThreshold));
CallPreProc(1);
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(16), Return(true)))
.WillOnce(DoAll(SetArgPointee<0>(16), Return(true)))
.WillOnce(DoAll(SetArgPointee<0>(16), Return(true)))
.WillOnce(DoAll(SetArgPointee<0>(16), Return(true)))
.WillRepeatedly(Return(false));
CallProcess(19);
EXPECT_CALL(gctrl_, set_compression_gain_db(14)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(15)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(16)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(17)).WillOnce(Return(0));
CallProcess(20);
EXPECT_CALL(gctrl_, set_compression_gain_db(18)).WillOnce(Return(0));
CallProcess(1);
}
TEST_F(AgcManagerDirectTest, UserCanRaiseVolumeAfterClipping) {
SetVolumeAndProcess(225);
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillOnce(Return(kAboveClippedThreshold));
EXPECT_CALL(*agc_, Reset()).Times(AtLeast(1));
CallPreProc(1);
EXPECT_EQ(210, volume_.GetMicVolume());
// High enough error to trigger a volume check.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(14), Return(true)));
// User changed the volume.
volume_.SetMicVolume(250);
EXPECT_CALL(*agc_, Reset()).Times(AtLeast(1));
CallProcess(1);
EXPECT_EQ(250, volume_.GetMicVolume());
// Move down...
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(-10), Return(true)));
CallProcess(1);
EXPECT_EQ(210, volume_.GetMicVolume());
// And back up to the new max established by the user.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(40), Return(true)));
CallProcess(1);
EXPECT_EQ(250, volume_.GetMicVolume());
// Will not move above new maximum.
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillOnce(DoAll(SetArgPointee<0>(30), Return(true)));
CallProcess(1);
EXPECT_EQ(250, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, ClippingDoesNotPullLowVolumeBackUp) {
SetVolumeAndProcess(80);
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillOnce(Return(kAboveClippedThreshold));
EXPECT_CALL(*agc_, Reset()).Times(0);
int initial_volume = volume_.GetMicVolume();
CallPreProc(1);
EXPECT_EQ(initial_volume, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, TakesNoActionOnZeroMicVolume) {
FirstProcess();
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(30), Return(true)));
volume_.SetMicVolume(0);
CallProcess(10);
EXPECT_EQ(0, volume_.GetMicVolume());
}
TEST(AgcManagerDirectStandaloneTest, DisableDigitalDisablesDigital) {
auto agc = std::unique_ptr<Agc>(new testing::NiceMock<MockAgc>());
test::MockGainControl gctrl;
TestVolumeCallbacks volume;
AgcManagerDirect manager(agc.release(), &gctrl, &volume, kInitialVolume,
kClippedMin,
/* use agc2 level estimation */ false,
/* disable digital adaptive */ true);
EXPECT_CALL(gctrl, set_mode(GainControl::kFixedDigital));
EXPECT_CALL(gctrl, set_target_level_dbfs(0));
EXPECT_CALL(gctrl, set_compression_gain_db(0));
EXPECT_CALL(gctrl, enable_limiter(false));
manager.Initialize();
}
} // namespace webrtc