Remove AgcManager.

It was not used anywhere.

R=andrew@webrtc.org

Review URL: https://codereview.webrtc.org/1299143003 .

Cr-Commit-Position: refs/heads/master@{#10113}
This commit is contained in:
Alejandro Luebs 2015-09-29 15:43:42 -07:00
parent a67696b3cd
commit d094c04baf
14 changed files with 705 additions and 1559 deletions

View File

@ -21,9 +21,9 @@ class DebugFile;
class GainControl;
// Callbacks that need to be injected into AgcManagerDirect to read and control
// the volume values. They have different behavior if they are called from
// AgcManager or AudioProcessing. This is done to remove the VoiceEngine
// dependency in AgcManagerDirect.
// the volume values. This is done to remove the VoiceEngine dependency in
// AgcManagerDirect.
// TODO(aluebs): Remove VolumeCallbacks.
class VolumeCallbacks {
public:
virtual ~VolumeCallbacks() {}
@ -33,11 +33,10 @@ class VolumeCallbacks {
// Direct interface to use AGC to set volume and compression values.
// AudioProcessing uses this interface directly to integrate the callback-less
// AGC. AgcManager delegates most of its calls here. See agc_manager.h for
// undocumented methods.
// AGC.
//
// This class is not thread-safe.
class AgcManagerDirect {
class AgcManagerDirect final {
public:
// AgcManagerDirect will configure GainControl internally. The user is
// responsible for processing the audio using it after the call to Process.
@ -60,6 +59,15 @@ class AgcManagerDirect {
size_t samples_per_channel);
void Process(const int16_t* audio, size_t length, int sample_rate_hz);
// Call when the capture stream has been muted/unmuted. This causes the
// manager to disregard all incoming audio; chances are good it's background
// noise to which we'd like to avoid adapting.
void SetCaptureMuted(bool muted);
bool capture_muted() { return capture_muted_; }
float voice_probability();
private:
// Sets a new microphone level, after first checking that it hasn't been
// updated by the user, in which case no action is taken.
void SetLevel(int new_level);
@ -69,12 +77,6 @@ class AgcManagerDirect {
// |kClippedLevelMin|.
void SetMaxLevel(int level);
void SetCaptureMuted(bool muted);
bool capture_muted() { return capture_muted_; }
float voice_probability();
private:
int CheckVolumeAndReset();
void UpdateGain();
void UpdateCompressor();
@ -97,6 +99,8 @@ class AgcManagerDirect {
rtc::scoped_ptr<DebugFile> file_preproc_;
rtc::scoped_ptr<DebugFile> file_postproc_;
RTC_DISALLOW_COPY_AND_ASSIGN(AgcManagerDirect);
};
} // namespace webrtc

View File

@ -0,0 +1,686 @@
/*
* 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/modules/audio_processing/agc/agc_manager_direct.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/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 int kInitialVolume = 128;
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) {
ExpectInitialize();
manager_.Initialize();
}
void FirstProcess() {
EXPECT_CALL(*agc_, Reset());
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(0));
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_;
MockGainControl gctrl_;
TestVolumeCallbacks volume_;
AgcManagerDirect manager_;
test::TraceToStderr trace_to_stderr;
};
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)));
// GetMicVolume returns a value outside of the quantization slack, indicating
// a manual volume change.
volume_.SetMicVolume(154);
// SetMicVolume should not be called.
EXPECT_CALL(*agc_, Reset()).Times(1);
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(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(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(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(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(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(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(1);
CallPreProc(1);
EXPECT_EQ(170, volume_.GetMicVolume());
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillRepeatedly(Return(kAboveClippedThreshold));
EXPECT_CALL(*agc_, Reset()).Times(0);
CallPreProc(1000);
EXPECT_EQ(170, volume_.GetMicVolume());
}
TEST_F(AgcManagerDirectTest, ClippingMaxIsRespectedWhenEqualToLevel) {
SetVolumeAndProcess(255);
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillOnce(Return(kAboveClippedThreshold));
EXPECT_CALL(*agc_, Reset()).Times(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(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(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(1);
CallPreProc(1);
EXPECT_EQ(180, volume_.GetMicVolume());
CallPreProc(300);
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.WillOnce(Return(kAboveClippedThreshold));
EXPECT_CALL(*agc_, Reset()).Times(1);
CallPreProc(1);
EXPECT_EQ(170, 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(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(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());
}
} // namespace webrtc

View File

@ -163,6 +163,7 @@
'audio_device/fine_audio_buffer_unittest.cc',
'audio_processing/aec/echo_cancellation_unittest.cc',
'audio_processing/aec/system_delay_unittest.cc',
'audio_processing/agc/agc_manager_direct_unittest.cc',
# TODO(ajm): Fix to match new interface.
# 'audio_processing/agc/agc_unittest.cc',
'audio_processing/agc/histogram_unittest.cc',

View File

@ -1,44 +0,0 @@
/*
* 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.
*/
#ifndef WEBRTC_TEST_FAKE_COMMON_H_
#define WEBRTC_TEST_FAKE_COMMON_H_
// Borrowed from libjingle's talk/media/webrtc/fakewebrtccommon.h.
#include "webrtc/typedefs.h"
#define WEBRTC_STUB(method, args) \
int method args override { return 0; }
#define WEBRTC_STUB_CONST(method, args) \
int method args const override { return 0; }
#define WEBRTC_BOOL_STUB(method, args) \
bool method args override { return true; }
#define WEBRTC_VOID_STUB(method, args) \
void method args override {}
#define WEBRTC_FUNC(method, args) int method args override
#define WEBRTC_FUNC_CONST(method, args) int method args const override
#define WEBRTC_BOOL_FUNC(method, args) bool method args override
#define WEBRTC_VOID_FUNC(method, args) void method args override
#define WEBRTC_CHECK_CHANNEL(channel) \
if (channels_.find(channel) == channels_.end()) return -1;
#define WEBRTC_ASSERT_CHANNEL(channel) \
ASSERT(channels_.find(channel) != channels_.end());
#endif // WEBRTC_TEST_FAKE_COMMON_H_

View File

@ -17,7 +17,6 @@
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/test/channel_transport/include/channel_transport.h"
#include "webrtc/test/testsupport/trace_to_stderr.h"
#include "webrtc/tools/agc/agc_manager.h"
#include "webrtc/modules/audio_processing/include/audio_processing.h"
#include "webrtc/voice_engine/include/voe_audio_processing.h"
#include "webrtc/voice_engine/include/voe_base.h"

View File

@ -1,255 +0,0 @@
/*
* 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/tools/agc/agc_manager.h"
#include <assert.h>
#include "webrtc/modules/audio_processing/agc/agc.h"
#include "webrtc/modules/audio_processing/include/audio_processing.h"
#include "webrtc/modules/interface/module_common_types.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/voice_engine/include/voe_external_media.h"
#include "webrtc/voice_engine/include/voe_volume_control.h"
namespace webrtc {
class AgcManagerVolume : public VolumeCallbacks {
public:
// AgcManagerVolume acquires ownership of |volume|.
explicit AgcManagerVolume(VoEVolumeControl* volume)
: volume_(volume) {
}
~AgcManagerVolume() {
if (volume_) {
volume_->Release();
}
}
virtual void SetMicVolume(int volume) {
if (volume_->SetMicVolume(volume) != 0) {
LOG_FERR1(LS_WARNING, SetMicVolume, volume);
}
}
int GetMicVolume() {
unsigned int volume = 0;
if (volume_->GetMicVolume(volume) != 0) {
LOG_FERR0(LS_WARNING, GetMicVolume);
return -1;
}
return volume;
}
private:
VoEVolumeControl* volume_;
};
class MediaCallback : public VoEMediaProcess {
public:
MediaCallback(AgcManagerDirect* direct, AudioProcessing* audioproc,
CriticalSectionWrapper* crit)
: direct_(direct),
audioproc_(audioproc),
crit_(crit),
frame_() {
}
protected:
virtual void Process(const int channel, const ProcessingTypes type,
int16_t audio[], const size_t samples_per_channel,
const int sample_rate_hz, const bool is_stereo) {
CriticalSectionScoped cs(crit_);
if (direct_->capture_muted()) {
return;
}
// Extract the first channel.
const int kMaxSampleRateHz = 48000;
const int kMaxSamplesPerChannel = kMaxSampleRateHz / 100;
assert(samples_per_channel < kMaxSamplesPerChannel &&
sample_rate_hz < kMaxSampleRateHz);
int16_t mono[kMaxSamplesPerChannel];
int16_t* mono_ptr = audio;
if (is_stereo) {
for (size_t n = 0; n < samples_per_channel; n++) {
mono[n] = audio[n * 2];
}
mono_ptr = mono;
}
direct_->Process(mono_ptr, samples_per_channel, sample_rate_hz);
// TODO(ajm): It's unfortunate we have to memcpy to this frame here, but
// it's needed for use with AudioProcessing.
frame_.num_channels_ = is_stereo ? 2 : 1;
frame_.samples_per_channel_ = samples_per_channel;
frame_.sample_rate_hz_ = sample_rate_hz;
const size_t length_samples = frame_.num_channels_ * samples_per_channel;
memcpy(frame_.data_, audio, length_samples * sizeof(int16_t));
// Apply compression to the audio.
if (audioproc_->ProcessStream(&frame_) != 0) {
LOG_FERR0(LS_ERROR, ProcessStream);
}
// Copy the compressed audio back to voice engine's array.
memcpy(audio, frame_.data_, length_samples * sizeof(int16_t));
}
private:
AgcManagerDirect* direct_;
AudioProcessing* audioproc_;
CriticalSectionWrapper* crit_;
AudioFrame frame_;
};
class PreprocCallback : public VoEMediaProcess {
public:
PreprocCallback(AgcManagerDirect* direct, CriticalSectionWrapper* crit)
: direct_(direct),
crit_(crit) {
}
protected:
virtual void Process(const int channel, const ProcessingTypes type,
int16_t audio[], const size_t samples_per_channel,
const int sample_rate_hz, const bool is_stereo) {
CriticalSectionScoped cs(crit_);
if (direct_->capture_muted()) {
return;
}
direct_->AnalyzePreProcess(audio, is_stereo ? 2 : 1, samples_per_channel);
}
private:
AgcManagerDirect* direct_;
CriticalSectionWrapper* crit_;
};
AgcManager::AgcManager(VoiceEngine* voe)
: media_(VoEExternalMedia::GetInterface(voe)),
volume_callbacks_(new AgcManagerVolume(VoEVolumeControl::GetInterface(
voe))),
crit_(CriticalSectionWrapper::CreateCriticalSection()),
enabled_(false),
initialized_(false) {
Config config;
config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
audioproc_.reset(AudioProcessing::Create(config));
direct_.reset(new AgcManagerDirect(audioproc_->gain_control(),
volume_callbacks_.get(),
kAgcStartupMinVolume));
media_callback_.reset(new MediaCallback(direct_.get(),
audioproc_.get(),
crit_.get()));
preproc_callback_.reset(new PreprocCallback(direct_.get(), crit_.get()));
}
AgcManager::AgcManager(VoEExternalMedia* media,
VoEVolumeControl* volume,
Agc* agc,
AudioProcessing* audioproc)
: media_(media),
volume_callbacks_(new AgcManagerVolume(volume)),
crit_(CriticalSectionWrapper::CreateCriticalSection()),
audioproc_(audioproc),
direct_(new AgcManagerDirect(agc,
audioproc_->gain_control(),
volume_callbacks_.get(),
kAgcStartupMinVolume)),
media_callback_(
new MediaCallback(direct_.get(), audioproc_.get(), crit_.get())),
preproc_callback_(new PreprocCallback(direct_.get(), crit_.get())),
enabled_(false),
initialized_(false) {
}
AgcManager::AgcManager()
: media_(NULL),
enabled_(false),
initialized_(false) {
}
AgcManager::~AgcManager() {
if (media_) {
if (enabled_) {
DeregisterCallbacks();
}
media_->Release();
}
}
int AgcManager::Enable(bool enable) {
if (enable == enabled_) {
return 0;
}
if (!initialized_) {
CriticalSectionScoped cs(crit_.get());
if (audioproc_->gain_control()->Enable(true) != 0) {
LOG_FERR1(LS_ERROR, gain_control()->Enable, true);
return -1;
}
if (direct_->Initialize() != 0) {
assert(false);
return -1;
}
initialized_ = true;
}
if (enable) {
if (media_->RegisterExternalMediaProcessing(0, kRecordingAllChannelsMixed,
*media_callback_) != 0) {
LOG(LS_ERROR) << "Failed to register postproc callback";
return -1;
}
if (media_->RegisterExternalMediaProcessing(0, kRecordingPreprocessing,
*preproc_callback_) != 0) {
LOG(LS_ERROR) << "Failed to register preproc callback";
return -1;
}
} else {
if (DeregisterCallbacks() != 0)
return -1;
}
enabled_ = enable;
return 0;
}
void AgcManager::CaptureDeviceChanged() {
CriticalSectionScoped cs(crit_.get());
direct_->Initialize();
}
void AgcManager::SetCaptureMuted(bool muted) {
CriticalSectionScoped cs(crit_.get());
direct_->SetCaptureMuted(muted);
}
int AgcManager::DeregisterCallbacks() {
// DeRegister shares a lock with the Process() callback. This call will block
// until the callback is finished and it's safe to continue teardown.
int err = 0;
if (media_->DeRegisterExternalMediaProcessing(0,
kRecordingAllChannelsMixed) != 0) {
LOG(LS_ERROR) << "Failed to deregister postproc callback";
err = -1;
}
if (media_->DeRegisterExternalMediaProcessing(0,
kRecordingPreprocessing) != 0) {
LOG(LS_ERROR) << "Failed to deregister preproc callback";
err = -1;
}
return err;
}
} // namespace webrtc

View File

@ -1,81 +0,0 @@
/*
* 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.
*/
#ifndef WEBRTC_TOOLS_AGC_AGC_MANAGER_H_
#define WEBRTC_TOOLS_AGC_AGC_MANAGER_H_
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/audio_processing/agc/agc_manager_direct.h"
namespace webrtc {
class Agc;
class AudioProcessing;
class CriticalSectionWrapper;
class MediaCallback;
class PreprocCallback;
class VoEExternalMedia;
class VoEVolumeControl;
class VoiceEngine;
class VolumeCallbacks;
// Handles the interaction between VoiceEngine and the internal AGC. It hooks
// into the capture stream through VoiceEngine's external media interface and
// sends the audio to the AGC for analysis. It forwards requests for a capture
// volume change from the AGC to the VoiceEngine volume interface.
class AgcManager {
public:
explicit AgcManager(VoiceEngine* voe);
// Dependency injection for testing. Don't delete |agc| or |audioproc| as the
// memory is owned by the manager. If |media| or |volume| are non-fake
// reference counted classes, don't release them as this is handled by the
// manager.
AgcManager(VoEExternalMedia* media, VoEVolumeControl* volume, Agc* agc,
AudioProcessing* audioproc);
virtual ~AgcManager();
// When enabled, registers external media processing callbacks with
// VoiceEngine to hook into the capture stream. Disabling deregisters the
// callbacks.
virtual int Enable(bool enable);
virtual bool enabled() const { return enabled_; }
// Call when the capture device has changed. This will trigger a retrieval of
// the initial capture volume on the next audio frame.
virtual void CaptureDeviceChanged();
// Call when the capture stream has been muted/unmuted. This causes the
// manager to disregard all incoming audio; chances are good it's background
// noise to which we'd like to avoid adapting.
virtual void SetCaptureMuted(bool muted);
virtual bool capture_muted() const { return direct_->capture_muted(); }
protected:
// Provide a default constructor for testing.
AgcManager();
private:
int DeregisterCallbacks();
int CheckVolumeAndReset();
VoEExternalMedia* media_;
rtc::scoped_ptr<VolumeCallbacks> volume_callbacks_;
rtc::scoped_ptr<CriticalSectionWrapper> crit_;
rtc::scoped_ptr<AudioProcessing> audioproc_;
rtc::scoped_ptr<AgcManagerDirect> direct_;
rtc::scoped_ptr<MediaCallback> media_callback_;
rtc::scoped_ptr<PreprocCallback> preproc_callback_;
bool enabled_;
bool initialized_;
};
} // namespace webrtc
#endif // WEBRTC_TOOLS_AGC_AGC_MANAGER_H_

View File

@ -1,123 +0,0 @@
/*
* 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/tools/agc/agc_manager.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/audio_processing/agc/mock_agc.h"
#include "webrtc/modules/audio_processing/include/audio_processing.h"
#include "webrtc/system_wrappers/interface/sleep.h"
#include "webrtc/test/channel_transport/include/channel_transport.h"
#include "webrtc/test/testsupport/gtest_disable.h"
#include "webrtc/voice_engine/include/voe_base.h"
#include "webrtc/voice_engine/include/voe_external_media.h"
#include "webrtc/voice_engine/include/voe_network.h"
#include "webrtc/voice_engine/include/voe_volume_control.h"
using ::testing::_;
using ::testing::AtLeast;
using ::testing::Mock;
using ::testing::Return;
namespace webrtc {
class AgcManagerTest : public ::testing::Test {
protected:
AgcManagerTest()
: voe_(VoiceEngine::Create()),
base_(VoEBase::GetInterface(voe_)),
agc_(new MockAgc()),
manager_(new AgcManager(VoEExternalMedia::GetInterface(voe_),
VoEVolumeControl::GetInterface(voe_),
agc_,
AudioProcessing::Create())),
channel_(-1) {
}
virtual void SetUp() {
ASSERT_TRUE(voe_ != NULL);
ASSERT_TRUE(base_ != NULL);
ASSERT_EQ(0, base_->Init());
channel_ = base_->CreateChannel();
ASSERT_NE(-1, channel_);
VoENetwork* network = VoENetwork::GetInterface(voe_);
ASSERT_TRUE(network != NULL);
channel_transport_.reset(
new test::VoiceChannelTransport(network, channel_));
ASSERT_EQ(0, channel_transport_->SetSendDestination("127.0.0.1", 1234));
network->Release();
}
virtual void TearDown() {
channel_transport_.reset(NULL);
ASSERT_EQ(0, base_->DeleteChannel(channel_));
ASSERT_EQ(0, base_->Terminate());
delete manager_;
// Test that the manager has released all VoE interfaces. The last
// reference is released in VoiceEngine::Delete.
EXPECT_EQ(1, base_->Release());
ASSERT_TRUE(VoiceEngine::Delete(voe_));
}
VoiceEngine* voe_;
VoEBase* base_;
MockAgc* agc_;
rtc::scoped_ptr<test::VoiceChannelTransport> channel_transport_;
// We use a pointer for the manager, so we can tear it down and test
// base_->Release() in the destructor.
AgcManager* manager_;
int channel_;
};
TEST_F(AgcManagerTest, DISABLED_ON_ANDROID(EnableSucceeds)) {
EXPECT_EQ(0, manager_->Enable(true));
EXPECT_TRUE(manager_->enabled());
EXPECT_EQ(0, manager_->Enable(false));
EXPECT_FALSE(manager_->enabled());
}
TEST_F(AgcManagerTest, DISABLED_ON_ANDROID(ProcessIsNotCalledByDefault)) {
EXPECT_CALL(*agc_, AnalyzePreproc(_, _)).Times(0);
EXPECT_CALL(*agc_, Process(_, _, _)).Times(0);
EXPECT_CALL(*agc_, GetRmsErrorDb(_)).Times(0);
ASSERT_EQ(0, base_->StartSend(channel_));
SleepMs(100);
ASSERT_EQ(0, base_->StopSend(channel_));
}
TEST_F(AgcManagerTest, DISABLED_ProcessIsCalledOnlyWhenEnabled) {
EXPECT_CALL(*agc_, Reset());
EXPECT_CALL(*agc_, AnalyzePreproc(_, _))
.Times(AtLeast(1))
.WillRepeatedly(Return(0));
EXPECT_CALL(*agc_, Process(_, _, _))
.Times(AtLeast(1))
.WillRepeatedly(Return(0));
EXPECT_CALL(*agc_, GetRmsErrorDb(_))
.Times(AtLeast(1))
.WillRepeatedly(Return(false));
EXPECT_EQ(0, manager_->Enable(true));
ASSERT_EQ(0, base_->StartSend(channel_));
SleepMs(100);
EXPECT_EQ(0, manager_->Enable(false));
SleepMs(100);
Mock::VerifyAndClearExpectations(agc_);
EXPECT_CALL(*agc_, AnalyzePreproc(_, _)).Times(0);
EXPECT_CALL(*agc_, Process(_, _, _)).Times(0);
EXPECT_CALL(*agc_, GetRmsErrorDb(_)).Times(0);
SleepMs(100);
ASSERT_EQ(0, base_->StopSend(channel_));
}
} // namespace webrtc

View File

@ -1,741 +0,0 @@
/*
* 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 size_t kSamplesPerChannel = static_cast<size_t>(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

View File

@ -1,155 +0,0 @@
/*
* 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 <cmath>
#include <cstdio>
#include <algorithm>
#include "gflags/gflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/audio_processing/agc/agc.h"
#include "webrtc/modules/audio_processing/agc/utility.h"
#include "webrtc/modules/audio_processing/include/audio_processing.h"
#include "webrtc/modules/interface/module_common_types.h"
#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/test/testsupport/trace_to_stderr.h"
#include "webrtc/tools/agc/agc_manager.h"
#include "webrtc/tools/agc/test_utils.h"
#include "webrtc/voice_engine/mock/fake_voe_external_media.h"
#include "webrtc/voice_engine/mock/mock_voe_volume_control.h"
DEFINE_string(in, "in.pcm", "input filename");
DEFINE_string(out, "out.pcm", "output filename");
DEFINE_int32(rate, 16000, "sample rate in Hz");
DEFINE_int32(channels, 1, "number of channels");
DEFINE_int32(level, -18, "target level in RMS dBFs [-100, 0]");
DEFINE_bool(limiter, true, "enable a limiter for the compression stage");
DEFINE_int32(cmp_level, 2, "target level in dBFs for the compression stage");
DEFINE_int32(mic_gain, 80, "range of gain provided by the virtual mic in dB");
DEFINE_int32(gain_offset, 0,
"an amount (in dB) to add to every entry in the gain map");
DEFINE_string(gain_file, "",
"filename providing a mic gain mapping. The file should be text containing "
"a (floating-point) gain entry in dBFs per line corresponding to levels "
"from 0 to 255.");
using ::testing::_;
using ::testing::ByRef;
using ::testing::DoAll;
using ::testing::Mock;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgReferee;
namespace webrtc {
namespace {
const char kUsage[] = "\nProcess an audio file to simulate an analog agc.";
void ReadGainMapFromFile(FILE* file, int offset, int gain_map[256]) {
for (int i = 0; i < 256; ++i) {
float gain = 0;
ASSERT_EQ(1, fscanf(file, "%f", &gain));
gain_map[i] = std::floor(gain + 0.5);
}
// Adjust from dBFs to gain in dB. We assume that level 127 provides 0 dB
// gain. This corresponds to the interpretation in MicLevel2Gain().
const int midpoint = gain_map[127];
printf("Gain map\n");
for (int i = 0; i < 256; ++i) {
gain_map[i] += offset - midpoint;
if (i % 5 == 0) {
printf("%d: %d dB\n", i, gain_map[i]);
}
}
}
void CalculateGainMap(int gain_range_db, int offset, int gain_map[256]) {
printf("Gain map\n");
for (int i = 0; i < 256; ++i) {
gain_map[i] = std::floor(MicLevel2Gain(gain_range_db, i) + 0.5) + offset;
if (i % 5 == 0) {
printf("%d: %d dB\n", i, gain_map[i]);
}
}
}
void RunAgc() {
test::TraceToStderr trace_to_stderr(true);
FILE* in_file = fopen(FLAGS_in.c_str(), "rb");
ASSERT_TRUE(in_file != NULL);
FILE* out_file = fopen(FLAGS_out.c_str(), "wb");
ASSERT_TRUE(out_file != NULL);
int gain_map[256];
if (!FLAGS_gain_file.empty()) {
FILE* gain_file = fopen(FLAGS_gain_file.c_str(), "rt");
ASSERT_TRUE(gain_file != NULL);
ReadGainMapFromFile(gain_file, FLAGS_gain_offset, gain_map);
fclose(gain_file);
} else {
CalculateGainMap(FLAGS_mic_gain, FLAGS_gain_offset, gain_map);
}
FakeVoEExternalMedia media;
MockVoEVolumeControl volume;
Agc* agc = new Agc;
AudioProcessing* audioproc = AudioProcessing::Create();
ASSERT_TRUE(audioproc != NULL);
AgcManager manager(&media, &volume, agc, audioproc);
int mic_level = 128;
int last_mic_level = mic_level;
EXPECT_CALL(volume, GetMicVolume(_))
.WillRepeatedly(DoAll(SetArgReferee<0>(ByRef(mic_level)), Return(0)));
EXPECT_CALL(volume, SetMicVolume(_))
.WillRepeatedly(DoAll(SaveArg<0>(&mic_level), Return(0)));
manager.Enable(true);
ASSERT_EQ(0, agc->set_target_level_dbfs(FLAGS_level));
const AudioProcessing::Error kNoErr = AudioProcessing::kNoError;
GainControl* gctrl = audioproc->gain_control();
ASSERT_EQ(kNoErr, gctrl->set_target_level_dbfs(FLAGS_cmp_level));
ASSERT_EQ(kNoErr, gctrl->enable_limiter(FLAGS_limiter));
AudioFrame frame;
frame.num_channels_ = FLAGS_channels;
frame.sample_rate_hz_ = FLAGS_rate;
frame.samples_per_channel_ = FLAGS_rate / 100;
const size_t frame_length = frame.samples_per_channel_ * FLAGS_channels;
size_t sample_count = 0;
while (fread(frame.data_, sizeof(int16_t), frame_length, in_file) ==
frame_length) {
SimulateMic(gain_map, mic_level, last_mic_level, &frame);
last_mic_level = mic_level;
media.CallProcess(kRecordingAllChannelsMixed, frame.data_,
frame.samples_per_channel_, FLAGS_rate, FLAGS_channels);
ASSERT_EQ(frame_length,
fwrite(frame.data_, sizeof(int16_t), frame_length, out_file));
sample_count += frame_length;
trace_to_stderr.SetTimeSeconds(static_cast<float>(sample_count) /
FLAGS_channels / FLAGS_rate);
}
fclose(in_file);
fclose(out_file);
EXPECT_CALL(volume, Release());
}
} // namespace
} // namespace webrtc
int main(int argc, char* argv[]) {
google::SetUsageMessage(webrtc::kUsage);
google::ParseCommandLineFlags(&argc, &argv, true);
webrtc::RunAgc();
return 0;
}

View File

@ -101,19 +101,6 @@
'conditions': [
['include_tests==1', {
'targets' : [
{
'target_name': 'agc_manager',
'type': 'static_library',
'dependencies': [
'<(webrtc_root)/common_audio/common_audio.gyp:common_audio',
'<(webrtc_root)/modules/modules.gyp:audio_processing',
'<(webrtc_root)/voice_engine/voice_engine.gyp:voice_engine',
],
'sources': [
'agc/agc_manager.cc',
'agc/agc_manager.h',
],
},
{
'target_name': 'agc_test_utils',
'type': 'static_library',
@ -131,35 +118,19 @@
'<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers_default',
'<(webrtc_root)/test/test.gyp:channel_transport',
'<(webrtc_root)/test/test.gyp:test_support',
'agc_manager',
'<(webrtc_root)/voice_engine/voice_engine.gyp:voice_engine',
],
'sources': [
'agc/agc_harness.cc',
],
}, # agc_harness
{
'target_name': 'agc_proc',
'type': 'executable',
'dependencies': [
'<(DEPTH)/testing/gmock.gyp:gmock',
'<(DEPTH)/testing/gtest.gyp:gtest',
'<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
'<(webrtc_root)/test/test.gyp:test_support',
'<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers_default',
'agc_manager',
'agc_test_utils',
],
'sources': [
'agc/agc_test.cc',
],
}, # agc_proc
{
'target_name': 'activity_metric',
'type': 'executable',
'dependencies': [
'<(DEPTH)/testing/gtest.gyp:gtest',
'<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
'agc_manager',
'<(webrtc_root)/modules/modules.gyp:audio_processing',
],
'sources': [
'agc/activity_metric.cc',

View File

@ -1,69 +0,0 @@
/*
* 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.
*/
#ifndef WEBRTC_VOICE_ENGINE_INCLUDE_MOCK_FAKE_VOE_EXTERNAL_MEDIA_H_
#define WEBRTC_VOICE_ENGINE_INCLUDE_MOCK_FAKE_VOE_EXTERNAL_MEDIA_H_
#include <map>
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/test/fake_common.h"
#include "webrtc/voice_engine/include/voe_external_media.h"
namespace webrtc {
class FakeVoEExternalMedia : public VoEExternalMedia {
public:
FakeVoEExternalMedia() {}
virtual ~FakeVoEExternalMedia() {}
WEBRTC_STUB(Release, ());
WEBRTC_FUNC(RegisterExternalMediaProcessing,
(int channel, ProcessingTypes type, VoEMediaProcess& processObject)) {
callback_map_[type] = &processObject;
return 0;
}
WEBRTC_FUNC(DeRegisterExternalMediaProcessing,
(int channel, ProcessingTypes type)) {
callback_map_.erase(type);
return 0;
}
WEBRTC_STUB(GetAudioFrame, (int channel, int desired_sample_rate_hz,
AudioFrame* frame));
WEBRTC_STUB(SetExternalMixing, (int channel, bool enable));
// Use this to trigger the Process() callback to a registered media processor.
// If |audio| is NULL, a zero array of the correct length will be forwarded.
void CallProcess(ProcessingTypes type, int16_t* audio,
size_t samples_per_channel, int sample_rate_hz,
int num_channels) {
const size_t length = samples_per_channel * num_channels;
rtc::scoped_ptr<int16_t[]> data;
if (!audio) {
data.reset(new int16_t[length]);
memset(data.get(), 0, length * sizeof(data[0]));
audio = data.get();
}
std::map<ProcessingTypes, VoEMediaProcess*>::const_iterator it =
callback_map_.find(type);
if (it != callback_map_.end()) {
it->second->Process(0, type, audio, samples_per_channel, sample_rate_hz,
num_channels == 2 ? true : false);
}
}
private:
std::map<ProcessingTypes, VoEMediaProcess*> callback_map_;
};
} // namespace webrtc
#endif // WEBRTC_VOICE_ENGINE_INCLUDE_MOCK_FAKE_VOE_EXTERNAL_MEDIA_H_

View File

@ -1,43 +0,0 @@
/*
* 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.
*/
#ifndef WEBRTC_VOICE_ENGINE_INCLUDE_MOCK_MOCK_VOE_VOLUME_CONTROL_H_
#define WEBRTC_VOICE_ENGINE_INCLUDE_MOCK_MOCK_VOE_VOLUME_CONTROL_H_
#include "testing/gmock/include/gmock/gmock.h"
#include "webrtc/voice_engine/include/voe_volume_control.h"
namespace webrtc {
class VoiceEngine;
class MockVoEVolumeControl : public VoEVolumeControl {
public:
MOCK_METHOD0(Release, int());
MOCK_METHOD1(SetSpeakerVolume, int(unsigned int volume));
MOCK_METHOD1(GetSpeakerVolume, int(unsigned int& volume));
MOCK_METHOD1(SetMicVolume, int(unsigned int volume));
MOCK_METHOD1(GetMicVolume, int(unsigned int& volume));
MOCK_METHOD2(SetInputMute, int(int channel, bool enable));
MOCK_METHOD2(GetInputMute, int(int channel, bool& enabled));
MOCK_METHOD1(GetSpeechInputLevel, int(unsigned int& level));
MOCK_METHOD2(GetSpeechOutputLevel, int(int channel, unsigned int& level));
MOCK_METHOD1(GetSpeechInputLevelFullRange, int(unsigned int& level));
MOCK_METHOD2(GetSpeechOutputLevelFullRange,
int(int channel, unsigned int& level));
MOCK_METHOD2(SetChannelOutputVolumeScaling, int(int channel, float scaling));
MOCK_METHOD2(GetChannelOutputVolumeScaling, int(int channel, float& scaling));
MOCK_METHOD3(SetOutputVolumePan, int(int channel, float left, float right));
MOCK_METHOD3(GetOutputVolumePan, int(int channel, float& left, float& right));
};
} // namespace webrtc
#endif // WEBRTC_VOICE_ENGINE_INCLUDE_MOCK_MOCK_VOE_VOLUME_CONTROL_H_

View File

@ -155,7 +155,6 @@
'call/packet_injection_tests.cc',
'test/common_unittest.cc',
'test/testsupport/metrics/video_metrics_unittest.cc',
'tools/agc/agc_manager_unittest.cc',
'video/end_to_end_tests.cc',
'video/send_statistics_proxy_unittest.cc',
'video/video_capture_input_unittest.cc',
@ -175,7 +174,6 @@
'test/metrics.gyp:metrics',
'test/test.gyp:test_main',
'test/webrtc_test_common.gyp:webrtc_test_common',
'tools/tools.gyp:agc_manager',
'webrtc',
],
'conditions': [
@ -205,7 +203,6 @@
'call/call_perf_tests.cc',
'modules/audio_coding/neteq/test/neteq_performance_unittest.cc',
'modules/remote_bitrate_estimator/remote_bitrate_estimators_test.cc',
'tools/agc/agc_manager_integrationtest.cc',
'video/full_stack.cc',
'video/rampup_tests.cc',
'video/rampup_tests.h',
@ -223,7 +220,6 @@
'test/test.gyp:test_main',
'test/webrtc_test_common.gyp:webrtc_test_common',
'test/webrtc_test_common.gyp:webrtc_test_renderer',
'tools/tools.gyp:agc_manager',
'webrtc',
],
'conditions': [