AudioProcessingImpl: Add input volume unit tests
Bug: webrtc:7494 Change-Id: I5a32359cacfb7cd6b610ae13b95f92283c761362 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/275500 Commit-Queue: Hanna Silen <silen@webrtc.org> Reviewed-by: Alessio Bazzica <alessiob@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38132}
This commit is contained in:
parent
50a2a73ed9
commit
c69188d15a
@ -12,7 +12,9 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "absl/types/optional.h"
|
||||||
#include "api/make_ref_counted.h"
|
#include "api/make_ref_counted.h"
|
||||||
#include "api/scoped_refptr.h"
|
#include "api/scoped_refptr.h"
|
||||||
#include "modules/audio_processing/include/audio_processing.h"
|
#include "modules/audio_processing/include/audio_processing.h"
|
||||||
@ -23,6 +25,7 @@
|
|||||||
#include "modules/audio_processing/test/test_utils.h"
|
#include "modules/audio_processing/test/test_utils.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
#include "rtc_base/random.h"
|
#include "rtc_base/random.h"
|
||||||
|
#include "rtc_base/strings/string_builder.h"
|
||||||
#include "test/field_trial.h"
|
#include "test/field_trial.h"
|
||||||
#include "test/gmock.h"
|
#include "test/gmock.h"
|
||||||
#include "test/gtest.h"
|
#include "test/gtest.h"
|
||||||
@ -128,6 +131,123 @@ class TestRenderPreProcessor : public CustomProcessing {
|
|||||||
static constexpr float ProcessSample(float x) { return 2.f * x; }
|
static constexpr float ProcessSample(float x) { return 2.f * x; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Creates a simple `AudioProcessing` instance for APM input volume testing
|
||||||
|
// with analog and digital AGC enabled and minimum volume `startup_min_volume`
|
||||||
|
// at the startup.
|
||||||
|
rtc::scoped_refptr<AudioProcessing> CreateApmForInputVolumeTest(
|
||||||
|
int startup_min_volume) {
|
||||||
|
webrtc::AudioProcessing::Config config;
|
||||||
|
// Enable AGC1 analog.
|
||||||
|
config.gain_controller1.enabled = true;
|
||||||
|
config.gain_controller1.analog_gain_controller.enabled = true;
|
||||||
|
config.gain_controller1.analog_gain_controller.startup_min_volume =
|
||||||
|
startup_min_volume;
|
||||||
|
// Enable AGC2 digital.
|
||||||
|
config.gain_controller2.enabled = true;
|
||||||
|
config.gain_controller2.adaptive_digital.enabled = true;
|
||||||
|
|
||||||
|
auto apm(AudioProcessingBuilder().Create());
|
||||||
|
apm->ApplyConfig(config);
|
||||||
|
return apm;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runs `apm` input processing for volume adjustments for `num_frames` random
|
||||||
|
// frames starting from the volume `initial_volume`. This includes three steps:
|
||||||
|
// 1) Set the input volume 2) Process the stream 3) Set the new recommended
|
||||||
|
// input volume. Returns the new recommended input volume.
|
||||||
|
int ProcessInputVolume(AudioProcessing& apm,
|
||||||
|
int num_frames,
|
||||||
|
int initial_volume) {
|
||||||
|
constexpr int kSampleRateHz = 48000;
|
||||||
|
constexpr int kNumChannels = 1;
|
||||||
|
std::array<float, kSampleRateHz / 100> buffer;
|
||||||
|
float* channel_pointers[] = {buffer.data()};
|
||||||
|
StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
|
||||||
|
/*num_channels=*/kNumChannels);
|
||||||
|
int recommended_input_volume = initial_volume;
|
||||||
|
for (int i = 0; i < num_frames; ++i) {
|
||||||
|
Random random_generator(2341U);
|
||||||
|
RandomizeSampleVector(&random_generator, buffer);
|
||||||
|
|
||||||
|
apm.set_stream_analog_level(recommended_input_volume);
|
||||||
|
apm.ProcessStream(channel_pointers, stream_config, stream_config,
|
||||||
|
channel_pointers);
|
||||||
|
recommended_input_volume = apm.recommended_stream_analog_level();
|
||||||
|
}
|
||||||
|
return recommended_input_volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr char kMinMicLevelFieldTrial[] =
|
||||||
|
"WebRTC-Audio-2ndAgcMinMicLevelExperiment";
|
||||||
|
constexpr int kMinInputVolume = 12;
|
||||||
|
|
||||||
|
std::string GetMinMicLevelExperimentFieldTrial(absl::optional<int> value) {
|
||||||
|
char field_trial_buffer[64];
|
||||||
|
rtc::SimpleStringBuilder builder(field_trial_buffer);
|
||||||
|
if (value.has_value()) {
|
||||||
|
RTC_DCHECK_GE(*value, 0);
|
||||||
|
RTC_DCHECK_LE(*value, 255);
|
||||||
|
builder << kMinMicLevelFieldTrial << "/Enabled-" << *value << "/";
|
||||||
|
} else {
|
||||||
|
builder << kMinMicLevelFieldTrial << "/Disabled/";
|
||||||
|
}
|
||||||
|
return builder.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(webrtc:7494): Remove the fieldtrial from the input volume tests when
|
||||||
|
// "WebRTC-Audio-2ndAgcMinMicLevelExperiment" is removed.
|
||||||
|
class InputVolumeStartupParameterizedTest
|
||||||
|
: public ::testing::TestWithParam<
|
||||||
|
std::tuple<int, int, absl::optional<int>>> {
|
||||||
|
protected:
|
||||||
|
InputVolumeStartupParameterizedTest()
|
||||||
|
: field_trials_(
|
||||||
|
GetMinMicLevelExperimentFieldTrial(std::get<2>(GetParam()))) {}
|
||||||
|
int GetMinStartupVolume() const { return std::get<0>(GetParam()); }
|
||||||
|
int GetStartupVolume() const { return std::get<1>(GetParam()); }
|
||||||
|
int GetMinVolume() const {
|
||||||
|
return std::get<2>(GetParam()).value_or(kMinInputVolume);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
test::ScopedFieldTrials field_trials_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class InputVolumeNotZeroParameterizedTest
|
||||||
|
: public ::testing::TestWithParam<
|
||||||
|
std::tuple<int, int, absl::optional<int>>> {
|
||||||
|
protected:
|
||||||
|
InputVolumeNotZeroParameterizedTest()
|
||||||
|
: field_trials_(
|
||||||
|
GetMinMicLevelExperimentFieldTrial(std::get<2>(GetParam()))) {}
|
||||||
|
int GetStartupVolume() const { return std::get<0>(GetParam()); }
|
||||||
|
int GetVolume() const { return std::get<1>(GetParam()); }
|
||||||
|
int GetMinVolume() const {
|
||||||
|
return std::get<2>(GetParam()).value_or(kMinInputVolume);
|
||||||
|
}
|
||||||
|
bool GetMinMicLevelExperimentEnabled() {
|
||||||
|
return std::get<2>(GetParam()).has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
test::ScopedFieldTrials field_trials_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class InputVolumeZeroParameterizedTest
|
||||||
|
: public ::testing::TestWithParam<std::tuple<int, absl::optional<int>>> {
|
||||||
|
protected:
|
||||||
|
InputVolumeZeroParameterizedTest()
|
||||||
|
: field_trials_(
|
||||||
|
GetMinMicLevelExperimentFieldTrial(std::get<1>(GetParam()))) {}
|
||||||
|
int GetStartupVolume() const { return std::get<0>(GetParam()); }
|
||||||
|
int GetMinVolume() const {
|
||||||
|
return std::get<1>(GetParam()).value_or(kMinInputVolume);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
test::ScopedFieldTrials field_trials_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TEST(AudioProcessingImplTest, AudioParameterChangeTriggersInit) {
|
TEST(AudioProcessingImplTest, AudioParameterChangeTriggersInit) {
|
||||||
@ -813,4 +933,119 @@ TEST(ApmWithSubmodulesExcludedTest, ToggleTransientSuppressor) {
|
|||||||
kNoErr);
|
kNoErr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests that the minimum startup volume is applied at the startup.
|
||||||
|
TEST_P(InputVolumeStartupParameterizedTest,
|
||||||
|
VerifyStartupMinVolumeAppliedAtStartup) {
|
||||||
|
const int applied_startup_input_volume = GetStartupVolume();
|
||||||
|
const int startup_min_volume = GetMinStartupVolume();
|
||||||
|
const int min_volume = std::max(startup_min_volume, GetMinVolume());
|
||||||
|
const int expected_volume =
|
||||||
|
std::max(applied_startup_input_volume, min_volume);
|
||||||
|
auto apm(CreateApmForInputVolumeTest(startup_min_volume));
|
||||||
|
|
||||||
|
const int recommended_input_volume =
|
||||||
|
ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
|
||||||
|
|
||||||
|
ASSERT_EQ(recommended_input_volume, expected_volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that the minimum input volume is applied if the volume is manually
|
||||||
|
// adjusted to a non-zero value only if
|
||||||
|
// "WebRTC-Audio-2ndAgcMinMicLevelExperiment" is enabled.
|
||||||
|
TEST_P(InputVolumeNotZeroParameterizedTest,
|
||||||
|
VerifyMinVolumeMaybeAppliedAfterManualVolumeAdjustments) {
|
||||||
|
constexpr int kStartupMinVolume = 0;
|
||||||
|
const int applied_startup_input_volume = GetStartupVolume();
|
||||||
|
const int applied_input_volume = GetVolume();
|
||||||
|
const int expected_volume = std::max(applied_input_volume, GetMinVolume());
|
||||||
|
auto apm(CreateApmForInputVolumeTest(kStartupMinVolume));
|
||||||
|
|
||||||
|
ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
|
||||||
|
const int recommended_input_volume =
|
||||||
|
ProcessInputVolume(*apm, /*num_frames=*/1, applied_input_volume);
|
||||||
|
|
||||||
|
ASSERT_NE(applied_input_volume, 0);
|
||||||
|
if (GetMinMicLevelExperimentEnabled()) {
|
||||||
|
ASSERT_EQ(recommended_input_volume, expected_volume);
|
||||||
|
} else {
|
||||||
|
ASSERT_EQ(recommended_input_volume, applied_input_volume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that the minimum input volume is not applied if the volume is manually
|
||||||
|
// adjusted to zero.
|
||||||
|
TEST_P(InputVolumeZeroParameterizedTest,
|
||||||
|
VerifyMinVolumeNotAppliedAfterManualVolumeAdjustments) {
|
||||||
|
constexpr int kStartupMinVolume = 0;
|
||||||
|
constexpr int kZeroVolume = 0;
|
||||||
|
const int applied_startup_input_volume = GetStartupVolume();
|
||||||
|
auto apm(CreateApmForInputVolumeTest(kStartupMinVolume));
|
||||||
|
|
||||||
|
const int recommended_input_volume_after_startup =
|
||||||
|
ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
|
||||||
|
const int recommended_input_volume =
|
||||||
|
ProcessInputVolume(*apm, /*num_frames=*/1, kZeroVolume);
|
||||||
|
|
||||||
|
ASSERT_NE(recommended_input_volume, recommended_input_volume_after_startup);
|
||||||
|
ASSERT_EQ(recommended_input_volume, kZeroVolume);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that the minimum input volume is applied if the volume is not zero
|
||||||
|
// before it is automatically adjusted.
|
||||||
|
TEST_P(InputVolumeNotZeroParameterizedTest,
|
||||||
|
VerifyMinVolumeAppliedAfterAutomaticVolumeAdjustments) {
|
||||||
|
constexpr int kStartupMinVolume = 0;
|
||||||
|
const int applied_startup_input_volume = GetStartupVolume();
|
||||||
|
const int applied_input_volume = GetVolume();
|
||||||
|
auto apm(CreateApmForInputVolumeTest(kStartupMinVolume));
|
||||||
|
|
||||||
|
ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
|
||||||
|
const int recommended_input_volume =
|
||||||
|
ProcessInputVolume(*apm, /*num_frames=*/400, applied_input_volume);
|
||||||
|
|
||||||
|
ASSERT_NE(applied_input_volume, 0);
|
||||||
|
if (recommended_input_volume != applied_input_volume) {
|
||||||
|
ASSERT_GE(recommended_input_volume, GetMinVolume());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that the minimum input volume is not applied if the volume is zero
|
||||||
|
// before it is automatically adjusted.
|
||||||
|
TEST_P(InputVolumeZeroParameterizedTest,
|
||||||
|
VerifyMinVolumeNotAppliedAfterAutomaticVolumeAdjustments) {
|
||||||
|
constexpr int kStartupMinVolume = 0;
|
||||||
|
constexpr int kZeroVolume = 0;
|
||||||
|
const int applied_startup_input_volume = GetStartupVolume();
|
||||||
|
auto apm(CreateApmForInputVolumeTest(kStartupMinVolume));
|
||||||
|
|
||||||
|
const int recommended_input_volume_after_startup =
|
||||||
|
ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
|
||||||
|
const int recommended_input_volume =
|
||||||
|
ProcessInputVolume(*apm, /*num_frames=*/400, kZeroVolume);
|
||||||
|
|
||||||
|
ASSERT_NE(recommended_input_volume, recommended_input_volume_after_startup);
|
||||||
|
ASSERT_EQ(recommended_input_volume, kZeroVolume);
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
|
||||||
|
InputVolumeStartupParameterizedTest,
|
||||||
|
::testing::Combine(::testing::Values(0, 5, 15),
|
||||||
|
::testing::Values(0, 5, 30),
|
||||||
|
::testing::Values(absl::nullopt,
|
||||||
|
20)));
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
|
||||||
|
InputVolumeNotZeroParameterizedTest,
|
||||||
|
::testing::Combine(::testing::Values(0, 5, 15),
|
||||||
|
::testing::Values(1, 5, 30),
|
||||||
|
::testing::Values(absl::nullopt,
|
||||||
|
20)));
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
|
||||||
|
InputVolumeZeroParameterizedTest,
|
||||||
|
::testing::Combine(::testing::Values(0, 5, 15),
|
||||||
|
::testing::Values(absl::nullopt,
|
||||||
|
20)));
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user