diff --git a/meson.build b/meson.build index c65b01c7f..8b6a0a781 100644 --- a/meson.build +++ b/meson.build @@ -295,7 +295,6 @@ summary({'sndfile': sndfile_dep.found()}, bool_yn: true, section: 'pw-cat/pw-pla cdata.set('HAVE_SNDFILE', sndfile_dep.found()) libmysofa_dep = dependency('libmysofa', required : get_option('libmysofa')) summary({'libmysofa': libmysofa_dep.found()}, bool_yn: true, section: 'filter-chain') -cdata.set('HAVE_LIBMYSOFA', libmysofa_dep.found()) pulseaudio_dep = dependency('libpulse', required : get_option('libpulse')) summary({'libpulse': pulseaudio_dep.found()}, bool_yn: true, section: 'Streaming between daemons') avahi_dep = dependency('avahi-client', required : get_option('avahi')) @@ -403,7 +402,6 @@ summary({'OpenSSL (for raop-sink)': openssl_lib.found()}, bool_yn: true) lilv_lib = dependency('lilv-0', required: get_option('lv2')) summary({'lilv (for lv2 plugins)': lilv_lib.found()}, bool_yn: true) -cdata.set('HAVE_LILV', lilv_lib.found()) libffado_dep = dependency('libffado', required: get_option('libffado')) summary({'ffado': libffado_dep.found()}, bool_yn: true) diff --git a/src/modules/meson.build b/src/modules/meson.build index 3bf2233e3..3b9cacf13 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -117,20 +117,12 @@ filter_chain_sources = [ 'module-filter-chain/biquad.c', 'module-filter-chain/ladspa_plugin.c', 'module-filter-chain/builtin_plugin.c', - 'module-filter-chain/sofa_plugin.c', 'module-filter-chain/convolver.c' ] filter_chain_dependencies = [ - mathlib, dl_lib, pipewire_dep, sndfile_dep, audioconvert_dep, libmysofa_dep + mathlib, dl_lib, pipewire_dep, sndfile_dep, audioconvert_dep ] -if lilv_lib.found() - filter_chain_sources += [ - 'module-filter-chain/lv2_plugin.c' - ] - filter_chain_dependencies += [ lilv_lib ] -endif - pipewire_module_filter_chain = shared_library('pipewire-module-filter-chain', filter_chain_sources, include_directories : [configinc], @@ -141,6 +133,31 @@ pipewire_module_filter_chain = shared_library('pipewire-module-filter-chain', dependencies : filter_chain_dependencies, ) +if libmysofa_dep.found() +pipewire_module_filter_chain_sofa = shared_library('pipewire-module-filter-chain-sofa', + [ 'module-filter-chain/sofa_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, + dependencies : [ filter_chain_dependencies, libmysofa_dep ] +) +endif + +if lilv_lib.found() +pipewire_module_filter_chain_lv2 = shared_library('pipewire-module-filter-chain-lv2', + [ 'module-filter-chain/lv2_plugin.c' ], + include_directories : [configinc], + install : true, + install_dir : modules_install_dir, + install_rpath: modules_install_dir, + dependencies : [ filter_chain_dependencies, lilv_lib ] +) +endif + + pipewire_module_combine_stream = shared_library('pipewire-module-combine-stream', [ 'module-combine-stream.c' ], include_directories : [configinc], diff --git a/src/modules/module-filter-chain.c b/src/modules/module-filter-chain.c index bcc38635d..6e1db3ad7 100644 --- a/src/modules/module-filter-chain.c +++ b/src/modules/module-filter-chain.c @@ -523,6 +523,11 @@ static const struct spa_dict_item module_props[] = { static float silence_data[MAX_SAMPLES]; static float discard_data[MAX_SAMPLES]; +struct fc_plugin *load_ladspa_plugin(const struct spa_support *support, uint32_t n_support, + struct dsp_ops *dsp, const char *path, const char *config); +struct fc_plugin *load_builtin_plugin(const struct spa_support *support, uint32_t n_support, + struct dsp_ops *dsp, const char *path, const char *config); + struct plugin { struct spa_list link; int ref; @@ -533,6 +538,13 @@ struct plugin { struct spa_list descriptor_list; }; +struct plugin_func { + struct spa_list link; + char type[256]; + fc_plugin_load_func *func; + void *hndl; +}; + struct descriptor { struct spa_list link; int ref; @@ -647,6 +659,7 @@ struct impl { struct dsp_ops dsp; struct spa_list plugin_list; + struct spa_list plugin_func_list; struct pw_properties *capture_props; struct pw_stream *capture; @@ -1348,12 +1361,92 @@ static void plugin_unref(struct plugin *hndl) free(hndl); } + +static struct plugin_func *add_plugin_func(struct impl *impl, const char *type, + fc_plugin_load_func *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 fc_plugin_load_func *find_plugin_func(struct impl *impl, const char *type) +{ + fc_plugin_load_func *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; + pw_log_debug("moduledir set to: %s", module_dir); + + while ((p = pw_split_walk(module_dir, ":", &len, &state))) { + if ((res = spa_scnprintf(module, sizeof(module), + "%.*s/libpipewire-module-filter-chain-%s.so", + (int)len, p, type)) <= 0) + continue; + + hndl = dlopen(module, RTLD_NOW | RTLD_LOCAL); + if (hndl != NULL) + break; + + pw_log_debug("open plugin module %s failed: %s", module, dlerror()); + } + if (hndl == NULL) { + errno = ENOENT; + return NULL; + } + func = dlsym(hndl, FC_PLUGIN_LOAD_FUNC); + if (func != NULL) { + pw_log_info("opened plugin module %s", module); + pl = add_plugin_func(impl, type, func, hndl); + if (pl == NULL) + goto error_close; + } else { + errno = ENOSYS; + pw_log_error("%s is not a filter chain 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 fc_plugin *pl = NULL; struct plugin *hndl; const struct spa_support *support; uint32_t n_support; + fc_plugin_load_func *plugin_func; spa_list_for_each(hndl, &impl->plugin_list, link) { if (spa_streq(hndl->type, type) && @@ -1364,27 +1457,12 @@ static struct plugin *plugin_load(struct impl *impl, const char *type, const cha } support = pw_context_get_support(impl->context, &n_support); - if (spa_streq(type, "builtin")) { - pl = load_builtin_plugin(support, n_support, &impl->dsp, path, NULL); - } - else if (spa_streq(type, "sofa")) { - pl = load_sofa_plugin(support, n_support, &impl->dsp, path, NULL); - } - else if (spa_streq(type, "ladspa")) { - pl = load_ladspa_plugin(support, n_support, &impl->dsp, path, NULL); - } - else if (spa_streq(type, "lv2")) { -#ifdef HAVE_LILV - pl = load_lv2_plugin(support, n_support, &impl->dsp, path, NULL); -#else - pw_log_error("filter-chain is compiled without lv2 support"); + plugin_func = find_plugin_func(impl, type); + if (plugin_func == NULL) { + pw_log_error("can't load plugin type '%s': %m", type); pl = NULL; - errno = ENOTSUP; -#endif } else { - pw_log_error("invalid plugin type '%s'", type); - pl = NULL; - errno = EINVAL; + pl = plugin_func(support, n_support, &impl->dsp, path, NULL); } if (pl == NULL) goto exit; @@ -1397,7 +1475,7 @@ static struct plugin *plugin_load(struct impl *impl, const char *type, const cha snprintf(hndl->type, sizeof(hndl->type), "%s", type); snprintf(hndl->path, sizeof(hndl->path), "%s", path); - pw_log_info("successfully opened '%s'", path); + pw_log_info("successfully opened '%s':'%s'", type, path); hndl->plugin = pl; @@ -2374,6 +2452,8 @@ static const struct pw_proxy_events core_proxy_events = { static void impl_destroy(struct impl *impl) { + struct plugin_func *pl; + /* disconnect both streams before destroying any of them */ if (impl->capture) pw_stream_disconnect(impl->capture); @@ -2391,6 +2471,8 @@ static void impl_destroy(struct impl *impl) pw_properties_free(impl->capture_props); pw_properties_free(impl->playback_props); graph_free(&impl->graph); + spa_list_consume(pl, &impl->plugin_func_list, link) + free_plugin_func(pl); free(impl); } @@ -2502,6 +2584,10 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) impl->graph.impl = impl; 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); support = pw_context_get_support(impl->context, &n_support); diff --git a/src/modules/module-filter-chain/builtin_plugin.c b/src/modules/module-filter-chain/builtin_plugin.c index 672faa185..7ff0cca9b 100644 --- a/src/modules/module-filter-chain/builtin_plugin.c +++ b/src/modules/module-filter-chain/builtin_plugin.c @@ -10,6 +10,7 @@ #include #endif #include +#include #include #include diff --git a/src/modules/module-filter-chain/ladspa_plugin.c b/src/modules/module-filter-chain/ladspa_plugin.c index da7980992..a2e579344 100644 --- a/src/modules/module-filter-chain/ladspa_plugin.c +++ b/src/modules/module-filter-chain/ladspa_plugin.c @@ -6,6 +6,7 @@ #include #include +#include #include #include diff --git a/src/modules/module-filter-chain/lv2_plugin.c b/src/modules/module-filter-chain/lv2_plugin.c index 5a58db9da..3f036ceaf 100644 --- a/src/modules/module-filter-chain/lv2_plugin.c +++ b/src/modules/module-filter-chain/lv2_plugin.c @@ -451,7 +451,8 @@ static void lv2_unload(struct fc_plugin *plugin) free(p); } -struct fc_plugin *load_lv2_plugin(const struct spa_support *support, uint32_t n_support, +SPA_EXPORT +struct fc_plugin *pipewire__filter_chain_plugin_load(const struct spa_support *support, uint32_t n_support, struct dsp_ops *ops, const char *plugin_uri, const char *config) { struct context *c; diff --git a/src/modules/module-filter-chain/plugin.h b/src/modules/module-filter-chain/plugin.h index 66bf0fe76..5955740af 100644 --- a/src/modules/module-filter-chain/plugin.h +++ b/src/modules/module-filter-chain/plugin.h @@ -7,14 +7,8 @@ #include #include -#include -#include -#include #include -#include -#include -#include #include "dsp-ops.h" @@ -83,13 +77,10 @@ static inline void fc_descriptor_free(const struct fc_descriptor *desc) desc->free(desc); } -struct fc_plugin *load_ladspa_plugin(const struct spa_support *support, uint32_t n_support, - struct dsp_ops *dsp, const char *path, const char *config); -struct fc_plugin *load_lv2_plugin(const struct spa_support *support, uint32_t n_support, - struct dsp_ops *dsp, const char *path, const char *config); -struct fc_plugin *load_builtin_plugin(const struct spa_support *support, uint32_t n_support, - struct dsp_ops *dsp, const char *path, const char *config); -struct fc_plugin *load_sofa_plugin(const struct spa_support *support, uint32_t n_support, +#define FC_PLUGIN_LOAD_FUNC "pipewire__filter_chain_plugin_load" + +typedef struct fc_plugin *(fc_plugin_load_func)(const struct spa_support *support, uint32_t n_support, struct dsp_ops *dsp, const char *path, const char *config); + #endif /* PLUGIN_H */ diff --git a/src/modules/module-filter-chain/sofa_plugin.c b/src/modules/module-filter-chain/sofa_plugin.c index c403db341..eff68aa05 100644 --- a/src/modules/module-filter-chain/sofa_plugin.c +++ b/src/modules/module-filter-chain/sofa_plugin.c @@ -1,19 +1,20 @@ #include "config.h" +#include + #include #include #include + #include "plugin.h" #include "convolver.h" #include "dsp-ops.h" #include "pffft.h" -#ifdef HAVE_LIBMYSOFA #include #define MAX_SAMPLES 8192u -#endif static struct dsp_ops *dsp_ops; static struct spa_loop *data_loop; @@ -25,9 +26,7 @@ struct spatializer_impl { int n_samples, blocksize, tailsize; float *tmp[2]; -#ifdef HAVE_LIBMYSOFA struct MYSOFA_EASY *sofa; -#endif unsigned int interpolate:1; struct convolver *l_conv[3]; struct convolver *r_conv[3]; @@ -36,7 +35,6 @@ struct spatializer_impl { static void * spatializer_instantiate(const struct fc_descriptor * Descriptor, unsigned long SampleRate, int index, const char *config) { -#ifdef HAVE_LIBMYSOFA struct spatializer_impl *impl; struct spa_json it[2]; const char *val; @@ -115,14 +113,8 @@ error: mysofa_close_cached(impl->sofa); free(impl); return NULL; -#else - pw_log_error("libmysofa is required for spatializer, but disabled at compile time"); - errno = EINVAL; - return NULL; -#endif } -#ifdef HAVE_LIBMYSOFA static int do_switch(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data) @@ -205,11 +197,9 @@ do_free(struct spa_loop *loop, bool async, uint32_t seq, const void *data, convolver_free(fd->item[1]); return 0; } -#endif static void spatializer_run(void * Instance, unsigned long SampleCount) { -#ifdef HAVE_LIBMYSOFA struct spatializer_impl *impl = Instance; if (impl->interpolate) { @@ -239,7 +229,6 @@ static void spatializer_run(void * Instance, unsigned long SampleCount) convolver_run(impl->l_conv[0], impl->port[2], impl->port[0], SampleCount); convolver_run(impl->r_conv[0], impl->port[2], impl->port[1], SampleCount); } -#endif } static void spatializer_connect_port(void * Instance, unsigned long Port, @@ -261,10 +250,8 @@ static void spatializer_cleanup(void * Instance) if (impl->r_conv[i]) convolver_free(impl->r_conv[i]); } -#ifdef HAVE_LIBMYSOFA if (impl->sofa) mysofa_close_cached(impl->sofa); -#endif free(impl->tmp[0]); free(impl->tmp[1]); @@ -273,10 +260,8 @@ static void spatializer_cleanup(void * Instance) static void spatializer_control_changed(void * Instance) { -#ifdef HAVE_LIBMYSOFA pw_log_info("control changed"); spatializer_reload(Instance); -#endif } static void spatializer_deactivate(void * Instance) @@ -361,7 +346,8 @@ static struct fc_plugin builtin_plugin = { .make_desc = sofa_make_desc }; -struct fc_plugin *load_sofa_plugin(const struct spa_support *support, uint32_t n_support, +SPA_EXPORT +struct fc_plugin *pipewire__filter_chain_plugin_load(const struct spa_support *support, uint32_t n_support, struct dsp_ops *dsp, const char *plugin, const char *config) { dsp_ops = dsp; @@ -372,4 +358,3 @@ struct fc_plugin *load_sofa_plugin(const struct spa_support *support, uint32_t n return &builtin_plugin; } -