Compare commits

..

No commits in common. "master" and "0.4.15" have entirely different histories.

486 changed files with 15703 additions and 45181 deletions

View file

@ -1,15 +1,6 @@
# Create merge request pipelines for open merge requests, branch pipelines
# otherwise. This allows MRs for new users to run CI, and prevents duplicate
# pipelines for branches with open MRs.
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
- if: $CI_COMMIT_BRANCH
stages: stages:
- container - container
- container_coverity
- build - build
- analysis - analysis
- pages - pages
@ -19,8 +10,8 @@ variables:
# change to build against a different tag or branch of pipewire # change to build against a different tag or branch of pipewire
PIPEWIRE_HEAD: 'master' PIPEWIRE_HEAD: 'master'
# ci-templates as of Feb 14th 2025 # ci-templates as of Mar 24th 2023
.templates_sha: &templates_sha ef5e4669b7500834a17ffe9277e15fbb6d977fff .templates_sha: &templates_sha dd90ac0d7a03b574eb4f18d7358083f0c97825f3
include: include:
- project: 'freedesktop/ci-templates' - project: 'freedesktop/ci-templates'
@ -36,8 +27,8 @@ include:
.fedora: .fedora:
variables: variables:
# Update this tag when you want to trigger a rebuild # Update this tag when you want to trigger a rebuild
FDO_DISTRIBUTION_TAG: '2025-03-05.1' FDO_DISTRIBUTION_TAG: '2023-03-24.1'
FDO_DISTRIBUTION_VERSION: '41' FDO_DISTRIBUTION_VERSION: '37'
# findutils: used by the .build script below # findutils: used by the .build script below
# dbus-devel: required by pipewire # dbus-devel: required by pipewire
# dbus-daemon: required by GDBus unit tests # dbus-daemon: required by GDBus unit tests
@ -68,13 +59,12 @@ include:
.ubuntu: .ubuntu:
variables: variables:
# Update this tag when you want to trigger a rebuild # Update this tag when you want to trigger a rebuild
FDO_DISTRIBUTION_TAG: '2023-06-16.1' FDO_DISTRIBUTION_TAG: '2023-03-24.1'
FDO_DISTRIBUTION_VERSION: '22.04' FDO_DISTRIBUTION_VERSION: '20.04'
FDO_DISTRIBUTION_PACKAGES: >- FDO_DISTRIBUTION_PACKAGES: >-
debhelper-compat debhelper-compat
findutils findutils
git git
meson
ninja-build ninja-build
pkg-config pkg-config
python3-pip python3-pip
@ -85,12 +75,14 @@ include:
libgirepository1.0-dev libgirepository1.0-dev
doxygen doxygen
python3-lxml python3-lxml
FDO_DISTRIBUTION_EXEC: >-
pip3 install meson
.alpine: .alpine:
variables: variables:
# Update this tag when you want to trigger a rebuild # Update this tag when you want to trigger a rebuild
FDO_DISTRIBUTION_TAG: '2025-03-05.1' FDO_DISTRIBUTION_TAG: '2023-03-24.1'
FDO_DISTRIBUTION_VERSION: '3.21' FDO_DISTRIBUTION_VERSION: '3.15'
FDO_DISTRIBUTION_PACKAGES: >- FDO_DISTRIBUTION_PACKAGES: >-
dbus dbus
dbus-dev dbus-dev
@ -121,23 +113,14 @@ include:
tar xf /tmp/cov-analysis-linux64.tgz ; tar xf /tmp/cov-analysis-linux64.tgz ;
mv cov-analysis-linux64-* coverity ; mv cov-analysis-linux64-* coverity ;
rm /tmp/cov-analysis-linux64.tgz rm /tmp/cov-analysis-linux64.tgz
only:
variables:
- $COVERITY
.rules_on_success_except_coverity: .not_coverity:
rules: except:
- if: $COVERITY variables:
when: never - $COVERITY
- when: on_success
.rules_only_on_coverity:
rules:
- if: $COVERITY
.rules_only_on_mr_and_branch:
rules:
- if: $COVERITY
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH != "master"
.build: .build:
before_script: before_script:
@ -154,22 +137,13 @@ include:
# Fedora also ships that, but without the test plugins that we need... # Fedora also ships that, but without the test plugins that we need...
- git clone --depth=1 --branch="$PIPEWIRE_HEAD" - git clone --depth=1 --branch="$PIPEWIRE_HEAD"
https://gitlab.freedesktop.org/pipewire/pipewire.git https://gitlab.freedesktop.org/pipewire/pipewire.git
# Set build options based on PipeWire version - meson "$PW_BUILD_DIR" pipewire --prefix="$PREFIX"
- | -Dpipewire-alsa=disabled -Dpipewire-jack=disabled
case "$PIPEWIRE_HEAD" in -Dalsa=disabled -Dv4l2=disabled -Djack=disabled -Dbluez5=disabled
1.0|1.2|1.4) -Dvulkan=disabled -Dgstreamer=disabled -Dsystemd=disabled
export PIPEWIRE_BUILD_OPTIONS="-Dsystemd=disabled" -Ddocs=disabled -Dman=disabled -Dexamples=disabled -Dpw-cat=disabled
;; -Dsdl2=disabled -Dsndfile=disabled -Dlibpulse=disabled -Davahi=disabled
*) -Decho-cancel-webrtc=disabled -Dsession-managers=[]
export PIPEWIRE_BUILD_OPTIONS="-Dlibsystemd=disabled"
;;
esac
- meson "$PW_BUILD_DIR" pipewire --prefix="$PREFIX" $PIPEWIRE_BUILD_OPTIONS
-Dpipewire-alsa=disabled -Dpipewire-jack=disabled -Dalsa=disabled
-Dv4l2=disabled -Djack=disabled -Dbluez5=disabled -Dvulkan=disabled
-Dgstreamer=disabled -Ddocs=disabled -Dman=disabled -Dexamples=disabled
-Dpw-cat=disabled -Dsdl2=disabled -Dsndfile=disabled -Dlibpulse=disabled
-Davahi=disabled -Decho-cancel-webrtc=disabled -Dsession-managers=[]
-Dvideotestsrc=enabled -Daudiotestsrc=enabled -Dtest=enabled -Dvideotestsrc=enabled -Daudiotestsrc=enabled -Dtest=enabled
- ninja $NINJA_ARGS -C "$PW_BUILD_DIR" install - ninja $NINJA_ARGS -C "$PW_BUILD_DIR" install
# misc environment only for wireplumber # misc environment only for wireplumber
@ -191,7 +165,6 @@ include:
container_fedora: container_fedora:
extends: extends:
- .rules_on_success_except_coverity
- .fedora - .fedora
- .fdo.container-build@fedora - .fdo.container-build@fedora
stage: container stage: container
@ -200,7 +173,6 @@ container_fedora:
container_ubuntu: container_ubuntu:
extends: extends:
- .rules_only_on_mr_and_branch
- .ubuntu - .ubuntu
- .fdo.container-build@ubuntu - .fdo.container-build@ubuntu
stage: container stage: container
@ -209,7 +181,6 @@ container_ubuntu:
container_alpine: container_alpine:
extends: extends:
- .rules_only_on_mr_and_branch
- .alpine - .alpine
- .fdo.container-build@alpine - .fdo.container-build@alpine
stage: container stage: container
@ -218,18 +189,17 @@ container_alpine:
container_coverity: container_coverity:
extends: extends:
- .rules_only_on_coverity
- .fedora - .fedora
- .coverity - .coverity
- .fdo.container-build@fedora - .fdo.container-build@fedora
stage: container stage: container_coverity
variables: variables:
GIT_STRATEGY: none GIT_STRATEGY: none
build_on_fedora_with_docs: build_on_fedora_with_docs:
extends: extends:
- .rules_on_success_except_coverity
- .fedora - .fedora
- .not_coverity
- .fdo.distribution-image@fedora - .fdo.distribution-image@fedora
- .build - .build
stage: build stage: build
@ -238,21 +208,18 @@ build_on_fedora_with_docs:
build_on_fedora_no_docs: build_on_fedora_no_docs:
extends: extends:
- .rules_only_on_mr_and_branch
- .fedora - .fedora
- .not_coverity
- .fdo.distribution-image@fedora - .fdo.distribution-image@fedora
- .build - .build
stage: build stage: build
variables: variables:
BUILD_OPTIONS: -Dintrospection=enabled -Ddoc=disabled -Dsystem-lua=false BUILD_OPTIONS: -Dintrospection=enabled -Ddoc=disabled -Dsystem-lua=false
parallel:
matrix:
- PIPEWIRE_HEAD: ['master', '1.4', '1.2', '1.0']
build_on_ubuntu_with_gir: build_on_ubuntu_with_gir:
extends: extends:
- .rules_only_on_mr_and_branch
- .ubuntu - .ubuntu
- .not_coverity
- .fdo.distribution-image@ubuntu - .fdo.distribution-image@ubuntu
- .build - .build
stage: build stage: build
@ -261,8 +228,8 @@ build_on_ubuntu_with_gir:
build_on_ubuntu_no_gir: build_on_ubuntu_no_gir:
extends: extends:
- .rules_only_on_mr_and_branch
- .ubuntu - .ubuntu
- .not_coverity
- .fdo.distribution-image@ubuntu - .fdo.distribution-image@ubuntu
- .build - .build
stage: build stage: build
@ -271,8 +238,8 @@ build_on_ubuntu_no_gir:
build_on_alpine: build_on_alpine:
extends: extends:
- .rules_only_on_mr_and_branch
- .alpine - .alpine
- .not_coverity
- .fdo.distribution-image@alpine - .fdo.distribution-image@alpine
- .build - .build
stage: build stage: build
@ -281,7 +248,6 @@ build_on_alpine:
build_with_coverity: build_with_coverity:
extends: extends:
- .rules_only_on_coverity
- .fedora - .fedora
- .coverity - .coverity
- .fdo.suffixed-image@fedora - .fdo.suffixed-image@fedora
@ -311,23 +277,16 @@ build_with_coverity:
shellcheck: shellcheck:
extends: extends:
- .fedora - .fedora
- .not_coverity
- .fdo.distribution-image@fedora - .fdo.distribution-image@fedora
stage: analysis stage: analysis
script: script:
- shellcheck $(git grep -l "#\!/.*bin/.*sh") - shellcheck $(git grep -l "#\!/.*bin/.*sh")
rules:
- if: $COVERITY
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- "**/*.sh"
- if: $CI_COMMIT_BRANCH != "master"
changes:
- "**/*.sh"
linguas_check: linguas_check:
extends: extends:
- .fedora - .fedora
- .not_coverity
- .fdo.distribution-image@fedora - .fdo.distribution-image@fedora
stage: analysis stage: analysis
script: script:
@ -336,17 +295,10 @@ linguas_check:
- ls *.po | sed s/.po//g | sort > LINGUAS.new - ls *.po | sed s/.po//g | sort > LINGUAS.new
- diff -u LINGUAS.sorted LINGUAS.new - diff -u LINGUAS.sorted LINGUAS.new
- rm -f LINGUAS.* - rm -f LINGUAS.*
rules:
- if: $COVERITY
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- po/*
- if: $CI_COMMIT_BRANCH != "master"
changes:
- po/*
pages: pages:
extends:
- .not_coverity
stage: pages stage: pages
dependencies: dependencies:
- build_on_fedora_with_docs - build_on_fedora_with_docs
@ -356,7 +308,5 @@ pages:
artifacts: artifacts:
paths: paths:
- public - public
rules: only:
- if: $COVERITY - master
when: never
- if: $CI_COMMIT_BRANCH == "master"

View file

@ -1,37 +0,0 @@
## Building and Testing
- To compile the project: `meson compile -C build` (compiles everything, no target needed)
- To run tests: `meson test -C build`
- The build artifacts always live in a directory called `build` or `builddir`.
If `build` doesn't exist, use `-C builddir` in the meson commands.
## Git Workflow
- Main branch: `master`
- Always create feature branches for new work
- Use descriptive commit messages following project conventions
- Reference GitLab MR/issue numbers in commits where applicable
- Never commit build artifacts or temporary files
- Use `glab` CLI tool for GitLab interactions (MRs, issues, etc.)
## Making a release
- Each release always consists of an entry in NEWS.rst, at the top of the file, which describes
the changes between the previous release and the current one. In addition, each release is given
a unique version number, which is present:
1. on the section header of that NEWS.rst entry
2. in the project() command in meson.build
3. on the commit message of the commit that introduces the above 2 changes
4. on the git tag that marks the above commit
- In order to make a release:
- Begin by analyzing the git history and the merged MRs from GitLab between the previous release
and today. GitLab MRs that are relevant always have the new release's version number set as a
"milestone"
- Create a new entry in NEWS.rst describing the changes, in a similar style and format as the
previous entries. Consolidate the changes to larger work items and also reference the relevant
gitlab MR that corresponds to each change and/or the gitlab issues that were addressed by each
change.
- Make sure to move the "Past releases" section header up, so that the only 2 top-level sections
are the new release section and the "Past releases" section.
- Edit meson.build to change the project version to the new release number
- Do not commit anything to git. Let the user review the changes and commit manually.

778
NEWS.rst
View file

@ -1,778 +1,5 @@
WirePlumber 0.5.14
~~~~~~~~~~~~~~~~~~
Additions & Enhancements:
- Added per-device default volume configuration via the
``device.routes.default-{source,sink}-volume`` property, allowing device-specific volume
defaults (e.g. a comfortable default for internal speakers or no attenuation for HDMI) (!772)
- Added Lua 5.5 support; the bundled Lua subproject wrap has also been updated to 5.5.0
(!775, !788)
- Enhanced libcamera monitor to load camera nodes locally within the WirePlumber
process instead of the PipeWire daemon, eliminating race conditions that could occur
during initial enumeration and hotplug events (!790)
- Enhanced Bluetooth loopback nodes to always be created when a device supports both
A2DP and HSP/HFP profiles, simplifying the logic and making the BT profile autoswitch
setting take effect immediately without requiring device reconnection (!782)
- Enhanced Bluetooth loopback nodes to use ``target.object`` property instead of smart
filters, fixing issues that prevented users from setting them as default nodes and
also allowing smart filters to be used with them (#898; !792)
- Enhanced Bluetooth profile autoswitch logic with further robustness improvements,
including better headset profile detection using profile name patterns and resolving
race conditions by running profile switching after ``device/apply-profile`` in a
dedicated event hook (#926, #923; !776, !777, !808)
- Enhanced wpctl ``set-default`` command to accept virtual nodes (e.g.
``Audio/Source/Virtual``) in addition to regular device nodes (#896; !787)
- Improved stream linking to make the full graph rescan optional when linkable items
change, saving CPU on low-end systems and reducing audio startup latency when
connecting multiple streams in quick succession (!800)
- Allowed installation of systemd service units without libsystemd being present,
useful for distributions like Alpine Linux that allow systemd service subpackages
(!793)
- Allowed the ``mincore`` syscall in the WirePlumber systemd sandbox, required for
Mesa/EGL (e.g. for the libcamera GPUISP pipeline)
- Allowed passing ``WIREPLUMBER_CONFIG_DIR`` via the ``wp-uninstalled`` script,
useful for passing additional configuration paths in an uninstalled environment (!801)
Fixes:
- Removed Bluetooth sink loopback node, which was causing issues with KDE and GNOME (!794)
- Fixed default audio source selection to never automatically use ``Audio/Sink`` nodes
as the default source unless explicitly selected by the user (#886; !781)
- Fixed crash in ``state-stream`` when the Format parameter has a Choice for the
number of channels (#903; !795)
- Fixed BAP Bluetooth device set channel properties, where ``audio.position`` was
incorrectly serialized as a pointer address instead of the channel array (!786)
- Fixed memory leaks in ``wp_interest_event_hook_get_matching_event_types`` and in
the Lua ``LocalModule()`` implementation (!784, !810)
- Fixed HFP HF stream media class being incorrectly assigned due to
``api.bluez5.internal=true`` being set on HFP HF streams (!809)
- Fixed Lua 5.4 compatibility in ``state-stream`` script
- Updated translations: Bulgarian, Georgian, Kazakh, Swedish
Past releases
~~~~~~~~~~~~~
WirePlumber 0.5.13
..................
Additions & Enhancements:
- Added internal filter graph support for audio nodes, allowing users to
create audio preprocessing and postprocessing chains without exposing
filters to applications, useful for software DSP (!743)
- Added new Lua Properties API that significantly improves performance by
avoiding constant serialization between WpProperties and Lua tables,
resulting in approximately 40% faster node linking (!757)
- Added WpIterator Lua API for more efficient parameter enumeration (!746)
- Added bash completions for wpctl command (!762)
- Added script to find suitable volume control when using role-based policy,
allowing volume sliders to automatically adjust the volume of the currently
active role (e.g., ringing, call, media) (!711)
- Added experimental HDMI channel detection setting to use HDMI ELD
information for channel configuration (!749)
- Enhanced role-based policy to allow setting preferred target sinks for
media role loopbacks via ``policy.role-based.preferred-target`` (!754)
- Enhanced Bluetooth profile autoswitch logic to be more robust and handle
saved profiles correctly, including support for loopback sink nodes (!739)
- Enhanced ALSA monitor to include ``alsa.*`` device properties on nodes for
rule matching (!761)
- Optimized stream node linking for common cases to reduce latency when new
audio/video streams are added (!760)
- Improved event dispatcher performance by using hash table registration for
event hooks, eliminating performance degradation as more hooks are
registered (!765)
- Increased audio headroom for VMware and VirtualBox virtual machines (!756)
- Added setting to prevent restoring "Off" profiles via
``session.dont-restore-off-profile`` property (!753)
- Added support for 128 audio channels when compiled with a recent version of
PipeWire (pipewire#4995; CI checks in !768)
Fixes:
- Fixed memory leaks and issues in the modem manager module (!770, !764)
- Fixed MPRIS module incorrectly treating GHashTable as GObject (!759)
- Fixed warning messages when process files in ``/proc/<pid>/*`` don't exist,
particularly when processes are removed quickly (#816, !717)
- Fixed MONO audio configuration to only apply to device sink nodes, allowing
multi-channel mixing in the graph (!769)
- Fixed event dispatcher hook registration and removal to avoid spurious
errors (!747)
- Improved logging for standard-link activation failures (!744)
- Simplified event-hook interest matching for better performance (!758)
WirePlumber 0.5.12
..................
Additions & Enhancements:
- Added mono audio configuration support via ``node.features.audio.mono``
setting that can be changed at runtime with wpctl (!721)
- Added automatic muting of ALSA devices when a running node is removed,
helping prevent loud audio on speakers when headsets are unplugged (!734)
- Added notifications API module for sending system notifications (!734)
- Added comprehensive wpctl man page and documentation (!735, #825)
- Enhanced object interest handling for PipeWire properties on session items (!738)
Fixes:
- Fixed race condition during shutdown in the permissions portal module that
could cause crashes in GDBus signal handling (!748)
- Added device validity check in state-routes handling to prevent issues
when devices are removed during async operations (!737, #844)
- Fixed Log.critical undefined function error in device-info-cache (!733)
- Improved device hook documentation and configuration (!736)
WirePlumber 0.5.11
..................
Additions & Enhancements:
- Added modem manager module for tracking voice call status and voice call
device profile selection hooks to improve phone call audio routing on
mobile devices (!722, !729, #819)
- Added MPRIS media player pause functionality that automatically pauses
media playback when the audio target (e.g. headphones) is removed (!699, #764)
- Added support for human-readable names and localization of settings in
``wireplumber.conf`` with ``wpctl`` displaying localized setting descriptions (!712)
- Improved default node selection logic to use both session and route
priorities when nodes have equal session priorities (!720)
- Increased USB device priority in the ALSA monitor (!719)
Fixes:
- Fixed multiple Lua runtime issues including type confusion bugs, stack
overflow prevention, and SPA POD array/choice builders (!723, !728)
- Fixed proxy object lifecycle management by properly clearing the
OWNED_BY_PROXY flag when proxies are destroyed to prevent dangling
pointers (!732)
- Fixed state-routes handling to prevent saving unavailable routes and
eliminate race conditions during profile switching (!730, #762)
- Fixed some memory leaks in the script tester and the settings iterator (!727, !726)
- Fixed a potential crash caused by module-loopback destroying itself when the
pipewire connection is closed (#812)
- Fixed profile saving behavior in ``wpctl set-profile`` command (#808)
- Fixed GObject introspection closure annotation
WirePlumber 0.5.10
..................
Fixed a critical crash in ``linking-utils.haveAvailableRoutes`` that was
introduced accidentally in 0.5.9 and caused loss of audio output on affected
systems (#797, #799, #800, !713)
WirePlumber 0.5.9
.................
Additions & Enhancements:
- Added a new audio node grouping functionality using an external command line
tool (!646)
- The libcamera monitor now supports devices that are not associated with
device ids (!701)
- The wireplumber user systemd service is now associated with dbus.service to
avoid strange warnings when dbus exits (!702)
- Added "SYSLOG_IDENTIFIER", "SYSLOG_FACILITY", "SYSLOG_PID" and "TID" to log
messages that are sent to the journal (!709)
Fixes:
- Fixed a crash of ``wpctl set-default`` on 32-bit architectures (#773)
- Fixed a crash when a configuration component had no 'provides' field (#771)
- Reduced the log level of some messages that didn't need to be as high (!695)
- Fixed another nil reference issue in the alsa.lua monitor script (!704)
- Fixed name deduplication of v4l2 and libcamera devices (!705)
- Fixed an issue with wpctl not being able to save settings sometimes (!708, #749)
WirePlumber 0.5.8
.................
Additions & Enhancements:
- Added support for handling UCM SplitPCM nodes in the ALSA monitor, which
allows native PipeWire channel remapping using loopbacks for devices that
use this feature (!685)
- Introduced new functions to mark WpSpaDevice child objects as pending.
This allows properly associating asynchronously created loopback nodes with
their parent WpSpaDevice without losing ObjectConfig events (!687, !689)
- Improved the node name deduplication logic in the ALSA monitor to prevent
node names with .2, .3, etc appended to them in some more cases (!688)
- Added a new script to populate ``session.services``. This is a step towards
implementing detection of features that PipeWire can service (!686)
Fixes:
- Fixed an issue that was causing duplicate Bluetooth SCO (HSP/HFP) source
nodes to be shown in UIs (#701, !683)
- In the BlueZ monitor, marked the source loopback node as non-virtual,
addressing how it appears on UIs (#729)
- Disabled stream-restore for device loopback nodes to prevent unwanted
property changes (!691)
- Fixed ``wp_lua_log_topic_copy()`` to correctly copy topic names (#757)
- Updated script tests to handle differences in object identifiers
(``object.serial`` vs ``node.id``), ensuring proper test behavior (#761)
WirePlumber 0.5.7
.................
Highlights:
- Fixed an issue that would cause random profile switching when an application
was trying to capture from non-Bluetooth devices (#715, #634, !669)
- Fixed an issue that would cause strange profile selection issues [choices
not being remembered or unavailable routes being selected] (#734)
- Added a timer that delays switching Bluetooth headsets to the HSP/HFP
profile, avoiding needless rapid switching when an application is trying to
probe device capabilities instead of actually capturing audio (!664)
- Improved libcamera/v4l2 device deduplication logic to work with more complex
devices (!674, !675, #689, #708)
Fixes:
- Fixed two memory leaks in module-mixer-api and module-dbus-connection
(!672, !673)
- Fixed a crash that could occur in module-reserve-device (!680, #742)
- Fixed an issue that would cause the warning "[string "alsa.lua"]:182:
attempt to concatenate a nil value (local 'node_name')" to appear in the
logs when an ALSA device was busy, breaking node name deduplication (!681)
- Fixed an issue that could make find-preferred-profile.lua crash instead of
properly applying profile priority rules (#751)
WirePlumber 0.5.6
.................
Additions:
- Implemented before/after dependencies for components, to ensure correct
load order in custom configurations (#600)
- Implemented profile inheritance in the configuration file. This allows
profiles to inherit all the feature specifications of other profiles, which
is useful to avoid copying long lists of features just to make small changes
- Added multi-instance configuration profiles, tested and documented them
- Added a ``main-systemwide`` profile, which is now the default for instances
started via the system-wide systemd service and disables features that
depend on the user session (#608)
- Added a ``wp_core_connect_fd`` method, which allows making a connection to
PipeWire via an existing open socket (useful for portal-based connections)
Fixes:
- The Bluetooth auto-switch script now uses the common event source object
managers, which should improve its stability (!663)
- Fix an issue where switching between Bluetooth profiles would temporarily
link active audio streams to the internal speakers (!655)
WirePlumber 0.5.5
.................
Highlights:
- Hotfix release to address crashes in the Bluetooth HSP/HFP autoswitch
functionality that were side-effects of some changes that were part
of the role-based linking policy (#682)
Improvements:
- wpctl will now properly show a '*' in front of sink filters when they are
selected as the default sink (!660)
WirePlumber 0.5.4
.................
Highlights:
- Refactored the role-based linking policy (previously known also as
"endpoints" or "virtual items" policy) to blend in with the standard desktop
policy. It is now possible use role-based sinks alongside standard desktop
audio operations and they will only be used for streams that have a
"media.role" defined. It is also possible to force streams to have a
media.role, using a setting. Other features include: blending with smart
filters in the graph and allowing hardware DSP nodes to be also used easily
instead of requiring software loopbacks for all roles. (#610, !649)
Improvements:
- Filters that are not declared as smart will now behave again as normal
application streams, instead of being treated sometimes differently (!657)
Fixes:
- Fixed an issue that would cause WirePlumber to crash at startup if an
empty configuration file was present in one of the search paths (#671)
- Fixed Bluetooth profile auto-switching when a filter is permanently linked
to the Bluetooth source (!650)
- Fixed an issue in the software-dsp script that would cause DSP filters to
stay around and cause issues after their device node was destroyed (!651)
- Fixed an issue in the autoswitch-bluetooth-profile script that could cause
an infinite loop of switching between profiles (!652, #617)
- Fixed a rare issue that could cause WirePlumber to crash when dealing with
a device object that didn't have the "device.name" property set (#674)
WirePlumber 0.5.3
.................
Fixes:
- Fixed a long standing issue that would cause many device nodes to have
inconsistent naming, with a '.N' suffix (where N is a number >= 2) being
appended at seemingly random times (#500)
- Fixed an issue that would cause unavailable device profiles to be selected
if they were previously stored in the state file, sometimes requiring users
to manually remove the state file to get things working again (#613)
- Fixed an occasional crash that could sometimes be triggered by hovering
the volume icon on the KDE taskbar, and possibly other similar actions
(#628, !644)
- Fixed camera device deduplication logic when the same device is available
through both V4L2 and libcamera, and the libcamera one groups multiple V4L2
devices together (#623, !636)
- Fixed applying the default volume on streams that have no volume previously
stored in the state file (#655)
- Fixed an issue that would prevent some camera nodes - in some cases -
from being destroyed when the camera device is removed (#640)
- Fixed an issue that would cause video stream nodes to be linked with audio
smart filters, if smart audio filters were configured (!647)
- Fixed an issue that would cause WP to re-activate device profiles even
though they were already active (!639)
- Configuration files in standard JSON format (starting with a '{', among
other things) are now correctly parsed (#633)
- Fixed overriding non-container values when merging JSON objects (#653)
- Functions marked with WP_PRIVATE_API are now also marked as
non-introspectable in the gobject-introspection metadata (#599)
Improvements:
- Logging on the systemd journal now includes the log topic and also the log
level and location directly on the message string when the log level is
high enough, which is useful for gathering additional context in logs
submitted by users (!640)
- Added a video-only profile in wireplumber.conf, for systems where only
camera & screensharing are to be used (#652)
- Improved seat state monitoring so that Bluetooth devices are only enabled
when the user is active on a local seat, instead of allowing remote users
as well (!641)
- Improved how main filter nodes are detected for the smart filters (!642)
- Added Lua method to merge JSON containers (!637)
WirePlumber 0.5.2
.................
Highlights:
- Added support for loading configuration files other than the default
wireplumber.conf within Lua scripts (!629)
- Added support for loading single-section configuration files, without
fragments (!629)
- Updated the node.software-dsp script to be able to load filter-chain graphs
from external configuration files, which is needed for Asahi Linux audio
DSP configuration (!629)
Fixes:
- Fixed destroying camera nodes when the camera device is removed (#627, !631)
- Fixed an issue with Bluetooth BAP device set naming (!632)
- Fixed an issue caused by the pipewire event loop not being "entered" as
expected (!634, #638)
- A false positive warning about no modules being loaded is now suppressed
when using libpipewire >= 1.0.5 (#620)
- Default nodes can now be selected using priority.driver when
priority.session is not set (#642)
Changes:
- The library version is now generated following pipewire's versioning scheme:
libwireplumber-0.5.so.0.5.2 becomes libwireplumber-0.5.so.0.0502.0 (!633)
WirePlumber 0.5.1
.................
Highlights:
- Added a guide documenting how to migrate configuration from 0.4 to 0.5,
also available online at:
https://pipewire.pages.freedesktop.org/wireplumber/daemon/configuration/migration.html
If you are packaging WirePlumber for a distribution, please consider
informing users about this.
Fixes:
- Fixed an odd issue where microphones would stop being usable when a
Bluetooth headset was connected in the HSP/HFP profile (#598, !620)
- Fixed an issue where it was not possible to store the volume/mute state of
system notifications (#604)
- Fixed a rare crash that could occur when a node was destroyed while the
'select-target' event was still being processed (!621)
- Fixed deleting all the persistent settings via ``wpctl --delete`` (!622)
- Fixed using Bluetooth autoswitch with A2DP profiles that have an input route
(!624)
- Fixed sending an error to clients when linking fails due to a format
mismatch (!625)
Additions:
- Added a check that prints a verbose warning when old-style 0.4.x Lua
configuration files are found in the system. (#611)
- The "policy-dsp" script, used in Asahi Linux to provide a software DSP
for Apple Sillicon devices, has now been ported to 0.5 properly and
documented (#619, !627)
WirePlumber 0.5.0
.................
Changes:
- Bumped the minimum required version of PipeWire to 1.0.2, because we
make use of the 'api.bluez5.internal' property of the BlueZ monitor (!613)
- Improved the naming of Bluetooth nodes when the auto-switching loopback
node is present (!614)
- Updated the documentation on "settings", the Bluetooth monitor, the Access
configuration, the file search locations and added a document on how to
modify the configuration file (#595, !616)
Fixes:
- Fixed checking for available routes when selecting the default node (!609)
- Fixed an issue that was causing an infinite loop storing routes in the
state file (!610)
- Fixed the interpretation of boolean values in the alsa monitor rules (#586, !611)
- Fixes a Lua crash when we have 2 smart filters, one with a target and one
without (!612)
- Fixed an issue where the default nodes would not be updated when the
currently selected default node became unavailable (#588, !615)
- Fixed an issue that would cause the Props (volume, mute, etc) of loopbacks
and other filter nodes to not be restored at startup (#577, !617)
- Fixed how some constants were represented in the gobject-introspection file,
mostly by converting them from defines to enums (#540, #591)
- Fixed an issue using WirePlumber headers in other projects due to
redefinition of G_LOG_DOMAIN (#571)
WirePlumber 0.4.90
..................
This is the first release candidate (RC1) of WirePlumber 0.5.0.
Highlights:
- The configuration system has been changed back to load files from the
WirePlumber configuration directories, such as ``/etc/wireplumber`` and
``$XDG_CONFIG_HOME/wireplumber``, unlike in the pre-releases. This was done
because issues were observed with installations that use a different prefix
for pipewire and wireplumber. If you had a ``wireplumber.conf`` file in
``/etc/pipewire`` or ``$XDG_CONFIG_HOME/pipewire``, you should move it to
``/etc/wireplumber`` or ``$XDG_CONFIG_HOME/wireplumber`` respectively (!601)
- The internal base directories lookup system now also respects the
``XDG_CONFIG_DIRS`` and ``XDG_DATA_DIRS`` environment variables, and their
default values as per the XDG spec, so it is possible to install
configuration files also in places like ``/etc/xdg/wireplumber`` and
override system-wide data paths (!601)
- ``wpctl`` now has a ``settings`` subcommand to show, change and delete
settings at runtime. This comes with changes in the ``WpSettings`` system to
validate settings using a schema that is defined in the configuration file.
The schema is also exported on a metadata object, so it is available to any
client that wants to expose WirePlumber settings (!599, !600)
- The ``WpConf`` API has changed to not be a singleton and support opening
arbitrary config files. The main config file now needs to be opened prior to
creating a ``WpCore`` and passed to the core using a property. The core uses
that without letting the underlying ``pw_context`` open and read the default
``client.conf``. The core also closes the ``WpConf`` after all components
are loaded, which means all the config loading is done early at startup.
Finally, ``WpConf`` loads all sections lazily, keeping the underlying files
memory mapped until it is closed and merging them on demand (!601, !606)
WirePlumber 0.4.82
..................
This is a second pre-release of WirePlumber 0.5.0, made available for testing
purposes. This is not API/ABI stable yet and there is still pending work to do
before the final 0.5.0 release, both in the codebase and the documentation.
Highlights:
- Bluetooth auto-switching is now implemented with a virtual source node. When
an application links to it, the actual device switches to the HSP/HFP
profile to provide the real audio stream. This is a more robust solution
that works with more applications and is more user-friendly than the
previous application whitelist approach
- Added support for dynamic log level changes via the PipeWire ``settings``
metadata. Also added support for log level patterns in the configuration
file
- The "persistent" (i.e. stored) settings approach has changed to use two
different metadata objects: ``sm-settings`` and ``persistent-sm-settings``.
Changes in the former are applied in the current session but not stored,
while changes in the latter are stored and restored at startup. Some work
was also done to expose a ``wpctl`` interface to read and change these
settings, but more is underway
- Several WirePlumber-specific node properties that used to be called
``target.*`` have been renamed to ``node.*`` to match the PipeWire
convention of ``node.dont-reconnect``. These are also now fully documented
Other changes:
- Many documentation updates
- Added support for SNAP container permissions
- Fixed multiple issues related to restoring the Route parameter of devices,
which includes volume state (#551)
- Smart filters can now be targetted by specific streams directly when
the ``filter.smart.targetable`` property is set (#554)
- Ported the mechanism to override device profile priorities in the
configuration, which is used to re-prioritize Bluetooth codecs
- WpSettings is no longer a singleton class and there is a built-in component
to preload an instance of it
WirePlumber 0.4.81
..................
This is a preliminary release of WirePlumber 0.5.0, which is made available
for testing purposes. Please test it and report feedback (merge requests are
also welcome ;) ). This is not API/ABI stable yet and there is still pending
work to do before the final 0.5.0 release, both in the codebase and the
documentation.
Highlights:
- Lua scripts have been refactored to use the new event dispatcher API, which
allows them to be split into multiple small fragments that react to
events in a specified order. This allows scripts to be more modular and
easier to maintain, as well as more predictable in terms of execution
order.
- The configuration system has been refactored to use a single SPA-JSON file,
like PipeWire does, with support for fragments that can override options.
This file is also now loaded using PipeWire's configuration API, which
effectively means that the file is now loaded from the PipeWire configuration
directories, such as ``/etc/pipewire`` and ``$XDG_CONFIG_HOME/pipewire``.
- The configuration system now has the concept of profiles, which are groups
of components that can be loaded together, with the ability to mark certain
components as optional. This allows having multiple configurations that
can be loaded using the same configuration file. Optional components also
allow loading the same profile gracefully on different setups, where some
components may not be available (ex, loading of the session D-Bus plugin on
a system-wide PipeWire setup now does not fail).
- Many configuration options are now exposed in the ``sm-settings`` metadata,
which allows changing them at runtime. This can be leveraged in the future
to implement configuration tools that can modify WirePlumber's behaviour
dynamically, without restarting.
- A new "filters" system has been implemented, which allows specifying chains
of "filter" nodes to be dynamically linked in-between streams and devices.
This is achieved with certain properties and metadata that can be set on
the filter nodes themselves.
- The default linking policy now reads some more ``target.*`` properties from
nodes, which allows fine-tuning some aspects of their linking behaviour,
such as whether they are allowed to be re-linked or whether an error should
be sent to the client if they cannot be linked.
- Some state files have been renamed and some have changed format to use JSON
for storing complex values, such as arrays. This may cause some of the old
state to be lost on upgrade, as there is no transition path implemented.
- The libcamera and V4L2 monitors have a "device deduplication" logic built-in,
which means that for each physical camera device, only one node will be
created, either from libcamera or V4L2, depending on which one is considered
better for the device. This is mainly to avoid having multiple nodes for
the same camera device, which can cause confusion when looking at the list
of available cameras in applications.
WirePlumber 0.4.17
..................
Fixes:
- Fixed a reference counting issue in the object managers that could cause
crashes due to memory corruption (#534)
- Fixed an issue with filters linking to wrong targets, often with two sets
of links (#536)
- Fixed a crash in the endpoints policy that would show up when log messages
were enabled at level 3 or higher
WirePlumber 0.4.16
..................
Additions:
- Added a new "sm-objects" script that allows loading objects on demand
via metadata entries that describe the object to load; this can be used to
load pipewire modules, such as filters or network sources/sinks, on demand
- Added a mechanism to override device profile priorities in the configuration,
mainly as a way to re-prioritize Bluetooth codecs, but this also can be used
for other devices
- Added a mechanism in the endpoints policy to allow connecting filters
between a certain endpoint's virtual sink and the device sink; this is
specifically intended to allow plugging a filter-chain to act as equalizer
on the Multimedia endpoint
- Added wp_core_get_own_bound_id() method in WpCore
Changes:
- PipeWire 0.3.68 is now required
- policy-dsp now has the ability to hide hardware nodes behind the DSP sink
to prevent hardware misuse or damage
- JSON parsing in Lua now allows keys inside objects to be without quotes
- Added optional argument in the Lua JSON parse() method to limit recursions,
making it possible to partially parse a JSON object
- It is now possible to pass ``nil`` in Lua object constructors that expect an
optional properties object; previously, omitting the argument was the only
way to skip the properties
- The endpoints policy now marks the endpoint nodes as "passive" instead of
marking their links, adjusting for the behavior change in PipeWire 0.3.68
- Removed the "passive" property from si-standard-link, since only nodes are
marked as passive now
Fixes:
- Fixed the ``wpctl clear-default`` command to completely clear all the
default nodes state instead of only the last set default
- Reduced the amount of globals that initially match the interest in the
object manager
- Used an idle callback instead of pw_core_sync() in the object manager to
expose tmp globals
WirePlumber 0.4.15 WirePlumber 0.4.15
.................. ~~~~~~~~~~~~~~~~~~
Additions: Additions:
@ -824,6 +51,9 @@ Changes/Fixes:
- Added some missing `\since` annotations and made them show up in the - Added some missing `\since` annotations and made them show up in the
generated gobject-introspection file, to help bindings generators generated gobject-introspection file, to help bindings generators
Past releases
~~~~~~~~~~~~~
WirePlumber 0.4.14 WirePlumber 0.4.14
.................. ..................

View file

@ -7,6 +7,9 @@ WirePlumber
.. image:: https://scan.coverity.com/projects/21488/badge.svg .. image:: https://scan.coverity.com/projects/21488/badge.svg
:alt: Coverity Scan Build Status :alt: Coverity Scan Build Status
.. image:: https://img.shields.io/tokei/lines/gitlab.freedesktop.org/pipewire/wireplumber
:alt: Lines of code
.. image:: https://img.shields.io/badge/license-MIT-green .. image:: https://img.shields.io/badge/license-MIT-green
:alt: License :alt: License

View file

@ -1240,6 +1240,15 @@ HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80 HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this
# to YES can help to show when doxygen was last run and thus if the
# documentation is up to date.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = NO
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
# documentation will contain a main index with vertical navigation menus that # documentation will contain a main index with vertical navigation menus that
# are dynamically created via JavaScript. If disabled, the navigation index will # are dynamically created via JavaScript. If disabled, the navigation index will
@ -1534,6 +1543,17 @@ HTML_FORMULA_FORMAT = png
FORMULA_FONTSIZE = 10 FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
# Note that when changing this option you need to delete any form_*.png files in
# the HTML output directory before the changes have effect.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
FORMULA_TRANSPARENT = YES
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
# to create new LaTeX commands to be used in formulas as building blocks. See # to create new LaTeX commands to be used in formulas as building blocks. See
# the section "Including formulas" for details. # the section "Including formulas" for details.
@ -1845,6 +1865,14 @@ LATEX_HIDE_INDICES = NO
LATEX_BIB_STYLE = plain LATEX_BIB_STYLE = plain
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
# page will contain the date and time when the page was generated. Setting this
# to NO can help when comparing the output of multiple runs.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_TIMESTAMP = NO
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) # The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
# path from which the emoji images will be read. If a relative path is entered, # path from which the emoji images will be read. If a relative path is entered,
# it will be relative to the LATEX_OUTPUT directory. If left blank the # it will be relative to the LATEX_OUTPUT directory. If left blank the
@ -2237,6 +2265,23 @@ HAVE_DOT = YES
DOT_NUM_THREADS = 0 DOT_NUM_THREADS = 0
# When you want a differently looking font in the dot files that doxygen
# generates you can specify the font name using DOT_FONTNAME. You need to make
# sure dot is able to find the font, which can be done by putting it in a
# standard location or by setting the DOTFONTPATH environment variable or by
# setting DOT_FONTPATH to the directory containing the font.
# The default value is: Helvetica.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTNAME = Helvetica
# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
# dot graphs.
# Minimum value: 4, maximum value: 24, default value: 10.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTSIZE = 10
# By default doxygen will tell dot to use the default font as specified with # By default doxygen will tell dot to use the default font as specified with
# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set # DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
# the path where dot can find it using this tag. # the path where dot can find it using this tag.
@ -2473,6 +2518,18 @@ DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0 MAX_DOT_GRAPH_DEPTH = 0
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
# background. This is disabled by default, because dot on Windows does not seem
# to support this out of the box.
#
# Warning: Depending on the platform used, enabling this option may lead to
# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
# read).
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_TRANSPARENT = NO
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This # files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) support # makes dot run faster, but since only newer versions of dot (>1.8.10) support

View file

@ -1,15 +1,11 @@
# -- Project information ----------------------------------------------------- # -- Project information -----------------------------------------------------
project = 'WirePlumber' project = 'WirePlumber'
copyright = '2020-2025, Collabora & contributors' copyright = '2021, Collabora'
author = 'The WirePlumber Developers' author = 'Collabora'
release = '@VERSION@' release = '@VERSION@'
version = '@VERSION@' version = '@VERSION@'
# -- General configuration ---------------------------------------------------
smartquotes = False
# -- Breathe configuration --------------------------------------------------- # -- Breathe configuration ---------------------------------------------------
extensions = [ extensions = [
@ -47,9 +43,3 @@ html_css_files = ['custom.css']
graphviz_output_format = "svg" graphviz_output_format = "svg"
pygments_style = "friendly" pygments_style = "friendly"
# -- Options for manual page output -----------------------------------------
man_pages = [
('tools/wpctl', 'wpctl', 'WirePlumber Control CLI', ['The WirePlumber Developers'], 1)
]

View file

@ -130,7 +130,7 @@ class DoxygenProcess(object):
def __process_element(self, xml): def __process_element(self, xml):
s = "" s = ""
if xml.text and re.search(r'\S', xml.text): if xml.text and re.search('\S', xml.text):
s += xml.text s += xml.text
for n in xml.getchildren(): for n in xml.getchildren():
if n.tag == "emphasis": if n.tag == "emphasis":
@ -143,7 +143,7 @@ class DoxygenProcess(object):
s += " - " + self.__process_element(n) s += " - " + self.__process_element(n)
if n.tag == "para": if n.tag == "para":
p = self.__process_element(n) p = self.__process_element(n)
if re.search(r'\S', p): if re.search('\S', p):
s += p + "\n" s += p + "\n"
if n.tag == "ref": if n.tag == "ref":
s += n.text if n.text else "" s += n.text if n.text else ""
@ -168,7 +168,7 @@ class DoxygenProcess(object):
if n.tag == "htmlonly": if n.tag == "htmlonly":
s += "" s += ""
if n.tail: if n.tail:
if re.search(r'\S', n.tail): if re.search('\S', n.tail):
s += n.tail s += n.tail
if n.tag.startswith("param"): if n.tag.startswith("param"):
pass # parameters are handled separately in DoxyFunction::from_memberdef() pass # parameters are handled separately in DoxyFunction::from_memberdef()
@ -319,8 +319,6 @@ class DoxyFunction(DoxyElement):
d = normalize_text(d) d = normalize_text(d)
e = DoxyFunction(name, d) e = DoxyFunction(name, d)
if (xml.get("prot") == "private"):
e.extra = "(skip)"
e.add_brief(xml.find("briefdescription")) e.add_brief(xml.find("briefdescription"))
e.add_detail(xml.find("detaileddescription")) e.add_detail(xml.find("detaileddescription"))
for p in xml.xpath(".//detaileddescription/*/parameterlist[@kind='param']/parameteritem"): for p in xml.xpath(".//detaileddescription/*/parameterlist[@kind='param']/parameteritem"):

