Make AgcManagerDirect clipping parameters configurable

Bug: webrtc:12774
Change-Id: I99824b5aabe6f921a5db425dd1c1c1d4c606186c
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219681
Commit-Queue: Hanna Silen <silen@webrtc.org>
Reviewed-by: Alessio Bazzica <alessiob@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34069}
This commit is contained in:
Hanna Silen
2021-05-20 17:37:56 +02:00
committed by WebRTC LUCI CQ
parent e2b9fc6909
commit b8dc7fa5a6
6 changed files with 145 additions and 52 deletions

View File

@ -27,33 +27,26 @@ namespace webrtc {
namespace { namespace {
// Amount the microphone level is lowered with every clipping event.
const int kClippedLevelStep = 15;
// Proportion of clipped samples required to declare a clipping event.
const float kClippedRatioThreshold = 0.1f;
// Time in frames to wait after a clipping event before checking again.
const int kClippedWaitFrames = 300;
// Amount of error we tolerate in the microphone level (presumably due to OS // Amount of error we tolerate in the microphone level (presumably due to OS
// quantization) before we assume the user has manually adjusted the microphone. // quantization) before we assume the user has manually adjusted the microphone.
const int kLevelQuantizationSlack = 25; constexpr int kLevelQuantizationSlack = 25;
const int kDefaultCompressionGain = 7; constexpr int kDefaultCompressionGain = 7;
const int kMaxCompressionGain = 12; constexpr int kMaxCompressionGain = 12;
const int kMinCompressionGain = 2; constexpr int kMinCompressionGain = 2;
// Controls the rate of compression changes towards the target. // Controls the rate of compression changes towards the target.
const float kCompressionGainStep = 0.05f; constexpr float kCompressionGainStep = 0.05f;
const int kMaxMicLevel = 255; constexpr int kMaxMicLevel = 255;
static_assert(kGainMapSize > kMaxMicLevel, "gain map too small"); static_assert(kGainMapSize > kMaxMicLevel, "gain map too small");
const int kMinMicLevel = 12; constexpr int kMinMicLevel = 12;
// Prevent very large microphone level changes. // Prevent very large microphone level changes.
const int kMaxResidualGainChange = 15; constexpr int kMaxResidualGainChange = 15;
// Maximum additional gain allowed to compensate for microphone level // Maximum additional gain allowed to compensate for microphone level
// restrictions from clipping events. // restrictions from clipping events.
const int kSurplusCompressionGain = 6; constexpr int kSurplusCompressionGain = 6;
// Returns whether a fall-back solution to choose the maximum level should be // Returns whether a fall-back solution to choose the maximum level should be
// chosen. // chosen.
@ -182,19 +175,19 @@ void MonoAgc::Process(const int16_t* audio,
} }
} }
void MonoAgc::HandleClipping() { void MonoAgc::HandleClipping(int clipped_level_step) {
// Always decrease the maximum level, even if the current level is below // Always decrease the maximum level, even if the current level is below
// threshold. // threshold.
SetMaxLevel(std::max(clipped_level_min_, max_level_ - kClippedLevelStep)); SetMaxLevel(std::max(clipped_level_min_, max_level_ - clipped_level_step));
if (log_to_histograms_) { if (log_to_histograms_) {
RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.AgcClippingAdjustmentAllowed", RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.AgcClippingAdjustmentAllowed",
level_ - kClippedLevelStep >= clipped_level_min_); level_ - clipped_level_step >= clipped_level_min_);
} }
if (level_ > clipped_level_min_) { if (level_ > clipped_level_min_) {
// Don't try to adjust the level if we're already below the limit. As // Don't try to adjust the level if we're already below the limit. As
// a consequence, if the user has brought the level above the limit, we // a consequence, if the user has brought the level above the limit, we
// will still not react until the postproc updates the level. // will still not react until the postproc updates the level.
SetLevel(std::max(clipped_level_min_, level_ - kClippedLevelStep)); SetLevel(std::max(clipped_level_min_, level_ - clipped_level_step));
// Reset the AGCs for all channels since the level has changed. // Reset the AGCs for all channels since the level has changed.
agc_->Reset(); agc_->Reset();
} }
@ -404,12 +397,18 @@ int AgcManagerDirect::instance_counter_ = 0;
AgcManagerDirect::AgcManagerDirect(Agc* agc, AgcManagerDirect::AgcManagerDirect(Agc* agc,
int startup_min_level, int startup_min_level,
int clipped_level_min, int clipped_level_min,
int sample_rate_hz) int sample_rate_hz,
int clipped_level_step,
float clipped_ratio_threshold,
int clipped_wait_frames)
: AgcManagerDirect(/*num_capture_channels*/ 1, : AgcManagerDirect(/*num_capture_channels*/ 1,
startup_min_level, startup_min_level,
clipped_level_min, clipped_level_min,
/*disable_digital_adaptive*/ false, /*disable_digital_adaptive*/ false,
sample_rate_hz) { sample_rate_hz,
clipped_level_step,
clipped_ratio_threshold,
clipped_wait_frames) {
RTC_DCHECK(channel_agcs_[0]); RTC_DCHECK(channel_agcs_[0]);
RTC_DCHECK(agc); RTC_DCHECK(agc);
channel_agcs_[0]->set_agc(agc); channel_agcs_[0]->set_agc(agc);
@ -419,15 +418,21 @@ AgcManagerDirect::AgcManagerDirect(int num_capture_channels,
int startup_min_level, int startup_min_level,
int clipped_level_min, int clipped_level_min,
bool disable_digital_adaptive, bool disable_digital_adaptive,
int sample_rate_hz) int sample_rate_hz,
int clipped_level_step,
float clipped_ratio_threshold,
int clipped_wait_frames)
: data_dumper_( : data_dumper_(
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_counter_))), new ApmDataDumper(rtc::AtomicOps::Increment(&instance_counter_))),
use_min_channel_level_(!UseMaxAnalogChannelLevel()), use_min_channel_level_(!UseMaxAnalogChannelLevel()),
sample_rate_hz_(sample_rate_hz), sample_rate_hz_(sample_rate_hz),
num_capture_channels_(num_capture_channels), num_capture_channels_(num_capture_channels),
disable_digital_adaptive_(disable_digital_adaptive), disable_digital_adaptive_(disable_digital_adaptive),
frames_since_clipped_(kClippedWaitFrames), frames_since_clipped_(clipped_wait_frames),
capture_output_used_(true), capture_output_used_(true),
clipped_level_step_(clipped_level_step),
clipped_ratio_threshold_(clipped_ratio_threshold),
clipped_wait_frames_(clipped_wait_frames),
channel_agcs_(num_capture_channels), channel_agcs_(num_capture_channels),
new_compressions_to_set_(num_capture_channels) { new_compressions_to_set_(num_capture_channels) {
const int min_mic_level = GetMinMicLevel(); const int min_mic_level = GetMinMicLevel();
@ -438,7 +443,13 @@ AgcManagerDirect::AgcManagerDirect(int num_capture_channels,
data_dumper_ch, startup_min_level, clipped_level_min, data_dumper_ch, startup_min_level, clipped_level_min,
disable_digital_adaptive_, min_mic_level); disable_digital_adaptive_, min_mic_level);
} }
RTC_DCHECK_LT(0, channel_agcs_.size()); RTC_DCHECK(!channel_agcs_.empty());
RTC_DCHECK_GT(clipped_level_step, 0);
RTC_DCHECK_LE(clipped_level_step, 255);
RTC_DCHECK_GT(clipped_ratio_threshold, 0.f);
RTC_DCHECK_LT(clipped_ratio_threshold, 1.f);
RTC_DCHECK_GT(clipped_wait_frames, 0);
channel_agcs_[0]->ActivateLogging(); channel_agcs_[0]->ActivateLogging();
} }
@ -489,7 +500,7 @@ void AgcManagerDirect::AnalyzePreProcess(const float* const* audio,
return; return;
} }
if (frames_since_clipped_ < kClippedWaitFrames) { if (frames_since_clipped_ < clipped_wait_frames_) {
++frames_since_clipped_; ++frames_since_clipped_;
return; return;
} }
@ -506,11 +517,11 @@ void AgcManagerDirect::AnalyzePreProcess(const float* const* audio,
float clipped_ratio = float clipped_ratio =
ComputeClippedRatio(audio, num_capture_channels_, samples_per_channel); ComputeClippedRatio(audio, num_capture_channels_, samples_per_channel);
if (clipped_ratio > kClippedRatioThreshold) { if (clipped_ratio > clipped_ratio_threshold_) {
RTC_DLOG(LS_INFO) << "[agc] Clipping detected. clipped_ratio=" RTC_DLOG(LS_INFO) << "[agc] Clipping detected. clipped_ratio="
<< clipped_ratio; << clipped_ratio;
for (auto& state_ch : channel_agcs_) { for (auto& state_ch : channel_agcs_) {
state_ch->HandleClipping(); state_ch->HandleClipping(clipped_level_step_);
} }
frames_since_clipped_ = 0; frames_since_clipped_ = 0;
} }

View File

@ -34,12 +34,20 @@ class AgcManagerDirect final {
// AgcManagerDirect will configure GainControl internally. The user is // AgcManagerDirect will configure GainControl internally. The user is
// responsible for processing the audio using it after the call to Process. // responsible for processing the audio using it after the call to Process.
// The operating range of startup_min_level is [12, 255] and any input value // The operating range of startup_min_level is [12, 255] and any input value
// outside that range will be clamped. // outside that range will be clamped. `clipped_level_step` is the amount
// the microphone level is lowered with every clipping event, limited to
// (0, 255]. `clipped_ratio_threshold` is the proportion of clipped
// samples required to declare a clipping event, limited to (0.f, 1.f).
// `clipped_wait_frames` is the time in frames to wait after a clipping event
// before checking again, limited to values higher than 0.
AgcManagerDirect(int num_capture_channels, AgcManagerDirect(int num_capture_channels,
int startup_min_level, int startup_min_level,
int clipped_level_min, int clipped_level_min,
bool disable_digital_adaptive, bool disable_digital_adaptive,
int sample_rate_hz); int sample_rate_hz,
int clipped_level_step,
float clipped_ratio_threshold,
int clipped_wait_frames);
~AgcManagerDirect(); ~AgcManagerDirect();
AgcManagerDirect(const AgcManagerDirect&) = delete; AgcManagerDirect(const AgcManagerDirect&) = delete;
@ -81,13 +89,18 @@ class AgcManagerDirect final {
AgcMinMicLevelExperimentEnabled50); AgcMinMicLevelExperimentEnabled50);
FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest, FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest,
AgcMinMicLevelExperimentEnabledAboveStartupLevel); AgcMinMicLevelExperimentEnabledAboveStartupLevel);
FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest,
ClippingParametersVerified);
// Dependency injection for testing. Don't delete |agc| as the memory is owned // Dependency injection for testing. Don't delete |agc| as the memory is owned
// by the manager. // by the manager.
AgcManagerDirect(Agc* agc, AgcManagerDirect(Agc* agc,
int startup_min_level, int startup_min_level,
int clipped_level_min, int clipped_level_min,
int sample_rate_hz); int sample_rate_hz,
int clipped_level_step,
float clipped_ratio_threshold,
int clipped_wait_frames);
void AnalyzePreProcess(const float* const* audio, size_t samples_per_channel); void AnalyzePreProcess(const float* const* audio, size_t samples_per_channel);
@ -105,6 +118,10 @@ class AgcManagerDirect final {
bool capture_output_used_; bool capture_output_used_;
int channel_controlling_gain_ = 0; int channel_controlling_gain_ = 0;
const int clipped_level_step_;
const float clipped_ratio_threshold_;
const int clipped_wait_frames_;
std::vector<std::unique_ptr<MonoAgc>> channel_agcs_; std::vector<std::unique_ptr<MonoAgc>> channel_agcs_;
std::vector<absl::optional<int>> new_compressions_to_set_; std::vector<absl::optional<int>> new_compressions_to_set_;
}; };
@ -123,7 +140,7 @@ class MonoAgc {
void Initialize(); void Initialize();
void HandleCaptureOutputUsedChange(bool capture_output_used); void HandleCaptureOutputUsedChange(bool capture_output_used);
void HandleClipping(); void HandleClipping(int clipped_level_step);
void Process(const int16_t* audio, void Process(const int16_t* audio,
size_t samples_per_channel, size_t samples_per_channel,

View File

@ -26,13 +26,16 @@ using ::testing::SetArgPointee;
namespace webrtc { namespace webrtc {
namespace { namespace {
const int kSampleRateHz = 32000; constexpr int kSampleRateHz = 32000;
const int kNumChannels = 1; constexpr int kNumChannels = 1;
const int kSamplesPerChannel = kSampleRateHz / 100; constexpr int kSamplesPerChannel = kSampleRateHz / 100;
const int kInitialVolume = 128; constexpr int kInitialVolume = 128;
constexpr int kClippedMin = 165; // Arbitrary, but different from the default. constexpr int kClippedMin = 165; // Arbitrary, but different from the default.
const float kAboveClippedThreshold = 0.2f; constexpr float kAboveClippedThreshold = 0.2f;
const int kMinMicLevel = 12; constexpr int kMinMicLevel = 12;
constexpr int kClippedLevelStep = 15;
constexpr float kClippedRatioThreshold = 0.1f;
constexpr int kClippedWaitFrames = 300;
class MockGainControl : public GainControl { class MockGainControl : public GainControl {
public: public:
@ -57,10 +60,14 @@ class MockGainControl : public GainControl {
}; };
std::unique_ptr<AgcManagerDirect> CreateAgcManagerDirect( std::unique_ptr<AgcManagerDirect> CreateAgcManagerDirect(
int startup_min_level) { int startup_min_level,
int clipped_level_step,
float clipped_ratio_threshold,
int clipped_wait_frames) {
return std::make_unique<AgcManagerDirect>( return std::make_unique<AgcManagerDirect>(
/*num_capture_channels=*/1, startup_min_level, kClippedMin, /*num_capture_channels=*/1, startup_min_level, kClippedMin,
/*disable_digital_adaptive=*/true, kSampleRateHz); /*disable_digital_adaptive=*/true, kSampleRateHz, clipped_level_step,
clipped_ratio_threshold, clipped_wait_frames);
} }
} // namespace } // namespace
@ -69,7 +76,13 @@ class AgcManagerDirectTest : public ::testing::Test {
protected: protected:
AgcManagerDirectTest() AgcManagerDirectTest()
: agc_(new MockAgc), : agc_(new MockAgc),
manager_(agc_, kInitialVolume, kClippedMin, kSampleRateHz), manager_(agc_,
kInitialVolume,
kClippedMin,
kSampleRateHz,
kClippedLevelStep,
kClippedRatioThreshold,
kClippedWaitFrames),
audio(kNumChannels), audio(kNumChannels),
audio_data(kNumChannels * kSamplesPerChannel, 0.f) { audio_data(kNumChannels * kSamplesPerChannel, 0.f) {
ExpectInitialize(); ExpectInitialize();
@ -705,14 +718,16 @@ TEST(AgcManagerDirectStandaloneTest, DisableDigitalDisablesDigital) {
EXPECT_CALL(gctrl, enable_limiter(false)); EXPECT_CALL(gctrl, enable_limiter(false));
std::unique_ptr<AgcManagerDirect> manager = std::unique_ptr<AgcManagerDirect> manager =
CreateAgcManagerDirect(kInitialVolume); CreateAgcManagerDirect(kInitialVolume, kClippedLevelStep,
kClippedRatioThreshold, kClippedWaitFrames);
manager->Initialize(); manager->Initialize();
manager->SetupDigitalGainControl(&gctrl); manager->SetupDigitalGainControl(&gctrl);
} }
TEST(AgcManagerDirectStandaloneTest, AgcMinMicLevelExperiment) { TEST(AgcManagerDirectStandaloneTest, AgcMinMicLevelExperiment) {
std::unique_ptr<AgcManagerDirect> manager = std::unique_ptr<AgcManagerDirect> manager =
CreateAgcManagerDirect(kInitialVolume); CreateAgcManagerDirect(kInitialVolume, kClippedLevelStep,
kClippedRatioThreshold, kClippedWaitFrames);
EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevel); EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevel);
EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), kInitialVolume); EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), kInitialVolume);
} }
@ -721,7 +736,8 @@ TEST(AgcManagerDirectStandaloneTest, AgcMinMicLevelExperimentDisabled) {
test::ScopedFieldTrials field_trial( test::ScopedFieldTrials field_trial(
"WebRTC-Audio-AgcMinMicLevelExperiment/Disabled/"); "WebRTC-Audio-AgcMinMicLevelExperiment/Disabled/");
std::unique_ptr<AgcManagerDirect> manager = std::unique_ptr<AgcManagerDirect> manager =
CreateAgcManagerDirect(kInitialVolume); CreateAgcManagerDirect(kInitialVolume, kClippedLevelStep,
kClippedRatioThreshold, kClippedWaitFrames);
EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevel); EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevel);
EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), kInitialVolume); EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), kInitialVolume);
} }
@ -732,7 +748,8 @@ TEST(AgcManagerDirectStandaloneTest, AgcMinMicLevelExperimentOutOfRangeAbove) {
test::ScopedFieldTrials field_trial( test::ScopedFieldTrials field_trial(
"WebRTC-Audio-AgcMinMicLevelExperiment/Enabled-256/"); "WebRTC-Audio-AgcMinMicLevelExperiment/Enabled-256/");
std::unique_ptr<AgcManagerDirect> manager = std::unique_ptr<AgcManagerDirect> manager =
CreateAgcManagerDirect(kInitialVolume); CreateAgcManagerDirect(kInitialVolume, kClippedLevelStep,
kClippedRatioThreshold, kClippedWaitFrames);
EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevel); EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevel);
EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), kInitialVolume); EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), kInitialVolume);
} }
@ -743,7 +760,8 @@ TEST(AgcManagerDirectStandaloneTest, AgcMinMicLevelExperimentOutOfRangeBelow) {
test::ScopedFieldTrials field_trial( test::ScopedFieldTrials field_trial(
"WebRTC-Audio-AgcMinMicLevelExperiment/Enabled--1/"); "WebRTC-Audio-AgcMinMicLevelExperiment/Enabled--1/");
std::unique_ptr<AgcManagerDirect> manager = std::unique_ptr<AgcManagerDirect> manager =
CreateAgcManagerDirect(kInitialVolume); CreateAgcManagerDirect(kInitialVolume, kClippedLevelStep,
kClippedRatioThreshold, kClippedWaitFrames);
EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevel); EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevel);
EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), kInitialVolume); EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), kInitialVolume);
} }
@ -755,7 +773,8 @@ TEST(AgcManagerDirectStandaloneTest, AgcMinMicLevelExperimentEnabled50) {
test::ScopedFieldTrials field_trial( test::ScopedFieldTrials field_trial(
"WebRTC-Audio-AgcMinMicLevelExperiment/Enabled-50/"); "WebRTC-Audio-AgcMinMicLevelExperiment/Enabled-50/");
std::unique_ptr<AgcManagerDirect> manager = std::unique_ptr<AgcManagerDirect> manager =
CreateAgcManagerDirect(kInitialVolume); CreateAgcManagerDirect(kInitialVolume, kClippedLevelStep,
kClippedRatioThreshold, kClippedWaitFrames);
EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), 50); EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), 50);
EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), kInitialVolume); EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), kInitialVolume);
} }
@ -768,9 +787,33 @@ TEST(AgcManagerDirectStandaloneTest,
test::ScopedFieldTrials field_trial( test::ScopedFieldTrials field_trial(
"WebRTC-Audio-AgcMinMicLevelExperiment/Enabled-50/"); "WebRTC-Audio-AgcMinMicLevelExperiment/Enabled-50/");
std::unique_ptr<AgcManagerDirect> manager = std::unique_ptr<AgcManagerDirect> manager =
CreateAgcManagerDirect(/*startup_min_level=*/30); CreateAgcManagerDirect(/*startup_min_level=*/30, kClippedLevelStep,
kClippedRatioThreshold, kClippedWaitFrames);
EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), 50); EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), 50);
EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), 50); EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), 50);
} }
// TODO(bugs.webrtc.org/12774): Test the bahavior of `clipped_level_step`.
// TODO(bugs.webrtc.org/12774): Test the bahavior of `clipped_ratio_threshold`.
// TODO(bugs.webrtc.org/12774): Test the bahavior of `clipped_wait_frames`.
// Verifies that configurable clipping parameters are initialized as intended.
TEST(AgcManagerDirectStandaloneTest, ClippingParametersVerified) {
std::unique_ptr<AgcManagerDirect> manager =
CreateAgcManagerDirect(kInitialVolume, kClippedLevelStep,
kClippedRatioThreshold, kClippedWaitFrames);
manager->Initialize();
EXPECT_EQ(manager->clipped_level_step_, kClippedLevelStep);
EXPECT_EQ(manager->clipped_ratio_threshold_, kClippedRatioThreshold);
EXPECT_EQ(manager->clipped_wait_frames_, kClippedWaitFrames);
std::unique_ptr<AgcManagerDirect> manager_custom =
CreateAgcManagerDirect(kInitialVolume,
/*clipped_level_step*/ 10,
/*clipped_ratio_threshold*/ 0.2f,
/*clipped_wait_frames*/ 50);
manager_custom->Initialize();
EXPECT_EQ(manager_custom->clipped_level_step_, 10);
EXPECT_EQ(manager_custom->clipped_ratio_threshold_, 0.2f);
EXPECT_EQ(manager_custom->clipped_wait_frames_, 50);
}
} // namespace webrtc } // namespace webrtc

