From b3257ae425aa629cdf8c5af93652dc8872f790c0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 8 May 2026 09:57:52 +0200 Subject: [PATCH] context: add library.use-fallback option Normally, when loading a plugin feature, often a library.name property is given as well. If the feature to load is not explicitly listed in context.spa-libs, the library.name is used a fallback library. Add an option to ignore this library.name and only use the context.spa-libs entries. This makes it possible to only load explicitly listed features in the config file and makes it possible to lock down what plugins can be loaded. Set the option to true by default for now, which keeps the existing behaviour of using the fallback library. Add some more entries to the context.spa-libs in case the option is switched off to make things work. Set the option to false for the minimal.conf. --- doc/dox/config/pipewire.conf.5.md | 6 ++++++ src/daemon/minimal.conf.in | 21 ++++++++++++++++++++- src/daemon/pipewire-pulse.conf.in | 20 ++++++++++++++++---- src/daemon/pipewire.conf.in | 23 ++++++++++++++++++----- src/pipewire/context.c | 16 +++++++++------- src/pipewire/private.h | 1 + src/pipewire/settings.c | 2 ++ 7 files changed, 72 insertions(+), 17 deletions(-) diff --git a/doc/dox/config/pipewire.conf.5.md b/doc/dox/config/pipewire.conf.5.md index 12d2ea855..a1b3564aa 100644 --- a/doc/dox/config/pipewire.conf.5.md +++ b/doc/dox/config/pipewire.conf.5.md @@ -288,6 +288,12 @@ Default video rate denominator @PAR@ pipewire.conf library.name.system = support/libspa-support The name of the shared library to use for the system functions for the main thread. +@PAR@ pipewire.conf library.use-fallback = true +When a plugin feature is not listed in context.spa-libs, a predefined fallback +plugin location is used by default. If this option is set to false, only plugin +features explicitly listed in context.spa-libs will be loadable. This can be used +to lock down what plugins that can be loaded. + @PAR@ pipewire.conf link.max-buffers = 64 The maximum number of buffers to negotiate between nodes. Note that version < 3 clients can only support 16 buffers. More buffers is almost always worse than less, latency diff --git a/src/daemon/minimal.conf.in b/src/daemon/minimal.conf.in index 7ab93e92b..89cbb017f 100644 --- a/src/daemon/minimal.conf.in +++ b/src/daemon/minimal.conf.in @@ -13,6 +13,7 @@ context.properties = { #library.name.system = support/libspa-support #context.data-loop.library.name.system = support/libspa-support #support.dbus = true + library.use-fallback = false #link.max-buffers = 64 link.max-buffers = 16 # version < 3 clients can't handle more #mem.warn-mlock = false @@ -70,10 +71,28 @@ context.spa-libs = { # regular expression to a library name that should contain # that factory. # + support.* = support/libspa-support audio.convert.* = audioconvert/libspa-audioconvert audio.adapt = audioconvert/libspa-audioconvert api.alsa.* = alsa/libspa-alsa - support.* = support/libspa-support + #api.v4l2.* = v4l2/libspa-v4l2 + #api.libcamera.* = libcamera/libspa-libcamera + #api.bluez5.* = bluez5/libspa-bluez5 + #api.vulkan.* = vulkan/libspa-vulkan + #video.convert.* = videoconvert/libspa-videoconvert + #video.adapt = videoconvert/libspa-videoconvert + audio.mixer.* = audiomixer/libspa-audiomixer + control.mixer = control/libspa-mixer + #audio.aec = aec/libspa-aec-webrtc + #filter.graph.plugin.ffmpeg = filter-graph/libspa-filter-graph-plugin-ffmpeg + #filter.graph.plugin.onnx = filter-graph/libspa-filter-graph-plugin-onnx + #filter.graph.plugin.pipe = blocked + #filter.graph.plugin.ebur128 = filter-graph/libspa-filter-graph-plugin-ebur128 + #filter.graph.plugin.sofa = filter-graph/libspa-filter-graph-plugin-sofa + #filter.graph.plugin.ladspa = filter-graph/libspa-filter-graph-plugin-ladspa + #filter.graph.plugin.lv2 = filter-graph/libspa-filter-graph-plugin-lv2 + #filter.graph.plugin.builtin = filter-graph/libspa-filter-graph-plugin-builtin + #filter.graph = filter-graph/libspa-filter-graph } context.modules = [ diff --git a/src/daemon/pipewire-pulse.conf.in b/src/daemon/pipewire-pulse.conf.in index 5fedd36bf..0b9a31b4d 100644 --- a/src/daemon/pipewire-pulse.conf.in +++ b/src/daemon/pipewire-pulse.conf.in @@ -15,17 +15,29 @@ context.properties = { #mem.mlock-all = false #log.level = 2 #rlimit.nofile = -1 + #library.use-fallback = true #default.clock.quantum-limit = 8192 } context.spa-libs = { - audio.convert.* = audioconvert/libspa-audioconvert support.* = support/libspa-support + audio.convert.* = audioconvert/libspa-audioconvert + audio.adapt = audioconvert/libspa-audioconvert + audio.mixer = audiomixer/libspa-audiomixer + audio.aec = aec/libspa-aec-webrtc # because the pulse server allows dynamic loading of streams and modules - # inside the server, we must be careful with the filter-graph. Only allow - # LADSPA filters. - filter.graph.plugin.pipe = blocked + # inside the server, we must be careful with the filter-graph. + #filter.graph.plugin.ffmpeg = filter-graph/libspa-filter-graph-plugin-ffmpeg + #filter.graph.plugin.onnx = filter-graph/libspa-filter-graph-plugin-onnx + #filter.graph.plugin.pipe = filter-graph/libspa-filter-graph-plugin-pipe + filter.graph.plugin.pipe = blocked + #filter.graph.plugin.ebur128 = filter-graph/libspa-filter-graph-plugin-ebur128 + #filter.graph.plugin.sofa = filter-graph/libspa-filter-graph-plugin-sofa + filter.graph.plugin.ladspa = filter-graph/libspa-filter-graph-plugin-ladspa + #filter.graph.plugin.lv2 = filter-graph/libspa-filter-graph-plugin-lv2 + filter.graph.plugin.builtin = filter-graph/libspa-filter-graph-plugin-builtin + filter.graph = filter-graph/libspa-filter-graph } context.modules = [ diff --git a/src/daemon/pipewire.conf.in b/src/daemon/pipewire.conf.in index a9142cede..720872aaa 100644 --- a/src/daemon/pipewire.conf.in +++ b/src/daemon/pipewire.conf.in @@ -12,6 +12,7 @@ context.properties = { ## Configure properties in the system. #library.name.system = support/libspa-support #context.data-loop.library.name.system = support/libspa-support + #library.use-fallback = true #support.dbus = true #link.max-buffers = 64 link.max-buffers = 16 # version < 3 clients can't handle more @@ -75,17 +76,29 @@ context.spa-libs = { # regular expression to a library name that should contain # that factory. # + support.* = support/libspa-support audio.convert.* = audioconvert/libspa-audioconvert - avb.* = avb/libspa-avb + audio.adapt = audioconvert/libspa-audioconvert api.alsa.* = alsa/libspa-alsa api.v4l2.* = v4l2/libspa-v4l2 api.libcamera.* = libcamera/libspa-libcamera api.bluez5.* = bluez5/libspa-bluez5 - api.vulkan.* = vulkan/libspa-vulkan - api.jack.* = jack/libspa-jack - support.* = support/libspa-support + #api.vulkan.* = vulkan/libspa-vulkan video.convert.* = videoconvert/libspa-videoconvert - #filter.graph = filter-graph/libspa-filter-graph + video.adapt = videoconvert/libspa-videoconvert + audio.mixer.* = audiomixer/libspa-audiomixer + control.mixer = control/libspa-mixer + audio.aec = aec/libspa-aec-webrtc + #filter.graph.plugin.ffmpeg = filter-graph/libspa-filter-graph-plugin-ffmpeg + filter.graph.plugin.onnx = filter-graph/libspa-filter-graph-plugin-onnx + #filter.graph.plugin.pipe = filter-graph/libspa-filter-graph-plugin-pipe + filter.graph.plugin.pipe = blocked + filter.graph.plugin.ebur128 = filter-graph/libspa-filter-graph-plugin-ebur128 + filter.graph.plugin.sofa = filter-graph/libspa-filter-graph-plugin-sofa + filter.graph.plugin.ladspa = filter-graph/libspa-filter-graph-plugin-ladspa + filter.graph.plugin.lv2 = filter-graph/libspa-filter-graph-plugin-lv2 + filter.graph.plugin.builtin = filter-graph/libspa-filter-graph-plugin-builtin + filter.graph = filter-graph/libspa-filter-graph #videotestsrc = videotestsrc/libspa-videotestsrc #audiotestsrc = audiotestsrc/libspa-audiotestsrc } diff --git a/src/pipewire/context.c b/src/pipewire/context.c index eb89ca752..c4ecaa004 100644 --- a/src/pipewire/context.c +++ b/src/pipewire/context.c @@ -152,7 +152,6 @@ static struct spa_handle *impl_plugin_loader_load(void *object, const char *fact errno = EINVAL; return NULL; } - return pw_context_load_spa_handle(&impl->this, factory_name, info); } @@ -1057,20 +1056,23 @@ struct spa_handle *pw_context_load_spa_handle(struct pw_context *context, const char *factory_name, const struct spa_dict *info) { - const char *lib; + const char *lib, *fallback_lib = NULL; const struct spa_support *support; uint32_t n_support; struct spa_handle *handle; - pw_log_debug("%p: load factory %s", context, factory_name); + if (info != NULL) + fallback_lib = spa_dict_lookup(info, SPA_KEY_LIBRARY_NAME); + + pw_log_info("%p: load factory %s fallback:%s", context, factory_name, fallback_lib); lib = pw_context_find_spa_lib(context, factory_name); - if (lib == NULL && info != NULL) - lib = spa_dict_lookup(info, SPA_KEY_LIBRARY_NAME); + if (lib == NULL && context->settings.use_fallback) + lib = fallback_lib; if (lib == NULL || spa_streq(lib, "blocked")) { errno = lib ? EPERM : ENOENT; - pw_log_warn("%p: no library for %s: %m", - context, factory_name); + pw_log_warn("%p: no library for %s (fallback: %s): %m", + context, factory_name, fallback_lib); return NULL; } diff --git a/src/pipewire/private.h b/src/pipewire/private.h index dd81178ff..fa562b320 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -52,6 +52,7 @@ struct settings { unsigned int clock_power_of_two_quantum:1; unsigned int check_quantum:1; unsigned int check_rate:1; + unsigned int use_fallback:1; #define CLOCK_RATE_UPDATE_MODE_HARD 0 #define CLOCK_RATE_UPDATE_MODE_SOFT 1 int clock_rate_update_mode; diff --git a/src/pipewire/settings.c b/src/pipewire/settings.c index 74d4cfcb2..944fee30c 100644 --- a/src/pipewire/settings.c +++ b/src/pipewire/settings.c @@ -37,6 +37,7 @@ #define DEFAULT_MEM_ALLOW_MLOCK true #define DEFAULT_CHECK_QUANTUM false #define DEFAULT_CHECK_RATE false +#define DEFAULT_USE_FALLBACK true struct impl { struct pw_context *context; @@ -227,6 +228,7 @@ void pw_settings_init(struct pw_context *this) d->check_quantum = get_default_bool(p, "settings.check-quantum", DEFAULT_CHECK_QUANTUM); d->check_rate = get_default_bool(p, "settings.check-rate", DEFAULT_CHECK_RATE); + d->use_fallback = get_default_bool(p, "library.use-fallback", DEFAULT_USE_FALLBACK); d->link_max_buffers = SPA_MAX(d->link_max_buffers, 1u);