Add generic input volume controller test for both AGC1 and AGC2

Make sure that the input volume controller implementations exhibit
the adaptive behavior regardless of the sample rate and the number
of channels. The newly added tests check that:
- a downward adjustment takes place with clipping input
- an upward adjustment takes place with a too low speech level
- a downward adjustment takes place with a too high speech level

Bug: webrtc:14761
Change-Id: I1795e74c5f219e15107e928ebaca2bfa75214526
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/287301
Commit-Queue: Alessio Bazzica <alessiob@webrtc.org>
Reviewed-by: Hanna Silen <silen@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38930}
This commit is contained in:
Alessio Bazzica 2022-12-20 14:36:29 +01:00 committed by WebRTC LUCI CQ
parent ed0dd8e419
commit 6b7834c14f
2 changed files with 138 additions and 0 deletions

View file

@ -43,6 +43,7 @@ constexpr int kMinMicLevel = 12;
constexpr int kClippedLevelStep = 15;
constexpr float kClippedRatioThreshold = 0.1f;
constexpr int kClippedWaitFrames = 300;
constexpr float kLowSpeechProbability = 0.1f;
constexpr float kHighSpeechProbability = 0.7f;
constexpr float kSpeechLevelDbfs = -25.0f;
@ -2113,4 +2114,71 @@ TEST_P(AgcManagerDirectParametrizedTest, NonEmptyRmsErrorOverrideHasEffect) {
EXPECT_EQ(manager_1.voice_probability(), manager_2.voice_probability());
}
class AgcManagerDirectChannelSampleRateTest
: public ::testing::TestWithParam<std::tuple<int, int>> {
protected:
int GetNumChannels() const { return std::get<0>(GetParam()); }
int GetSampleRateHz() const { return std::get<1>(GetParam()); }
};
TEST_P(AgcManagerDirectChannelSampleRateTest, CheckIsAlive) {
const int num_channels = GetNumChannels();
const int sample_rate_hz = GetSampleRateHz();
constexpr AnalogAgcConfig kConfig{.enabled = true,
.clipping_predictor{.enabled = true}};
AgcManagerDirect manager(num_channels, kConfig);
manager.Initialize();
AudioBuffer buffer(sample_rate_hz, num_channels, sample_rate_hz, num_channels,
sample_rate_hz, num_channels);
constexpr int kStartupVolume = 100;
int applied_initial_volume = kStartupVolume;
// Trigger a downward adaptation with clipping.
WriteAudioBufferSamples(/*samples_value=*/0.0f, /*clipped_ratio=*/0.5f,
buffer);
const int initial_volume1 = applied_initial_volume;
for (int i = 0; i < 400; ++i) {
manager.set_stream_analog_level(applied_initial_volume);
manager.AnalyzePreProcess(buffer);
manager.Process(buffer, kLowSpeechProbability,
/*speech_level_dbfs=*/-20.0f);
applied_initial_volume = manager.recommended_analog_level();
}
ASSERT_LT(manager.recommended_analog_level(), initial_volume1);
// Fill in audio that does not clip.
WriteAudioBufferSamples(/*samples_value=*/1234.5f, /*clipped_ratio=*/0.0f,
buffer);
// Trigger an upward adaptation.
const int initial_volume2 = manager.recommended_analog_level();
for (int i = 0; i < kConfig.clipped_wait_frames; ++i) {
manager.set_stream_analog_level(applied_initial_volume);
manager.AnalyzePreProcess(buffer);
manager.Process(buffer, kHighSpeechProbability,
/*speech_level_dbfs=*/-65.0f);
applied_initial_volume = manager.recommended_analog_level();
}
EXPECT_GT(manager.recommended_analog_level(), initial_volume2);
// Trigger a downward adaptation.
const int initial_volume = manager.recommended_analog_level();
for (int i = 0; i < 100; ++i) {
manager.set_stream_analog_level(applied_initial_volume);
manager.AnalyzePreProcess(buffer);
manager.Process(buffer, kHighSpeechProbability,
/*speech_level_dbfs=*/-5.0f);
applied_initial_volume = manager.recommended_analog_level();
}
EXPECT_LT(manager.recommended_analog_level(), initial_volume);
}
INSTANTIATE_TEST_SUITE_P(
,
AgcManagerDirectChannelSampleRateTest,
::testing::Combine(::testing::Values(1, 2, 3, 6),
::testing::Values(8000, 16000, 32000, 48000)));
} // namespace webrtc

