Introduction to Wireplumber

Photo by Michel Didier Joomun on Unsplash (cropped)

Wireplumber is the session and policy manager for Pipewire. It has its own systemd user service. It is a separate project, with separate concerns. Current version is 0.5.8 on Fedora Workstation 41.

Session managers save the current state of open audio applications along with their connections, allowing sessions to be easily restored without having to manually open each application, load individual settings files, and reconnect all connectionsLinuxAudio

As you have seen in the previous article, we can add nodes via Pipewire configuration files or arbitrary CLI commands. But the operating system is a complex dynamic system. A lot of things can happen; for example, you can plug in your headphones any time, or you can switch between video and audio streaming. There appears to be a need for a separate controller to react to the various multimedia events. This controller or manager is Wireplumber.

What is included with Wireplumber

Let’s look at the installed files before moving to documentation. There are some utilities, like wpctl and wpexec, a few configuration files, and quite a lot of Lua files in the scripts folder.

rg@f41:~$ rpm -ql wireplumber
/usr/bin/wireplumber
/usr/bin/wpctl
/usr/bin/wpexec
/usr/share/wireplumber/wireplumber.conf
/usr/lib/systemd/user/wireplumber.service
/usr/share/wireplumber/scripts/client/access-default.lua
...

Wireplumber comes with shared libraries. Take a moment to review the module names.

rg@f41:~$ ls -l /usr/lib64/wireplumber-0.5/
-rwxr-xr-x. root libwireplumber-module-dbus-connection.so
-rwxr-xr-x. root libwireplumber-module-logind.so
-rwxr-xr-x. root libwireplumber-module-standard-event-source.so
...

As an example, the logind module, shown in this list, is used to check some logic involving bluetooth and logind active seat.

Utility Programs

Two utilities are available in the wireplumber package.

  • Wpexec contains the execution context; you will see it in use in some Lua executable files.
  • Wpctl allows the dynamic modification of settings. To check all available settings, use wpctl settings.
rg@f41:~$ wpctl
Usage:
wpctl [OPTION…] COMMAND [COMMAND_OPTIONS] - WirePlumber Control CLI

Commands:
status
get-volume ID
inspect ID
set-default ID
set-volume ID VOL[%][-/+]
set-mute ID 1|0|toggle
set-profile ID INDEX
set-route ID INDEX
clear-default [ID]
settings [KEY] [VAL]
set-log-level [ID] LEVEL

Configuring

The configuration file is similar, to some degree, to the Pipewire configuration file:

rg@f41:~$ less /usr/share/wireplumber/wireplumber.conf
context.spa-libs = { ... }
context.modules = [ ... ]
wireplumber.profiles = { ... }
wireplumber.components = [ ... ]
wireplumber.components.rules = [ ... ]
wireplumber.settings.schema = { ... }

Sections spa-libs and modules import a few audio and Pipewire libraries. The profiles section defines a few basic profiles in terms of the offered features (audio/video/bluez). The components section loads a list of various functional parts from the modules. These can range from logging to Lua scripting engine and event hooks. Each component provides a specific feature. The settings section contains well-known multimedia settings with a detailed description. Configuration can be changed using wpctl or homedir drop-in configuration files.

Example

In the following example, we disable a specific feature of the main profile. Don’t forget to revert the change once tested.

cat <<EOF > ~/.config/wireplumber/wireplumber.conf.d/50.conf
wireplumber.profiles = {
main = {
hardware.video-capture = disabled
} }
EOF

rg@f41:~$ systemctl --user restart wireplumber.service

Interaction with Pipewire

Wireplumber interacts with Pipewire via metadata objects. Let’s use wpctl settings to change one of the well-known settings, like the default sink volume.

rg@f41:~$ wpctl settings device.routes.default-sink-volume 0.23
rg@f41:~$ pw-metadata -n sm-settings 0 device.routes.default-sink-volume
Found "sm-settings" metadata 36
update: id:0 key:'device.routes.default-sink-volume' value:'0.23' type:'Spa:String:JSON'
...

Notice that using pw-metadata shows Pipewire has the updated value for this setting. To make the setting persistent across restarts, we can save it in the Wireplumber persistent state.