View File

@ -1918,7 +1918,10 @@ void AudioProcessingImpl::InitializeGainController1() {
config_.gain_controller1.analog_gain_controller.clipped_level_min, config_.gain_controller1.analog_gain_controller.clipped_level_min,
!config_.gain_controller1.analog_gain_controller !config_.gain_controller1.analog_gain_controller
.enable_digital_adaptive, .enable_digital_adaptive,
capture_nonlocked_.split_rate)); capture_nonlocked_.split_rate,
config_.gain_controller1.analog_gain_controller.clipped_level_step,
config_.gain_controller1.analog_gain_controller.clipped_ratio_threshold,
config_.gain_controller1.analog_gain_controller.clipped_wait_frames));
if (re_creation) { if (re_creation) {
submodules_.agc_manager->set_stream_analog_level(stream_analog_level); submodules_.agc_manager->set_stream_analog_level(stream_analog_level);
} }

View File

@ -77,7 +77,11 @@ bool Agc1Config::operator==(const Agc1Config& rhs) const {
analog_lhs.startup_min_volume == analog_rhs.startup_min_volume && analog_lhs.startup_min_volume == analog_rhs.startup_min_volume &&
analog_lhs.clipped_level_min == analog_rhs.clipped_level_min && analog_lhs.clipped_level_min == analog_rhs.clipped_level_min &&
analog_lhs.enable_digital_adaptive == analog_lhs.enable_digital_adaptive ==
analog_rhs.enable_digital_adaptive; analog_rhs.enable_digital_adaptive &&
analog_lhs.clipped_level_step == analog_rhs.clipped_level_step &&
analog_lhs.clipped_ratio_threshold ==
analog_rhs.clipped_ratio_threshold &&
analog_lhs.clipped_wait_frames == analog_rhs.clipped_wait_frames;
} }
bool Agc2Config::AdaptiveDigital::operator==( bool Agc2Config::AdaptiveDigital::operator==(
@ -157,6 +161,12 @@ std::string AudioProcessing::Config::ToString() const {
<< gain_controller1.analog_gain_controller.clipped_level_min << gain_controller1.analog_gain_controller.clipped_level_min
<< ", enable_digital_adaptive: " << ", enable_digital_adaptive: "
<< gain_controller1.analog_gain_controller.enable_digital_adaptive << gain_controller1.analog_gain_controller.enable_digital_adaptive
<< ", clipped_level_step: "
<< gain_controller1.analog_gain_controller.clipped_level_step
<< ", clipped_ratio_threshold: "
<< gain_controller1.analog_gain_controller.clipped_ratio_threshold
<< ", clipped_wait_frames: "
<< gain_controller1.analog_gain_controller.clipped_wait_frames
<< " }}, gain_controller2: { enabled: " << gain_controller2.enabled << " }}, gain_controller2: { enabled: " << gain_controller2.enabled
<< ", fixed_digital: { gain_db: " << ", fixed_digital: { gain_db: "
<< gain_controller2.fixed_digital.gain_db << gain_controller2.fixed_digital.gain_db

View File

@ -59,9 +59,9 @@ class CustomProcessing;
// //
// Must be provided through AudioProcessingBuilder().Create(config). // Must be provided through AudioProcessingBuilder().Create(config).
#if defined(WEBRTC_CHROMIUM_BUILD) #if defined(WEBRTC_CHROMIUM_BUILD)
static const int kAgcStartupMinVolume = 85; static constexpr int kAgcStartupMinVolume = 85;
#else #else
static const int kAgcStartupMinVolume = 0; static constexpr int kAgcStartupMinVolume = 0;
#endif // defined(WEBRTC_CHROMIUM_BUILD) #endif // defined(WEBRTC_CHROMIUM_BUILD)
static constexpr int kClippedLevelMin = 70; static constexpr int kClippedLevelMin = 70;
@ -334,6 +334,15 @@ class RTC_EXPORT AudioProcessing : public rtc::RefCountInterface {
// clipping. // clipping.
int clipped_level_min = kClippedLevelMin; int clipped_level_min = kClippedLevelMin;
bool enable_digital_adaptive = true; bool enable_digital_adaptive = true;
// Amount the microphone level is lowered with every clipping event.
// Limited to (0, 255].
int clipped_level_step = 15;
// Proportion of clipped samples required to declare a clipping event.
// Limited to (0.f, 1.f).
float clipped_ratio_threshold = 0.1f;
// Time in frames to wait after a clipping event before checking again.
// Limited to values higher than 0.
int clipped_wait_frames = 300;
} analog_gain_controller; } analog_gain_controller;
} gain_controller1; } gain_controller1;