View file

@ -325,6 +325,76 @@ class InputVolumeControllerTestHelper {
InputVolumeController controller;
};
class InputVolumeControllerChannelSampleRateTest
: public ::testing::TestWithParam<std::tuple<int, int>> {
protected:
int GetNumChannels() const { return std::get<0>(GetParam()); }
int GetSampleRateHz() const { return std::get<1>(GetParam()); }
};
TEST_P(InputVolumeControllerChannelSampleRateTest, CheckIsAlive) {
const int num_channels = GetNumChannels();
const int sample_rate_hz = GetSampleRateHz();
constexpr InputVolumeController::Config kConfig{.enable_clipping_predictor =
true};
InputVolumeController controller(num_channels, kConfig);
controller.Initialize();
AudioBuffer buffer(sample_rate_hz, num_channels, sample_rate_hz, num_channels,
sample_rate_hz, num_channels);
constexpr int kStartupVolume = 100;
int applied_initial_volume = kStartupVolume;
// Trigger a downward adaptation with clipping.
constexpr int kLevelWithinTargetDbfs =
(kConfig.target_range_min_dbfs + kConfig.target_range_max_dbfs) / 2;
WriteAlternatingAudioBufferSamples(/*samples_value=*/kMaxSample, buffer);
const int initial_volume1 = applied_initial_volume;
for (int i = 0; i < 400; ++i) {
controller.AnalyzeInputAudio(applied_initial_volume, buffer);
auto recommended_input_volume = controller.RecommendInputVolume(
kLowSpeechProbability,
/*speech_level_dbfs=*/kLevelWithinTargetDbfs);
ASSERT_TRUE(recommended_input_volume.has_value());
applied_initial_volume = *recommended_input_volume;
}
ASSERT_LT(controller.recommended_input_volume(), initial_volume1);
// Fill in audio that does not clip.
WriteAlternatingAudioBufferSamples(/*samples_value=*/1234.5f, buffer);
// Trigger an upward adaptation.
const int initial_volume2 = controller.recommended_input_volume();
for (int i = 0; i < kConfig.clipped_wait_frames; ++i) {
controller.AnalyzeInputAudio(applied_initial_volume, buffer);
auto recommended_input_volume = controller.RecommendInputVolume(
kHighSpeechProbability,
/*speech_level_dbfs=*/kConfig.target_range_min_dbfs - 5);
ASSERT_TRUE(recommended_input_volume.has_value());
applied_initial_volume = *recommended_input_volume;
}
EXPECT_GT(controller.recommended_input_volume(), initial_volume2);
// Trigger a downward adaptation.
const int initial_volume = controller.recommended_input_volume();
for (int i = 0; i < kConfig.update_input_volume_wait_frames; ++i) {
controller.AnalyzeInputAudio(applied_initial_volume, buffer);
auto recommended_input_volume = controller.RecommendInputVolume(
kHighSpeechProbability,
/*speech_level_dbfs=*/kConfig.target_range_max_dbfs + 5);
ASSERT_TRUE(recommended_input_volume.has_value());
applied_initial_volume = *recommended_input_volume;
}
EXPECT_LT(controller.recommended_input_volume(), initial_volume);
}
INSTANTIATE_TEST_SUITE_P(
,
InputVolumeControllerChannelSampleRateTest,
::testing::Combine(::testing::Values(1, 2, 3, 6),
::testing::Values(8000, 16000, 32000, 48000)));
class InputVolumeControllerParametrizedTest
: public ::testing::TestWithParam<int> {};