From 70471989e5e8349f751bf8d96b8950ffc6d4e497 Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Mon, 12 Sep 2022 11:45:35 +0200 Subject: [PATCH] module-echo-cancel: Add activate/deactivate methods Add methods activate() that is called before first call to run() when stream starts and deactivate() that is called after last call to run() when stream stops. This makes it possible for aec-plugins to reset their state between streams. --- spa/include/spa/interfaces/audio/aec.h | 8 +++- src/modules/module-echo-cancel.c | 58 ++++++++++++++++++++------ 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/spa/include/spa/interfaces/audio/aec.h b/spa/include/spa/interfaces/audio/aec.h index 601f7b61e..e68224057 100644 --- a/spa/include/spa/interfaces/audio/aec.h +++ b/spa/include/spa/interfaces/audio/aec.h @@ -36,7 +36,7 @@ extern "C" { #define SPA_TYPE_INTERFACE_AUDIO_AEC SPA_TYPE_INFO_INTERFACE_BASE "Audio:AEC" -#define SPA_VERSION_AUDIO_AEC 0 +#define SPA_VERSION_AUDIO_AEC 1 struct spa_audio_aec { struct spa_interface iface; const char *name; @@ -60,7 +60,7 @@ struct spa_audio_aec_events { }; struct spa_audio_aec_methods { -#define SPA_VERSION_AUDIO_AEC_METHODS 0 +#define SPA_VERSION_AUDIO_AEC_METHODS 1 uint32_t version; int (*add_listener) (void *object, @@ -71,6 +71,8 @@ struct spa_audio_aec_methods { int (*init) (void *object, const struct spa_dict *args, const struct spa_audio_info_raw *info); int (*run) (void *object, const float *rec[], const float *play[], float *out[], uint32_t n_samples); int (*set_props) (void *object, const struct spa_dict *args); + int (*activate) (void *object); + int (*deactivate) (void *object); }; #define spa_audio_aec_method(o,method,version,...) \ @@ -87,6 +89,8 @@ struct spa_audio_aec_methods { #define spa_audio_aec_init(o,...) spa_audio_aec_method(o, init, 0, __VA_ARGS__) #define spa_audio_aec_run(o,...) spa_audio_aec_method(o, run, 0, __VA_ARGS__) #define spa_audio_aec_set_props(o,...) spa_audio_aec_method(o, set_props, 0, __VA_ARGS__) +#define spa_audio_aec_activate(o) spa_audio_aec_method(o, activate, 1) +#define spa_audio_aec_deactivate(o) spa_audio_aec_method(o, deactivate, 1) #ifdef __cplusplus } /* extern "C" */ diff --git a/src/modules/module-echo-cancel.c b/src/modules/module-echo-cancel.c index 5ac3cb6be..e9d426f2e 100644 --- a/src/modules/module-echo-cancel.c +++ b/src/modules/module-echo-cancel.c @@ -402,7 +402,7 @@ static void capture_process(void *data) pw_stream_queue_buffer(impl->capture, buf); } -static void input_state_changed(void *data, enum pw_stream_state old, +static void capture_state_changed(void *data, enum pw_stream_state old, enum pw_stream_state state, const char *error) { struct impl *impl = data; @@ -423,6 +423,44 @@ static void input_state_changed(void *data, enum pw_stream_state old, } } +static void source_state_changed(void *data, enum pw_stream_state old, + enum pw_stream_state state, const char *error) +{ + struct impl *impl = data; + int res; + + switch (state) { + case PW_STREAM_STATE_PAUSED: + pw_stream_flush(impl->source, false); + pw_stream_flush(impl->capture, false); + + if (old == PW_STREAM_STATE_STREAMING) { + pw_log_debug("%p: deactivate %s", impl, impl->aec->name); + res = spa_audio_aec_deactivate(impl->aec); + if (res < 0 && res != -EOPNOTSUPP) { + pw_log_error("aec plugin %s deactivate failed: %s", impl->aec->name, spa_strerror(res)); + } + } + break; + case PW_STREAM_STATE_STREAMING: + pw_log_debug("%p: activate %s", impl, impl->aec->name); + res = spa_audio_aec_activate(impl->aec); + if (res < 0 && res != -EOPNOTSUPP) { + pw_log_error("aec plugin %s activate failed: %s", impl->aec->name, spa_strerror(res)); + } + break; + case PW_STREAM_STATE_UNCONNECTED: + pw_log_info("%p: input unconnected", impl); + pw_impl_module_schedule_destroy(impl->module); + break; + case PW_STREAM_STATE_ERROR: + pw_log_info("%p: input error: %s", impl, error); + break; + default: + break; + } +} + static void input_param_latency_changed(struct impl *impl, const struct spa_pod *param) { struct spa_latency_info latency; @@ -455,7 +493,7 @@ static void input_param_changed(void *data, uint32_t id, const struct spa_pod *p static const struct pw_stream_events capture_events = { PW_VERSION_STREAM_EVENTS, .destroy = capture_destroy, - .state_changed = input_state_changed, + .state_changed = capture_state_changed, .process = capture_process, .param_changed = input_param_changed }; @@ -470,7 +508,7 @@ static void source_destroy(void *d) static const struct pw_stream_events source_events = { PW_VERSION_STREAM_EVENTS, .destroy = source_destroy, - .state_changed = input_state_changed, + .state_changed = source_state_changed, .param_changed = input_param_changed }; @@ -976,7 +1014,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) handle = spa_plugin_loader_load(impl->loader, SPA_NAME_AEC, &info); if (handle == NULL) { - pw_log_error("AEC codec plugin %s not available library.name %s", SPA_NAME_AEC, path); + pw_log_error("aec plugin %s not available library.name %s", SPA_NAME_AEC, path); return -ENOENT; } @@ -986,14 +1024,8 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) } impl->aec = iface; impl->spa_handle = handle; - if (impl->aec->iface.version != SPA_VERSION_AUDIO_AEC) { - pw_log_error("codec plugin %s has incompatible ABI version (%d != %d)", - SPA_NAME_AEC, impl->aec->iface.version, SPA_VERSION_AUDIO_AEC); - res = -ENOENT; - goto error; - } - - pw_log_info("Using plugin AEC %s", impl->aec->name); + pw_log_info("loaded aec plugin %s with interface version %d, using interface version %d", + impl->aec->name, impl->aec->iface.version, SPA_VERSION_AUDIO_AEC); if ((str = pw_properties_get(props, "aec.args")) != NULL) aec_props = pw_properties_new_string(str); @@ -1005,7 +1037,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) pw_properties_free(aec_props); if (res < 0) { - pw_log_error("codec plugin %s create failed: %s", impl->aec->name, + pw_log_error("aec plugin %s create failed: %s", impl->aec->name, spa_strerror(res)); goto error; }