Move config from CRAS to webrtc-apm

Before this change, APM and AEC3 settings are passed to
webrtc-apm library by additional struct. The logic of
parsing config file and finally sets to APM/AEC3 config
structures are separated in different projects, and that
makes maintainance difficult.
This change fixes the problem by passing ini dictionary
to webrtc-apm library, and owns the parsing logic.

New files under cras-conifg/ are copied from CRAS/adhd
and applied necessary adjustment.

BUG=chromium:906512
TEST=Build and test on nocturne
CQ-DEPEND=CL:1337229

Change-Id: Ib2835f0053800fb091fce5a5a29f2b177e809575
Reviewed-on: https://chromium-review.googlesource.com/1337170
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: Hsinyu Chao <hychao@chromium.org>
Reviewed-by: Cheng-Yi Chiang <cychiang@chromium.org>
Reviewed-by: Per Ã…hgren <peah@chromium.org>
diff --git a/Makefile b/Makefile
index 21bb278..3025aed 100644
--- a/Makefile
+++ b/Makefile
@@ -30,7 +30,8 @@
 	system_wrappers/source/libsystem_wrappers \
 	modules/audio_coding/libaudio_coding \
 	modules/audio_processing/libaudioproc_debug_proto \
-	absl
+	absl \
+	cras-config
 
 CXX_LIBRARY(libwebrtc_apm.so): CPPFLAGS += \
 	$(call get_pc_cflags,$(webrtc_apm_PC_DEPS))
@@ -43,6 +44,8 @@
 	rtc_base/librtc_base.pic.a \
 	libaudioproc_debug_proto.pic.a \
 	absl.pic.a \
-	$(call get_pc_libs,$(webrtc_apm_PC_DEPS))
+	cras-config.pic.a \
+	$(call get_pc_libs,$(webrtc_apm_PC_DEPS)) \
+	-liniparser
 
 all: CXX_LIBRARY(libwebrtc_apm.so)