View file

@ -69,7 +69,6 @@ if build_doc
meson.current_source_dir()/'..'/'README.rst', meson.current_source_dir()/'..'/'README.rst',
meson.current_source_dir()/'..'/'NEWS.rst', meson.current_source_dir()/'..'/'NEWS.rst',
) )
sphinx_files += scripts_doc_files
subdir('rst') subdir('rst')
sphinx_conf_data = configuration_data() sphinx_conf_data = configuration_data()
@ -99,27 +98,7 @@ if build_doc
depends: [doxyxml_wp], depends: [doxyxml_wp],
output: 'html', output: 'html',
install: true, install: true,
install_dir: wireplumber_doc_dir, install_dir: get_option('datadir') / 'doc' / 'wireplumber',
build_by_default: true,
)
# Generate man pages directory with sphinx
custom_target('manpages',
command: [sphinx_p,
'-q', # quiet
'-E', # rebuild from scratch
'-b', 'man', # man page builder
'-d', '@PRIVATE_DIR@', # doctrees dir
'-c', '@OUTDIR@', # conf.py dir
'@CURRENT_SOURCE_DIR@/rst', # source dir
'@OUTDIR@', # output directory
],
depend_files: [
sphinx_conf, sphinx_files,
],
output: ['wpctl.1'],
install: true,
install_dir: get_option('mandir') / 'man1',
build_by_default: true, build_by_default: true,
) )
endif endif
@ -161,7 +140,7 @@ if build_gir
dependencies: [wp_dep, dummy_dep], dependencies: [wp_dep, dummy_dep],
namespace: 'Wp', namespace: 'Wp',
nsversion: wireplumber_api_version, nsversion: wireplumber_api_version,
export_packages: 'wireplumber-' + wireplumber_api_version, export_packages: 'wireplumber-0.4',
header: 'wp/wp.h', header: 'wp/wp.h',
sources: [wpenums_h, wp_gtkdoc_h, wp_lib_headers], sources: [wpenums_h, wp_gtkdoc_h, wp_lib_headers],
include_directories: [wpenums_include_dir], include_directories: [wpenums_include_dir],

View file

@ -1,4 +1,4 @@
.. _library_c_api: .. _library_root:
C API Documentation C API Documentation
=================== ===================
@ -23,8 +23,8 @@ C API Documentation
c_api/link_api.rst c_api/link_api.rst
c_api/device_api.rst c_api/device_api.rst
c_api/client_api.rst c_api/client_api.rst
c_api/permission_manager_api.rst
c_api/metadata_api.rst c_api/metadata_api.rst
c_api/endpoint_api.rst
c_api/spa_device_api.rst c_api/spa_device_api.rst
c_api/impl_node_api.rst c_api/impl_node_api.rst
c_api/impl_module_api.rst c_api/impl_module_api.rst
@ -34,10 +34,7 @@ C API Documentation
c_api/spa_pod_api.rst c_api/spa_pod_api.rst
c_api/plugin_api.rst c_api/plugin_api.rst
c_api/component_loader_api.rst c_api/component_loader_api.rst
c_api/settings_api.rst
c_api/conf_api.rst
c_api/session_item_api.rst c_api/session_item_api.rst
c_api/si_interfaces_api.rst c_api/si_interfaces_api.rst
c_api/si_factory_api.rst c_api/si_factory_api.rst
c_api/state_api.rst c_api/state_api.rst
c_api/base_dirs_api.rst

View file

@ -7,12 +7,14 @@ Component Loader
digraph inheritance { digraph inheritance {
rankdir=LR; rankdir=LR;
GInterface -> WpComponentLoader; GObject -> WpObject;
WpObject -> WpPlugin;
WpPlugin -> WpComponentLoader;
} }
.. doxygenstruct:: WpComponentLoader .. doxygenstruct:: WpComponentLoader
.. doxygenstruct:: _WpComponentLoaderInterface .. doxygenstruct:: _WpComponentLoaderClass
.. doxygengroup:: wpcomponentloader .. doxygengroup:: wpcomponentloader
:content-only: :content-only:

View file

@ -7,8 +7,7 @@ Core
digraph inheritance { digraph inheritance {
rankdir=LR; rankdir=LR;
GObject -> WpObject; GObject -> WpCore;
WpObject -> WpCore;
} }
.. doxygenstruct:: WpCore .. doxygenstruct:: WpCore

View file

@ -0,0 +1,24 @@
.. _endpoint_api:
PipeWire Endpoint
=================
.. graphviz::
:align: center
digraph inheritance {
rankdir=LR;
GObject -> WpObject;
WpObject -> WpProxy;
WpProxy -> WpGlobalProxy;
WpGlobalProxy -> WpEndpoint;
GInterface -> WpPipewireObject;
WpPipewireObject -> WpEndpoint;
WpEndpoint -> WpImplEndpoint;
}
.. doxygenstruct:: WpEndpoint
.. doxygenstruct:: WpImplEndpoint
.. doxygengroup:: wpendpoint
:content-only:

View file

