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}
This commit is contained in:
Alex Loiko 2018-07-02 17:00:31 +02:00 committed by Commit Bot
parent 5afa61cf15
commit 4d01146f16
7 changed files with 66 additions and 5 deletions

View File

@ -76,8 +76,9 @@ void AdaptiveDigitalGainApplier::Process(
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);

View File

@ -175,4 +175,14 @@ TEST(AutomaticGainController2AdaptiveGainApplier, NoiseLimitsGain) {
}
}
}
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

View File

@ -56,7 +56,15 @@ void AdaptiveModeLevelEstimator::UpdateEstimation(
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() {

View File

@ -22,6 +22,7 @@ class AdaptiveModeLevelEstimator {
explicit AdaptiveModeLevelEstimator(ApmDataDumper* apm_data_dumper);
void UpdateEstimation(const VadWithLevel::LevelAndProbability& vad_data);
float LatestLevelEstimate() const;
void Reset();
private:
void DebugDumpEstimate();

View File

@ -76,7 +76,7 @@ TEST(AutomaticGainController2AdaptiveModeLevelEstimator, TimeToAdapt) {
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 @@ TEST(AutomaticGainController2AdaptiveModeLevelEstimator, TimeToAdapt) {
// 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 @@ TEST(AutomaticGainController2AdaptiveModeLevelEstimator, TimeToAdapt) {
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

View File

@ -80,6 +80,10 @@ float SaturationProtector::LastMargin() const {
return last_margin_;
}
void SaturationProtector::Reset() {
peak_enveloper_ = PeakEnveloper();
}
void SaturationProtector::DebugDumpEstimate() const {
apm_data_dumper_->DumpRaw(
"agc2_adaptive_saturation_protector_delayed_peak_dbfs",

View File

@ -35,6 +35,9 @@ class SaturationProtector {
// detected.
float LastMargin() const;
// Resets the internal memory.
void Reset();
void DebugDumpEstimate() const;
private: