Commit c7ff629f authored by George Kiagiadakis's avatar George Kiagiadakis
Browse files

config: add an example of split-instance configuration

This configuration allows splitting wireplumber into multiple instances.
The "main" instance takes care of loading and managing devices
The "policy" instance does all the linking and implements endpoints
The "bluetooth" instance runs the bluetooth devices & nodes

Test with (in separate terminals):
./wp-uninstalled.sh -c config-split -- wireplumber -c main.conf
./wp-uninstalled.sh -c config-split -- wireplumber -c policy.conf
./wp-uninstalled.sh -c config-split -- wireplumber -c bluetooth.conf
parent 3b144fa9
# WirePlumber daemon context configuration #
context.properties = {
## Properties to configure the PipeWire context and some modules
application.name = "WirePlumber Bluetooth"
log.level = 2
wireplumber.script-engine = lua-scripting
wireplumber.export-core = false
#mem.mlock-all = false
#support.dbus = true
}
context.spa-libs = {
#<factory-name regex> = <library-name>
#
# Used to find spa factory names. It maps an spa factory name
# regular expression to a library name that should contain
# that factory.
#
api.bluez5.* = bluez5/libspa-bluez5
audio.convert.* = audioconvert/libspa-audioconvert
support.* = support/libspa-support
}
context.modules = [
#{ name = <module-name>
# [ args = { <key> = <value> ... } ]
# [ flags = [ [ ifexists ] [ nofail ] ]
#}
#
# PipeWire modules to load.
# If ifexists is given, the module is ignored when it is not found.
# If nofail is given, module initialization failures are ignored.
#
# The native communication protocol.
{ name = libpipewire-module-protocol-native }
# Allows creating nodes that run in the context of the
# client. Is used by all clients that want to provide
# data to PipeWire.
{ name = libpipewire-module-client-node }
# Allows creating devices that run in the context of the
# client. Is used by the session manager.
{ name = libpipewire-module-client-device }
# Makes a factory for wrapping nodes in an adapter with a
# converter and resampler.
{ name = libpipewire-module-adapter }
# Allows applications to create metadata objects. It creates
# a factory for Metadata objects.
{ name = libpipewire-module-metadata }
# Provides factories to make session manager objects.
{ name = libpipewire-module-session-manager }
]
wireplumber.components = [
#{ name = <component-name>, type = <component-type> }
#
# WirePlumber components to load
#
# The lua scripting engine
{ name = libwireplumber-module-lua-scripting, type = module }
# The lua configuration file
# Other components are loaded from there
{ name = bluetooth.lua, type = config/lua }
]
../common/00-functions.lua
\ No newline at end of file
bluez_monitor = {}
bluez_monitor.properties = {}
bluez_monitor.rules = {}
function bluez_monitor.enable()
load_monitor("bluez", {
properties = bluez_monitor.properties,
rules = bluez_monitor.rules,
})
end
bluez_monitor.properties = {
--["bluez5.sbc-xq-support"] = true,
-- Enabled headset roles (default: [ hsp_hs hfp_ag ]), this
-- property only applies to native backend. Currently some headsets
-- (Sony WH-1000XM3) are not working with both hsp_ag and hfp_ag
-- enabled, disable either hsp_ag or hfp_ag to work around it.
--
-- Supported headset roles: hsp_hs (HSP Headset),
-- hsp_ag (HSP Audio Gateway),
-- hfp_hf (HFP Hands-Free),
-- hfp_ag (HFP Audio Gateway)
--["bluez5.headset-roles"] = "[ hsp_hs hsp_ag hfp_hf hfp_ag ]",
-- Enabled A2DP codecs (default: all).
--["bluez5.codecs"] = "[ sbc aac ldac aptx aptx_hd ]",
}
bluez_monitor.rules = {
-- An array of matches/actions to evaluate.
{
-- Rules for matching a device or node. It is an array of
-- properties that all need to match the regexp. If any of the
-- matches work, the actions are executed for the object.
matches = {
{
-- This matches all cards.
{ "device.name", "matches", "bluez_card.*" },
},
},
-- Apply properties on the matched object.
apply_properties = {
-- Autoconnect device profiles, disabled by default
-- if the property is not specified.
["bluez5.reconnect-profiles"] = "[ hfp_hf hsp_hs a2dp_sink ]",
-- MSBC is not expected to work on all headset + adapter combinations.
--["bluez5.msbc-support"] = false,
-- LDAC encoding quality
-- Available values: auto (Adaptive Bitrate, default)
-- hq (High Quality, 990/909kbps)
-- sq (Standard Quality, 660/606kbps)
-- mq (Mobile use Quality, 330/303kbps)
--["bluez5.a2dp.ldac.quality"] = "auto",
},
},
{
matches = {
{
-- Matches all sources.
{ "node.name", "matches", "bluez_input.*" },
},
{
-- Matches all sinks.
{ "node.name", "matches", "bluez_output.*" },
},
},
apply_properties = {
--["node.nick"] = "My Node",
--["priority.driver"] = 100,
--["priority.session"] = 100,
--["node.pause-on-idle"] = false,
--["resample.quality"] = 4,
--["channelmix.normalize"] = false,
--["channelmix.mix-lfe"] = false,
},
},
}
components = {}
function load_module(m, a)
if not components[m] then
components[m] = { "libwireplumber-module-" .. m, type = "module", args = a }
end
end
function load_pw_module(m)
if not components[m] then
components[m] = { "libpipewire-module-" .. m, type = "pw_module" }
end
end
function load_script(s, a)
if not components[s] then
components[s] = { s, type = "script/lua", args = a }
end
end
function load_monitor(s, a)
load_script("monitors/" .. s .. ".lua", a)
end
function load_access(s, a)
load_script("access/access-" .. s .. ".lua", a)
end
# WirePlumber daemon context configuration #
context.properties = {
## Properties to configure the PipeWire context and some modules
#application.name = WirePlumber
log.level = 2
wireplumber.script-engine = lua-scripting
#mem.mlock-all = false
#support.dbus = true
}
context.spa-libs = {
#<factory-name regex> = <library-name>
#
# Used to find spa factory names. It maps an spa factory name
# regular expression to a library name that should contain
# that factory.
#
api.alsa.* = alsa/libspa-alsa
api.v4l2.* = v4l2/libspa-v4l2
audio.convert.* = audioconvert/libspa-audioconvert
support.* = support/libspa-support
}
context.modules = [
#{ name = <module-name>
# [ args = { <key> = <value> ... } ]
# [ flags = [ [ ifexists ] [ nofail ] ]
#}
#
# PipeWire modules to load.
# If ifexists is given, the module is ignored when it is not found.
# If nofail is given, module initialization failures are ignored.
#
# The native communication protocol.
{ name = libpipewire-module-protocol-native }
# Allows creating nodes that run in the context of the
# client. Is used by all clients that want to provide
# data to PipeWire.
{ name = libpipewire-module-client-node }
# Allows creating devices that run in the context of the
# client. Is used by the session manager.
{ name = libpipewire-module-client-device }
# Makes a factory for wrapping nodes in an adapter with a
# converter and resampler.
{ name = libpipewire-module-adapter }
# Allows applications to create metadata objects. It creates
# a factory for Metadata objects.
{ name = libpipewire-module-metadata }
# Provides factories to make session manager objects.
{ name = libpipewire-module-session-manager }
]
wireplumber.components = [
#{ name = <component-name>, type = <component-type> }
#
# WirePlumber components to load
#
# The lua scripting engine
{ name = libwireplumber-module-lua-scripting, type = module }
# The lua configuration file
# Other components are loaded from there
{ name = main.lua, type = config/lua }
]
../common/00-functions.lua
\ No newline at end of file
alsa_monitor = {}
alsa_monitor.properties = {}
alsa_monitor.rules = {}
function alsa_monitor.enable()
-- The "reserve-device" module needs to be loaded for reservation to work
if alsa_monitor.properties["alsa.reserve"] then
load_module("reserve-device")
end
load_monitor("alsa", {
properties = alsa_monitor.properties,
rules = alsa_monitor.rules,
})
end
v4l2_monitor = {}
v4l2_monitor.properties = {}
v4l2_monitor.rules = {}
function v4l2_monitor.enable()
load_monitor("v4l2", {
properties = v4l2_monitor.properties,
rules = v4l2_monitor.rules,
})
end
device_defaults = {}
device_defaults.properties = {
-- store preferences to the file system and restore them at startup
["use-persistent-storage"] = true,
}
function device_defaults.enable()
-- Enables saving and restoring default nodes
load_module("default-nodes", device_defaults.properties)
if device_defaults.properties["use-persistent-storage"] then
-- Automatically save and restore default routes
load_module("default-routes")
-- Enables functionality to save and restore default device profiles
load_module("default-profile")
end
end
alsa_monitor.properties = {
-- Create a JACK device. This is not enabled by default because
-- it requires that the PipeWire JACK replacement libraries are
-- not used by the session manager, in order to be able to
-- connect to the real JACK server.
--["alsa.jack-device"] = false,
-- Reserve devices via org.freedesktop.ReserveDevice1 on D-Bus
["alsa.reserve"] = true,
--["alsa.reserve.priority"] = -20,
--["alsa.reserve.application-name"] = "WirePlumber",
}
alsa_monitor.rules = {
-- An array of matches/actions to evaluate.
{
-- Rules for matching a device or node. It is an array of
-- properties that all need to match the regexp. If any of the
-- matches work, the actions are executed for the object.
matches = {
{
-- This matches all cards.
{ "device.name", "matches", "alsa_card.*" },
},
},
-- Apply properties on the matched object.
apply_properties = {
-- Use ALSA-Card-Profile devices. They use UCM or the profile
-- configuration to configure the device and mixer settings.
["api.alsa.use-acp"] = true,
-- Use UCM instead of profile when available. Can be
-- disabled to skip trying to use the UCM profile.
--["api.alsa.use-ucm"] = true,
-- Don't use the hardware mixer for volume control. It
-- will only use software volume. The mixer is still used
-- to mute unused paths based on the selected port.
--["api.alsa.soft-mixer"] = false,
-- Ignore decibel settings of the driver. Can be used to
-- work around buggy drivers that report wrong values.
--["api.alsa.ignore-dB"] = false,
-- The profile set to use for the device. Usually this is
-- "default.conf" but can be changed with a udev rule or here.
--["device.profile-set"] = "profileset-name",
-- The default active profile. Is by default set to "Off".
--["device.profile"] = "default profile name",
-- Automatically select the best profile. This is the
-- highest priority available profile. This is disabled
-- here and instead implemented in the session manager
-- where it can save and load previous preferences.
["api.acp.auto-profile"] = false,
-- Automatically switch to the highest priority available port.
-- This is disabled here and implemented in the session manager instead.
["api.acp.auto-port"] = false,
-- Other properties can be set here.
--["device.nick"] = "My Device",
},
},
{
matches = {
{
-- Matches all sources.
{ "node.name", "matches", "alsa_input.*" },
},
{
-- Matches all sinks.
{ "node.name", "matches", "alsa_output.*" },
},
},
apply_properties = {
--["node.nick"] = "My Node",
--["priority.driver"] = 100,
--["priority.session"] = 100,
--["node.pause-on-idle"] = false,
--["resample.quality"] = 4,
--["channelmix.normalize"] = false,
--["channelmix.mix-lfe"] = false,
--["audio.channels"] = 2,
--["audio.format"] = "S16LE",
--["audio.rate"] = 44100,
--["audio.position"] = "FL,FR",
--["api.alsa.period-size"] = 1024,
--["api.alsa.headroom"] = 0,
--["api.alsa.disable-mmap"] = false,
--["api.alsa.disable-batch"] = false,
}
}
}
v4l2_monitor.rules = {
-- An array of matches/actions to evaluate.
{
-- Rules for matching a device or node. It is an array of
-- properties that all need to match the regexp. If any of the
-- matches work, the actions are executed for the object.
matches = {
{
-- This matches all cards.
{ "device.name", "matches", "v4l2_device.*" },
},
},
-- Apply properties on the matched object.
apply_properties = {
-- ["device.nick"] = "My Device",
},
},
{
matches = {
{
-- Matches all sources.
{ "node.name", "matches", "v4l2_input.*" },
},
{
-- Matches all sinks.
{ "node.name", "matches", "v4l2_output.*" },
},
},
apply_properties = {
--["node.nick"] = "My Node",
--["priority.driver"] = 100,
--["priority.session"] = 100,
--["node.pause-on-idle"] = false,
},
},
}
-- Provide the "default" pw_metadata, which stores
-- dynamic properties of pipewire objects in RAM
load_module("metadata")
-- Load devices
alsa_monitor.enable()
v4l2_monitor.enable()
-- Track/store/restore user choices about devices
device_defaults.enable()
-- Automatically suspends idle nodes after 3 seconds
load_script("suspend-node.lua")
-- Automatically sets device profiles to 'On'
load_module("device-activation")
# WirePlumber daemon context configuration #
context.properties = {
## Properties to configure the PipeWire context and some modules
application.name = "WirePlumber Policy"
log.level = 2
wireplumber.script-engine = lua-scripting
wireplumber.export-core = false
#mem.mlock-all = false
#support.dbus = true
}
context.spa-libs = {
#<factory-name regex> = <library-name>
#
# Used to find spa factory names. It maps an spa factory name
# regular expression to a library name that should contain
# that factory.
#
audio.convert.* = audioconvert/libspa-audioconvert
support.* = support/libspa-support
}
context.modules = [
#{ name = <module-name>
# [ args = { <key> = <value> ... } ]
# [ flags = [ [ ifexists ] [ nofail ] ]
#}
#
# PipeWire modules to load.
# If ifexists is given, the module is ignored when it is not found.
# If nofail is given, module initialization failures are ignored.
#
# The native communication protocol.
{ name = libpipewire-module-protocol-native }
# Allows creating nodes that run in the context of the
# client. Is used by all clients that want to provide
# data to PipeWire.
{ name = libpipewire-module-client-node }
# Allows creating devices that run in the context of the
# client. Is used by the session manager.
{ name = libpipewire-module-client-device }
# Makes a factory for wrapping nodes in an adapter with a
# converter and resampler.
{ name = libpipewire-module-adapter }
# Allows applications to create metadata objects. It creates
# a factory for Metadata objects.
{ name = libpipewire-module-metadata }
# Provides factories to make session manager objects.
{ name = libpipewire-module-session-manager }
]
wireplumber.components = [
#{ name = <component-name>, type = <component-type> }
#
# WirePlumber components to load
#
# The lua scripting engine
{ name = libwireplumber-module-lua-scripting, type = module }
# The lua configuration file
# Other components are loaded from there
{ name = policy.lua, type = config/lua }
]
../common/00-functions.lua
\ No newline at end of file
default_policy = {}
default_policy.sessions = {
-- [session name] = { session properties }
["audio"] = { ["media.type"] = "Audio" },
["video"] = { ["media.type"] = "Video" },
}
default_policy.endpoints = {}
default_policy.policy = {
["move"] = true, -- moves session items when metadata target.node changes
["follow"] = true, -- moves session items to the default device when it has changed
}
function default_policy.enable()
-- Session item factories, building blocks for the session management graph
-- Do not disable these unless you really know what you are doing
load_module("si-node")
load_module("si-audio-adapter")
load_module("si-standard-link")
load_module("si-audio-endpoint")
-- API to access default nodes from scripts
load_module("default-nodes-api")
-- Create sessions statically at startup
load_script("static-sessions.lua", default_policy.sessions)
-- Create endpoints statically at startup
load_script("static-endpoints.lua", default_policy.endpoints)
-- Create items for nodes that appear in the graph
load_script("create-item.lua")
-- Link nodes to each other to make media flow in the graph
load_script("policy-node.lua", default_policy.policy)
-- Link client nodes with endpoints to make media flow in the graph
load_script("policy-endpoint-client.lua", default_policy.policy)
load_script("policy-endpoint-client-links.lua", default_policy.policy)
-- Link endpoints with device nodes to make media flow in the graph
load_script("policy-endpoint-device.lua", default_policy.policy)
end
default_policy.policy.roles = {
["Multimedia"] = {
["alias"] = { "Movie", "Music", "Game" },
["priority"] = 10,
["action.default"] = "mix",
},
["Notification"] = {
["priority"] = 20,
["action.default"] = "cork",
["action.Notification"] = "mix",
},
["Alert"] = {
["priority"] = 30,
["action.default"] = "cork",
["action.Alert"] = "mix",
},
}
default_policy.endpoints = {
["endpoint.multimedia"] = {