AEC3: Kill kill-switches

"Perfection is achieved, not when there is nothing more to add,
but when there is nothing left to take away."

This CL removes the following kill-switches from AEC3
- WebRTC-Aec3DownSamplingFactor8KillSwitch
- WebRTC-Aec3NewSuppressionKillSwitch
- WebRTC-Aec3ShadowFilterJumpstartKillSwitch
- WebRTC-Aec3SlowFilterAdaptationKillSwitch
- WebRTC-Aec3SuppressorNearendAveragingKillSwitch

It also removes code paths and configuration parameters that are no
longer in use. The list of kill-switches in the audio processing
fuzzer test is updated.

The change has been tested for bit-exactness.

Bug: webrtc:8671
Change-Id: Ie0af86a14baf853548bf9c00b2b9b3bbc32c1aaa
Reviewed-on: https://webrtc-review.googlesource.com/c/105324
Reviewed-by: Sam Zackrisson <saza@webrtc.org>
Reviewed-by: Per Åhgren <peah@webrtc.org>
Commit-Queue: Gustaf Ullberg <gustaf@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25120}
This commit is contained in:
Gustaf Ullberg 2018-10-11 15:27:26 +02:00 committed by Commit Bot
parent 8b3cc4982f
commit 53e22113fd
9 changed files with 30 additions and 235 deletions

View File