diff --git a/cras-config/aec_config.cc b/cras-config/aec_config.cc
new file mode 100644
index 0000000..68696c6
--- /dev/null
+++ b/cras-config/aec_config.cc
@@ -0,0 +1,465 @@
+/* Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <syslog.h>
+
+#include "aec_config.h"
+
+#define AEC_CONFIG_NAME "aec.ini"
+
+#define AEC_GET_INT(ini, category, key)			\
+	iniparser_getint(				\
+		ini, AEC_ ## category ## _ ## key,	\
+		AEC_ ## category ## _ ## key ## _VALUE)
+
+#define AEC_GET_FLOAT(ini, category, key)		\
+	iniparser_getdouble(				\
+		ini, AEC_ ## category ## _ ## key,	\
+		AEC_ ## category ## _ ## key ## _VALUE)
+
+void aec_config_get(dictionary *ini, webrtc::EchoCanceller3Config *config)
+{
+	if (ini == NULL)
+		return;
+
+	config->delay.default_delay =
+		AEC_GET_INT(ini, DELAY, DEFAULT_DELAY);
+	config->delay.down_sampling_factor =
+		AEC_GET_INT(ini, DELAY, DOWN_SAMPLING_FACTOR);
+	config->delay.num_filters =
+		AEC_GET_INT(ini, DELAY, NUM_FILTERS);
+	config->delay.api_call_jitter_blocks =
+		AEC_GET_INT(ini, DELAY, API_CALL_JITTER_BLOCKS);
+	config->delay.min_echo_path_delay_blocks =
+		AEC_GET_INT(ini, DELAY, MIN_ECHO_PATH_DELAY_BLOCKS);
+	config->delay.delay_headroom_blocks =
+		AEC_GET_INT(ini, DELAY, DELAY_HEADROOM_BLOCKS);
+	config->delay.hysteresis_limit_1_blocks =
+		AEC_GET_INT(ini, DELAY, HYSTERESIS_LIMIT_1_BLOCKS);
+	config->delay.hysteresis_limit_2_blocks =
+		AEC_GET_INT(ini, DELAY, HYSTERESIS_LIMIT_2_BLOCKS);
+	config->delay.skew_hysteresis_blocks =
+		AEC_GET_INT(ini, DELAY, SKEW_HYSTERESIS_BLOCKS);
+	config->delay.fixed_capture_delay_samples =
+		AEC_GET_INT(ini, DELAY, FIXED_CAPTURE_DELAY_SAMPLES);
+
+	config->filter.main.length_blocks =
+		AEC_GET_INT(ini, FILTER_MAIN, LENGTH_BLOCKS);
+	config->filter.main.leakage_converged =
+		AEC_GET_FLOAT(ini, FILTER_MAIN, LEAKAGE_CONVERGED);
+	config->filter.main.leakage_diverged =
+		AEC_GET_FLOAT(ini, FILTER_MAIN, LEAKAGE_DIVERGED);
+	config->filter.main.error_floor =
+		AEC_GET_FLOAT(ini, FILTER_MAIN, ERROR_FLOOR);
+	config->filter.main.noise_gate =
+		AEC_GET_FLOAT(ini, FILTER_MAIN, NOISE_GATE);
+
+	config->filter.shadow.length_blocks =
+		AEC_GET_INT(ini, FILTER_SHADOW, LENGTH_BLOCKS);
+	config->filter.shadow.rate =
+		AEC_GET_FLOAT(ini, FILTER_SHADOW, RATE);
+	config->filter.shadow.noise_gate =
+		AEC_GET_FLOAT(ini, FILTER_SHADOW, NOISE_GATE);
+
+	config->filter.main_initial.length_blocks =
+		AEC_GET_INT(ini, FILTER_MAIN_INIT, LENGTH_BLOCKS);
+	config->filter.main_initial.leakage_converged =
+		AEC_GET_FLOAT(ini, FILTER_MAIN_INIT, LEAKAGE_CONVERGED);
+	config->filter.main_initial.leakage_diverged =
+		AEC_GET_FLOAT(ini, FILTER_MAIN_INIT, LEAKAGE_DIVERGED);
+	config->filter.main_initial.error_floor =
+		AEC_GET_FLOAT(ini, FILTER_MAIN_INIT, ERROR_FLOOR);
+	config->filter.main_initial.noise_gate =
+		AEC_GET_FLOAT(ini, FILTER_MAIN_INIT, NOISE_GATE);
+
+	config->filter.shadow_initial.length_blocks =
+		AEC_GET_INT(ini, FILTER_SHADOW_INIT, LENGTH_BLOCKS);
+	config->filter.shadow_initial.rate =
+		AEC_GET_FLOAT(ini, FILTER_SHADOW_INIT, RATE);
+	config->filter.shadow_initial.noise_gate =
+		AEC_GET_FLOAT(ini, FILTER_SHADOW_INIT, NOISE_GATE);
+
+	config->filter.config_change_duration_blocks =
+		AEC_GET_INT(ini, FILTER, CONFIG_CHANGE_DURATION_BLOCKS);
+	config->filter.initial_state_seconds =
+		AEC_GET_FLOAT(ini, FILTER, INITIAL_STATE_SECONDS);
+	config->filter.conservative_initial_phase =
+		AEC_GET_INT(ini, FILTER, CONSERVATIVE_INITIAL_PHASE);
+	config->filter.enable_shadow_filter_output_usage =
+		AEC_GET_INT(ini, FILTER, ENABLE_SHADOW_FILTER_OUTPUT_USAGE);
+
+	config->erle.min =
+		AEC_GET_FLOAT(ini, ERLE, MIN);
+	config->erle.max_l =
+		AEC_GET_FLOAT(ini, ERLE, MAX_L);
+	config->erle.max_h =
+		AEC_GET_FLOAT(ini, ERLE, MAX_H);
+	config->erle.onset_detection =
+		AEC_GET_INT(ini, ERLE, ONSET_DETECTION);
+
+	config->ep_strength.lf =
+		AEC_GET_FLOAT(ini, EP_STRENGTH, LF);
+	config->ep_strength.mf =
+		AEC_GET_FLOAT(ini, EP_STRENGTH, MF);
+	config->ep_strength.hf =
+		AEC_GET_FLOAT(ini, EP_STRENGTH, HF);
+	config->ep_strength.default_len =
+		AEC_GET_FLOAT(ini, EP_STRENGTH, DEFAULT_LEN);
+	config->ep_strength.reverb_based_on_render =
+		AEC_GET_INT(ini, EP_STRENGTH, REVERB_BASED_ON_RENDER);
+	config->ep_strength.bounded_erl =
+		AEC_GET_INT(ini, EP_STRENGTH, BOUNDED_ERL);
+	config->ep_strength.echo_can_saturate =
+		AEC_GET_INT(ini, EP_STRENGTH, ECHO_CAN_SATURATE);
+
+	config->gain_mask.m0 =
+		AEC_GET_FLOAT(ini, GAIN_MASK, M0);
+	config->gain_mask.m1 =
+		AEC_GET_FLOAT(ini, GAIN_MASK, M1);
+	config->gain_mask.m2 =
+		AEC_GET_FLOAT(ini, GAIN_MASK, M2);
+	config->gain_mask.m3 =
+		AEC_GET_FLOAT(ini, GAIN_MASK, M3);
+	config->gain_mask.m5 =
+		AEC_GET_FLOAT(ini, GAIN_MASK, M5);
+	config->gain_mask.m6 =
+		AEC_GET_FLOAT(ini, GAIN_MASK, M6);
+	config->gain_mask.m7 =
+		AEC_GET_FLOAT(ini, GAIN_MASK, M7);
+	config->gain_mask.m8 =
+		AEC_GET_FLOAT(ini, GAIN_MASK, M8);
+	config->gain_mask.m9 =
+		AEC_GET_FLOAT(ini, GAIN_MASK, M9);
+	config->gain_mask.gain_curve_offset =
+		AEC_GET_FLOAT(ini, GAIN_MASK, GAIN_CURVE_OFFSET);
+	config->gain_mask.gain_curve_slope =
+		AEC_GET_FLOAT(ini, GAIN_MASK, GAIN_CURVE_SLOPE);
+	config->gain_mask.temporal_masking_lf =
+		AEC_GET_FLOAT(ini, GAIN_MASK, TEMPORAL_MASKING_LF);
+	config->gain_mask.temporal_masking_hf =
+		AEC_GET_FLOAT(ini, GAIN_MASK, TEMPORAL_MASKING_HF);
+	config->gain_mask.temporal_masking_lf_bands =
+		AEC_GET_INT(ini, GAIN_MASK, TEMPORAL_MASKING_LF_BANDS);
+
+	config->echo_audibility.low_render_limit =
+		AEC_GET_FLOAT(ini, ECHO_AUDIBILITY, LOW_RENDER_LIMIT);
+	config->echo_audibility.normal_render_limit =
+		AEC_GET_FLOAT(ini, ECHO_AUDIBILITY, NORMAL_RENDER_LIMIT);
+	config->echo_audibility.floor_power =
+		AEC_GET_FLOAT(ini, ECHO_AUDIBILITY, FLOOR_POWER);
+	config->echo_audibility.audibility_threshold_lf =
+		AEC_GET_FLOAT(ini, ECHO_AUDIBILITY, AUDIBILITY_THRESHOLD_LF);
+	config->echo_audibility.audibility_threshold_mf =
+		AEC_GET_FLOAT(ini, ECHO_AUDIBILITY, AUDIBILITY_THRESHOLD_MF);
+	config->echo_audibility.audibility_threshold_hf =
+		AEC_GET_FLOAT(ini, ECHO_AUDIBILITY, AUDIBILITY_THRESHOLD_HF);
+	config->echo_audibility.use_stationary_properties =
+		AEC_GET_INT(ini, ECHO_AUDIBILITY, USE_STATIONARY_PROPERTIES);
+
+	config->render_levels.active_render_limit =
+		AEC_GET_FLOAT(ini, RENDER_LEVELS, ACTIVE_RENDER_LIMIT);
+	config->render_levels.poor_excitation_render_limit =
+		AEC_GET_FLOAT(ini, RENDER_LEVELS, POOR_EXCITATION_RENDER_LIMIT);
+	config->render_levels.poor_excitation_render_limit_ds8 =
+		AEC_GET_FLOAT(ini, RENDER_LEVELS, POOR_EXCITATION_RENDER_LIMIT_DS8);
+
+	config->echo_removal_control.gain_rampup.initial_gain =
+		AEC_GET_FLOAT(ini, ECHO_REMOVAL_CTL, INITIAL_GAIN);
+	config->echo_removal_control.gain_rampup.first_non_zero_gain =
+		AEC_GET_FLOAT(ini, ECHO_REMOVAL_CTL, FIRST_NON_ZERO_GAIN);
+	config->echo_removal_control.gain_rampup.non_zero_gain_blocks =
+		AEC_GET_INT(ini, ECHO_REMOVAL_CTL, NON_ZERO_GAIN_BLOCKS);
+	config->echo_removal_control.gain_rampup.full_gain_blocks =
+		AEC_GET_INT(ini, ECHO_REMOVAL_CTL, FULL_GAIN_BLOCKS);
+	config->echo_removal_control.has_clock_drift =
+		AEC_GET_INT(ini, ECHO_REMOVAL_CTL, HAS_CLOCK_DRIFT);
+	config->echo_removal_control.linear_and_stable_echo_path =
+		AEC_GET_INT(ini, ECHO_REMOVAL_CTL, LINEAR_AND_STABLE_ECHO_PATH);
+
+	config->echo_model.noise_floor_hold =
+		AEC_GET_INT(ini, ECHO_MODEL, NOISE_FLOOR_HOLD);
+	config->echo_model.min_noise_floor_power =
+		AEC_GET_FLOAT(ini, ECHO_MODEL, MIN_NOISE_FLOOR_POWER);
+	config->echo_model.stationary_gate_slope =
+		AEC_GET_FLOAT(ini, ECHO_MODEL, STATIONARY_GATE_SLOPE);
+	config->echo_model.noise_gate_power =
+		AEC_GET_FLOAT(ini, ECHO_MODEL, NOISE_GATE_POWER);
+	config->echo_model.noise_gate_slope =
+		AEC_GET_FLOAT(ini, ECHO_MODEL, NOISE_GATE_SLOPE);
+	config->echo_model.render_pre_window_size =
+		AEC_GET_INT(ini, ECHO_MODEL, RENDER_PRE_WINDOW_SIZE);
+	config->echo_model.render_post_window_size =
+		AEC_GET_INT(ini, ECHO_MODEL, RENDER_POST_WINDOW_SIZE);
+	config->echo_model.render_pre_window_size_init =
+		AEC_GET_INT(ini, ECHO_MODEL, RENDER_PRE_WINDOW_SIZE_INIT);
+	config->echo_model.render_post_window_size_init =
+		AEC_GET_INT(ini, ECHO_MODEL, RENDER_POST_WINDOW_SIZE_INIT);
+	config->echo_model.nonlinear_hold =
+		AEC_GET_FLOAT(ini, ECHO_MODEL, NONLINEAR_HOLD);
+	config->echo_model.nonlinear_release =
+		AEC_GET_FLOAT(ini, ECHO_MODEL, NONLINEAR_RELEASE);
+
+	config->suppressor.nearend_average_blocks =
+		AEC_GET_INT(ini, SUPPRESSOR, NEAREND_AVERAGE_BLOCKS);
+
+	config->suppressor.normal_tuning.mask_lf.enr_transparent =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_NORMAL_TUNING,
+			      MASK_LF_ENR_TRANSPARENT);
+	config->suppressor.normal_tuning.mask_lf.enr_suppress =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_NORMAL_TUNING,
+			      MASK_LF_ENR_SUPPRESS);
+	config->suppressor.normal_tuning.mask_lf.emr_transparent =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_NORMAL_TUNING,
+			      MASK_LF_EMR_TRANSPARENT);
+	config->suppressor.normal_tuning.mask_hf.enr_transparent =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_NORMAL_TUNING,
+			      MASK_HF_ENR_TRANSPARENT);
+	config->suppressor.normal_tuning.mask_hf.enr_suppress =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_NORMAL_TUNING,
+			      MASK_HF_ENR_SUPPRESS);
+	config->suppressor.normal_tuning.mask_hf.emr_transparent =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_NORMAL_TUNING,
+			      MASK_HF_EMR_TRANSPARENT);
+	config->suppressor.normal_tuning.max_inc_factor =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_NORMAL_TUNING, MAX_INC_FACTOR);
+	config->suppressor.normal_tuning.max_dec_factor_lf =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_NORMAL_TUNING, MAX_DEC_FACTOR_LF);
+
+	config->suppressor.nearend_tuning.mask_lf.enr_transparent =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_NEAREND_TUNING,
+			      MASK_LF_ENR_TRANSPARENT);
+	config->suppressor.nearend_tuning.mask_lf.enr_suppress =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_NEAREND_TUNING,
+			      MASK_LF_ENR_SUPPRESS);
+	config->suppressor.nearend_tuning.mask_lf.emr_transparent =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_NEAREND_TUNING,
+			      MASK_LF_EMR_TRANSPARENT);
+	config->suppressor.nearend_tuning.mask_hf.enr_transparent =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_NEAREND_TUNING,
+			      MASK_HF_ENR_TRANSPARENT);
+	config->suppressor.nearend_tuning.mask_hf.enr_suppress =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_NEAREND_TUNING,
+			      MASK_HF_ENR_SUPPRESS);
+	config->suppressor.nearend_tuning.mask_hf.emr_transparent =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_NEAREND_TUNING,
+			      MASK_HF_EMR_TRANSPARENT);
+	config->suppressor.nearend_tuning.max_inc_factor =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_NEAREND_TUNING, MAX_INC_FACTOR);
+	config->suppressor.nearend_tuning.max_dec_factor_lf =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_NEAREND_TUNING, MAX_DEC_FACTOR_LF);
+
+	config->suppressor.dominant_nearend_detection.enr_threshold =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_DOMINANT_NEAREND_DETECTION,
+			ENR_THRESHOLD);
+	config->suppressor.dominant_nearend_detection.snr_threshold =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_DOMINANT_NEAREND_DETECTION,
+			SNR_THRESHOLD);
+	config->suppressor.dominant_nearend_detection.hold_duration =
+		AEC_GET_INT(ini, SUPPRESSOR_DOMINANT_NEAREND_DETECTION,
+			HOLD_DURATION);
+	config->suppressor.dominant_nearend_detection.trigger_threshold =
+		AEC_GET_INT(ini, SUPPRESSOR_DOMINANT_NEAREND_DETECTION,
+			TRIGGER_THRESHOLD);
+
+	config->suppressor.high_bands_suppression.enr_threshold =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_HIGH_BANDS_SUPPRESSION,
+			ENR_THRESHOLD);
+	config->suppressor.high_bands_suppression.max_gain_during_echo =
+		AEC_GET_FLOAT(ini, SUPPRESSOR_HIGH_BANDS_SUPPRESSION,
+			MAX_GAIN_DURING_ECHO);
+
+	config->suppressor.floor_first_increase =
+		AEC_GET_FLOAT(ini, SUPPRESSOR, FLOOR_FIRST_INCREASE);
+	config->suppressor.enforce_transparent =
+		AEC_GET_INT(ini, SUPPRESSOR, ENFORCE_TRANSPARENT);
+	config->suppressor.enforce_empty_higher_bands =
+		AEC_GET_INT(ini, SUPPRESSOR, ENFORCE_EMPTY_HIGHER_BANDS);
+}
+
+void aec_config_dump(dictionary *ini)
+{
+	webrtc::EchoCanceller3Config config;
+
+	aec_config_get(ini, &config);
+
+	syslog(LOG_ERR, "---- aec config dump ----");
+	syslog(LOG_ERR, "Delay:");
+	syslog(LOG_ERR, "    default_delay %zu sampling_factor %zu num_filters %zu",
+			config.delay.default_delay,
+			config.delay.down_sampling_factor,
+			config.delay.num_filters);
+	syslog(LOG_ERR, "    api_call_jitter_blocks %zu, min_echo_path_delay_blocks %zu",
+			config.delay.api_call_jitter_blocks,
+			config.delay.min_echo_path_delay_blocks);
+	syslog(LOG_ERR, "    delay_headroom_blocks %zu, hysteresis_limit_1_blocks %zu",
+			config.delay.delay_headroom_blocks,
+			config.delay.hysteresis_limit_1_blocks);
+	syslog(LOG_ERR, "    hysteresis_limit_2_blocks %zu, skew_hysteresis_blocks %zu",
+			config.delay.hysteresis_limit_2_blocks,
+			config.delay.skew_hysteresis_blocks);
+	syslog(LOG_ERR, "    fixed_capture_delay_samples %zu",
+			config.delay.fixed_capture_delay_samples);
+
+	syslog(LOG_ERR, "Filter main configuration:");
+	syslog(LOG_ERR, "    length_blocks %zu, leakage_converged %f, leakage_diverged %f",
+			config.filter.main.length_blocks,
+			config.filter.main.leakage_converged,
+			config.filter.main.leakage_diverged);
+	syslog(LOG_ERR, "    error_floor %f, noise_gate %f",
+			config.filter.main.error_floor,
+			config.filter.main.noise_gate);
+	syslog(LOG_ERR, "Filter shadow configuration:");
+	syslog(LOG_ERR, "    length_blocks %zu, rate %f, noise_gate %f",
+			config.filter.shadow.length_blocks,
+			config.filter.shadow.rate,
+			config.filter.shadow.noise_gate);
+	syslog(LOG_ERR, "Filter main initial configuration:");
+	syslog(LOG_ERR, "    length_blocks %zu, leakage_converged %f",
+			config.filter.main_initial.length_blocks,
+			config.filter.main_initial.leakage_converged);
+	syslog(LOG_ERR, "    leakage_diverged %f, error_floor %f, noise_gate %f",
+			config.filter.main_initial.leakage_diverged,
+			config.filter.main_initial.error_floor,
+			config.filter.main_initial.noise_gate);
+	syslog(LOG_ERR, "Filter shadow initial configuration:");
+	syslog(LOG_ERR, "    length_blocks %zu, rate %f, noise_gate %f",
+			config.filter.shadow_initial.length_blocks,
+			config.filter.shadow_initial.rate,
+			config.filter.shadow_initial.noise_gate);
+	syslog(LOG_ERR, "Filter:    config_change_duration_blocks %d",
+			config.filter.config_change_duration_blocks);
+	syslog(LOG_ERR, "    initial_state_seconds %f",
+			config.filter.initial_state_seconds);
+	syslog(LOG_ERR, "    conservative_initial_phase %d",
+			config.filter.conservative_initial_phase);
+	syslog(LOG_ERR, "    enable_shadow_filter_output_usage %d",
+			config.filter.enable_shadow_filter_output_usage);
+	syslog(LOG_ERR, "Erle: min %f max_l %f max_h %f onset_detection %d",
+			config.erle.min, config.erle.max_l,
+			config.erle.max_h, config.erle.onset_detection);
+	syslog(LOG_ERR, "Ep strength: lf %f mf %f hf %f default_len %f",
+			config.ep_strength.lf,
+			config.ep_strength.mf,
+			config.ep_strength.hf,
+			config.ep_strength.default_len);
+	syslog(LOG_ERR, "    echo_can_saturate %d, bounded_erl %d,"
+			"    ep_strength.reverb_based_on_render %d",
+			config.ep_strength.echo_can_saturate,
+			config.ep_strength.bounded_erl,
+			config.ep_strength.reverb_based_on_render);
+	syslog(LOG_ERR, "Gain mask: m0 %f m1 %f m2 %f m3 %f m5 %f",
+			config.gain_mask.m0,
+			config.gain_mask.m1,
+			config.gain_mask.m2,
+			config.gain_mask.m3,
+			config.gain_mask.m5);
+	syslog(LOG_ERR, "    m6 %f m7 %f m8 %f m9 %f",
+			config.gain_mask.m6,
+			config.gain_mask.m7,
+			config.gain_mask.m8,
+			config.gain_mask.m9);
+	syslog(LOG_ERR, "    gain_curve offset %f, gain_curve_slope %f",
+			config.gain_mask.gain_curve_offset,
+			config.gain_mask.gain_curve_slope);
+	syslog(LOG_ERR, "    temporal_masking_lf %f, temporal_masking_hf %f",
+			config.gain_mask.temporal_masking_lf,
+			config.gain_mask.temporal_masking_hf);
+	syslog(LOG_ERR, "    temporal_masking_lf_bands %zu",
+			config.gain_mask.temporal_masking_lf_bands);
+	syslog(LOG_ERR, "Echo audibility:");
+	syslog(LOG_ERR, "    low_render_limit %f, normal_render_limit %f",
+			config.echo_audibility.low_render_limit,
+			config.echo_audibility.normal_render_limit);
+	syslog(LOG_ERR, "    floor_power %f, audibility_threshold_lf %f",
+			config.echo_audibility.floor_power,
+			config.echo_audibility.audibility_threshold_lf);
+	syslog(LOG_ERR, "    audibility_threshold_mf %f",
+			config.echo_audibility.audibility_threshold_mf);
+	syslog(LOG_ERR, "    audibility_threshold_hf %f",
+			config.echo_audibility.audibility_threshold_hf);
+	syslog(LOG_ERR, "    use_stationary_properties %d",
+			config.echo_audibility.use_stationary_properties);
+	syslog(LOG_ERR, "Render levels:");
+	syslog(LOG_ERR, "    active_render_limit %f",
+			config.render_levels.active_render_limit);
+	syslog(LOG_ERR, "    poor_excitation_render_limit %f",
+			config.render_levels.poor_excitation_render_limit);
+	syslog(LOG_ERR, "    poor_excitation_render_limit_ds8 %f",
+			config.render_levels.poor_excitation_render_limit_ds8);
+	syslog(LOG_ERR, "Echo removal control:");
+	syslog(LOG_ERR, "    gain rampup:");
+	syslog(LOG_ERR, "        initial_gain %f, first_non_zero_gain %f",
+			config.echo_removal_control.gain_rampup.initial_gain,
+			config.echo_removal_control.gain_rampup.first_non_zero_gain);
+	syslog(LOG_ERR, "        non_zero_gain_blocks %d, full_gain_blocks %d",
+			config.echo_removal_control.gain_rampup.non_zero_gain_blocks,
+			config.echo_removal_control.gain_rampup.full_gain_blocks);
+	syslog(LOG_ERR, "    has_clock_drift %d",
+			config.echo_removal_control.has_clock_drift);
+	syslog(LOG_ERR, "    linear_and_stable_echo_path %d",
+			config.echo_removal_control.linear_and_stable_echo_path);
+	syslog(LOG_ERR, "Echo model:");
+	syslog(LOG_ERR, "    noise_floor_hold %zu, min_noise_floor_power %f",
+			config.echo_model.noise_floor_hold,
+			config.echo_model.min_noise_floor_power);
+	syslog(LOG_ERR, "    stationary_gate_slope %f, noise_gate_power %f",
+			config.echo_model.stationary_gate_slope,
+			config.echo_model.noise_gate_power);
+	syslog(LOG_ERR, "    noise_gate_slope %f, render_pre_window_size %zu",
+			config.echo_model.noise_gate_slope,
+			config.echo_model.render_pre_window_size);
+	syslog(LOG_ERR, "    render_post_window_size %zu nonlinear_hold %f",
+			config.echo_model.render_post_window_size,
+			config.echo_model.nonlinear_hold);
+	syslog(LOG_ERR, "    render_pre_window_size_init %u, "
+			"render_post_window_size_init %u",
+			config.echo_model.render_pre_window_size_init,
+			config.echo_model.render_post_window_size_init);
+	syslog(LOG_ERR, "    nonlinear_release %f",
+			config.echo_model.nonlinear_release);
+	syslog(LOG_ERR, "Suppressor:");
+	syslog(LOG_ERR, "    nearend_average_blocks %u",
+			config.suppressor.nearend_average_blocks);
+	syslog(LOG_ERR, "    Normal tuning, mask_lf %f %f %f",
+			config.suppressor.normal_tuning.mask_lf.enr_transparent,
+			config.suppressor.normal_tuning.mask_lf.enr_suppress,
+			config.suppressor.normal_tuning.mask_lf.emr_transparent);
+	syslog(LOG_ERR, "                   mask_hf %f %f %f",
+			config.suppressor.normal_tuning.mask_hf.enr_transparent,
+			config.suppressor.normal_tuning.mask_hf.enr_suppress,
+			config.suppressor.normal_tuning.mask_hf.emr_transparent);
+	syslog(LOG_ERR, "                   max_inc_factor %f max_dec_factor_lf %f",
+			config.suppressor.normal_tuning.max_inc_factor,
+			config.suppressor.normal_tuning.max_dec_factor_lf);
+	syslog(LOG_ERR, "    Nearend tuning, mask_lf %f %f %f",
+			config.suppressor.nearend_tuning.mask_lf.enr_transparent,
+			config.suppressor.nearend_tuning.mask_lf.enr_suppress,
+			config.suppressor.nearend_tuning.mask_lf.emr_transparent);
+	syslog(LOG_ERR, "                   mask_hf %f %f %f",
+			config.suppressor.nearend_tuning.mask_hf.enr_transparent,
+			config.suppressor.nearend_tuning.mask_hf.enr_suppress,
+			config.suppressor.nearend_tuning.mask_hf.emr_transparent);
+	syslog(LOG_ERR, "                   max_inc_factor %f max_dec_factor_lf %f",
+			config.suppressor.nearend_tuning.max_inc_factor,
+			config.suppressor.nearend_tuning.max_dec_factor_lf);
+	syslog(LOG_ERR, "    Dominant nearend detection:");
+	syslog(LOG_ERR, "        enr_threshold %f",
+			config.suppressor.dominant_nearend_detection.enr_threshold);
+	syslog(LOG_ERR, "        snr_threshold %f",
+			config.suppressor.dominant_nearend_detection.snr_threshold);
+	syslog(LOG_ERR, "        hold_duration %d",
+			config.suppressor.dominant_nearend_detection.hold_duration);
+	syslog(LOG_ERR, "        trigger_threshold %d",
+			config.suppressor.dominant_nearend_detection.trigger_threshold);
+	syslog(LOG_ERR, "    High bands suppression:");
+	syslog(LOG_ERR, "        enr_threshold %f max_gain_during_echo %f",
+			config.suppressor.high_bands_suppression.enr_threshold,
+			config.suppressor.high_bands_suppression.max_gain_during_echo);
+	syslog(LOG_ERR, "    floor_first_increase %f, enforce_transparent %d",
+			config.suppressor.floor_first_increase,
+			config.suppressor.enforce_transparent);
+	syslog(LOG_ERR, "    enforce_empty_higher_bands %f",
+			config.suppressor.enforce_empty_higher_bands);
+}
diff --git a/cras-config/aec_config.h b/cras-config/aec_config.h
new file mode 100644
index 0000000..8255ce5
--- /dev/null
+++ b/cras-config/aec_config.h
@@ -0,0 +1,320 @@
+/* Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef AEC_CONFIG_H_
+#define AEC_CONFIG_H_
+
+#include <iniparser.h>
+
+#include "api/audio/echo_canceller3_config.h"
+
+#define AEC_DELAY_DEFAULT_DELAY "delay:default_delay"
+#define AEC_DELAY_DEFAULT_DELAY_VALUE 5
+#define AEC_DELAY_DOWN_SAMPLING_FACTOR "delay:down_sampling_factor"
+#define AEC_DELAY_DOWN_SAMPLING_FACTOR_VALUE 4
+#define AEC_DELAY_NUM_FILTERS "delay:num_filters"
+#define AEC_DELAY_NUM_FILTERS_VALUE 6
+#define AEC_DELAY_API_CALL_JITTER_BLOCKS "delay:api_call_jitter_blocks"
+#define AEC_DELAY_API_CALL_JITTER_BLOCKS_VALUE 26
+#define AEC_DELAY_MIN_ECHO_PATH_DELAY_BLOCKS "delay:min_echo_path_delay_blocks"
+#define AEC_DELAY_MIN_ECHO_PATH_DELAY_BLOCKS_VALUE 0
+#define AEC_DELAY_DELAY_HEADROOM_BLOCKS "delay:delay_headroom_blocks"
+#define AEC_DELAY_DELAY_HEADROOM_BLOCKS_VALUE 2
+#define AEC_DELAY_HYSTERESIS_LIMIT_1_BLOCKS "delay:hysteresis_limit_1_blocks"
+#define AEC_DELAY_HYSTERESIS_LIMIT_1_BLOCKS_VALUE 1
+#define AEC_DELAY_HYSTERESIS_LIMIT_2_BLOCKS "delay:hysteresis_limit_2_blocks"
+#define AEC_DELAY_HYSTERESIS_LIMIT_2_BLOCKS_VALUE 1
+#define AEC_DELAY_SKEW_HYSTERESIS_BLOCKS "delay:skew_hysteresis_blocks"
+#define AEC_DELAY_SKEW_HYSTERESIS_BLOCKS_VALUE 3
+#define AEC_DELAY_FIXED_CAPTURE_DELAY_SAMPLES \
+	"delay:fixed_capture_delay_samples"
+#define AEC_DELAY_FIXED_CAPTURE_DELAY_SAMPLES_VALUE 0
+
+// Filter Main configuration
+#define AEC_FILTER_MAIN_LENGTH_BLOCKS "filter.main:length_blocks"
+#define AEC_FILTER_MAIN_LENGTH_BLOCKS_VALUE 13
+#define AEC_FILTER_MAIN_LEAKAGE_CONVERGED "filter.main:leakage_converged"
+#define AEC_FILTER_MAIN_LEAKAGE_CONVERGED_VALUE 0.00005f
+#define AEC_FILTER_MAIN_LEAKAGE_DIVERGED "filter.main:leakage_diverged"
+#define AEC_FILTER_MAIN_LEAKAGE_DIVERGED_VALUE 0.01f
+#define AEC_FILTER_MAIN_ERROR_FLOOR "filter.main:error_floor"
+#define AEC_FILTER_MAIN_ERROR_FLOOR_VALUE 0.1f
+#define AEC_FILTER_MAIN_NOISE_GATE "filter.main:noise_gate"
+#define AEC_FILTER_MAIN_NOISE_GATE_VALUE 20075344.f
+
+// Filter Shadow configuration
+#define AEC_FILTER_SHADOW_LENGTH_BLOCKS "filter.shadow:length_blocks"
+#define AEC_FILTER_SHADOW_LENGTH_BLOCKS_VALUE 13
+#define AEC_FILTER_SHADOW_RATE "filter.shadow:rate"
+#define AEC_FILTER_SHADOW_RATE_VALUE 0.7f
+#define AEC_FILTER_SHADOW_NOISE_GATE "filter.shadow:noise_gate"
+#define AEC_FILTER_SHADOW_NOISE_GATE_VALUE 20075344.f
+
+// Filter Main initial configuration
+#define AEC_FILTER_MAIN_INIT_LENGTH_BLOCKS "filter.main_initial:length_blocks"
+#define AEC_FILTER_MAIN_INIT_LENGTH_BLOCKS_VALUE 12
+#define AEC_FILTER_MAIN_INIT_LEAKAGE_CONVERGED \
+	"filter.main_initial:leakage_converged"
+#define AEC_FILTER_MAIN_INIT_LEAKAGE_CONVERGED_VALUE 0.005f
+#define AEC_FILTER_MAIN_INIT_LEAKAGE_DIVERGED \
+	"filter.main_initial:leakage_diverged"
+#define AEC_FILTER_MAIN_INIT_LEAKAGE_DIVERGED_VALUE 0.5f
+#define AEC_FILTER_MAIN_INIT_ERROR_FLOOR "filter.main_initial:error_floor"
+#define AEC_FILTER_MAIN_INIT_ERROR_FLOOR_VALUE 0.001f
+#define AEC_FILTER_MAIN_INIT_NOISE_GATE "filter.main_initial:noise_gate"
+#define AEC_FILTER_MAIN_INIT_NOISE_GATE_VALUE 20075344.f
+
+// Filter Shadow initial configuration
+#define AEC_FILTER_SHADOW_INIT_LENGTH_BLOCKS \
+	"filter.shadow_initial:length_blocks"
+#define AEC_FILTER_SHADOW_INIT_LENGTH_BLOCKS_VALUE 12
+#define AEC_FILTER_SHADOW_INIT_RATE "filter.shadow_initial:rate"
+#define AEC_FILTER_SHADOW_INIT_RATE_VALUE 0.9f
+#define AEC_FILTER_SHADOW_INIT_NOISE_GATE "filter.shadow_initial:noise_gate"
+#define AEC_FILTER_SHADOW_INIT_NOISE_GATE_VALUE 20075344.f
+
+#define AEC_FILTER_CONFIG_CHANGE_DURATION_BLOCKS \
+	"filter:config_change_duration_blocks"
+#define AEC_FILTER_CONFIG_CHANGE_DURATION_BLOCKS_VALUE 250
+#define AEC_FILTER_INITIAL_STATE_SECONDS "filter:initial_state_seconds"
+#define AEC_FILTER_INITIAL_STATE_SECONDS_VALUE 2.5f
+#define AEC_FILTER_CONSERVATIVE_INITIAL_PHASE \
+	"filter:conservative_initial_phase"
+#define AEC_FILTER_CONSERVATIVE_INITIAL_PHASE_VALUE 0
+#define AEC_FILTER_ENABLE_SHADOW_FILTER_OUTPUT_USAGE \
+	"filter:enable_shadow_filter_output_usage"
+#define AEC_FILTER_ENABLE_SHADOW_FILTER_OUTPUT_USAGE_VALUE 1
+
+// Erle
+#define AEC_ERLE_MIN "erle:min"
+#define AEC_ERLE_MIN_VALUE 1.f
+#define AEC_ERLE_MAX_L "erle:max_l"
+#define AEC_ERLE_MAX_L_VALUE 4.f
+#define AEC_ERLE_MAX_H "erle:max_h"
+#define AEC_ERLE_MAX_H_VALUE 1.5f
+#define AEC_ERLE_ONSET_DETECTION "erle:onset_detection"
+#define AEC_ERLE_ONSET_DETECTION_VALUE 1
+
+// EpStrength
+#define AEC_EP_STRENGTH_LF "ep_strength:lf"
+#define AEC_EP_STRENGTH_LF_VALUE 1.f
+#define AEC_EP_STRENGTH_MF "ep_strength:mf"
+#define AEC_EP_STRENGTH_MF_VALUE 1.f
+#define AEC_EP_STRENGTH_HF "ep_strength:hf"
+#define AEC_EP_STRENGTH_HF_VALUE 1.f
+#define AEC_EP_STRENGTH_DEFAULT_LEN "ep_strength:default_len"
+#define AEC_EP_STRENGTH_DEFAULT_LEN_VALUE 0.88f
+#define AEC_EP_STRENGTH_REVERB_BASED_ON_RENDER \
+	"ep_strength:reverb_based_on_render"
+#define AEC_EP_STRENGTH_REVERB_BASED_ON_RENDER_VALUE 1
+#define AEC_EP_STRENGTH_ECHO_CAN_SATURATE "ep_strength:echo_can_saturate"
+#define AEC_EP_STRENGTH_ECHO_CAN_SATURATE_VALUE 1
+#define AEC_EP_STRENGTH_BOUNDED_ERL "ep_strength:bounded_erl"
+#define AEC_EP_STRENGTH_BOUNDED_ERL_VALUE 0
+
+// Gain mask
+#define AEC_GAIN_MASK_M0 "gain_mask:m0"
+#define AEC_GAIN_MASK_M0_VALUE 0.1f
+#define AEC_GAIN_MASK_M1 "gain_mask:m1"
+#define AEC_GAIN_MASK_M1_VALUE 0.01f
+#define AEC_GAIN_MASK_M2 "gain_mask:m2"
+#define AEC_GAIN_MASK_M2_VALUE 0.0001f
+#define AEC_GAIN_MASK_M3 "gain_mask:m3"
+#define AEC_GAIN_MASK_M3_VALUE 0.01f
+// m4 was removed intentionally.
+// https://webrtc-review.googlesource.com/c/src/+/70421
+#define AEC_GAIN_MASK_M5 "gain_mask:m5"
+#define AEC_GAIN_MASK_M5_VALUE 0.01f
+#define AEC_GAIN_MASK_M6 "gain_mask:m6"
+#define AEC_GAIN_MASK_M6_VALUE 0.0001f
+#define AEC_GAIN_MASK_M7 "gain_mask:m7"
+#define AEC_GAIN_MASK_M7_VALUE 0.01f
+#define AEC_GAIN_MASK_M8 "gain_mask:m8"
+#define AEC_GAIN_MASK_M8_VALUE 0.0001f
+#define AEC_GAIN_MASK_M9 "gain_mask:m9"
+#define AEC_GAIN_MASK_M9_VALUE 0.1f
+#define AEC_GAIN_MASK_GAIN_CURVE_OFFSET "gain_mask:gain_curve_offset"
+#define AEC_GAIN_MASK_GAIN_CURVE_OFFSET_VALUE 1.45f
+#define AEC_GAIN_MASK_GAIN_CURVE_SLOPE "gain_mask:gain_curve_slope"
+#define AEC_GAIN_MASK_GAIN_CURVE_SLOPE_VALUE 5.f
+#define AEC_GAIN_MASK_TEMPORAL_MASKING_LF "gain_mask:temporal_masking_lf"
+#define AEC_GAIN_MASK_TEMPORAL_MASKING_LF_VALUE 0.9f
+#define AEC_GAIN_MASK_TEMPORAL_MASKING_HF "gain_mask:temporal_masking_hf"
+#define AEC_GAIN_MASK_TEMPORAL_MASKING_HF_VALUE 0.6f
+#define AEC_GAIN_MASK_TEMPORAL_MASKING_LF_BANDS \
+	"gain_mask:temporal_masking_lf_bands"
+#define AEC_GAIN_MASK_TEMPORAL_MASKING_LF_BANDS_VALUE 3
+
+#define AEC_ECHO_AUDIBILITY_LOW_RENDER_LIMIT "echo_audibility:low_render_limit"
+#define AEC_ECHO_AUDIBILITY_LOW_RENDER_LIMIT_VALUE 4 * 64.f
+#define AEC_ECHO_AUDIBILITY_NORMAL_RENDER_LIMIT \
+	"echo_audibility:normal_render_limit"
+#define AEC_ECHO_AUDIBILITY_NORMAL_RENDER_LIMIT_VALUE 64.f
+#define AEC_ECHO_AUDIBILITY_FLOOR_POWER "echo_audibility:floor_power"
+#define AEC_ECHO_AUDIBILITY_FLOOR_POWER_VALUE 2 * 64.f
+#define AEC_ECHO_AUDIBILITY_AUDIBILITY_THRESHOLD_LF \
+	"echo_audibility:audibility_threshold_lf"
+#define AEC_ECHO_AUDIBILITY_AUDIBILITY_THRESHOLD_LF_VALUE 10
+#define AEC_ECHO_AUDIBILITY_AUDIBILITY_THRESHOLD_MF \
+	"echo_audibility:audibility_threshold_mf"
+#define AEC_ECHO_AUDIBILITY_AUDIBILITY_THRESHOLD_MF_VALUE 10
+#define AEC_ECHO_AUDIBILITY_AUDIBILITY_THRESHOLD_HF \
+	"echo_audibility:audibility_threshold_hf"
+#define AEC_ECHO_AUDIBILITY_AUDIBILITY_THRESHOLD_HF_VALUE 10
+#define AEC_ECHO_AUDIBILITY_USE_STATIONARY_PROPERTIES \
+	"echo_audibility:use_stationary_properties"
+#define AEC_ECHO_AUDIBILITY_USE_STATIONARY_PROPERTIES_VALUE 1
+
+// Rendering levels
+#define AEC_RENDER_LEVELS_ACTIVE_RENDER_LIMIT \
+	"render_levels:active_render_limit"
+#define AEC_RENDER_LEVELS_ACTIVE_RENDER_LIMIT_VALUE 100.f
+#define AEC_RENDER_LEVELS_POOR_EXCITATION_RENDER_LIMIT \
+	"render_levels:poor_excitation_render_limit"
+#define AEC_RENDER_LEVELS_POOR_EXCITATION_RENDER_LIMIT_VALUE 150.f
+#define AEC_RENDER_LEVELS_POOR_EXCITATION_RENDER_LIMIT_DS8 \
+	"render_levels:poor_excitation_render_limit_ds8"
+#define AEC_RENDER_LEVELS_POOR_EXCITATION_RENDER_LIMIT_DS8_VALUE 20.f
+
+// Echo removal controls
+#define AEC_ECHO_REMOVAL_CTL_INITIAL_GAIN "echo_removal_control:initial_gain"
+#define AEC_ECHO_REMOVAL_CTL_INITIAL_GAIN_VALUE 0.0f
+#define AEC_ECHO_REMOVAL_CTL_FIRST_NON_ZERO_GAIN \
+	"echo_removal_control:first_non_zero_gain"
+#define AEC_ECHO_REMOVAL_CTL_FIRST_NON_ZERO_GAIN_VALUE 0.001f
+#define AEC_ECHO_REMOVAL_CTL_NON_ZERO_GAIN_BLOCKS \
+	"echo_removal_control:non_zero_gain_blocks"
+#define AEC_ECHO_REMOVAL_CTL_NON_ZERO_GAIN_BLOCKS_VALUE 187
+#define AEC_ECHO_REMOVAL_CTL_FULL_GAIN_BLOCKS \
+	"echo_removal_control:full_gain_blocks"
+#define AEC_ECHO_REMOVAL_CTL_FULL_GAIN_BLOCKS_VALUE 312
+#define AEC_ECHO_REMOVAL_CTL_HAS_CLOCK_DRIFT \
+	"echo_removal_control:has_clock_drift"
+#define AEC_ECHO_REMOVAL_CTL_HAS_CLOCK_DRIFT_VALUE 0
+#define AEC_ECHO_REMOVAL_CTL_LINEAR_AND_STABLE_ECHO_PATH \
+	"echo_removal_control:linear_and_stable_echo_path"
+#define AEC_ECHO_REMOVAL_CTL_LINEAR_AND_STABLE_ECHO_PATH_VALUE 0
+
+// EchoModel
+#define AEC_ECHO_MODEL_NOISE_FLOOR_HOLD "echo_model:noise_floor_hold"
+#define AEC_ECHO_MODEL_NOISE_FLOOR_HOLD_VALUE 50
+#define AEC_ECHO_MODEL_MIN_NOISE_FLOOR_POWER "echo_model:min_noise_floor_power"
+#define AEC_ECHO_MODEL_MIN_NOISE_FLOOR_POWER_VALUE 1638400.f
+#define AEC_ECHO_MODEL_STATIONARY_GATE_SLOPE "echo_model:stationary_gate_slope"
+#define AEC_ECHO_MODEL_STATIONARY_GATE_SLOPE_VALUE 10.f
+#define AEC_ECHO_MODEL_NOISE_GATE_POWER "echo_model:noise_gate_power"
+#define AEC_ECHO_MODEL_NOISE_GATE_POWER_VALUE 27509.42f
+#define AEC_ECHO_MODEL_NOISE_GATE_SLOPE "echo_model:noise_gate_slope"
+#define AEC_ECHO_MODEL_NOISE_GATE_SLOPE_VALUE 0.3f
+#define AEC_ECHO_MODEL_RENDER_PRE_WINDOW_SIZE \
+	"echo_model:render_pre_window_size"
+#define AEC_ECHO_MODEL_RENDER_PRE_WINDOW_SIZE_VALUE 1
+#define AEC_ECHO_MODEL_RENDER_POST_WINDOW_SIZE \
+	"echo_model:render_post_window_size"
+#define AEC_ECHO_MODEL_RENDER_POST_WINDOW_SIZE_VALUE 1
+#define AEC_ECHO_MODEL_RENDER_PRE_WINDOW_SIZE_INIT \
+	"echo_model:render_pre_window_size_init"
+#define AEC_ECHO_MODEL_RENDER_PRE_WINDOW_SIZE_INIT_VALUE 10
+#define AEC_ECHO_MODEL_RENDER_POST_WINDOW_SIZE_INIT \
+	"echo_model:render_post_window_size_init"
+#define AEC_ECHO_MODEL_RENDER_POST_WINDOW_SIZE_INIT_VALUE 10
+#define AEC_ECHO_MODEL_NONLINEAR_HOLD "echo_model:nonlinear_hold"
+#define AEC_ECHO_MODEL_NONLINEAR_HOLD_VALUE 1
+#define AEC_ECHO_MODEL_NONLINEAR_RELEASE "echo_model:nonlinear_release"
+#define AEC_ECHO_MODEL_NONLINEAR_RELEASE_VALUE 0.001f
+
+#define AEC_SUPPRESSOR_NEAREND_AVERAGE_BLOCKS \
+	"suppressor:nearend_average_blocks"
+#define AEC_SUPPRESSOR_NEAREND_AVERAGE_BLOCKS_VALUE 4
+
+#define AEC_SUPPRESSOR_NORMAL_TUNING_MASK_LF_ENR_TRANSPARENT \
+	"suppressor.normal_tuning:mask_lf_enr_transparent"
+#define AEC_SUPPRESSOR_NORMAL_TUNING_MASK_LF_ENR_TRANSPARENT_VALUE .2f
+#define AEC_SUPPRESSOR_NORMAL_TUNING_MASK_LF_ENR_SUPPRESS \
+	"suppressor.normal_tuning:mask_lf_enr_suppress"
+#define AEC_SUPPRESSOR_NORMAL_TUNING_MASK_LF_ENR_SUPPRESS_VALUE .3f
+#define AEC_SUPPRESSOR_NORMAL_TUNING_MASK_LF_EMR_TRANSPARENT \
+	"suppressor.normal_tuning:mask_lf_emr_transparent"
+#define AEC_SUPPRESSOR_NORMAL_TUNING_MASK_LF_EMR_TRANSPARENT_VALUE .3f
+
+#define AEC_SUPPRESSOR_NORMAL_TUNING_MASK_HF_ENR_TRANSPARENT \
+	"suppressor.normal_tuning:mask_hf_enr_transparent"
+#define AEC_SUPPRESSOR_NORMAL_TUNING_MASK_HF_ENR_TRANSPARENT_VALUE .07f
+#define AEC_SUPPRESSOR_NORMAL_TUNING_MASK_HF_ENR_SUPPRESS \
+	"suppressor.normal_tuning:mask_hf_enr_suppress"
+#define AEC_SUPPRESSOR_NORMAL_TUNING_MASK_HF_ENR_SUPPRESS_VALUE .1f
+#define AEC_SUPPRESSOR_NORMAL_TUNING_MASK_HF_EMR_TRANSPARENT \
+	"suppressor.normal_tuning:mask_hf_emr_transparent"
+#define AEC_SUPPRESSOR_NORMAL_TUNING_MASK_HF_EMR_TRANSPARENT_VALUE .3f
+
+#define AEC_SUPPRESSOR_NORMAL_TUNING_MAX_INC_FACTOR \
+	"suppressor.normal_tuning:max_inc_factor"
+#define AEC_SUPPRESSOR_NORMAL_TUNING_MAX_INC_FACTOR_VALUE 2.0f
+#define AEC_SUPPRESSOR_NORMAL_TUNING_MAX_DEC_FACTOR_LF \
+	"suppressor.normal_tuning:max_dec_factor_lf"
+#define AEC_SUPPRESSOR_NORMAL_TUNING_MAX_DEC_FACTOR_LF_VALUE 0.25f
+
+#define AEC_SUPPRESSOR_NEAREND_TUNING_MASK_LF_ENR_TRANSPARENT \
+	"suppressor.nearend_tuning:mask_lf_enr_transparent"
+#define AEC_SUPPRESSOR_NEAREND_TUNING_MASK_LF_ENR_TRANSPARENT_VALUE .2f
+#define AEC_SUPPRESSOR_NEAREND_TUNING_MASK_LF_ENR_SUPPRESS \
+	"suppressor.nearend_tuning:mask_lf_enr_suppress"
+#define AEC_SUPPRESSOR_NEAREND_TUNING_MASK_LF_ENR_SUPPRESS_VALUE .3f
+#define AEC_SUPPRESSOR_NEAREND_TUNING_MASK_LF_EMR_TRANSPARENT \
+	"suppressor.nearend_tuning:mask_lf_emr_transparent"
+#define AEC_SUPPRESSOR_NEAREND_TUNING_MASK_LF_EMR_TRANSPARENT_VALUE .3f
+
+#define AEC_SUPPRESSOR_NEAREND_TUNING_MASK_HF_ENR_TRANSPARENT \
+	"suppressor.nearend_tuning:mask_hf_enr_transparent"
+#define AEC_SUPPRESSOR_NEAREND_TUNING_MASK_HF_ENR_TRANSPARENT_VALUE .07f
+#define AEC_SUPPRESSOR_NEAREND_TUNING_MASK_HF_ENR_SUPPRESS \
+	"suppressor.nearend_tuning:mask_hf_enr_suppress"
+#define AEC_SUPPRESSOR_NEAREND_TUNING_MASK_HF_ENR_SUPPRESS_VALUE .1f
+#define AEC_SUPPRESSOR_NEAREND_TUNING_MASK_HF_EMR_TRANSPARENT \
+	"suppressor.nearend_tuning:mask_hf_emr_transparent"
+#define AEC_SUPPRESSOR_NEAREND_TUNING_MASK_HF_EMR_TRANSPARENT_VALUE .3f
+
+#define AEC_SUPPRESSOR_NEAREND_TUNING_MAX_INC_FACTOR \
+	"suppressor.nearend_tuning:max_inc_factor"
+#define AEC_SUPPRESSOR_NEAREND_TUNING_MAX_INC_FACTOR_VALUE 2.0f
+#define AEC_SUPPRESSOR_NEAREND_TUNING_MAX_DEC_FACTOR_LF \
+	"suppressor.nearend_tuning:max_dec_factor_lf"
+#define AEC_SUPPRESSOR_NEAREND_TUNING_MAX_DEC_FACTOR_LF_VALUE 0.25f
+
+#define AEC_SUPPRESSOR_DOMINANT_NEAREND_DETECTION_ENR_THRESHOLD \
+	"suppressor.dominant_nearend_detection:enr_threshold"
+#define AEC_SUPPRESSOR_DOMINANT_NEAREND_DETECTION_ENR_THRESHOLD_VALUE 10.f
+#define AEC_SUPPRESSOR_DOMINANT_NEAREND_DETECTION_SNR_THRESHOLD \
+	"suppressor.dominant_nearend_detection:snr_threshold"
+#define AEC_SUPPRESSOR_DOMINANT_NEAREND_DETECTION_SNR_THRESHOLD_VALUE 10.f
+#define AEC_SUPPRESSOR_DOMINANT_NEAREND_DETECTION_HOLD_DURATION \
+	"suppressor.dominant_nearend_detection:hold_duration"
+#define AEC_SUPPRESSOR_DOMINANT_NEAREND_DETECTION_HOLD_DURATION_VALUE 25
+#define AEC_SUPPRESSOR_DOMINANT_NEAREND_DETECTION_TRIGGER_THRESHOLD \
+	"suppressor.dominant_nearend_detection:trigger_threshold"
+#define AEC_SUPPRESSOR_DOMINANT_NEAREND_DETECTION_TRIGGER_THRESHOLD_VALUE 15
+
+#define AEC_SUPPRESSOR_HIGH_BANDS_SUPPRESSION_ENR_THRESHOLD \
+	"suppressor.high_bands_suppression:enr_threshold"
+#define AEC_SUPPRESSOR_HIGH_BANDS_SUPPRESSION_ENR_THRESHOLD_VALUE 1.f
+#define AEC_SUPPRESSOR_HIGH_BANDS_SUPPRESSION_MAX_GAIN_DURING_ECHO \
+	"suppressor.high_bands_suppression:max_gain_during_echo"
+#define AEC_SUPPRESSOR_HIGH_BANDS_SUPPRESSION_MAX_GAIN_DURING_ECHO_VALUE 1.f
+
+#define AEC_SUPPRESSOR_FLOOR_FIRST_INCREASE "suppressor:floor_first_increase"
+#define AEC_SUPPRESSOR_FLOOR_FIRST_INCREASE_VALUE 0.00001f
+#define AEC_SUPPRESSOR_ENFORCE_TRANSPARENT "suppressor:enforce_transparent"
+#define AEC_SUPPRESSOR_ENFORCE_TRANSPARENT_VALUE 0
+#define AEC_SUPPRESSOR_ENFORCE_EMPTY_HIGHER_BANDS \
+	"suppressor:enforce_empty_higher_bands"
+#define AEC_SUPPRESSOR_ENFORCE_EMPTY_HIGHER_BANDS_VALUE 0
+
+/* Gets the aec config from given config directory. */
+void aec_config_get(dictionary *ini, webrtc::EchoCanceller3Config *config);
+
+/* Prints the config content to syslog. */
+void aec_config_dump(dictionary *config);
+
+#endif /* AEC_CONFIG_H_ */
diff --git a/cras-config/apm_config.cc b/cras-config/apm_config.cc
new file mode 100644
index 0000000..bcf1c96
--- /dev/null
+++ b/cras-config/apm_config.cc
@@ -0,0 +1,88 @@
+/* Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <syslog.h>
+
+#include "apm_config.h"
+
+#define APM_CONFIG_NAME "apm.ini"
+
+#define APM_GET_INT(ini, key)	\
+	iniparser_getint(	\
+		ini, key,	\
+		key ## _VALUE)
+#define APM_GET_FLOAT(ini, key)	\
+	iniparser_getdouble(	\
+		ini, key,	\
+		key ## _VALUE)
+
+void apm_config_apply(dictionary *ini, webrtc::AudioProcessing *apm)
+{
+	webrtc::AudioProcessing::Config config;
+	webrtc::GainControl::Mode agc_mode;
+	webrtc::NoiseSuppression::Level ns_level;
+
+	if (ini == NULL)
+		return;
+
+	config.residual_echo_detector.enabled =
+			APM_GET_INT(ini, APM_RESIDUAL_ECHO_DETECTOR_ENABLED);
+	config.high_pass_filter.enabled =
+			APM_GET_INT(ini, APM_HIGH_PASS_FILTER_ENABLED);
+	config.pre_amplifier.enabled =
+			APM_GET_INT(ini, APM_PRE_AMPLIFIER_ENABLED);
+	config.pre_amplifier.fixed_gain_factor =
+			APM_GET_FLOAT(ini, APM_PRE_AMPLIFIER_FIXED_GAIN_FACTOR);
+	config.gain_controller2.enabled =
+			APM_GET_INT(ini, APM_GAIN_CONTROLLER2_ENABLED);
+	config.gain_controller2.fixed_gain_db =
+			APM_GET_FLOAT(ini, APM_GAIN_CONTROLLER2_FIXED_GAIN_DB);
+	config.gain_controller2.adaptive_digital_mode =
+			APM_GET_INT(ini, APM_GAIN_CONTROLLER2_ADAPTIVE_DIGITAL_MODE);
+	apm->ApplyConfig(config);
+
+	apm->gain_control()->set_compression_gain_db(
+			APM_GET_INT(ini, APM_GAIN_CONTROL_COMPRESSION_GAIN_DB));
+
+	agc_mode = static_cast<webrtc::GainControl::Mode>(
+			APM_GET_INT(ini, APM_GAIN_CONTROL_MODE));
+	apm->gain_control()->set_mode(agc_mode);
+	apm->gain_control()->Enable(APM_GET_INT(ini, APM_GAIN_CONTROL_ENABLED));
+
+	ns_level = static_cast<webrtc::NoiseSuppression::Level>(
+			APM_GET_INT(ini, APM_NOISE_SUPPRESSION_LEVEL));
+	apm->noise_suppression()->set_level(ns_level);
+	apm->noise_suppression()->Enable(
+			APM_GET_INT(ini, APM_NOISE_SUPPRESSION_ENABLED));
+}
+
+void apm_config_dump(dictionary *ini)
+{
+	syslog(LOG_ERR, "---- apm config dump ----");
+	syslog(LOG_ERR, "residual_echo_detector_enabled %u",
+		APM_GET_INT(ini, APM_RESIDUAL_ECHO_DETECTOR_ENABLED));
+	syslog(LOG_ERR, "high_pass_filter_enabled %u",
+		APM_GET_INT(ini, APM_HIGH_PASS_FILTER_ENABLED));
+	syslog(LOG_ERR, "pre_amplifier_enabled %u",
+		APM_GET_INT(ini, APM_PRE_AMPLIFIER_ENABLED));
+	syslog(LOG_ERR, "pre_amplifier_fixed_gain_factor %f",
+		APM_GET_FLOAT(ini, APM_PRE_AMPLIFIER_FIXED_GAIN_FACTOR));
+	syslog(LOG_ERR, "gain_controller2_enabled %u",
+		APM_GET_INT(ini, APM_GAIN_CONTROLLER2_ENABLED));
+	syslog(LOG_ERR, "gain_controller2_fixed_gain_db %f",
+		APM_GET_FLOAT(ini, APM_GAIN_CONTROLLER2_FIXED_GAIN_DB));
+	syslog(LOG_ERR, "gain_controller2_adaptive_digital_mode %d",
+		APM_GET_INT(ini, APM_GAIN_CONTROLLER2_ADAPTIVE_DIGITAL_MODE));
+	syslog(LOG_ERR, "gain_control_compression_gain_db %u",
+		APM_GET_INT(ini, APM_GAIN_CONTROL_COMPRESSION_GAIN_DB));
+	syslog(LOG_ERR, "gain_control_mode %u",
+		APM_GET_INT(ini, APM_GAIN_CONTROL_MODE));
+	syslog(LOG_ERR, "gain_control_enabled %u",
+		APM_GET_INT(ini, APM_GAIN_CONTROL_ENABLED));
+	syslog(LOG_ERR, "noise_suppression_level %u",
+		APM_GET_INT(ini, APM_NOISE_SUPPRESSION_LEVEL));
+	syslog(LOG_ERR, "noise_suppression_enabled %u",
+		APM_GET_INT(ini, APM_NOISE_SUPPRESSION_ENABLED));
+}
diff --git a/cras-config/apm_config.h b/cras-config/apm_config.h
new file mode 100644
index 0000000..30d2b04
--- /dev/null
+++ b/cras-config/apm_config.h
@@ -0,0 +1,46 @@
+/* Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef APM_CONFIG_H_
+#define APM_CONFIG_H_
+
+#include <iniparser.h>
+
+#include "modules/audio_processing/include/audio_processing.h"
+
+#define APM_RESIDUAL_ECHO_DETECTOR_ENABLED "apm:residual_echo_detector_enabled"
+#define APM_RESIDUAL_ECHO_DETECTOR_ENABLED_VALUE 1
+#define APM_HIGH_PASS_FILTER_ENABLED "apm:high_pass_filter_enabled"
+#define APM_HIGH_PASS_FILTER_ENABLED_VALUE 0
+#define APM_PRE_AMPLIFIER_ENABLED "apm:pre_amplifier_enabled"
+#define APM_PRE_AMPLIFIER_ENABLED_VALUE 0
+#define APM_PRE_AMPLIFIER_FIXED_GAIN_FACTOR "apm:pre_amplifier_fixed_gain_factor"
+#define APM_PRE_AMPLIFIER_FIXED_GAIN_FACTOR_VALUE 1.f
+#define APM_GAIN_CONTROLLER2_ENABLED "apm:gain_controller2_enabled"
+#define APM_GAIN_CONTROLLER2_ENABLED_VALUE 0
+#define APM_GAIN_CONTROLLER2_FIXED_GAIN_DB "apm:gain_controller2_fixed_gain_db"
+#define APM_GAIN_CONTROLLER2_FIXED_GAIN_DB_VALUE 0.f
+#define APM_GAIN_CONTROLLER2_ADAPTIVE_DIGITAL_MODE "apm:gain_controller2_adaptive_digital_mode"
+#define APM_GAIN_CONTROLLER2_ADAPTIVE_DIGITAL_MODE_VALUE 1
+#define APM_GAIN_CONTROL_COMPRESSION_GAIN_DB "apm:gain_control_compression_gain_db"
+#define APM_GAIN_CONTROL_COMPRESSION_GAIN_DB_VALUE 9
+/* 0: adaptive analog, 1: adaptive digital, 2: fixed digital */
+#define APM_GAIN_CONTROL_MODE "apm:gain_control_mode"
+#define APM_GAIN_CONTROL_MODE_VALUE 0
+#define APM_GAIN_CONTROL_ENABLED "apm:gain_control_enabled"
+#define APM_GAIN_CONTROL_ENABLED_VALUE 0
+/* 0: low, 1: moderate, 2: high, 3: very high*/
+#define APM_NOISE_SUPPRESSION_LEVEL "apm:noise_suppression_level"
+#define APM_NOISE_SUPPRESSION_LEVEL_VALUE 0
+#define APM_NOISE_SUPPRESSION_ENABLED "apm:noise_suppression_enabled"
+#define APM_NOISE_SUPPRESSION_ENABLED_VALUE 0
+
+/* Gets apm config from given config directory. */
+void apm_config_apply(dictionary *ini, webrtc::AudioProcessing *apm);
+
+/* Prints config content to syslog. */
+void apm_config_dump(dictionary *ini);
+
+#endif /* APM_CONFIG_H_ */
diff --git a/cras-config/module.mk b/cras-config/module.mk
new file mode 100644
index 0000000..face43e
--- /dev/null
+++ b/cras-config/module.mk
@@ -0,0 +1,18 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+include common.mk
+
+cras-config_CC_OBJECTS = \
+	cras-config/aec_config.o \
+	cras-config/apm_config.o
+
+CXX_STATIC_LIBRARY(cras-config.pic.a): \
+	$(cras-config_CC_OBJECTS)
+
+cras-config: CXX_STATIC_LIBRARY(cras-config.pic.a)
+
+clean: CLEAN(cras-config.pic.a)
+
+.PHONY: cras-config
diff --git a/webrtc_apm.cc b/webrtc_apm.cc
index dbc35aa..ce8f8ee 100644
--- a/webrtc_apm.cc
+++ b/webrtc_apm.cc
@@ -4,6 +4,8 @@
  */
 
 #include "api/audio/echo_canceller3_factory.h"
