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.
This commit is contained in:
Wim Taymans 2026-05-08 09:57:52 +02:00
parent ddab12a5aa
commit b3257ae425
7 changed files with 72 additions and 17 deletions

View file

@ -288,6 +288,12 @@ Default video rate denominator
@PAR@ pipewire.conf library.name.system = support/libspa-support @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. 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 @PAR@ pipewire.conf link.max-buffers = 64
The maximum number of buffers to negotiate between nodes. Note that version < 3 clients 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 can only support 16 buffers. More buffers is almost always worse than less, latency

View file

@ -13,6 +13,7 @@ context.properties = {
#library.name.system = support/libspa-support #library.name.system = support/libspa-support
#context.data-loop.library.name.system = support/libspa-support #context.data-loop.library.name.system = support/libspa-support
#support.dbus = true #support.dbus = true
library.use-fallback = false
#link.max-buffers = 64 #link.max-buffers = 64
link.max-buffers = 16 # version < 3 clients can't handle more link.max-buffers = 16 # version < 3 clients can't handle more
#mem.warn-mlock = false #mem.warn-mlock = false
@ -70,10 +71,28 @@ context.spa-libs = {
# regular expression to a library name that should contain # regular expression to a library name that should contain
# that factory. # that factory.
# #
support.* = support/libspa-support
audio.convert.* = audioconvert/libspa-audioconvert audio.convert.* = audioconvert/libspa-audioconvert
audio.adapt = audioconvert/libspa-audioconvert audio.adapt = audioconvert/libspa-audioconvert
api.alsa.* = alsa/libspa-alsa 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 = [ context.modules = [

View file

@ -15,17 +15,29 @@ context.properties = {
#mem.mlock-all = false #mem.mlock-all = false
#log.level = 2 #log.level = 2
#rlimit.nofile = -1 #rlimit.nofile = -1
#library.use-fallback = true
#default.clock.quantum-limit = 8192 #default.clock.quantum-limit = 8192
} }
context.spa-libs = { context.spa-libs = {
audio.convert.* = audioconvert/libspa-audioconvert
support.* = support/libspa-support 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 # because the pulse server allows dynamic loading of streams and modules
# inside the server, we must be careful with the filter-graph. Only allow # inside the server, we must be careful with the filter-graph.
# LADSPA filters. #filter.graph.plugin.ffmpeg = filter-graph/libspa-filter-graph-plugin-ffmpeg
filter.graph.plugin.pipe = blocked #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 = [ context.modules = [

View file

@ -12,6 +12,7 @@ context.properties = {
## Configure properties in the system. ## Configure properties in the system.
#library.name.system = support/libspa-support #library.name.system = support/libspa-support
#context.data-loop.library.name.system = support/libspa-support #context.data-loop.library.name.system = support/libspa-support
#library.use-fallback = true
#support.dbus = true #support.dbus = true
#link.max-buffers = 64 #link.max-buffers = 64
link.max-buffers = 16 # version < 3 clients can't handle more 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 # regular expression to a library name that should contain
# that factory. # that factory.
# #
support.* = support/libspa-support
audio.convert.* = audioconvert/libspa-audioconvert audio.convert.* = audioconvert/libspa-audioconvert
avb.* = avb/libspa-avb audio.adapt = audioconvert/libspa-audioconvert
api.alsa.* = alsa/libspa-alsa api.alsa.* = alsa/libspa-alsa
api.v4l2.* = v4l2/libspa-v4l2 api.v4l2.* = v4l2/libspa-v4l2
api.libcamera.* = libcamera/libspa-libcamera api.libcamera.* = libcamera/libspa-libcamera
api.bluez5.* = bluez5/libspa-bluez5 api.bluez5.* = bluez5/libspa-bluez5
api.vulkan.* = vulkan/libspa-vulkan #api.vulkan.* = vulkan/libspa-vulkan
api.jack.* = jack/libspa-jack
support.* = support/libspa-support
video.convert.* = videoconvert/libspa-videoconvert 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 #videotestsrc = videotestsrc/libspa-videotestsrc
#audiotestsrc = audiotestsrc/libspa-audiotestsrc #audiotestsrc = audiotestsrc/libspa-audiotestsrc
} }

View file

@ -152,7 +152,6 @@ static struct spa_handle *impl_plugin_loader_load(void *object, const char *fact
errno = EINVAL; errno = EINVAL;
return NULL; return NULL;
} }
return pw_context_load_spa_handle(&impl->this, factory_name, info); 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 char *factory_name,
const struct spa_dict *info) const struct spa_dict *info)
{ {
const char *lib; const char *lib, *fallback_lib = NULL;
const struct spa_support *support; const struct spa_support *support;
uint32_t n_support; uint32_t n_support;
struct spa_handle *handle; 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); lib = pw_context_find_spa_lib(context, factory_name);
if (lib == NULL && info != NULL) if (lib == NULL && context->settings.use_fallback)
lib = spa_dict_lookup(info, SPA_KEY_LIBRARY_NAME); lib = fallback_lib;
if (lib == NULL || spa_streq(lib, "blocked")) { if (lib == NULL || spa_streq(lib, "blocked")) {
errno = lib ? EPERM : ENOENT; errno = lib ? EPERM : ENOENT;
pw_log_warn("%p: no library for %s: %m", pw_log_warn("%p: no library for %s (fallback: %s): %m",
context, factory_name); context, factory_name, fallback_lib);
return NULL; return NULL;
} }

View file

@ -52,6 +52,7 @@ struct settings {
unsigned int clock_power_of_two_quantum:1; unsigned int clock_power_of_two_quantum:1;
unsigned int check_quantum:1; unsigned int check_quantum:1;
unsigned int check_rate:1; unsigned int check_rate:1;
unsigned int use_fallback:1;
#define CLOCK_RATE_UPDATE_MODE_HARD 0 #define CLOCK_RATE_UPDATE_MODE_HARD 0
#define CLOCK_RATE_UPDATE_MODE_SOFT 1 #define CLOCK_RATE_UPDATE_MODE_SOFT 1
int clock_rate_update_mode; int clock_rate_update_mode;

View file

@ -37,6 +37,7 @@
#define DEFAULT_MEM_ALLOW_MLOCK true #define DEFAULT_MEM_ALLOW_MLOCK true
#define DEFAULT_CHECK_QUANTUM false #define DEFAULT_CHECK_QUANTUM false
#define DEFAULT_CHECK_RATE false #define DEFAULT_CHECK_RATE false
#define DEFAULT_USE_FALLBACK true
struct impl { struct impl {
struct pw_context *context; 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_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->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); d->link_max_buffers = SPA_MAX(d->link_max_buffers, 1u);