+static bool pa_speex_ec_preprocessor_init(pa_echo_canceller *ec, pa_sample_spec *out_ss, uint32_t nframes, pa_modargs *ma) {
+ bool agc;
+ bool denoise;
+ bool echo_suppress;
+ int32_t echo_suppress_attenuation;
+ int32_t echo_suppress_attenuation_active;
+
+ agc = DEFAULT_AGC_ENABLED;
+ if (pa_modargs_get_value_boolean(ma, "agc", &agc) < 0) {
+ pa_log("Failed to parse agc value");
+ goto fail;
+ }
+
+ denoise = DEFAULT_DENOISE_ENABLED;
+ if (pa_modargs_get_value_boolean(ma, "denoise", &denoise) < 0) {
+ pa_log("Failed to parse denoise value");
+ goto fail;
+ }
+
+ echo_suppress = DEFAULT_ECHO_SUPPRESS_ENABLED;
+ if (pa_modargs_get_value_boolean(ma, "echo_suppress", &echo_suppress) < 0) {
+ pa_log("Failed to parse echo_suppress value");
+ goto fail;
+ }
+
+ echo_suppress_attenuation = DEFAULT_ECHO_SUPPRESS_ATTENUATION;
+ if (pa_modargs_get_value_s32(ma, "echo_suppress_attenuation", &echo_suppress_attenuation) < 0) {
+ pa_log("Failed to parse echo_suppress_attenuation value");
+ goto fail;
+ }
+ if (echo_suppress_attenuation > 0) {
+ pa_log("echo_suppress_attenuation should be a negative dB value");
+ goto fail;
+ }
+
+ echo_suppress_attenuation_active = DEFAULT_ECHO_SUPPRESS_ATTENUATION;
+ if (pa_modargs_get_value_s32(ma, "echo_suppress_attenuation_active", &echo_suppress_attenuation_active) < 0) {
+ pa_log("Failed to parse echo_suppress_attenuation_active value");
+ goto fail;
+ }
+ if (echo_suppress_attenuation_active > 0) {
+ pa_log("echo_suppress_attenuation_active should be a negative dB value");
+ goto fail;
+ }
+
+ if (agc || denoise || echo_suppress) {
+ spx_int32_t tmp;
+
+ if (out_ss->channels != 1) {
+ pa_log("AGC, denoising and echo suppression only work with channels=1");
+ goto fail;
+ }
+
+ ec->params.priv.speex.pp_state = speex_preprocess_state_init(nframes, out_ss->rate);
+
+ tmp = agc;
+ speex_preprocess_ctl(ec->params.priv.speex.pp_state, SPEEX_PREPROCESS_SET_AGC, &tmp);
+
+ tmp = denoise;
+ speex_preprocess_ctl(ec->params.priv.speex.pp_state, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
+
+ if (echo_suppress) {
+ if (echo_suppress_attenuation)
+ speex_preprocess_ctl(ec->params.priv.speex.pp_state, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS,
+ &echo_suppress_attenuation);
+
+ if (echo_suppress_attenuation_active) {
+ speex_preprocess_ctl(ec->params.priv.speex.pp_state, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE,
+ &echo_suppress_attenuation_active);
+ }
+
+ speex_preprocess_ctl(ec->params.priv.speex.pp_state, SPEEX_PREPROCESS_SET_ECHO_STATE,
+ ec->params.priv.speex.state);
+ }
+
+ pa_log_info("Loaded speex preprocessor with params: agc=%s, denoise=%s, echo_suppress=%s", pa_yes_no(agc),
+ pa_yes_no(denoise), pa_yes_no(echo_suppress));
+ } else
+ pa_log_info("All preprocessing options are disabled");
+
+ return true;
+
+fail:
+ return false;
+}
+
+bool pa_speex_ec_init(pa_core *c, pa_echo_canceller *ec,
+ pa_sample_spec *rec_ss, pa_channel_map *rec_map,
+ pa_sample_spec *play_ss, pa_channel_map *play_map,
+ pa_sample_spec *out_ss, pa_channel_map *out_map,
+ uint32_t *nframes, const char *args) {
+ int rate;