diff options
| -rw-r--r-- | src/modules/echo-cancel/echo-cancel.h | 6 | ||||
| -rw-r--r-- | src/modules/echo-cancel/module-echo-cancel.c | 61 | 
2 files changed, 64 insertions, 3 deletions
diff --git a/src/modules/echo-cancel/echo-cancel.h b/src/modules/echo-cancel/echo-cancel.h index 5f6adbc1..5f18053c 100644 --- a/src/modules/echo-cancel/echo-cancel.h +++ b/src/modules/echo-cancel/echo-cancel.h @@ -29,6 +29,7 @@  #include <pulsecore/macro.h>  #include <speex/speex_echo.h> +#include <speex/speex_preprocess.h>  #include "adrian.h"  /* Common data structures */ @@ -63,6 +64,11 @@ struct pa_echo_canceller {      void        (*done)                 (pa_echo_canceller *ec);      pa_echo_canceller_params params; + +    pa_bool_t agc; +    pa_bool_t denoise; +    pa_bool_t echo_suppress; +    SpeexPreprocessState *pp_state;  };  /* Speex canceller functions */ diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c index b0d3c687..e83839a9 100644 --- a/src/modules/echo-cancel/module-echo-cancel.c +++ b/src/modules/echo-cancel/module-echo-cancel.c @@ -77,6 +77,9 @@ PA_MODULE_USAGE(            "channel_map=<channel map> "            "aec_method=<implementation to use> "            "aec_args=<parameters for the AEC engine> " +          "agc=<perform automagic gain control?> " +          "denoise=<apply denoising?> " +          "echo_suppress=<perform echo suppression? (only with the speex canceller)> "            "save_aec=<save AEC data in /tmp> "            "autoloaded=<set if this module is being loaded automatically> "          )); @@ -106,6 +109,9 @@ static const pa_echo_canceller ec_table[] = {  };  #define DEFAULT_ADJUST_TIME_USEC (1*PA_USEC_PER_SEC) +#define DEFAULT_AGC_ENABLED FALSE +#define DEFAULT_DENOISE_ENABLED FALSE +#define DEFAULT_ECHO_SUPPRESS_ENABLED FALSE  #define DEFAULT_SAVE_AEC 0  #define DEFAULT_AUTOLOADED FALSE @@ -212,6 +218,9 @@ static const char* const valid_modargs[] = {      "channel_map",      "aec_method",      "aec_args", +    "agc", +    "denoise", +    "echo_suppress",      "save_aec",      "autoloaded",      NULL @@ -710,14 +719,20 @@ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk)                  cchunk.memblock = pa_memblock_new(u->source->core->mempool, cchunk.length);                  cdata = pa_memblock_acquire(cchunk.memblock); -                /* perform echo cancelation */ -                u->ec->run(u->ec, rdata, pdata, cdata); -                  if (u->save_aec) {                      if (u->captured_file)                          fwrite(rdata, 1, u->blocksize, u->captured_file);                      if (u->played_file)                          fwrite(pdata, 1, u->blocksize, u->played_file); +                } + +                if (u->ec->pp_state) +                    speex_preprocess_run(u->ec->pp_state, (spx_int16_t *) rdata); + +                /* perform echo cancelation */ +                u->ec->run(u->ec, rdata, pdata, cdata); + +                if (u->save_aec) {                      if (u->canceled_file)                          fwrite(cdata, 1, u->blocksize, u->canceled_file);                  } @@ -1391,6 +1406,28 @@ int pa__init(pa_module*m) {      else          u->adjust_time = DEFAULT_ADJUST_TIME_USEC; +    u->ec->agc = DEFAULT_AGC_ENABLED; +    if (pa_modargs_get_value_boolean(ma, "agc", &u->ec->agc) < 0) { +        pa_log("Failed to parse agc value"); +        goto fail; +    } + +    u->ec->denoise = DEFAULT_DENOISE_ENABLED; +    if (pa_modargs_get_value_boolean(ma, "denoise", &u->ec->denoise) < 0) { +        pa_log("Failed to parse denoise value"); +        goto fail; +    } + +    u->ec->echo_suppress = DEFAULT_ECHO_SUPPRESS_ENABLED; +    if (pa_modargs_get_value_boolean(ma, "echo_suppress", &u->ec->echo_suppress) < 0) { +        pa_log("Failed to parse echo_suppress value"); +        goto fail; +    } +    if (u->ec->echo_suppress && ec_method != PA_ECHO_CANCELLER_SPEEX) { +        pa_log("Echo suppression is only useful with the speex canceller"); +        goto fail; +    } +      u->save_aec = DEFAULT_SAVE_AEC;      if (pa_modargs_get_value_u32(ma, "save_aec", &u->save_aec) < 0) {          pa_log("Failed to parse save_aec value"); @@ -1412,6 +1449,21 @@ int pa__init(pa_module*m) {          }      } +    if (u->ec->agc || u->ec->denoise || u->ec->echo_suppress) { +        if (source_ss.channels != 1) { +            pa_log("AGC, denoising and echo suppression only work with channels=1"); +            goto fail; +        } + +        u->ec->pp_state = speex_preprocess_state_init(u->blocksize, source_ss.rate); + +        speex_preprocess_ctl(u->ec->pp_state, SPEEX_PREPROCESS_SET_AGC, &u->ec->agc); +        speex_preprocess_ctl(u->ec->pp_state, SPEEX_PREPROCESS_SET_DENOISE, &u->ec->denoise); +        speex_preprocess_ctl(u->ec->pp_state, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS, &u->ec->echo_suppress); +        if (u->ec->echo_suppress) +            speex_preprocess_ctl(u->ec->pp_state, SPEEX_PREPROCESS_SET_ECHO_STATE, u->ec->params.priv.speex.state); +    } +      /* Create source */      pa_source_new_data_init(&source_data);      source_data.driver = __FILE__; @@ -1682,6 +1734,9 @@ void pa__done(pa_module*m) {      if (u->sink_memblockq)          pa_memblockq_free(u->sink_memblockq); +    if (u->ec->pp_state) +        speex_preprocess_state_destroy(u->ec->pp_state); +      if (u->ec) {          if (u->ec->done)              u->ec->done(u->ec);  | 