+#include "cras-config/aec_config.h"
+#include "cras-config/apm_config.h"
 #include "modules/audio_processing/aec_dump/aec_dump_factory.h"
 #include "modules/audio_processing/include/aec_dump.h"
 #include "modules/audio_processing/include/audio_processing.h"
@@ -15,232 +17,10 @@
 
 #include "webrtc_apm.h"
 
-int convert_to_aec3_config(
-		const struct aec_config *config,
-		webrtc::EchoCanceller3Config *aec3_config)
-{
-	aec3_config->delay.default_delay =
-		config->delay.default_delay;
-	aec3_config->delay.down_sampling_factor =
-		config->delay.down_sampling_factor;
-	aec3_config->delay.num_filters =
-		config->delay.num_filters;
-	aec3_config->delay.api_call_jitter_blocks =
-		config->delay.api_call_jitter_blocks;
-	aec3_config->delay.min_echo_path_delay_blocks =
-		config->delay.min_echo_path_delay_blocks,
-	aec3_config->delay.delay_headroom_blocks =
-		config->delay.delay_headroom_blocks;
-	aec3_config->delay.hysteresis_limit_1_blocks =
-		config->delay.hysteresis_limit_1_blocks;
-	aec3_config->delay.hysteresis_limit_2_blocks =
-		config->delay.hysteresis_limit_2_blocks,
-	aec3_config->delay.skew_hysteresis_blocks =
-		config->delay.skew_hysteresis_blocks;
-	aec3_config->delay.fixed_capture_delay_samples =
-		config->delay.fixed_capture_delay_samples;
-
-	aec3_config->filter.main = {
-		config->filter.main.length_blocks,
-		config->filter.main.leakage_converged,
-		config->filter.main.leakage_diverged,
-		config->filter.main.error_floor,
-		config->filter.main.noise_gate
-	};
-	aec3_config->filter.shadow = {
-		config->filter.shadow.length_blocks,
-		config->filter.shadow.rate,
-		config->filter.shadow.noise_gate
-	};
-	aec3_config->filter.main_initial = {
-		config->filter.main_initial.length_blocks,
-		config->filter.main_initial.leakage_converged,
-		config->filter.main_initial.leakage_diverged,
-		config->filter.main_initial.error_floor,
-		config->filter.main_initial.noise_gate
-	};
-	aec3_config->filter.shadow_initial = {
-		config->filter.shadow_initial.length_blocks,
-		config->filter.shadow_initial.rate,
-		config->filter.shadow_initial.noise_gate
-	};
-	aec3_config->filter.config_change_duration_blocks =
-		config->filter.config_change_duration_blocks;
-	aec3_config->filter.initial_state_seconds =
-		config->filter.initial_state_seconds;
-	aec3_config->filter.conservative_initial_phase =
-		static_cast<bool>(config->filter.conservative_initial_phase);
-	aec3_config->filter.enable_shadow_filter_output_usage =
-		static_cast<bool>(
-			config->filter.enable_shadow_filter_output_usage);
-	aec3_config->erle = {
-		config->erle.min,
-		config->erle.max_l,
-		config->erle.max_h,
-		static_cast<bool>(config->erle.onset_detection)
-	};
-	aec3_config->ep_strength = {
-		config->ep_strength.lf,
-		config->ep_strength.mf,
-		config->ep_strength.hf,
-		config->ep_strength.default_len,
-		static_cast<bool>(config->ep_strength.reverb_based_on_render),
-		static_cast<bool>(config->ep_strength.echo_can_saturate),
-		static_cast<bool>(config->ep_strength.bounded_erl)
-	};
-
-	aec3_config->gain_mask.m0 = config->gain_mask.m0;
-	aec3_config->gain_mask.m1 = config->gain_mask.m1;
-	aec3_config->gain_mask.m2 = config->gain_mask.m2;
-	aec3_config->gain_mask.m3 = config->gain_mask.m3;
-	aec3_config->gain_mask.m5 = config->gain_mask.m5;
-	aec3_config->gain_mask.m6 = config->gain_mask.m6;
-	aec3_config->gain_mask.m7 = config->gain_mask.m7;
-	aec3_config->gain_mask.m8 = config->gain_mask.m8;
-	aec3_config->gain_mask.m9 = config->gain_mask.m9;
-	aec3_config->gain_mask.gain_curve_offset =
-			config->gain_mask.gain_curve_offset;
-	aec3_config->gain_mask.gain_curve_slope =
-			config->gain_mask.gain_curve_slope;
-	aec3_config->gain_mask.temporal_masking_lf =
-			config->gain_mask.temporal_masking_lf;
-	aec3_config->gain_mask.temporal_masking_hf =
-			config->gain_mask.temporal_masking_hf;
-	aec3_config->gain_mask.temporal_masking_lf_bands =
-			config->gain_mask.temporal_masking_lf_bands;
-
-	aec3_config->echo_audibility = {
-		config->echo_audibility.low_render_limit,
-		config->echo_audibility.normal_render_limit,
-		config->echo_audibility.floor_power,
-		config->echo_audibility.audibility_threshold_lf,
-		config->echo_audibility.audibility_threshold_mf,
-		config->echo_audibility.audibility_threshold_hf,
-		static_cast<bool>(
-			config->echo_audibility.use_stationary_properties)
-	};
-	aec3_config->render_levels = {
-		config->render_levels.active_render_limit,
-		config->render_levels.poor_excitation_render_limit,
-		config->render_levels.poor_excitation_render_limit_ds8,
-	};
-
-	aec3_config->echo_removal_control = {
-		{
-		config->echo_removal_control.gain_rampup.initial_gain,
-		config->echo_removal_control.gain_rampup.first_non_zero_gain,
-		config->echo_removal_control.gain_rampup.non_zero_gain_blocks,
-		config->echo_removal_control.gain_rampup.full_gain_blocks
-		},
-		static_cast<bool>(config->echo_removal_control.has_clock_drift),
-		static_cast<bool>(
-			config->echo_removal_control.linear_and_stable_echo_path)
-	};
-
-	webrtc::EchoCanceller3Config::EchoModel echo_model;
-
-	echo_model.noise_floor_hold = config->echo_model.noise_floor_hold;
-	echo_model.min_noise_floor_power =
-			config->echo_model.min_noise_floor_power;
-	echo_model.stationary_gate_slope =
-			config->echo_model.stationary_gate_slope;
-	echo_model.noise_gate_power = config->echo_model.noise_gate_power;
-	echo_model.noise_gate_slope = config->echo_model.noise_gate_slope;
-	echo_model.render_pre_window_size =
-			config->echo_model.render_pre_window_size;
-	echo_model.render_post_window_size =
-			config->echo_model.render_post_window_size;
-	echo_model.render_pre_window_size_init =
-			config->echo_model.render_pre_window_size_init;
-	echo_model.render_post_window_size_init =
-			config->echo_model.render_post_window_size_init;
-	echo_model.nonlinear_hold = config->echo_model.nonlinear_hold;
-	echo_model.nonlinear_release = config->echo_model.nonlinear_release;
-
-	aec3_config->echo_model = echo_model;
-
-	aec3_config->suppressor.normal_tuning.mask_lf.enr_transparent =
-		config->suppressor.normal_tuning.mask_lf.enr_transparent;
-	aec3_config->suppressor.normal_tuning.mask_lf.enr_suppress =
-		config->suppressor.normal_tuning.mask_lf.enr_suppress;
-	aec3_config->suppressor.normal_tuning.mask_lf.emr_transparent =
-		config->suppressor.normal_tuning.mask_lf.emr_transparent;
-	aec3_config->suppressor.normal_tuning.mask_hf.enr_transparent =
-		config->suppressor.normal_tuning.mask_hf.enr_transparent;
-	aec3_config->suppressor.normal_tuning.mask_hf.enr_suppress =
-		config->suppressor.normal_tuning.mask_hf.enr_suppress;
-	aec3_config->suppressor.normal_tuning.mask_hf.emr_transparent =
-		config->suppressor.normal_tuning.mask_hf.emr_transparent;
-	aec3_config->suppressor.normal_tuning.max_inc_factor =
-		config->suppressor.normal_tuning.max_inc_factor;
-	aec3_config->suppressor.normal_tuning.max_dec_factor_lf =
-		config->suppressor.normal_tuning.max_dec_factor_lf;
-
-	aec3_config->suppressor.nearend_tuning.mask_lf.enr_transparent =
-		config->suppressor.nearend_tuning.mask_lf.enr_transparent;
-	aec3_config->suppressor.nearend_tuning.mask_lf.enr_suppress =
-		config->suppressor.nearend_tuning.mask_lf.enr_suppress;
-	aec3_config->suppressor.nearend_tuning.mask_lf.emr_transparent =
-		config->suppressor.nearend_tuning.mask_lf.emr_transparent;
-	aec3_config->suppressor.nearend_tuning.mask_hf.enr_transparent =
-		config->suppressor.nearend_tuning.mask_hf.enr_transparent;
-	aec3_config->suppressor.nearend_tuning.mask_hf.enr_suppress =
-		config->suppressor.nearend_tuning.mask_hf.enr_suppress,
-	aec3_config->suppressor.nearend_tuning.mask_hf.emr_transparent =
-		config->suppressor.nearend_tuning.mask_hf.emr_transparent;
-	aec3_config->suppressor.nearend_tuning.max_inc_factor =
-		config->suppressor.nearend_tuning.max_inc_factor;
-	aec3_config->suppressor.nearend_tuning.max_dec_factor_lf =
-		config->suppressor.nearend_tuning.max_dec_factor_lf;
-
-	aec3_config->suppressor.dominant_nearend_detection.enr_threshold =
-		config->suppressor.dominant_nearend_detection.enr_threshold;
-	aec3_config->suppressor.dominant_nearend_detection.snr_threshold =
-		config->suppressor.dominant_nearend_detection.snr_threshold;
-	aec3_config->suppressor.dominant_nearend_detection.hold_duration =
-		config->suppressor.dominant_nearend_detection.hold_duration;
-	aec3_config->suppressor.dominant_nearend_detection.trigger_threshold =
-		config->suppressor.dominant_nearend_detection.trigger_threshold;
-
-	aec3_config->suppressor.high_bands_suppression.enr_threshold =
-		config->suppressor.high_bands_suppression.enr_threshold;
-	aec3_config->suppressor.high_bands_suppression.max_gain_during_echo =
-		config->suppressor.high_bands_suppression.max_gain_during_echo;
-
-	aec3_config->suppressor.floor_first_increase =
-		config->suppressor.floor_first_increase;
-	aec3_config->suppressor.enforce_transparent =
-		config->suppressor.enforce_transparent;
-	aec3_config->suppressor.enforce_empty_higher_bands =
-		config->suppressor.enforce_empty_higher_bands;
-
-	return 0;
-}
-
-int convert_to_ap_config(struct apm_config *apm_config,
-			 webrtc::AudioProcessing::Config *ap_config)
-{
-	ap_config->residual_echo_detector.enabled =
-		apm_config->residual_echo_detector_enabled;
-	ap_config->high_pass_filter.enabled =
-		apm_config->high_pass_filter_enabled;
-	ap_config->pre_amplifier.enabled =
-		apm_config->pre_amplifier_enabled;
-	ap_config->pre_amplifier.fixed_gain_factor =
-		apm_config->pre_amplifier_fixed_gain_factor;
-	ap_config->gain_controller2.enabled =
-		apm_config->gain_controller2_enabled;
-	ap_config->gain_controller2.fixed_gain_db =
-		apm_config->gain_controller2_fixed_gain_db;
-	ap_config->gain_controller2.adaptive_digital_mode =
-		apm_config->gain_controller2_adaptive_digital_mode;
-	return 0;
-}
-
 webrtc_apm webrtc_apm_create(unsigned int num_channels,
 			     unsigned int frame_rate,
-			     struct aec_config *aec_config,
-			     struct apm_config *apm_config)
+			     dictionary *aec_ini,
+			     dictionary *apm_ini)
 {
 	int err;
 	webrtc::AudioProcessing *apm;
@@ -248,17 +28,6 @@
 	webrtc::AudioProcessingBuilder apm_builder;
 	webrtc::EchoCanceller3Config aec3_config;
 	std::unique_ptr<webrtc::EchoControlFactory> ec3_factory;
-	webrtc::AudioProcessing::Config ap_config;
-	webrtc::GainControl::Mode agc_mode;
-	webrtc::NoiseSuppression::Level ns_level;
-
-	if (aec_config) {
-		convert_to_aec3_config(aec_config, &aec3_config);
-		ec3_factory.reset(
-			new webrtc::EchoCanceller3Factory(aec3_config));
-	} else {
-		ec3_factory.reset(new webrtc::EchoCanceller3Factory());
-	}
 
 	switch (num_channels) {
 		case 1:
@@ -271,54 +40,19 @@
 			return NULL;
 	}
 
+	if (aec_ini) {
+		aec_config_get(aec_ini, &aec3_config);
+		ec3_factory.reset(
+			new webrtc::EchoCanceller3Factory(aec3_config));
+	} else {
+		ec3_factory.reset(new webrtc::EchoCanceller3Factory());
+	}
+
 	apm_builder.SetEchoControlFactory(std::move(ec3_factory));
 	apm = apm_builder.Create();
 
-	if (apm_config) {
-		convert_to_ap_config(apm_config, &ap_config);
-		apm->ApplyConfig(ap_config);
-
-		/* Configure AGC1 */
-		switch (apm_config->agc_mode) {
-		case ADAPTIVE_ANALOG:
-			agc_mode = webrtc::GainControl::Mode::kAdaptiveAnalog;
-			break;
-		case ADAPTIVE_DIGITAL:
-			agc_mode = webrtc::GainControl::Mode::kAdaptiveDigital;
-			break;
-		case FIXED_DITIGAL:
-			agc_mode = webrtc::GainControl::Mode::kFixedDigital;
-			break;
-		default:
-			return NULL;
-		}
-		apm->gain_control()->set_compression_gain_db(
-				apm_config->gain_control_compression_gain_db);
-		apm->gain_control()->set_mode(agc_mode);
-		apm->gain_control()->Enable(
-				apm_config->gain_control_enabled);
-		/* Configure noise suppression */
-		switch (apm_config->ns_level) {
-		case LOW:
-			ns_level = webrtc::NoiseSuppression::Level::kLow;
-			break;
-		case MODERATE:
-			ns_level = webrtc::NoiseSuppression::Level::kModerate;
-			break;
-		case HIGH:
-			ns_level = webrtc::NoiseSuppression::Level::kHigh;
-			break;
-		case VERY_HIGH:
-			ns_level = webrtc::NoiseSuppression::Level::kVeryHigh;
-			break;
-		default:
-			return NULL;
-
-		}
-		apm->noise_suppression()->set_level(ns_level);
-		apm->noise_suppression()->Enable(
-				apm_config->noise_suppression_enabled);
-	}
+	if (apm_ini)
+		apm_config_apply(apm_ini, apm);
 
 	err = apm->Initialize(frame_rate, frame_rate, frame_rate,
 			      channel_layout, channel_layout, channel_layout);
@@ -330,6 +64,15 @@
 	return reinterpret_cast<webrtc_apm>(apm);
 }
 
