AGC2 adaptive digital dry run mode
Add the option to run the adaptive digital controller of AGC2 without
side-effects - i.e., no gain applied.
Tested: adapation verified during a video call in chromium
Bug: webrtc:7494
Change-Id: I4776f6012907d76a17a3bca89991da97dc38657f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/215964
Commit-Queue: Alessio Bazzica <alessiob@webrtc.org>
Reviewed-by: Per Ã…hgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33875}
diff --git a/modules/audio_processing/agc2/adaptive_agc.cc b/modules/audio_processing/agc2/adaptive_agc.cc
index 8bf192e..3fc9008 100644
--- a/modules/audio_processing/agc2/adaptive_agc.cc
+++ b/modules/audio_processing/agc2/adaptive_agc.cc
@@ -25,10 +25,6 @@
using NoiseEstimatorType =
AudioProcessing::Config::GainController2::NoiseEstimator;
-constexpr int kGainApplierAdjacentSpeechFramesThreshold = 1;
-constexpr float kMaxGainChangePerSecondDb = 3.0f;
-constexpr float kMaxOutputNoiseLevelDbfs = -50.0f;
-
// Detects the available CPU features and applies any kill-switches.
AvailableCpuFeatures GetAllowedCpuFeatures(
const AdaptiveDigitalConfig& config) {
@@ -56,29 +52,8 @@
}
}
-constexpr NoiseEstimatorType kDefaultNoiseLevelEstimatorType =
- NoiseEstimatorType::kNoiseFloor;
-
} // namespace
-AdaptiveAgc::AdaptiveAgc(ApmDataDumper* apm_data_dumper)
- : speech_level_estimator_(apm_data_dumper),
- gain_controller_(apm_data_dumper,
- kGainApplierAdjacentSpeechFramesThreshold,
- kMaxGainChangePerSecondDb,
- kMaxOutputNoiseLevelDbfs),
- apm_data_dumper_(apm_data_dumper),
- noise_level_estimator_(
- CreateNoiseLevelEstimator(kDefaultNoiseLevelEstimatorType,
- apm_data_dumper)),
- saturation_protector_(
- CreateSaturationProtector(kSaturationProtectorInitialHeadroomDb,
- kSaturationProtectorExtraHeadroomDb,
- kGainApplierAdjacentSpeechFramesThreshold,
- apm_data_dumper)) {
- RTC_DCHECK(apm_data_dumper);
-}
-
AdaptiveAgc::AdaptiveAgc(ApmDataDumper* apm_data_dumper,
const AdaptiveDigitalConfig& config)
: speech_level_estimator_(apm_data_dumper,
@@ -87,7 +62,8 @@
gain_controller_(apm_data_dumper,
config.adjacent_speech_frames_threshold,
config.max_gain_change_db_per_second,
- config.max_output_noise_level_dbfs),
+ config.max_output_noise_level_dbfs,
+ config.dry_run),
apm_data_dumper_(apm_data_dumper),
noise_level_estimator_(
CreateNoiseLevelEstimator(config.noise_estimator, apm_data_dumper)),
@@ -106,6 +82,10 @@
AdaptiveAgc::~AdaptiveAgc() = default;
+void AdaptiveAgc::Initialize(int sample_rate_hz, int num_channels) {
+ gain_controller_.Initialize(sample_rate_hz, num_channels);
+}
+
void AdaptiveAgc::Process(AudioFrameView<float> frame, float limiter_envelope) {
AdaptiveDigitalGainApplier::FrameInfo info;
diff --git a/modules/audio_processing/agc2/adaptive_agc.h b/modules/audio_processing/agc2/adaptive_agc.h
index fe81444..43c7787 100644
--- a/modules/audio_processing/agc2/adaptive_agc.h
+++ b/modules/audio_processing/agc2/adaptive_agc.h
@@ -25,19 +25,21 @@
class ApmDataDumper;
// Adaptive digital gain controller.
-// TODO(crbug.com/webrtc/7494): Unify with `AdaptiveDigitalGainApplier`.
+// TODO(crbug.com/webrtc/7494): Rename to `AdaptiveDigitalGainController`.
class AdaptiveAgc {
public:
- explicit AdaptiveAgc(ApmDataDumper* apm_data_dumper);
- // TODO(crbug.com/webrtc/7494): Remove ctor above.
AdaptiveAgc(
ApmDataDumper* apm_data_dumper,
const AudioProcessing::Config::GainController2::AdaptiveDigital& config);
~AdaptiveAgc();
+ void Initialize(int sample_rate_hz, int num_channels);
+
+ // TODO(crbug.com/webrtc/7494): Add `SetLimiterEnvelope()`.
+
// Analyzes `frame` and applies a digital adaptive gain to it. Takes into
// account the envelope measured by the limiter.
- // TODO(crbug.com/webrtc/7494): Make the class depend on the limiter.
+ // TODO(crbug.com/webrtc/7494): Remove `limiter_envelope`.
void Process(AudioFrameView<float> frame, float limiter_envelope);
// Handles a gain change applied to the input signal (e.g., analog gain).
diff --git a/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc b/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc
index 8a8a7fd..e59b110 100644
--- a/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc
+++ b/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc
@@ -92,13 +92,28 @@
max_gain_increase_db);
}
+// Copies the (multichannel) audio samples from `src` into `dst`.
+void CopyAudio(AudioFrameView<const float> src,
+ std::vector<std::vector<float>>& dst) {
+ RTC_DCHECK_GT(src.num_channels(), 0);
+ RTC_DCHECK_GT(src.samples_per_channel(), 0);
+ RTC_DCHECK_EQ(dst.size(), src.num_channels());
+ for (size_t c = 0; c < src.num_channels(); ++c) {
+ rtc::ArrayView<const float> channel_view = src.channel(c);
+ RTC_DCHECK_EQ(channel_view.size(), src.samples_per_channel());
+ RTC_DCHECK_EQ(dst[c].size(), src.samples_per_channel());
+ std::copy(channel_view.begin(), channel_view.end(), dst[c].begin());
+ }
+}
+
} // namespace
AdaptiveDigitalGainApplier::AdaptiveDigitalGainApplier(
ApmDataDumper* apm_data_dumper,
int adjacent_speech_frames_threshold,
float max_gain_change_db_per_second,
- float max_output_noise_level_dbfs)
+ float max_output_noise_level_dbfs,
+ bool dry_run)
: apm_data_dumper_(apm_data_dumper),
gain_applier_(
/*hard_clip_samples=*/false,
@@ -107,13 +122,39 @@
max_gain_change_db_per_10ms_(max_gain_change_db_per_second *
kFrameDurationMs / 1000.f),
max_output_noise_level_dbfs_(max_output_noise_level_dbfs),
+ dry_run_(dry_run),
calls_since_last_gain_log_(0),
frames_to_gain_increase_allowed_(adjacent_speech_frames_threshold_),
last_gain_db_(kInitialAdaptiveDigitalGainDb) {
- RTC_DCHECK_GT(max_gain_change_db_per_second, 0.f);
+ RTC_DCHECK_GT(max_gain_change_db_per_second, 0.0f);
RTC_DCHECK_GE(frames_to_gain_increase_allowed_, 1);
- RTC_DCHECK_GE(max_output_noise_level_dbfs_, -90.f);
- RTC_DCHECK_LE(max_output_noise_level_dbfs_, 0.f);
+ RTC_DCHECK_GE(max_output_noise_level_dbfs_, -90.0f);
+ RTC_DCHECK_LE(max_output_noise_level_dbfs_, 0.0f);
+ Initialize(/*sample_rate_hz=*/48000, /*num_channels=*/1);
+}
+
+void AdaptiveDigitalGainApplier::Initialize(int sample_rate_hz,
+ int num_channels) {
+ if (!dry_run_) {
+ return;
+ }
+ RTC_DCHECK_GT(sample_rate_hz, 0);
+ RTC_DCHECK_GT(num_channels, 0);
+ int frame_size = rtc::CheckedDivExact(sample_rate_hz, 100);
+ bool sample_rate_changed =
+ dry_run_frame_.empty() || // Handle initialization.
+ dry_run_frame_[0].size() != static_cast<size_t>(frame_size);
+ bool num_channels_changed =
+ dry_run_channels_.size() != static_cast<size_t>(num_channels);
+ if (sample_rate_changed || num_channels_changed) {
+ // Resize the multichannel audio vector and update the channel pointers.
+ dry_run_frame_.resize(num_channels);
+ dry_run_channels_.resize(num_channels);
+ for (int c = 0; c < num_channels; ++c) {
+ dry_run_frame_[c].resize(frame_size);
+ dry_run_channels_[c] = dry_run_frame_[c].data();
+ }
+ }
}
void AdaptiveDigitalGainApplier::Process(const FrameInfo& info,
@@ -174,7 +215,19 @@
gain_applier_.SetGainFactor(
DbToRatio(last_gain_db_ + gain_change_this_frame_db));
}
- gain_applier_.ApplyGain(frame);
+
+ // Modify `frame` only if not running in "dry run" mode.
+ if (!dry_run_) {
+ gain_applier_.ApplyGain(frame);
+ } else {
+ // Copy `frame` so that `ApplyGain()` is called (on a copy).
+ CopyAudio(frame, dry_run_frame_);
+ RTC_DCHECK(!dry_run_channels_.empty());
+ AudioFrameView<float> frame_copy(&dry_run_channels_[0],
+ frame.num_channels(),
+ frame.samples_per_channel());
+ gain_applier_.ApplyGain(frame_copy);
+ }
// Remember that the gain has changed for the next iteration.
last_gain_db_ = last_gain_db_ + gain_change_this_frame_db;
diff --git a/modules/audio_processing/agc2/adaptive_digital_gain_applier.h b/modules/audio_processing/agc2/adaptive_digital_gain_applier.h
index 74220fa..8b58ea0 100644
--- a/modules/audio_processing/agc2/adaptive_digital_gain_applier.h
+++ b/modules/audio_processing/agc2/adaptive_digital_gain_applier.h
@@ -11,6 +11,8 @@
#ifndef MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_DIGITAL_GAIN_APPLIER_H_
#define MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_DIGITAL_GAIN_APPLIER_H_
+#include <vector>
+
#include "modules/audio_processing/agc2/gain_applier.h"
#include "modules/audio_processing/include/audio_frame_view.h"
@@ -37,15 +39,18 @@
// frames must be observed in order to consider the sequence as speech.
// `max_gain_change_db_per_second` limits the adaptation speed (uniformly
// operated across frames). `max_output_noise_level_dbfs` limits the output
- // noise level.
+ // noise level. If `dry_run` is true, `Process()` will not modify the audio.
AdaptiveDigitalGainApplier(ApmDataDumper* apm_data_dumper,
int adjacent_speech_frames_threshold,
float max_gain_change_db_per_second,
- float max_output_noise_level_dbfs);
+ float max_output_noise_level_dbfs,
+ bool dry_run);
AdaptiveDigitalGainApplier(const AdaptiveDigitalGainApplier&) = delete;
AdaptiveDigitalGainApplier& operator=(const AdaptiveDigitalGainApplier&) =
delete;
+ void Initialize(int sample_rate_hz, int num_channels);
+
// Analyzes `info`, updates the digital gain and applies it to a 10 ms
// `frame`. Supports any sample rate supported by APM.
void Process(const FrameInfo& info, AudioFrameView<float> frame);
@@ -57,10 +62,14 @@
const int adjacent_speech_frames_threshold_;
const float max_gain_change_db_per_10ms_;
const float max_output_noise_level_dbfs_;
+ const bool dry_run_;
int calls_since_last_gain_log_;
int frames_to_gain_increase_allowed_;
float last_gain_db_;
+
+ std::vector<std::vector<float>> dry_run_frame_;
+ std::vector<float*> dry_run_channels_;
};
} // namespace webrtc
diff --git a/modules/audio_processing/agc2/adaptive_digital_gain_applier_unittest.cc b/modules/audio_processing/agc2/adaptive_digital_gain_applier_unittest.cc
index ee9cb02..f4a23a9 100644
--- a/modules/audio_processing/agc2/adaptive_digital_gain_applier_unittest.cc
+++ b/modules/audio_processing/agc2/adaptive_digital_gain_applier_unittest.cc
@@ -48,7 +48,8 @@
&apm_data_dumper,
adjacent_speech_frames_threshold,
kMaxGainChangePerSecondDb,
- kMaxOutputNoiseLevelDbfs)) {}
+ kMaxOutputNoiseLevelDbfs,
+ /*dry_run=*/false)) {}
ApmDataDumper apm_data_dumper;
std::unique_ptr<AdaptiveDigitalGainApplier> gain_applier;
};
@@ -67,6 +68,7 @@
TEST(GainController2AdaptiveGainApplier, GainApplierShouldNotCrash) {
GainApplierHelper helper;
+ helper.gain_applier->Initialize(/*sample_rate_hz=*/48000, kStereo);
// Make one call with reasonable audio level values and settings.
VectorFloatFrame fake_audio(kStereo, kFrameLen10ms48kHz, 10000.0f);
AdaptiveDigitalGainApplier::FrameInfo info = kFrameInfo;
@@ -80,6 +82,7 @@
static_cast<int>(kMaxGainDb / kMaxGainChangePerFrameDb) + 10;
GainApplierHelper helper;
+ helper.gain_applier->Initialize(/*sample_rate_hz=*/8000, kMono);
AdaptiveDigitalGainApplier::FrameInfo info = kFrameInfo;
info.speech_level_dbfs = -60.0f;
float applied_gain;
@@ -94,6 +97,7 @@
TEST(GainController2AdaptiveGainApplier, GainDoesNotChangeFast) {
GainApplierHelper helper;
+ helper.gain_applier->Initialize(/*sample_rate_hz=*/8000, kMono);
constexpr float initial_level_dbfs = -25.0f;
// A few extra frames for safety.
@@ -131,6 +135,7 @@
TEST(GainController2AdaptiveGainApplier, GainIsRampedInAFrame) {
GainApplierHelper helper;
+ helper.gain_applier->Initialize(/*sample_rate_hz=*/48000, kMono);
constexpr float initial_level_dbfs = -25.0f;
@@ -155,6 +160,7 @@
TEST(GainController2AdaptiveGainApplier, NoiseLimitsGain) {
GainApplierHelper helper;
+ helper.gain_applier->Initialize(/*sample_rate_hz=*/48000, kMono);
constexpr float initial_level_dbfs = -25.0f;
constexpr int num_initial_frames =
@@ -184,6 +190,7 @@
TEST(GainController2GainApplier, CanHandlePositiveSpeechLevels) {
GainApplierHelper helper;
+ helper.gain_applier->Initialize(/*sample_rate_hz=*/48000, kStereo);
// Make one call with positive audio level values and settings.
VectorFloatFrame fake_audio(kStereo, kFrameLen10ms48kHz, 10000.0f);
@@ -194,6 +201,7 @@
TEST(GainController2GainApplier, AudioLevelLimitsGain) {
GainApplierHelper helper;
+ helper.gain_applier->Initialize(/*sample_rate_hz=*/48000, kMono);
constexpr float initial_level_dbfs = -25.0f;
constexpr int num_initial_frames =
@@ -231,6 +239,7 @@
DoNotIncreaseGainWithTooFewSpeechFrames) {
const int adjacent_speech_frames_threshold = AdjacentSpeechFramesThreshold();
GainApplierHelper helper(adjacent_speech_frames_threshold);
+ helper.gain_applier->Initialize(/*sample_rate_hz=*/48000, kMono);
float prev_gain = 0.0f;
for (int i = 0; i < adjacent_speech_frames_threshold; ++i) {
@@ -248,6 +257,7 @@
TEST_P(AdaptiveDigitalGainApplierTest, IncreaseGainWithEnoughSpeechFrames) {
const int adjacent_speech_frames_threshold = AdjacentSpeechFramesThreshold();
GainApplierHelper helper(adjacent_speech_frames_threshold);
+ helper.gain_applier->Initialize(/*sample_rate_hz=*/48000, kMono);
float prev_gain = 0.0f;
for (int i = 0; i < adjacent_speech_frames_threshold; ++i) {
@@ -269,5 +279,68 @@
AdaptiveDigitalGainApplierTest,
::testing::Values(1, 7, 31));
+// Checks that the input is never modified when running in dry run mode.
+TEST(GainController2GainApplier, DryRunDoesNotChangeInput) {
+ ApmDataDumper apm_data_dumper(0);
+ AdaptiveDigitalGainApplier gain_applier(
+ &apm_data_dumper, /*adjacent_speech_frames_threshold=*/1,
+ kMaxGainChangePerSecondDb, kMaxOutputNoiseLevelDbfs, /*dry_run=*/true);
+ // Simulate an input signal with log speech level.
+ AdaptiveDigitalGainApplier::FrameInfo info = kFrameInfo;
+ info.speech_level_dbfs = -60.0f;
+ // Allow enough time to reach the maximum gain.
+ constexpr int kNumFramesToAdapt =
+ static_cast<int>(kMaxGainDb / kMaxGainChangePerFrameDb) + 10;
+ constexpr float kPcmSamples = 123.456f;
+ // Run the gain applier and check that the PCM samples are not modified.
+ gain_applier.Initialize(/*sample_rate_hz=*/8000, kMono);
+ for (int i = 0; i < kNumFramesToAdapt; ++i) {
+ SCOPED_TRACE(i);
+ VectorFloatFrame fake_audio(kMono, kFrameLen10ms8kHz, kPcmSamples);
+ gain_applier.Process(info, fake_audio.float_frame_view());
+ EXPECT_FLOAT_EQ(fake_audio.float_frame_view().channel(0)[0], kPcmSamples);
+ }
+}
+
+// Checks that no sample is modified before and after the sample rate changes.
+TEST(GainController2GainApplier, DryRunHandlesSampleRateChange) {
+ ApmDataDumper apm_data_dumper(0);
+ AdaptiveDigitalGainApplier gain_applier(
+ &apm_data_dumper, /*adjacent_speech_frames_threshold=*/1,
+ kMaxGainChangePerSecondDb, kMaxOutputNoiseLevelDbfs, /*dry_run=*/true);
+ AdaptiveDigitalGainApplier::FrameInfo info = kFrameInfo;
+ info.speech_level_dbfs = -60.0f;
+ constexpr float kPcmSamples = 123.456f;
+ VectorFloatFrame fake_audio_8k(kMono, kFrameLen10ms8kHz, kPcmSamples);
+ gain_applier.Initialize(/*sample_rate_hz=*/8000, kMono);
+ gain_applier.Process(info, fake_audio_8k.float_frame_view());
+ EXPECT_FLOAT_EQ(fake_audio_8k.float_frame_view().channel(0)[0], kPcmSamples);
+ gain_applier.Initialize(/*sample_rate_hz=*/48000, kMono);
+ VectorFloatFrame fake_audio_48k(kMono, kFrameLen10ms48kHz, kPcmSamples);
+ gain_applier.Process(info, fake_audio_48k.float_frame_view());
+ EXPECT_FLOAT_EQ(fake_audio_48k.float_frame_view().channel(0)[0], kPcmSamples);
+}
+
+// Checks that no sample is modified before and after the number of channels
+// changes.
+TEST(GainController2GainApplier, DryRunHandlesNumChannelsChange) {
+ ApmDataDumper apm_data_dumper(0);
+ AdaptiveDigitalGainApplier gain_applier(
+ &apm_data_dumper, /*adjacent_speech_frames_threshold=*/1,
+ kMaxGainChangePerSecondDb, kMaxOutputNoiseLevelDbfs, /*dry_run=*/true);
+ AdaptiveDigitalGainApplier::FrameInfo info = kFrameInfo;
+ info.speech_level_dbfs = -60.0f;
+ constexpr float kPcmSamples = 123.456f;
+ VectorFloatFrame fake_audio_8k(kMono, kFrameLen10ms8kHz, kPcmSamples);
+ gain_applier.Initialize(/*sample_rate_hz=*/8000, kMono);
+ gain_applier.Process(info, fake_audio_8k.float_frame_view());
+ EXPECT_FLOAT_EQ(fake_audio_8k.float_frame_view().channel(0)[0], kPcmSamples);
+ VectorFloatFrame fake_audio_48k(kStereo, kFrameLen10ms8kHz, kPcmSamples);
+ gain_applier.Initialize(/*sample_rate_hz=*/8000, kStereo);
+ gain_applier.Process(info, fake_audio_48k.float_frame_view());
+ EXPECT_FLOAT_EQ(fake_audio_48k.float_frame_view().channel(0)[0], kPcmSamples);
+ EXPECT_FLOAT_EQ(fake_audio_48k.float_frame_view().channel(1)[0], kPcmSamples);
+}
+
} // namespace
} // namespace webrtc
diff --git a/modules/audio_processing/agc2/agc2_common.h b/modules/audio_processing/agc2/agc2_common.h
index 0f806d3..adb1614 100644
--- a/modules/audio_processing/agc2/agc2_common.h
+++ b/modules/audio_processing/agc2/agc2_common.h
@@ -44,8 +44,6 @@
1.0f - 1.0f / kLevelEstimatorTimeToConfidenceMs;
// Robust VAD probability and speech decisions.
-constexpr int kDefaultVadRnnResetPeriodMs = 1500;
-static_assert(kDefaultVadRnnResetPeriodMs % kFrameDurationMs == 0, "");
constexpr int kDefaultLevelEstimatorAdjacentSpeechFramesThreshold = 12;
// Saturation Protector settings.
diff --git a/modules/audio_processing/agc2/vad_with_level.cc b/modules/audio_processing/agc2/vad_with_level.cc
index 034f2b6..9747ca2 100644
--- a/modules/audio_processing/agc2/vad_with_level.cc
+++ b/modules/audio_processing/agc2/vad_with_level.cc
@@ -67,10 +67,6 @@
} // namespace
-VadLevelAnalyzer::VadLevelAnalyzer()
- : VadLevelAnalyzer(kDefaultVadRnnResetPeriodMs, GetAvailableCpuFeatures()) {
-}
-
VadLevelAnalyzer::VadLevelAnalyzer(int vad_reset_period_ms,
const AvailableCpuFeatures& cpu_features)
: VadLevelAnalyzer(vad_reset_period_ms,
diff --git a/modules/audio_processing/agc2/vad_with_level.h b/modules/audio_processing/agc2/vad_with_level.h
index 7cd93d6..8d2ae45 100644
--- a/modules/audio_processing/agc2/vad_with_level.h
+++ b/modules/audio_processing/agc2/vad_with_level.h
@@ -37,8 +37,6 @@
virtual float ComputeProbability(AudioFrameView<const float> frame) = 0;
};
- // Ctor. Uses the default VAD with the default settings.
- VadLevelAnalyzer();
// Ctor. `vad_reset_period_ms` indicates the period in milliseconds to call
// `VadLevelAnalyzer::Reset()`; it must be equal to or greater than the
// duration of two frames. Uses `cpu_features` to instantiate the default VAD.
diff --git a/modules/audio_processing/agc2/vad_with_level_unittest.cc b/modules/audio_processing/agc2/vad_with_level_unittest.cc
index 99b0136..ec8e476 100644
--- a/modules/audio_processing/agc2/vad_with_level_unittest.cc
+++ b/modules/audio_processing/agc2/vad_with_level_unittest.cc
@@ -71,16 +71,16 @@
const AudioFrameView<const float> view;
};
-TEST(GainController2VadLevelAnalyzer, PeakLevelGreaterThanRmsLevel) {
+TEST(GainController2VadLevelAnalyzer, RmsLessThanPeakLevel) {
+ auto analyzer = CreateVadLevelAnalyzerWithMockVad(
+ /*vad_reset_period_ms=*/1500,
+ /*speech_probabilities=*/{1.0f},
+ /*expected_vad_reset_calls=*/0);
// Handcrafted frame so that the average is lower than the peak value.
FrameWithView frame(1000.0f); // Constant frame.
frame.samples[10] = 2000.0f; // Except for one peak value.
-
- // Compute audio frame levels (the VAD result is ignored).
- VadLevelAnalyzer analyzer;
- auto levels_and_vad_prob = analyzer.AnalyzeFrame(frame.view);
-
- // Compare peak and RMS levels.
+ // Compute audio frame levels.
+ auto levels_and_vad_prob = analyzer->AnalyzeFrame(frame.view);
EXPECT_LT(levels_and_vad_prob.rms_dbfs, levels_and_vad_prob.peak_dbfs);
}
diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc
index 842fd88..225b6b5 100644
--- a/modules/audio_processing/audio_processing_impl.cc
+++ b/modules/audio_processing/audio_processing_impl.cc
@@ -1936,7 +1936,8 @@
submodules_.gain_controller2.reset(new GainController2());
}
- submodules_.gain_controller2->Initialize(proc_fullband_sample_rate_hz());
+ submodules_.gain_controller2->Initialize(proc_fullband_sample_rate_hz(),
+ num_input_channels());
submodules_.gain_controller2->ApplyConfig(config_.gain_controller2);
} else {
submodules_.gain_controller2.reset();
diff --git a/modules/audio_processing/gain_controller2.cc b/modules/audio_processing/gain_controller2.cc
index 9e3e8e7..74b63c9 100644
--- a/modules/audio_processing/gain_controller2.cc
+++ b/modules/audio_processing/gain_controller2.cc
@@ -26,22 +26,26 @@
GainController2::GainController2()
: data_dumper_(rtc::AtomicOps::Increment(&instance_count_)),
gain_applier_(/*hard_clip_samples=*/false,
- /*initial_gain_factor=*/0.f),
+ /*initial_gain_factor=*/0.0f),
limiter_(static_cast<size_t>(48000), &data_dumper_, "Agc2"),
calls_since_last_limiter_log_(0) {
if (config_.adaptive_digital.enabled) {
- adaptive_agc_ = std::make_unique<AdaptiveAgc>(&data_dumper_);
+ adaptive_agc_ =
+ std::make_unique<AdaptiveAgc>(&data_dumper_, config_.adaptive_digital);
}
}
GainController2::~GainController2() = default;
-void GainController2::Initialize(int sample_rate_hz) {
+void GainController2::Initialize(int sample_rate_hz, int num_channels) {
RTC_DCHECK(sample_rate_hz == AudioProcessing::kSampleRate8kHz ||
sample_rate_hz == AudioProcessing::kSampleRate16kHz ||
sample_rate_hz == AudioProcessing::kSampleRate32kHz ||
sample_rate_hz == AudioProcessing::kSampleRate48kHz);
limiter_.SetSampleRate(sample_rate_hz);
+ if (adaptive_agc_) {
+ adaptive_agc_->Initialize(sample_rate_hz, num_channels);
+ }
data_dumper_.InitiateNewSetOfRecordings();
data_dumper_.DumpRaw("sample_rate_hz", sample_rate_hz);
calls_since_last_limiter_log_ = 0;
diff --git a/modules/audio_processing/gain_controller2.h b/modules/audio_processing/gain_controller2.h
index b62890d..ce758c7 100644
--- a/modules/audio_processing/gain_controller2.h
+++ b/modules/audio_processing/gain_controller2.h
@@ -34,7 +34,7 @@
GainController2& operator=(const GainController2&) = delete;
~GainController2();
- void Initialize(int sample_rate_hz);
+ void Initialize(int sample_rate_hz, int num_channels);
void Process(AudioBuffer* audio);
void NotifyAnalogLevel(int level);
diff --git a/modules/audio_processing/gain_controller2_unittest.cc b/modules/audio_processing/gain_controller2_unittest.cc
index 815d58e..85c08bb 100644
--- a/modules/audio_processing/gain_controller2_unittest.cc
+++ b/modules/audio_processing/gain_controller2_unittest.cc
@@ -65,7 +65,7 @@
size_t sample_rate_hz) {
auto agc2 = std::make_unique<GainController2>();
agc2->ApplyConfig(CreateAgc2FixedDigitalModeConfig(fixed_gain_db));
- agc2->Initialize(sample_rate_hz);
+ agc2->Initialize(sample_rate_hz, /*num_channels=*/1);
return agc2;
}
@@ -337,9 +337,10 @@
constexpr float kExpectedGainDb = 4.3f;
constexpr float kToleranceDb = 0.5f;
GainController2 gain_controller2;
- gain_controller2.Initialize(AudioProcessing::kSampleRate48kHz);
+ gain_controller2.Initialize(AudioProcessing::kSampleRate48kHz,
+ /*num_channels=*/1);
AudioProcessing::Config::GainController2 config;
- config.fixed_digital.gain_db = 0.f;
+ config.fixed_digital.gain_db = 0.0f;
config.adaptive_digital.enabled = true;
gain_controller2.ApplyConfig(config);
EXPECT_NEAR(
diff --git a/modules/audio_processing/include/audio_processing.h b/modules/audio_processing/include/audio_processing.h
index 01bb7c3..8072230 100644
--- a/modules/audio_processing/include/audio_processing.h
+++ b/modules/audio_processing/include/audio_processing.h
@@ -358,6 +358,7 @@
} fixed_digital;
struct AdaptiveDigital {
bool enabled = false;
+ bool dry_run = false;
NoiseEstimator noise_estimator = kNoiseFloor;
int vad_reset_period_ms = 1500;
int adjacent_speech_frames_threshold = 12;