Expose aec3 config

This change exposes the upstream EchoCanceller3Config
and make webrtc_apm_create takes a copy of this struct.
This allows caller to change the parameters for tuning.

BUG=chromium:710465
TEST=None
CQ-DEPEND=CL:1041306

Change-Id: I8337c151d4b7c08bf5dedd4c8833815214b8c058
Reviewed-on: https://chromium-review.googlesource.com/1046726
Commit-Ready: Hsinyu Chao <hychao@chromium.org>
Tested-by: Hsinyu Chao <hychao@chromium.org>
Reviewed-by: Cheng-Yi Chiang <cychiang@chromium.org>
diff --git a/webrtc_apm.cc b/webrtc_apm.cc
index b92a008..b770ab6 100644
--- a/webrtc_apm.cc
+++ b/webrtc_apm.cc
@@ -13,15 +13,180 @@
 extern "C" {
 #include "webrtc_apm.h"
 
+int convert_to_aec3_config(
+		const struct aec_config *config,
+		webrtc::EchoCanceller3Config *aec3_config)
+{
+	aec3_config->delay = {
+		config->delay.default_delay,
+		config->delay.down_sampling_factor,
+		config->delay.num_filters,
+		config->delay.api_call_jitter_blocks,
+		config->delay.min_echo_path_delay_blocks,
+		config->delay.delay_headroom_blocks,
+		config->delay.hysteresis_limit_1_blocks,
+		config->delay.hysteresis_limit_2_blocks,
+		config->delay.skew_hysteresis_blocks
+	};
+	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->erle = {
+		config->erle.min,
+		config->erle.max_l,
+		config->erle.max_h,
+	};
+	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.echo_can_saturate),
+		static_cast<bool>(config->ep_strength.bounded_erl)
+	};
+
+	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,
+	};
+	aec3_config->gain_updates.low_noise = {
+		config->gain_updates.low_noise.max_inc,
+		config->gain_updates.low_noise.max_dec,
+		config->gain_updates.low_noise.rate_inc,
+		config->gain_updates.low_noise.rate_dec,
+		config->gain_updates.low_noise.min_inc,
+		config->gain_updates.low_noise.min_dec,
+	};
+	aec3_config->gain_updates.initial = {
+		config->gain_updates.initial.max_inc,
+		config->gain_updates.initial.max_dec,
+		config->gain_updates.initial.rate_inc,
+		config->gain_updates.initial.rate_dec,
+		config->gain_updates.initial.min_inc,
+		config->gain_updates.initial.min_dec,
+	};
+	aec3_config->gain_updates.normal = {
+		config->gain_updates.normal.max_inc,
+		config->gain_updates.normal.max_dec,
+		config->gain_updates.normal.rate_inc,
+		config->gain_updates.normal.rate_dec,
+		config->gain_updates.normal.min_inc,
+		config->gain_updates.normal.min_dec,
+	};
+	aec3_config->gain_updates.saturation = {
+		config->gain_updates.saturation.max_inc,
+		config->gain_updates.saturation.max_dec,
+		config->gain_updates.saturation.rate_inc,
+		config->gain_updates.saturation.rate_dec,
+		config->gain_updates.saturation.min_inc,
+		config->gain_updates.saturation.min_dec,
+	};
+	aec3_config->gain_updates.nonlinear = {
+		config->gain_updates.nonlinear.max_inc,
+		config->gain_updates.nonlinear.max_dec,
+		config->gain_updates.nonlinear.rate_inc,
+		config->gain_updates.nonlinear.rate_dec,
+		config->gain_updates.nonlinear.min_inc,
+		config->gain_updates.nonlinear.min_dec,
+	};
+	aec3_config->gain_updates.floor_first_increase =
+		config->gain_updates.floor_first_increase;
+
+	aec3_config->echo_removal_control = {
+		{
+		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)
+	};
+
+	aec3_config->echo_model = {
+		config->echo_model.noise_floor_hold,
+		config->echo_model.min_noise_floor_power,
+		config->echo_model.stationary_gate_slope,
+		config->echo_model.noise_gate_power,
+		config->echo_model.noise_gate_slope,
+		config->echo_model.render_pre_window_size,
+		config->echo_model.render_post_window_size,
+		config->echo_model.nonlinear_hold,
+		config->echo_model.nonlinear_release
+	};
+
+
+	return 0;
+}
+
 webrtc_apm webrtc_apm_create(unsigned int num_channels,
-			unsigned int frame_rate,
-			unsigned int enable_echo_cancellation)
+			     unsigned int frame_rate,
+			     struct aec_config *config)
 {
 	int err;
 	webrtc::AudioProcessing *apm;
 	webrtc::AudioProcessing::ChannelLayout channel_layout;
 	webrtc::AudioProcessingBuilder apm_builder;
-	std::unique_ptr<webrtc::EchoControlFactory> ec3_factory(new webrtc::EchoCanceller3Factory());
+	webrtc::EchoCanceller3Config aec3_config;
+	std::unique_ptr<webrtc::EchoControlFactory> ec3_factory;
+
+	if (config) {
+		convert_to_aec3_config(config, &aec3_config);
+		ec3_factory.reset(
+			new webrtc::EchoCanceller3Factory(aec3_config));
+	} else {
+		ec3_factory.reset(new webrtc::EchoCanceller3Factory());
+	}
 
 	switch (num_channels) {
 		case 1:
diff --git a/webrtc_apm.h b/webrtc_apm.h
index a68e96f..918c4ab 100644
--- a/webrtc_apm.h
+++ b/webrtc_apm.h
@@ -11,6 +11,152 @@
 
 #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;
+};
+
+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;
+};
+
+struct erle {
+	float min;
+	float max_l;
+	float max_h;
+};
+
+struct ep_strength {
+	float lf;
+	float mf;
+	float hf;
+	float default_len;
+	int echo_can_saturate;
+	int bounded_erl;
+};
+
+struct mask {
+	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;
+};
+
+struct GainChanges {
+	float max_inc;
+	float max_dec;
+	float rate_inc;
+	float rate_dec;
+	float min_inc;
+	float min_dec;
+};
+
+struct gain_updates {
+	struct GainChanges low_noise;
+	struct GainChanges initial;
+	struct GainChanges normal;
+	struct GainChanges saturation;
+	struct GainChanges nonlinear;
+	float floor_first_increase;
+};
+
+struct GainRampup {
+	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;
+};
+
+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;
+	float nonlinear_hold;
+	float nonlinear_release;
+};
+
+struct suppressor {
+	size_t bands_with_reliable_coherence;
+ };
+
+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 gain_updates gain_updates;
+	struct echo_removal_control echo_removal_control;
+	struct echo_model echo_model;
+	struct suppressor suppressor;
+};
+
 /* Pointer to a webrtc::AudioProcessing instance. */
 typedef void* webrtc_apm;
 
@@ -19,13 +165,12 @@
  * Args:
  *    num_channels - Number of channels of the forward stream.
  *    frame_rate - Frame rate used by forward stream.
- *    enable_echo_cancellation - Set to true to enable echo cancellation in
- *        created webrtc_apm instance.
+ *    aec_config - Pointer to aec config.
  */
 WEBRTC_APM_API webrtc_apm webrtc_apm_create(
 		unsigned int num_channels,
 		unsigned int frame_rate,
-		unsigned int enable_echo_cancellation);
+		struct aec_config *aec_config);
 
 /* Destroys a webrtc_apm instance. */
 WEBRTC_APM_API void webrtc_apm_destroy(webrtc_apm apm);