PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(true);
PA_MODULE_USAGE(
+ "method=<name of method using for echo cancellation> "
"blocksize=<the bytes of processing block on source domain> ");
typedef struct echo_cancel pa_echo_cancel;
bool enable;
uint32_t n_source_output;
size_t blocksize;
+ char *default_method;
pa_thread *thread;
pa_thread_mq thread_mq;
#define MEMBLOCKQ_MAXLENGTH (16 * 1024 * 1024)
#define CHECK_FLAGS_AEC(x) (x & PA_SOURCE_OUTPUT_ECHO_CANCEL)
#define CHECK_COUNT_SOURCE_OUTPUT_AEC(x) (x->n_source_output)
+#define DEFAULT_AEC_METHOD "speex"
static const char* const valid_modargs[] = {
+ "method",
"blocksize",
NULL,
};
return 0;
}
-static pa_processor_algo_t pa_processor_get_algo(pa_source_output *o) {
- const char *algo = pa_proplist_gets(o->proplist, "echo");
+static int pa_processor_get_method(pa_source_output *o, const char *default_method, pa_processor_algo_t *method) {
+ const char *selected, *requested;
- if (!algo) {
- pa_log_warn("Use default processor(speex)");
- return PA_PROCESSOR_SPEEX;
- }
+ pa_assert(method);
+ pa_assert(default_method);
- if (pa_streq(algo, "adrian"))
- return PA_PROCESSOR_ADRIAN;
- else if (pa_streq(algo, "speex"))
- return PA_PROCESSOR_SPEEX;
- else if (pa_streq(algo, "webrtc"))
- return PA_PROCESSOR_WEBRTC;
- else if (pa_streq(algo, "auto"))
- return PA_PROCESSOR_WEBRTC;
- else {
- pa_log_warn("invalid algo(%s), Use default processor(speex)", algo);
- return PA_PROCESSOR_SPEEX;
- }
+ requested = pa_proplist_gets(o->proplist, "echo_cancel");
+ if (!requested)
+ return -1;
+
+ selected = pa_streq(requested, "default") ? default_method : requested;
+
+ if (pa_streq(selected, "webrtc"))
+ *method = PA_PROCESSOR_WEBRTC;
+ else if (pa_streq(selected, "speex"))
+ *method = PA_PROCESSOR_SPEEX;
+ else if (pa_streq(selected, "adrian"))
+ *method = PA_PROCESSOR_ADRIAN;
+ else
+ *method = PA_PROCESSOR_SPEEX;
+
+ return 0;
}
static pa_source_output *find_source_output_by_flags(pa_source *s) {
static pa_hook_result_t source_output_new_cb(pa_core *c, pa_source_output_new_data *data, void *userdata) {
struct userdata *u = (struct userdata *)userdata;
- const char *echo = pa_proplist_gets(data->proplist, "echo");
+ const char *echo_cancel;
pa_assert(c);
- pa_assert(data);
pa_assert(u);
+ pa_assert(data);
- if (!echo)
+ echo_cancel = pa_proplist_gets(data->proplist, "echo_cancel");
+ if (!echo_cancel)
return PA_HOOK_OK;
if (CHECK_COUNT_SOURCE_OUTPUT_AEC(u) > 0) {
static pa_hook_result_t source_output_put_cb(pa_core *c, pa_source_output *o, void *userdata) {
struct userdata *u = (struct userdata *)userdata;
size_t blocksize = u->blocksize;
- pa_processor_algo_t backend;
+ pa_processor_algo_t method;
pa_assert(c);
pa_assert(o);
if (o->thread_info.resampler)
blocksize = pa_resampler_result(o->thread_info.resampler, blocksize);
- backend = pa_processor_get_algo(o);
+ if (pa_processor_get_method(o, u->default_method, &method)) {
+ pa_log_error("Can't find method");
+ goto fail;
+ }
+
o->thread_info.processor = pa_processor_new(blocksize / pa_frame_size(&o->sample_spec),
&o->sample_spec,
- backend, PA_PROCESSOR_FLAGS_ECHO_CANCEL);
+ method, PA_PROCESSOR_FLAGS_ECHO_CANCEL);
if (!o->thread_info.processor) {
pa_log_error("Failed to create pa_processor. echo-cancellation will be disabled");
goto fail;
u->core = m->core;
u->m = m;
u->blocksize = blocksize;
+ u->default_method = pa_xstrdup(pa_modargs_get_value(ma, "method", DEFAULT_AEC_METHOD));
u->echo_cancel = pa_msgobject_new(pa_echo_cancel);
u->echo_cancel->parent.process_msg = process_msg;
pa_thread_mq_done(&u->thread_mq);
+ pa_xfree(u->default_method);
pa_xfree(u);
}