@ -1,11 +1,10 @@
# you need to add here any files you add to the api directory as well # you need to add here any files you add to the api directory as well
sphinx_files += files( sphinx_files += files(
'base_dirs_api.rst',
'client_api.rst', 'client_api.rst',
'component_loader_api.rst', 'component_loader_api.rst',
'conf_api.rst',
'core_api.rst', 'core_api.rst',
'device_api.rst', 'device_api.rst',
'endpoint_api.rst',
'global_proxy_api.rst', 'global_proxy_api.rst',
'impl_module_api.rst', 'impl_module_api.rst',
'impl_node_api.rst', 'impl_node_api.rst',
@ -18,13 +17,11 @@ sphinx_files += files(
'obj_manager_api.rst', 'obj_manager_api.rst',
'object_api.rst', 'object_api.rst',
'pipewire_object_api.rst', 'pipewire_object_api.rst',
'permission_manager_api.rst',
'plugin_api.rst', 'plugin_api.rst',
'port_api.rst', 'port_api.rst',
'properties_api.rst', 'properties_api.rst',
'proxy_api.rst', 'proxy_api.rst',
'session_item_api.rst', 'session_item_api.rst',
'settings_api.rst',
'si_factory_api.rst', 'si_factory_api.rst',
'si_interfaces_api.rst', 'si_interfaces_api.rst',
'spa_device_api.rst', 'spa_device_api.rst',

View file

@ -7,7 +7,6 @@ PipeWire Metadata
digraph inheritance { digraph inheritance {
rankdir=LR; rankdir=LR;
GBoxed -> WpMetadataItem
GObject -> WpObject; GObject -> WpObject;
WpObject -> WpProxy; WpObject -> WpProxy;
WpProxy -> WpGlobalProxy; WpProxy -> WpGlobalProxy;
@ -15,8 +14,6 @@ PipeWire Metadata
WpMetadata-> WpImplMetadata; WpMetadata-> WpImplMetadata;
} }
.. doxygenstruct:: WpMetadataItem
.. doxygenstruct:: WpMetadata .. doxygenstruct:: WpMetadata
.. doxygenstruct:: WpImplMetadata .. doxygenstruct:: WpImplMetadata

View file

@ -7,12 +7,17 @@ Session Items Interfaces
digraph inheritance { digraph inheritance {
rankdir=LR; rankdir=LR;
GInterface -> WpSiEndpoint;
GInterface -> WpSiAdapter; GInterface -> WpSiAdapter;
GInterface -> WpSiLinkable; GInterface -> WpSiLinkable;
GInterface -> WpSiLink; GInterface -> WpSiLink;
GInterface -> WpSiAcquisition; GInterface -> WpSiAcquisition;
} }
.. doxygenstruct:: WpSiEndpoint
.. doxygenstruct:: _WpSiEndpointInterface
.. doxygenstruct:: WpSiAdapter .. doxygenstruct:: WpSiAdapter
.. doxygenstruct:: _WpSiAdapterInterface .. doxygenstruct:: _WpSiAdapterInterface

View file

@ -1,4 +1,4 @@
.. _resources_community: .. _community:
Community Resources Community Resources
=================== ===================

View file

@ -0,0 +1,34 @@
.. _configuration:
Configuration
=============
WirePlumber is a heavily modular daemon. By itself, it doesn't do anything
except load the configured modules. All the rest of the logic is implemented
inside those modules.
Modular design ensures that it is possible to swap the implementation of
specific functionality without having to re-implement the rest of it, allowing
flexibility on target-sensitive parts, such as policy management and
making use of non-standard hardware.
At startup, WirePlumber first reads its **main** configuration file.
This file configures the operation context (properties of the daemon,
modules to be loaded, etc). This file may also specify additional, secondary
configuration files which will be loaded as well at the time of parsing the
main file.
All files and modules are specified relative to their standard search locations,
which are documented later in this chapter.
.. toctree::
:maxdepth: 1
configuration/locations.rst
configuration/main.rst
configuration/config_lua.rst
configuration/multi_instance.rst
configuration/alsa.rst
configuration/bluetooth.rst
configuration/policy.rst
configuration/access.rst

View file

@ -0,0 +1,63 @@
.. _config_access:
Access configuration
====================
main.lua.d/50-default-access-config.lua
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Using a similar format as the :ref:`ALSA monitor <config_alsa>`, this
configuration file is charged to configure the client objects created by
PipeWire.
* *default_access.properties*
A Lua object that contains generic client configuration properties in the
for of key pairs.
Example:
.. code-block:: lua
default_access.properties = {
["enable-flatpak-portal"] = true,
}
The above example sets to ``true`` the ``enable-flatpak-portal`` property.
The list of valid properties are:
.. code-block:: lua
["enable-flatpak-portal"] = true,
Whether to enable the flatpak portal or not.
* *default_access.rules*
This is a Lua array that can contain objects with rules for a client object.
Those Lua objects have 2 properties. Similar to the
:ref:`ALSA configuration <config_alsa>`, the first property is ``matches``,
which allow users to define rules to match a client object.
The second property is ``default_permissions``, and it is used to set
permissions on the matched client object.
Example:
.. code-block:: lua
{
matches = {
{
{ "pipewire.access", "=", "flatpak" },
},
},
default_permissions = "rx",
}
This grants read and execute permissions to all clients that have the
``pipewire.access`` property set to ``flatpak``.
Possible permissions are any combination of ``r``, ``w`` and ``x`` for read,
write and execute; or ``all`` for all kind of permissions.

View file

@ -0,0 +1,478 @@
.. _config_alsa:
ALSA configuration
==================
Modifying the default configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ALSA devices are created and managed by the session manager with the *alsa.lua*
monitor script. In the default configuration, this script is loaded by
``main.lua.d/30-alsa-monitor.lua``, which also specifies an ``alsa_monitor``
global table that can be filled in with properties and rules in subsequent
config files. By default, these are filled in ``main.lua.d/50-alsa-config.lua``.
The ``alsa_monitor`` global table has 2 sub-tables:
* *alsa_monitor.properties*
This is a simple Lua table that has key value pairs used as properties.
Example:
.. code-block:: lua
alsa_monitor.properties = {
["alsa.jack-device"] = false,
["alsa.reserve"] = true,
}
The above example will configure the ALSA monitor to not enable the JACK
device, and do ALSA device reservation using the mentioned DBus interface.
A list of valid properties are:
.. code-block:: lua
["alsa.jack-device"] = false
Creates a JACK device if set to ``true``. 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.
.. code-block:: lua
["alsa.reserve"] = true
Reserve ALSA devices via *org.freedesktop.ReserveDevice1* on D-Bus.
.. code-block:: lua
["alsa.reserve.priority"] = -20
The used ALSA device reservation priority.
.. code-block:: lua
["alsa.reserve.application-name"] = "WirePlumber"
The used ALSA device reservation application name.
* *alsa_monitor.rules*
This is a Lua array that can contain objects with rules for a device or node.
Those objects have 2 properties. The first one is ``matches``, which allow
users to define rules to match a device or node. The second property is
``apply_properties``, and it is used to apply properties on the matched object.
Example:
.. code-block:: lua
alsa_monitor.rules = {
matches = {
{
{ "device.name", "matches", "alsa_card.*" },
},
},
apply_properties = {
["api.alsa.use-acp"] = true,
}
}
This sets the API ALSA use ACP property to all devices with a name that
matches the ``alsa_card.*`` pattern.
The ``matches`` section is an array of arrays. On the first level, the rules
are ORed together, so any rule match is going to apply the properties. On
the second level, the rules are merged with AND, so they must all match.
Example:
.. code-block:: lua
matches = {
{
{ "node.name", "matches", "alsa_input.*" },
{ "alsa.driver_name", "equals", "snd_hda_intel" },
},
{
{ "node.name", "matches", "alsa_output.*" },
},
},
This is equivalent to the following logic, in pseudocode:
.. code-block::
if ("node.name" MATCHES "alsa_input.*" AND "alsa.driver_name" EQUALS "snd_hda_intel" )
OR
("node.name" MATCHES "alsa_output.*")
then
... apply the properties ...
end
As you can notice, the individual rules are themselves also lua arrays. The
first element is a property name (ex "node.name"), the second element is a
verb and the third element is an expected value, which depends on the verb.
Internally, this uses the ``Constraint`` API, which is documented in the
:ref:`Object Interet API <lua_object_interest_api>` section. All the verbs
that you can use on ``Constraint`` are also allowed here.
.. note::
When using the "matches" verb, the values are not complete regular expressions.
They are wildcard patterns, which means that '*' matches an arbitrary,
possibly empty, string and '?' matches an arbitrary character.
All the possible properties that you can apply to devices and nodes of the
ALSA monitor are described in the sections below.
Device properties
^^^^^^^^^^^^^^^^^
PipeWire devices correspond to the ALSA cards.
The following properties can be configured on devices created by the monitor:
.. code-block:: lua
["api.alsa.use-acp"] = true
Use the ACP (alsa card profile) code to manage the device. This will probe the
device and configure the available profiles, ports and mixer settings. The
code to do this is taken directly from PulseAudio and provides devices that
look and feel exactly like the PulseAudio devices.
.. code-block:: lua
["api.alsa.use-ucm"] = true
By default, the UCM configuration is used when it is available for your device.
With this option you can disable this and use the ACP profiles instead.
.. code-block:: lua
["api.alsa.soft-mixer"] = false
Setting this option to true will disable the hardware mixer for volume control
and mute. All volume handling will then use software volume and mute, leaving
the hardware mixer untouched. The hardware mixer will still be used to mute
unused audio paths in the device.
.. code-block:: lua
["api.alsa.ignore-dB"] = false
Setting this option to true will ignore the decibel setting configured by the
driver. Use this when the driver reports wrong settings.
.. code-block:: lua
["device.profile-set"] = "profileset-name"
This option can be used to select a custom profile set name for the device.
Usually this is configured in Udev rules but it can also be specified here.
.. code-block:: lua
["device.profile"] = "default profile name"
The default active profile name.
.. code-block:: lua
["api.acp.auto-profile"] = false
Automatically select the best profile for the device. Normally this option is
disabled because the session manager will manage the profile of the device.
The session manager can save and load previously selected profiles. Enable
this if your session manager does not handle this feature.
.. code-block:: lua
["api.acp.auto-port"] = false
Automatically select the highest priority port that is available. This is by
default disabled because the session manager handles the task of selecting and
restoring ports. It can, for example, restore previously saved volumes. Enable
this here when the session manager does not handle port restore.
.. code-block:: lua
["api.acp.probe-rate"] = 48000
Sets the samplerate used for probing the ALSA devices and collecting the profiles
and ports.
.. code-block:: lua
["api.acp.pro-channels"] = 64
Sets the number of channels to use when probing the Pro Audio profile. Normally,
the maximum amount of channels will be used but with this setting this can be
reduced, which can make it possible to use other samplerates on some devices.
Some of the other properties that might be configured on devices:
.. code-block:: lua
["device.nick"] = "My Device",
["device.description"] = "My Device"
``device.description`` will show up in most apps when a device name is shown.
Node Properties
^^^^^^^^^^^^^^^
Nodes are sinks or sources in the PipeWire graph. They correspond to the ALSA
devices. In addition to the generic stream node configuration options, there are
some alsa specific options as well:
.. code-block:: lua
["priority.driver"] = 2000
This configures the node driver priority. Nodes with higher priority will be
used as a driver in the graph. Other nodes with lower priority will have to
resample to the driver node when they are joined in the same graph. The default
value is set based on some heuristics.
.. code-block:: lua
["priority.session"] = 1200
This configures the priority of the node when selecting a default node.
Higher priority nodes will be more likely candidates as a default node.
.. note::
By default, sources have a ``priority.session`` value around 1600-2000 and
sinks have a value around 600-1000. If you are increasing the priority of a
sink, it is **not advised** to use a value higher than 1500, as it may cause
a sink's monitor to be selected as a default source.
.. code-block:: lua
["node.pause-on-idle"] = false
Pause-on-idle will stop the node when nothing is linked to it anymore.
This is by default false because some devices cause a pop when they are
opened/closed. The node will, normally, pause and suspend after a timeout
(see suspend-node.lua).
.. code-block:: lua
["session.suspend-timeout-seconds"] = 5 -- 0 disables suspend
This option configures a different suspend timeout on the node.
By default this is 5 seconds. For some devices (HiFi amplifiers, for example)
it might make sense to set a higher timeout because they might require some
time to restart after being idle.
A value of 0 disables suspend for a node and will leave the ALSA device busy.
The device can then manually be suspended with ``pactl suspend-sink|source``.
**The following properties can be used to configure the format used by the
ALSA device:**
.. code-block:: lua
["audio.format"] = "S16LE"
By default, PipeWire will use a 32 bits sample format but a different format
can be set here.
The Audio rate of a device can be set here:
.. code-block:: lua
["audio.rate"] = 44100
By default, the ALSA device will be configured with the same samplerate as the
global graph. If this is not supported, or a custom values is set here,
resampling will be used to match the graph rate.
.. code-block:: lua
["audio.channels"] = 2
["audio.position"] = "FL,FR"
By default the channels and their position are determined by the selected
Device profile. You can override this setting here and optionally swap or
reconfigure the channel positions.
.. code-block:: lua
["api.alsa.use-chmap"] = false
Use the channel map as reported by the driver. This is disabled by default
because it is often wrong and the ACP code handles this better.
.. code-block:: lua
["api.alsa.disable-mmap"] = true
PipeWire will by default access the memory of the device using mmap.
This can be disabled and force the usage of the slower read and write access
modes in case the mmap support of the device is not working properly.
.. code-block:: lua
["channelmix.normalize"] = true
Makes sure that during such mixing & resampling original 0 dB level is
preserved, so nothing sounds wildly quieter/louder.
.. code-block:: lua
["channelmix.mix-lfe"] = true
Creates "center" channel for X.0 recordings from front stereo on X.1 setups and
pushes some low-frequency/bass from "center" from X.1 recordings into front
stereo on X.0 setups.
.. code-block:: lua
["monitor.channel-volumes"] = false
By default, the volume of the sink/source does not influence the volume on the
monitor ports. Set this option to true to change this. PulseAudio has
inconsistent behaviour regarding this option, it applies channel-volumes only
when the sink/source is using software volumes.
ALSA buffer properties
^^^^^^^^^^^^^^^^^^^^^^
PipeWire uses a timer to consume and produce samples to/from ALSA devices.
After every timeout, it queries the device hardware pointers of the device and
uses this information to set a new timeout. See also this example program.
By default, PipeWire handles ALSA batch devices differently from non-batch
devices. Batch devices only get their hardware pointers updated after each
hardware interrupt. Non-batch devices get updates independent of the interrupt.
This means that for batch devices we need to set the interrupt at a sufficiently
high frequency (at the cost of CPU usage) while for non-batch devices we want to
set the interrupt frequency as low as possible (to save CPU).
For batch devices we also need to take the extra buffering into account caused
by the delayed updates of the hardware pointers.
Most USB devices are batch devices and will be handled as such by PipeWire by
default.
There are 2 tunable parameters to control the buffering and timeouts in a
device
.. code-block:: lua
["api.alsa.period-size"] = 1024
This sets the device interrupt to every period-size samples for non-batch
devices and to half of this for batch devices. For batch devices, the other
half of the period-size is used as extra buffering to compensate for the delayed
update. So, for batch devices, there is an additional period-size/2 delay.
It makes sense to lower the period-size for batch devices to reduce this delay.
.. code-block:: lua
["api.alsa.headroom"] = 0
This adds extra delay between the hardware pointers and software pointers.
In most cases this can be set to 0. For very bad devices or emulated devices
(like in a VM) it might be necessary to increase the headroom value.
In summary, this is the overview of buffering and timings:
============== ========================================== =========
Property Batch Non-Batch
============== ========================================== =========
IRQ Frequency api.alsa.period-size/2 api.alsa.period-size
Extra Delay api.alsa.headroom + api.alsa.period-size/2 api.alsa.headroom
============== ========================================== =========
It is possible to disable the batch device tweaks with:
.. code-block:: lua
["api.alsa.disable-batch"] = true
It removes the extra delay added of period-size/2 if the device can support this.
For batch devices it is also a good idea to lower the period-size
(and increase the IRQ frequency) to get smaller batch updates and lower latency.
ALSA extra latency properties
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Extra internal delay in the DAC and ADC converters of the device itself can be
set with the ``latency.internal.*`` properties:
.. code-block:: lua
["latency.internal.rate"] = 256
["latency.internal.ns"] = 0
You can configure a latency in samples (relative to rate with
``latency.internal.rate``) or in nanoseconds (``latency.internal.ns``).
This value will be added to the total reported latency by the node of the device.
You can use a tool like ``jack_iodelay`` to get the number of samples of
internal latency of your device.
This property is also adjustable at runtime with the ``ProcessLatency`` param.
You will need to find the id of the Node you want to change. For example:
Query the current internal latency of an ALSA node with id 58:
.. code-block:: console
$ pw-cli e 58 ProcessLatency
Object: size 80, type Spa:Pod:Object:Param:ProcessLatency (262156), id Spa:Enum:ParamId:ProcessLatency (16)
Prop: key Spa:Pod:Object:Param:ProcessLatency:quantum (1), flags 00000000
Float 0.000000
Prop: key Spa:Pod:Object:Param:ProcessLatency:rate (2), flags 00000000
Int 0
Prop: key Spa:Pod:Object:Param:ProcessLatency:ns (3), flags 00000000
Long 0
Set the internal latency to 256 samples:
.. code-block:: console
$ pw-cli s 58 ProcessLatency '{ rate = 256 }'
Object: size 32, type Spa:Pod:Object:Param:ProcessLatency (262156), id Spa:Enum:ParamId:ProcessLatency (16)
Prop: key Spa:Pod:Object:Param:ProcessLatency:rate (2), flags 00000000
Int 256
remote 0 node 58 changed
remote 0 port 70 changed
remote 0 port 72 changed
remote 0 port 74 changed
remote 0 port 76 changed
Startup tweaks
^^^^^^^^^^^^^^
Some devices need some time before they can report accurate hardware pointer
positions. In those cases, an extra start delay can be added that is used to
compensate for this startup delay:
.. code-block:: lua
["api.alsa.start-delay"] = 0
It is unsure when this tunable should be used.
IEC958 (S/PDIF) passthrough
^^^^^^^^^^^^^^^^^^^^^^^^^^^
S/PDIF passthrough will only be enabled when the accepted codecs are configured
on the ALSA device.
This can be done in 3 different ways:
1. Use pavucontrol and toggle the codecs in the output advanced section
2. Modify the ``["iec958.codecs"] = "[ PCM DTS AC3 MPEG MPEG2-AAC EAC3 TrueHD DTS-HD ]"``
node property to something.
3. Use ``pw-cli s <node-id> Props '{ iec958Codecs : [ PCM ] }'`` to modify
the codecs at runtime.

View file

@ -0,0 +1,160 @@
.. _config_bluetooth:
Bluetooth configuration
=======================
Using the same format as the :ref:`ALSA monitor <config_alsa>`, the
configuration file ``bluetooth.lua.d/50-bluez-config.lua`` is charged
to configure the Bluetooth devices and nodes created by WirePlumber.
* *bluez_monitor.properties*
A Lua object that contains generic client configuration properties in the
for of key pairs.
Example:
.. code-block:: lua
bluez_monitor.properties = {
["bluez5.enable-msbc"] = true,
}
This example will enable the MSBC codec in connected Bluetooth devices that
support it.
The list of valid properties are:
.. code-block:: lua
["bluez5.enable-sbc-xq"] = true
Enables the SBC-XQ codec in connected Blueooth devices that support it
.. code-block:: lua
["bluez5.enable-msbc"] = true
Enables the MSBC codec in connected Blueooth devices that support it
.. code-block:: lua
["bluez5.enable-hw-volume"] = true
Enables hardware volume controls in Bluetooth devices that support it
.. code-block:: lua
["bluez5.headset-roles"] = "[ hsp_hs hsp_ag hfp_hf hfp_ag ]"
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) and ``hfp_ag`` (HFP Audio Gateway)
.. code-block:: lua
["bluez5.codecs"] = "[ sbc sbc_xq aac ]"
Enables ``sbc``, ``sbc_zq`` and ``aac`` A2DP codecs.
Supported codecs: ``sbc``, ``sbc_xq``, ``aac``, ``ldac``, ``aptx``,
``aptx_hd``, ``aptx_ll``, ``aptx_ll_duplex``, ``faststream``, ``faststream_duplex``.
All codecs are supported by default.
.. code-block:: lua
["bluez5.hfphsp-backend"] = "native"
HFP/HSP backend (default: native). Available values: ``any``, ``none``,
``hsphfpd``, ``ofono`` or ``native``.
.. code-block:: lua
["bluez5.default.rate"] = 48000
The bluetooth default audio rate.
.. code-block:: lua
["bluez5.default.channels"] = 2
The bluetooth default number of channels.
* *bluez_monitor.rules*
Like in the :ref:`ALSA configuration <config_alsa>`, this is a Lua array that
can contain objects with rules for a Bluetooth device or node.
Those objects have 2 properties. The first one is ``matches``, which allows
users to define rules to match a Bluetooth device or node.
The second property is ``apply_properties``, and it is used to apply
properties on the matched Bluetooth device or node.
Example:
.. code-block:: lua
{
matches = {
{
{ "device.name", "matches", "bluez_card.*" },
},
},
apply_properties = {
["bluez5.auto-connect"] = "[ hfp_hf hsp_hs a2dp_sink ]"
}
}
This will set the auto-connect property to ``hfp_hf``, ``hsp_hs`` and ``a2dp_sink``
on bluetooth devices whose name matches the ``bluez_card.*`` pattern.
A list of valid properties are:
.. code-block:: lua
["bluez5.auto-connect"] = "[ hfp_hf hsp_hs a2dp_sink ]"
Auto-connect device profiles on start up or when only partial profiles have
connected. Disabled by default if the property is not specified.
Supported values are: ``hfp_hf``, ``hsp_hs``, ``a2dp_sink``, ``hfp_ag``,
``hsp_ag`` and ``a2dp_source``.
.. code-block:: lua
["bluez5.hw-volume"] = "[ hfp_ag hsp_ag a2dp_source ]"
Hardware volume controls (default: ``hfp_ag``, ``hsp_ag``, and ``a2dp_source``)
Supported values are: ``hfp_hf``, ``hsp_hs``, ``a2dp_sink``, ``hfp_ag``,
``hsp_ag`` and ``a2dp_source``.
.. code-block:: lua
["bluez5.a2dp.ldac.quality"] = "auto"
LDAC encoding quality.
Available values: ``auto`` (Adaptive Bitrate, default),
``hq`` (High Quality, 990/909kbps), ``sq`` (Standard Quality, 660/606kbps) and
``mq`` (Mobile use Quality, 330/303kbps).
.. code-block:: lua
["bluez5.a2dp.aac.bitratemode"] = 0
AAC variable bitrate mode.
Available values: 0 (cbr, default), 1-5 (quality level).
.. code-block:: lua
["device.profile"] = "a2dp-sink"
Profile connected first.
Available values: ``a2dp-sink`` (default) or ``headset-head-unit``.

View file

@ -0,0 +1,185 @@
.. _config_lua:
Lua Configuration Files
=======================
Lua configuration files are similar to the main configuration file, but they
leverage the Lua language to enable advanced configuration of module arguments
and allow split-file configuration.
There is only one global section that WirePlumber reads from these files: the
**components** table. This table is equivalent to the **context.components**
object on the main configuration file. Its purpose is to list components that
WirePlumber should load on startup.
Every line on the **components** table should be another table that contains
information about the loaded component::
{
"component-name",
type = "component-type",
args = { additional arguments },
optional = true/false,
}
* **component-name**: Should be the name of the component to load
(ex. *"libwireplumber-module-mixer-api"*).
* **component-type**: Should be the type of the component.
Valid component types include:
* ``module``: A WirePlumber shared object module.
* ``script/lua``: A WirePlumber Lua script.
* ``pw_module``: A PipeWire shared object module (loaded on WirePlumber,
not on the PipeWire daemon).
* **args**: Is an optional table that can contain additional arguments to be
passed down to the module or script. Scripts can retrieve these arguments
by declaring a line that reads ``local config = ...`` at the top of the script.
Modules receive these arguments as a GVariant ``a{sv}`` table.
* **optional**: Is a boolean value that specifies whether loading of this
component is optional. The default value is ``false``. If set to ``true``,
then WirePlumber will not fail loading if the component is not found.
Split-File Configuration
------------------------
When a Lua configuration file is loaded, the engine also looks for additional
files in a directory that has the same name as the configuration file and a
``.d`` suffix.
A Lua directory can contain a list of Lua configuration files. Those files are
loaded alphabetically by filename so that user can control the order in which
Lua configuration files are executed.
Lua files in the directory are always loaded *after* the configuration file
that is out of the directory. However, it is perfectly valid to not have any
configuration file out of the directory.
Example hierarchy with files both in and out of the directory
(in the order of loading)::
config.lua
config.lua.d/00-functions.lua
config.lua.d/01-alsa.lua
config.lua.d/10-policy.lua
config.lua.d/99-misc.lua
Example hierarchy with files only in the directory
(in the order of loading)::
config.lua.d/00-functions.lua
config.lua.d/01-alsa.lua
config.lua.d/10-policy.lua
config.lua.d/99-misc.lua
Example of a file using alsa_monitor.rules in a split-file configuration:
.. code-block:: lua
table.insert (alsa_monitor.rules, {
matches = {
{
{ "device.name", "matches", "alsa_card.*" },
},
},
apply_properties = {
["api.alsa.use-acp"] = true,
}
})
Multi-Path Merging
------------------
WirePlumber looks for configuration files in 3 different places, as described
in the :ref:`Locations of files <config_locations>` section. When a split-file
configuration scheme is used, files will be merged from these different locations.
For example, consider these files exist on the filesystem::
/usr/share/wireplumber/config.lua.d/00-functions.lua
/usr/share/wireplumber/config.lua.d/01-alsa.lua
/usr/share/wireplumber/config.lua.d/10-policy.lua
/usr/share/wireplumber/config.lua.d/99-misc.lua
...
/etc/wireplumber/config.lua.d/01-alsa.lua
...
/home/user/.config/wireplumber/config.lua.d/11-policy-extras.lua
In this case, loading ``config.lua`` will result in loading these files
(in this order)::
/usr/share/wireplumber/config.lua.d/00-functions.lua
/etc/wireplumber/config.lua.d/01-alsa.lua
/usr/share/wireplumber/config.lua.d/10-policy.lua
/home/user/.config/wireplumber/config.lua.d/11-policy-extras.lua
/usr/share/wireplumber/config.lua.d/99-misc.lua
This is useful to keep the default configuration in /usr and override it
with host-specific and user-specific parts in /etc and /home respectively.
As an exception to this rule, if the configuration path is overridden with
the ``WIREPLUMBER_CONFIG_DIR`` environment variable, then configuration files
will only be loaded from this path and no merging will happen.
Functions
---------
Because of the nature of these files (they are scripts!), it is more convenient
to manage the **components** table through functions. In the default
configuration files shipped with WirePlumber, there is a file called
``00-functions.lua`` that defines some helper functions to load components.
When loading components through these functions, *duplicate calls are ignored*,
so it is possible to call a function to load a specific component multiple times
and it will only be loaded once.
.. function:: load_module(module, args)
Loads a WirePlumber shared object module.
:param string module: the module name, without the "libwireplumber-module-"
prefix (ex specify "mixer-api" to load "libwireplumber-module-mixer-api")
:param table args: optional module arguments table
.. function:: load_optional_module(module, args)
Loads an optional WirePlumber shared object module. Optional in this case
means that if the module is not present on the filesystem, it will be ignored.
:param string module: the module name, without the "libwireplumber-module-"
prefix (ex specify "mixer-api" to load "libwireplumber-module-mixer-api")
:param table args: optional module arguments table
.. function:: load_pw_module(module)
Loads a PipeWire shared object module
:param string module: the module name, without the "libpipewire-module-"
prefix (ex specify "adapter" to load "libpipewire-module-adapter")
.. function:: load_script(script, args)
Loads a Lua script (a functionality script, not a lua configuration file)
:param string script: the script's filename (ex. "policy-node.lua")
:param table args: optional script arguments table
.. function:: load_monitor(monitor, args)
Loads a Lua monitor script. Monitors are scripts found in the ``monitors/``
directory and their purpose is to monitor and load devices.
:param string monitor: the scripts's name without the directory or the .lua
extension (ex. "alsa" will load "monitors/alsa.lua")
:param table args: optional script arguments table
.. function:: load_access(access, args)
Loads a Lua access script. Access scripts are ones found in the ``access/``
directory and their purpose is to manage application permissions.
:param string access: the scripts's name without the directory or the .lua
extension (ex. "flatpak" will load "access/access-flatpak.lua")
:param table args: optional script arguments table

View file

@ -0,0 +1,94 @@
.. _config_locations:
Locations of files
==================
Location of configuration files
-------------------------------
WirePlumber's default locations of its configuration files are determined at
compile time by the build system. Typically, those end up being
``$XDG_CONFIG_DIR/wireplumber``, ``/etc/wireplumber``, and
``/usr/share/wireplumber``, in that order of priority.
In more detail, the latter two are controlled by the ``--sysconfdir`` and ``--datadir``
meson options. When those are set to an absolute path, such as ``/etc``, the
location of the configuration files is set to be ``$sysconfdir/wireplumber``.
When set to a relative path, such as ``etc``, then the installation prefix (``--prefix``)
is prepended to the path: ``$prefix/$sysconfdir/wireplumber``
The three locations are intended for custom user configuration,
host-specific configuration and distribution-provided configuration,
respectively. At runtime, WirePlumber will search the directories
for the highest-priority directory to contain the needed configuration file.
This allows a user or system administrator to easily override the distribution
provided configuration files by placing an equally named file in the respective
directory.
It is also possible to override the configuration directory by setting the
``WIREPLUMBER_CONFIG_DIR`` environment variable::
WIREPLUMBER_CONFIG_DIR=src/config wireplumber
If ``WIREPLUMBER_CONFIG_DIR`` is set, the default locations are ignored and
configuration files are *only* looked up in this directory.
Location of scripts
-------------------
WirePlumber's default locations of its scripts are the same ones as for the
configuration files, but with the ``scripts`` directory appended.
Typically, these end up being ``$XDG_CONFIG_DIR/wireplumber/scripts``,
``/etc/wireplumber/scripts``, and ``/usr/share/wireplumber/scripts``,
in that order of priority.
The three locations are intended for custom user scripts,
host-specific scripts and distribution-provided scripts, respectively.
At runtime, WirePlumber will search the directories for the highest-priority
directory to contain the needed script.
It is also possible to override the scripts directory by setting the
``WIREPLUMBER_DATA_DIR`` environment variable::
WIREPLUMBER_DATA_DIR=src wireplumber
The "data" directory is a somewhat more generic path that may be used for
other kinds of data files in the future. For scripts, WirePlumber still expects
to find a ``scripts`` subdirectory in this "data" directory, so in the above
example the scripts would be in ``src/scripts``.
If ``WIREPLUMBER_DATA_DIR`` is set, the default locations are ignored and
scripts are *only* looked up in this directory.
Location of modules
-------------------
WirePlumber modules
^^^^^^^^^^^^^^^^^^^
Like with configuration files, WirePlumber's default location of its modules is
determined at compile time by the build system. Typically, it ends up being
``/usr/lib/wireplumber-0.4`` (or ``/usr/lib/<arch-triplet>/wireplumber-0.4`` on
multiarch systems)
In more detail, this is controlled by the ``--libdir`` meson option. When
this is set to an absolute path, such as ``/lib``, the location of the
modules is set to be ``$libdir/wireplumber-$abi_version``. When this is set
to a relative path, such as ``lib``, then the installation prefix (``--prefix``)
is prepended to the path: ``$prefix/$libdir/wireplumber-$abi_version``.
It is possible to override this directory at runtime by setting the
``WIREPLUMBER_MODULE_DIR`` environment variable::
WIREPLUMBER_MODULE_DIR=build/modules wireplumber
PipeWire and SPA modules
^^^^^^^^^^^^^^^^^^^^^^^^
PipeWire and SPA modules are not loaded from the same location as WirePlumber's
modules. They are loaded from the location that PipeWire loads them.
It is also possible to override these locations by using environment variables:
``SPA_PLUGIN_DIR`` and ``PIPEWIRE_MODULE_DIR``. For more details, refer to
PipeWire's documentation.

View file

@ -0,0 +1,126 @@
.. _config_main:
Main configuration file
=======================
The main configuration file is by default called ``wireplumber.conf``. This can
be changed on the command line by passing the ``--config-file`` or ``-c`` option::
wireplumber --config-file=bluetooth.conf
The ``--config-file`` option is useful to run multiple instances of wireplumber
that do separate tasks each. For more information on this subject, see the
:ref:`Multiple Instances <config_multi_instance>` section.
The format of this configuration file is the variant of JSON that is also
used in PipeWire configuration files. Note that this is subject to change
in the future.
All sections are essentially JSON objects. Lines starting with *#* are treated
as comments and ignored. The list of all possible section JSON objects are:
* *context.properties*
Used to define properties to configure the PipeWire context and some modules.
Example::
context.properties = {
application.name = WirePlumber
log.level = 2
}
This sets the daemon's name to *WirePlumber* and the log level to *2*, which
only displays errors and warnings. See the
:ref:`Debug Logging <logging>` section for more details.
* *context.spa-libs*
Used to find spa factory names. It maps a spa factory name regular expression
to a library name that should contain that factory. The object property names
are the regular expression, and the object property values are the actual
library name::
<factory-name regex> = <library-name>
Example::
context.spa-libs = {
api.alsa.* = alsa/libspa-alsa
audio.convert.* = audioconvert/libspa-audioconvert
}
In this example, we instruct wireplumber to only any *api.alsa.** factory name
from the *libspa-alsa* library, and also any *audio.convert.** factory name
from the *libspa-audioconvert* library.
* *context.modules*
Used to load PipeWire modules. This does not affect the PipeWire daemon by any
means. It exists simply to allow loading *libpipewire* modules in the PipeWire
core that runs inside WirePlumber. This is usually useful to load PipeWire
protocol extensions, so that you can export custom objects to PipeWire and
other clients.
Users can also pass key-value pairs if the specific module has arguments, and
a combination of 2 flags: ``ifexists`` flag is given, the module is ignored when
not found; if ``nofail`` is given, module initialization failures are ignored::
{
name = <module-name>
[ args = { <key> = <value> ... } ]
[ flags = [ [ ifexists ] [ nofail ] ]
}
Example::
context.modules = [
{ name = libpipewire-module-adapter }
{
name = libpipewire-module-metadata,
flags = [ ifexists ]
}
]
The above example loads both PipeWire adapter and metadata modules. The
metadata module will be ignored if not found because of its ``ifexists`` flag.
* *context.components*
Used to load WirePlumber components. Components can be either WirePlumber
modules written in C, WirePlumber scripts or other configuration
files::
{ name = <component-name>, type = <component-type> }
Valid component types include:
* ``module``: A WirePlumber shared object module
* ``script/lua``: A WirePlumber Lua script
(requires ``libwireplumber-module-lua-scripting``)
* ``config/lua``: A WirePlumber Lua configuration file
(requires ``libwireplumber-module-lua-scripting``)
Example::
context.components = [
{ name = libwireplumber-module-lua-scripting, type = module }
{ name = main.lua, type = config/lua }
]
This will load the WirePlumber lua-scripting module, dynamically, and then
it will also load any components specified in the ``main.lua`` file.
.. note::
When loading lua configuration files, WirePlumber will also look for
additional files in the directory suffixed with ``.d`` and will load
all of them as well. For example, loading ``example.lua`` will also load
any ``.lua`` files under ``example.lua.d/``. In addition, the presence of the
main file is optional, so it is valid to specify ``example.lua`` in the
component name, while ``example.lua`` doesn't exist, but ``example.lua.d/``
exists instead and has ``.lua`` files to load.
For more information about lua configuration files, see the
:ref:`Lua configuration files <config_lua>` section.

View file

@ -0,0 +1,11 @@
# you need to add here any files you add to the toc directory as well
sphinx_files += files(
'locations.rst',
'main.rst',
'config_lua.rst',
'multi_instance.rst',
'alsa.rst',
'bluetooth.rst',
'policy.rst',
'access.rst',
)

View file

@ -0,0 +1,45 @@
.. _config_multi_instance:
Running multiple instances
==========================
WirePlumber has the ability to run either as a single instance daemon or as
multiple instances, meaning that there can be multiple processes, each one
doing a different task.
In the default configuration, both setups are supported. The default is to run
in single-instance mode.
In single-instance mode, WirePlumber reads ``wireplumber.conf``, which is the
default configuration file, and from there it loads ``main.lua``, ``policy.lua``
and ``bluetooth.lua``, which are lua configuration files (deployed as directories)
that enable all the relevant functionality.
In multi-instance mode, WirePlumber is meant to be started with the
``--config-file`` command line option 3 times:
.. code-block:: console
$ wireplumber --config-file=main.conf
$ wireplumber --config-file=policy.conf
$ wireplumber --config-file=bluetooth.conf
That loads one process which reads ``main.conf``, which then loads ``main.lua``
and enables core functionality. Then another process that reads ``policy.conf``,
which then loads ``policy.lua`` and enables policy functionality... and so on.
To make this easier to work with, a template systemd unit is provided, which is
meant to be started with the name of the main configuration file as a
template argument:
.. code-block:: console
$ systemctl --user disable wireplumber # disable the single instance
$ systemctl --user enable wireplumber@main
$ systemctl --user enable wireplumber@policy
$ systemctl --user enable wireplumber@bluetooth
It is obviously possible to start as many instances as desired, with manually
crafted configuration files, as long as it is ensured that these instances
serve a different purpose and they do not conflict with each other.

View file

@ -0,0 +1,116 @@
.. _config_policy:
Policy Configuration
====================
policy.lua.d/10-default-policy.lua
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This file contains generic default policy properties that can be configured.
* *default_policy.policy*
This is a Lua object that contains several properties that change the
behavior of the default WirePlumber policy.
Example:
.. code-block:: lua
default_policy.policy = {
["move"] = true,
}
The above example will set the ``move`` policy property to ``true``.
The list of supported properties are:
.. code-block:: lua
["move"] = true
Moves session items when metadata ``target.node`` changes.
.. code-block:: lua
["follow"] = true
Moves session items to the default device when it has changed.
.. code-block:: lua
["audio.no-dsp"] = false
Set to ``true`` to disable channel splitting & merging on nodes and enable
passthrough of audio in the same format as the format of the device. Note that
this breaks JACK support; it is generally not recommended.
.. code-block:: lua
["duck.level"] = 0.3
How much to lower the volume of lower priority streams when ducking. Note that
this is a linear volume modifier (not cubic as in PulseAudio).
policy.lua.d/50-endpoints-config.lua
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Endpoints are objects that can group multiple clients into different groups or
roles. This is useful if a user wants to apply specific actions when a client
is connected to a particular role/endpoint. This configuration file allows
users to configure those endpoints and their actions.
* *default_policy.policy.roles*
This is a Lua array with objects defining the actions of each role.
Example:
.. code-block:: lua
default_policy.policy.roles = {
["Multimedia"] = {
["alias"] = { "Movie", "Music", "Game" },
["priority"] = 10,
["action.default"] = "mix",
}
["Notification"] = {
["priority"] = 20,
["action.default"] = "duck",
["action.Notification"] = "mix",
}
}
The above example defines actions for both ``Multimedia`` and ``Notification``
roles. Since the Notification role has more priority than the Multimedia
role, when a client connects to the Notification endpoint, it will ``duck``
the volume of all Multimedia clients. If Multiple Notification clients want
to play audio, only the Notifications audio will be mixed.
Possible values of actions are: ``mix`` (Mixes audio),
``duck`` (Mixes and lowers the audio volume) or ``cork`` (Pauses audio).
* *default_policy.policy.endpoints*
This is a Lua array with objects defining the endpoints that the user wants
to create.
Example:
.. code-block:: lua
default_policy.endpoints = {
["endpoint.multimedia"] = {
["media.class"] = "Audio/Sink",
["role"] = "Multimedia",
}
},
["endpoint.notifications"] = {
["media.class"] = "Audio/Sink",
["role"] = "Notification",
}
This example creates 2 endpoints, with names ``endpoint.multimedia`` and
``endpoint.notifications``; and assigned roles ``Multimedia`` and ``Notification``
respectively. Both endpoints have ``Audio/Sink`` media class, and so are only
used for playback.

View file

@ -1,4 +1,4 @@
.. _resources_contributing: .. _contributing:
Contributing to WirePlumber Contributing to WirePlumber
=========================== ===========================
@ -25,7 +25,7 @@ the indentation settings.
Tests Tests
----- -----
See :ref:`resources_testing` See :ref:`testing`
Running in gdb / valgrind / etc... Running in gdb / valgrind / etc...
---------------------------------- ----------------------------------

139
docs/rst/daemon-logging.rst Normal file
View file

@ -0,0 +1,139 @@
.. _logging:
Debug Logging
=============
Getting debug messages on the command line is a matter of setting the
``WIREPLUMBER_DEBUG`` environment variable. The generic syntax is:
.. code::
WIREPLUMBER_DEBUG=level:category1,category2,...
``level`` can be one of ``CEWMIDT`` or a numerical log level as listed below.
In either case it defines the minimum debug level to show:
0. critical warnings and fatal errors (``C`` & ``E`` in the log)
1. warnings (``W``)
2. normal messages (``M``)
3. informational messages (``I``)
4. debug messages (``D``)
5. trace messages (``T``)
``category1,category2,...`` is an *optional* comma-separated list of debug
categories to show. Any categories not listed here will *not* appear in the log.
If no categories are specified, then all messages are printed.
Categories support
`glob style patterns <https://developer.gnome.org/glib/stable/glib-Glob-style-pattern-matching.html>`_
containing ``*`` and ``?``, for convenience.
Well known categories include:
- **wireplumber**: messages from the wireplumber daemon
- **pw**: messages from libpipewire & spa plugins
- **wp-***: messages from libwireplumber
- **wp-core**: messages from *WpCore*
- **wp-proxy**: messages from *WpProxy*
- ... and so on ...
- **m-***: messages from wireplumber modules
- **m-default-profile**: messages from *libwireplumber-module-default-profile*
- **m-default-routes**: messages from *libwireplumber-module-default-routes*
- ... and so on ...
- **script/***: messages from scripts
- **script/policy-node**: messages from the *policy-node.lua* script
- ... and so on ...
Examples
--------
Show all messages:
.. code::
WIREPLUMBER_DEBUG=T
Show all messages up to the *debug* level (E, C, W, M, I & D), excluding *trace*:
.. code::
WIREPLUMBER_DEBUG=D
Show all messages up to the *message* level (E, C, W & M),
excluding *info*, *debug* & *trace*
(this is also the default when ``WIREPLUMBER_DEBUG`` is omitted):
.. code::
WIREPLUMBER_DEBUG=2
Show all messages from the wireplumber library:
.. code::
WIREPLUMBER_DEBUG=T:wp-*
Show all messages from ``wp-registry``, libpipewire and all modules:
.. code::
WIREPLUMBER_DEBUG=T:wp-registry,pw,m-*
Relationship with the GLib log handler & G_MESSAGES_DEBUG
---------------------------------------------------------
Older versions of WirePlumber used to use ``G_MESSAGES_DEBUG`` to control their
log output, which is the environment variable that affects GLib's default
log handler.
As of WirePlumber 0.3, ``G_MESSAGES_DEBUG`` is no longer used, since
libwireplumber replaces the default log handler.
If you are writing your own application based on libwireplumber, you can choose
if you want to replace this log handler using the flags passed to
:c:func:`wp_init`.
Relationship with the PipeWire log handler & PIPEWIRE_DEBUG
-----------------------------------------------------------
libpipewire uses the ``PIPEWIRE_DEBUG`` environment variable, with a similar syntax.
WirePlumber replaces the log handler of libpipewire with its own, rendering
``PIPEWIRE_DEBUG`` useless. Instead, you should use ``WIREPLUMBER_DEBUG`` and the
``pw`` category to control log messages from libpipewire & its plugins.
If you are writing your own application based on libwireplumber, you can choose
if you want to replace this log handler using the flags passed to
:c:func:`wp_init`.
Mapping of PipeWire debug levels to WirePlumber
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Both WirePlumber and PipeWire support 6 levels of debug logging, from 0 to 5
PipeWire uses a slightly different semantic for the first 3 levels:
===== ======== ===========
Level PipeWire WirePlumber
===== ======== ===========
0 no log Critical / fatal Errors
1 Errors Warnings
2 Warnings Messages
===== ======== ===========
When PipeWire log messages are printed by the WirePlumber log handler, the
level number stays the same and the semantic changes. PipeWire's errors are
printed in the ``W`` category and PipeWire's warnings are printed in the
``M`` category.
In WirePlumber's (actually GLib's) semantics, this feels more appropriate
because:
- GLib's errors are fatal (``abort()`` is called)
- GLib's critical warnings are assertion failures (i.e. programming mistakes,
not runtime errors)
- PipeWire's errors are neither fatal, nor programming mistakes; they are
just bad situations that are not meant to happen
- GLib's warnings are exactly that: bad runtime situations that are not meant
to happen, so mapping PipeWire errors to GLib warnings makes sense
- The **Messages** log level does not exist in PipeWire, so it can be used to
fill the gap for PipeWire warnings

View file

@ -1,30 +0,0 @@
.. _daemon_configuration:
Configuration
=============
WirePlumber is a heavily modular daemon. By itself, it doesn't do anything
except load its configured components. The actual management logic is
implemented inside those components.
At startup, WirePlumber reads its configuration file (combined with all the
fragments it may have) and loads the components specified in the selected
profile. This configures the operation context. Then, the components take over
and drive the entirety of the daemon's operation.
The sections below describe in more detail the configuration file format and
the various options available.
.. toctree::
:maxdepth: 1
configuration/conf_file.rst
configuration/components_and_profiles.rst
configuration/configuration_option_types.rst
configuration/modifying_configuration.rst
configuration/migration.rst
configuration/features.rst
configuration/settings.rst
configuration/alsa.rst
configuration/bluetooth.rst
configuration/access.rst

View file

@ -1,125 +0,0 @@
.. _config_access:
Access configuration
====================
WirePlumber includes a "client access" policy which defines access control
rules for PipeWire clients.
Rules
-----
This policy can be configured with rules that can be used to match clients and
apply default permissions to them.
Example:
.. code-block::
access.rules = [
{
matches = [
{
access = "flatpak"
media.category = "Manager"
}
]
actions = {
update-props = {
access = "flatpak-manager"
default_permissions = "all",
}
}
}
{
matches = [
{
access = "flatpak"
}
]
actions = {
update-props = {
default_permissions = "rx"
}
}
}
]
Possible permissions are any combination of:
* ``r``: client is allowed to **read** objects, i.e. "see" them on the registry
and list their properties
* ``w``: client is allowed to **write** objects, i.e. call methods that modify
their state
* ``x``: client is allowed to **execute** methods on objects; the ``w`` flag
must also be present to call methods that modify the object
* ``m``: client is allowed to set **metadata** on objects
* ``l``: nodes of this client are allowed to **link** to other nodes that the
client can't "see" (i.e. the client doesn't have ``r`` permission on them)
The special value ``all`` is also supported and it is synonym for ``rwxm``
Permission Managers
-------------------
For more advanced use cases, WirePlumber supports *permission managers* that can
apply per-object permissions dynamically based on rules and object interests.
Permission managers are defined in the ``access.permission-managers`` section
and then referenced by name in ``access.rules``.
Example:
.. code-block::
access.permission-managers = [
{
name = "custom"
default_permissions = "all"
core_permissions = "rx"
rules = [
{
matches = [
{
media.class = "Audio/Source"
}
]
actions = {
set-permissions = "-"
}
}
]
}
]
access.rules = [
{
matches = [
{
application.name = "paplay"
}
]
actions = {
update-props = {
permission_manager_name = "custom"
}
}
}
]
Each permission manager supports the following properties:
* ``name``: (required) a unique name used to reference the manager from
``access.rules``
* ``default_permissions``: the fallback permissions applied to all objects
that don't match any rule (applied as ``PW_ID_ANY``)
* ``core_permissions``: permissions applied specifically to the PipeWire core
object (``PW_ID_CORE``, ID 0). This is useful when you want to allow a
client to interact with the core (e.g. enumerate objects, subscribe to
events) while restricting access to individual objects. If not set, the
``default_permissions`` value is used for the core as well.
* ``rules``: a list of match rules with ``set-permissions`` actions that
grant specific permissions to objects matching the given constraints
When both ``default_permissions`` and ``permission_manager_name`` are set in
a rule's ``update-props`` action, ``default_permissions`` takes precedence and
the permission manager is ignored.

View file

@ -1,485 +0,0 @@
.. _config_alsa:
ALSA configuration
==================
One of the components of WirePlumber is the ALSA monitor. This monitor is
responsible for creating PipeWire devices and nodes for all the ALSA cards that
are available on the system. It also manages the configuration of these devices.
The ALSA monitor is enabled by default and can be disabled using the
``monitor.alsa`` :ref:`feature <config_features>` in the configuration file.
The monitor, as with all device monitors, is implemented as a SPA plugin and is
part of PipeWire. WirePlumber merely loads the plugin and lets it do its work.
The plugin then monitors UDev and creates device and node objects for all the
ALSA cards that are available on the system.
.. note::
One thing worth remembering here is that in ALSA, a "card" represents a
physical sound controller device, and a "device" is a logical access point
that represents a set of inputs and/or outputs that are part of the card. In
PipeWire, a "device" is the direct equivalent of an ALSA "card" and a "node"
is almost equivalent (close, but not quite) of an ALSA "device".
Properties
----------
The ALSA monitor SPA plugin (``api.alsa.enum.udev``) supports properties that
can be used to configure it when it is loaded. These properties can be set in
the ``monitor.alsa.properties`` section of the WirePlumber configuration file.
Example:
.. code-block::
monitor.alsa.properties = {
alsa.use-acp = true
}
.. describe:: alsa.use-acp
A boolean that controls whether the ACP (alsa card profile) code is to be
the default manager of the device. This will probe the device and configure
the available profiles, ports and mixer settings. The code to do this is
taken directly from PulseAudio and provides devices that look and feel
exactly like the PulseAudio devices.
Rules
-----
When device and node objects are created by the ALSA monitor, they can be
configured using rules. These rules allow matching the existing properties of
these objects and updating them with new values. This is the main way of
configuring ALSA device settings.
These rules can be set in the ``monitor.alsa.rules`` section of the WirePlumber
configuration file.
Example:
.. code-block::
monitor.alsa.rules = [
{
matches = [
{
# This matches the value of the 'device.name' property of the device.
device.name = "~alsa_card.*"
}
]
actions = {
update-props = {
# Apply all the desired device settings here.
api.alsa.use-acp = true
}
}
}
{
matches = [
# This matches the value of the 'node.name' property of the node.
{
node.name = "~alsa_output.*"
}
]
actions = {
# Apply all the desired node specific settings here.
update-props = {
node.nick = "My Node"
priority.driver = 100
session.suspend-timeout-seconds = 5
}
}
}
]
Device properties
^^^^^^^^^^^^^^^^^
The following properties can be configured on devices created by the monitor:
.. describe:: api.alsa.use-acp
Use the ACP (alsa card profile) code to manage this device. This will probe
the device and configure the available profiles, ports and mixer settings.
The code to do this is taken directly from PulseAudio and provides devices
that look and feel exactly like the PulseAudio devices.
:Default value: ``true``
:Type: boolean
.. describe:: api.alsa.use-ucm
When ACP is enabled and a UCM configuration is available for a device, by
default it is used instead of the ACP profiles. This option allows you to
disable this and use the ACP profiles instead.
This option does nothing if ``api.alsa.use-acp`` is set to ``false``.
:Default value: ``true``
:Type: boolean
.. describe:: api.alsa.soft-mixer
Setting this option to ``true`` will disable the hardware mixer for volume
control and mute. All volume handling will then use software volume and mute,
leaving the hardware mixer untouched. The hardware mixer will still be used
to mute unused audio paths in the device.
:Type: boolean
.. describe:: api.alsa.ignore-dB
Setting this option to ``true`` will ignore the decibel setting configured by
the driver. Use this when the driver reports wrong settings.
:Type: boolean
.. describe:: device.profile-set
This option can be used to select a custom ACP profile-set name for the
device. This can be configured in UDev rules, but it can also be specified
here. The default is to use "default.conf".
:Type: string
.. describe:: device.profile
The initial active profile name. The default is to start from the "Off"
profile and then let WirePlumber select the best profile based on its
policy.
:Type: string
.. describe:: api.acp.auto-profile
Automatically select the best profile for the device. Normally this option is
disabled because WirePlumber will manage the profile of the device.
WirePlumber can save and load previously selected profiles. Enable this in
custom configurations where the relevant WirePlumber components are disabled.
:Type: boolean
.. describe:: api.acp.auto-port
Automatically select the highest priority port that is available ("port" is a
PulseAudio/ACP term, the equivalent of a "Route" in PipeWire). This is by
default disabled because WirePlumber handles the task of selecting and
restoring Routes. Enable this in custom configurations where the relevant
WirePlumber components are disabled.
:Type: boolean
.. describe:: api.acp.probe-rate
Sets the samplerate used for probing the ALSA devices and collecting the
profiles and ports.
:Type: integer
.. describe:: api.acp.pro-channels
Sets the number of channels to use when probing the "Pro Audio" profile.
Normally, the maximum amount of channels will be used but with this setting
this can be reduced, which can make it possible to use other samplerates on
some devices.
:Type: integer
Some of the other properties that can be configured on devices:
.. describe:: device.nick
A short name for the device.
.. describe:: device.description
A longer, user-friendly name of the device. This will show up in most
user interfaces as the device's name.
.. describe:: device.disabled
Disables the device. PipeWire will remove it from the list of cards or
devices.
:Type: boolean
Node properties
^^^^^^^^^^^^^^^
The following properties can be configured on nodes created by the monitor:
.. describe:: priority.driver
This configures the node driver priority. Nodes with higher priority will be
used as a driver in the graph. Other nodes with lower priority will have to
resample to the driver node when they are joined in the same graph. The
default value is set based on some heuristics.
:Type: integer
.. describe:: priority.session
This configures the priority of the node when selecting a default node
(default sink/source as a link target for streams). Higher priority nodes
will be more likely candidates for becoming the default node.
:Type: integer
.. note::
By default, sources have a ``priority.session`` value around 1600-2000 and
sinks have a value around 600-1000. If you are increasing the priority of
a sink, it is **not advised** to use a value higher than 1500, as it may
cause a sink's monitor to be selected as the default source.
.. describe:: node.pause-on-idle
Pause the node when nothing is linked to it anymore. This is by default false
because some devices make a "pop" sound when they are opened/closed.
The node will normally pause and suspend after a timeout (see below).
:Type: boolean
.. describe:: session.suspend-timeout-seconds
This option configures a different suspend timeout on the node. By default
this is ``5`` seconds. For some devices (HiFi amplifiers, for example) it
might make sense to set a higher timeout because they might require some time
to restart after being idle.
A value of ``0`` disables suspend for a node and will leave the ALSA device
busy. The device can then be manually suspended with
``pactl suspend-sink|source``.
:Type: integer
.. describe:: audio.format
The sample format of the device. By default, PipeWire will use a 32 bits
sample format but a different format can be set here.
:Type: string (``"S16LE"``, ``"S32LE"``, ``"F32LE"``, ...)
.. describe:: audio.rate
The sample rate of the device. By default, the ALSA device will be configured
with the same samplerate as the global graph. If this is not supported, or a
custom value is set here, resampling will be used to match the graph rate.
:Type: integer
.. describe:: audio.channels
The number of channels of the device. By default the channels and their
position are determined by the selected device profile. You can override
this setting here.
:Type: integer
.. describe:: audio.position
The position of the channels. By default the number of channels and their
position are determined by the selected device profile. You can override
this setting here and optionally swap or reconfigure the channel positions.
:Type: array of strings (example: ``["FL", "FR", "LFE", "FC", "RL", "RR"]``)
.. describe:: api.alsa.use-chmap
Use the channel map as reported by the driver. This is disabled by default
because it is often wrong and the ACP code handles this better.
:Type: boolean
.. describe:: api.alsa.disable-mmap
Disable the use of mmap for the ALSA device. By default, PipeWire will access
the memory of the device using mmap. This can be disabled and force the usage
of the slower read and write access modes, in case the mmap support of the
device is not working properly.
:Type: boolean
.. describe:: channelmix.normalize
Normalize the channel volumes when mixing & resampling, making sure that the
original 0 dB level is preserved so that nothing sounds wildly
quieter/louder. This is disabled by default.
:Type: boolean
.. describe:: channelmix.mix-lfe
Creates a "center" channel for X.0 recordings from the front stereo on X.1
setups and pushes some low-frequency/bass from the "center" of X.1 recordings
into the front stereo on X.0 setups. This is disabled by default.
:Type: boolean
.. describe:: monitor.channel-volumes
By default, the volume of the sink/source does not influence the volume on
the monitor ports. Set this option to true to change this. PulseAudio has
inconsistent behaviour regarding this option, it applies channel-volumes only
when the sink/source is using software volumes.
:Type: boolean
.. describe:: node.disabled
Disables the node. Pipewire will remove it from the list of the nodes.
:Type: boolean
ALSA buffer properties
......................
PipeWire by default uses a timer to consume and produce samples to/from ALSA
devices. After every timeout, it queries the hardware pointers of the device and
uses this information to set a new timeout. This works well for most devices,
but there is a class of devices, so called "batch" devices, that need extra
buffering and timing tweaks to work properly. This is because batch devices only
get their hardware pointers updated after each hardware interrupt. When the
hardware interrupt frequency and the timer frequency are aligned, it is possible
for the hardware pointers to be updated just after the timer has expired,
resulting in sometimes wrong timing information being returned by the query. In
contrast, non-batch devices get pointer updates independent of the interrupt.
This means that for batch devices we need to set the interrupt at a sufficiently
high frequency, at the cost of CPU usage, while for non-batch devices we want to
set the interrupt frequency as low as possible to save CPU. For batch devices
we also need to take the extra buffering into account caused by the delayed
updates of the hardware pointers.
.. note::
Most USB devices are batch devices and will be handled as such by PipeWire by
default.
There are 2 tunable parameters to control the buffering and timeouts in a
device:
.. describe:: api.alsa.period-size
This sets the device interrupt to every period-size samples for non-batch
devices and to half of this for batch devices. For batch devices, the other
half of the period-size is used as extra buffering to compensate for the
delayed update. So, for batch devices, there is an additional period-size/2
delay. It makes sense to lower the period-size for batch devices to reduce
this delay.
:Type: integer (samples)
.. describe:: api.alsa.headroom
This adds extra delay between the hardware pointers and software pointers.
In most cases this can be set to 0. For very bad devices or emulated devices
(like in a VM) it might be necessary to increase the headroom value.
:Type: integer (samples)
.. describe:: api.alsa.period-num
This configures the number of periods in the hardware buffer, which controls
its size. Note that this is multiplied by the period of the device to
determine the size, so for batch devices, the total buffer size is
effectively period-num * period-size/2.
:Type: integer
In summary, this is the overview of buffering and timings:
============== ============================================ ==========================================
Property Batch Non-Batch
============== ============================================ ==========================================
IRQ Frequency api.alsa.period-size/2 api.alsa.period-size
Extra Delay api.alsa.headroom + api.alsa.period-size/2 api.alsa.headroom
Buffer Size api.alsa.period-num * api.alsa.period-size/2 api.alsa.period-num * api.alsa.period-size
============== ============================================ ==========================================
Finally, it is possible to disable the batch device tweaks with:
.. describe:: api.alsa.disable-batch
This disables the batch device tweaks. It removes the extra delay added of
period-size/2 if the device can support this. For batch devices it is also a
good idea to lower the period-size (and increase the IRQ frequency) to get
smaller batch updates and lower latency.
:Type: boolean
ALSA extra latency properties
.............................
Extra internal delay in the DAC and ADC converters of the device itself can be
set with the ``latency.internal.*`` properties:
.. code-block::
latency.internal.rate = 256
latency.internal.ns = 0
You can configure a latency in samples (relative to rate with
``latency.internal.rate``) or in nanoseconds (``latency.internal.ns``).
This value will be added to the total reported latency by the node of the device.
You can use a tool like ``jack_iodelay`` to get the number of samples of
internal latency of your device.
This property is also adjustable at runtime with the ``ProcessLatency`` param.
You will need to find the id of the Node you want to change. For example:
Query the current internal latency of an ALSA node with id 58:
.. code-block:: console
$ pw-cli e 58 ProcessLatency
Object: size 80, type Spa:Pod:Object:Param:ProcessLatency (262156), id Spa:Enum:ParamId:ProcessLatency (16)
Prop: key Spa:Pod:Object:Param:ProcessLatency:quantum (1), flags 00000000
Float 0.000000
Prop: key Spa:Pod:Object:Param:ProcessLatency:rate (2), flags 00000000
Int 0
Prop: key Spa:Pod:Object:Param:ProcessLatency:ns (3), flags 00000000
Long 0
Set the internal latency to 256 samples:
.. code-block:: console
$ pw-cli s 58 ProcessLatency '{ rate = 256 }'
Object: size 32, type Spa:Pod:Object:Param:ProcessLatency (262156), id Spa:Enum:ParamId:ProcessLatency (16)
Prop: key Spa:Pod:Object:Param:ProcessLatency:rate (2), flags 00000000
Int 256
remote 0 node 58 changed
remote 0 port 70 changed
remote 0 port 72 changed
remote 0 port 74 changed
remote 0 port 76 changed
Startup tweaks
..............
.. describe:: api.alsa.start-delay
Some devices need some time before they can report accurate hardware pointer
positions. In those cases, an extra start delay can be added to compensate
for this startup delay. This sets the startup delay in samples. The default
is 0.
:Type: integer (samples)
IEC958 (S/PDIF) passthrough
...........................
.. describe:: iec958.codecs
S/PDIF passthrough will only be enabled when the accepted codecs are configured
on the ALSA device. This can be done by setting the list of supported codecs
on this property.
Note that it is possible to also configure this property at runtime, either
with tools like pavucontrol or with the ``pw-cli`` tool, like this:
``pw-cli s <node-id> Props '{ iec958Codecs : [ PCM ] }'``
:Type: array of strings (example: ``[ "PCM", "DTS", "AC3", "EAC3", "TrueHD", "DTS-HD" ]``)

View file

@ -1,440 +0,0 @@
.. _config_bluetooth:
Bluetooth configuration
=======================
Bluetooth audio and MIDI devices are managed by the BlueZ and BlueZ-MIDI
monitors, respectively.
Both monitors are enabled by default and can be disabled using the
``monitor.bluez`` and ``monitor.bluez-midi`` :ref:`features <config_features>`
in the configuration file.
As with all device monitors, both of these monitors are implemented as SPA
plugins and are part of PipeWire. WirePlumber merely loads the plugins and lets
them do their work. These plugins then monitor the BlueZ system-wide D-Bus
service and create device and node objects for all the connected Bluetooth audio
and MIDI devices.
Logind integration
------------------
The BlueZ monitors are integrated with logind to ensure that only one user at a
time can use the Bluetooth audio devices. This is because on most Linux desktop
systems, the graphical login manager (GDM, SDDM, etc.) is running as a separate
user and runs its own instance of PipeWire and Wireplumber. This means that if a
user logs in graphically, the Bluetooth audio devices will be automatically
grabbed by the PipeWire/WirePlumber instance of the graphical login manager,
and the user that logs in will not get access to them.
To overcome this, the BlueZ monitors are integrated with logind and are only
allowed to create device and node objects for Bluetooth audio devices if the
user is currently on the "active" logind session.
In some cases, however, this behavior is not desired. For example, if you
manually switch to a TTY and log in there, you may want to keep the Bluetooth
audio devices connected to the now inactive graphical session. Or you may want
to have a dedicated user that is always allowed to use the Bluetooth audio
devices, regardless of the active logind session, for example for a (possibly
headless) music player daemon.
To disable this behavior, you can set the ``monitor.bluez.seat-monitoring``
:ref:`feature <config_features>` to ``disabled``.
Example configuration :ref:`fragment <config_conf_file_fragments>` file:
.. code-block::
wireplumber.profiles = {
main = {
monitor.bluez.seat-monitoring = disabled
}
}
.. note::
If logind is not installed on the system, this functionality is disabled
automatically.
Monitor Properties
------------------
The BlueZ monitor SPA plugin (``api.bluez5.enum.dbus``) supports properties that
can be used to configure it when it is loaded. These properties can be set in
the ``monitor.bluez.properties`` section of the WirePlumber configuration file.
Example:
.. code-block::
monitor.bluez.properties = {
bluez5.roles = [ a2dp_sink a2dp_source bap_sink bap_source hsp_hs hsp_ag hfp_hf hfp_ag ]
bluez5.codecs = [ sbc sbc_xq aac ]
bluez5.enable-sbc-xq = true
bluez5.hfphsp-backend = "native"
}
.. describe:: bluez5.roles
Enabled roles.
Currently some headsets (e.g. Sony WH-1000XM3) do not work with both
``hsp_ag`` and ``hfp_ag`` enabled, so by default we enable only HFP.
Supported roles:
- ``hsp_hs`` (HSP Headset)
- ``hsp_ag`` (HSP Audio Gateway),
- ``hfp_hf`` (HFP Hands-Free),
- ``hfp_ag`` (HFP Audio Gateway)
- ``a2dp_sink`` (A2DP Audio Sink)
- ``a2dp_source`` (A2DP Audio Source)
- ``bap_sink`` (LE Audio Basic Audio Profile Sink)
- ``bap_source`` (LE Audio Basic Audio Profile Source)
:Default value: ``[ a2dp_sink a2dp_source bap_sink bap_source hfp_hf hfp_ag ]``
:Type: array of strings
.. describe:: bluez5.codecs
Enabled A2DP codecs.
Supported codecs: ``sbc``, ``sbc_xq``, ``aac``, ``ldac``, ``aptx``,
``aptx_hd``, ``aptx_ll``, ``aptx_ll_duplex``, ``faststream``,
``faststream_duplex``, ``lc3plus_h3``, ``opus_05``, ``opus_05_51``,
``opus_05_71``, ``opus_05_duplex``, ``opus_05_pro``, ``lc3``.
:Default value: all available codecs
:Type: array of strings
.. describe:: bluez5.enable-msbc
Enable mSBC codec (wideband speech codec for HFP/HSP).
This does not work on all headsets, so it is enabled based on the hardware
quirks database. By explicitly setting this option you can force it to be
enabled or disabled regardless.
:Default value: ``true``
:Type: boolean
.. describe:: bluez5.enable-sbc-xq
Enable SBC-XQ codec (high quality SBC codec for A2DP).
This does not work on all headsets, so it is enabled based on the hardware
quirks database. By explicitly setting this option you can force it to be
enabled or disabled regardless.
:Default value: ``true``
:Type: boolean
.. describe:: bluez5.enable-hw-volume
Enable hardware volume controls.
This does not work on all headsets, so it is enabled based on the hardware
quirks database. By explicitly setting this option you can force it to be
enabled or disabled regardless.
:Default value: ``true``
:Type: boolean
.. describe:: bluez5.hfphsp-backend
HFP/HSP backend.
Available values: ``any``, ``none``, ``hsphfpd``, ``ofono`` or ``native``.
:Default value: ``native``
:Type: string
.. describe:: bluez5.hfphsp-backend-native-modem
Modem to use for native HFP/HSP backend ModemManager support. When enabled,
PipeWire will forward HFP commands to the specified ModemManager device.
This corresponds to the 'Device' property of the
``org.freedesktop.ModemManager1.Modem`` interface. May also be ``any`` to
use any available modem device.
:Default value: ``none``
:Type: string
.. describe:: bluez5.hw-offload-sco
HFP/HSP hardware offload SCO support.
Using this feature requires a custom WirePlumber script that handles audio
routing in a platform-specific way. See ``tests/examples/bt-pinephone.lua``
for an example.
:Default value: ``false``
:Type: boolean
.. describe:: bluez5.default.rate
The default audio rate for the A2DP codec configuration.
:Default value: ``48000``
:Type: integer
.. describe:: bluez5.default.channels
The default number of channels for the A2DP codec configuration.
:Default value: ``2``
:Type: integer
.. describe:: bluez5.dummy-avrcp-player
Register dummy AVRCP player. Some devices have wrongly functioning volume or
playback controls if this is not enabled. Disabled by default.
:Default value: ``false``
:Type: boolean
.. describe:: Opus Pro Audio mode settings
.. code-block::
bluez5.a2dp.opus.pro.channels = 3
bluez5.a2dp.opus.pro.coupled-streams = 1
bluez5.a2dp.opus.pro.locations = [ FL,FR,LFE ]
bluez5.a2dp.opus.pro.max-bitrate = 600000
bluez5.a2dp.opus.pro.frame-dms = 50
bluez5.a2dp.opus.pro.bidi.channels = 1
bluez5.a2dp.opus.pro.bidi.coupled-streams = 0
bluez5.a2dp.opus.pro.bidi.locations = [ FC ]
bluez5.a2dp.opus.pro.bidi.max-bitrate = 160000
bluez5.a2dp.opus.pro.bidi.frame-dms = 400
Options for the PipeWire-specific multichannel Opus codec, which can be used
to transport audio over Bluetooth between devices running PipeWire.
MIDI Monitor Properties
-----------------------
The BlueZ MIDI monitor SPA plugin (``api.bluez5.midi.enum``) may, in the future,
support properties that can be used to configure it when it is loaded. These
properties can be set in the ``monitor.bluez-midi.properties`` section of the
WirePlumber configuration file. At the moment of writing, there are no
properties that can be set there.
In addition, the BlueZ MIDI monitor supports a list of MIDI server node names
that can be used to create Bluetooth LE MIDI service instances. These
server node names can be set in the ``monitor.bluez-midi.servers`` section of
the WirePlumber configuration file.
Example:
.. code-block::
monitor.bluez-midi.servers = [ "bluez_midi.server" ]
.. note::
Typical BLE MIDI instruments have one service instance, so adding more than
one here may confuse some clients.
Rules
-----
When device and node objects are created by the BlueZ monitor, they can be
configured using rules. These rules allow matching the existing properties of
these objects and updating them with new values. This is the main way of
configuring Bluetooth device settings.
These rules can be set in the ``monitor.bluez.rules`` section of the WirePlumber
configuration file.
Example:
.. code-block::
monitor.bluez.rules = [
{
matches = [
{
## This matches all bluetooth devices.
device.name = "~bluez_card.*"
}
]
actions = {
update-props = {
bluez5.auto-connect = [ hfp_hf hsp_hs a2dp_sink hfp_ag hsp_ag a2dp_source ]
bluez5.hw-volume = [ hfp_hf hsp_hs a2dp_sink hfp_ag hsp_ag a2dp_source ]
bluez5.a2dp.ldac.quality = "auto"
bluez5.a2dp.aac.bitratemode = 0
bluez5.a2dp.opus.pro.application = "audio"
bluez5.a2dp.opus.pro.bidi.application = "audio"
}
}
}
{
matches = [
{
## Matches all sources.
node.name = "~bluez_input.*"
}
{
## Matches all sinks.
node.name = "~bluez_output.*"
}
]
actions = {
update-props = {
bluez5.media-source-role = "input"
# Common node & audio adapter properties may also be set here
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
session.suspend-timeout-seconds = 5
monitor.channel-volumes = false
}
}
}
]
Device properties
^^^^^^^^^^^^^^^^^
The following properties can be set on device objects:
.. describe:: bluez5.auto-connect
Auto-connect device profiles on start up or when only partial profiles have
connected. Disabled by default if the property is not specified.
Supported values are: ``hfp_hf``, ``hsp_hs``, ``a2dp_sink``, ``hfp_ag``,
``hsp_ag`` and ``a2dp_source``.
:Default value: ``[]``
:Type: array of strings
.. describe:: bluez5.hw-volume
Enable hardware volume controls on these profiles.
Supported values are: ``hfp_hf``, ``hsp_hs``, ``a2dp_sink``, ``hfp_ag``,
``hsp_ag`` and ``a2dp_source``.
:Default value: ``[ hfp_ag hsp_ag a2dp_source ]``
:Type: array of strings
.. describe:: bluez5.a2dp.ldac.quality
LDAC encoding quality.
Available values: ``auto`` (Adaptive Bitrate, default), ``hq`` (High
Quality, 990/909kbps), ``sq`` (Standard Quality, 660/606kbps) and ``mq``
(Mobile use Quality, 330/303kbps).
:Default value: ``auto``
:Type: string
.. describe:: bluez5.a2dp.aac.bitratemode
AAC variable bitrate mode.
Available values: 0 (cbr, default), 1-5 (quality level).
:Default value: ``0``
:Type: integer
.. describe:: bluez5.a2dp.opus.pro.application
Opus Pro Audio encoding mode.
Available values: ``audio``, ``voip``, ``lowdelay``.
:Default value: ``audio``
:Type: string
.. describe:: bluez5.a2dp.opus.pro.bidi.application
Opus Pro Audio encoding mode for bidirectional audio.
Available values: ``audio``, ``voip``, ``lowdelay``.
:Default value: ``audio``
:Type: string
.. describe:: device.profile
The profile that is activated initially when the device is connected.
Available values: ``a2dp-sink`` (default) or ``headset-head-unit``.
:Default value: ``a2dp-sink``
:Type: string
Node properties
^^^^^^^^^^^^^^^
The following properties can be set on node objects:
.. describe:: bluez5.media-source-role
Media source role, ``input`` or ``playback``. This controls how a media
source device, such as a smartphone, is used by the system. Defaults to
``playback``, playing the incoming stream out to speakers. Set to ``input``
to use the smartphone as an input for apps (like a microphone).
:Default value: ``playback``
:Type: string
MIDI Rules
----------
Similarly to the above rules, the BlueZ MIDI monitor also supports rules that
can be used to configure MIDI nodes when they are created.
These rules can be set in the ``monitor.bluez-midi.rules`` section of the
WirePlumber configuration file.
Example:
.. code-block::
monitor.bluez-midi.rules = [
{
matches = [
{
node.name = "~bluez_midi.*"
}
]
actions = {
update-props = {
node.nick = "My Node"
priority.driver = 100
priority.session = 100
node.pause-on-idle = false
session.suspend-timeout-seconds = 5
node.latency-offset-msec = 0
}
}
}
]
.. note::
It is possible to also match MIDI server nodes by testing the ``node.name``
property against the server node names that were set in the
``monitor.bluez-midi.servers`` section of the WirePlumber configuration file.
MIDI-specific properties
^^^^^^^^^^^^^^^^^^^^^^^^
.. describe:: node.latency-offset-msec
Latency adjustment to apply on the node. Larger values add a
constant latency, but reduces timing jitter caused by Bluetooth
transport.
:Default value: ``0``
:Type: integer (milliseconds)

View file

@ -1,218 +0,0 @@
.. _config_components_and_profiles:
Components & Profiles
=====================
WirePlumber is organized in components and profiles. Components are
functional parts that provide a specific feature, while profiles are
collections of components that are loaded together to offer a certain
overall experience.
Components
----------
Components are functional parts that provide a specific feature. They can be
described by a name, a type, a feature that they provide and a set of
dependencies, required and optional.
In the configuration file, a component is described as a SPA-JSON object,
in the ``wireplumber.components`` array section, like this:
.. code-block::
{
name = <component-name>
type = <component-type>
arguments = { <json object> }
# Feature that this component provides
provides = <feature>
# List of features that must be provided before this component is loaded
requires = [ <features> ]
# List of features that would offer additional functionality if provided
# but are not strictly required
wants = [ <features> ]
}
Name & arguments
~~~~~~~~~~~~~~~~
The name identifies the resource that this component loads. For example,
it can be a file or a shared library. Depending on the type, the component
may also accept arguments, which are passed on to the resource when it is
loaded.
Types
~~~~~
The main types of components are:
* **script/lua**
A Lua script, which usually contains one or more event hooks and/or
other custom logic. This is the main type of component as WirePlumber's
business logic is mostly written in Lua.
* **module**
A WirePlumber module, which is a shared library that can be loaded
dynamically. Modules usually provide some bundled logic to be consumed by
scripts or some integration between WirePlumber and an external service.
* **pw-module**
A PipeWire module, which is also a shared library that can be loaded
dynamically, but extends the functionality of the underlying *libpipewire*
library. Loading PipeWire modules in the WirePlumber context can be useful
to load custom protocol extensions or to offload some functionality from
the PipeWire daemon.
* **virtual**
Virtual components are just load targets that can be used to pull in
other components by defining dependencies. They do not provide any
functionality by themselves. Note that such components do not have a "name".
* **built-in**
These components are functional parts that are already built into the
WirePlumber library. They provide mostly internal support elements and checks.
Features
~~~~~~~~
A "feature" is a name that we can use to refer to what is being provided
by a component. For example, the ``monitors/alsa.lua`` script provides the
``monitor.alsa`` feature. The feature name is used to refer to the component
when defining dependencies between components and also when defining profiles.
When a component loads successfully, its feature is marked as provided,
otherwise it is not. Whether a feature is provided or not can be checked at
runtime in Lua scripts using the :func:`Core.test_feature` function and in C code
using the :c:func:`wp_core_test_feature` function.
For a list of well-known features, see :ref:`config_features`.
Dependencies
~~~~~~~~~~~~
Each component can "provide" a feature. When the component is loaded, the
feature is marked as provided. Other components can either "require"
or "want" a feature.
If a component "requires" a feature, that means that this feature **must** be
provided before this component is loaded and WirePlumber will try to load the
relevant component that provides that feature if it is not already loaded
(i.e. it will pull in the component). If that other component fails to load,
hence the feature is not provided, the component that requires it will fail
to load as well.
If a component "wants" a feature, that means that this feature would be nice
to have, in the sense that it would offer additional functionality if it
was provided, but it's not strictly needed. WirePlumber will also try to load
the relevant component that provides that feature if it is not already loaded,
meaning that it will also pull in the component. However, if that other
component fails to load, the component that wants it will still be loaded
without error.
Profiles
--------
A profile is a collection of components that are loaded together to offer
a certain overall experience.
Profiles are defined in the configuration file as a SPA-JSON object,
in the ``wireplumber.profiles`` section, like this:
.. code-block::
<profile> = {
<feature name> = [ required | optional | disabled ]
...
}
Each feature can be marked as *required*, *optional* or *disabled*.
* **required**: Loading this profile will pull in the component that can
provide this feature in and if it fails to load, the profile will fail to
load as well.
* **optional**: Loading this profile does not pull in the component that
can provide this feature. If any of the required components either
*requires* or *wants* this feature, then WirePlumber will try to load it.
If it fails to load, the error condition depends on whether this feature was
required or wanted by the component that pulled it in.
* **disabled**: This feature will **not** be loaded, even if it is *wanted*
by some component. If any required component *requires* this feature, then
the profile will fail to load.
By default, all the features provided by all the components in the
``wireplumber.components`` section are considered to be *optional*.
That means that no component will be loaded on an empty profile, since optional
components are not pulled in automatically.
If a feature is marked as *required* in a profile, then the component that
provides that feature will be pulled in, together with all its dependencies,
both required and optional.
.. note::
In essence, all optional features are opt-in by default. To opt out,
you need to mark the feature as *disabled*.
Dependency chain example
------------------------
Consider the following configuration file:
.. code-block::
wireplumber.components = [
{
name = libwireplumber-module-dbus-connection, type = module
provides = support.dbus
}
{
name = libwireplumber-module-reserve-device, type = module
provides = support.reserve-device
requires = [ support.dbus ]
}
{
name = monitors/alsa.lua, type = script/lua
provides = monitor.alsa
wants = [ support.reserve-device ]
}
]
wireplumber.profiles = {
main = {
monitor.alsa = required
}
}
In this example, the ``main`` profile requires the ``monitor.alsa`` feature.
This will cause the ``monitors/alsa.lua`` script to be loaded. Now, since the
``monitors/alsa.lua`` script *wants* the ``support.reserve-device`` feature,
the ``libwireplumber-module-reserve-device`` module will also be pulled in.
And since that one *requires* the ``support.dbus`` feature, the
``libwireplumber-module-dbus-connection`` module will also be pulled in.
However, on a system without D-Bus, a user may want to opt out of the
``libwireplumber-module-dbus-connection`` module. This can be done by marking
the ``support.dbus`` feature as disabled in the profile:
.. code-block::
wireplumber.profiles = {
main = {
monitor.alsa = required
support.dbus = disabled
}
}
Upon doing that, the ``libwireplumber-module-dbus-connection`` module will
not be loaded, causing the ``libwireplumber-module-reserve-device`` module
to not be loaded as well, since it requires the ``support.dbus`` feature.
The ``monitors/alsa.lua`` script will still be loaded, since it only *wants*
the ``support.reserve-device`` feature.

View file

@ -1,244 +0,0 @@
.. _config_conf_file:
The configuration file
======================
WirePlumber's configuration file is by default ``wireplumber.conf`` and resides
in one of the WirePlumber specific
:ref:`configuration file search locations <config_locations>`.
The default configuration file can be changed on the command line by passing
the ``--config-file`` or ``-c`` option:
.. code-block:: bash
$ wireplumber --config-file=custom.conf
.. important::
Starting with WirePlumber 0.5, this is the only file that WirePlumber reads
to load configuration (together with its fragments - see below). In the past,
WirePlumber also used to read Lua configuration files that were referenced
from ``wireplumber.conf`` and all the heavy lifting was done in Lua. This is
no longer the case, and the **Lua configuration files are no longer supported.**
See :ref:`config_migration`.
Note that Lua is still the scripting language for WirePlumber, but it is only
used for actual scripting and not for configuration.
The SPA-JSON Format
-------------------
The format of this configuration file is a variant of JSON that is also
used in PipeWire configuration files (also known as SPA-JSON). The file consists
of a global JSON object that is not explicitly typed, and a list of sections
which are essentially key-value pairs of that global JSON object. Each section
is usually a JSON object, but it can also be a JSON array.
SPA-JSON is a superset of standard JSON, so any valid JSON file is also a valid
SPA-JSON file. However, it is more permissive than standard JSON. First of all,
it allows strings to be typed without quotes (``"``), and it also allows the
character ``=`` as a separator between keys and values in addition to the
standard ``:``. This can make it look similar to INI files or other custom
configuration formats that people are familiar with, which makes it easier for
users to read and edit.
Other deviations from standard JSON include allowing comments (lines starting
with ``#`` are treated as comments) and allowing the separator characters
(``:``, ``=``, ``,``) to appear in excess or abundance. That means that you can
write ``key = value`` or ``key: value`` or ``key value`` and it will be
interpreted the same way. You may also write ``[val1, val2, val3]`` or
``[val1, val2, val3, ]`` or ``[val1 val2 val3]`` and it will be interpreted
the same way. This is allowed because the SPA-JSON parser in fact ignores all
the separator characters (the real separator is the space character).
Examples of valid SPA-JSON files:
.. code-block::
# This is the most common syntax
section1 = {
string-key = value1
number-key = 123
boolean-key = true
}
section2 = [
val1, val2, val3
]
.. code-block::
# Mixed syntax
section1 {
"string-key" = "value1"
number-key: 123
boolean-key true
}
section2 = [
val1, val2 val3,
]
.. code-block::
# Standard JSON (albeit this comment line)
"section1": {
"string-key": "value1",
"number-key": 123,
"boolean-key": true
}
"section2": [
"val1", "val2", "val3"
]
.. _config_conf_file_fragments:
Fragments
---------
Just like PipeWire, WirePlumber supports configuration fragments. This means
that the main configuration file can be split into multiple files, and all of
them will be loaded and merged together. This is mostly useful to allow users
to customize their configuration without having to modify the main file.
When loading the configuration file, WirePlumber will also look for
additional files in the directory that has the same name as the configuration
file suffixed with ``.d`` and will load all of them as well. For example,
loading ``wireplumber.conf`` will also load any ``.conf`` files under
``wireplumber.conf.d/``. This directory is searched in all the configuration
search locations and the fragments are loaded from *all* of them, starting
from the most system-wide locations and moving towards the most user-specific
locations, in alphanumerical order within each location (see also
:ref:`config_locations_fragments`).
When a JSON object appears in multiple files, the properties of the objects are
merged together. When a JSON array appears in multiple files, the arrays are
concatenated together. When merging objects, if specific properties appear in
many of those objects, the last one to be parsed always overwrites previous
ones, unless the value is also an object or array; if it is, then the value is
recursively merged using the same rules.
Sections
--------
WirePlumber reads the following standard sections from the configuration
file:
* *wireplumber.components*
This section is an array that lists components that can be loaded by
WirePlumber. For more information, see :ref:`config_components_and_profiles`.
* *wireplumber.components.rules*
This section is an array containing rules that can be used to modify entries
of the *wireplumber.components* array. This is useful to inject changes
to the components list without having to modify the main configuration file.
* *wireplumber.profiles*
This section is an object that defines profiles that can be loaded by
WirePlumber. For more information, see :ref:`config_components_and_profiles`.
* *wireplumber.settings*
This section is an object that defines settings that can be used to
alter WirePlumber's behavior. For more information, see :ref:`config_settings`.
* *wireplumber.settings.schema*
This section is an object that defines the schema for the settings that
can be listed in *wireplumber.settings*. This is used to validate the
settings when they are modified at runtime. For more information, see
:ref:`config_configuration_option_types`.
In addition, there are many sections that are specific to certain components,
mostly hardware monitors, such as *monitor.alsa.properties*,
*monitor.alsa.rules*, etc. These are documented further on, in the respective
sections of this documentation that describe the configuration options of
these components.
Finally, WirePlumber also reads the following sections, which are parsed
by libpipewire to configure the PipeWire context:
* *context.properties*
Used to define properties to configure the PipeWire context and some modules.
* *context.spa-libs*
Used to find SPA factory names. It maps a SPA factory name regular expression
to a library name that should contain that factory. The object property names
are the regular expressions, and the object property values are the actual
library names:
.. code-block::
<factory-name regex> = <library-name>
For example:
.. code-block::
context.spa-libs = {
api.alsa.* = alsa/libspa-alsa
audio.convert.* = audioconvert/libspa-audioconvert
}
In this example, we instruct wireplumber to lookup any *api.alsa.** factory
in the *libspa-alsa* library, and any *audio.convert.** factory
in the *libspa-audioconvert* library.
.. note::
The default configuration file already contains a list of well-known
factory names and their corresponding libraries. You should only
need to add entries to this section if you are using custom SPA plugins.
* *context.modules*
Used to load PipeWire modules. This does not affect the PipeWire daemon by any
means. It exists simply to allow loading *libpipewire* modules inside
WirePlumber. This is usually useful to load PipeWire protocol extensions,
so that you can export custom objects to PipeWire and other clients.
.. note::
PipeWire modules can also be loaded as :ref:`components <config_components_and_profiles>`,
which may be preferable since it allows you to load them conditionally
based on the profile and component dependencies.
.. admonition:: Remember
Modules listed in *context.modules* are always loaded before attempting a
connection to the PipeWire daemon, while modules listed in
*wireplumber.components* are always loaded after the connection is
established. It is important to load the PipeWire protocol-native module
and any extensions (such as module-metadata) in the *context.modules*
section, so that the connection can be done properly.
Each module is described by a JSON object containing the module's *name*,
its arguments (*args*) and a combination of *flags*, which can be ``ifexists``
and ``nofail``.
.. code-block::
{
name = <module-name>
[ args = { <key> = <value> ... } ]
[ flags = [ [ ifexists ] [ nofail ] ]
}
For example:
.. code-block::
context.modules = [
{ name = libpipewire-module-adapter }
{
name = libpipewire-module-metadata,
flags = [ ifexists ]
}
]
The above example loads both PipeWire adapter and metadata modules. The
metadata module will be ignored if not found because of its ``ifexists`` flag.

View file

@ -1,125 +0,0 @@
.. _config_configuration_option_types:
Configuration option types
==========================
As seen in the previous sections, WirePlumber can be partly configured by
enabling or disabling features, which affect which components are getting
loaded. These components, however, can be further configured to fine-tune their
behavior. This section describes the different types of configuration options
that can be used to configure WirePlumber components.
Dynamic options ("Settings")
----------------------------
Dynamic options (also simply referred to as "settings") are configuration
options that can be changed at runtime. They are typically simple values like
booleans, integers, strings, etc. and are all located under the
``wireplumber.settings`` section in the configuration file. Their purpose is to
allow the user to change simple behavioral aspects of WirePlumber.
As the name suggests, these options are dynamic and can be changed at runtime
using ``wpctl`` or the :ref:`settings_api` API. For example, setting the
``device.routes.default-sink-volume`` setting to ``0.5`` can be done like this:
.. code-block:: bash
$ wpctl settings device.routes.default-sink-volume 0.5
Under the hood, when WirePlumber starts, the ``metadata.sm-settings`` component
(provided by ``libwireplumber-module-settings``) reads this section from the
configuration file and populates the ``sm-settings`` metadata object, which is
exported to PipeWire. In addition, it reads the ``wireplumber.settings.schema``
section and populates the ``schema-sm-settings`` metadata object, which is used
by the API to validate the settings. Any options that are missing from
``wireplumber.settings`` are also populated in ``sm-settings`` from their
default values in the schema. Then the rest of the components read their
configuration options from this metadata object via the :ref:`settings_api` API.
Most of the components that use such dynamic options make sure to listen
to changes in the metadata object so that they can immediately adapt their
behavior. Other components, however, do not react immediately and the changes
only take effect the next time the option is needed. For instance, some options
affect created objects in a way that cannot be changed after the object has been
created, so when the option is changed it applies only to new objects and not
existing ones.
Changing the settings at runtime in the ``sm-settings`` metadata object is
a non-persistent change. The changes will be lost when WirePlumber is
restarted. However, the :ref:`settings_api` API also supports saving settings
to a state file, which will be loaded again when WirePlumber starts and
override the settings from the configuration file. This is done by using yet
another metadata object called ``persistent-sm-settings``. When a setting is
changed in the ``persistent-sm-settings`` metadata object, WirePlumber
automatically saves the change to the state file and also changes the value in
the ``sm-settings`` metadata object immediately.
To make such a persistent change using ``wpctl``, the ``--save`` option can be
used. For example, to set the ``device.routes.default-sink-volume`` setting to
``0.5`` and save it to the state file:
.. code-block:: bash
$ wpctl settings --save device.routes.default-sink-volume 0.5
With ``wpctl``, it is also possible to restore a setting to its default value
(taken from the schema), by using the ``--reset`` option. For example, to reset
the ``device.routes.default-sink-volume`` setting, the following command can be
used:
.. code-block:: bash
$ wpctl settings --reset device.routes.default-sink-volume
In addition, the ``--delete`` option can be used to delete a setting from the
``persistent-sm-settings`` metadata object, which will also remove it from the
state file. After deleting, the value from the ``wireplumber.settings`` section
of the configuration file will be used again. For example, to delete the
``device.routes.default-sink-volume`` setting, the following command can be
used:
.. code-block:: bash
$ wpctl settings --delete device.routes.default-sink-volume
A list of all the available settings can be found in the :ref:`config_settings`
section.
Static options
--------------
Static options are more complex configuration structures that reside only in the
configuration file and cannot be changed at runtime. They are typically used to
configure device monitors and provide rules that match objects and perform
actions such as update their properties.
While these options could also in theory be stored in the metadata object and
be made dynamic, this is not supported because these options are both complex
and therefore hard to change on the command line, but also because they are
typically used to configure objects that are created at startup and cannot be
changed later.
Static options are located in their own top-level sections. Examples of such
sections are ``monitor.alsa.properties`` and ``monitor.alsa.rules`` that are
used to configure the ``monitor.alsa`` component. The next sections of this
documentation describe in detail all the available static options.
Component arguments
~~~~~~~~~~~~~~~~~~~
Components can also be configured statically by passing arguments to them when
they are loaded. This is done by adding an ``arguments`` key to the component
description in the ``wireplumber.components`` section (see
:ref:`config_components_and_profiles`).
The arguments are mostly meant as a way to instantiate multiple instances of the
same module or script with slightly different configuration to create a new
unique component. For example, the ``metadata.lua`` script can be instantiated
multiple times to create multiple metadata objects, each with a different name.
The name of the metadata object is passed as an argument to the script.
While many more static options could be passed as arguments, this is not
recommended because it is not possible to override the arguments by adding
:ref:`fragment<config_conf_file_fragments>` configuration files. Therefore, it
is recommended to use component-specific top-level sections, unless the option
is not meant to be changed by the user.

View file

@ -1,157 +0,0 @@
.. _config_features:
Well-known features
===================
This is a list of some well-known features that can be enabled or
disabled accordingly.
There are many more features actually defined in the configuration file, and it
can be confusing to go through them. This list here is meant to be a quick
reference for the most common ones that actually make sense to be toggled in
a configuration file in order to customize WirePlumber's behavior.
For more information on what features are and how they work, refer to the
previous section: :ref:`config_components_and_profiles`.
Hardware monitors
-----------------
Audio
~~~~~
.. describe:: hardware.audio
Enables bringing up audio hardware.
:wants: ``monitor.alsa``, ``monitor.alsa-midi``
.. describe:: monitor.alsa
Enables the ALSA device monitor.
:wants: ``monitor.alsa.reserve-device``
.. describe:: monitor.alsa.reserve-device
Enables D-Bus device reservation API for ALSA devices.
:requires: ``support.reserve-device``
.. describe:: monitor.alsa-midi
Enables the ALSA MIDI device monitor.
.. describe:: node.software-dsp
Enables software DSP based on pre-configured hardware rules.
See :ref:`policies_software_dsp` for more information.
Bluetooth
~~~~~~~~~
.. describe:: hardware.bluetooth
Enables bringing up bluetooth hardware.
:wants: ``monitor.bluez``, ``monitor.bluez-midi``
.. describe:: monitor.bluez
Enables the BlueZ device monitor.
:wants: ``monitor.bluez.seat-monitoring``
.. describe:: monitor.bluez.seat-monitoring
Enables seat monitoring on the bluetooth monitor.
When enabled, this will make sure that the bluetooth devices are only
enabled on the active seat.
:requires: ``support.logind``
.. describe:: monitor.bluez-midi
Enables the BlueZ MIDI device monitor.
:wants: ``monitor.bluez.seat-monitoring``
Video
~~~~~
.. describe:: hardware.video-capture
Enables bringing up video capture hardware (cameras, hdmi capture devices,
etc.)
:wants: ``monitor.v4l2``, ``monitor.libcamera``
.. describe:: monitor.v4l2
Enables the V4L2 device monitor.
.. describe:: monitor.libcamera
Enables the libcamera device monitor.
Support components
------------------
.. describe:: support.dbus
Provides a D-Bus connection to the session bus. This is needed by some other
support features (see below) but it is generally optional. WirePlumber does
not require a D-Bus connection to work.
On a system where WirePlumber is configured to run system-wide (headless,
embedded, etc), this will most likely fail to load and thus disable all the
other support features that require it. On such systems it makes sense to
disable this feature explicitly, to avoid the overhead of trying to connect
to the session bus.
.. describe:: support.reserve-device
Provides support for the
`D-Bus device reservation API <http://git.0pointer.net/reserve.git/tree/reserve.txt>`_,
allowing the device monitors to reserve devices for exclusive access.
:requires: ``support.dbus``
.. describe:: support.portal-permissionstore
Integrates with the flatpak portal permission store to give appropriate
access permissions to flatpak applications.
:requires: ``support.dbus``
.. describe:: support.logind
Integrates with systemd-logind to enable specific functionality only on the
active seat.
Policies
--------
.. describe:: policy.standard
Enables the standard WirePlumber policy. This includes all the logic
for enabling devices, linking streams, granting permissions to clients,
etc, as appropriate for a desktop system.
.. describe:: policy.role-based
Enables the role based priority system policy. This system creates virtual sinks
that group streams based on their ``media.role`` property, and assigns a
priority to each role. Depending on the priority configuration, lower
priority roles may be corked or ducked when a higher priority role stream
is active.
This policy was designed for automotive and mobile systems and may not work
as expected on desktop systems.
Note that this policy is implemented as a superset of ``policy.standard``,
so ``policy.standard`` should not be disabled when enabling this policy.
:requires: ``policy.standard``

View file

@ -1,13 +0,0 @@
# you need to add here any files you add to the toc directory as well
sphinx_files += files(
'conf_file.rst',
'components_and_profiles.rst',
'configuration_option_types.rst',
'modifying_configuration.rst',
'migration.rst',
'features.rst',
'settings.rst',
'alsa.rst',
'bluetooth.rst',
'access.rst',
)

View file

@ -1,305 +0,0 @@
.. _config_migration:
Migrating configuration from 0.4
================================
The configuration file format has changed in version 0.5. No automatic migration
of old configuration files is performed, so you will have to manually update
them. This document describes the changes and how to update your configuration.
wireplumber.conf
----------------
In WirePlumber 0.4, there used to be a ``.conf`` file, typically
``wireplumber.conf``, using the SPA-JSON format, that would list some Lua
scripts in the ``wireplumber.components`` section. These scripts were of type
``config/lua`` and they were called by default ``main.lua``, ``policy.lua`` and
``bluetooth.lua``.
Typical ``wireplumber.components`` section of a ``wireplumber.conf`` file in 0.4
would look like this:
.. code-block::
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(s)
# Other components are loaded from there
{ name = main.lua, type = config/lua }
{ name = policy.lua, type = config/lua }
{ name = bluetooth.lua, type = config/lua }
]
These Lua "configuration" scripts were then looked up in the standard
configuration directories (``/usr/share/wireplumber``, ``/etc/wireplumber`` and
``~/.config/wireplumber``). The system also supported fragments of these scripts
to be placed in directories called ``main.lua.d``, ``policy.lua.d`` and
``bluetooth.lua.d`` respectively, in the same locations.
.. attention::
Starting with WirePlumber 0.5, Lua "configuration" files are **no longer
supported**.
If you attempt to start it with a ``wireplumber.conf`` that still
lists ``config/lua`` components in its ``wireplumber.components`` section, you
will see the following error message on the output:
Failed to load configuration: The configuration file at '...' is likely an
old WirePlumber 0.4 config and is not supported anymore. Try removing it.
As the message says, to resolve this you should remove the old
``wireplumber.conf`` file from the designated location. This should allow the
new WirePlumber to start using the default configuration that it ships with.
Lua configuration scripts
-------------------------
If you had custom Lua configuration scripts in the standard configuration
directories, such as *"main.lua.d"*, *"policy.lua.d"* or *"bluetooth.lua.d"*,
**you need to port them**.
Locations of files
~~~~~~~~~~~~~~~~~~
The first thing you need to know is that the new files should be placed in the
``~/.config/wireplumber/wireplumber.conf.d/`` directory instead of
``~/.config/wireplumber/main.lua.d/`` and such ...
In addition, since the new files are in the SPA-JSON format, they should have
the ``.conf`` extension instead of ``.lua``.
See also :ref:`config_locations`.
Porting device/node rules
~~~~~~~~~~~~~~~~~~~~~~~~~
One of the most common use-cases for these scripts was to set up properties
for devices and nodes using rules. Here is an example of an old rules script:
.. code-block:: lua
:caption: ~/.config/wireplumber/main.lua.d/51-alsa-pro-audio.lua
local rule = {
matches = {
{
{ "device.name", "matches", "alsa_card.*" },
},
},
apply_properties = {
["api.alsa.use-acp"] = false,
["device.profile"] = "pro-audio",
["api.acp.auto-profile"] = false,
["api.acp.auto-port"] = false,
},
}
table.insert(alsa_monitor.rules, rule)
This equivalent of this script in the new configuration format would look like
this:
.. code-block::
:caption: ~/.config/wireplumber/wireplumber.conf.d/51-alsa-pro-audio.conf
monitor.alsa.rules = [
{
matches = [
{
device.name = "~alsa_card.*"
}
]
actions = {
update-props = {
api.alsa.use-acp = false,
device.profile = "pro-audio"
api.acp.auto-profile = false
api.acp.auto-port = false
}
}
}
]
Another example of Bluetooth node rules:
.. code-block:: lua
:caption: ~/.config/wireplumber/bluetooth.lua.d/51-headphones.lua
local rule = {
matches = {
{
{ "node.name", "equals", "bluez_output.02_11_45_A0_B3_27.a2dp-sink" },
},
},
apply_properties = {
["node.nick"] = "Headphones",
},
}
table.insert(bluez_monitor.rules, rule)
This equivalent of this script in the new configuration format would look like:
.. code-block::
:caption: ~/.config/wireplumber/wireplumber.conf.d/51-headphones.conf
monitor.bluez.rules = [
{
matches = [
{
node.name = "bluez_output.02_11_45_A0_B3_27.a2dp-sink"
}
]
actions = {
update-props = {
node.nick = "Headphones"
}
}
}
]
See also :ref:`config_modifying_configuration_rules`.
Porting properties configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you had configuration scripts that were setting properties in tables such
as ``alsa_monitor.properties`` or ``bluez_monitor.properties``, then in many
cases porting to the new format can be done as follows:
.. code-block:: lua
:caption: ~/.config/wireplumber/bluetooth.lua.d/80-bluez-properties.lua
bluez_monitor.properties["bluez5.roles"] = "[ a2dp_sink a2dp_source bap_sink bap_source hsp_hs hsp_ag hfp_hf hfp_ag ]"
bluez_monitor.properties["bluez5.hfphsp-backend"] = "native"
.. code-block::
:caption: ~/.config/wireplumber/wireplumber.conf.d/80-bluez-properties.conf
monitor.bluez.properties = {
bluez5.roles = [ a2dp_sink a2dp_source bap_sink bap_source hsp_hs hsp_ag hfp_hf hfp_ag ]
bluez5.hfphsp-backend = "native"
}
See also :ref:`config_modifying_configuration_static`.
In a lot of cases, however, these properties have been promoted to become either
:ref:`Settings <config_modifying_configuration_settings>` or
:ref:`Features <config_modifying_configuration_features>`.
Here are some common examples:
Disabling the D-Bus device reservation API in the ALSA monitor:
* Old format:
.. code-block:: lua
:caption: ~/.config/wireplumber/main.lua.d/80-disable-alsa-reserve.lua
alsa_monitor.properties["alsa.reserve"] = false
* New format:
.. code-block::
:caption: ~/.config/wireplumber/wireplumber.conf.d/80-disable-alsa-reserve.conf
wireplumber.profiles = {
main = {
monitor.alsa.reserve-device = disabled
}
}
Disabling seat monitoring via logind in the BlueZ monitor:
* Old format:
.. code-block:: lua
:caption: ~/.config/wireplumber/bluetooth.lua.d/80-disable-logind.lua
bluez_monitor.properties["with-logind"] = false
* New format:
.. code-block::
:caption: ~/.config/wireplumber/wireplumber.conf.d/80-disable-logind.conf
wireplumber.profiles = {
main = {
monitor.bluez.seat-monitoring = disabled
}
}
See also :ref:`config_modifying_configuration_features`.
Linking policy configuration (moved to settings and renamed):
* Old format:
.. code-block:: lua
:caption: ~/.config/wireplumber/policy.lua.d/80-policy.lua
default_policy.policy = {
["move"] = false,
["follow"] = false,
}
* New format:
.. code-block::
:caption: ~/.config/wireplumber/wireplumber.conf.d/80-policy.conf
wireplumber.settings = {
linking.allow-moving-streams = false
linking.follow-default-target = false
}
See also :ref:`config_modifying_configuration_settings` and remember that
settings can also be changed at runtime via :command:`wpctl`.
Loading custom scripts
~~~~~~~~~~~~~~~~~~~~~~
If you had custom Lua scripts that were loaded by the old configuration file,
you need to port the old ``load_script()`` commands into component descriptions.
For example, if you had a script that was loaded like this:
.. code-block:: lua
:caption: ~/.config/wireplumber/main.lua.d/99-my-script.lua
load_script("my-script.lua")
You should now create a new component description in the configuration file
and also make sure to require it in the profile:
.. code-block::
:caption: ~/.config/wireplumber/wireplumber.conf.d/99-my-script.conf
wireplumber.components = [
{
name = my-script.lua, type = script/lua
provides = custom.my-script
}
]
wireplumber.profiles = {
main = {
custom.my-script = required
}
}
.. attention::
Another important thing to mention here is the location of custom scripts. In
0.4, scripts could be loaded in configuration locations such as
``~/.config/wireplumber/scripts/`` and ``/etc/wireplumber/scripts/``. In 0.5,
the XDG base directory specification for data files is honored, so the new
location for custom scripts is ``~/.local/share/wireplumber/scripts/`` and
anything else specified in ``$XDG_DATA_HOME`` and ``$XDG_DATA_DIRS``. See
:ref:`daemon_file_locations` for more information.

View file

@ -1,365 +0,0 @@
.. _config_modifying_configuration:
Modifying configuration
=======================
WirePlumber is a heavily modular daemon that depends on its configuration
file to operate. If you were to start WirePlumber with an empty configuration
file, it would fail to start. This is why the default configuration file is
installed in the system-wide application data directory, which prevents it from
being modified by the user.
It is technically possible, if you wish, to copy the default configuration
file in one of the other :ref:`configuration search locations <config_locations>`
and modify it. However, this is **not recommended**, as it may lead to issues
when upgrading WirePlumber.
In the :ref:`Configuration file <config_conf_file>` section, we saw that
configuration files support fragments, which allow you to override or extend the
default configuration. This is the recommended way to modify the configuration.
Working with fragments
----------------------
The easiest way to add :ref:`fragments <config_conf_file_fragments>` to
modify the default configuration is to create a directory called
``~/.config/wireplumber/wireplumber.conf.d`` and place your fragments there.
All fragment files need to have the ``.conf`` extension and must be valid
SPA-JSON files. The fragments are loaded in alphanumerical order, so you can
control the order in which they are loaded by naming them accordingly. It is
recommended to use a numeric prefix for the file names, e.g.
``10-my-fragment.conf``, ``20-my-other-fragment.conf``, etc., so that you can
easily control the order in which they are loaded.
.. _config_modifying_configuration_features:
Customizing the loaded features
-------------------------------
As seen in the :ref:`Components & Profiles <config_components_and_profiles>`
section, the list of components that are loaded can be customized by enabling or
disabling :ref:`well-known features <config_features>` in the profile that is
in use by WirePlumber.
The default profile of WirePlumber is called ``main``, so a fragment that
enables or disables a specific feature in the default configuration should look
like this:
.. code-block::
wireplumber.profiles = {
main = {
some.feature.name = disabled
some.other.feature.name = required
}
}
Remember that features can be ``required``, ``optional`` or ``disabled``. See
the :ref:`Components & Profiles <config_components_and_profiles>` for details.
.. _config_modifying_configuration_settings:
Modifying dynamic options ("settings")
--------------------------------------
As seen in the :ref:`Configuration option types <config_configuration_option_types>`
section, WirePlumber components can be partly configured with dynamic options
(referred to as "settings"). These settings can either be modified permanently
in the configuration file, or they can be modified at runtime using the
``wpctl`` command-line tool.
To modify a setting in the configuration file, you can use a fragment like this:
.. code-block::
wireplumber.settings = {
some.setting.name = value
}
For example, setting the ``device.routes.default-sink-volume`` setting to
``0.5`` can be done like this:
.. code-block::
wireplumber.settings = {
device.routes.default-sink-volume = 0.5
}
.. note::
Since the configuration file is only read at startup, this will only take
effect after restarting WirePlumber.
If you would prefer to change the setting at runtime, you can use ``wpctl`` as
follows:
.. code-block:: bash
$ wpctl settings device.routes.default-sink-volume 0.5
Updated setting 'device.routes.default-sink-volume' to: 0.5
The above command changes the setting immediately, but for the current
WirePlumber instance only. If you want the setting to be applied every time
WirePlumber is started, you may also use the ``--save`` option:
.. code-block:: bash
$ wpctl settings --save device.routes.default-sink-volume 0.5
Updated and saved setting 'device.routes.default-sink-volume' to: 0.5
This will save the setting persistently in WirePlumber's state storage.
Even though it is not in the configuration file, this saved value will be
applied automatically when WirePlumber is started.
.. attention::
When a setting's value is saved, it will override the value from the
configuration file. Changing the value in the configuration file will
have no effect until the saved value is removed. Use the ``--delete``
switch in ``wpctl`` to remove a saved value (see below).
With ``wpctl``, it is also possible to restore a setting to its default value
(taken from the schema), by using the ``--reset`` option. For example, to reset
the ``device.routes.default-sink-volume`` setting, the following command can be
used:
.. code-block:: bash
$ wpctl settings --reset device.routes.default-sink-volume
Reset setting 'device.routes.default-sink-volume' successfully
$ wpctl settings device.routes.default-sink-volume
Value: 0.064 (Saved: 0.5)
Note that the ``--reset`` option will only reset the setting to its default
value, but it will not remove the saved value from the state file. If you want
to remove the saved value, you can use the ``--delete`` option:
.. code-block:: bash
$ wpctl settings --delete device.routes.default-sink-volume
Deleted setting 'device.routes.default-sink-volume' successfully
$ wpctl settings device.routes.default-sink-volume
Value: 0.064
A list of all the available settings can be found in the :ref:`config_settings`
section.
.. _config_modifying_configuration_static:
Modifying static options
------------------------
Static options always live in their own section of the configuration file.
Sections can be of two types: either a JSON object or a JSON array.
When dealing with a **JSON object**, you can add or modify a key-value pair by
creating a fragment like this:
.. code-block::
wireplumber.some-section = {
some.option = new_value
}
This is similar to what we have seen also above for modifying profile features
and settings (because both are JSON objects).
When dealing with a **JSON array**, any values that you define in a fragment
will be appended to the array. For example, to add a new rule to the
``monitor.alsa.rules`` array, you can create a fragment like this:
.. code-block::
monitor.alsa.rules = [
{
matches = [
{
device.name = "~alsa_card.*"
}
]
actions = {
update-props = {
api.alsa.use-ucm = false
}
}
}
]
This will add a new rule to the ``monitor.alsa.rules`` array, which will
be evaluated **after** all other rules that were parsed before. This is where
the order in which fragments are loaded actually matters.
If you don't want to append a new rule, but rather override the entire array
with a new one, you can do so by using the ``override.`` prefix on the array
name:
.. code-block::
override.monitor.alsa.rules = [
{
matches = [
{
device.name = "~alsa_card.*"
}
]
actions = {
update-props = {
api.alsa.use-ucm = false
}
}
}
]
This will now replace the entire ``monitor.alsa.rules`` array with this new one.
.. attention::
If you want to remove a rule from the array, you will need to override the
whole array with a new one that does not contain the rule you want to remove.
There is no way to remove a specific element from an array using fragments.
Another thing worth remembering here is that this behavior of appending values
to arrays also works in arrays that are nested inside other arrays or objects.
For example, consider this fragment:
.. code-block::
monitor.bluez.properties = {
bluez5.codecs = [ sbc_xq aac ldac ]
}
If this is the first time that the ``bluez5.codecs`` array is being defined, it
will be created with the given values. If it already exists, the given values
will be appended to the existing array. If you want to make sure that this
fragment will override the existing array, you need to use the ``override.``
prefix on the array name:
.. code-block::
monitor.bluez.properties = {
override.bluez5.codecs = [ sbc_xq aac ldac ]
}
The ``override.`` prefix may also be used in JSON object keys, to override the
entire object with a new one. For example, to override the entire
``monitor.bluez.properties`` object, you can use a fragment like this:
.. code-block::
override.monitor.bluez.properties = {
bluez5.codecs = [ sbc_xq aac ldac ]
}
Here, the entire ``monitor.bluez.properties`` object will be replaced with the
new one, and all previous key-value pairs configured will be discarded. This
also means that the ``bluez5.codecs`` array will be replaced with the new one
and does not require the ``override.`` prefix.
.. note::
Even though WirePlumber uses PipeWire's syntax for configuration files, the
``override.`` prefix is a WirePlumber extension and does not work in
PipeWire.
.. _config_modifying_configuration_rules:
Working with rules
------------------
Some of the static option sections in the configuration file are used to define
rules that are evaluated by WirePlumber at runtime. These rules are typically
used to match objects and perform actions on them. For example, the
``monitor.alsa.rules`` section is used to define rules that are evaluated by
the ALSA monitor to match ALSA devices and update their properties.
The syntax of these rules is the same as the syntax of
`PipeWire's rules <https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Config-PipeWire#rules>`_.
A rule is always a JSON object with two keys: ``matches`` and ``actions``. The
``matches`` key is used to define the conditions that need to be met for the
rule to be evaluated as true, and the ``actions`` key is used to define the
actions that are performed when the rule is evaluated as true.
The ``matches`` key is always a JSON array of objects, where each object
defines a condition that needs to be met. Each condition is a list of key-value
pairs, where the key is the name of the property that is being matched, and the
value is the value that the property needs to have. Within a condition, all
the key-value pairs are combined with a logical AND, and all the conditions in
the ``matches`` array are combined with a logical OR.
The ``actions`` key is always a JSON object, where each key-value pair defines
an action that is performed when the rule is evaluated as true. The action
name is specific to the rule and is defined by the rule's documentation, but
most frequently you will see the ``update-props`` action, which is used to
update the properties of the matched object.
For example:
.. code-block::
some.theoretical.rules = [
{
matches = [
{
object.name = "my_object"
object.profile.name = "my_profile"
}
{
object.name = "other_object"
}
]
actions = {
update-props = {
object.tag = "matched_by_my_rule"
}
}
}
]
This rule is equivalent to the following expression:
.. code-block:: python
if (properties["object.name"] == "my_object" and properties["object.profile.name"] == "my_profile") or (properties["object.name"] == "other_object"):
properties["object.tag"] = "matched_by_my_rule"
In the ``matches`` array, it is also possible to use regular expressions to match
property values. For example, to match all nodes with a name that starts with
``my_``, you can use the following condition:
.. code-block::
matches = [
{
node.name = "~my_.*"
}
]
The ``~`` character signifies that the value is a regular expression. The exact
syntax of the regular expressions is the POSIX extended regex syntax, as
described in the `regex (7)` man page.
In addition to regular expressions, you may also use the ``!`` character to
negate a condition. For example, to match all nodes with a name that does not
start with ``my_``, you can use the following condition:
.. code-block::
matches = [
{
node.name = "!~my_.*"
}
]
The ``!`` character can be used with or without a regular expression. For
example, to match all nodes with a name that is not equal to ``my_node``,
you can use the following condition:
.. code-block::
matches = [
{
node.name = "!my_node"
}
]

View file

@ -1,228 +0,0 @@
.. _config_settings:
Well-known settings
===================
This section describes the settings that can be configured on WirePlumber.
Settings can be either configured statically in the configuration file
by setting them under the ``wireplumber.settings`` section, or they can be
configured dynamically at runtime by using metadata.
For more information on what "settings" are and how they work, refer to the
previous section: :ref:`config_configuration_option_types`.
.. describe:: device.restore-profile
When a device profile is changed manually (e.g. via pavucontrol), WirePlumber
stores the selected profile and restores it when the device appears again
(e.g. after a reboot). If this setting is disabled, WirePlumber will always
pick the best profile for the device based on profile priorities and
availability (or custom rules, if any).
:Default value: ``true``
.. describe:: device.restore-routes
When a device route is changed manually (e.g. via pavucontrol), WirePlumber
stores the selected route and restores it when the same profile is
selected for this device. If this setting is disabled, WirePlumber will
always pick the best route for this device profile based on route priorities
and availability (or custom rules, if any).
This setting also enables WirePlumber to restore properties of the device
route when the route is restored. This includes the volume levels of sources
and sinks, as well as the IEC958 codecs selected (for routes that support
encoded streams, such as HDMI).
:Default value: ``true``
.. describe:: device.routes.default-sink-volume
This option allows to set the default volume for sinks that are part of a
device route (e.g. ALSA PCM sinks). This is used when the route is restored
and the sink does not have a previously stored volume.
It is possible to override the value on a per-device basis with a property
(*not* a setting, so this would go into a configuration file) on the device
named ``device.routes.default-sink-volume``.
:Default value: ``0.4 ^ 3`` (40% on the cubic scale)
.. describe:: device.routes.default-source-volume
This option allows to set the default volume for sources that are part of a
device route (e.g. ALSA PCM sources). This is used when the route is restored
and the source does not have a previously stored volume.
It is possible to override the value on a per-device basis with a property
(*not* a setting, so this would go into a configuration file) on the device
named ``device.routes.default-source-volume``.
:Default value: ``1.0`` (100%)
.. describe:: linking.allow-moving-streams
This option allows moving streams by overriding their target via metadata.
When enabled, WirePlumber monitors the "default" metadata for changes in the
``target.object`` key of streams and if this key is set to a valid node name
(``node.name``) or serial (``object.serial``), the stream is moved to that
target node.
This is used by applications such as pavucontrol and is recommended for
compatibility with PulseAudio.
.. note::
On the metadata, the ``target.node`` key is also supported for
compatibility with older versions of PipeWire, but it is deprecated.
Please use the ``target.object`` key instead.
:Default value: ``true``
:See also: ``node.stream.restore-target``
.. describe:: linking.follow-default-target
When a stream was started with the ``target.object`` property, WirePlumber
normally links that stream to that target node and ignores the "default"
target for that direction. However, if this option is enabled, WirePlumber
will check if the designated target node *is* the "default" target and if so,
it will act as if the stream did not have that property.
In practice, this means that if the "default" target changes at runtime,
the stream will be moved to the new "default" target.
This is what Pulseaudio does and is implemented here for compatibility
with some applications that do start with a ``target.object`` property
set to the "default" target and expect the stream to be moved when the
"default" target changes.
Note that this logic is only applied on client (i.e. application) streams
and *not* on filters.
:Default value: ``true``
.. describe:: linking.pause-playback
When an audio sink is removed, pause media players that have streams
playing to it. Pausing is done via MPRIS interface.
:Default value: ``true``
.. describe:: node.features.audio.no-dsp
When this option is set to ``true``, audio nodes will not be configured
in dsp mode, meaning that their channels will *not* be split into separate
ports and that the audio data will *not* be converted to the float 32 format
(F32P). Instead, devices will be configured in passthrough mode and streams
will be configured in convert mode, so that their audio data is converted
directly to the format that the device is expecting.
This may be useful if you are trying to minimize audio processing for an
embedded system, but it is not recommended for general use.
.. warning::
This option **will break** compatibility with JACK applications
and may also break certain patchbay applications. Do not enable, unless
you understand what you are doing.
:Default value: ``false``
.. describe:: node.features.audio.monitor-ports
This enables the creation of "monitor" ports for audio nodes. Monitor ports
are created on nodes that have input ports (i.e. sinks and capture streams)
and allow monitoring of the audio data that is being sent to the node.
This is mostly used by monitoring applications, such as pavucontrol.
:Default value: ``true``
.. describe:: node.features.audio.control-port
This enables the creation of a "control" port for audio nodes. Control ports
allow sending MIDI data to the node, allowing for control of certain node's
parameters (such as volume) via external controllers.
:Default value: ``false``
.. describe:: node.stream.restore-props
WirePlumber stores stream parameters such as volume and mute status for each
client (i.e. application) stream. If this setting is enabled, WirePlumber
will restore the previously stored stream parameters when the stream is
activated. If it is disabled, stream parameters will be initialized to their
default values.
:Default value: ``true``
.. describe:: node.stream.restore-target
When a client (i.e. application) stream is manually moved to a different
target node (e.g. via pavucontrol), the target node is stored by WirePlumber.
If this setting is enabled, WirePlumber will restore the previously stored
target node when the stream is activated.
.. note::
This does not restore manual links made by patchbay applications. This
is only meant to restore the ``target.object`` property in the "default"
metadata, which is manipulated by applications such as pavucontrol when
a stream is moved to a different target.
:Default value: ``true``
:See also: ``linking.allow-moving-streams``
.. describe:: node.stream.default-playback-volume
The default volume for playback streams to be applied when the stream is
activated. This is only applied when ``node.stream.restore-props`` is
``true`` and the stream does not have a previously stored volume.
:Default value: ``1.0``
:Range: ``0.0`` to ``1.0``
.. describe:: node.stream.default-capture-volume
The default volume for capture streams to be applied when the stream is
activated. This is only applied when ``node.stream.restore-props`` is
``true`` and the stream does not have a previously stored volume.
:Default value: ``1.0``
:Range: ``0.0`` to ``1.0``
.. describe:: node.filter.forward-format
When a "filter" pair of nodes (such as echo-cancel or filter-chain) is
linked to a device node that has a different channel map than the filter
nodes, this option allows the channel map of the filter nodes to be changed
to match the channel map of the device node. The change is applied to both
ends of the "filter", so that any streams linked to the filter are also
reconfigured to match the target channel map.
This is useful, for instance, to make sure that an application will be
properly configured to output surround audio to a surround device, even
when going through a filter that was not explicitly configured to have
a surround channel map.
:Default value: ``false``
.. describe:: node.restore-default-targets
This setting enables WirePlumber to store and restore the "default" source
and sink targets of the graph. In PulseAudio terminology, this is also known
as the "fallback" source and sink.
When this setting is enabled, WirePlumber will store the "default" source
and sink targets when they are changed manually (e.g. via pavucontrol) and
restore them when the available nodes change or after a reload/restart.
It will also store a history of past selected "default" targets and restore
previously selected ones if the currently selected are not available.
If this is disabled, WirePlumber will pick the best available source
and sink targets based on their priorities, but it will also respect
manual user selections that are done at runtime - it will just not remember
them so that it can restore them at a later time.
:Default value: ``true``

View file

@ -1,175 +0,0 @@
.. _daemon_file_locations:
Locations of WirePlumber's files
================================
.. _config_locations:
Location of configuration files
-------------------------------
WirePlumber's default locations of its configuration files are the following,
in order of priority:
1. ``$XDG_CONFIG_HOME/wireplumber``
2. ``$XDG_CONFIG_DIRS/wireplumber``
3. ``$sysconfdir/wireplumber``
4. ``$XDG_DATA_DIRS/wireplumber``
5. ``$datadir/wireplumber``
Notes:
* ``$syscondir`` and ``$datadir`` refer to
`meson's directory options <https://mesonbuild.com/Builtin-options.html#directories>`_
and are hardcoded at build time
* ``$XDG_`` variables refer to the
`XDG Base Directory Specification <https://specifications.freedesktop.org/basedir-spec/latest/index.html>`_
It is recommended that user specific overrides are placed in
``$XDG_CONFIG_HOME/wireplumber``, while host-specific configuration is placed in
``$XDG_CONFIG_DIRS/wireplumber`` or ``$sysconfdir/wireplumber`` and
distribution-provided configuration is placed in ``$XDG_DATA_DIRS/wireplumber``
or ``$datadir/wireplumber``.
At runtime, WirePlumber will seek out the directory with the highest priority
that contains the required configuration file. This setup allows a user or
system administrator to effortlessly override the configuration files provided
by the distribution. They can achieve this by placing a file with an identical
name in a higher priority directory.
It is also possible to override the configuration directory by setting the
``WIREPLUMBER_CONFIG_DIR`` environment variable:
.. code-block:: bash
WIREPLUMBER_CONFIG_DIR=src/config wireplumber
``WIREPLUMBER_CONFIG_DIR`` supports listing multiple directories, using the
standard path list separator ``:``. If multiple directories are specified,
the first one has the highest priority and the last one has the lowest.
.. note::
When the configuration directory is overridden with
``WIREPLUMBER_CONFIG_DIR``, the default locations are ignored and
configuration files are *only* looked up in the directories specified by this
variable.
.. _config_locations_fragments:
Configuration fragments
^^^^^^^^^^^^^^^^^^^^^^^
WirePlumber also supports configuration fragments. These are configuration files
that are loaded in addition to the main configuration file, allowing to
override or extend the configuration without having to copy the whole file.
See also the :ref:`config_conf_file_fragments` section for semantics.
Configuration fragments are always loaded from subdirectories of the main search
directories that have the same name as the configuration file, with the ``.d``
suffix appended. For example, if WirePlumber loads ``wireplumber.conf``, it will
also load ``wireplumber.conf.d/*.conf``. Note also that the fragment files need
to have the ``.conf`` suffix.
When WirePlumber loads a configuration file from the default locations, it will
also load all configuration fragments that are present in all of the default
locations, but following the reverse order of priority. This allows
configuration fragments that are installed in more system-wide locations to be
overridden by the system administrator or the users.
For example, assuming WirePlumber loads ``wireplumber.conf``, from any of the
search locations, it will also locate and load the following fragments, in this
order:
1. ``$datadir/wireplumber/wireplumber.conf.d/*.conf``
2. ``$XDG_DATA_DIRS/wireplumber/wireplumber.conf.d/*.conf``
3. ``$sysconfdir/wireplumber/wireplumber.conf.d/*.conf``
4. ``$XDG_CONFIG_DIRS/wireplumber/wireplumber.conf.d/*.conf``
5. ``$XDG_CONFIG_HOME/wireplumber/wireplumber.conf.d/*.conf``
Within each search location that contains fragments, the individual fragment
files are opened in alphanumerical order. This can be important to know, because
the parsing order matters in merging. See :ref:`config_conf_file_fragments`
.. note::
When ``WIREPLUMBER_CONFIG_DIR`` is set, the default locations are ignored and
fragment files are *only* looked up in the directories specified by this
variable.
.. _config_locations_scripts:
Location of scripts
-------------------
WirePlumber's default locations of its data files are the following,
in order of priority:
1. ``$XDG_DATA_HOME/wireplumber``
2. ``$XDG_DATA_DIRS/wireplumber``
3. ``$datadir/wireplumber``
At runtime, WirePlumber will search the directories for the highest-priority
directory to contain the needed data file.
Scripts are a specific kind of "data" files and are expected to be located
within a ``scripts`` subdirectory in the above data search locations. The "data"
directory is a somewhat more generic path that may be used for other kinds of
data files in the future.
It is also possible to override the data directory by setting the
``WIREPLUMBER_DATA_DIR`` environment variable:
.. code-block:: bash
WIREPLUMBER_DATA_DIR=src wireplumber
As with the default data directories, script files in particular are expected
to be located within a ``scripts`` subdirectory, so in the above example the
scripts would actually reside in ``src/scripts``.
``WIREPLUMBER_DATA_DIR`` supports listing multiple directories, using the
standard path list separator ``:``. If multiple directories are specified,
the first one has the highest priority and the last one has the lowest.
.. note::
When ``WIREPLUMBER_DATA_DIR`` is set, the default locations are ignored and
scripts are *only* looked up in the directories specified by this variable.
Location of modules
-------------------
WirePlumber modules
^^^^^^^^^^^^^^^^^^^
WirePlumber's default location of its modules is
``$libdir/wireplumber-$api_version``, where ``$libdir`` is set at compile time
by the build system. Typically, it ends up being ``/usr/lib/wireplumber-0.5``
(or ``/usr/lib/<arch-triplet>/wireplumber-0.5`` on multiarch systems)
It is possible to override this directory at runtime by setting the
``WIREPLUMBER_MODULE_DIR`` environment variable:
.. code-block:: bash
WIREPLUMBER_MODULE_DIR=build/modules wireplumber
``WIREPLUMBER_MODULE_DIR`` supports listing multiple directories, using the
standard path list separator ``:``. If multiple directories are specified, the
first one has the highest priority and the last one has the lowest.
.. note::
When ``WIREPLUMBER_MODULE_DIR`` is set, the default locations are ignored and
scripts are *only* looked up in the directories specified by this variable.
PipeWire and SPA modules
^^^^^^^^^^^^^^^^^^^^^^^^
PipeWire and SPA modules are not loaded from the same location as WirePlumber's
modules. They are loaded from the location that PipeWire loads them.
It is also possible to override these locations by using environment variables:
``SPA_PLUGIN_DIR`` and ``PIPEWIRE_MODULE_DIR``. For more details, refer to
PipeWire's documentation.

View file

@ -1,248 +0,0 @@
.. _daemon_logging:
Debug Logging
=============
WirePlumber is instrumented with log messages in its entire codebase. These
messages are categorized based on two heuristics: the log topic and the log
level.
The log topic is a string that identifies which component of the code this
message is coming from. Well-known topics include:
- **wireplumber**: messages from the wireplumber daemon
- **wp-***: messages from libwireplumber
- **wp-core**: messages from *WpCore*
- **wp-proxy**: messages from *WpProxy*
- ... and so on ...
- **m-***: messages from wireplumber modules
- **m-default-profile**: messages from *libwireplumber-module-default-profile*
- **m-default-routes**: messages from *libwireplumber-module-default-routes*
- ... and so on ...
- **s-***: messages from scripts
- **s-linking**: messages from the *linking/\*.lua* scripts
- **s-default-nodes**: messages from the *default-nodes/\*.lua* scripts
- ... and so on ...
- **pw.***: messages from libpipewire
- **spa.***: messages from spa plugins
- **mod.***: messages from libpipewire modules
- **conn.***: messages to debug the pipewire socket connection
The log level is a value that designates the importance of the message.
The levels that exist in WirePlumber are the following:
- ``F``: *Fatal errors*. These messages represent situations where execution
of the program cannot continue. In the extremely unlikely case that
they appear, these messages also cause the process to be terminated.
- ``E``: *Critical warnings* (or "errors" in the PipeWire terminology).
These messages represent situations where something unexpected has happened
and someone with understanding of the code should probably take a look at it.
These situations are usually programming mistakes or omissions.
This does not necessarily mean that the program is not functioning correctly.
It may mean, though, that the specific part of the program that logged the
message (the plugin, subsystem, ...) may not work optimally.
- ``W``: *Warnings*. These messages represent situations where something has
gone unintentionally wrong, but it was not totally unexpected. The situation
is recovered and the program can continue. In many cases, this warning may
mean that there is something wrong with the configuration or the environment
and may need attention from the user.
- ``N``: *Notices*. These are important messages that the user should notice,
like warnings, but they do not necessarily mean a bad situation.
- ``I``: *Informational messages*. These messages provide information about
the internal operations of the program.
- ``D``: *Debug messages*. These messages provide details about the
internal operations of the program, which can be useful for debugging.
- ``T``: *Traces*. These messages provide very verbose printouts of internal
operations and data that affects these operations. These can be useful for
debugging as well, but it may be best to be enabled only for the topic(s)
that are intended to be debugged, as they can be very big in volume.
By default, WirePlumber logs only messages from levels ``F``, ``E``, ``W``
and ``N``. These messages are printed on the standard error (``stderr``) stream,
or they are logged to the systemd journal, if WirePlumber was started as a
systemd service.
The ``WIREPLUMBER_DEBUG`` environment variable can be used to change which
topics and levels are enabled. The generic syntax is:
.. code::
WIREPLUMBER_DEBUG=[<topic pattern>:]<level>,...,
This is a comma-separated list of topics to enable, paired with a level for
each topic.
``<level>`` can be one of ``FEWNIDT`` or a numerical log level as listed below.
0. fatal errors (``F``)
1. critical warnings (``E``)
2. warnings and notices (``W`` & ``N``)
3. informational messages (``I``)
4. debug messages (``D``)
5. trace messages (``T``)
Each level always includes messages from the previous levels, so for instance
enabling level ``3`` (or ``I``) will also enable messages from levels ``2``
and ``1`` (``N``, ``W``, ``E`` and ``F``)
``<topic pattern>`` is an *optional* description of one or more topics.
This supports
`glob style patterns <https://developer-old.gnome.org/glib/stable/glib-Glob-style-pattern-matching.html>`_
containing ``*`` and ``?``.
If a ``<topic pattern>`` is not specified, then the given ``<level>`` is
considered to be the global log level, which applies to all topics that have
no explicit level specified.
Changing log level at runtime
-----------------------------
The debug log level can be changed at runtime using ``wpctl``:
.. code::
wpctl set-log-level D # enable debug logging for Wireplumber
wpctl set-log-level - # restore default logging for Wireplumber
wpctl set-log-level 0 4 # enable debug logging for Pipewire daemon
wpctl set-log-level 0 - # restore default logging for Pipewire daemon
Equivalently, it is also possible to adjust the logging by setting
``log.level`` in the ``settings`` metadata:
.. code::
pw-metadata -n settings <ID> log.level "D" # WirePlumber logging
pw-metadata -n settings 0 log.level 4 # PipeWire daemon logging
Above, ``<ID>`` should be replaced by the WirePlumber daemon client ID.
Note that PipeWire daemon log levels must be specified by numbers, not
letter codes.
Changing log level via static configuration
-------------------------------------------
If you need to capture logs from WirePlumber at startup or in other circumstances
where changing the level at runtime or setting an environment variable is not
feasible, then you may also set the log level in the configuration file.
The log level changes via the ``log.level`` key in the ``context.properties``
section:
.. code::
context.properties = {
log.level = "D"
}
You may use the same syntax as in ``WIREPLUMBER_DEBUG`` to describe the exact
logging you want to achieve. For instance, to log debug messages from all
scripts and informational messages from everywhere else:
.. code::
context.properties = {
log.level = "I,s-*:D"
}
The easiest way to configure this is to drop a
:ref:`fragment file <config_conf_file_fragments>` that contains just this.
.. code-block:: bash
$ mkdir -p ~/.config/wireplumber/wireplumber.conf.d
$ echo 'context.properties = { log.level = "D" }' > ~/.config/wireplumber/wireplumber.conf.d/log.conf
See also :ref:`config_modifying_configuration`
Examples
--------
Show *all* messages:
.. code::
WIREPLUMBER_DEBUG=T
Show all messages up to the *debug* level (F, E, W, N, I & D), excluding *trace*:
.. code::
WIREPLUMBER_DEBUG=D
Show all messages up to the *notice* level (F, E, W & N),
excluding *info*, *debug* & *trace*
(this is also the default when ``WIREPLUMBER_DEBUG`` is omitted):
.. code::
WIREPLUMBER_DEBUG=2
Show all messages from the wireplumber library (including traces), but only
up to informational messages from other topics:
.. code::
WIREPLUMBER_DEBUG=I,wp-*:T
Show debug messages from ``wp-registry``, libpipewire and all modules, keeping
all other topics up to the *notice* level.
.. code::
WIREPLUMBER_DEBUG=2,wp-registry:4,pw.*:4,m-*:4
Relationship with the GLib log handler & G_MESSAGES_DEBUG
---------------------------------------------------------
Older versions of WirePlumber used to use ``G_MESSAGES_DEBUG`` to control their
log output, which is the environment variable that affects GLib's default
log handler.
As of WirePlumber 0.3, ``G_MESSAGES_DEBUG`` is no longer used, since
libwireplumber replaces the default log handler.
If you are writing your own application based on libwireplumber, you can choose
if you want to replace this log handler using the flags passed to
:c:func:`wp_init`.
Relationship with the PipeWire log handler & PIPEWIRE_DEBUG
-----------------------------------------------------------
libpipewire uses the ``PIPEWIRE_DEBUG`` environment variable, with a similar syntax.
WirePlumber replaces the log handler of libpipewire with its own, rendering
``PIPEWIRE_DEBUG`` useless. Instead, you should use ``WIREPLUMBER_DEBUG``.
All the log topics that apply to libpipewire and its modules / plugins work
the same in ``WIREPLUMBER_DEBUG``.
If you are writing your own application based on libwireplumber, you can choose
if you want to replace this log handler using the flags passed to
:c:func:`wp_init`.
Mapping of PipeWire debug levels to WirePlumber
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
PipeWire supports 5 levels of debug logging. WirePlumber, on the other hand,
supports 7 levels. Some levels seem common, but the terminology and the
semantics are slightly different. The following table shows how the various
levels are mapped:
============= =============== ========================
Numeric Level PipeWire WirePlumber
============= =============== ========================
0 no log ``F`` - Fatal Error
1 ``E`` - Error ``E`` - Critical Warning
2 ``W`` - Warning ``W`` - Warning,
``N`` - Notice
3 ``I`` - Info ``I`` - Info
4 ``D`` - Debug ``D`` - Debug
5 ``T`` - Trace ``T`` - Trace
============= =============== ========================

View file

@ -1,11 +0,0 @@
# you need to add here any files you add to the toc directory as well
sphinx_files += files(
'installing.rst',
'running.rst',
'configuration.rst',
'locations.rst',
'logging.rst',
'multi_instance.rst',
)
subdir('configuration')

View file

@ -1,88 +0,0 @@
.. _daemon_multi_instance:
Running multiple instances
==========================
WirePlumber has the ability to run either as a single instance daemon or as
multiple instances, meaning that there can be multiple processes, each one
doing a different task.
The most common use case for such a setup is to separate the graph orchestration
tasks from the device monitoring and object creation ones. This can be useful
for robustness and security reasons, as it allows restarting the device monitors
or running them in different security contexts without affecting the rest of the
session management functionality.
To achieve a multi-instance setup, WirePlumber can be started multiple times
with a different :ref:`profile<config_components_and_profiles>` loaded in each
instance. This can be achieved using the ``--profile`` command line option to
select the profile to load:
.. code-block:: console
$ wireplumber --profile=custom
When no particular profile is specified, the ``main`` profile is loaded.
For multi-instance configuration, the default ``wireplumber.conf`` specifies 4
profiles:
.. describe:: policy
This profile runs all the policy scripts, i.e. ones that monitor changes
in the graph and execute actions to link nodes, select default devices,
create new nodes or configure existing ones differently.
.. describe:: audio
The audio profile runs the ALSA and ALSA MIDI monitors, which make audio &
MIDI devices available to PipeWire.
.. describe:: bluetooth
The bluetooth profile runs the BlueZ and BlueZ MIDI monitors, which enable
Bluetooth audio & MIDI devices and other Bluetooth functionality tied to the
A2DP, HSP, HFP and BAP profiles, using BlueZ.
.. describe:: video-capture
The video-capture profile runs the V4L2 and libcamera monitors, which make
video capture devices, such as cameras and HDMI capture cards, available
to PipeWire.
.. note::
The ``main`` profile includes all the functionality of the ``policy``,
``audio``, ``video-capture`` and ``bluetooth`` profiles combined (i.e. it is
the default for a standard single instance configuration). You should never
load the ``main`` profile alongside these other 4 profiles, as their
functionality will conflict.
.. warning::
Always ensure that the instances you load serve a different purpose and they
do not conflict with each other. Conflicting components executed in parallel
will have undefined behavior.
Systemd integration
-------------------
To make this easier to work with, a template systemd unit is provided, which is
meant to be started with the name of the profile as a template argument:
.. code-block:: console
$ systemctl --user disable wireplumber # disable the "main" profile instance
$ systemctl --user enable wireplumber@policy
$ systemctl --user enable wireplumber@audio
$ systemctl --user enable wireplumber@video-capture
$ systemctl --user enable wireplumber@bluetooth
.. note::
In WirePlumber 0.4, the template argument was the name of the configuration
file to load, since profiles did not exist. In WirePlumber 0.5, the template
argument is the name of the profile and the configuration file is always
``wireplumber.conf``. To change the name of the configuration file you need
to craft custom systemd unit files and use the ``--config-file`` command line
option as needed.

View file

@ -1,139 +0,0 @@
.. _design_events_and_hooks:
Events and Hooks
================
Session management is all about reacting to events and taking necessary
actions. This is why WirePlumber's logic is all built on events and hooks.
Events
------
Events are objects that represent a change that has just happened on a PipeWire
object, or just a trigger for making a decision and potentially taking some
action.
Every event has a source, a subject and some properties, which include the
event type.
* The ``source`` is a reference to the GObject that created this event.
Typically, this is the ``WpStandardEventSource`` plugin.
* The ``subject`` is an *optional* reference to the object that this event
is about. For example, in a ``node-added`` event, the ``subject`` would be
a reference to the ``WpNode`` object that was just added. Some events,
especially those which are used only to trigger actions, do not have a
subject.
* The ``properties`` is a dictionary that contains information about the event,
including the event type, and also includes all the PipeWire properties of the
``subject``, if there is one.
* The ``event.type`` property describes the nature of the event, for example
``node-added`` or ``metadata-changed`` are some valid event types.
Every event also has a priority. Events with a higher priority are processed
before events with a lower priority. When two or more events have the same
priority, they are processed in a first-in-first-out manner. This logic
is defined in the *event dispatcher*.
Events are short-lived objects. They are created at the time that something is
happening and they are destroyed after they get processed. Processing an event
means executing all the hooks that are associated with it. The next section
explains what hooks are and how they are associated with events.
Hooks
-----
Hooks are objects that represent a runnable action that needs to be executed
when a certain event is processed. Every hook, therefore, consists of a
function - synchronous or asynchronous - that can be executed. Additionally,
every hook has a means to associate itself with specific events. This is
normally done by declaring *interest* to specific event properties or
combinations of them.
There are two main types of hooks: ``SimpleEventHook`` and ``AsyncEventHook``.
* ``SimpleEventHook`` contains a single, synchronous function. As soon as this
function is executed, the hook is completed.
* ``AsyncEventHook`` contains multiple functions, combined together in a state
machine using ``WpTransition`` underneath. The hook is completed only after
the state machine reaches its final state and this can take any amount of time
necessary.
Every hook also has a name, which can be an arbitrary string of characters.
Additionally, it has two arrays of names, which declare dependencies between
this hook and others. One array is called ``before`` and the other is called
``after``. The hook names in the ``before`` array specify that this hook must
be executed *before* those other hooks. Similarly, the hook names in the
``after`` array specify that this hook must be executed *after* those other
hooks. Using this mechanism, it is possible to define the order in which
hooks will be executed, for a specific event.
Hooks are long-lived objects. They are created once, registered in the
*event dispatcher*, they are attached on events and detached after their
execution. They don't maintain any internal state, so the actions of the hook
depend solely on the event itself.
The Event Dispatcher
--------------------
The event dispatcher is a (per core) singleton object that processes all events
and also maintains a list of all the registered hooks. It has a method to
*push* events on it, which causes them to be scheduled for processing.
Scheduling of events and hooks
------------------------------
The main idea and reasoning behind this architecture is to have everything
execute in a predefined order and always wait for an action to finish before
executing the next one.
Every event has a *priority* and every hook also has an order of execution that
derives from the inter-dependencies between hooks, which are defined with
``before`` and ``after`` (see above). When an event is pushed on the dispatcher,
the dispatcher goes through all the registered hooks and checks which hooks are
configured to run on this event (their event interest matches the event).
It then makes a list of them, sorted by their order of execution, and stores it
on the event. The event is then added on the dispatcher's list of events, which
is sorted by priority.
For example::
List of events
| event1 (prio 99) -> hook1, hook2, hook3
| event2 (prio 50) -> hook5, hook2, hook4
v
The dispatcher has an internal ``GSource`` that is registered with
``G_PRIORITY_HIGH_IDLE`` priority. When there is at least one event in the
list of events, the source is dispatched. Every time it gets dispatched,
it takes the top-most event (the highest priority one) and executes the highest
priority hook in that event. If the hook executes synchronously, it then takes
the next hook and continues until there are no more hooks on this event;
then it goes to the next event, and so on. If the hook, however, executes
asynchronously, processing stops until the hook finishes; after finishing,
processing resumes like before.
It is important to notice here that the list of events may be modified while
events are getting processed. For example, a device is added; that's a
``device-added`` event. Then a hook is executed to set the profile. That creates
nodes, so a couple of ``node-added`` events... But there is also another hook to
set the route, which was attached on the ``device-added`` event for the device.
Suppose that we give the ``node-added`` events lower priority than the
``device-added`` events, then the ``set-route`` hook will execute right after
the ``set-profile`` and before any ``node-added`` events are processed.
Visually, with sample priorities::
List of events
| "device-added" (prio 20) -> set-profile, set-route
| "node-added" (prio 10) -> restore-stream, create-session-item
v
Obviously, there can also be a case where a newly added event has higher
priority than the event that was being processed before. In that case,
processing the hooks of the original event is stopped until all the hooks from
the higher priority event have been processed. For example, a capture stream
node being added may trigger the "bluetooth autoswitch" hook, which will then
change the profile of a device. Changing the profile also has to trigger setting
a new route and also handling the new device nodes, creating session items for
them... After all this is done, processing the original capture stream
``node-added`` event can continue.

View file

@ -1,6 +0,0 @@
# you need to add here any files you add to the toc directory as well
sphinx_files += files(
'understanding_session_management.rst',
'understanding_wireplumber.rst',
'events_and_hooks.rst',
)

View file

@ -1,105 +0,0 @@
.. _design_understanding_session_management:
Understanding Session Management
================================
The PipeWire session manager is a tool that is tasked to do a lot of things.
Many people understand the term "session manager" as a tool that is responsible
for managing links between nodes, but that is only one of many tasks. To
understand the entirety of its operation, we need to discuss how PipeWire works,
first.
When PipeWire starts, it loads a set of modules that are defined in its
configuration file. These modules provide functionality to PipeWire, otherwise
it is just an empty process that does nothing. Under normal circumstances,
the modules that are loaded on PipeWire's startup contain object *factories*,
plus the native protocol module that allows inter-process communication.
Other than that, PipeWire does not really load or do anything else. This is
where session management begins.
Session management is basically about setting up PipeWire to do something
useful. This is achieved by utilizing PipeWire's exposed object factories to
create some useful objects, then work with their methods to modify and later
destroy them. Such objects include devices, nodes, ports, links and others.
This is a task that requires continuous monitoring and action taking, reacting
on a large number of different events that happen as the system is being used.
High-level areas of operation
-----------------------------
The session management logic, in WirePlumber, is divided into 6 different areas
of operation:
1. Device Enablement
^^^^^^^^^^^^^^^^^^^^
Enabling devices is a fundamental area of operation. It is achieved by using
the device monitor objects (or just "monitors"), which are typically
implemented as SPA plugins in PipeWire, but they are loaded by WirePlumber.
Their task is to discover available media devices and create objects in PipeWire
that offer a way to interact with them.
Well-known monitors include:
- The ALSA monitor, which enables audio devices
- The ALSA MIDI monitor, which enables MIDI devices
- The libcamera monitor, which enables cameras
- The Video4Linux2 (V4L2) monitor, which also enables cameras, but also
other video capture devices through the V4L2 Linux API
- The BlueZ monitor, which enables bluetooth audio devices
2. Device Configuration
^^^^^^^^^^^^^^^^^^^^^^^
Most devices expose complex functionality, from the computer's perspective, that
needs to be managed in order to provide a simple and smooth user experience.
For that reason, for example, audio devices are organized into *profiles* and
*routes*, which allow setting them up to serve a specific use case. These
need to be configured and managed by the session manager.
3. Client Access Control
^^^^^^^^^^^^^^^^^^^^^^^^
When client applications connect to PipeWire, they need to obtain permissions
in order to be able to access the objects exposed by PipeWire and interact
with them. In some circumstances and configurations, the session manager is also
tasked with deciding which permissions should be granted to each client.
4. Node Configuration
^^^^^^^^^^^^^^^^^^^^^
Nodes are the fundamental elements of media processing. They are typically
created either by the device monitors or by client applications. When they are
created, they are in a state where they cannot be linked. Linking them requires
some configuration, such as configuring the media format and subsequently
the number and the type of ports that should be exposed. Additionally, some
properties and metadata related to the node might need to be set according to
user preferences. All of this is taken care of by the session manager.
5. Link Management
^^^^^^^^^^^^^^^^^^
When nodes are finally ready to use, the session manager is also tasked to
decide how they should be linked together in order for media to flow though.
For instance, an audio playback stream node most likely needs to be linked to
the default audio output device node. The session manager then also needs to
create all these links and monitor all conditions that may affect them so that
dynamic re-linking is possible in case something changes
(ex. if a device disconnects). In some cases, device and node configuration
may also need to change as a result of links being created or destroyed.
6. Metadata Management
^^^^^^^^^^^^^^^^^^^^^^
While in operation, PipeWire and WirePlumber both store some additional
properties about objects and their operation in storage that lives outside
these objects. These properties are referred to as "metadata" and they are
stored in "metadata objects". This metadata can be changed externally by tools
such as `pw-metadata`, but also others.
In some circumstances, this metadata needs to interact with logic inside
the session manager. Most notably, selecting the default audio and video inputs
and outputs is done by setting metadata. The session manager then needs to
validate this information, store it and restore it on the next restart, but also
ensure that the default inputs and outputs stay valid and reasonable when
devices are plugged and unplugged dynamically.

View file

@ -1,101 +0,0 @@
.. _design_understanding_wireplumber:
Understanding WirePlumber
=========================
Knowing the fundamentals of session management, let's see here how WirePlumber
is structured.
The library
-----------
WirePlumber is built on top of the `libwireplumber` library, which provides
fundamental building blocks for expressing all the session management logic.
Libwireplumber, which is written in C and based on GObject, wraps the PipeWire
API and offers a higher level and more convenient API. While the WirePlumber
daemon implements the session management logic, the underlying library can also
be utilized outside the scope of the WirePlumber daemon. This allows for the
creation of external tools and GUIs that interact with PipeWire.
Being GObject based, the library is introspectable and can be used from any
language that supports `GObject Introspection <https://gi.readthedocs.io/en/latest/>`_.
The library is also available as a C API.
The object model
^^^^^^^^^^^^^^^^
The most fundamental code contained in the WirePlumber library is the object
model, i.e. its representation of PipeWire's objects.
PipeWire exposes several objects, such nodes and ports, via the IPC protocol
in a manner that is hard to interact with using standard object-oriented
principles, because it is asynchronous. For example, when an object is created,
its existence is announced over the protocol, but its properties are announced
later, on a secondary message. If something needs to react on this object
creation event, it typically needs to access the object's properties, so it
must wait until the properties have been sent. Doing this might sound simple,
and it is, but it becomes a tedious repetitive process to be doing this
everywhere instead of focusing on writing the actual event handling logic.
WirePlumber's library solves this by creating proxy objects that cache all the
information and updates received from PipeWire throughout each object's lifetime.
Then, it makes them available via the :ref:`WpObjectManager <obj_manager_api>`
API, which has the ability to wait until certain information (ex, the
properties) has been cached on each object before announcing it.
Session management utilities
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The library also provides a set of utilities that are useful for session
management. For example, it provides the :ref:`WpSessionItem <session_item_api>`
class that can be used to abstract a part of the graph with some logic attached
to it. It also provides the :ref:`Events & Hooks API <design_events_and_hooks>`,
which is a way to express event handling logic in a declarative way.
Misc utilities
^^^^^^^^^^^^^^
The library also provides a set of miscellaneous utilities that bridge the
PipeWire API with the GObject API, such as :ref:`WpProperties <properties_api>`,
:ref:`WpSpaPod <spa_pod_api>`, :ref:`WpSpaJson <spa_json_api>` and others.
These complement the object model and make it easier to interact with PipeWire
objects.
The daemon
----------
The WirePlumber daemon is implemented on top of the library API and its job is
to host components that implement the session management logic. By itself, it
doesn't do anything except load and activate these components. The actual logic
is implemented inside them.
Modular design ensures that it is possible to swap the implementation of
specific functionality without having to re-implement the rest of it, allowing
flexibility on target-sensitive parts, such as policy management and
making use of non-standard hardware.
There are several kinds of components, each with a different purpose. The two
main kinds are `modules` and `Lua scripts`. See also
:ref:`config_components_and_profiles`.
Modules
^^^^^^^
Modules extend the libwireplumber API for specific purposes, usually to provide
support code or to allow WirePlumber to communicate with external services (ex
D-Bus APIs). They either expose their own APIs via GObject signals (i.e. dynamic
APIs that do not require linking at compile time) or implement certain objects
through interfaces. They are written in C.
Lua scripts
^^^^^^^^^^^
Lua scripts implement most of the session management. The libwireplumber API is
made available in Lua with idiomatic bindings that make it very easy to write
session management logic.
Lua has been chosen because it is a very lightweight scripting language that is
suitable for embedding. It is also very easy to learn and use, as well as bind
it to C code. However, WirePlumber can be easily extended to support scripting
languages other than Lua. The entire Lua scripting system is implemented as a
module.

View file

@ -7,54 +7,23 @@ Table of Contents
:maxdepth: 2 :maxdepth: 2
:caption: The WirePlumber Daemon :caption: The WirePlumber Daemon
daemon/installing.rst installing-wireplumber.rst
daemon/running.rst running-wireplumber-daemon.rst
daemon/configuration.rst configuration.rst
daemon/locations.rst daemon-logging.rst
daemon/logging.rst
daemon/multi_instance.rst
.. toctree::
:maxdepth: 2
:caption: WirePlumber's Design
design/understanding_session_management.rst
design/understanding_wireplumber.rst
design/events_and_hooks.rst
.. toctree::
:maxdepth: 2
:caption: WirePlumber's Policies
policies/linking.rst
policies/smart_filters.rst
policies/software_dsp.rst
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
:caption: The WirePlumber Library :caption: The WirePlumber Library
library/c_api.rst c_api.rst
lua_api.rst
.. toctree::
:maxdepth: 2
:caption: Scripting
scripting/lua_api.rst
scripting/existing_scripts.rst
scripting/custom_scripts.rst
.. toctree::
:maxdepth: 2
:caption: Tools
tools/wpctl.rst
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
:caption: Resources :caption: Resources
resources/contributing.rst contributing.rst
resources/testing.rst testing.rst
resources/community.rst community.rst
resources/releases.rst releases.rst

View file

@ -1,4 +1,4 @@
.. _daemon_installing: .. _installing-wireplumber:
Installing WirePlumber Installing WirePlumber
====================== ======================
@ -8,8 +8,8 @@ Dependencies
In order to compile WirePlumber you will need: In order to compile WirePlumber you will need:
* GLib >= 2.68 * GLib >= 2.62
* PipeWire >= 1.0 * PipeWire 0.3 (>= 0.3.43)
* Lua 5.3 or 5.4 * Lua 5.3 or 5.4
Lua is optional in the sense that if it is not found in the system, a bundled Lua is optional in the sense that if it is not found in the system, a bundled

View file

@ -1,6 +0,0 @@
.. _base_dirs_api:
Base Directories File Lookup
============================
.. doxygengroup:: wpbasedirs
:content-only:

View file

@ -1,16 +0,0 @@
.. _conf_api:
Static Configuration
====================
.. graphviz::
:align: center
digraph inheritance {
rankdir=LR;
GObject -> WpConf;
}
.. doxygenstruct:: WpConf
.. doxygengroup:: wpconf
:content-only:

View file

@ -1,17 +0,0 @@
.. _permission_manager_api:
WpPermissionManager
===================
.. graphviz::
:align: center
digraph inheritance {
rankdir=LR;
GObject -> WpObject;
WpObject -> WpPermissionManager;
}
.. doxygenstruct:: WpPermissionManager
.. doxygengroup:: wppermissionmanager
:content-only:

View file

@ -1,23 +0,0 @@
.. _settings_api:
Settings
========
.. graphviz::
:align: center
digraph inheritance {
rankdir=LR;
GBoxed -> WpSettingsSpec;
GBoxed -> WpSettingsItem;
GObject -> WpObject;
WpObject -> WpSettings;
}
.. doxygenstruct:: WpSettingsSpec
.. doxygenstruct:: WpSettingsItem
.. doxygenstruct:: WpSettings
.. doxygengroup:: wpsettings
:content-only:

View file

@ -1,6 +0,0 @@
# you need to add here any files you add to the toc directory as well
sphinx_files += files(
'c_api.rst',
)
subdir('c_api')

View file

@ -1,4 +1,4 @@
.. _scripting_lua_api: .. _lua_api:
Lua API Documentation Lua API Documentation
===================== =====================

View file

@ -8,17 +8,6 @@ object is not exposed to the scripts.
For some functionality, though, the following static functions are exposed. For some functionality, though, the following static functions are exposed.
.. function:: Core.get_properties()
Binds :c:func:`wp_core_get_properties`
Returns a table with the properties of the core. These are the same
properties that appear on WirePlumber's *client* object in the PipeWire
global registry.
:returns: the properties of the core
:rtype: table
.. function:: Core.get_info() .. function:: Core.get_info()
Returns a table with information about the core. The table contains Returns a table with information about the core. The table contains
@ -131,14 +120,3 @@ For some functionality, though, the following static functions are exposed.
the api plugins to load, if they are not already loaded the api plugins to load, if they are not already loaded
:param callback: the function to call after the plugins have been loaded; :param callback: the function to call after the plugins have been loaded;
this function takes references to the plugins as parameters this function takes references to the plugins as parameters
.. function:: Core.test_feature()
Binds :c:func:`wp_core_test_feature`
Tests if the specified feature is provided in the current WirePlumber
configuration.
:param string feature: the name of the feature to test
:returns: true if the feature is provided, false otherwise
:rtype: boolean

View file

@ -9,7 +9,12 @@ embeddable scripting language.
WirePlumber uses `Lua version 5.4 <https://www.lua.org/versions.html>`_ to WirePlumber uses `Lua version 5.4 <https://www.lua.org/versions.html>`_ to
implement its engine. For older systems, Lua 5.3 is also supported. implement its engine. For older systems, Lua 5.3 is also supported.
Scripts can be ran with the ``wpexec`` tool. There are currently two uses for Lua in WirePlumber:
- To implement the scripting engine
- To implement lua-based :ref:`config files <config_lua>`
This section is only documenting the API of the **scripting engine**. Scripts can be ran with the ``wpexec`` tool.
Example scripts can be found in the `tests/examples` directory of the wireplumber source tree. Example scripts can be found in the `tests/examples` directory of the wireplumber source tree.
@ -40,7 +45,7 @@ In this environment, the following rules apply:
Here is a full list of Lua functions (and API tables) that are exposed: Here is a full list of Lua functions (and API tables) that are exposed:
.. literalinclude:: ../../../../modules/module-lua-scripting/wplua/sandbox.lua .. literalinclude:: ../../../modules/module-lua-scripting/wplua/sandbox.lua
:language: lua :language: lua
:lines: 27-30 :lines: 27-30

View file

@ -11,7 +11,7 @@ dropped, the module is unloaded.
Constructors Constructors
~~~~~~~~~~~~ ~~~~~~~~~~~~
.. function:: LocalModule(name, arguments, properties) .. function:: LocalModule(name, arguments, properties, [load_args_from_file])
Loads the named module with the provided arguments and properties (either of Loads the named module with the provided arguments and properties (either of
which can be ``nil``). which can be ``nil``).
@ -21,6 +21,7 @@ Constructors
module arguments module arguments
:param table properties: can be ``nil`` or a table that can be :param table properties: can be ``nil`` or a table that can be
:ref:`converted <lua_gobject_lua_to_c>` to :c:struct:`WpProperties` :ref:`converted <lua_gobject_lua_to_c>` to :c:struct:`WpProperties`
:param load_args_from_file: (since 0.4.15) optional. if true, arguments param is treated as a file path to load args from
:returns: a new LocalModule :returns: a new LocalModule
:rtype: LocalModule (:c:struct:`WpImplModule`) :rtype: LocalModule (:c:struct:`WpImplModule`)
:since: 0.4.2 :since: 0.4.2

View file

@ -3,33 +3,6 @@
Debug Logging Debug Logging
============= =============
Constructors
~~~~~~~~~~~~
.. function:: Log.open_topic(topic)
Opens a LogTopic with the given topic name. Well known script topics are
described in :ref:`daemon_logging`, and messages from scripts shall use
**s-***.
Example:
.. code-block:: lua
local obj
log = Log.open_topic ("s-linking")
log:info (obj, "an info message on obj")
log:debug ("a debug message")
Above example shows how to output debug logs.
:param string topic: The log topic to open
:returns: the log topic object
:rtype: Log (:c:struct:`WpLogTopic`)
Methods
~~~~~~~
.. function:: Log.warning(object, message) .. function:: Log.warning(object, message)
Logs a warning message, like :c:macro:`wp_warning_object` Logs a warning message, like :c:macro:`wp_warning_object`
@ -39,9 +12,9 @@ Methods
:type object: GObject or GBoxed :type object: GObject or GBoxed
:param string message: the warning message to log :param string message: the warning message to log
.. function:: Log.notice(object, message) .. function:: Log.message(object, message)
Logs a notice message, like :c:macro:`wp_notice_object` Logs a normal message, like :c:macro:`wp_message_object`
:param object: optional object to associate the message with; you :param object: optional object to associate the message with; you
may skip this and just start with the *message* as the first parameter may skip this and just start with the *message* as the first parameter

View file

@ -30,7 +30,7 @@ contain the following methods:
:param string param_name: the PipeWire param name to enumerate, :param string param_name: the PipeWire param name to enumerate,
ex "Props", "Route" ex "Props", "Route"
:returns: the available parameters :returns: the available parameters
:rtype: Iterator; the iteration items are Spa Pod objects :rtype: Iterator; the iteration items are :ref:`Spa Pod <lua_spa_pod>` objects
.. function:: PipewireObject.set_param(self, param_name, pod) .. function:: PipewireObject.set_param(self, param_name, pod)

View file

@ -1,12 +1,18 @@
# you need to add here any files you add to the toc directory as well # you need to add here any files you add to the toc directory as well
sphinx_files += files( sphinx_files += files(
'index.rst', 'index.rst',
'installing-wireplumber.rst',
'running-wireplumber-daemon.rst',
'configuration.rst',
'daemon-logging.rst',
'contributing.rst',
'community.rst',
'testing.rst',
'releases.rst',
'c_api.rst',
'lua_api.rst',
) )
subdir('daemon') subdir('c_api')
subdir('design') subdir('lua_api')
subdir('policies') subdir('configuration')
subdir('library')
subdir('scripting')
subdir('tools')
subdir('resources')

View file

@ -1,140 +0,0 @@
.. _policies_linking:
Linking Policy
==============
Introduction
------------
The linking policy in WirePlumber is the logic charged to link a PipeWire stream
node with a PipeWire device node (most cases), or with another PipeWire stream
node (monitoring applications).
PipeWire stream nodes always have one of the following media classes:
- Stream/Output/Audio: For audio playback applications (Eg pw-play).
- Stream/Input/Audio: For audio capture applications (Eg pw-record).
- Stream/Input/Video: For video capture applications (Eg cheese).
And Pipewire device nodes always have one of the following media classes:
- Audio/Sink: For audio playback devices (Eg Speakers).
- Audio/Source: For audio capture devices (Eg Microphones).
- Video/Source: For video capture devices (Eg Cameras).
By default, since in most cases we want to link a stream node with a device
node, the linking policy logic when linking 2 nodes always follows the following
assignments:
.. graphviz::
digraph nodes {
rankdir=LR;
APS [shape=box label=<audio playback stream<BR/>(Stream/Output/Audio)>];
APD [shape=box label=<audio playback device<BR/>(Audio/Sink)>];
ACS [shape=box label=<audio capture stream<BR/>(Stream/Input/Audio)>];
ACD [shape=box label=<audio capture device<BR/>(Audio/Source)>];
VCS [shape=box label=<video capture stream<BR/>(Stream/Input/Video)>];
VCD [shape=box label=<video capture device<BR/>(Video/Source)>];
APS -> APD;
ACD -> ACS;
VCD -> VCS;
}
After that, once the media class of a device node has been selected for a
particular stream node, and there are more than 1 device node matching such
media class, WirePlumber will select one based on a set of priorities:
First, it will check if there is a default configured device node for the
selected device media class. If there is one, and the node exists, it will link
the stream node with such configured default node. Users can easily configure
default device nodes for all the 3 different device media classes using tools
such as ``pavucontrol`` or ``wpctl``. The logic is implemented in the
``linking/find-default-target.lua`` Lua script.
If there isn't any default node configured, or there is a default node
configured but the node does not exist, WirePlumber will instead select the
best device node available. The best device node is the node with highest
session priority and available routes to the physical device. The logic is
implemented in the ``linking/find-best-target.lua`` Lua script.
If the best node could not be found because the system does not have any,
WirePlumber won't link the stream and will send a "no target node available"
error to the client.
Stream node linking properties
------------------------------
The above default linking logic behavior can be changed by setting specific
properties on the nodes.
.. note::
These properties must be set in the **stream** nodes (not the device nodes),
otherwise they won't have any effect.
- **target.object**:
  The name of the desired node for this stream to be linked with.
  If this property is present, WirePlumber will try to find such node, see if it
  can be linked with the stream, and if so, will use it instead of the default
  node or best node. The logic is implemented in the ``linking/find-defined-target.lua``
  Lua script. Since this property is not set by default, WirePlumber will always
  link stream nodes to the default or best device node found. This property can be
  easily set using tools such as ``pw-play`` with the ``--target`` flag.
  Note that any node name can be specified there, even if the name is not a device
  node name, but another stream node name. If this is the case, WirePlumber will
  link 2 stream nodes together. An example of this case is the monitoring nodes
  created by ``pavucontrol`` to monitor audio of all audio devices and streams.
- **node.dont-reconnect**:
  Boolean indicating whether the stream node should not be reconnected to a new
  node if its current linked node (target) was destroyed or not. By default it
  is set to ``false``, so if the property is not present in the stream node, WirePlumber
  will always try to reconnect the stream node to a new target instead of sending
  an error to the client. The logic is implemented in the ``linking/prepare-link.lua``
  Lua script.
- **node.dont-move**:
  Boolean indicating whether the stream node should not be movable or not at runtime
  using the metadata. If a stream node is not movable, it means that users cannot
  relink the stream node to a new target at runtime (using tools such as ``pavucontrol``
  or ``pw-metadata``) when the stream node is already linked to a different node. By
  default it is set to ``false``, so if the property is not present, WirePlumber will
  always move, and therefore link the stream node to a new target if it is defined and
  updated in the ``target.object`` metadata key.
- **node.dont-fallback**:
  Boolean indicating whether the stream node should not fallback to a different
  target if its defined target does not exist (the one defined with the ``target.object``
  property) or not. Therefore, if this property is set to ``true``, WirePlumber sends
  a "defined target not found" error to the client and will also destroy the stream
  node. By default it is set to ``false``, so if the property is not present in the
  stream node, WirePlumber will always fallback to the default or best target if
  the defined target was not found.
- **node.linger**:
  Boolean indicating whether the stream node should linger or not if its defined
  target was not found and the ``node.dont-fallback`` is set to true. Therefore, if
  this property is set to ``true``, the defined target was not found, and the
  ``node.dont-fallback`` is set to true, WirePlumber won't send a "defined target not found"
  error to the client, and won't destroy the stream node. This is useful if we want
  the stream to wait (without processing any data) until its defined target becomes
  available. By default it is set to ``false``, so if the property is not present in the
  stream node, WirePlumber will always destroy the node and send an error to the client
  if its target was not found and ``node.dont-fallback`` was set to true.
Linking settings
----------------
Apart from the above properties, there are also global settings for the linking
policy. See :ref:`config_settings` for more information, the linking settings
are prefixed with ``linking.``.

View file

@ -1,6 +0,0 @@
# you need to add here any files you add to the toc directory as well
sphinx_files += files(
'linking.rst',
'smart_filters.rst',
'software_dsp.rst',
)

View file

@ -1,380 +0,0 @@
.. _policies_smart_filters:
Smart Filters
=============
Introduction
------------
The smart filters policy allows automatically linking filters together, in a
chain, and tied to a specific target node. This is useful when we want to apply
a specific processing chain to a specific device, for example. When a stream is
about to be linked to a target node that is associated with a smart filter
chain, the policy will automatically link the stream with the first filter in
the chain, and the last filter in the chain with the target node. This is done
transparently to the client, allowing users to define a specific processing
chain for a specific device without having to create setups with virtual sinks
(or sources) that must be explicitly targeted by the clients.
Filters, in general, are nodes that are placed in the middle of the graph and
are used to modify the data that passes through them. For example, the
*echo-cancel*, the *filter-chain*, or the *loopback* nodes are filters.
Filters can be implemented either as a single node or as a pair of nodes with
opposite directions. For example, the *null-audio-sink* node can be configured
to be a single-node filter. On the other hand, the *filter-chain* is a pair of
nodes with opposite directions, where one node captures the audio from the graph
and the other node sends the modified audio back to the graph.
For the purpose of the **smart filters** policy, WirePlumber will only consider
pairs of nodes as filters, not single-node ones. More specifically, a pair of
nodes will be considered to be a filter by WirePlumber if they have the
``node.link-group`` property set to a common value. This property is always set
on pairs of nodes that are internally linked together and is a good indicator
that the nodes are implementing a filter.
That pair of nodes **must** always consist of a *stream* node and a *main* node.
The main node acts as a virtual device, where the data is sent or captured
to/from, and the stream node acts as a regular stream, where the data is sent
or received to/from the next node in the graph. This is designated by their
media class, as shown in the table below:
.. list-table::
:widths: 30 35 35
:header-rows: 1
:stub-columns: 1
* -
- Input filter (virtual sink)
- Output filter (virtual source)
* - Main node
- ``Audio/Sink`` (capture)
- ``Audio/Source`` (playback)
* - Stream node
- ``Stream/Output/Audio`` (playback)
- ``Stream/Input/Audio`` (capture)
For instance, if a smart filter is used between an application playback stream
and the default audio sink, the graph would look like this:
.. graphviz::
digraph nodes {
rankdir=LR;
A [shape=box label=<application stream node<BR/>(Stream/Output/Audio)>];
FM [shape=box label=<filter main node<BR/>(Audio/Sink)>];
FS [shape=box label=<filter stream node<BR/>(Stream/Output/Audio)>];
D [shape=box label=<default device node<BR/>(Audio/Sink)>];
A -> FM;
FS -> D;
subgraph cluster_filter {
style="dotted";
FM; FS;
}
}
The same logic is applied if the smart filter is used between an application
capture stream and the default audio source, it is just all in the opposite
direction. This is how the graph would look like in this case:
.. graphviz::
digraph nodes {
rankdir=LR;
A [shape=box label=<application stream node<BR/>(Stream/Input/Audio)>];
FM [shape=box label=<filter main node<BR/>(Audio/Source)>];
FS [shape=box label=<filter stream node<BR/>(Stream/Input/Audio)>];
D [shape=box label=<default device node<BR/>(Audio/Source)>];
D -> FS;
FM -> A;
subgraph cluster_filter {
style="dotted";
FM; FS;
}
}
When multiple filters have the same direction, they can also be chained together
so that the output of one filter is sent to the input of the next filter. The
next section describes how these chains can be described with properties so that
they are automatically linked by WirePlumber in any way we want.
Filter properties
-----------------
When a filter node is created, WirePlumber will check for the presence of the
following optional node properties on the **main** node:
- **filter.smart**
Boolean indicating whether smart policy will be used for these filter nodes or
not. This is disabled by default, therefore filter nodes will be treated as
regular nodes, without applying any kind of extra logic. On the other hand, if
this property is set to ``true``, automatic (smart) filter policy will be used
when linking them. The properties below will then also apply, providing
further instructions.
- **filter.smart.name**
The unique name of the filter. WirePlumber will use the value of the
``node.link-group`` property as the filter name if this property is not set.
- **filter.smart.disabled**
Boolean indicating whether the filter should be disabled or not. A disabled
filter will never be used under any circumstances. If the property is not set,
WirePlumber will consider the filter as enabled (i.e. disabled = false).
- **filter.smart.targetable**
Boolean indicating whether the filter can be directly linked with clients that
have it defined as a target (Eg: ``pw-play --target <filter-name>``) or not.
This can be useful when a client wants to be linked with a filter that is in
the middle of the chain in order to bypass the filters that are placed before
the selected one. If the property is not set, WirePlumber will consider the
filter not targetable by default, meaning filters will never by bypassed by
clients, and clients will always be linked with the first filter in the chain.
- **filter.smart.target**
A JSON object that defines the matching properties of the filter's target
node. A filter target can never be another filter node (WirePlumber will
ignore it), it must be a device or virtual sink (or source, depending on the
direction of the filter). If this property is not set, WirePlumber will use
the default sink/source as the target.
- **filter.smart.before**
A JSON array containing the names of the filters that are supposed to be
chained after this filter (i.e. this filter here should be chained *before*
those). If not set, WirePlumber will link the filters by order of creation.
- **filter.smart.after**
A JSON array containing the names of the filters that are supposed to be
chained before this filter (i.e. this filter here should be chained *after*
those). If not set, WirePlumber will link the filters by order of creation.
.. note::
These properties must be set on the filter's **main** node, not the stream
node.
As an example, we will describe here how to create 2 loopback filters in
PipeWire's configuration, with names loopback-1 and loopback-2, that will be
linked with the default audio device, and use loopback-2 filter as the last
filter in the chain.
The PipeWire configuration files for the 2 filters should be like this:
- ~/.config/pipewire/pipewire.conf.d/loopback-1.conf:
.. code-block::
:emphasize-lines: 8-11
context.modules = [
{ name = libpipewire-module-loopback
args = {
node.name = loopback-1-sink
node.description = "Loopback 1 Sink"
capture.props = {
audio.position = [ FL FR ]
media.class = Audio/Sink
filter.smart = true
filter.smart.name = loopback-1
filter.smart.before = [ loopback-2 ]
}
playback.props = {
audio.position = [ FL FR ]
node.passive = true
stream.dont-remix = true
}
}
}
]
- ~/.config/pipewire/pipewire.conf.d/loopback-2.conf:
.. code-block::
:emphasize-lines: 8-10
context.modules = [
{ name = libpipewire-module-loopback
args = {
node.name = loopback-2-sink
node.description = "Loopback 2 Sink"
capture.props = {
audio.position = [ FL FR ]
media.class = Audio/Sink
filter.smart = true
filter.smart.name = loopback-2
}
playback.props = {
audio.position = [ FL FR ]
node.passive = true
stream.dont-remix = true
}
}
}
]
After restarting PipeWire to apply the configuration changes, playing a test
wave audio file with paplay to the default device should result in the following
graph:
.. graphviz::
digraph nodes {
rankdir=LR;
paplay [shape=box label=<paplay node<BR/>(Stream/Output/Audio)>];
L1M [shape=box label=<loopback-1 main node<BR/>(Audio/Sink)>];
L1S [shape=box label=<loopback-1 stream node<BR/>(Stream/Output/Audio)>];
L2M [shape=box label=<loopback-2 main node<BR/>(Audio/Sink)>];
L2S [shape=box label=<loopback-2 stream node<BR/>(Stream/Output/Audio)>];
device [shape=box label=<default device node<BR/>(Audio/Sink)>];
paplay -> L1M;
L1S -> L2M;
L2S -> device;
subgraph cluster_filter1 {
style="dotted";
L1M; L1S;
}
subgraph cluster_filter2 {
style="dotted";
L2M; L2S;
}
}
Now, if we remove the ``filter.smart.before = [ loopback-2 ]`` property from the
loopback-1 filter, and add a ``filter.smart.before = [ loopback-1 ]`` property
in the loopback-2 filter configuration file, WirePlumber should link the
loopback-1 filter as the last filter in the chain, like this:
.. graphviz::
digraph nodes {
rankdir=LR;
paplay [shape=box label=<paplay node<BR/>(Stream/Output/Audio)>];
L1M [shape=box label=<loopback-1 main node<BR/>(Audio/Sink)>];
L1S [shape=box label=<loopback-1 stream node<BR/>(Stream/Output/Audio)>];
L2M [shape=box label=<loopback-2 main node<BR/>(Audio/Sink)>];
L2S [shape=box label=<loopback-2 stream node<BR/>(Stream/Output/Audio)>];
device [shape=box label=<default device node<BR/>(Audio/Sink)>];
paplay -> L2M;
L2S -> L1M;
L1S -> device;
subgraph cluster_filter1 {
style="dotted";
L1M; L1S;
}
subgraph cluster_filter2 {
style="dotted";
L2M; L2S;
}
}
In addition, the filters can have different targets. For example, we can define
the filters like this:
- ~/.config/pipewire/pipewire.conf.d/loopback-1.conf:
.. code-block::
:emphasize-lines: 12
context.modules = [
{ name = libpipewire-module-loopback
args = {
node.name = loopback-1-sink
node.description = "Loopback 1 Sink"
capture.props = {
audio.position = [ FL FR ]
media.class = Audio/Sink
filter.smart = true
filter.smart.name = loopback-1
filter.smart.after = [ loopback-2 ]
filter.smart.target = { node.name = "not-default-audio-device" }
}
playback.props = {
audio.position = [ FL FR ]
node.passive = true
stream.dont-remix = true
}
}
}
]
- ~/.config/pipewire/pipewire.conf.d/loopback-2.conf:
.. code-block::
context.modules = [
{ name = libpipewire-module-loopback
args = {
node.name = loopback-2-sink
node.description = "Loopback 2 Sink"
capture.props = {
audio.position = [ FL FR ]
media.class = Audio/Sink
filter.smart = true
filter.smart.name = loopback-2
}
playback.props = {
audio.position = [ FL FR ]
node.passive = true
stream.dont-remix = true
}
}
}
]
In this case, playing a test wave audio file with paplay to the
``not-default-audio-device`` device should result in the following graph:
.. graphviz::
digraph nodes {
rankdir=LR;
paplay [shape=box label=<paplay node<BR/>(Stream/Output/Audio)>];
L1M [shape=box label=<loopback-1 main node<BR/>(Audio/Sink)>];
L1S [shape=box label=<loopback-1 stream node<BR/>(Stream/Output/Audio)>];
L2M [shape=box label=<loopback-2 main node<BR/>(Audio/Sink)>];
L2S [shape=box label=<loopback-2 stream node<BR/>(Stream/Output/Audio)>];
device [shape=box label=<not-default-audio-device node<BR/>(Audio/Sink)>];
paplay -> L2M;
L2S -> L1M;
L1S -> device;
subgraph cluster_filter1 {
style="dotted";
L1M; L1S;
}
subgraph cluster_filter2 {
style="dotted";
L2M; L2S;
}
}
In this configuration, the loopback-1 filter will only be linked if the
application stream is targeting the device node called
"not-default-audio-device".
Filters metadata
----------------
Similar to the default metadata, it is also possible to override the filter
properties using the "filters" metadata object. This allow users to change the
filters policy at runtime.
For example, assuming the id of the *loopback-1* main node is ``40``, we can
disable the filter by setting its ``filter.smart.disabled`` metadata key to
``true`` using the ``pw-metadata`` tool like this:
.. code-block:: bash
$ pw-metadata -n filters 40 "filter.smart.disabled" true Spa:String:JSON
We can also change the target of a filter at runtime:
.. code-block:: bash
$ pw-metadata -n filters 40 "filter.smart.target" "{ node.name = new-target-node-name }" Spa:String:JSON
Every time a key in the filters metadata changes, all filters are unlinked and
re-linked properly, following the new policy.

Some files were not shown because too many files have changed in this diff Show more