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:
parent
a67696b3cd
commit
d094c04baf
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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',
|
||||
|
||||
@ -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_
|
||||
@ -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"
|
||||
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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',
|
||||
|
||||
@ -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_
|
||||
@ -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_
|
||||
@ -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': [
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user