@ -45,9 +45,6 @@ EchoCanceller3Config::Delay::Delay() = default;
EchoCanceller3Config::Delay::Delay(const EchoCanceller3Config::Delay& e) = EchoCanceller3Config::Delay::Delay(const EchoCanceller3Config::Delay& e) =
default; default;
EchoCanceller3Config::Mask::Mask() = default;
EchoCanceller3Config::Mask::Mask(const EchoCanceller3Config::Mask& m) = default;
EchoCanceller3Config::EchoModel::EchoModel() = default; EchoCanceller3Config::EchoModel::EchoModel() = default;
EchoCanceller3Config::EchoModel::EchoModel( EchoCanceller3Config::EchoModel::EchoModel(
const EchoCanceller3Config::EchoModel& e) = default; const EchoCanceller3Config::EchoModel& e) = default;
@ -158,22 +155,6 @@ bool EchoCanceller3Config::Validate(EchoCanceller3Config* config) {
res = res && Limit(&c->ep_strength.hf, 0.f, 1000000.f); res = res && Limit(&c->ep_strength.hf, 0.f, 1000000.f);
res = res && Limit(&c->ep_strength.default_len, 0.f, 1.f); res = res && Limit(&c->ep_strength.default_len, 0.f, 1.f);
res = res && Limit(&c->gain_mask.m0, 0.f, 1.f);
res = res && Limit(&c->gain_mask.m1, 0.f, 1.f);
res = res && Limit(&c->gain_mask.m2, 0.f, 1.f);
res = res && Limit(&c->gain_mask.m3, 0.f, 1.f);
res = res && Limit(&c->gain_mask.m5, 0.f, 1.f);
res = res && Limit(&c->gain_mask.m6, 0.f, 1.f);
res = res && Limit(&c->gain_mask.m7, 0.f, 1.f);
res = res && Limit(&c->gain_mask.m8, 0.f, 1.f);
res = res && Limit(&c->gain_mask.m9, 0.f, 1.f);
res = res && Limit(&c->gain_mask.gain_curve_offset, 0.f, 1000.f);
res = res && Limit(&c->gain_mask.gain_curve_slope, 0.f, 1000.f);
res = res && Limit(&c->gain_mask.temporal_masking_lf, 0.f, 1000.f);
res = res && Limit(&c->gain_mask.temporal_masking_hf, 0.f, 1000.f);
res = res && Limit(&c->gain_mask.temporal_masking_lf_bands, 0, 65);
res = res && res = res &&
Limit(&c->echo_audibility.low_render_limit, 0.f, 32768.f * 32768.f); Limit(&c->echo_audibility.low_render_limit, 0.f, 32768.f * 32768.f);
res = res && res = res &&

View File

@ -92,26 +92,6 @@ struct RTC_EXPORT EchoCanceller3Config {
bool bounded_erl = false; bool bounded_erl = false;
} ep_strength; } ep_strength;
struct Mask {
Mask();
Mask(const Mask& m);
float m0 = 0.1f;
float m1 = 0.01f;
float m2 = 0.0001f;
float m3 = 0.01f;
float m5 = 0.01f;
float m6 = 0.0001f;
float m7 = 0.01f;
float m8 = 0.0001f;
float m9 = 0.1f;
float gain_curve_offset = 1.45f;
float gain_curve_slope = 5.f;
float temporal_masking_lf = 0.9f;
float temporal_masking_hf = 0.6f;
size_t temporal_masking_lf_bands = 3;
} gain_mask;
struct EchoAudibility { struct EchoAudibility {
float low_render_limit = 4 * 64.f; float low_render_limit = 4 * 64.f;
float normal_render_limit = 64.f; float normal_render_limit = 64.f;

View File

@ -192,26 +192,6 @@ EchoCanceller3Config Aec3ConfigFromJsonString(absl::string_view json_string) {
ReadParam(section, "bounded_erl", &cfg.ep_strength.bounded_erl); ReadParam(section, "bounded_erl", &cfg.ep_strength.bounded_erl);
} }
if (rtc::GetValueFromJsonObject(aec3_root, "gain_mask", &section)) {
ReadParam(section, "m1", &cfg.gain_mask.m1);
ReadParam(section, "m2", &cfg.gain_mask.m2);
ReadParam(section, "m3", &cfg.gain_mask.m3);
ReadParam(section, "m5", &cfg.gain_mask.m5);
ReadParam(section, "m6", &cfg.gain_mask.m6);
ReadParam(section, "m7", &cfg.gain_mask.m7);
ReadParam(section, "m8", &cfg.gain_mask.m8);
ReadParam(section, "m9", &cfg.gain_mask.m9);
ReadParam(section, "gain_curve_offset", &cfg.gain_mask.gain_curve_offset);
ReadParam(section, "gain_curve_slope", &cfg.gain_mask.gain_curve_slope);
ReadParam(section, "temporal_masking_lf",
&cfg.gain_mask.temporal_masking_lf);
ReadParam(section, "temporal_masking_hf",
&cfg.gain_mask.temporal_masking_hf);
ReadParam(section, "temporal_masking_lf_bands",
&cfg.gain_mask.temporal_masking_lf_bands);
}
if (rtc::GetValueFromJsonObject(aec3_root, "echo_audibility", &section)) { if (rtc::GetValueFromJsonObject(aec3_root, "echo_audibility", &section)) {
ReadParam(section, "low_render_limit", ReadParam(section, "low_render_limit",
&cfg.echo_audibility.low_render_limit); &cfg.echo_audibility.low_render_limit);
@ -424,26 +404,6 @@ std::string Aec3ConfigToJsonString(const EchoCanceller3Config& config) {
ost << "},"; ost << "},";
ost << "\"gain_mask\": {";
ost << "\"m0\": " << config.gain_mask.m0 << ",";
ost << "\"m1\": " << config.gain_mask.m1 << ",";
ost << "\"m2\": " << config.gain_mask.m2 << ",";
ost << "\"m3\": " << config.gain_mask.m3 << ",";
ost << "\"m5\": " << config.gain_mask.m5 << ",";
ost << "\"m6\": " << config.gain_mask.m6 << ",";
ost << "\"m7\": " << config.gain_mask.m7 << ",";
ost << "\"m8\": " << config.gain_mask.m8 << ",";
ost << "\"m9\": " << config.gain_mask.m9 << ",";
ost << "\"gain_curve_offset\": " << config.gain_mask.gain_curve_offset << ",";
ost << "\"gain_curve_slope\": " << config.gain_mask.gain_curve_slope << ",";
ost << "\"temporal_masking_lf\": " << config.gain_mask.temporal_masking_lf
<< ",";
ost << "\"temporal_masking_hf\": " << config.gain_mask.temporal_masking_hf
<< ",";
ost << "\"temporal_masking_lf_bands\": "
<< config.gain_mask.temporal_masking_lf_bands;
ost << "},";
ost << "\"echo_audibility\": {"; ost << "\"echo_audibility\": {";
ost << "\"low_render_limit\": " << config.echo_audibility.low_render_limit ost << "\"low_render_limit\": " << config.echo_audibility.low_render_limit
<< ","; << ",";

View File

@ -41,19 +41,6 @@ bool EnableReverbModelling() {
return !field_trial::IsEnabled("WebRTC-Aec3ReverbModellingKillSwitch"); return !field_trial::IsEnabled("WebRTC-Aec3ReverbModellingKillSwitch");
} }
bool EnableSuppressorNearendAveraging() {
return !field_trial::IsEnabled(
"WebRTC-Aec3SuppressorNearendAveragingKillSwitch");
}
bool EnableSlowFilterAdaptation() {
return !field_trial::IsEnabled("WebRTC-Aec3SlowFilterAdaptationKillSwitch");
}
bool EnableShadowFilterJumpstart() {
return !field_trial::IsEnabled("WebRTC-Aec3ShadowFilterJumpstartKillSwitch");
}
bool EnableUnityInitialRampupGain() { bool EnableUnityInitialRampupGain() {
return field_trial::IsEnabled("WebRTC-Aec3EnableUnityInitialRampupGain"); return field_trial::IsEnabled("WebRTC-Aec3EnableUnityInitialRampupGain");
} }
@ -101,30 +88,6 @@ EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config) {
adjusted_cfg.ep_strength.reverb_based_on_render = false; adjusted_cfg.ep_strength.reverb_based_on_render = false;
} }
if (!EnableSuppressorNearendAveraging()) {
adjusted_cfg.suppressor.nearend_average_blocks = 1;
}
if (!EnableSlowFilterAdaptation()) {
if (!EnableShadowFilterJumpstart()) {
adjusted_cfg.filter.main.leakage_converged = 0.005f;
adjusted_cfg.filter.main.leakage_diverged = 0.1f;
}
adjusted_cfg.filter.main_initial.leakage_converged = 0.05f;
adjusted_cfg.filter.main_initial.leakage_diverged = 5.f;
}
if (!EnableShadowFilterJumpstart()) {
if (EnableSlowFilterAdaptation()) {
adjusted_cfg.filter.main.leakage_converged = 0.0005f;
adjusted_cfg.filter.main.leakage_diverged = 0.01f;
} else {
adjusted_cfg.filter.main.leakage_converged = 0.005f;
adjusted_cfg.filter.main.leakage_diverged = 0.1f;
}
adjusted_cfg.filter.main.error_floor = 0.001f;
}
if (!EnableNewFilterParams()) { if (!EnableNewFilterParams()) {
adjusted_cfg.filter.main.leakage_diverged = 0.01f; adjusted_cfg.filter.main.leakage_diverged = 0.01f;
adjusted_cfg.filter.main.error_floor = 0.1f; adjusted_cfg.filter.main.error_floor = 0.1f;

View File

@ -19,21 +19,12 @@
#include "system_wrappers/include/field_trial.h" #include "system_wrappers/include/field_trial.h"
namespace webrtc { namespace webrtc {
namespace {
size_t GetDownSamplingFactor(const EchoCanceller3Config& config) {
// Do not use down sampling factor 8 if kill switch is triggered.
return (config.delay.down_sampling_factor == 8 &&
field_trial::IsEnabled("WebRTC-Aec3DownSamplingFactor8KillSwitch"))
? 4
: config.delay.down_sampling_factor;
}
} // namespace
EchoPathDelayEstimator::EchoPathDelayEstimator( EchoPathDelayEstimator::EchoPathDelayEstimator(
ApmDataDumper* data_dumper, ApmDataDumper* data_dumper,
const EchoCanceller3Config& config) const EchoCanceller3Config& config)
: data_dumper_(data_dumper), : data_dumper_(data_dumper),
down_sampling_factor_(GetDownSamplingFactor(config)), down_sampling_factor_(config.delay.down_sampling_factor),
sub_block_size_(down_sampling_factor_ != 0 sub_block_size_(down_sampling_factor_ != 0
? kBlockSize / down_sampling_factor_ ? kBlockSize / down_sampling_factor_
: kBlockSize), : kBlockSize),
@ -45,7 +36,7 @@ EchoPathDelayEstimator::EchoPathDelayEstimator(
kMatchedFilterWindowSizeSubBlocks, kMatchedFilterWindowSizeSubBlocks,
config.delay.num_filters, config.delay.num_filters,
kMatchedFilterAlignmentShiftSizeSubBlocks, kMatchedFilterAlignmentShiftSizeSubBlocks,
GetDownSamplingFactor(config) == 8 config.delay.down_sampling_factor == 8
? config.render_levels.poor_excitation_render_limit_ds8 ? config.render_levels.poor_excitation_render_limit_ds8
: config.render_levels.poor_excitation_render_limit, : config.render_levels.poor_excitation_render_limit,
config.delay.delay_estimate_smoothing, config.delay.delay_estimate_smoothing,

View File

@ -35,14 +35,6 @@ bool EnableZeroExternalDelayHeadroom() {
"WebRTC-Aec3ZeroExternalDelayHeadroomKillSwitch"); "WebRTC-Aec3ZeroExternalDelayHeadroomKillSwitch");
} }
size_t GetDownSamplingFactor(const EchoCanceller3Config& config) {
// Do not use down sampling factor 8 if kill switch is triggered.
return (config.delay.down_sampling_factor == 8 &&
field_trial::IsEnabled("WebRTC-Aec3DownSamplingFactor8KillSwitch"))
? 4
: config.delay.down_sampling_factor;
}
class RenderDelayBufferImpl final : public RenderDelayBuffer { class RenderDelayBufferImpl final : public RenderDelayBuffer {
public: public:
RenderDelayBufferImpl(const EchoCanceller3Config& config, size_t num_bands); RenderDelayBufferImpl(const EchoCanceller3Config& config, size_t num_bands);
@ -177,7 +169,7 @@ RenderDelayBufferImpl::RenderDelayBufferImpl(const EchoCanceller3Config& config,
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
optimization_(DetectOptimization()), optimization_(DetectOptimization()),
config_(config), config_(config),
down_sampling_factor_(GetDownSamplingFactor(config)), down_sampling_factor_(config.delay.down_sampling_factor),
use_zero_external_delay_headroom_(EnableZeroExternalDelayHeadroom()), use_zero_external_delay_headroom_(EnableZeroExternalDelayHeadroom()),
sub_block_size_(static_cast<int>(down_sampling_factor_ > 0 sub_block_size_(static_cast<int>(down_sampling_factor_ > 0
? kBlockSize / down_sampling_factor_ ? kBlockSize / down_sampling_factor_

View File

@ -25,10 +25,6 @@
namespace webrtc { namespace webrtc {
namespace { namespace {
bool EnableNewSuppression() {
return !field_trial::IsEnabled("WebRTC-Aec3NewSuppressionKillSwitch");
}
// Adjust the gains according to the presence of known external filters. // Adjust the gains according to the presence of known external filters.
void AdjustForExternalFilters(std::array<float, kFftLengthBy2Plus1>* gain) { void AdjustForExternalFilters(std::array<float, kFftLengthBy2Plus1>* gain) {
// Limit the low frequency gains to avoid the impact of the high-pass filter // Limit the low frequency gains to avoid the impact of the high-pass filter
@ -83,57 +79,6 @@ void WeightEchoForAudibility(const EchoCanceller3Config& config,
weigh(threshold, normalizer, 7, kFftLengthBy2Plus1, echo, weighted_echo); weigh(threshold, normalizer, 7, kFftLengthBy2Plus1, echo, weighted_echo);
} }
// Computes the gain to reduce the echo to a non audible level.
void GainToNoAudibleEchoFallback(
const EchoCanceller3Config& config,
bool low_noise_render,
bool saturated_echo,
bool linear_echo_estimate,
const std::array<float, kFftLengthBy2Plus1>& nearend,
const std::array<float, kFftLengthBy2Plus1>& weighted_echo,
const std::array<float, kFftLengthBy2Plus1>& masker,
const std::array<float, kFftLengthBy2Plus1>& min_gain,
const std::array<float, kFftLengthBy2Plus1>& max_gain,
const std::array<float, kFftLengthBy2Plus1>& one_by_weighted_echo,
std::array<float, kFftLengthBy2Plus1>* gain) {
float nearend_masking_margin = 0.f;
if (linear_echo_estimate) {
nearend_masking_margin =
low_noise_render
? config.gain_mask.m9
: (saturated_echo ? config.gain_mask.m2 : config.gain_mask.m3);
} else {
nearend_masking_margin = config.gain_mask.m7;
}
RTC_DCHECK_LE(0.f, nearend_masking_margin);
RTC_DCHECK_GT(1.f, nearend_masking_margin);
const float masker_margin =
linear_echo_estimate ? config.gain_mask.m0 : config.gain_mask.m8;
for (size_t k = 0; k < gain->size(); ++k) {
// TODO(devicentepena): Experiment by removing the reverberation estimation
// from the nearend signal before computing the gains.
const float unity_gain_masker = std::max(nearend[k], masker[k]);
RTC_DCHECK_LE(0.f, nearend_masking_margin * unity_gain_masker);
if (weighted_echo[k] <= nearend_masking_margin * unity_gain_masker ||
unity_gain_masker <= 0.f) {
(*gain)[k] = 1.f;
} else {
RTC_DCHECK_LT(0.f, unity_gain_masker);
(*gain)[k] =
std::max(0.f, (1.f - config.gain_mask.gain_curve_slope *
weighted_echo[k] / unity_gain_masker) *
config.gain_mask.gain_curve_offset);
(*gain)[k] = std::max(masker_margin * masker[k] * one_by_weighted_echo[k],
(*gain)[k]);
}
(*gain)[k] = std::min(std::max((*gain)[k], min_gain[k]), max_gain[k]);
}
}
// TODO(peah): Make adaptive to take the actual filter error into account. // TODO(peah): Make adaptive to take the actual filter error into account.
constexpr size_t kUpperAccurateBandPlus1 = 29; constexpr size_t kUpperAccurateBandPlus1 = 29;
@ -321,30 +266,9 @@ void SuppressionGain::LowerBandGain(
std::array<float, kFftLengthBy2Plus1> max_gain; std::array<float, kFftLengthBy2Plus1> max_gain;
GetMaxGain(max_gain); GetMaxGain(max_gain);
// Iteratively compute the gain required to attenuate the echo to a non
// noticeable level.
if (enable_new_suppression_) {
GainToNoAudibleEcho(nearend, weighted_residual_echo, comfort_noise, GainToNoAudibleEcho(nearend, weighted_residual_echo, comfort_noise,
min_gain, max_gain, gain); min_gain, max_gain, gain);
AdjustForExternalFilters(gain); AdjustForExternalFilters(gain);
} else {
const bool linear_echo_estimate = aec_state.UsableLinearEstimate();
std::array<float, kFftLengthBy2Plus1> masker;
std::array<float, kFftLengthBy2Plus1> one_by_weighted_echo;
std::transform(weighted_residual_echo.begin(), weighted_residual_echo.end(),
one_by_weighted_echo.begin(),
[](float e) { return e > 0.f ? 1.f / e : 1.f; });
gain->fill(0.f);
for (int k = 0; k < 2; ++k) {
std::copy(comfort_noise.begin(), comfort_noise.end(), masker.begin());
GainToNoAudibleEchoFallback(config_, low_noise_render, saturated_echo,
linear_echo_estimate, nearend,
weighted_residual_echo, masker, min_gain,
max_gain, one_by_weighted_echo, gain);
AdjustForExternalFilters(gain);
}
}
// Adjust the gain for frequencies which have not yet converged. // Adjust the gain for frequencies which have not yet converged.
AdjustNonConvergedFrequencies(gain); AdjustNonConvergedFrequencies(gain);
@ -372,7 +296,6 @@ SuppressionGain::SuppressionGain(const EchoCanceller3Config& config,
config_(config), config_(config),
state_change_duration_blocks_( state_change_duration_blocks_(
static_cast<int>(config_.filter.config_change_duration_blocks)), static_cast<int>(config_.filter.config_change_duration_blocks)),
enable_new_suppression_(EnableNewSuppression()),
moving_average_(kFftLengthBy2Plus1, moving_average_(kFftLengthBy2Plus1,
config.suppressor.nearend_average_blocks), config.suppressor.nearend_average_blocks),
nearend_params_(config_.suppressor.nearend_tuning), nearend_params_(config_.suppressor.nearend_tuning),

View File

@ -137,7 +137,6 @@ class SuppressionGain {
LowNoiseRenderDetector low_render_detector_; LowNoiseRenderDetector low_render_detector_;
bool initial_state_ = true; bool initial_state_ = true;
int initial_state_change_counter_ = 0; int initial_state_change_counter_ = 0;
const bool enable_new_suppression_;
aec3::MovingAverage moving_average_; aec3::MovingAverage moving_average_;
const GainParameters nearend_params_; const GainParameters nearend_params_;
const GainParameters normal_params_; const GainParameters normal_params_;

View File

@ -25,33 +25,39 @@ namespace webrtc {
namespace { namespace {
const std::string kFieldTrialNames[] = { const std::string kFieldTrialNames[] = {
"WebRTC-Aec3TransparentModeKillSwitch", "WebRTC-Aec3AdaptErleOnLowRenderKillSwitch",
"WebRTC-Aec3StationaryRenderImprovementsKillSwitch", "WebRTC-Aec3AgcGainChangeResponseKillSwitch",
"WebRTC-Aec3EnforceDelayAfterRealignmentKillSwitch", "WebRTC-Aec3BoundedNearendKillSwitch",
"WebRTC-Aec3UseShortDelayEstimatorWindow", "WebRTC-Aec3EarlyShadowFilterJumpstartKillSwitch",
"WebRTC-Aec3ReverbBasedOnRenderKillSwitch", "WebRTC-Aec3EnableAdaptiveEchoReverbEstimation",
"WebRTC-Aec3ReverbModellingKillSwitch", "WebRTC-Aec3EnableLegacyDominantNearend",
"WebRTC-Aec3FilterAnalyzerPreprocessorKillSwitch", "WebRTC-Aec3EnableUnityInitialRampupGain",
"WebRTC-Aec3TransparencyImprovementsKillSwitch", "WebRTC-Aec3EnableUnityNonZeroRampupGain",
"WebRTC-Aec3SoftTransparentModeKillSwitch",
"WebRTC-Aec3OverrideEchoPathGainKillSwitch",
"WebRTC-Aec3ZeroExternalDelayHeadroomKillSwitch",
"WebRTC-Aec3DownSamplingFactor8KillSwitch",
"WebRTC-Aec3EnforceSkewHysteresis1", "WebRTC-Aec3EnforceSkewHysteresis1",
"WebRTC-Aec3EnforceSkewHysteresis2", "WebRTC-Aec3EnforceSkewHysteresis2",
"WebRTC-Aec3NewSuppressionKillSwitch", "WebRTC-Aec3FilterAnalyzerPreprocessorKillSwitch",
"WebRTC-Aec3LinearModeWithDivergedFilterKillSwitch",
"WebRTC-Aec3MisadjustmentEstimatorKillSwitch", "WebRTC-Aec3MisadjustmentEstimatorKillSwitch",
"WebRTC-Aec3NewFilterParamsKillSwitch",
"WebRTC-Aec3OverrideEchoPathGainKillSwitch",
"WebRTC-Aec3RapidAgcGainRecoveryKillSwitch", "WebRTC-Aec3RapidAgcGainRecoveryKillSwitch",
"WebRTC-Aec3SlowFilterAdaptationKillSwitch", "WebRTC-Aec3ResetErleAtGainChangesKillSwitch",
"WebRTC-Aec3SmoothUpdatesTailFreqRespKillSwitch", "WebRTC-Aec3ReverbBasedOnRenderKillSwitch",
"WebRTC-Aec3SuppressorNearendAveragingKillSwitch", "WebRTC-Aec3ReverbModellingKillSwitch",
"WebRTC-Aec3AgcGainChangeResponseKillSwitch", "WebRTC-Aec3ShadowFilterBoostedJumpstartKillSwitch",
"WebRTC-Aec3ShadowFilterJumpstartKillSwitch", "WebRTC-Aec3ShadowFilterJumpstartKillSwitch",
"WebRTC-Aec3EarlyLinearFilterUsageKillSwitch", "WebRTC-Aec3ShortReverbKillSwitch",
"WebRTC-Aec3ShortInitialStateKillSwitch", "WebRTC-Aec3SmoothSignalTransitionsKillSwitch",
"WebRTC-Aec3SmoothUpdatesTailFreqRespKillSwitch",
"WebRTC-Aec3SoftTransparentModeKillSwitch",
"WebRTC-Aec3StandardNonlinearReverbModelKillSwitch", "WebRTC-Aec3StandardNonlinearReverbModelKillSwitch",
"WebRTC-Aec3EnableAdaptiveEchoReverbEstimation"}; "WebRTC-Aec3StrictDivergenceCheckKillSwitch",
"WebRTC-Aec3UseLegacyNormalSuppressorTuning",
"WebRTC-Aec3UseOffsetBlocks",
"WebRTC-Aec3UseShortDelayEstimatorWindow",
"WebRTC-Aec3UseStationarityPropertiesKillSwitch",
"WebRTC-Aec3UtilizeShadowFilterOutputKillSwitch",
"WebRTC-Aec3ZeroExternalDelayHeadroomKillSwitch",
};
std::unique_ptr<AudioProcessing> CreateApm(test::FuzzDataHelper* fuzz_data, std::unique_ptr<AudioProcessing> CreateApm(test::FuzzDataHelper* fuzz_data,
std::string* field_trial_string) { std::string* field_trial_string) {