rg@f41:~$ wpctl settings --save device.routes.default-sink-volume 0.23
rg@f41:~$ cat ~/.local/state/wireplumber/*
device.routes.default-sink-volume=0.23
...

It is worth your time to investigate all the other saved properties. You will find the current sink volume. You will also find some client or application-specific settings. The same is true for interaction with gnome-sound-panel. When you change the GUI volume, you should see the updated value saved in the state folder. When you change the default sink from speaker to headset, you should see this reflected in the wpctl status output.

It would also be beneficial to look over the Lua scripts to understand the logic behind their actions and perhaps to find templates that you can use as examples for your own configurations.

Lua Scripting

It is worth mentioning a little bit about the scripts. Lua is a simple and easy-to-learn scripting language. The scripts, in many cases, are importing some shared objects (i.e. spa-plugins) that provide the ability to orchestrate the Pipewire graph. In this way, a more complex logic is achievable. Check media-role-nodes.conf for an example of such logic. There media streams are grouped by roles and assigned to virtual sinks with different priorities for gaming, multimedia, voice assistant, navigation, emergency alarms, etc.

In the previous article, whenever we chose the --target argument for pw-play, the logic of creating the necessary node links was implemented by Wireplumber in the find-defined-target.lua file provided by this package.

Example

Here we demonstrate creating a simple script to list all streaming nodes.

cat <<EOF > ~/.local/share/wireplumber/scripts/10-medialog.lua
log = Log.open_topic("logger-media")

node_om = ObjectManager {
Interest {
type = "node",
Constraint { "media.class",
"matches",
"Stream/Output/Audio", type = "pw-global"
}
}
}

node_om:connect("object-added", function (om, node)
log:notice(node, "Process [" .. node.properties["application.process.binary"] ..
"] -- [" .. node.properties["media.name"] .. "]"
)
end)

node_om:activate()
EOF

We can include this as a separate Wireplumber feature and then restart the wireplumber.service and verify using journalctl :

cat <<EOF > ~/.config/wireplumber/wireplumber.conf.d/70-media.conf
wireplumber.components = [
{
name = "10-medialog.lua", type = script/lua
provides = logger-media
}
]

wireplumber.profiles = {
main = {
logger-media = required
}
}
EOF


rg@f41:~$ systemctl --user restart wireplumber.service
rg@f41:~$ journalctl --user -u wireplumber.service -g logger-media

12:38:00 logger-media: <WpNode:99:0x564>
Process [gnome-shell] -- [bell-window-system]
12:38:00 logger-media: <WpNode:87:0x564>

Process [firefox] -- [The Woods in Lorn]

Alternatively, you can execute the lua scripts individually by including the shebang #!/usr/bin/wpexec as the first line.

Conclusions

In this article we investigated the capabilities offered by a powerful media session manager and demonstrated implementing our own session logic. Wireplumber docs are well written and describe this topic, and much more, in greater detail. Thanks to the people and organizations maintaining all the above-mentioned packages.

Fedora Project community

13 Comments

  1. Patrick O'Callaghan

    How do I restart wireplumber without logging out and in again? Seems that wpctl should be able to do this but it’s not clear and neither wireplumber nor wpctl has a man page (a very annoying trend with more and more apps). There isn’t even a doc section in the rpm.

    • Does the

      systemctl --user restart wireplumber.service

      command shown under several of the “Example” sections not work?

      • Patrick O'Callaghan

        I hadn’t read the examples in detail so didn’t notice this. My remarks about documentation still apply though. How is the user to know this when there is no man page or included docs? Even the wireplumber-doc rpm consists only of examples, none of which say anything about restarting.

        As a matter of interest, how did you discover this yourself?

        • RG

          I also looked for man page and didn’t find it. Wireplumber is still version 0.5.8, I am sure they will add this at some point. Some things design and functionality wise are still being changed, so probably not a good idea to make a man page now. Until then you have the next best thing – Fedora Magazine!

          • Patrick O'Callaghan

            I strongly disagree. A man page should be an integral part of a project and developed alongside the software, especially as it’s being released to a wide audience. In fact if I had my way it would be a blocking requirement for any user-visible app, but I’m afraid that ship has sailed.

        • FeRD (Frank Dana)

          For better or worse, man pages are falling out of favor, particularly as more and more software is being developed cross-platform — man pages are of limited use on macOS, and none at all on Windows. They’re also a byzantine documentation format that requires significant effort to create. The goal generally seems to be that all of the necessary information about a command is found in its –help output (and/or help subcommand output, and sufficiently complete interactive documentation often renders a formal man page largely redundant.

          There’s nothing that would be found in a wpctl man page that isn’t already accessible via the command itself. Including information on restarting wireplumber. Since that’s not part of wpctl‘s job, there wouldn’t have been any reason to cover the topic in its man page.

          The existence of the file /usr/lib/systemd/user/wireplumber.service in the wireplumber RPM is the clearest indication that it’s a user-session systemd service. Though, since most things are managed via systemd these days, that’s a pretty good bet even absent any other information.

          While it’s wandering off-topic for this particular article, looking through the output of systemctl –user status and systemctl –user list-unit-files is a great way to discover what services are part of your user session, both active and available. systemctl cat –full $SOMETHING.service will show you the unit definition, though that requires some familiarity with systemd to interpret.

          And systemd itself has very comprehensive man pages on its commands, file formats, and operating theory. man -k systemd produces 314 lines of output, on my system, and man -k systemd | grep -E ‘^systemd’ produces 265.

        • FeRD (Frank Dana)

          Ugh, WordPress.

          All of the en-dashes in my previous comment’s commands should of course be double hyphens. (dash dash help, not en-dash help, etc.)

          I placed the commands in italics instead of using CODE tags because (IIRC) the terrible WordPress CSS doesn’t support inline CODE spans; they get block-formatted. (And without a comment-Preview function, there’s no way to be sure what your comment will really look like when posted.)

  2. Bruno

    Just replace “There” by “their” in “the logic behind there actions”
    Nice work, interesting

  3. James

    A great article and timely as I am setting up a live audio workstation on a Raspberry pi 5.

    Does wireplumber open the audio applications when you open a saved session?

    Also, how does pipewire handle different usb audio interfaces? There used to be a directory in alsa.conf.d (or similar) with different pcm.stream configuration settings for the different mixers, that I think were loaded via udev rules when a usb interface was plugged in, and I was hoping that it still existed in pipewire, as I want to create a config for an old tascam us144v2, but I’ve hunted around, and I can’t find it…

    • FeRD (Frank Dana)

      Does wireplumber open the audio applications when you open a saved session?

      No, and that isn’t exactly the kind of session management we’re talking about. Sessions in wireplumber aren’t discrete things that you load and save manually. Each execution of an application that outputs audio is “a session” for that application, and wireplumber automatically keeps track of the parameters of each of those sessions.

      So if (for example) you use VLC with the audio routed to your bluetooth headphones, rather than your laptop’s speakers, then the next time you launch VLC the routing will be restored so that the audio is still connected to your bluetooth headphones… IF they’re still connected. If not (if the audio sink has disappeared), then wireplumber will re-route VLC’s audio back to your primary audio output, so that your video doesn’t end up playing in silence.

      (That behavior (and others) is also configurable using wpctl settings — running it without any other options will display a listing of all known settings with descriptions. Settings like bluetooth.use-persistent-storage, bluetooth.autoswitch-to-headset-profile, device.restore-profile, device.restore-routes and etc. allow the behavior of the session management to be tuned.)

      Other audio parameters like channel routing, volume, etc. are also tracked and reapplied for each application session. That’s what it means for WirePlumber to be doing session management, it’s not really a discrete, explicitly-stored-state kind of thing. The complexity of the audio system makes that unworkable in practice.

      As far as hardware parameters, you shouldn’t need udev rules to configure USB audio devices, and it’s unlikely you’d need udev rules to load configurations, because anything that shows up as a USB audio device should automatically show up in ALSA, and therefore also be accessible to PipeWire/WirePlumber.

      ALSA’s configuration tools are still useful: alsamixer -c N or amixer -c N to configure “card” #N as seen in the list produced by aplay -l, and alsactl store N to save a persistent configuration to /etc/alsa/alsactl.conf. You’ll definitely have to run alsactl as root using sudo, and possibly all of the commands will need sudo to gain permission to access the hardware devices, something user sessions don’t have by default.

      There isn’t much that can be manually configured per-device using wpctl — mostly just set-default to choose the default sink, and set-volume, set-mute, set-profile and set-route to configure session parameters for individual applications/sinks.

    • Visitor

      Hi James, I am not sure I understand the problem, but there seems to be some kind of ALSA configuration possible in Wireplumber. This specific section from the docs might prove useful but I myself did not test it https://pipewire.pages.freedesktop.org/wireplumber/daemon/configuration/alsa.html

Leave a Reply


The interval between posting a comment and its appearance will be irregular so please DO NOT resend the same post repeatedly. All comments are moderated but this site is not monitored continuously so comments will not appear as soon as posted.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

The opinions expressed on this website are those of each author, not of the author's employer or of Red Hat. Fedora Magazine aspires to publish all content under a Creative Commons license but may not be able to do so in all cases. You are responsible for ensuring that you have the necessary permission to reuse any work on this site. The Fedora logo is a trademark of Red Hat, Inc. Terms and Conditions