+void webrtc_apm_dump_configs(dictionary *apm_ini,
+			     dictionary *aec_ini)
+{
+	if (apm_ini)
+		apm_config_dump(apm_ini);
+	if (aec_ini)
+		aec_config_dump(aec_ini);
+}
+
 int webrtc_apm_process_reverse_stream_f(
 		webrtc_apm ptr,
 		int num_channels, int rate,
diff --git a/webrtc_apm.h b/webrtc_apm.h
index 81c1784..dce3ea1 100644
--- a/webrtc_apm.h
+++ b/webrtc_apm.h
@@ -6,213 +6,12 @@
 #ifndef WEBRTC_APM_H_
 #define WEBRTC_APM_H_
 
+#include <iniparser.h>
 #include <stdint.h>
 #include <stdio.h>
 
 #define WEBRTC_APM_API __attribute__((visibility("default")))
 
-/*
- * Structures exposing EchoCanceller3Config from upstream
- * echo_canceller3_config.h to webrtc-apm library callers for
- * tuning purpose. We need to update these parameter structures
- * carefully because changing them could break the caller.
- */
-struct delay {
-	size_t default_delay;
-	size_t down_sampling_factor;
-	size_t num_filters;
-	size_t api_call_jitter_blocks;
-	size_t min_echo_path_delay_blocks;
-	size_t delay_headroom_blocks;
-	size_t hysteresis_limit_1_blocks;
-	size_t hysteresis_limit_2_blocks;
-	size_t skew_hysteresis_blocks;
-	size_t fixed_capture_delay_samples;
-};
-
-struct MainConfiguration {
-	size_t length_blocks;
-	float leakage_converged;
-	float leakage_diverged;
-	float error_floor;
-	float noise_gate;
-};
-
-struct ShadowConfiguration {
-	size_t length_blocks;
-	float rate;
-	float noise_gate;
-};
-
-struct filter {
-	struct MainConfiguration main;
-	struct ShadowConfiguration shadow;
-	struct MainConfiguration main_initial;
-	struct ShadowConfiguration shadow_initial;
-	int config_change_duration_blocks;
-	float initial_state_seconds;
-	int conservative_initial_phase;
-	int enable_shadow_filter_output_usage;
-};
-
-struct erle {
-	float min;
-	float max_l;
-	float max_h;
-	int onset_detection;
-};
-
-struct ep_strength {
-	float lf;
-	float mf;
-	float hf;
-	float default_len;
-	int reverb_based_on_render;
-	int echo_can_saturate;
-	int bounded_erl;
-};
-
-struct mask {
-	float m0;
-	float m1;
-	float m2;
-	float m3;
-	float m5;
-	float m6;
-	float m7;
-	float m8;
-	float m9;
-
-	float gain_curve_offset;
-	float gain_curve_slope;
-	float temporal_masking_lf;
-	float temporal_masking_hf;
-	size_t temporal_masking_lf_bands;
-};
-
-struct echo_audibility {
-	float low_render_limit;
-	float normal_render_limit;
-	float floor_power;
-	float audibility_threshold_lf;
-	float audibility_threshold_mf;
-	float audibility_threshold_hf;
-	int use_stationary_properties;
-};
-
-struct render_levels {
-	float active_render_limit;
-	float poor_excitation_render_limit;
-	float poor_excitation_render_limit_ds8;
-};
-
-struct GainRampup {
-	float initial_gain;
-	float first_non_zero_gain;
-	int non_zero_gain_blocks;
-	int full_gain_blocks;
-};
-
-struct echo_removal_control {
-	struct GainRampup gain_rampup;
-	int has_clock_drift;
-	int linear_and_stable_echo_path;
-};
-
-struct echo_model {
-	size_t noise_floor_hold;
-	float min_noise_floor_power;
-	float stationary_gate_slope;
-	float noise_gate_power;
-	float noise_gate_slope;
-	size_t render_pre_window_size;
-	size_t render_post_window_size;
-	size_t render_pre_window_size_init;
-	size_t render_post_window_size_init;
-	float nonlinear_hold;
-	float nonlinear_release;
-};
-
-struct masking_thresholds {
-	float enr_transparent;
-	float enr_suppress;
-	float emr_transparent;
-};
-
-struct tuning {
-	struct masking_thresholds mask_lf;
-	struct masking_thresholds mask_hf;
-	float max_inc_factor;
-	float max_dec_factor_lf;
-};
-
-struct dominant_nearend_detection {
-	float enr_threshold;
-	float snr_threshold;
-	int hold_duration;
-	int trigger_threshold;
-};
-
-struct high_bands_suppression {
-	float enr_threshold;
-	float max_gain_during_echo;
-};
-
-struct suppressor {
-	size_t nearend_average_blocks;
-	struct tuning normal_tuning;
-	struct tuning nearend_tuning;
-	struct dominant_nearend_detection dominant_nearend_detection;
-	struct high_bands_suppression high_bands_suppression;
-	float floor_first_increase;
-	int enforce_transparent;
-	int enforce_empty_higher_bands;
-};
-
-struct aec_config {
-	struct delay delay;
-	struct filter filter;
-	struct erle erle;
-	struct ep_strength ep_strength;
-	struct mask gain_mask;
-	struct echo_audibility echo_audibility;
-	struct render_levels render_levels;
-	struct echo_removal_control echo_removal_control;
-	struct echo_model echo_model;
-	struct suppressor suppressor;
-};
-
-/* Corresponds to webrtc::GainControl::Mode */
-enum gain_control_mode {
-	ADAPTIVE_ANALOG,
-	ADAPTIVE_DIGITAL,
-	FIXED_DITIGAL,
-};
-
-/* Corresponds to webrtc::NoiseSuppression::Level */
-enum noise_suppression_level {
-	LOW,
-	MODERATE,
-	HIGH,
-	VERY_HIGH,
-};
-
-/* Equivalent to AudioProcessing::Config */
-struct apm_config {
-	int residual_echo_detector_enabled;
-	int high_pass_filter_enabled;
-	int pre_amplifier_enabled;
-	float pre_amplifier_fixed_gain_factor;
-	int gain_controller2_enabled;
-	float gain_controller2_fixed_gain_db;
-	int gain_controller2_adaptive_digital_mode;
-	int gain_control_compression_gain_db;
-	enum gain_control_mode agc_mode;
-	int gain_control_enabled;
-	enum noise_suppression_level ns_level;
-	int noise_suppression_enabled;
-};
-
 /* Pointer to a webrtc::AudioProcessing instance. */
 typedef void* webrtc_apm;
 
@@ -227,8 +26,17 @@
 WEBRTC_APM_API webrtc_apm webrtc_apm_create(
 		unsigned int num_channels,
 		unsigned int frame_rate,
-		struct aec_config *aec_config,
-		struct apm_config *apm_config);
+		dictionary *aec_ini,
+		dictionary *apm_ini);
+
+/* Dumps configs content.
+ * Args:
+ *    apm_ini - APM config file in ini format.
+ *    aec_ini - AEC3 config file in ini format.
+ */
+WEBRTC_APM_API void webrtc_apm_dump_configs(
+		dictionary *apm_ini,
+		dictionary *aec_ini);
 
 /* Destroys a webrtc_apm instance. */
 WEBRTC_APM_API void webrtc_apm_destroy(webrtc_apm apm);