mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00
APM: Add a field trial for input volume controller
Add a field trial WebRTC-Audio-InputVolumeControllerExperiment and a mechanism to adjust the config accordingly. Pass the additional input volume controller config to GainController2. Bug: webrtc:7494 Change-Id: I3dd624df1f4774cb533417747627995e1f60aa68 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/284101 Reviewed-by: Alessio Bazzica <alessiob@webrtc.org> Reviewed-by: Per Åhgren <peah@webrtc.org> Reviewed-by: Sam Zackrisson <saza@webrtc.org> Commit-Queue: Hanna Silen <silen@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38780}
This commit is contained in:
parent
c19ec96bd7
commit
a6574909e9
7 changed files with 565 additions and 48 deletions
|
@ -193,6 +193,7 @@ rtc_library("audio_processing") {
|
|||
"../../rtc_base:sanitizer",
|
||||
"../../rtc_base:swap_queue",
|
||||
"../../rtc_base:timeutils",
|
||||
"../../rtc_base/experiments:field_trial_parser",
|
||||
"../../rtc_base/synchronization:mutex",
|
||||
"../../rtc_base/system:rtc_export",
|
||||
"../../system_wrappers",
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "modules/audio_processing/logging/apm_data_dumper.h"
|
||||
#include "modules/audio_processing/optionally_built_submodule_creators.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/time_utils.h"
|
||||
#include "rtc_base/trace_event.h"
|
||||
|
@ -144,8 +145,6 @@ void PackRenderAudioBufferForEchoDetector(const AudioBuffer& audio,
|
|||
audio.channels_const()[0] + audio.num_frames());
|
||||
}
|
||||
|
||||
constexpr int kUnspecifiedDataDumpInputVolume = -100;
|
||||
|
||||
// Options for gracefully handling processing errors.
|
||||
enum class FormatErrorOutputOption {
|
||||
kOutputExactCopyOfInput,
|
||||
|
@ -326,6 +325,125 @@ int HandleUnsupportedAudioFormats(const float* const* src,
|
|||
return error_code;
|
||||
}
|
||||
|
||||
const absl::optional<InputVolumeController::Config>
|
||||
GetInputVolumeControllerConfigOverride() {
|
||||
constexpr char kInputVolumeControllerFieldTrial[] =
|
||||
"WebRTC-Audio-InputVolumeControllerExperiment";
|
||||
|
||||
if (!field_trial::IsEnabled(kInputVolumeControllerFieldTrial)) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
constexpr InputVolumeController::Config kDefaultConfig;
|
||||
|
||||
FieldTrialFlag enabled("Enabled", false);
|
||||
FieldTrialConstrained<int> clipped_level_min(
|
||||
"clipped_level_min", kDefaultConfig.clipped_level_min, 0, 255);
|
||||
FieldTrialConstrained<int> clipped_level_step(
|
||||
"clipped_level_step", kDefaultConfig.clipped_level_step, 0, 255);
|
||||
FieldTrialConstrained<double> clipped_ratio_threshold(
|
||||
"clipped_ratio_threshold", kDefaultConfig.clipped_ratio_threshold, 0, 1);
|
||||
FieldTrialConstrained<int> clipped_wait_frames(
|
||||
"clipped_wait_frames", kDefaultConfig.clipped_wait_frames, 0,
|
||||
absl::nullopt);
|
||||
FieldTrialParameter<bool> enable_clipping_predictor(
|
||||
"enable_clipping_predictor", kDefaultConfig.enable_clipping_predictor);
|
||||
FieldTrialConstrained<int> target_range_max_dbfs(
|
||||
"target_range_max_dbfs", kDefaultConfig.target_range_max_dbfs, -90, 30);
|
||||
FieldTrialConstrained<int> target_range_min_dbfs(
|
||||
"target_range_min_dbfs", kDefaultConfig.target_range_min_dbfs, -90, 30);
|
||||
FieldTrialConstrained<int> update_input_volume_wait_frames(
|
||||
"update_input_volume_wait_frames",
|
||||
kDefaultConfig.update_input_volume_wait_frames, 0, absl::nullopt);
|
||||
FieldTrialConstrained<double> speech_probability_threshold(
|
||||
"speech_probability_threshold",
|
||||
kDefaultConfig.speech_probability_threshold, 0, 1);
|
||||
FieldTrialConstrained<double> speech_ratio_threshold(
|
||||
"speech_ratio_threshold", kDefaultConfig.speech_ratio_threshold, 0, 1);
|
||||
|
||||
// Field-trial based override for the input volume controller config.
|
||||
const std::string field_trial_name =
|
||||
field_trial::FindFullName(kInputVolumeControllerFieldTrial);
|
||||
|
||||
ParseFieldTrial({&enabled, &clipped_level_min, &clipped_level_step,
|
||||
&clipped_ratio_threshold, &clipped_wait_frames,
|
||||
&enable_clipping_predictor, &target_range_max_dbfs,
|
||||
&target_range_min_dbfs, &update_input_volume_wait_frames,
|
||||
&speech_probability_threshold, &speech_ratio_threshold},
|
||||
field_trial_name);
|
||||
|
||||
// Checked already by `IsEnabled()` before parsing, therefore always true.
|
||||
RTC_DCHECK(enabled);
|
||||
|
||||
return InputVolumeController::Config{
|
||||
.clipped_level_min = static_cast<int>(clipped_level_min.Get()),
|
||||
.clipped_level_step = static_cast<int>(clipped_level_step.Get()),
|
||||
.clipped_ratio_threshold =
|
||||
static_cast<float>(clipped_ratio_threshold.Get()),
|
||||
.clipped_wait_frames = static_cast<int>(clipped_wait_frames.Get()),
|
||||
.enable_clipping_predictor =
|
||||
static_cast<bool>(enable_clipping_predictor.Get()),
|
||||
.target_range_max_dbfs = static_cast<int>(target_range_max_dbfs.Get()),
|
||||
.target_range_min_dbfs = static_cast<int>(target_range_min_dbfs.Get()),
|
||||
.update_input_volume_wait_frames =
|
||||
static_cast<int>(update_input_volume_wait_frames.Get()),
|
||||
.speech_probability_threshold =
|
||||
static_cast<float>(speech_probability_threshold.Get()),
|
||||
.speech_ratio_threshold =
|
||||
static_cast<float>(speech_ratio_threshold.Get()),
|
||||
};
|
||||
}
|
||||
|
||||
// Switches all gain control to AGC2 if experimenting with input volume
|
||||
// controller.
|
||||
const AudioProcessing::Config AdjustConfig(
|
||||
const AudioProcessing::Config& config,
|
||||
const absl::optional<InputVolumeController::Config>&
|
||||
input_volume_controller_config_override) {
|
||||
const bool analog_agc_enabled =
|
||||
config.gain_controller1.enabled &&
|
||||
(config.gain_controller1.mode ==
|
||||
AudioProcessing::Config::GainController1::kAdaptiveAnalog ||
|
||||
config.gain_controller1.analog_gain_controller.enabled);
|
||||
|
||||
// Do not update the config if none of the analog AGCs is active
|
||||
// regardless of the input volume controller override.
|
||||
if (!analog_agc_enabled ||
|
||||
!input_volume_controller_config_override.has_value()) {
|
||||
return config;
|
||||
}
|
||||
|
||||
const bool hybrid_agc_config_detected =
|
||||
config.gain_controller1.enabled &&
|
||||
config.gain_controller1.analog_gain_controller.enabled &&
|
||||
!config.gain_controller1.analog_gain_controller.enable_digital_adaptive &&
|
||||
config.gain_controller2.enabled &&
|
||||
config.gain_controller2.adaptive_digital.enabled;
|
||||
|
||||
const bool full_agc1_config_detected =
|
||||
config.gain_controller1.enabled &&
|
||||
config.gain_controller1.analog_gain_controller.enabled &&
|
||||
config.gain_controller1.analog_gain_controller.enable_digital_adaptive &&
|
||||
!config.gain_controller2.enabled;
|
||||
|
||||
if (hybrid_agc_config_detected == full_agc1_config_detected ||
|
||||
config.gain_controller2.input_volume_controller.enabled) {
|
||||
RTC_LOG(LS_ERROR) << "Unexpected AGC config: Config not adjusted.";
|
||||
return config;
|
||||
}
|
||||
|
||||
AudioProcessing::Config adjusted_config = config;
|
||||
adjusted_config.gain_controller1.enabled = false;
|
||||
adjusted_config.gain_controller1.analog_gain_controller.enabled = false;
|
||||
adjusted_config.gain_controller2.enabled = true;
|
||||
adjusted_config.gain_controller2.adaptive_digital.enabled = true;
|
||||
adjusted_config.gain_controller2.input_volume_controller.enabled = true;
|
||||
|
||||
return adjusted_config;
|
||||
}
|
||||
|
||||
constexpr int kUnspecifiedDataDumpInputVolume = -100;
|
||||
|
||||
} // namespace
|
||||
|
||||
// Throughout webrtc, it's assumed that success is represented by zero.
|
||||
|
@ -448,6 +566,8 @@ AudioProcessingImpl::AudioProcessingImpl(
|
|||
: data_dumper_(new ApmDataDumper(instance_count_.fetch_add(1) + 1)),
|
||||
use_setup_specific_default_aec3_config_(
|
||||
UseSetupSpecificDefaultAec3Congfig()),
|
||||
input_volume_controller_config_override_(
|
||||
GetInputVolumeControllerConfigOverride()),
|
||||
use_denormal_disabler_(
|
||||
!field_trial::IsEnabled("WebRTC-ApmDenormalDisablerKillSwitch")),
|
||||
transient_suppressor_vad_mode_(GetTransientSuppressorVadMode()),
|
||||
|
@ -456,7 +576,7 @@ AudioProcessingImpl::AudioProcessingImpl(
|
|||
capture_runtime_settings_enqueuer_(&capture_runtime_settings_),
|
||||
render_runtime_settings_enqueuer_(&render_runtime_settings_),
|
||||
echo_control_factory_(std::move(echo_control_factory)),
|
||||
config_(config),
|
||||
config_(AdjustConfig(config, input_volume_controller_config_override_)),
|
||||
submodule_states_(!!capture_post_processor,
|
||||
!!render_pre_processor,
|
||||
!!capture_analyzer),
|
||||
|
@ -490,6 +610,8 @@ AudioProcessingImpl::AudioProcessingImpl(
|
|||
RTC_LOG(LS_INFO) << "Denormal disabler unsupported";
|
||||
}
|
||||
|
||||
RTC_LOG(LS_INFO) << "AudioProcessing: " << config_.ToString();
|
||||
|
||||
// Mark Echo Controller enabled if a factory is injected.
|
||||
capture_nonlocked_.echo_controller_enabled =
|
||||
static_cast<bool>(echo_control_factory_);
|
||||
|
@ -681,46 +803,57 @@ void AudioProcessingImpl::InitializeLocked(const ProcessingConfig& config) {
|
|||
}
|
||||
|
||||
void AudioProcessingImpl::ApplyConfig(const AudioProcessing::Config& config) {
|
||||
RTC_LOG(LS_INFO) << "AudioProcessing::ApplyConfig: " << config.ToString();
|
||||
|
||||
// Run in a single-threaded manner when applying the settings.
|
||||
MutexLock lock_render(&mutex_render_);
|
||||
MutexLock lock_capture(&mutex_capture_);
|
||||
|
||||
// TODO(bugs.webrtc.org/7494): Replace `adjusted_config` with `config` after
|
||||
// "WebRTC-Audio-InputVolumeControllerExperiment" field trial is removed.
|
||||
const auto adjusted_config =
|
||||
AdjustConfig(config, input_volume_controller_config_override_);
|
||||
|
||||
RTC_LOG(LS_INFO) << "AudioProcessing::ApplyConfig: "
|
||||
<< adjusted_config.ToString();
|
||||
|
||||
const bool pipeline_config_changed =
|
||||
config_.pipeline.multi_channel_render !=
|
||||
config.pipeline.multi_channel_render ||
|
||||
adjusted_config.pipeline.multi_channel_render ||
|
||||
config_.pipeline.multi_channel_capture !=
|
||||
config.pipeline.multi_channel_capture ||
|
||||
adjusted_config.pipeline.multi_channel_capture ||
|
||||
config_.pipeline.maximum_internal_processing_rate !=
|
||||
config.pipeline.maximum_internal_processing_rate;
|
||||
adjusted_config.pipeline.maximum_internal_processing_rate;
|
||||
|
||||
const bool aec_config_changed =
|
||||
config_.echo_canceller.enabled != config.echo_canceller.enabled ||
|
||||
config_.echo_canceller.mobile_mode != config.echo_canceller.mobile_mode;
|
||||
config_.echo_canceller.enabled !=
|
||||
adjusted_config.echo_canceller.enabled ||
|
||||
config_.echo_canceller.mobile_mode !=
|
||||
adjusted_config.echo_canceller.mobile_mode;
|
||||
|
||||
const bool agc1_config_changed =
|
||||
config_.gain_controller1 != config.gain_controller1;
|
||||
config_.gain_controller1 != adjusted_config.gain_controller1;
|
||||
|
||||
const bool agc2_config_changed =
|
||||
config_.gain_controller2 != config.gain_controller2;
|
||||
config_.gain_controller2 != adjusted_config.gain_controller2;
|
||||
|
||||
const bool ns_config_changed =
|
||||
config_.noise_suppression.enabled != config.noise_suppression.enabled ||
|
||||
config_.noise_suppression.level != config.noise_suppression.level;
|
||||
config_.noise_suppression.enabled !=
|
||||
adjusted_config.noise_suppression.enabled ||
|
||||
config_.noise_suppression.level !=
|
||||
adjusted_config.noise_suppression.level;
|
||||
|
||||
const bool ts_config_changed = config_.transient_suppression.enabled !=
|
||||
config.transient_suppression.enabled;
|
||||
adjusted_config.transient_suppression.enabled;
|
||||
|
||||
const bool pre_amplifier_config_changed =
|
||||
config_.pre_amplifier.enabled != config.pre_amplifier.enabled ||
|
||||
config_.pre_amplifier.enabled != adjusted_config.pre_amplifier.enabled ||
|
||||
config_.pre_amplifier.fixed_gain_factor !=
|
||||
config.pre_amplifier.fixed_gain_factor;
|
||||
adjusted_config.pre_amplifier.fixed_gain_factor;
|
||||
|
||||
const bool gain_adjustment_config_changed =
|
||||
config_.capture_level_adjustment != config.capture_level_adjustment;
|
||||
config_.capture_level_adjustment !=
|
||||
adjusted_config.capture_level_adjustment;
|
||||
|
||||
config_ = config;
|
||||
config_ = adjusted_config;
|
||||
|
||||
if (aec_config_changed) {
|
||||
InitializeEchoController();
|
||||
|
@ -2123,8 +2256,10 @@ void AudioProcessingImpl::InitializeGainController2(bool config_has_changed) {
|
|||
const bool use_internal_vad =
|
||||
transient_suppressor_vad_mode_ != TransientSuppressor::VadMode::kRnnVad;
|
||||
submodules_.gain_controller2 = std::make_unique<GainController2>(
|
||||
config_.gain_controller2, proc_fullband_sample_rate_hz(),
|
||||
num_input_channels(), use_internal_vad);
|
||||
config_.gain_controller2,
|
||||
input_volume_controller_config_override_.value_or(
|
||||
InputVolumeController::Config{}),
|
||||
proc_fullband_sample_rate_hz(), num_input_channels(), use_internal_vad);
|
||||
submodules_.gain_controller2->SetCaptureOutputUsed(
|
||||
capture_.capture_output_used);
|
||||
}
|
||||
|
|
|
@ -160,6 +160,9 @@ class AudioProcessingImpl : public AudioProcessing {
|
|||
ReinitializeTransientSuppressor);
|
||||
FRIEND_TEST_ALL_PREFIXES(ApmWithSubmodulesExcludedTest,
|
||||
BitexactWithDisabledModules);
|
||||
FRIEND_TEST_ALL_PREFIXES(
|
||||
AudioProcessingImplInputVolumeControllerExperimentParametrizedTest,
|
||||
ConfigAdjustedWhenExperimentEnabled);
|
||||
|
||||
void set_stream_analog_level_locked(int level)
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
|
||||
|
@ -188,6 +191,12 @@ class AudioProcessingImpl : public AudioProcessing {
|
|||
static std::atomic<int> instance_count_;
|
||||
const bool use_setup_specific_default_aec3_config_;
|
||||
|
||||
// TODO(bugs.webrtc.org/7494): Remove the the config when the field trial is
|
||||
// removed. "WebRTC-Audio-InputVolumeControllerExperiment" field trial
|
||||
// override for the input volume controller config.
|
||||
const absl::optional<InputVolumeController::Config>
|
||||
input_volume_controller_config_override_;
|
||||
|
||||
const bool use_denormal_disabler_;
|
||||
|
||||
const TransientSuppressor::VadMode transient_suppressor_vad_mode_;
|
||||
|
|
|
@ -1188,4 +1188,282 @@ TEST(AudioProcessingImplTest,
|
|||
EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135);
|
||||
}
|
||||
|
||||
TEST(AudioProcessingImplInputVolumeControllerExperimentTest,
|
||||
ConfigAdjustedWhenExperimentEnabledAndAgc1AnalogEnabled) {
|
||||
webrtc::test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-Audio-InputVolumeControllerExperiment/"
|
||||
"Enabled,"
|
||||
"enable_clipping_predictor:true,"
|
||||
"clipped_level_min:20,"
|
||||
"clipped_level_step:30,"
|
||||
"clipped_ratio_threshold:0.4,"
|
||||
"clipped_wait_frames:50,"
|
||||
"target_range_max_dbfs:-6,"
|
||||
"target_range_min_dbfs:-70,"
|
||||
"update_input_volume_wait_frames:80,"
|
||||
"speech_probability_threshold:0.9,"
|
||||
"speech_ratio_threshold:1.0/");
|
||||
|
||||
AudioProcessingBuilderForTesting apm_builder;
|
||||
|
||||
// Set a config with analog AGC1 enabled.
|
||||
AudioProcessing::Config config;
|
||||
config.gain_controller1.enabled = true;
|
||||
config.gain_controller1.analog_gain_controller.enabled = true;
|
||||
config.gain_controller1.analog_gain_controller.enable_digital_adaptive = true;
|
||||
config.gain_controller2.enabled = false;
|
||||
config.gain_controller1.mode =
|
||||
AudioProcessing::Config::GainController1::kAdaptiveAnalog;
|
||||
|
||||
EXPECT_FALSE(config.gain_controller2.input_volume_controller.enabled);
|
||||
|
||||
apm_builder.SetConfig(config);
|
||||
|
||||
auto apm = apm_builder.Create();
|
||||
auto adjusted_config = apm->GetConfig();
|
||||
|
||||
// Expect the config to be adjusted.
|
||||
EXPECT_FALSE(adjusted_config.gain_controller1.enabled);
|
||||
EXPECT_FALSE(adjusted_config.gain_controller1.analog_gain_controller.enabled);
|
||||
EXPECT_TRUE(adjusted_config.gain_controller2.enabled);
|
||||
EXPECT_TRUE(adjusted_config.gain_controller2.adaptive_digital.enabled);
|
||||
EXPECT_TRUE(adjusted_config.gain_controller2.input_volume_controller.enabled);
|
||||
|
||||
// Change config back and compare.
|
||||
adjusted_config.gain_controller1.enabled = config.gain_controller1.enabled;
|
||||
adjusted_config.gain_controller1.analog_gain_controller.enabled =
|
||||
config.gain_controller1.analog_gain_controller.enabled;
|
||||
adjusted_config.gain_controller2.enabled = config.gain_controller2.enabled;
|
||||
adjusted_config.gain_controller2.adaptive_digital.enabled =
|
||||
config.gain_controller2.adaptive_digital.enabled;
|
||||
adjusted_config.gain_controller2.input_volume_controller.enabled =
|
||||
config.gain_controller2.input_volume_controller.enabled;
|
||||
|
||||
EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString()));
|
||||
}
|
||||
|
||||
TEST(AudioProcessingImplInputVolumeControllerExperimentTest,
|
||||
ConfigAdjustedWhenExperimentEnabledAndHybridAgcEnabled) {
|
||||
webrtc::test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-Audio-InputVolumeControllerExperiment/"
|
||||
"Enabled,"
|
||||
"enable_clipping_predictor:true,"
|
||||
"clipped_level_min:20,"
|
||||
"clipped_level_step:30,"
|
||||
"clipped_ratio_threshold:0.4,"
|
||||
"clipped_wait_frames:50,"
|
||||
"target_range_max_dbfs:-6,"
|
||||
"target_range_min_dbfs:-70,"
|
||||
"update_input_volume_wait_frames:80,"
|
||||
"speech_probability_threshold:0.9,"
|
||||
"speech_ratio_threshold:1.0/");
|
||||
|
||||
AudioProcessingBuilderForTesting apm_builder;
|
||||
|
||||
// Set a config with hybrid AGC enabled.
|
||||
AudioProcessing::Config config;
|
||||
config.gain_controller1.enabled = true;
|
||||
config.gain_controller1.analog_gain_controller.enabled = true;
|
||||
config.gain_controller1.analog_gain_controller.enable_digital_adaptive =
|
||||
false;
|
||||
config.gain_controller2.enabled = true;
|
||||
config.gain_controller2.adaptive_digital.enabled = true;
|
||||
config.gain_controller1.mode =
|
||||
AudioProcessing::Config::GainController1::kAdaptiveAnalog;
|
||||
|
||||
EXPECT_FALSE(config.gain_controller2.input_volume_controller.enabled);
|
||||
|
||||
apm_builder.SetConfig(config);
|
||||
|
||||
auto apm = apm_builder.Create();
|
||||
auto adjusted_config = apm->GetConfig();
|
||||
|
||||
// Expect the config to be adjusted.
|
||||
EXPECT_FALSE(adjusted_config.gain_controller1.enabled);
|
||||
EXPECT_FALSE(adjusted_config.gain_controller1.analog_gain_controller.enabled);
|
||||
EXPECT_TRUE(adjusted_config.gain_controller2.enabled);
|
||||
EXPECT_TRUE(adjusted_config.gain_controller2.adaptive_digital.enabled);
|
||||
EXPECT_TRUE(adjusted_config.gain_controller2.input_volume_controller.enabled);
|
||||
|
||||
// Change config back and compare.
|
||||
adjusted_config.gain_controller1.enabled = config.gain_controller1.enabled;
|
||||
adjusted_config.gain_controller1.analog_gain_controller.enabled =
|
||||
config.gain_controller1.analog_gain_controller.enabled;
|
||||
adjusted_config.gain_controller2.enabled = config.gain_controller2.enabled;
|
||||
adjusted_config.gain_controller2.adaptive_digital.enabled =
|
||||
config.gain_controller2.adaptive_digital.enabled;
|
||||
adjusted_config.gain_controller2.input_volume_controller.enabled =
|
||||
config.gain_controller2.input_volume_controller.enabled;
|
||||
|
||||
EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString()));
|
||||
}
|
||||
|
||||
TEST(AudioProcessingImplInputVolumeControllerExperimentTest,
|
||||
ConfigNotAdjustedWhenExperimentEnabledAndAgc1AnalogNotEnabled) {
|
||||
webrtc::test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-Audio-InputVolumeControllerExperiment/"
|
||||
"Enabled,"
|
||||
"enable_clipping_predictor:true,"
|
||||
"clipped_level_min:20,"
|
||||
"clipped_level_step:30,"
|
||||
"clipped_ratio_threshold:0.4,"
|
||||
"clipped_wait_frames:50,"
|
||||
"target_range_max_dbfs:-6,"
|
||||
"target_range_min_dbfs:-70,"
|
||||
"update_input_volume_wait_frames:80,"
|
||||
"speech_probability_threshold:0.9,"
|
||||
"speech_ratio_threshold:1.0/");
|
||||
|
||||
AudioProcessingBuilderForTesting apm_builder;
|
||||
|
||||
// Set a config with analog AGC1 not enabled.
|
||||
AudioProcessing::Config config;
|
||||
config.gain_controller1.enabled = false;
|
||||
config.gain_controller1.analog_gain_controller.enabled = true;
|
||||
config.gain_controller1.analog_gain_controller.enable_digital_adaptive = true;
|
||||
config.gain_controller2.enabled = false;
|
||||
config.gain_controller1.mode =
|
||||
AudioProcessing::Config::GainController1::kAdaptiveAnalog;
|
||||
|
||||
EXPECT_FALSE(config.gain_controller2.input_volume_controller.enabled);
|
||||
|
||||
apm_builder.SetConfig(config);
|
||||
|
||||
auto apm = apm_builder.Create();
|
||||
auto adjusted_config = apm->GetConfig();
|
||||
|
||||
EXPECT_EQ(config.gain_controller1.enabled,
|
||||
adjusted_config.gain_controller1.enabled);
|
||||
EXPECT_EQ(config.gain_controller1.analog_gain_controller.enabled,
|
||||
adjusted_config.gain_controller1.analog_gain_controller.enabled);
|
||||
EXPECT_EQ(config.gain_controller2.enabled,
|
||||
adjusted_config.gain_controller2.enabled);
|
||||
EXPECT_EQ(config.gain_controller2.adaptive_digital.enabled,
|
||||
adjusted_config.gain_controller2.adaptive_digital.enabled);
|
||||
EXPECT_FALSE(
|
||||
adjusted_config.gain_controller2.input_volume_controller.enabled);
|
||||
|
||||
EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString()));
|
||||
}
|
||||
|
||||
TEST(AudioProcessingImplInputVolumeControllerExperimentTest,
|
||||
ConfigNotAdjustedWhenExperimentEnabledAndHybridAgcNotEnabled) {
|
||||
webrtc::test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-Audio-InputVolumeControllerExperiment/"
|
||||
"Enabled,"
|
||||
"enable_clipping_predictor:true,"
|
||||
"clipped_level_min:20,"
|
||||
"clipped_level_step:30,"
|
||||
"clipped_ratio_threshold:0.4,"
|
||||
"clipped_wait_frames:50,"
|
||||
"target_range_max_dbfs:-6,"
|
||||
"target_range_min_dbfs:-70,"
|
||||
"update_input_volume_wait_frames:80,"
|
||||
"speech_probability_threshold:0.9,"
|
||||
"speech_ratio_threshold:1.0/");
|
||||
|
||||
AudioProcessingBuilderForTesting apm_builder;
|
||||
|
||||
// Set a config with hybrid AGC analog not enabled.
|
||||
AudioProcessing::Config config;
|
||||
config.gain_controller1.enabled = false;
|
||||
config.gain_controller1.analog_gain_controller.enabled = true;
|
||||
config.gain_controller1.analog_gain_controller.enable_digital_adaptive =
|
||||
false;
|
||||
config.gain_controller2.enabled = true;
|
||||
config.gain_controller2.adaptive_digital.enabled = true;
|
||||
config.gain_controller1.mode =
|
||||
AudioProcessing::Config::GainController1::kAdaptiveAnalog;
|
||||
|
||||
EXPECT_FALSE(config.gain_controller2.input_volume_controller.enabled);
|
||||
|
||||
apm_builder.SetConfig(config);
|
||||
|
||||
auto apm = apm_builder.Create();
|
||||
auto adjusted_config = apm->GetConfig();
|
||||
|
||||
EXPECT_EQ(config.gain_controller1.enabled,
|
||||
adjusted_config.gain_controller1.enabled);
|
||||
EXPECT_EQ(config.gain_controller1.analog_gain_controller.enabled,
|
||||
adjusted_config.gain_controller1.analog_gain_controller.enabled);
|
||||
EXPECT_EQ(config.gain_controller2.enabled,
|
||||
adjusted_config.gain_controller2.enabled);
|
||||
EXPECT_EQ(config.gain_controller2.adaptive_digital.enabled,
|
||||
adjusted_config.gain_controller2.adaptive_digital.enabled);
|
||||
EXPECT_FALSE(
|
||||
adjusted_config.gain_controller2.input_volume_controller.enabled);
|
||||
|
||||
EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString()));
|
||||
}
|
||||
|
||||
TEST(AudioProcessingImplInputVolumeControllerExperimentTest,
|
||||
ConfigNotAdjustedWhenExperimentNotEnabledAndAgc1AnalogEnabled) {
|
||||
AudioProcessingBuilderForTesting apm_builder;
|
||||
|
||||
// Set a config with analog AGC1 analog enabled.
|
||||
AudioProcessing::Config config;
|
||||
config.gain_controller1.enabled = true;
|
||||
config.gain_controller1.analog_gain_controller.enabled = true;
|
||||
config.gain_controller1.analog_gain_controller.enable_digital_adaptive = true;
|
||||
config.gain_controller2.enabled = false;
|
||||
config.gain_controller1.mode =
|
||||
AudioProcessing::Config::GainController1::kAdaptiveAnalog;
|
||||
|
||||
EXPECT_FALSE(config.gain_controller2.input_volume_controller.enabled);
|
||||
|
||||
apm_builder.SetConfig(config);
|
||||
|
||||
auto apm = apm_builder.Create();
|
||||
auto adjusted_config = apm->GetConfig();
|
||||
|
||||
EXPECT_EQ(config.gain_controller1.enabled,
|
||||
adjusted_config.gain_controller1.enabled);
|
||||
EXPECT_EQ(config.gain_controller1.analog_gain_controller.enabled,
|
||||
adjusted_config.gain_controller1.analog_gain_controller.enabled);
|
||||
EXPECT_EQ(config.gain_controller2.enabled,
|
||||
adjusted_config.gain_controller2.enabled);
|
||||
EXPECT_EQ(config.gain_controller2.adaptive_digital.enabled,
|
||||
adjusted_config.gain_controller2.adaptive_digital.enabled);
|
||||
EXPECT_FALSE(
|
||||
adjusted_config.gain_controller2.input_volume_controller.enabled);
|
||||
|
||||
EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString()));
|
||||
}
|
||||
|
||||
TEST(AudioProcessingImplInputVolumeControllerExperimentTest,
|
||||
ConfigNotAdjustedWhenExperimentNotEnabledAndHybridAgcEnabled) {
|
||||
AudioProcessingBuilderForTesting apm_builder;
|
||||
|
||||
// Set a config with hybrid AGC enabled.
|
||||
AudioProcessing::Config config;
|
||||
config.gain_controller1.enabled = true;
|
||||
config.gain_controller1.analog_gain_controller.enabled = true;
|
||||
config.gain_controller1.analog_gain_controller.enable_digital_adaptive =
|
||||
false;
|
||||
config.gain_controller2.enabled = true;
|
||||
config.gain_controller2.adaptive_digital.enabled = true;
|
||||
config.gain_controller1.mode =
|
||||
AudioProcessing::Config::GainController1::kAdaptiveAnalog;
|
||||
|
||||
EXPECT_FALSE(config.gain_controller2.input_volume_controller.enabled);
|
||||
|
||||
apm_builder.SetConfig(config);
|
||||
|
||||
auto apm = apm_builder.Create();
|
||||
auto adjusted_config = apm->GetConfig();
|
||||
|
||||
EXPECT_EQ(config.gain_controller1.enabled,
|
||||
adjusted_config.gain_controller1.enabled);
|
||||
EXPECT_EQ(config.gain_controller1.analog_gain_controller.enabled,
|
||||
adjusted_config.gain_controller1.analog_gain_controller.enabled);
|
||||
EXPECT_EQ(config.gain_controller2.enabled,
|
||||
adjusted_config.gain_controller2.enabled);
|
||||
EXPECT_EQ(config.gain_controller2.adaptive_digital.enabled,
|
||||
adjusted_config.gain_controller2.adaptive_digital.enabled);
|
||||
EXPECT_FALSE(
|
||||
adjusted_config.gain_controller2.input_volume_controller.enabled);
|
||||
|
||||
EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString()));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace webrtc {
|
|||
namespace {
|
||||
|
||||
using Agc2Config = AudioProcessing::Config::GainController2;
|
||||
using InputVolumeControllerConfig = InputVolumeController::Config;
|
||||
|
||||
constexpr int kLogLimiterStatsPeriodMs = 30'000;
|
||||
constexpr int kFrameLengthMs = 10;
|
||||
|
@ -64,10 +65,10 @@ std::unique_ptr<AdaptiveDigitalGainController> CreateAdaptiveDigitalController(
|
|||
// Creates an input volume controller if `enabled` is true.
|
||||
std::unique_ptr<InputVolumeController> CreateInputVolumeController(
|
||||
bool enabled,
|
||||
const InputVolumeControllerConfig& config,
|
||||
int num_channels) {
|
||||
if (enabled) {
|
||||
return std::make_unique<InputVolumeController>(
|
||||
num_channels, InputVolumeController::Config());
|
||||
return std::make_unique<InputVolumeController>(num_channels, config);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -76,7 +77,9 @@ std::unique_ptr<InputVolumeController> CreateInputVolumeController(
|
|||
|
||||
std::atomic<int> GainController2::instance_count_(0);
|
||||
|
||||
GainController2::GainController2(const Agc2Config& config,
|
||||
GainController2::GainController2(
|
||||
const Agc2Config& config,
|
||||
const InputVolumeControllerConfig& input_volume_controller_config,
|
||||
int sample_rate_hz,
|
||||
int num_channels,
|
||||
bool use_internal_vad)
|
||||
|
@ -92,6 +95,7 @@ GainController2::GainController2(const Agc2Config& config,
|
|||
&data_dumper_)),
|
||||
input_volume_controller_(
|
||||
CreateInputVolumeController(config.input_volume_controller.enabled,
|
||||
input_volume_controller_config,
|
||||
num_channels)),
|
||||
limiter_(sample_rate_hz, &data_dumper_, /*histogram_name_prefix=*/"Agc2"),
|
||||
calls_since_last_limiter_log_(0) {
|
||||
|
|
|
@ -34,7 +34,9 @@ class GainController2 {
|
|||
public:
|
||||
// Ctor. If `use_internal_vad` is true, an internal voice activity
|
||||
// detector is used for digital adaptive gain.
|
||||
GainController2(const AudioProcessing::Config::GainController2& config,
|
||||
GainController2(
|
||||
const AudioProcessing::Config::GainController2& config,
|
||||
const InputVolumeController::Config& input_volume_controller_config,
|
||||
int sample_rate_hz,
|
||||
int num_channels,
|
||||
bool use_internal_vad);
|
||||
|
|
|
@ -33,6 +33,7 @@ using ::testing::Eq;
|
|||
using ::testing::Optional;
|
||||
|
||||
using Agc2Config = AudioProcessing::Config::GainController2;
|
||||
using InputVolumeControllerConfig = InputVolumeController::Config;
|
||||
|
||||
// Sets all the samples in `ab` to `value`.
|
||||
void SetAudioBufferSamples(float value, AudioBuffer& ab) {
|
||||
|
@ -73,11 +74,25 @@ std::unique_ptr<GainController2> CreateAgc2FixedDigitalMode(
|
|||
config.adaptive_digital.enabled = false;
|
||||
config.fixed_digital.gain_db = fixed_gain_db;
|
||||
EXPECT_TRUE(GainController2::Validate(config));
|
||||
return std::make_unique<GainController2>(config, sample_rate_hz,
|
||||
return std::make_unique<GainController2>(
|
||||
config, InputVolumeControllerConfig{}, sample_rate_hz,
|
||||
/*num_channels=*/1,
|
||||
/*use_internal_vad=*/true);
|
||||
}
|
||||
|
||||
constexpr InputVolumeControllerConfig kTestInputVolumeControllerConfig{
|
||||
.clipped_level_min = 20,
|
||||
.clipped_level_step = 30,
|
||||
.clipped_ratio_threshold = 0.4,
|
||||
.clipped_wait_frames = 50,
|
||||
.enable_clipping_predictor = true,
|
||||
.target_range_max_dbfs = -6,
|
||||
.target_range_min_dbfs = -70,
|
||||
.update_input_volume_wait_frames = 100,
|
||||
.speech_probability_threshold = 0.9,
|
||||
.speech_ratio_threshold = 1,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(GainController2, CheckDefaultConfig) {
|
||||
|
@ -160,8 +175,40 @@ TEST(GainController2,
|
|||
Agc2Config config;
|
||||
config.input_volume_controller.enabled = false;
|
||||
|
||||
auto gain_controller =
|
||||
std::make_unique<GainController2>(config, kSampleRateHz, kNumChannels,
|
||||
auto gain_controller = std::make_unique<GainController2>(
|
||||
config, InputVolumeControllerConfig{}, kSampleRateHz, kNumChannels,
|
||||
/*use_internal_vad=*/true);
|
||||
|
||||
EXPECT_FALSE(gain_controller->GetRecommendedInputVolume().has_value());
|
||||
|
||||
// Run AGC for a signal with no clipping or detected speech.
|
||||
RunAgc2WithConstantInput(*gain_controller, kLowInputLevel, kNumFrames,
|
||||
kSampleRateHz, kNumChannels, kInitialInputVolume);
|
||||
|
||||
EXPECT_FALSE(gain_controller->GetRecommendedInputVolume().has_value());
|
||||
|
||||
// Run AGC for a signal with clipping.
|
||||
RunAgc2WithConstantInput(*gain_controller, kHighInputLevel, kNumFrames,
|
||||
kSampleRateHz, kNumChannels, kInitialInputVolume);
|
||||
|
||||
EXPECT_FALSE(gain_controller->GetRecommendedInputVolume().has_value());
|
||||
}
|
||||
|
||||
TEST(
|
||||
GainController2,
|
||||
CheckGetRecommendedInputVolumeWhenInputVolumeControllerNotEnabledAndSpecificConfigUsed) {
|
||||
constexpr float kHighInputLevel = 32767.0f;
|
||||
constexpr float kLowInputLevel = 1000.0f;
|
||||
constexpr int kInitialInputVolume = 100;
|
||||
constexpr int kNumChannels = 2;
|
||||
constexpr int kNumFrames = 5;
|
||||
constexpr int kSampleRateHz = 16000;
|
||||
|
||||
Agc2Config config;
|
||||
config.input_volume_controller.enabled = false;
|
||||
|
||||
auto gain_controller = std::make_unique<GainController2>(
|
||||
config, kTestInputVolumeControllerConfig, kSampleRateHz, kNumChannels,
|
||||
/*use_internal_vad=*/true);
|
||||
|
||||
EXPECT_FALSE(gain_controller->GetRecommendedInputVolume().has_value());
|
||||
|
@ -192,8 +239,41 @@ TEST(GainController2,
|
|||
config.input_volume_controller.enabled = true;
|
||||
config.adaptive_digital.enabled = true;
|
||||
|
||||
auto gain_controller =
|
||||
std::make_unique<GainController2>(config, kSampleRateHz, kNumChannels,
|
||||
auto gain_controller = std::make_unique<GainController2>(
|
||||
config, InputVolumeControllerConfig{}, kSampleRateHz, kNumChannels,
|
||||
/*use_internal_vad=*/true);
|
||||
|
||||
EXPECT_TRUE(gain_controller->GetRecommendedInputVolume().has_value());
|
||||
|
||||
// Run AGC for a signal with no clipping or detected speech.
|
||||
RunAgc2WithConstantInput(*gain_controller, kLowInputLevel, kNumFrames,
|
||||
kSampleRateHz, kNumChannels, kInitialInputVolume);
|
||||
|
||||
EXPECT_TRUE(gain_controller->GetRecommendedInputVolume().has_value());
|
||||
|
||||
// Run AGC for a signal with clipping.
|
||||
RunAgc2WithConstantInput(*gain_controller, kHighInputLevel, kNumFrames,
|
||||
kSampleRateHz, kNumChannels, kInitialInputVolume);
|
||||
|
||||
EXPECT_TRUE(gain_controller->GetRecommendedInputVolume().has_value());
|
||||
}
|
||||
|
||||
TEST(
|
||||
GainController2,
|
||||
CheckGetRecommendedInputVolumeWhenInputVolumeControllerEnabledAndSpecificConfigUsed) {
|
||||
constexpr float kHighInputLevel = 32767.0f;
|
||||
constexpr float kLowInputLevel = 1000.0f;
|
||||
constexpr int kInitialInputVolume = 100;
|
||||
constexpr int kNumChannels = 2;
|
||||
constexpr int kNumFrames = 5;
|
||||
constexpr int kSampleRateHz = 16000;
|
||||
|
||||
Agc2Config config;
|
||||
config.input_volume_controller.enabled = true;
|
||||
config.adaptive_digital.enabled = true;
|
||||
|
||||
auto gain_controller = std::make_unique<GainController2>(
|
||||
config, kTestInputVolumeControllerConfig, kSampleRateHz, kNumChannels,
|
||||
/*use_internal_vad=*/true);
|
||||
|
||||
EXPECT_TRUE(gain_controller->GetRecommendedInputVolume().has_value());
|
||||
|
@ -214,7 +294,8 @@ TEST(GainController2,
|
|||
// Checks that the default config is applied.
|
||||
TEST(GainController2, ApplyDefaultConfig) {
|
||||
auto gain_controller2 = std::make_unique<GainController2>(
|
||||
Agc2Config{}, /*sample_rate_hz=*/16000, /*num_channels=*/2,
|
||||
Agc2Config{}, InputVolumeControllerConfig{},
|
||||
/*sample_rate_hz=*/16000, /*num_channels=*/2,
|
||||
/*use_internal_vad=*/true);
|
||||
EXPECT_TRUE(gain_controller2.get());
|
||||
}
|
||||
|
@ -330,7 +411,8 @@ TEST(GainController2, CheckFinalGainWithAdaptiveDigitalController) {
|
|||
Agc2Config config;
|
||||
config.fixed_digital.gain_db = 0.0f;
|
||||
config.adaptive_digital.enabled = true;
|
||||
GainController2 agc2(config, kSampleRateHz, kStereo,
|
||||
GainController2 agc2(config, /*input_volume_controller_config=*/{},
|
||||
kSampleRateHz, kStereo,
|
||||
/*use_internal_vad=*/true);
|
||||
|
||||
test::InputAudioFile input_file(
|
||||
|
@ -385,9 +467,11 @@ TEST(GainController2,
|
|||
Agc2Config config;
|
||||
config.fixed_digital.gain_db = 0.0f;
|
||||
config.adaptive_digital.enabled = true;
|
||||
GainController2 agc2(config, kSampleRateHz, kStereo,
|
||||
GainController2 agc2(config, /*input_volume_controller_config=*/{},
|
||||
kSampleRateHz, kStereo,
|
||||
/*use_internal_vad=*/true);
|
||||
GainController2 agc2_reference(config, kSampleRateHz, kStereo,
|
||||
GainController2 agc2_reference(config, /*input_volume_controller_config=*/{},
|
||||
kSampleRateHz, kStereo,
|
||||
/*use_internal_vad=*/true);
|
||||
|
||||
test::InputAudioFile input_file(
|
||||
|
@ -452,9 +536,11 @@ TEST(GainController2,
|
|||
Agc2Config config;
|
||||
config.fixed_digital.gain_db = 0.0f;
|
||||
config.adaptive_digital.enabled = true;
|
||||
GainController2 agc2(config, kSampleRateHz, kStereo,
|
||||
GainController2 agc2(config, /*input_volume_controller_config=*/{},
|
||||
kSampleRateHz, kStereo,
|
||||
/*use_internal_vad=*/false);
|
||||
GainController2 agc2_reference(config, kSampleRateHz, kStereo,
|
||||
GainController2 agc2_reference(config, /*input_volume_controller_config=*/{},
|
||||
kSampleRateHz, kStereo,
|
||||
/*use_internal_vad=*/true);
|
||||
|
||||
test::InputAudioFile input_file(
|
||||
|
@ -521,9 +607,11 @@ TEST(GainController2,
|
|||
Agc2Config config;
|
||||
config.fixed_digital.gain_db = 0.0f;
|
||||
config.adaptive_digital.enabled = true;
|
||||
GainController2 agc2(config, kSampleRateHz, kStereo,
|
||||
GainController2 agc2(config, /*input_volume_controller_config=*/{},
|
||||
kSampleRateHz, kStereo,
|
||||
/*use_internal_vad=*/false);
|
||||
GainController2 agc2_reference(config, kSampleRateHz, kStereo,
|
||||
GainController2 agc2_reference(config, /*input_volume_controller_config=*/{},
|
||||
kSampleRateHz, kStereo,
|
||||
/*use_internal_vad=*/true);
|
||||
VoiceActivityDetectorWrapper vad(config.adaptive_digital.vad_reset_period_ms,
|
||||
GetAvailableCpuFeatures(), kSampleRateHz);
|
||||
|
|
Loading…
Reference in a new issue