From 2e157f7248570ea0430fb54ba7e9a26bae84c146 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 13 Nov 2024 10:20:54 +0100 Subject: [PATCH] filter-chain: make filter-graph SPA plugins Make SPA plugins from all the filter-graph plugins and use the plugin loader to load them. Because they are not in the standard plugin path in development, add the module dir to the plugin path for now. --- Makefile.in | 2 +- pw-uninstalled.sh | 2 +- src/modules/meson.build | 37 ++- src/modules/module-filter-chain.c | 4 + src/modules/module-filter-chain/audio-dsp.c | 3 + .../module-filter-chain/audio-plugin.h | 2 - .../module-filter-chain/builtin_plugin.c | 130 ++++++++-- .../module-filter-chain/filter-graph.c | 244 +++++++----------- .../module-filter-chain/ladspa_plugin.c | 198 ++++++++++---- src/modules/module-filter-chain/lv2_plugin.c | 224 +++++++++++----- src/modules/module-filter-chain/sofa_plugin.c | 128 +++++++-- 11 files changed, 648 insertions(+), 326 deletions(-) diff --git a/Makefile.in b/Makefile.in index 104619316..a5cc649b6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -16,7 +16,7 @@ clean: ninja -C $(BUILD_ROOT) clean run: all - SPA_PLUGIN_DIR=$(BUILD_ROOT)/spa/plugins \ + SPA_PLUGIN_DIR=$(BUILD_ROOT)/spa/plugins:$(BUILD_ROOT)/src/modules \ SPA_DATA_DIR=$(SOURCE_ROOT)/spa/plugins \ PIPEWIRE_MODULE_DIR=$(BUILD_ROOT)/src/modules \ PATH=$(BUILD_ROOT)/src/examples:$(PATH) \ diff --git a/pw-uninstalled.sh b/pw-uninstalled.sh index 1bb6c55c2..4167c4f4a 100755 --- a/pw-uninstalled.sh +++ b/pw-uninstalled.sh @@ -37,7 +37,7 @@ fi # the config file read by the daemon export PIPEWIRE_CONFIG_DIR="${BUILDDIR}/src/daemon" # the directory with SPA plugins -export SPA_PLUGIN_DIR="${BUILDDIR}/spa/plugins" +export SPA_PLUGIN_DIR="${BUILDDIR}/spa/plugins:${BUILDDIR}/src/modules" export SPA_DATA_DIR="${SCRIPT_DIR}/spa/plugins" # the directory with pipewire modules export PIPEWIRE_MODULE_DIR="${BUILDDIR}/src/modules" diff --git a/src/modules/meson.build b/src/modules/meson.build index fe3511310..219fa6170 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -126,9 +126,6 @@ simd_dependencies += filter_graph_c filter_graph = static_library('filter_graph', ['module-filter-chain/biquad.c', - 'module-filter-chain/ladspa_plugin.c', - 'module-filter-chain/builtin_plugin.c', - 'module-filter-chain/convolver.c', 'module-filter-chain/filter-graph.c' ], include_directories : [configinc], dependencies : [ spa_dep, sndfile_dep, plugin_dependencies ], @@ -150,25 +147,41 @@ pipewire_module_filter_chain = shared_library('pipewire-module-filter-chain', dependencies : [spa_dep, mathlib, dl_lib, pipewire_dep], ) -if libmysofa_dep.found() -pipewire_module_filter_graph_sofa = shared_library('pipewire-filter-graph-plugin-sofa', - [ 'module-filter-chain/sofa_plugin.c' ], +pipewire_module_filter_graph_builtin = shared_library('spa-filter-graph-plugin-builtin', + [ 'module-filter-chain/builtin_plugin.c', + 'module-filter-chain/convolver.c' ], include_directories : [configinc], install : true, - install_dir : modules_install_dir, - install_rpath: modules_install_dir, - link_with : simd_dependencies, + install_dir : spa_plugindir / 'filter-graph', + dependencies : [ filter_graph_dependencies ] +) + +pipewire_module_filter_graph_ladspa = shared_library('spa-filter-graph-plugin-ladspa', + [ 'module-filter-chain/ladspa_plugin.c' ], + include_directories : [configinc], + install : true, + install : true, + install_dir : spa_plugindir / 'filter-graph', + dependencies : [ filter_graph_dependencies ] +) + +if libmysofa_dep.found() +pipewire_module_filter_graph_sofa = shared_library('spa-filter-graph-plugin-sofa', + [ 'module-filter-chain/sofa_plugin.c', + 'module-filter-chain/convolver.c' ], + include_directories : [configinc], + install : true, + install_dir : spa_plugindir / 'filter-graph', dependencies : [ filter_graph_dependencies, libmysofa_dep ] ) endif if lilv_lib.found() -pipewire_module_filter_graph_lv2 = shared_library('pipewire-filter-graph-plugin-lv2', +pipewire_module_filter_graph_lv2 = shared_library('spa-filter-graph-plugin-lv2', [ 'module-filter-chain/lv2_plugin.c' ], include_directories : [configinc], install : true, - install_dir : modules_install_dir, - install_rpath: modules_install_dir, + install_dir : spa_plugindir / 'filter-graph', dependencies : [ filter_graph_dependencies, lilv_lib ] ) endif diff --git a/src/modules/module-filter-chain.c b/src/modules/module-filter-chain.c index 5a536a5e7..5add83ef0 100644 --- a/src/modules/module-filter-chain.c +++ b/src/modules/module-filter-chain.c @@ -1167,6 +1167,10 @@ static void impl_destroy(struct impl *impl) if (impl->core && impl->do_disconnect) pw_core_disconnect(impl->core); + if (impl->handle) + spa_handle_clear(impl->handle); + free(impl->handle); + pw_properties_free(impl->capture_props); pw_properties_free(impl->playback_props); diff --git a/src/modules/module-filter-chain/audio-dsp.c b/src/modules/module-filter-chain/audio-dsp.c index 1ba0b981c..fadd85349 100644 --- a/src/modules/module-filter-chain/audio-dsp.c +++ b/src/modules/module-filter-chain/audio-dsp.c @@ -11,6 +11,8 @@ #include #include +#include "pffft.h" + #include "audio-dsp-impl.h" struct dsp_info { @@ -111,6 +113,7 @@ struct spa_fga_dsp * spa_fga_dsp_new(uint32_t cpu_flags) if (dsp == NULL) return NULL; + pffft_select_cpu(cpu_flags); dsp->cpu_flags = cpu_flags; dsp->iface = SPA_INTERFACE_INIT( SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioDSP, diff --git a/src/modules/module-filter-chain/audio-plugin.h b/src/modules/module-filter-chain/audio-plugin.h index 124873487..1e2e31051 100644 --- a/src/modules/module-filter-chain/audio-plugin.h +++ b/src/modules/module-filter-chain/audio-plugin.h @@ -22,7 +22,6 @@ struct spa_fga_plugin_methods { uint32_t version; const struct spa_fga_descriptor *(*make_desc) (void *plugin, const char *name); - void (*free) (void *plugin); }; struct spa_fga_port { @@ -99,7 +98,6 @@ static inline void spa_fga_descriptor_free(const struct spa_fga_descriptor *desc #define spa_fga_plugin_make_desc(o,...) spa_fga_plugin_method_r(o,make_desc,0,__VA_ARGS__) -#define spa_fga_plugin_free(o,...) spa_fga_plugin_method(o,free,0,##__VA_ARGS__) typedef struct spa_fga_plugin *(spa_filter_graph_audio_plugin_load_func_t)(const struct spa_support *support, uint32_t n_support, const char *path, const struct spa_dict *info); diff --git a/src/modules/module-filter-chain/builtin_plugin.c b/src/modules/module-filter-chain/builtin_plugin.c index fd152ca9f..1ba7741c9 100644 --- a/src/modules/module-filter-chain/builtin_plugin.c +++ b/src/modules/module-filter-chain/builtin_plugin.c @@ -21,14 +21,15 @@ #include "audio-plugin.h" #include "biquad.h" -#include "pffft.h" #include "convolver.h" #include "audio-dsp.h" #define MAX_RATES 32u struct plugin { + struct spa_handle handle; struct spa_fga_plugin plugin; + struct spa_fga_dsp *dsp; struct spa_log *log; }; @@ -55,13 +56,14 @@ struct builtin { static void *builtin_instantiate(const struct spa_fga_plugin *plugin, const struct spa_fga_descriptor * Descriptor, unsigned long SampleRate, int index, const char *config) { + struct plugin *pl = SPA_CONTAINER_OF(plugin, struct plugin, plugin); struct builtin *impl; impl = calloc(1, sizeof(*impl)); if (impl == NULL) return NULL; - impl->plugin = (struct plugin *) plugin; + impl->plugin = pl; impl->rate = SampleRate; impl->dsp = impl->plugin->dsp; impl->log = impl->plugin->log; @@ -314,6 +316,7 @@ static void bq_raw_update(struct builtin *impl, float b0, float b1, float b2, static void *bq_instantiate(const struct spa_fga_plugin *plugin, const struct spa_fga_descriptor * Descriptor, unsigned long SampleRate, int index, const char *config) { + struct plugin *pl = SPA_CONTAINER_OF(plugin, struct plugin, plugin); struct builtin *impl; struct spa_json it[3]; const char *val; @@ -325,7 +328,7 @@ static void *bq_instantiate(const struct spa_fga_plugin *plugin, const struct sp if (impl == NULL) return NULL; - impl->plugin = (struct plugin *) plugin; + impl->plugin = pl; impl->log = impl->plugin->log; impl->dsp = impl->plugin->dsp; impl->rate = SampleRate; @@ -905,8 +908,8 @@ error: static void * convolver_instantiate(const struct spa_fga_plugin *plugin, const struct spa_fga_descriptor * Descriptor, unsigned long SampleRate, int index, const char *config) { + struct plugin *pl = SPA_CONTAINER_OF(plugin, struct plugin, plugin); struct convolver_impl *impl; - struct plugin *pl = (struct plugin*)plugin; float *samples; int offset = 0, length = 0, channel = index, n_samples = 0, len; uint32_t i = 0; @@ -1147,7 +1150,7 @@ static void delay_cleanup(void * Instance) static void *delay_instantiate(const struct spa_fga_plugin *plugin, const struct spa_fga_descriptor * Descriptor, unsigned long SampleRate, int index, const char *config) { - struct plugin *pl = (struct plugin*) plugin; + struct plugin *pl = SPA_CONTAINER_OF(plugin, struct plugin, plugin); struct delay_impl *impl; struct spa_json it[1]; const char *val; @@ -1901,7 +1904,7 @@ static int parse_filters(struct plugin *pl, struct spa_json *iter, int rate, static void *param_eq_instantiate(const struct spa_fga_plugin *plugin, const struct spa_fga_descriptor * Descriptor, unsigned long SampleRate, int index, const char *config) { - struct plugin *pl = (struct plugin *) plugin; + struct plugin *pl = SPA_CONTAINER_OF(plugin, struct plugin, plugin); struct spa_json it[3]; const char *val; char key[256], filename[PATH_MAX]; @@ -2142,30 +2145,121 @@ static const struct spa_fga_descriptor *builtin_plugin_make_desc(void *plugin, c return NULL; } -static void builtin_plugin_free(void *p) -{ - free(p); -} - static struct spa_fga_plugin_methods impl_plugin = { SPA_VERSION_FGA_PLUGIN_METHODS, .make_desc = builtin_plugin_make_desc, - .free = builtin_plugin_free }; -struct spa_fga_plugin *load_builtin_plugin(const struct spa_support *support, uint32_t n_support, - const char *plugin, const struct spa_dict *info) +static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface) { - struct plugin *impl = calloc (1, sizeof (struct plugin)); + struct plugin *impl; + + spa_return_val_if_fail(handle != NULL, -EINVAL); + spa_return_val_if_fail(interface != NULL, -EINVAL); + + impl = (struct plugin *) handle; + + if (spa_streq(type, SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioPlugin)) + *interface = &impl->plugin; + else + return -ENOENT; + + return 0; +} + +static int impl_clear(struct spa_handle *handle) +{ + return 0; +} + +static size_t +impl_get_size(const struct spa_handle_factory *factory, + const struct spa_dict *params) +{ + return sizeof(struct plugin); +} + +static int +impl_init(const struct spa_handle_factory *factory, + struct spa_handle *handle, + const struct spa_dict *info, + const struct spa_support *support, + uint32_t n_support) +{ + struct plugin *impl; + + handle->get_interface = impl_get_interface; + handle->clear = impl_clear; + + impl = (struct plugin *) handle; impl->plugin.iface = SPA_INTERFACE_INIT( SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioPlugin, SPA_VERSION_FGA_PLUGIN, &impl_plugin, impl); - impl->dsp = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioDSP); - pffft_select_cpu(impl->dsp->cpu_flags); impl->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); + impl->dsp = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioDSP); - return (struct spa_fga_plugin *) impl; + for (uint32_t i = 0; info && i < info->n_items; i++) { + const char *k = info->items[i].key; + const char *s = info->items[i].value; + if (spa_streq(k, "filter.graph.audio.dsp")) + sscanf(s, "pointer:%p", &impl->dsp); + } + if (impl->dsp == NULL) { + spa_log_error(impl->log, "%p: could not find DSP functions", impl); + return -EINVAL; + } + return 0; +} + +static const struct spa_interface_info impl_interfaces[] = { + {SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioPlugin,}, +}; + +static int +impl_enum_interface_info(const struct spa_handle_factory *factory, + const struct spa_interface_info **info, + uint32_t *index) +{ + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(info != NULL, -EINVAL); + spa_return_val_if_fail(index != NULL, -EINVAL); + + switch (*index) { + case 0: + *info = &impl_interfaces[*index]; + break; + default: + return 0; + } + (*index)++; + return 1; +} + +struct spa_handle_factory spa_fga_plugin_builtin_factory = { + SPA_VERSION_HANDLE_FACTORY, + "filter.graph.plugin.builtin", + NULL, + impl_get_size, + impl_init, + impl_enum_interface_info, +}; + +SPA_EXPORT +int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) +{ + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(index != NULL, -EINVAL); + + switch (*index) { + case 0: + *factory = &spa_fga_plugin_builtin_factory; + break; + default: + return 0; + } + (*index)++; + return 1; } diff --git a/src/modules/module-filter-chain/filter-graph.c b/src/modules/module-filter-chain/filter-graph.c index 3d2b5cfa3..9d9693aa0 100644 --- a/src/modules/module-filter-chain/filter-graph.c +++ b/src/modules/module-filter-chain/filter-graph.c @@ -15,13 +15,11 @@ #include "config.h" -#include "audio-plugin.h" -#include "filter-graph.h" - #include #include #include #include +#include #include #include #include @@ -32,7 +30,9 @@ #include #include -#include "module-filter-chain/audio-dsp-impl.h" +#include "audio-plugin.h" +#include "filter-graph.h" +#include "audio-dsp-impl.h" #undef SPA_LOG_TOPIC_DEFAULT #define SPA_LOG_TOPIC_DEFAULT &log_topic @@ -49,29 +49,19 @@ SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.filter-graph"); #define spa_filter_graph_emit_apply_props(hooks,...) spa_filter_graph_emit(hooks,apply_props, 0, __VA_ARGS__) #define spa_filter_graph_emit_props_changed(hooks,...) spa_filter_graph_emit(hooks,props_changed, 0, __VA_ARGS__) - -struct spa_fga_plugin *load_ladspa_plugin(const struct spa_support *support, uint32_t n_support, - const char *path, const struct spa_dict *info); -struct spa_fga_plugin *load_builtin_plugin(const struct spa_support *support, uint32_t n_support, - const char *path, const struct spa_dict *info); - struct plugin { struct spa_list link; + struct impl *impl; + int ref; char type[256]; char path[PATH_MAX]; + struct spa_handle *hndl; struct spa_fga_plugin *plugin; struct spa_list descriptor_list; }; -struct plugin_func { - struct spa_list link; - char type[256]; - spa_filter_graph_audio_plugin_load_func_t *func; - void *hndl; -}; - struct descriptor { struct spa_list link; int ref; @@ -195,12 +185,10 @@ struct impl { struct spa_filter_graph filter_graph; struct spa_hook_list hooks; - struct spa_support support[16]; - uint32_t n_support; - struct spa_log *log; struct spa_cpu *cpu; struct spa_fga_dsp *dsp; + struct spa_plugin_loader *loader; struct graph graph; @@ -212,7 +200,6 @@ struct impl { uint32_t out_ports; struct spa_list plugin_list; - struct spa_list plugin_func_list; float *silence_data; float *discard_data; @@ -731,40 +718,18 @@ static uint32_t count_array(struct spa_json *json) static void plugin_unref(struct plugin *hndl) { + struct impl *impl = hndl->impl; + if (--hndl->ref > 0) return; - spa_fga_plugin_free(hndl->plugin); - spa_list_remove(&hndl->link); + spa_handle_clear(hndl->hndl); + if (hndl->hndl) + spa_plugin_loader_unload(impl->loader, hndl->hndl); free(hndl); } - -static struct plugin_func *add_plugin_func(struct impl *impl, const char *type, - spa_filter_graph_audio_plugin_load_func_t *func, void *hndl) -{ - struct plugin_func *pl; - - pl = calloc(1, sizeof(*pl)); - if (pl == NULL) - return NULL; - - snprintf(pl->type, sizeof(pl->type), "%s", type); - pl->func = func; - pl->hndl = hndl; - spa_list_append(&impl->plugin_func_list, &pl->link); - return pl; -} - -static void free_plugin_func(struct plugin_func *pl) -{ - spa_list_remove(&pl->link); - if (pl->hndl) - dlclose(pl->hndl); - free(pl); -} - static inline const char *split_walk(const char *str, const char *delimiter, size_t * len, const char **state) { const char *s = *state ? *state : str; @@ -779,106 +744,71 @@ static inline const char *split_walk(const char *str, const char *delimiter, siz return s; } -static spa_filter_graph_audio_plugin_load_func_t *find_plugin_func(struct impl *impl, const char *type) -{ - spa_filter_graph_audio_plugin_load_func_t *func = NULL; - void *hndl = NULL; - int res; - struct plugin_func *pl; - char module[PATH_MAX]; - const char *module_dir; - const char *state = NULL, *p; - size_t len; - - spa_list_for_each(pl, &impl->plugin_func_list, link) { - if (spa_streq(pl->type, type)) - return pl->func; - } - module_dir = getenv("PIPEWIRE_MODULE_DIR"); - if (module_dir == NULL) - module_dir = MODULEDIR; - spa_log_debug(impl->log, "moduledir set to: %s", module_dir); - - while ((p = split_walk(module_dir, ":", &len, &state))) { - if ((res = spa_scnprintf(module, sizeof(module), - "%.*s/libpipewire-filter-graph-plugin-%s.so", - (int)len, p, type)) <= 0) - continue; - - hndl = dlopen(module, RTLD_NOW | RTLD_LOCAL); - if (hndl != NULL) - break; - - spa_log_debug(impl->log, "open plugin module %s failed: %s", module, dlerror()); - } - if (hndl == NULL) { - errno = ENOENT; - return NULL; - } - func = dlsym(hndl, SPA_FILTER_GRAPH_AUDIO_PLUGIN_LOAD_FUNC_NAME); - if (func != NULL) { - spa_log_info(impl->log, "opened plugin module %s", module); - pl = add_plugin_func(impl, type, func, hndl); - if (pl == NULL) - goto error_close; - } else { - errno = ENOSYS; - spa_log_error(impl->log, "%s is not a filter graph plugin: %m", module); - goto error_close; - } - return func; - -error_close: - dlclose(hndl); - return NULL; -} - static struct plugin *plugin_load(struct impl *impl, const char *type, const char *path) { - struct spa_fga_plugin *pl = NULL; - struct plugin *hndl; - spa_filter_graph_audio_plugin_load_func_t *plugin_func; + struct spa_handle *hndl = NULL; + struct plugin *plugin; + char module[PATH_MAX]; + char factory_name[256], dsp_ptr[256]; + void *iface; + int res; - spa_list_for_each(hndl, &impl->plugin_list, link) { - if (spa_streq(hndl->type, type) && - spa_streq(hndl->path, path)) { - hndl->ref++; - return hndl; + spa_list_for_each(plugin, &impl->plugin_list, link) { + if (spa_streq(plugin->type, type) && + spa_streq(plugin->path, path)) { + plugin->ref++; + return plugin; } } - plugin_func = find_plugin_func(impl, type); - if (plugin_func == NULL) { + spa_scnprintf(module, sizeof(module), + //"filter-graph/libspa-filter-graph-plugin-%s", type); + "libspa-filter-graph-plugin-%s", type); + spa_scnprintf(factory_name, sizeof(factory_name), + "filter.graph.plugin.%s", type); + spa_scnprintf(dsp_ptr, sizeof(dsp_ptr), + "pointer:%p", impl->dsp); + + hndl = spa_plugin_loader_load(impl->loader, factory_name, + &SPA_DICT_ITEMS( + SPA_DICT_ITEM(SPA_KEY_LIBRARY_NAME, module), + SPA_DICT_ITEM("filter.graph.path", path), + SPA_DICT_ITEM("filter.graph.audio.dsp", dsp_ptr))); + + if (hndl == NULL) { + res = -errno; spa_log_error(impl->log, "can't load plugin type '%s': %m", type); - pl = NULL; - } else { - char quantum[64]; - snprintf(quantum, sizeof(quantum), "%d", impl->quantum_limit); - pl = plugin_func(impl->support, impl->n_support, path, - &SPA_DICT_ITEMS( - SPA_DICT_ITEM("clock.quantum-limit", quantum) - )); - } - if (pl == NULL) goto exit; + } + if ((res = spa_handle_get_interface(hndl, SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioPlugin, &iface)) < 0) { + spa_log_error(impl->log, "can't find iface '%s': %s", + SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioPlugin, spa_strerror(res)); + goto exit; + } + plugin = calloc(1, sizeof(*plugin)); + if (!plugin) { + res = -errno; + goto exit; + } - hndl = calloc(1, sizeof(*hndl)); - if (!hndl) - return NULL; - - hndl->ref = 1; - snprintf(hndl->type, sizeof(hndl->type), "%s", type); - snprintf(hndl->path, sizeof(hndl->path), "%s", path); + plugin->ref = 1; + snprintf(plugin->type, sizeof(plugin->type), "%s", type); + snprintf(plugin->path, sizeof(plugin->path), "%s", path); spa_log_info(impl->log, "successfully opened '%s':'%s'", type, path); - hndl->plugin = pl; + plugin->impl = impl; + plugin->hndl = hndl; + plugin->plugin = iface; - spa_list_init(&hndl->descriptor_list); - spa_list_append(&impl->plugin_list, &hndl->link); + spa_list_init(&plugin->descriptor_list); + spa_list_append(&impl->plugin_list, &plugin->link); - return hndl; + return plugin; exit: + if (hndl) + spa_plugin_loader_unload(impl->loader, hndl); + errno = -res; return NULL; } @@ -902,17 +832,17 @@ static void descriptor_unref(struct descriptor *desc) static struct descriptor *descriptor_load(struct impl *impl, const char *type, const char *plugin, const char *label) { - struct plugin *hndl; + struct plugin *pl; struct descriptor *desc; const struct spa_fga_descriptor *d; uint32_t i, n_input, n_output, n_control, n_notify; unsigned long p; int res; - if ((hndl = plugin_load(impl, type, plugin)) == NULL) + if ((pl = plugin_load(impl, type, plugin)) == NULL) return NULL; - spa_list_for_each(desc, &hndl->descriptor_list, link) { + spa_list_for_each(desc, &pl->descriptor_list, link) { if (spa_streq(desc->label, label)) { desc->ref++; @@ -923,17 +853,17 @@ static struct descriptor *descriptor_load(struct impl *impl, const char *type, * so we need to unref handle here since we're merely reusing * thedescriptor, not creating a new one */ - plugin_unref(hndl); + plugin_unref(pl); return desc; } } desc = calloc(1, sizeof(*desc)); desc->ref = 1; - desc->plugin = hndl; + desc->plugin = pl; spa_list_init(&desc->link); - if ((d = spa_fga_plugin_make_desc(hndl->plugin, label)) == NULL) { + if ((d = spa_fga_plugin_make_desc(pl->plugin, label)) == NULL) { spa_log_error(impl->log, "cannot find label %s", label); res = -ENOENT; goto exit; @@ -1000,7 +930,7 @@ static struct descriptor *descriptor_load(struct impl *impl, const char *type, spa_log_info(impl->log, "control %d ('%s') default to %f", i, d->ports[p].name, desc->default_control[i]); } - spa_list_append(&hndl->descriptor_list, &desc->link); + spa_list_append(&pl->descriptor_list, &desc->link); return desc; @@ -2045,11 +1975,11 @@ static int impl_get_interface(struct spa_handle *handle, const char *type, void static int impl_clear(struct spa_handle *handle) { struct impl *impl = (struct impl *) handle; - struct plugin_func *pl; graph_free(&impl->graph); - spa_list_consume(pl, &impl->plugin_func_list, link) - free_plugin_func(pl); + + if (impl->dsp) + spa_fga_dsp_free(impl->dsp); free(impl->silence_data); free(impl->discard_data); @@ -2083,21 +2013,14 @@ impl_init(const struct spa_handle_factory *factory, impl->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); spa_log_topic_init(impl->log, &log_topic); - for (i = 0; i < SPA_MIN(n_support, 15u); i++) - impl->support[i] = support[i]; - impl->n_support = n_support; - impl->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU); impl->max_align = spa_cpu_get_max_align(impl->cpu); impl->dsp = spa_fga_dsp_new(impl->cpu ? spa_cpu_get_flags(impl->cpu) : 0); - impl->support[impl->n_support++] = SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioDSP, impl->dsp); + + impl->loader = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_PluginLoader); spa_list_init(&impl->plugin_list); - spa_list_init(&impl->plugin_func_list); - - add_plugin_func(impl, "builtin", load_builtin_plugin, NULL); - add_plugin_func(impl, "ladspa", load_ladspa_plugin, NULL); for (i = 0; info && i < info->n_items; i++) { const char *k = info->items[i].key; @@ -2174,3 +2097,20 @@ struct spa_handle_factory spa_filter_graph_factory = { impl_init, impl_enum_interface_info, }; + +SPA_EXPORT +int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) +{ + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(index != NULL, -EINVAL); + + switch (*index) { + case 0: + *factory = &spa_filter_graph_factory; + break; + default: + return 0; + } + (*index)++; + return 1; +} diff --git a/src/modules/module-filter-chain/ladspa_plugin.c b/src/modules/module-filter-chain/ladspa_plugin.c index f6fe5085f..122091708 100644 --- a/src/modules/module-filter-chain/ladspa_plugin.c +++ b/src/modules/module-filter-chain/ladspa_plugin.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -17,11 +18,12 @@ #include "ladspa.h" struct plugin { + struct spa_handle handle; struct spa_fga_plugin plugin; struct spa_log *log; - void *handle; + void *hndl; LADSPA_Descriptor_Function desc_func; }; @@ -165,64 +167,41 @@ static const struct spa_fga_descriptor *ladspa_plugin_make_desc(void *plugin, co return &desc->desc; } -static void ladspa_plugin_free(void *plugin) -{ - struct plugin *p = (struct plugin *)plugin; - if (p->handle) - dlclose(p->handle); - free(p); -} - static struct spa_fga_plugin_methods impl_plugin = { SPA_VERSION_FGA_PLUGIN_METHODS, .make_desc = ladspa_plugin_make_desc, - .free = ladspa_plugin_free }; -static struct spa_fga_plugin *ladspa_handle_load_by_path(struct spa_log *log, const char *path) +static int ladspa_handle_load_by_path(struct plugin *impl, const char *path) { - struct plugin *p; int res; void *handle = NULL; LADSPA_Descriptor_Function desc_func; handle = dlopen(path, RTLD_NOW); if (handle == NULL) { - spa_log_debug(log, "failed to open '%s': %s", path, dlerror()); + spa_log_debug(impl->log, "failed to open '%s': %s", path, dlerror()); res = -ENOENT; goto exit; } - spa_log_info(log, "successfully opened '%s'", path); + spa_log_info(impl->log, "successfully opened '%s'", path); desc_func = (LADSPA_Descriptor_Function) dlsym(handle, "ladspa_descriptor"); if (desc_func == NULL) { - spa_log_warn(log, "cannot find descriptor function in '%s': %s", path, dlerror()); + spa_log_warn(impl->log, "cannot find descriptor function in '%s': %s", path, dlerror()); res = -ENOSYS; goto exit; } - p = calloc(1, sizeof(*p)); - if (!p) { - res = -errno; - goto exit; - } - p->log = log; - p->handle = handle; - p->desc_func = desc_func; - - p->plugin.iface = SPA_INTERFACE_INIT( - SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioPlugin, - SPA_VERSION_FGA_PLUGIN, - &impl_plugin, p); - - return &p->plugin; + impl->hndl = handle; + impl->desc_func = desc_func; + return 0; exit: if (handle) dlclose(handle); - errno = -res; - return NULL; + return res; } static inline const char *split_walk(const char *str, const char *delimiter, size_t * len, const char **state) @@ -239,17 +218,13 @@ static inline const char *split_walk(const char *str, const char *delimiter, siz return s; } -struct spa_fga_plugin *load_ladspa_plugin(const struct spa_support *support, uint32_t n_support, - const char *plugin, const struct spa_dict *info) +static int load_ladspa_plugin(struct plugin *impl, const char *path) { - struct spa_fga_plugin *pl = NULL; - struct spa_log *log; + int res = -ENOENT; - log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); - - if (plugin[0] != '/') { + if (path[0] != '/') { const char *search_dirs, *p, *state = NULL; - char path[PATH_MAX]; + char filename[PATH_MAX]; size_t len; search_dirs = getenv("LADSPA_PATH"); @@ -261,29 +236,150 @@ struct spa_fga_plugin *load_ladspa_plugin(const struct spa_support *support, uin * is never called, which can only happen if the supplied * LADSPA_PATH contains too long paths */ - errno = ENAMETOOLONG; + res = -ENAMETOOLONG; while ((p = split_walk(search_dirs, ":", &len, &state))) { - int pathlen; + int namelen; - if (len >= sizeof(path)) + if (len >= sizeof(filename)) continue; - pathlen = snprintf(path, sizeof(path), "%.*s/%s.so", (int) len, p, plugin); - if (pathlen < 0 || (size_t) pathlen >= sizeof(path)) + namelen = snprintf(filename, sizeof(filename), "%.*s/%s.so", (int) len, p, path); + if (namelen < 0 || (size_t) namelen >= sizeof(filename)) continue; - pl = ladspa_handle_load_by_path(log, path); - if (pl != NULL) + res = ladspa_handle_load_by_path(impl, filename); + if (res >= 0) break; } } else { - pl = ladspa_handle_load_by_path(log, plugin); + res = ladspa_handle_load_by_path(impl, path); + } + return res; +} + +static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface) +{ + struct plugin *impl; + + spa_return_val_if_fail(handle != NULL, -EINVAL); + spa_return_val_if_fail(interface != NULL, -EINVAL); + + impl = (struct plugin *) handle; + + if (spa_streq(type, SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioPlugin)) + *interface = &impl->plugin; + else + return -ENOENT; + + return 0; +} + +static int impl_clear(struct spa_handle *handle) +{ + struct plugin *impl = (struct plugin *)handle; + if (impl->hndl) + dlclose(impl->hndl); + impl->hndl = NULL; + return 0; +} + +static size_t +impl_get_size(const struct spa_handle_factory *factory, + const struct spa_dict *params) +{ + return sizeof(struct plugin); +} + +static int +impl_init(const struct spa_handle_factory *factory, + struct spa_handle *handle, + const struct spa_dict *info, + const struct spa_support *support, + uint32_t n_support) +{ + struct plugin *impl; + uint32_t i; + int res; + const char *path = NULL; + + handle->get_interface = impl_get_interface; + handle->clear = impl_clear; + + impl = (struct plugin *) handle; + + impl->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); + + for (i = 0; info && i < info->n_items; i++) { + const char *k = info->items[i].key; + const char *s = info->items[i].value; + if (spa_streq(k, "filter.graph.path")) + path = s; + } + if (path == NULL) + return -EINVAL; + + if ((res = load_ladspa_plugin(impl, path)) < 0) { + spa_log_error(impl->log, "failed to load plugin '%s': %s", + path, spa_strerror(res)); + return res; } - if (pl == NULL) - spa_log_error(log, "failed to load plugin '%s': %s", plugin, strerror(errno)); + impl->plugin.iface = SPA_INTERFACE_INIT( + SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioPlugin, + SPA_VERSION_FGA_PLUGIN, + &impl_plugin, impl); - return pl; + return 0; +} + +static const struct spa_interface_info impl_interfaces[] = { + { SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioPlugin }, +}; + +static int +impl_enum_interface_info(const struct spa_handle_factory *factory, + const struct spa_interface_info **info, + uint32_t *index) +{ + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(info != NULL, -EINVAL); + spa_return_val_if_fail(index != NULL, -EINVAL); + + switch (*index) { + case 0: + *info = &impl_interfaces[*index]; + break; + default: + return 0; + } + (*index)++; + return 1; +} + +struct spa_handle_factory spa_fga_plugin_ladspa_factory = { + SPA_VERSION_HANDLE_FACTORY, + "filter.graph.plugin.ladspa", + NULL, + impl_get_size, + impl_init, + impl_enum_interface_info, +}; + +SPA_EXPORT +int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) +{ + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(index != NULL, -EINVAL); + + switch (*index) { + case 0: + *factory = &spa_fga_plugin_ladspa_factory; + break; + default: + return 0; + } + (*index)++; + return 1; } diff --git a/src/modules/module-filter-chain/lv2_plugin.c b/src/modules/module-filter-chain/lv2_plugin.c index 6948eab9e..a2af22d6a 100644 --- a/src/modules/module-filter-chain/lv2_plugin.c +++ b/src/modules/module-filter-chain/lv2_plugin.c @@ -88,10 +88,6 @@ struct context { int ref; LilvWorld *world; - struct spa_log *log; - struct spa_loop *data_loop; - struct spa_loop *main_loop; - LilvNode *lv2_InputPort; LilvNode *lv2_OutputPort; LilvNode *lv2_AudioPort; @@ -145,7 +141,7 @@ static const LV2_Feature buf_size_features[3] = { { LV2_BUF_SIZE__boundedBlockLength, NULL }, }; -static struct context *context_new(const struct spa_support *support, uint32_t n_support) +static struct context *context_new(void) { struct context *c; @@ -186,20 +182,16 @@ static struct context *context_new(const struct spa_support *support, uint32_t n c->atom_Int = context_map(c, LV2_ATOM__Int); c->atom_Float = context_map(c, LV2_ATOM__Float); - c->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); - c->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop); - c->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop); - return c; error: context_free(c); return NULL; } -static struct context *context_ref(const struct spa_support *support, uint32_t n_support) +static struct context *context_ref(void) { if (_context == NULL) { - _context = context_new(support, n_support); + _context = context_new(); if (_context == NULL) return NULL; } @@ -216,7 +208,13 @@ static void context_unref(struct context *context) } struct plugin { + struct spa_handle handle; struct spa_fga_plugin plugin; + + struct spa_log *log; + struct spa_loop *data_loop; + struct spa_loop *main_loop; + struct context *c; const LilvPlugin *p; }; @@ -228,6 +226,8 @@ struct descriptor { struct instance { struct descriptor *desc; + struct plugin *p; + LilvInstance *instance; LV2_Worker_Schedule work_schedule; LV2_Feature work_schedule_feature; @@ -256,8 +256,7 @@ static LV2_Worker_Status work_respond(LV2_Worker_Respond_Handle handle, uint32_t size, const void *data) { struct instance *i = (struct instance*)handle; - struct context *c = i->desc->p->c; - spa_loop_invoke(c->data_loop, do_respond, 1, data, size, false, i); + spa_loop_invoke(i->p->data_loop, do_respond, 1, data, size, false, i); return LV2_WORKER_SUCCESS; } @@ -275,8 +274,7 @@ static LV2_Worker_Status work_schedule(LV2_Worker_Schedule_Handle handle, uint32_t size, const void *data) { struct instance *i = (struct instance*)handle; - struct context *c = i->desc->p->c; - spa_loop_invoke(c->main_loop, do_schedule, 1, data, size, false, i); + spa_loop_invoke(i->p->main_loop, do_schedule, 1, data, size, false, i); return LV2_WORKER_SUCCESS; } @@ -299,6 +297,7 @@ static void *lv2_instantiate(const struct spa_fga_plugin *plugin, const struct s i->block_length = 1024; i->desc = d; + i->p = p; i->features[n_features++] = &c->map_feature; i->features[n_features++] = &c->unmap_feature; i->features[n_features++] = &buf_size_features[0]; @@ -453,68 +452,153 @@ static const struct spa_fga_descriptor *lv2_plugin_make_desc(void *plugin, const return &desc->desc; } -static void lv2_plugin_free(void *plugin) -{ - struct plugin *p = (struct plugin *)plugin; - context_unref(p->c); - free(p); -} - static struct spa_fga_plugin_methods impl_plugin = { SPA_VERSION_FGA_PLUGIN_METHODS, .make_desc = lv2_plugin_make_desc, - .free = lv2_plugin_free +}; + +static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface) +{ + struct plugin *impl; + + spa_return_val_if_fail(handle != NULL, -EINVAL); + spa_return_val_if_fail(interface != NULL, -EINVAL); + + impl = (struct plugin *) handle; + + if (spa_streq(type, SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioPlugin)) + *interface = &impl->plugin; + else + return -ENOENT; + + return 0; +} + +static int impl_clear(struct spa_handle *handle) +{ + struct plugin *p = (struct plugin *)handle; + context_unref(p->c); + return 0; +} + +static size_t +impl_get_size(const struct spa_handle_factory *factory, + const struct spa_dict *params) +{ + return sizeof(struct plugin); +} + +static int +impl_init(const struct spa_handle_factory *factory, + struct spa_handle *handle, + const struct spa_dict *info, + const struct spa_support *support, + uint32_t n_support) +{ + struct plugin *impl; + uint32_t i; + int res; + const char *path = NULL; + const LilvPlugins *plugins; + LilvNode *uri; + + handle->get_interface = impl_get_interface; + handle->clear = impl_clear; + + impl = (struct plugin *) handle; + impl->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); + impl->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop); + impl->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop); + + for (i = 0; info && i < info->n_items; i++) { + const char *k = info->items[i].key; + const char *s = info->items[i].value; + if (spa_streq(k, "filter.graph.path")) + path = s; + } + if (path == NULL) + return -EINVAL; + + impl->c = context_ref(); + if (impl->c == NULL) + return -EINVAL; + + uri = lilv_new_uri(impl->c->world, path); + if (uri == NULL) { + spa_log_warn(impl->log, "invalid URI %s", path); + res = -EINVAL; + goto error_cleanup; + } + + plugins = lilv_world_get_all_plugins(impl->c->world); + impl->p = lilv_plugins_get_by_uri(plugins, uri); + lilv_node_free(uri); + + if (impl->p == NULL) { + spa_log_warn(impl->log, "can't load plugin %s", path); + res = -EINVAL; + goto error_cleanup; + } + impl->plugin.iface = SPA_INTERFACE_INIT( + SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioPlugin, + SPA_VERSION_FGA_PLUGIN, + &impl_plugin, impl); + + return 0; + +error_cleanup: + if (impl->c) + context_unref(impl->c); + return res; +} + + +static const struct spa_interface_info impl_interfaces[] = { + { SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioPlugin }, +}; + +static int +impl_enum_interface_info(const struct spa_handle_factory *factory, + const struct spa_interface_info **info, + uint32_t *index) +{ + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(info != NULL, -EINVAL); + spa_return_val_if_fail(index != NULL, -EINVAL); + + switch (*index) { + case 0: + *info = &impl_interfaces[*index]; + break; + default: + return 0; + } + (*index)++; + return 1; +} + +static struct spa_handle_factory spa_fga_plugin_lv2_factory = { + SPA_VERSION_HANDLE_FACTORY, + "filter.graph.plugin.lv2", + NULL, + impl_get_size, + impl_init, + impl_enum_interface_info, }; SPA_EXPORT -struct spa_fga_plugin *spa_filter_graph_audio_plugin_load(const struct spa_support *support, uint32_t n_support, - const char *plugin_uri, const struct spa_dict *info) +int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) { - struct context *c; - const LilvPlugins *plugins; - const LilvPlugin *plugin; - LilvNode *uri; - int res; - struct plugin *p; + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(index != NULL, -EINVAL); - c = context_ref(support, n_support); - if (c == NULL) - return NULL; - - uri = lilv_new_uri(c->world, plugin_uri); - if (uri == NULL) { - spa_log_warn(c->log, "invalid URI %s", plugin_uri); - res = -EINVAL; - goto error_unref; + switch (*index) { + case 0: + *factory = &spa_fga_plugin_lv2_factory; + break; + default: + return 0; } - - plugins = lilv_world_get_all_plugins(c->world); - plugin = lilv_plugins_get_by_uri(plugins, uri); - lilv_node_free(uri); - - if (plugin == NULL) { - spa_log_warn(c->log, "can't load plugin %s", plugin_uri); - res = -EINVAL; - goto error_unref; - } - - p = calloc(1, sizeof(*p)); - if (!p) { - res = -errno; - goto error_unref; - } - p->p = plugin; - p->c = c; - - p->plugin.iface = SPA_INTERFACE_INIT( - SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioPlugin, - SPA_VERSION_FGA_PLUGIN, - &impl_plugin, p); - - return &p->plugin; - -error_unref: - context_unref(c); - errno = -res; - return NULL; + (*index)++; + return 1; } diff --git a/src/modules/module-filter-chain/sofa_plugin.c b/src/modules/module-filter-chain/sofa_plugin.c index 70b556f71..de2367817 100644 --- a/src/modules/module-filter-chain/sofa_plugin.c +++ b/src/modules/module-filter-chain/sofa_plugin.c @@ -9,11 +9,11 @@ #include "audio-plugin.h" #include "convolver.h" #include "audio-dsp.h" -#include "pffft.h" #include struct plugin { + struct spa_handle handle; struct spa_fga_plugin plugin; struct spa_fga_dsp *dsp; @@ -43,8 +43,8 @@ struct spatializer_impl { static void * spatializer_instantiate(const struct spa_fga_plugin *plugin, const struct spa_fga_descriptor * Descriptor, unsigned long SampleRate, int index, const char *config) { + struct plugin *pl = SPA_CONTAINER_OF(plugin, struct plugin, plugin); struct spatializer_impl *impl; - struct plugin *pl = (struct plugin*) plugin; struct spa_json it[1]; const char *val; char key[256]; @@ -424,23 +424,53 @@ static const struct spa_fga_descriptor *sofa_plugin_make_desc(void *plugin, cons return NULL; } -static void sofa_plugin_free(void *plugin) -{ - struct plugin *impl = plugin; - free(impl); -} - static struct spa_fga_plugin_methods impl_plugin = { SPA_VERSION_FGA_PLUGIN_METHODS, .make_desc = sofa_plugin_make_desc, - .free = sofa_plugin_free }; -SPA_EXPORT -struct spa_fga_plugin *spa_filter_graph_audio_plugin_load(const struct spa_support *support, uint32_t n_support, - const char *plugin, const struct spa_dict *info) +static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface) { - struct plugin *impl = calloc(1, sizeof (struct plugin)); + struct plugin *impl; + + spa_return_val_if_fail(handle != NULL, -EINVAL); + spa_return_val_if_fail(interface != NULL, -EINVAL); + + impl = (struct plugin *) handle; + + if (spa_streq(type, SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioPlugin)) + *interface = &impl->plugin; + else + return -ENOENT; + + return 0; +} + +static int impl_clear(struct spa_handle *handle) +{ + return 0; +} + +static size_t +impl_get_size(const struct spa_handle_factory *factory, + const struct spa_dict *params) +{ + return sizeof(struct plugin); +} + +static int +impl_init(const struct spa_handle_factory *factory, + struct spa_handle *handle, + const struct spa_dict *info, + const struct spa_support *support, + uint32_t n_support) +{ + struct plugin *impl; + + handle->get_interface = impl_get_interface; + handle->clear = impl_clear; + + impl = (struct plugin *) handle; impl->plugin.iface = SPA_INTERFACE_INIT( SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioPlugin, @@ -449,17 +479,77 @@ struct spa_fga_plugin *spa_filter_graph_audio_plugin_load(const struct spa_suppo impl->quantum_limit = 8192u; + impl->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); + impl->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop); + impl->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop); + impl->dsp = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioDSP); + for (uint32_t i = 0; info && i < info->n_items; i++) { const char *k = info->items[i].key; const char *s = info->items[i].value; if (spa_streq(k, "clock.quantum-limit")) spa_atou32(s, &impl->quantum_limit, 0); + if (spa_streq(k, "filter.graph.audio.dsp")) + sscanf(s, "pointer:%p", &impl->dsp); } - impl->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop); - impl->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop); - impl->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); - impl->dsp = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioDSP); - pffft_select_cpu(impl->dsp->cpu_flags); - return (struct spa_fga_plugin *) impl; + if (impl->data_loop == NULL || impl->main_loop == NULL) { + spa_log_error(impl->log, "%p: could not find a data/main loop", impl); + return -EINVAL; + } + if (impl->dsp == NULL) { + spa_log_error(impl->log, "%p: could not find DSP functions", impl); + return -EINVAL; + } + return 0; +} + +static const struct spa_interface_info impl_interfaces[] = { + {SPA_TYPE_INTERFACE_FILTER_GRAPH_AudioPlugin,}, +}; + +static int +impl_enum_interface_info(const struct spa_handle_factory *factory, + const struct spa_interface_info **info, + uint32_t *index) +{ + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(info != NULL, -EINVAL); + spa_return_val_if_fail(index != NULL, -EINVAL); + + switch (*index) { + case 0: + *info = &impl_interfaces[*index]; + break; + default: + return 0; + } + (*index)++; + return 1; +} + +struct spa_handle_factory spa_fga_sofa_plugin_factory = { + SPA_VERSION_HANDLE_FACTORY, + "filter.graph.plugin.sofa", + NULL, + impl_get_size, + impl_init, + impl_enum_interface_info, +}; + +SPA_EXPORT +int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) +{ + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(index != NULL, -EINVAL); + + switch (*index) { + case 0: + *factory = &spa_fga_sofa_plugin_factory; + break; + default: + return 0; + } + (*index)++; + return 1; }