diff --git a/modules/audio_processing/BUILD.gn b/modules/audio_processing/BUILD.gn index 186c43adbe..99314f33d9 100644 --- a/modules/audio_processing/BUILD.gn +++ b/modules/audio_processing/BUILD.gn @@ -716,6 +716,7 @@ if (rtc_include_tests) { "../../rtc_base:checks", "../../rtc_base:protobuf_utils", "../../rtc_base:rtc_base_approved", + "../../rtc_base:rtc_json", "../../rtc_base:rtc_task_queue", "../../rtc_base:stringutils", "../../system_wrappers", diff --git a/modules/audio_processing/test/audio_processing_simulator.cc b/modules/audio_processing/test/audio_processing_simulator.cc index 82bffe427f..28dc7cf5f0 100644 --- a/modules/audio_processing/test/audio_processing_simulator.cc +++ b/modules/audio_processing/test/audio_processing_simulator.cc @@ -11,6 +11,7 @@ #include "modules/audio_processing/test/audio_processing_simulator.h" #include +#include #include #include #include @@ -23,6 +24,7 @@ #include "modules/audio_processing/include/audio_processing.h" #include "modules/audio_processing/test/fake_recording_device.h" #include "rtc_base/checks.h" +#include "rtc_base/json.h" #include "rtc_base/logging.h" #include "rtc_base/stringutils.h" @@ -30,6 +32,223 @@ namespace webrtc { namespace test { namespace { +void ReadParam(const Json::Value& root, std::string param_name, bool* param) { + RTC_CHECK(param); + bool v; + if (rtc::GetBoolFromJsonObject(root, param_name, &v)) { + *param = v; + std::cout << param_name << ":" << (*param ? "true" : "false") << std::endl; + } +} + +void ReadParam(const Json::Value& root, std::string param_name, size_t* param) { + RTC_CHECK(param); + int v; + if (rtc::GetIntFromJsonObject(root, param_name, &v)) { + *param = v; + std::cout << param_name << ":" << *param << std::endl; + } +} + +void ReadParam(const Json::Value& root, std::string param_name, int* param) { + RTC_CHECK(param); + int v; + if (rtc::GetIntFromJsonObject(root, param_name, &v)) { + *param = v; + std::cout << param_name << ":" << *param << std::endl; + } +} + +void ReadParam(const Json::Value& root, std::string param_name, float* param) { + RTC_CHECK(param); + double v; + if (rtc::GetDoubleFromJsonObject(root, param_name, &v)) { + *param = static_cast(v); + std::cout << param_name << ":" << *param << std::endl; + } +} + +void ReadParam(const Json::Value& root, + std::string param_name, + EchoCanceller3Config::Filter::MainConfiguration* param) { + RTC_CHECK(param); + Json::Value json_array; + if (rtc::GetValueFromJsonObject(root, param_name, &json_array)) { + std::vector v; + rtc::JsonArrayToDoubleVector(json_array, &v); + if (v.size() != 5) { + std::cout << "Incorrect array size for " << param_name << std::endl; + RTC_CHECK(false); + } + param->length_blocks = static_cast(v[0]); + param->leakage_converged = static_cast(v[1]); + param->leakage_diverged = static_cast(v[2]); + param->error_floor = static_cast(v[3]); + param->noise_gate = static_cast(v[4]); + + std::cout << param_name << ":" + << "[" << param->length_blocks << "," << param->leakage_converged + << "," << param->leakage_diverged << "," << param->error_floor + << "," << param->noise_gate << "]" << std::endl; + } +} + +void ReadParam(const Json::Value& root, + std::string param_name, + EchoCanceller3Config::Filter::ShadowConfiguration* param) { + RTC_CHECK(param); + Json::Value json_array; + if (rtc::GetValueFromJsonObject(root, param_name, &json_array)) { + std::vector v; + rtc::JsonArrayToDoubleVector(json_array, &v); + if (v.size() != 3) { + std::cout << "Incorrect array size for " << param_name << std::endl; + RTC_CHECK(false); + } + param->length_blocks = static_cast(v[0]); + param->rate = static_cast(v[1]); + param->noise_gate = static_cast(v[2]); + std::cout << param_name << ":" + << "[" << param->length_blocks << "," << param->rate << "," + << param->noise_gate << "]" << std::endl; + } +} + +void ReadParam(const Json::Value& root, + std::string param_name, + EchoCanceller3Config::GainUpdates::GainChanges* param) { + RTC_CHECK(param); + Json::Value json_array; + if (rtc::GetValueFromJsonObject(root, param_name, &json_array)) { + std::vector v; + rtc::JsonArrayToDoubleVector(json_array, &v); + if (v.size() != 6) { + std::cout << "Incorrect array size for " << param_name << std::endl; + RTC_CHECK(false); + } + param->max_inc = static_cast(v[0]); + param->max_dec = static_cast(v[1]); + param->rate_inc = static_cast(v[2]); + param->rate_dec = static_cast(v[3]); + param->min_inc = static_cast(v[4]); + param->min_dec = static_cast(v[5]); + + std::cout << param_name << ":" + << "[" << param->max_inc << "," << param->max_dec << "," + << param->rate_inc << "," << param->rate_dec << "," + << param->min_inc << "," << param->min_dec << "]" << std::endl; + } +} + +EchoCanceller3Config ParseAec3Parameters(const std::string& filename) { + EchoCanceller3Config cfg; + Json::Value root; + std::string s; + std::string json_string; + std::ifstream f(filename.c_str()); + + if (f.fail()) { + std::cout << "Failed to open the file " << filename << std::endl; + RTC_CHECK(false); + } + + while (std::getline(f, s)) { + json_string += s; + } + bool failed = Json::Reader().parse(json_string, root); + if (failed) { + std::cout << "Incorrect JSON format:" << std::endl; + std::cout << json_string << std::endl; + RTC_CHECK(false); + } + + std::cout << "AEC3 Parameters from JSON input:" << std::endl; + Json::Value section; + if (rtc::GetValueFromJsonObject(root, "delay", §ion)) { + ReadParam(section, "default_delay", &cfg.delay.default_delay); + ReadParam(section, "down_sampling_factor", &cfg.delay.down_sampling_factor); + ReadParam(section, "num_filters", &cfg.delay.num_filters); + ReadParam(section, "api_call_jitter_blocks", + &cfg.delay.api_call_jitter_blocks); + ReadParam(section, "min_echo_path_delay_blocks", + &cfg.delay.min_echo_path_delay_blocks); + ReadParam(section, "delay_headroom_blocks", + &cfg.delay.delay_headroom_blocks); + ReadParam(section, "hysteresis_limit_1_blocks", + &cfg.delay.hysteresis_limit_1_blocks); + ReadParam(section, "hysteresis_limit_2_blocks", + &cfg.delay.hysteresis_limit_2_blocks); + } + + if (rtc::GetValueFromJsonObject(root, "filter", §ion)) { + ReadParam(section, "main", &cfg.filter.main); + ReadParam(section, "shadow", &cfg.filter.shadow); + ReadParam(section, "main_initial", &cfg.filter.main_initial); + ReadParam(section, "shadow_initial", &cfg.filter.shadow_initial); + } + + if (rtc::GetValueFromJsonObject(root, "erle", §ion)) { + ReadParam(section, "min", &cfg.erle.min); + ReadParam(section, "max_l", &cfg.erle.max_l); + ReadParam(section, "max_h", &cfg.erle.max_h); + } + + if (rtc::GetValueFromJsonObject(root, "ep_strength", §ion)) { + ReadParam(section, "lf", &cfg.ep_strength.lf); + ReadParam(section, "mf", &cfg.ep_strength.mf); + ReadParam(section, "hf", &cfg.ep_strength.hf); + ReadParam(section, "default_len", &cfg.ep_strength.default_len); + ReadParam(section, "echo_can_saturate", &cfg.ep_strength.echo_can_saturate); + ReadParam(section, "bounded_erl", &cfg.ep_strength.bounded_erl); + } + + if (rtc::GetValueFromJsonObject(root, "gain_mask", §ion)) { + ReadParam(section, "m1", &cfg.gain_mask.m1); + ReadParam(section, "m2", &cfg.gain_mask.m2); + ReadParam(section, "m3", &cfg.gain_mask.m3); + ReadParam(section, "m4", &cfg.gain_mask.m4); + 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); + } + + if (rtc::GetValueFromJsonObject(root, "echo_audibility", §ion)) { + ReadParam(section, "low_render_limit", + &cfg.echo_audibility.low_render_limit); + ReadParam(section, "normal_render_limit", + &cfg.echo_audibility.normal_render_limit); + } + + if (rtc::GetValueFromJsonObject(root, "gain_updates", §ion)) { + ReadParam(section, "low_noise", &cfg.gain_updates.low_noise); + ReadParam(section, "initial", &cfg.gain_updates.initial); + ReadParam(section, "normal", &cfg.gain_updates.normal); + ReadParam(section, "saturation", &cfg.gain_updates.saturation); + ReadParam(section, "nonlinear", &cfg.gain_updates.nonlinear); + ReadParam(section, "floor_first_increase", + &cfg.gain_updates.floor_first_increase); + } + + if (rtc::GetValueFromJsonObject(root, "echo_removal_control", §ion)) { + Json::Value subsection; + if (rtc::GetValueFromJsonObject(section, "gain_rampup", &subsection)) { + ReadParam(section, "first_non_zero_gain", + &cfg.echo_removal_control.gain_rampup.first_non_zero_gain); + ReadParam(section, "non_zero_gain_blocks", + &cfg.echo_removal_control.gain_rampup.non_zero_gain_blocks); + ReadParam(section, "full_gain_blocks", + &cfg.echo_removal_control.gain_rampup.full_gain_blocks); + } + ReadParam(section, "has_clock_drift", + &cfg.echo_removal_control.has_clock_drift); + } + + std::cout << std::endl; + return cfg; +} + void CopyFromAudioFrame(const AudioFrame& src, ChannelBuffer* dest) { RTC_CHECK_EQ(src.num_channels_, dest->num_channels()); RTC_CHECK_EQ(src.samples_per_channel_, dest->num_frames()); @@ -326,7 +545,11 @@ void AudioProcessingSimulator::CreateAudioProcessor() { apm_config.gain_controller2.fixed_gain_db = settings_.agc2_fixed_gain_db; } if (settings_.use_aec3 && *settings_.use_aec3) { - echo_control_factory.reset(new EchoCanceller3Factory()); + EchoCanceller3Config cfg; + if (settings_.aec3_settings_filename) { + cfg = ParseAec3Parameters(*settings_.aec3_settings_filename); + } + echo_control_factory.reset(new EchoCanceller3Factory(cfg)); } if (settings_.use_lc) { apm_config.level_controller.enabled = *settings_.use_lc; diff --git a/modules/audio_processing/test/audio_processing_simulator.h b/modules/audio_processing/test/audio_processing_simulator.h index 41a3f45106..56738d2cbf 100644 --- a/modules/audio_processing/test/audio_processing_simulator.h +++ b/modules/audio_processing/test/audio_processing_simulator.h @@ -90,6 +90,7 @@ struct SimulationSettings { bool fixed_interface = false; bool store_intermediate_output = false; rtc::Optional custom_call_order_filename; + rtc::Optional aec3_settings_filename; }; // Holds a few statistics about a series of TickIntervals. diff --git a/modules/audio_processing/test/audioproc_float.cc b/modules/audio_processing/test/audioproc_float.cc index c5229a4e10..5a3255dcba 100644 --- a/modules/audio_processing/test/audioproc_float.cc +++ b/modules/audio_processing/test/audioproc_float.cc @@ -181,6 +181,9 @@ DEFINE_bool(store_intermediate_output, false, "Creates new output files after each init"); DEFINE_string(custom_call_order_file, "", "Custom process API call order file"); +DEFINE_string(aec3_settings, + "", + "File in JSON-format with custom AEC3 settings"); DEFINE_bool(help, false, "Print this message"); void SetSettingIfSpecified(const std::string& value, @@ -279,6 +282,7 @@ SimulationSettings CreateSettings() { &settings.stream_drift_samples); SetSettingIfSpecified(FLAG_custom_call_order_file, &settings.custom_call_order_filename); + SetSettingIfSpecified(FLAG_aec3_settings, &settings.aec3_settings_filename); settings.initial_mic_level = FLAG_initial_mic_level; settings.simulate_mic_gain = FLAG_simulate_mic_gain; SetSettingIfSpecified(FLAG_simulated_mic_kind, &settings.simulated_mic_kind);