AGC2: retuning and large refactoring

- Bug fix: the desired initial gain quickly dropped to 0 dB hence
  starting a call with a too low level
- New tuning to make AGC2 more robust to VAD mistakes
- Smarter max gain increase speed: to deal with an increased threshold
  of adjacent speech frames, the gain applier temporarily allows a
  faster gain increase to deal with a longer time spent waiting for
  enough speech frames in a row to be observed
- Saturation protector isolated from `AdaptiveModeLevelEstimator` to
  simplify the unit tests for the latter (non bit-exact change)
- AGC2 adaptive digital config: unnecessary params deprecated
- Code readability improvements
- Data dumps clean-up and better naming

Bug: webrtc:7494
Change-Id: I4e36059bdf2566cc2a7e1a7e95b7430ba9ae9844
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/215140
Commit-Queue: Alessio Bazzica <alessiob@webrtc.org>
Reviewed-by: Jesus de Vicente Pena <devicentepena@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33736}
This commit is contained in:
Alessio Bazzica
2021-04-14 19:09:17 +02:00
committed by Commit Bot
parent d28434bd3f
commit 980c4601e1
29 changed files with 990 additions and 941 deletions

View File

@ -11,6 +11,7 @@
#include "modules/audio_processing/gain_controller2.h"
#include <algorithm>
#include <cmath>
#include <memory>
#include "api/array_view.h"
@ -68,7 +69,8 @@ std::unique_ptr<GainController2> CreateAgc2FixedDigitalMode(
return agc2;
}
float GainAfterProcessingFile(GainController2* gain_controller) {
float GainDbAfterProcessingFile(GainController2& gain_controller,
int max_duration_ms) {
// Set up an AudioBuffer to be filled from the speech file.
constexpr size_t kStereo = 2u;
const StreamConfig capture_config(AudioProcessing::kSampleRate48kHz, kStereo,
@ -82,24 +84,29 @@ float GainAfterProcessingFile(GainController2* gain_controller) {
std::vector<float> capture_input(capture_config.num_frames() *
capture_config.num_channels());
// The file should contain at least this many frames. Every iteration, we put
// a frame through the gain controller.
const int kNumFramesToProcess = 100;
for (int frame_no = 0; frame_no < kNumFramesToProcess; ++frame_no) {
// Process the input file which must be long enough to cover
// `max_duration_ms`.
RTC_DCHECK_GT(max_duration_ms, 0);
const int num_frames = rtc::CheckedDivExact(max_duration_ms, 10);
for (int i = 0; i < num_frames; ++i) {
ReadFloatSamplesFromStereoFile(capture_config.num_frames(),
capture_config.num_channels(), &capture_file,
capture_input);
test::CopyVectorToAudioBuffer(capture_config, capture_input, &ab);
gain_controller->Process(&ab);
gain_controller.Process(&ab);
}
// Send in a last frame with values constant 1 (It's low enough to detect high
// gain, and for ease of computation). The applied gain is the result.
// Send in a last frame with minimum dBFS level.
constexpr float sample_value = 1.f;
SetAudioBufferSamples(sample_value, &ab);
gain_controller->Process(&ab);
return ab.channels()[0][0];
gain_controller.Process(&ab);
// Measure the RMS level after processing.
float rms = 0.0f;
for (size_t i = 0; i < capture_config.num_frames(); ++i) {
rms += ab.channels()[0][i] * ab.channels()[0][i];
}
// Return the applied gain in dB.
return 20.0f * std::log10(std::sqrt(rms / capture_config.num_frames()));
}
} // namespace
@ -324,34 +331,20 @@ INSTANTIATE_TEST_SUITE_P(
48000,
true)));
TEST(GainController2, UsageSaturationMargin) {
// Checks that the gain applied at the end of a PCM samples file is close to the
// expected value.
TEST(GainController2, CheckGainAdaptiveDigital) {
constexpr float kExpectedGainDb = 4.3f;
constexpr float kToleranceDb = 0.5f;
GainController2 gain_controller2;
gain_controller2.Initialize(AudioProcessing::kSampleRate48kHz);
AudioProcessing::Config::GainController2 config;
// Check that samples are not amplified as much when extra margin is
// high. They should not be amplified at all, but only after convergence. GC2
// starts with a gain, and it takes time until it's down to 0 dB.
config.fixed_digital.gain_db = 0.f;
config.adaptive_digital.enabled = true;
config.adaptive_digital.extra_saturation_margin_db = 50.f;
gain_controller2.ApplyConfig(config);
EXPECT_LT(GainAfterProcessingFile(&gain_controller2), 2.f);
}
TEST(GainController2, UsageNoSaturationMargin) {
GainController2 gain_controller2;
gain_controller2.Initialize(AudioProcessing::kSampleRate48kHz);
AudioProcessing::Config::GainController2 config;
// Check that some gain is applied if there is no margin.
config.fixed_digital.gain_db = 0.f;
config.adaptive_digital.enabled = true;
config.adaptive_digital.extra_saturation_margin_db = 0.f;
gain_controller2.ApplyConfig(config);
EXPECT_GT(GainAfterProcessingFile(&gain_controller2), 1.9f);
EXPECT_NEAR(
GainDbAfterProcessingFile(gain_controller2, /*max_duration_ms=*/2000),
kExpectedGainDb, kToleranceDb);
}
} // namespace test