/* * 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 "webrtc/tools/agc/agc_manager.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/common_types.h" #include "webrtc/modules/audio_processing/agc/mock_agc.h" #include "webrtc/modules/audio_processing/include/mock_audio_processing.h" #include "webrtc/system_wrappers/interface/trace.h" #include "webrtc/voice_engine/mock/fake_voe_external_media.h" #include "webrtc/voice_engine/mock/mock_voe_volume_control.h" #include "webrtc/test/testsupport/trace_to_stderr.h" using ::testing::_; using ::testing::DoAll; using ::testing::Eq; using ::testing::Mock; using ::testing::Return; using ::testing::SetArgPointee; using ::testing::SetArgReferee; namespace webrtc { namespace { const int kSampleRateHz = 32000; const int kNumChannels = 1; const int kSamplesPerChannel = kSampleRateHz / 100; const float kAboveClippedThreshold = 0.2f; } // namespace class AgcManagerUnitTest : public ::testing::Test { protected: AgcManagerUnitTest() : media_(), volume_(), agc_(new MockAgc), audioproc_(new MockAudioProcessing), gctrl_(audioproc_->gain_control()), manager_(&media_, &volume_, agc_, audioproc_) { EXPECT_CALL(*gctrl_, Enable(true)); ExpectInitialize(); manager_.Enable(true); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(Return(false)); // TODO(bjornv): Find a better solution that adds an initial volume here // instead of applying SetVolumeAndProcess(128u) in each test, but at the // same time can test a too low initial value. } void SetInitialVolume(unsigned int volume) { ExpectInitialize(); manager_.CaptureDeviceChanged(); ExpectCheckVolumeAndReset(volume); EXPECT_CALL(*agc_, GetRmsErrorDb(_)).WillOnce(Return(false)); PostProcCallback(1); } void SetVolumeAndProcess(unsigned int volume) { // Volume is checked on first process call. ExpectCheckVolumeAndReset(volume); PostProcCallback(1); } void ExpectCheckVolumeAndReset(unsigned int volume) { EXPECT_CALL(volume_, GetMicVolume(_)) .WillOnce(DoAll(SetArgReferee<0>(volume), Return(0))); EXPECT_CALL(*agc_, Reset()); } void ExpectVolumeChange(unsigned int current_volume, unsigned int new_volume) { EXPECT_CALL(volume_, GetMicVolume(_)) .WillOnce(DoAll(SetArgReferee<0>(current_volume), Return(0))); EXPECT_CALL(volume_, SetMicVolume(Eq(new_volume))).WillOnce(Return(0)); } 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 PreProcCallback(int num_calls) { for (int i = 0; i < num_calls; ++i) { media_.CallProcess(kRecordingPreprocessing, NULL, kSamplesPerChannel, kSampleRateHz, kNumChannels); } } void PostProcCallback(int num_calls) { for (int i = 0; i < num_calls; ++i) { EXPECT_CALL(*agc_, Process(_, _, _)).WillOnce(Return(0)); EXPECT_CALL(*audioproc_, ProcessStream(_)).WillOnce(Return(0)); media_.CallProcess(kRecordingAllChannelsMixed, NULL, kSamplesPerChannel, kSampleRateHz, kNumChannels); } } ~AgcManagerUnitTest() { EXPECT_CALL(volume_, Release()).WillOnce(Return(0)); } FakeVoEExternalMedia media_; MockVoEVolumeControl volume_; MockAgc* agc_; MockAudioProcessing* audioproc_; MockGainControl* gctrl_; AgcManager manager_; test::TraceToStderr trace_to_stderr; }; TEST_F(AgcManagerUnitTest, MicVolumeResponseToRmsError) { SetVolumeAndProcess(128u); // Compressor default; no residual error. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(5), Return(true))); PostProcCallback(1); // Inside the compressor's window; no change of volume. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(10), Return(true))); PostProcCallback(1); // Above the compressor's window; volume should be increased. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(11), Return(true))); ExpectVolumeChange(128u, 130u); PostProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(20), Return(true))); ExpectVolumeChange(130u, 168u); PostProcCallback(1); // Inside the compressor's window; no change of volume. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(5), Return(true))); PostProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(0), Return(true))); PostProcCallback(1); // Below the compressor's window; volume should be decreased. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(-1), Return(true))); ExpectVolumeChange(168u, 167u); PostProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(-1), Return(true))); ExpectVolumeChange(167u, 163u); PostProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(-9), Return(true))); ExpectVolumeChange(163u, 129u); PostProcCallback(1); } TEST_F(AgcManagerUnitTest, MicVolumeIsLimited) { SetVolumeAndProcess(128u); // Maximum upwards change is limited. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(30), Return(true))); ExpectVolumeChange(128u, 183u); PostProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(30), Return(true))); ExpectVolumeChange(183u, 243u); PostProcCallback(1); // Won't go higher than the maximum. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(30), Return(true))); ExpectVolumeChange(243u, 255u); PostProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(-1), Return(true))); ExpectVolumeChange(255u, 254u); PostProcCallback(1); // Maximum downwards change is limited. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(-40), Return(true))); ExpectVolumeChange(254u, 194u); PostProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(-40), Return(true))); ExpectVolumeChange(194u, 137u); PostProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(-40), Return(true))); ExpectVolumeChange(137u, 88u); PostProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(-40), Return(true))); ExpectVolumeChange(88u, 54u); PostProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(-40), Return(true))); ExpectVolumeChange(54u, 33u); PostProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(-40), Return(true))); ExpectVolumeChange(33u, 18u); PostProcCallback(1); // Won't go lower than the minimum. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(-40), Return(true))); ExpectVolumeChange(18u, 12u); PostProcCallback(1); } TEST_F(AgcManagerUnitTest, CompressorStepsTowardsTarget) { SetVolumeAndProcess(128u); // 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); PostProcCallback(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); PostProcCallback(19); EXPECT_CALL(*gctrl_, set_compression_gain_db(8)).WillOnce(Return(0)); PostProcCallback(1); EXPECT_CALL(*gctrl_, set_compression_gain_db(_)).Times(0); PostProcCallback(19); EXPECT_CALL(*gctrl_, set_compression_gain_db(9)).WillOnce(Return(0)); PostProcCallback(1); EXPECT_CALL(*gctrl_, set_compression_gain_db(_)).Times(0); PostProcCallback(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); PostProcCallback(19); EXPECT_CALL(*gctrl_, set_compression_gain_db(8)).WillOnce(Return(0)); PostProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(9), Return(true))) .WillRepeatedly(Return(false)); EXPECT_CALL(*gctrl_, set_compression_gain_db(_)).Times(0); PostProcCallback(19); EXPECT_CALL(*gctrl_, set_compression_gain_db(9)).WillOnce(Return(0)); PostProcCallback(1); EXPECT_CALL(*gctrl_, set_compression_gain_db(_)).Times(0); PostProcCallback(20); } TEST_F(AgcManagerUnitTest, CompressorErrorIsDeemphasized) { SetVolumeAndProcess(128u); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(10), Return(true))) .WillRepeatedly(Return(false)); PostProcCallback(19); EXPECT_CALL(*gctrl_, set_compression_gain_db(8)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(9)).WillOnce(Return(0)); PostProcCallback(1); EXPECT_CALL(*gctrl_, set_compression_gain_db(_)).Times(0); PostProcCallback(20); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(0), Return(true))) .WillRepeatedly(Return(false)); PostProcCallback(19); EXPECT_CALL(*gctrl_, set_compression_gain_db(8)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(7)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(6)).WillOnce(Return(0)); PostProcCallback(1); EXPECT_CALL(*gctrl_, set_compression_gain_db(_)).Times(0); PostProcCallback(20); } TEST_F(AgcManagerUnitTest, CompressorReachesMaximum) { SetVolumeAndProcess(128u); 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)); PostProcCallback(19); EXPECT_CALL(*gctrl_, set_compression_gain_db(8)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(9)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(10)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(11)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(12)).WillOnce(Return(0)); PostProcCallback(1); } TEST_F(AgcManagerUnitTest, CompressorReachesMinimum) { SetVolumeAndProcess(128u); 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)); PostProcCallback(19); EXPECT_CALL(*gctrl_, set_compression_gain_db(6)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(5)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(4)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(3)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(2)).WillOnce(Return(0)); PostProcCallback(1); } TEST_F(AgcManagerUnitTest, NoActionWhileMuted) { SetVolumeAndProcess(128u); manager_.SetCaptureMuted(true); media_.CallProcess(kRecordingAllChannelsMixed, NULL, kSamplesPerChannel, kSampleRateHz, kNumChannels); } TEST_F(AgcManagerUnitTest, UnmutingChecksVolumeWithoutRaising) { SetVolumeAndProcess(128u); manager_.SetCaptureMuted(true); manager_.SetCaptureMuted(false); ExpectCheckVolumeAndReset(127u); // SetMicVolume should not be called. EXPECT_CALL(volume_, SetMicVolume(_)).Times(0); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(Return(false)); PostProcCallback(1); } TEST_F(AgcManagerUnitTest, UnmutingRaisesTooLowVolume) { SetVolumeAndProcess(128u); manager_.SetCaptureMuted(true); manager_.SetCaptureMuted(false); ExpectCheckVolumeAndReset(11u); EXPECT_CALL(volume_, SetMicVolume(Eq(12u))).WillOnce(Return(0)); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(Return(false)); PostProcCallback(1); } TEST_F(AgcManagerUnitTest, ChangingDevicesChecksVolume) { SetVolumeAndProcess(128u); ExpectInitialize(); manager_.CaptureDeviceChanged(); ExpectCheckVolumeAndReset(128u); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(Return(false)); PostProcCallback(1); } TEST_F(AgcManagerUnitTest, LowInitialVolumeIsRaised) { ExpectCheckVolumeAndReset(11u); #if defined(WEBRTC_CHROMIUM_BUILD) // Should set MicVolume to kMinInitMicLevel = 85 if built with Chromium. EXPECT_CALL(volume_, SetMicVolume(Eq(85u))).WillOnce(Return(0)); #else // Otherwise it will raise to the kMinMicLevel = 12. EXPECT_CALL(volume_, SetMicVolume(Eq(12u))).WillOnce(Return(0)); #endif PostProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(Return(false)); PostProcCallback(1); } TEST_F(AgcManagerUnitTest, ManualLevelChangeResultsInNoSetMicCall) { SetVolumeAndProcess(128u); // 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))); // GetMicVolume returns a value outside of the quantization slack, indicating // a manual volume change. EXPECT_CALL(volume_, GetMicVolume(_)) .WillOnce(DoAll(SetArgReferee<0>(154u), Return(0))); // SetMicVolume should not be called. EXPECT_CALL(volume_, SetMicVolume(_)).Times(0); EXPECT_CALL(*agc_, Reset()).Times(1); PostProcCallback(1); // Do the same thing, except downwards now. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(-1), Return(true))); EXPECT_CALL(volume_, GetMicVolume(_)) .WillOnce(DoAll(SetArgReferee<0>(100u), Return(0))); EXPECT_CALL(volume_, SetMicVolume(_)).Times(0); EXPECT_CALL(*agc_, Reset()).Times(1); PostProcCallback(1); // And finally verify the AGC continues working without a manual change. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(-1), Return(true))); ExpectVolumeChange(100u, 99u); PostProcCallback(1); } TEST_F(AgcManagerUnitTest, RecoveryAfterManualLevelChangeFromMax) { SetVolumeAndProcess(128u); // 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))); ExpectVolumeChange(128u, 183u); PostProcCallback(1); ExpectVolumeChange(183u, 243u); PostProcCallback(1); ExpectVolumeChange(243u, 255u); PostProcCallback(1); // Manual change does not result in SetMicVolume call. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(-1), Return(true))); EXPECT_CALL(volume_, GetMicVolume(_)) .WillOnce(DoAll(SetArgReferee<0>(50u), Return(0))); EXPECT_CALL(volume_, SetMicVolume(_)).Times(0); EXPECT_CALL(*agc_, Reset()).Times(1); PostProcCallback(1); // Continues working as usual afterwards. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(20), Return(true))); ExpectVolumeChange(50u, 69u); PostProcCallback(1); } TEST_F(AgcManagerUnitTest, RecoveryAfterManualLevelChangeBelowMin) { SetVolumeAndProcess(128u); // 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. EXPECT_CALL(volume_, GetMicVolume(_)) .WillOnce(DoAll(SetArgReferee<0>(1u), Return(0))); EXPECT_CALL(volume_, SetMicVolume(_)).Times(0); EXPECT_CALL(*agc_, Reset()).Times(1); PostProcCallback(1); // Continues working as usual afterwards. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(11), Return(true))); ExpectVolumeChange(1u, 2u); PostProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(30), Return(true))); ExpectVolumeChange(2u, 11u); PostProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(20), Return(true))); ExpectVolumeChange(11u, 18u); PostProcCallback(1); } TEST_F(AgcManagerUnitTest, NoClippingHasNoImpact) { SetVolumeAndProcess(128u); EXPECT_CALL(volume_, GetMicVolume(_)).Times(0); EXPECT_CALL(volume_, SetMicVolume(_)).Times(0); EXPECT_CALL(*agc_, Reset()).Times(0); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)).WillRepeatedly(Return(0)); PreProcCallback(100); } TEST_F(AgcManagerUnitTest, ClippingUnderThresholdHasNoImpact) { SetVolumeAndProcess(128u); EXPECT_CALL(volume_, GetMicVolume(_)).Times(0); EXPECT_CALL(volume_, SetMicVolume(_)).Times(0); EXPECT_CALL(*agc_, Reset()).Times(0); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)).WillOnce(Return(0.099)); PreProcCallback(1); } TEST_F(AgcManagerUnitTest, ClippingLowersVolume) { SetVolumeAndProcess(128u); SetInitialVolume(255u); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)).WillOnce(Return(0.101)); EXPECT_CALL(*agc_, Reset()).Times(1); ExpectVolumeChange(255u, 240u); PreProcCallback(1); } TEST_F(AgcManagerUnitTest, WaitingPeriodBetweenClippingChecks) { SetVolumeAndProcess(128u); SetInitialVolume(255u); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)) .WillOnce(Return(kAboveClippedThreshold)); EXPECT_CALL(*agc_, Reset()).Times(1); ExpectVolumeChange(255u, 240u); PreProcCallback(1); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)) .WillRepeatedly(Return(kAboveClippedThreshold)); EXPECT_CALL(volume_, GetMicVolume(_)).Times(0); EXPECT_CALL(volume_, SetMicVolume(_)).Times(0); EXPECT_CALL(*agc_, Reset()).Times(0); PreProcCallback(300); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)) .WillOnce(Return(kAboveClippedThreshold)); EXPECT_CALL(*agc_, Reset()).Times(1); ExpectVolumeChange(240u, 225u); PreProcCallback(1); } TEST_F(AgcManagerUnitTest, ClippingLoweringIsLimited) { SetVolumeAndProcess(128u); SetInitialVolume(180u); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)) .WillOnce(Return(kAboveClippedThreshold)); EXPECT_CALL(*agc_, Reset()).Times(1); ExpectVolumeChange(180u, 170u); PreProcCallback(1); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)) .WillRepeatedly(Return(kAboveClippedThreshold)); EXPECT_CALL(volume_, GetMicVolume(_)).Times(0); EXPECT_CALL(volume_, SetMicVolume(_)).Times(0); EXPECT_CALL(*agc_, Reset()).Times(0); PreProcCallback(1000); } TEST_F(AgcManagerUnitTest, ClippingMaxIsRespectedWhenEqualToLevel) { SetVolumeAndProcess(128u); SetInitialVolume(255u); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)) .WillOnce(Return(kAboveClippedThreshold)); EXPECT_CALL(*agc_, Reset()).Times(1); ExpectVolumeChange(255u, 240u); PreProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillRepeatedly(DoAll(SetArgPointee<0>(30), Return(true))); EXPECT_CALL(volume_, GetMicVolume(_)) .WillRepeatedly(DoAll(SetArgReferee<0>(240u), Return(0))); EXPECT_CALL(volume_, SetMicVolume(_)).Times(0); PostProcCallback(10); } TEST_F(AgcManagerUnitTest, ClippingMaxIsRespectedWhenHigherThanLevel) { SetVolumeAndProcess(128u); SetInitialVolume(200u); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)) .WillOnce(Return(kAboveClippedThreshold)); EXPECT_CALL(*agc_, Reset()).Times(1); ExpectVolumeChange(200u, 185u); PreProcCallback(1); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillRepeatedly(DoAll(SetArgPointee<0>(40), Return(true))); ExpectVolumeChange(185u, 240u); PostProcCallback(1); EXPECT_CALL(volume_, GetMicVolume(_)) .WillRepeatedly(DoAll(SetArgReferee<0>(240u), Return(0))); EXPECT_CALL(volume_, SetMicVolume(_)).Times(0); PostProcCallback(10); } TEST_F(AgcManagerUnitTest, MaxCompressionIsIncreasedAfterClipping) { SetVolumeAndProcess(128u); SetInitialVolume(210u); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)) .WillOnce(Return(kAboveClippedThreshold)); EXPECT_CALL(*agc_, Reset()).Times(1); ExpectVolumeChange(210u, 195u); PreProcCallback(1); 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)); PostProcCallback(19); EXPECT_CALL(*gctrl_, set_compression_gain_db(8)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(9)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(10)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(11)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(12)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(13)).WillOnce(Return(0)); PostProcCallback(1); // Continue clipping until we hit the maximum surplus compression. PreProcCallback(300); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)) .WillOnce(Return(kAboveClippedThreshold)); EXPECT_CALL(*agc_, Reset()).Times(1); ExpectVolumeChange(195u, 180u); PreProcCallback(1); PreProcCallback(300); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)) .WillOnce(Return(kAboveClippedThreshold)); EXPECT_CALL(*agc_, Reset()).Times(1); ExpectVolumeChange(180u, 170u); PreProcCallback(1); // Current level is now at the minimum, but the maximum allowed level still // has more to decrease. PreProcCallback(300); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)) .WillOnce(Return(kAboveClippedThreshold)); PreProcCallback(1); PreProcCallback(300); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)) .WillOnce(Return(kAboveClippedThreshold)); PreProcCallback(1); PreProcCallback(300); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)) .WillOnce(Return(kAboveClippedThreshold)); PreProcCallback(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)); PostProcCallback(19); EXPECT_CALL(*gctrl_, set_compression_gain_db(14)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(15)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(16)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(17)).WillOnce(Return(0)); PostProcCallback(20); EXPECT_CALL(*gctrl_, set_compression_gain_db(18)).WillOnce(Return(0)); PostProcCallback(1); } TEST_F(AgcManagerUnitTest, UserCanRaiseVolumeAfterClipping) { SetVolumeAndProcess(128u); SetInitialVolume(225u); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)) .WillOnce(Return(kAboveClippedThreshold)); EXPECT_CALL(*agc_, Reset()).Times(1); ExpectVolumeChange(225u, 210u); PreProcCallback(1); // High enough error to trigger a volume check. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(14), Return(true))); // User changed the volume. EXPECT_CALL(volume_, GetMicVolume(_)) .WillOnce(DoAll(SetArgReferee<0>(250u), Return(0))); EXPECT_CALL(volume_, SetMicVolume(_)).Times(0); EXPECT_CALL(*agc_, Reset()).Times(1); PostProcCallback(1); // Move down... EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(-10), Return(true))); ExpectVolumeChange(250u, 210u); PostProcCallback(1); // And back up to the new max established by the user. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(40), Return(true))); ExpectVolumeChange(210u, 250u); PostProcCallback(1); // Will not move above new maximum. EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillOnce(DoAll(SetArgPointee<0>(30), Return(true))); EXPECT_CALL(volume_, GetMicVolume(_)) .WillRepeatedly(DoAll(SetArgReferee<0>(250u), Return(0))); EXPECT_CALL(volume_, SetMicVolume(_)).Times(0); PostProcCallback(1); } TEST_F(AgcManagerUnitTest, ClippingDoesNotPullLowVolumeBackUp) { SetVolumeAndProcess(128u); SetInitialVolume(80u); EXPECT_CALL(*agc_, AnalyzePreproc(_, _)) .WillOnce(Return(kAboveClippedThreshold)); EXPECT_CALL(volume_, GetMicVolume(_)).Times(0); EXPECT_CALL(volume_, SetMicVolume(_)).Times(0); EXPECT_CALL(*agc_, Reset()).Times(0); PreProcCallback(1); } TEST_F(AgcManagerUnitTest, TakesNoActionOnZeroMicVolume) { SetVolumeAndProcess(128u); EXPECT_CALL(*agc_, GetRmsErrorDb(_)) .WillRepeatedly(DoAll(SetArgPointee<0>(30), Return(true))); EXPECT_CALL(volume_, GetMicVolume(_)) .WillRepeatedly(DoAll(SetArgReferee<0>(0), Return(0))); EXPECT_CALL(volume_, SetMicVolume(_)).Times(0); PostProcCallback(10); } } // namespace webrtc