Prepare AGC2 for analog gain changes.
1. Adds support for Reset calls in AGC2. The AGC will be reset during
analog gain changes.
2. Allows AdaptiveModeLevelEstimator to return estimates > 0. This can
happen if the signal gain is too high. It's needed for letting the
analog AGC know that the gain is too high.
Bug: webrtc:7494
Change-Id: I38def17c21cc01c36aaea79a2401d8c2f289407b
Reviewed-on: https://webrtc-review.googlesource.com/79360
Commit-Queue: Alex Loiko <aleloi@webrtc.org>
Reviewed-by: Ivo Creusen <ivoc@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23805}diff --git a/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc b/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc
index f5b6b91..ca6ec5d 100644
--- a/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc
+++ b/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc
@@ -76,8 +76,9 @@
float input_noise_level_dbfs,
const VadWithLevel::LevelAndProbability vad_result,
AudioFrameView<float> float_frame) {
+ input_level_dbfs = std::min(input_level_dbfs, 0.f);
+
RTC_DCHECK_GE(input_level_dbfs, -150.f);
- RTC_DCHECK_LE(input_level_dbfs, 0.f);
RTC_DCHECK_GE(float_frame.num_channels(), 1);
RTC_DCHECK_GE(float_frame.samples_per_channel(), 1);
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 860da00..ea9e5c7 100644
--- a/modules/audio_processing/agc2/adaptive_digital_gain_applier_unittest.cc
+++ b/modules/audio_processing/agc2/adaptive_digital_gain_applier_unittest.cc
@@ -175,4 +175,14 @@
}
}
}
+
+TEST(AutomaticGainController2GainApplier, CanHandlePositiveSpeechLevels) {
+ ApmDataDumper apm_data_dumper(0);
+ AdaptiveDigitalGainApplier gain_applier(&apm_data_dumper);
+
+ // Make one call with positive audio level values and settings.
+ VectorFloatFrame fake_audio(2, 480, 10000.f);
+ gain_applier.Process(5.0f, kNoNoiseDbfs, kVadSpeech,
+ fake_audio.float_frame_view());
+}
} // namespace webrtc
diff --git a/modules/audio_processing/agc2/adaptive_mode_level_estimator.cc b/modules/audio_processing/agc2/adaptive_mode_level_estimator.cc
index 6aa2e91..b670f4b 100644
--- a/modules/audio_processing/agc2/adaptive_mode_level_estimator.cc
+++ b/modules/audio_processing/agc2/adaptive_mode_level_estimator.cc
@@ -56,7 +56,15 @@
float AdaptiveModeLevelEstimator::LatestLevelEstimate() const {
return rtc::SafeClamp<float>(
last_estimate_with_offset_dbfs_ + saturation_protector_.LastMargin(),
- -90.f, 0.f);
+ -90.f, 30.f);
+}
+
+void AdaptiveModeLevelEstimator::Reset() {
+ buffer_size_ms_ = 0;
+ last_estimate_with_offset_dbfs_ = kInitialSpeechLevelEstimateDbfs;
+ estimate_numerator_ = 0.f;
+ estimate_denominator_ = 0.f;
+ saturation_protector_.Reset();
}
void AdaptiveModeLevelEstimator::DebugDumpEstimate() {
diff --git a/modules/audio_processing/agc2/adaptive_mode_level_estimator.h b/modules/audio_processing/agc2/adaptive_mode_level_estimator.h
index 186c59b..5ca7c55 100644
--- a/modules/audio_processing/agc2/adaptive_mode_level_estimator.h
+++ b/modules/audio_processing/agc2/adaptive_mode_level_estimator.h
@@ -22,6 +22,7 @@
explicit AdaptiveModeLevelEstimator(ApmDataDumper* apm_data_dumper);
void UpdateEstimation(const VadWithLevel::LevelAndProbability& vad_data);
float LatestLevelEstimate() const;
+ void Reset();
private:
void DebugDumpEstimate();
diff --git a/modules/audio_processing/agc2/adaptive_mode_level_estimator_unittest.cc b/modules/audio_processing/agc2/adaptive_mode_level_estimator_unittest.cc
index 71909d0..1915ce2 100644
--- a/modules/audio_processing/agc2/adaptive_mode_level_estimator_unittest.cc
+++ b/modules/audio_processing/agc2/adaptive_mode_level_estimator_unittest.cc
@@ -76,7 +76,7 @@
ApmDataDumper apm_data_dumper(0);
AdaptiveModeLevelEstimator level_estimator(&apm_data_dumper);
- // Run for one 'window size' interval
+ // Run for one 'window size' interval.
constexpr float kInitialSpeechRmsDbfs = -30.f;
RunOnConstantLevel(
kFullBufferSizeMs / kFrameDurationMs,
@@ -88,7 +88,7 @@
// Run for one half 'window size' interval. This should not be enough to
// adapt.
constexpr float kDifferentSpeechRmsDbfs = -10.f;
- // It should at most differ by 25% after one 'window size' interval.
+ // It should at most differ by 25% after one half 'window size' interval.
const float kMaxDifferenceDb =
0.25 * std::abs(kDifferentSpeechRmsDbfs - kInitialSpeechRmsDbfs);
RunOnConstantLevel(
@@ -109,7 +109,41 @@
kDifferentSpeechRmsDbfs),
&level_estimator);
EXPECT_NEAR(level_estimator.LatestLevelEstimate(), kDifferentSpeechRmsDbfs,
- kMaxDifferenceDb);
+ kMaxDifferenceDb * 0.5f);
+}
+
+TEST(AutomaticGainController2AdaptiveModeLevelEstimator,
+ ResetGivesFastAdaptation) {
+ ApmDataDumper apm_data_dumper(0);
+ AdaptiveModeLevelEstimator level_estimator(&apm_data_dumper);
+
+ // Run the level estimator for one window size interval. This gives time to
+ // adapt.
+ constexpr float kInitialSpeechRmsDbfs = -30.f;
+ RunOnConstantLevel(
+ kFullBufferSizeMs / kFrameDurationMs,
+ VadWithLevel::LevelAndProbability(
+ 1.f, kInitialSpeechRmsDbfs - kInitialSaturationMarginDb,
+ kInitialSpeechRmsDbfs),
+ &level_estimator);
+
+ constexpr float kDifferentSpeechRmsDbfs = -10.f;
+ // Reset and run one half window size interval.
+ level_estimator.Reset();
+
+ RunOnConstantLevel(
+ kFullBufferSizeMs / kFrameDurationMs / 2,
+ VadWithLevel::LevelAndProbability(
+ 1.f, kDifferentSpeechRmsDbfs - kInitialSaturationMarginDb,
+ kDifferentSpeechRmsDbfs),
+ &level_estimator);
+
+ // The level should be close to 'kDifferentSpeechRmsDbfs'.
+ const float kMaxDifferenceDb =
+ 0.1f * std::abs(kDifferentSpeechRmsDbfs - kInitialSpeechRmsDbfs);
+ EXPECT_LT(
+ std::abs(kDifferentSpeechRmsDbfs - level_estimator.LatestLevelEstimate()),
+ kMaxDifferenceDb);
}
} // namespace webrtc
diff --git a/modules/audio_processing/agc2/saturation_protector.cc b/modules/audio_processing/agc2/saturation_protector.cc
index 216e1b6..dc9be47 100644
--- a/modules/audio_processing/agc2/saturation_protector.cc
+++ b/modules/audio_processing/agc2/saturation_protector.cc
@@ -80,6 +80,10 @@
return last_margin_;
}
+void SaturationProtector::Reset() {
+ peak_enveloper_ = PeakEnveloper();
+}
+
void SaturationProtector::DebugDumpEstimate() const {
apm_data_dumper_->DumpRaw(
"agc2_adaptive_saturation_protector_delayed_peak_dbfs",
diff --git a/modules/audio_processing/agc2/saturation_protector.h b/modules/audio_processing/agc2/saturation_protector.h
index 3a796fa..3f207da 100644
--- a/modules/audio_processing/agc2/saturation_protector.h
+++ b/modules/audio_processing/agc2/saturation_protector.h
@@ -35,6 +35,9 @@
// detected.
float LastMargin() const;
+ // Resets the internal memory.
+ void Reset();
+
void DebugDumpEstimate() const;
private: