## The WirePlumber configuration context.spa-libs = { ## SPA factory name to library mappings ## Used to find SPA factory names. It maps a SPA factory name regular ## expression to a library name that should contain that factory. ## ## Syntax: ## = api.alsa.* = alsa/libspa-alsa api.bluez5.* = bluez5/libspa-bluez5 api.v4l2.* = v4l2/libspa-v4l2 api.libcamera.* = libcamera/libspa-libcamera audio.convert.* = audioconvert/libspa-audioconvert support.* = support/libspa-support } context.modules = [ ## PipeWire modules to load. ## These modules are loaded before a connection to pipewire is attempted. ## This section should be kept minimal and load only the modules that are ## necessary for the protocol to work. ## ## If ifexists is given, the module is ignored when it is not found. ## If nofail is given, module initialization failures are ignored. ## ## Syntax: ## { ## name = ## [ args = { = ... } ] ## [ flags = [ ifexists | nofail ] ] ## } # Uses RTKit to boost the data thread priority. Also allows clamping # of utilisation when using the Completely Fair Scheduler on Linux. { name = libpipewire-module-rt args = { nice.level = -11 # rt.prio = 88 # rt.time.soft = -1 # rt.time.hard = -1 # uclamp.min = 0 # uclamp.max = 1024 } flags = [ ifexists, nofail ] } ## The native communication protocol. { name = libpipewire-module-protocol-native } ## Support for metadata objects { name = libpipewire-module-metadata } ] wireplumber.profiles = { ## Syntax: ## = { ## inherits = [ other, profile, names ] # optional ## # optional is the default ## = [ required | optional | disabled ] ## ... ## } # The default profile main = { inherits = [ base ] metadata.sm-settings = required metadata.sm-objects = required policy.standard = required hardware.audio = required hardware.bluetooth = required hardware.video-capture = required } # Profile for running on a systemwide level main-systemwide = { inherits = [ main, mixin.systemwide-session ] } # Typical profile for embedded use cases, systemwide without maintaining state main-embedded = { inherits = [ main, mixin.systemwide-session, mixin.stateless ] } # Profile for video-only use cases (camera & screen sharing) video-only = { inherits = [ main ] hardware.audio = disabled hardware.bluetooth = disabled } ## ## Profiles for multi-instance setup ## policy = { inherits = [ base ] metadata.sm-settings = required metadata.sm-objects = required policy.standard = required } audio = { inherits = [ base ] hardware.audio = required } bluetooth = { inherits = [ base ] hardware.bluetooth = required } video-capture = { inherits = [ base ] hardware.video-capture = required } ## ## The following are not complete profiles, but blocks that can be inherited ## # The bare minimum that all instances should have by default base = { check.no-media-session = required support.settings = required support.log-settings = required } # Disable features that are meant only for user sessions mixin.systemwide-session = { support.reserve-device = disabled monitor.alsa.reserve-device = disabled support.portal-permissionstore = disabled script.client.access-portal = disabled support.logind = disabled monitor.bluez.seat-monitoring = disabled } # Disable storing/restoring runtime state information regarding # default nodes selection, profiles, routes and stream volume / properties # This makes sense for embedded systems that should always reboot to a default # state, not remembering any of the user's runtime changes mixin.stateless = { hooks.device.profile.state = disabled hooks.device.routes.state = disabled hooks.default-nodes.state = disabled hooks.stream.state = disabled } } wireplumber.components = [ ## WirePlumber components to load. ## These components are loaded after a connection to pipewire is established. ## type is mandatory; rest of the tags are optional ## ## Syntax: ## { ## name = ## type = ## arguments = { } ## ## # Feature that this component provides ## provides = ## ## # List of features that must be provided before this component is loaded ## requires = [ ] ## ## # List of features that would offer additional functionality if provided ## # but are not strictly required ## wants = [ ] ## } ## Check to avoid loading together with media-session { name = ensure-no-media-session, type = built-in provides = check.no-media-session } ## Makes a secondary connection to PipeWire for exporting objects { name = export-core, type = built-in provides = support.export-core } ## Enables creating local nodes that are exported to pipewire ## This is needed for LocalNode() / WpImplNode ## This should be used with the export-core to avoid protocol deadlocks, ## unless you know what you are doing { name = libpipewire-module-client-node, type = pw-module provides = pw.client-node wants = [ support.export-core ] } ## Enables creating local devices that are exported to pipewire ## This is needed for SpaDevice() / WpSpaDevice ## This should be used with the export-core to avoid protocol deadlocks, ## unless you know what you are doing { name = libpipewire-module-client-device, type = pw-module provides = pw.client-device wants = [ support.export-core ] } # Provides a node factory to create SPA nodes # You need this to use LocalNode("spa-node-factory", ...) { name = libpipewire-module-spa-node-factory, type = pw-module provides = pw.node-factory.spa requires = [ pw.client-node ] } ## Provides a node factory to create SPA nodes wrapped in an adapter ## You need this to use LocalNode("adapter", ...) { name = libpipewire-module-adapter, type = pw-module provides = pw.node-factory.adapter requires = [ pw.client-node ] } ## Provides the "sm-settings" metadata object { name = libwireplumber-module-settings, type = module arguments = { metadata.name = sm-settings } provides = metadata.sm-settings } ## Activates a global WpSettings instance, providing settings from ## the sm-settings metadata object. Note that this blocks and waits for the ## sm-settings metadata object to become available, so one instance must ## provide that, while others should only load this to access settings { name = settings-instance, type = built-in arguments = { metadata.name = sm-settings } provides = support.settings after = [ metadata.sm-settings ] } ## Log level settings { name = libwireplumber-module-log-settings, type = module provides = support.log-settings } ## The lua scripting engine { name = libwireplumber-module-lua-scripting, type = module provides = support.lua-scripting } ## Module listening for pipewire objects to push events { name = libwireplumber-module-standard-event-source, type = module provides = support.standard-event-source } ## The shared D-Bus connection { name = libwireplumber-module-dbus-connection, type = module provides = support.dbus } ## Module managing the portal permissions { name = libwireplumber-module-portal-permissionstore, type = module provides = support.portal-permissionstore requires = [ support.dbus ] } ## Needed for device reservation to work { name = libwireplumber-module-reserve-device, type = module provides = support.reserve-device requires = [ support.dbus ] } ## logind integration to enable certain functionality only on the active seat { name = libwireplumber-module-logind, type = module provides = support.logind } ## Session item factories { name = libwireplumber-module-si-node, type = module provides = si.node } { name = libwireplumber-module-si-audio-adapter, type = module provides = si.audio-adapter } { name = libwireplumber-module-si-standard-link, type = module provides = si.standard-link } ## API to access default nodes from scripts { name = libwireplumber-module-default-nodes-api, type = module provides = api.default-nodes } ## API to access mixer controls { name = libwireplumber-module-mixer-api, type = module provides = api.mixer } ## API to get notified about file changes { name = libwireplumber-module-file-monitor-api, type = module provides = api.file-monitor } ## Provide the "default" pw_metadata { name = metadata.lua, type = script/lua arguments = { metadata.name = default } provides = metadata.default } ## Provide the "filters" pw_metadata { name = metadata.lua, type = script/lua arguments = { metadata.name = filters } provides = metadata.filters } ## Provide the "sm-objects" pw_metadata, supporting dynamic loadable objects { name = sm-objects.lua, type = script/lua provides = metadata.sm-objects } ## Device monitors' optional features { type = virtual, provides = monitor.alsa.reserve-device, requires = [ support.reserve-device ] } { type = virtual, provides = monitor.alsa-midi.monitoring, requires = [ api.file-monitor ] } { type = virtual, provides = monitor.bluez.seat-monitoring, requires = [ support.logind ] } ## Device monitors { name = monitors/alsa.lua, type = script/lua provides = monitor.alsa requires = [ support.export-core, pw.client-device ] wants = [ monitor.alsa.reserve-device ] } { name = monitors/bluez.lua, type = script/lua provides = monitor.bluez requires = [ support.export-core, pw.client-device, pw.client-node, pw.node-factory.adapter ] wants = [ monitor.bluez.seat-monitoring ] } { name = monitors/bluez-midi.lua, type = script/lua provides = monitor.bluez-midi requires = [ support.export-core, pw.client-device, pw.client-node, pw.node-factory.spa ] wants = [ monitor.bluez.seat-monitoring ] } { name = monitors/alsa-midi.lua, type = script/lua provides = monitor.alsa-midi wants = [ monitor.alsa-midi.monitoring ] } ## v4l2 monitor { name = monitors/v4l2/name-device.lua, type = script/lua provides = hooks.monitor.v4l2-name-device } { name = monitors/v4l2/create-device.lua, type = script/lua provides = hooks.monitor.v4l2-create-device requires = [ support.export-core, pw.client-device, support.standard-event-source ] } { name = monitors/v4l2/name-node.lua, type = script/lua provides = hooks.monitor.v4l2-name-node } { name = monitors/v4l2/create-node.lua, type = script/lua provides = hooks.monitor.v4l2-create-node } { name = monitors/v4l2/enumerate-device.lua, type = script/lua provides = monitor.v4l2 requires = [ support.export-core, pw.client-device, support.standard-event-source, hooks.monitor.v4l2-create-device, hooks.monitor.v4l2-create-node ] wants = [ hooks.monitor.v4l2-name-device, hooks.monitor.v4l2-name-node ] } ## libcamera monitor { name = monitors/libcamera/name-device.lua, type = script/lua provides = hooks.monitor.libcamera-name-device } { name = monitors/libcamera/create-device.lua, type = script/lua provides = hooks.monitor.libcamera-create-device requires = [ support.export-core, pw.client-device, support.standard-event-source ] } { name = monitors/libcamera/name-node.lua, type = script/lua provides = hooks.monitor.libcamera-name-node } { name = monitors/libcamera/create-node.lua, type = script/lua provides = hooks.monitor.libcamera-create-node } { name = monitors/libcamera/enumerate-device.lua, type = script/lua provides = monitor.libcamera requires = [ support.export-core, pw.client-device, support.standard-event-source, hooks.monitor.libcamera-create-device, hooks.monitor.libcamera-create-node ] wants = [ hooks.monitor.libcamera-name-device, hooks.monitor.libcamera-name-node ] } ## Client access configuration hooks { name = client/access-default.lua, type = script/lua provides = script.client.access-default } { name = client/access-portal.lua, type = script/lua provides = script.client.access-portal requires = [ support.portal-permissionstore ] } { name = client/access-snap.lua, type = script/lua provides = script.client.access-snap } { type = virtual, provides = policy.client.access wants = [ script.client.access-default, script.client.access-portal, script.client.access-snap ] } ## Device profile selection hooks { name = device/select-profile.lua, type = script/lua provides = hooks.device.profile.select } { name = device/find-preferred-profile.lua, type = script/lua provides = hooks.device.profile.find-preferred } { name = device/find-best-profile.lua, type = script/lua provides = hooks.device.profile.find-best } { name = device/state-profile.lua, type = script/lua provides = hooks.device.profile.state } { name = device/apply-profile.lua, type = script/lua provides = hooks.device.profile.apply } { name = device/autoswitch-bluetooth-profile.lua, type = script/lua provides = hooks.device.profile.autoswitch-bluetooth } { type = virtual, provides = policy.device.profile requires = [ hooks.device.profile.select, hooks.device.profile.autoswitch-bluetooth, hooks.device.profile.apply ] wants = [ hooks.device.profile.find-best, hooks.device.profile.find-preferred, hooks.device.profile.state ] } # Device route selection hooks { name = device/select-routes.lua, type = script/lua provides = hooks.device.routes.select } { name = device/find-best-routes.lua, type = script/lua provides = hooks.device.routes.find-best } { name = device/state-routes.lua, type = script/lua provides = hooks.device.routes.state } { name = device/apply-routes.lua, type = script/lua provides = hooks.device.routes.apply } { type = virtual, provides = policy.device.routes requires = [ hooks.device.routes.select, hooks.device.routes.apply ] wants = [ hooks.device.routes.find-best, hooks.device.routes.state ] } ## Default nodes selection hooks { name = default-nodes/rescan.lua, type = script/lua provides = hooks.default-nodes.rescan } { name = default-nodes/find-selected-default-node.lua, type = script/lua provides = hooks.default-nodes.find-selected requires = [ metadata.default ] } { name = default-nodes/find-best-default-node.lua, type = script/lua provides = hooks.default-nodes.find-best } { name = default-nodes/state-default-nodes.lua, type = script/lua provides = hooks.default-nodes.state requires = [ metadata.default ] } { name = default-nodes/apply-default-node.lua, type = script/lua, provides = hooks.default-nodes.apply requires = [ metadata.default ] } { type = virtual, provides = policy.default-nodes requires = [ hooks.default-nodes.rescan, hooks.default-nodes.apply ] wants = [ hooks.default-nodes.find-selected, hooks.default-nodes.find-best, hooks.default-nodes.state ] } ## Node configuration hooks { name = node/create-item.lua, type = script/lua provides = hooks.node.create-session-item requires = [ si.audio-adapter, si.node ] } { name = node/suspend-node.lua, type = script/lua provides = hooks.node.suspend } { name = node/state-stream.lua, type = script/lua provides = hooks.stream.state } { name = node/filter-forward-format.lua, type = script/lua provides = hooks.filter.forward-format } { type = virtual, provides = policy.node requires = [ hooks.node.create-session-item ] wants = [ hooks.node.suspend hooks.stream.state hooks.filter.forward-format ] } { name = node/software-dsp.lua, type = script/lua provides = node.software-dsp } ## Linking hooks { name = linking/rescan.lua, type = script/lua provides = hooks.linking.rescan } { name = linking/find-media-role-target.lua, type = script/lua provides = hooks.linking.target.find-media-role } { name = linking/find-defined-target.lua, type = script/lua provides = hooks.linking.target.find-defined } { name = linking/find-filter-target.lua, type = script/lua provides = hooks.linking.target.find-filter requires = [ metadata.filters ] } { name = linking/find-default-target.lua, type = script/lua provides = hooks.linking.target.find-default requires = [ api.default-nodes ] } { name = linking/find-best-target.lua, type = script/lua provides = hooks.linking.target.find-best requires = [ metadata.filters ] } { name = linking/get-filter-from-target.lua, type = script/lua provides = hooks.linking.target.get-filter-from requires = [ metadata.filters ] } { name = linking/prepare-link.lua, type = script/lua provides = hooks.linking.target.prepare-link requires = [ api.default-nodes ] } { name = linking/link-target.lua, type = script/lua provides = hooks.linking.target.link requires = [ si.standard-link ] } { type = virtual, provides = policy.linking.standard requires = [ hooks.linking.rescan, hooks.linking.target.prepare-link, hooks.linking.target.link ] wants = [ hooks.linking.target.find-media-role, hooks.linking.target.find-defined, hooks.linking.target.find-filter, hooks.linking.target.find-default, hooks.linking.target.find-best, hooks.linking.target.get-filter-from ] } ## Linking: Role-based priority system { name = linking/rescan-media-role-links.lua, type = script/lua provides = hooks.linking.role-based.rescan requires = [ api.mixer ] } { type = virtual, provides = policy.linking.role-based requires = [ policy.linking.standard, hooks.linking.role-based.rescan ] } ## Standard policy definition { type = virtual, provides = policy.standard requires = [ policy.client.access policy.device.profile policy.device.routes policy.default-nodes policy.linking.standard policy.linking.role-based policy.node support.standard-event-source ] } ## Load targets { type = virtual, provides = hardware.audio wants = [ monitor.alsa, monitor.alsa-midi ] } { type = virtual, provides = hardware.bluetooth wants = [ monitor.bluez, monitor.bluez-midi ] } { type = virtual, provides = hardware.video-capture wants = [ monitor.v4l2, monitor.libcamera ] } ] wireplumber.components.rules = [ ## Rules to apply on top of wireplumber.components ## Syntax: ## { ## matches = [ ## { ## [ = ... ] ## } ## ... ## ] ## actions = { ## = { ## [ = ... ] ## } ## ... ## } ## } { matches = [ { type = "script/lua" } ] actions = { merge = { requires = [ support.lua-scripting ] } } } { matches = [ { provides = "~hooks.*" name = "!~monitors/.*" } ] actions = { merge = { before = [ support.standard-event-source ] } } } { matches = [ { provides = "~monitor.*" } ] actions = { merge = { after = [ support.standard-event-source ] } } } ] wireplumber.settings.schema = { ## Bluetooth bluetooth.use-persistent-storage = { description = "Whether to use persistent BT storage or not" type = "bool" default = true } bluetooth.autoswitch-to-headset-profile = { description = "Whether to autoswitch to BT headset profile or not" type = "bool" default = true } ## Device device.restore-profile = { description = "Whether to restore device profile or not" type = "bool" default = true } device.restore-routes = { description = "Whether to restore device routes or not" type = "bool" default = true } device.routes.default-sink-volume = { description = "The default volume for sink devices" type = "float" default = 0.064 min = 0.0 max = 1.0 } device.routes.default-source-volume = { description = "The default volume for source devices" type = "float" default = 1.0 min = 0.0 max = 1.0 } ## Linking linking.role-based.duck-level = { description = "The volume level to apply when ducking (= reducing volume for a higher priority stream to be audible) in the role-based linking policy" type = "float" default = 0.3 min = 0.0 max = 1.0 } linking.allow-moving-streams = { description = "Whether to allow metadata to move streams at runtime or not" type = "bool" default = true } linking.follow-default-target = { description = "Whether to allow streams follow the default device or not" type = "bool" default = true } ## Monitor monitor.camera-discovery-timeout = { description = "The camera discovery timeout in milliseconds" type = "int" default = 1000 min = 0 max = 60000 } ## Node node.features.audio.no-dsp = { description = "Whether to never convert audio to F32 format or not" type = "bool" default = false } node.features.audio.monitor-ports = { description = "Whether to enable monitor ports on audio nodes or not" type = "bool" default = true } node.features.audio.control-port = { description = "Whether to enable control ports on audio nodes or not" type = "bool" default = false } node.stream.restore-props = { description = "Whether to restore properties on stream nodes or not" type = "bool" default = true } node.stream.restore-target = { description = "Whether to restore target on stream nodes or not" type = "bool" default = true } node.stream.default-playback-volume = { description = "The default volume for playback nodes" type = "float" default = 1.0 min = 0.0 max = 1.0 } node.stream.default-capture-volume = { description = "The default volume for capture nodes" type = "float" default = 1.0 min = 0.0 max = 1.0 } node.stream.default-media-role = { description = "A media.role to assign on streams that have none specified" type = "string" default = null } node.filter.forward-format = { description = "Whether to forward format on filter nodes or not" type = "bool" default = false } node.restore-default-targets = { description = "Whether to restore default targets or not" type = "bool" default = true } }