Pipewire/Wireplumber useful documentation needed

I want to configure Pipwire/Wireplumber and desperately need useful documentation and tutorial resouces.
I’m digging through the Pipewire and Wireplumber documentations now for the 2. day and I am not getting anything useful out for me as a user. These documentations seem to be developer docs as opposed to user docs.
I want to

  • rename devices and nodes
  • disable devices and nodes
  • configure connections, so that specific sources always connect to a specific sink in a specific way, etc.

So far everything I’ve figured out through the ArchWiki and tutorials didn’t work. Why it doesn’t work? I don’t know because I have no idea what I’m actually doing there. It’s just monkey see, monkey do copying of configs without real comprehension.
Is there a user comprehendable documentation that explains this?

For example I have this config to disable unneeded devices and nodes (~/.config/wireplumber/wireplumber.conf.d/cleanup.conf)

monitor.alsa.rules = [
        {
                matches = [
                        { device.name = "alsa_card.pci-0000_2d_00.4" }
                        { device.name = "alsa_card.usb-MACROSILICON_UGREEN_25773_69357462-02" }
                        { device.name = "alsa_card.pci-0000_2b_00.1" }
                ]
                actions = {
                        update-props = {
                                device.disabled = true
                        }
                }
        }
        {
                matches = [
                        { node.name = "alsa_input.pci-0000_2d_00.4.analog-stereo" }
                        { node.name = "alsa_input.usb-MACROSILICON_UGREEN_25773_69357462-02.analog-stereo" }
                        { node.name = "alsa_output.pci-0000_2d_00.4.iec958-stereo" }
                ]
                actions = [
                        update-props = {
                                node.disabled = true
                        }
                ]
        }
]

It doesn’t work. All the devices and nodes are still there, checking pavucontroll and qpwgraph.
I havn’t even touched on setting up connections between specific ports because so far I havn’t found anything about this in a non-developer language I can apply.

There may be a separate pavucontrol configuration that the application saves and uses to override the pipewire defaults.
Have you tried disabling devices in pavucontrol?

Actually it did, thanks for the hint. Interesting to know that pavucontrol overrides this. I might get rid of pavucontrol then. As far as I can tell pavucontrol comes from the pipewire-pulse package. Is that safe to remove?
But that only explains the disabling not working but unfortunatelly not why the renaming, or does pavucontrol overwrites this too?

If you remove pipewire-pulse I would expect audio to stop working for most desktop applications. If your computer is dedicated to Ardour use ( or other JACK capable production applications) you could probably get away with that, but I would expect that if you attempt to remove pipewire-pulse using your distribution package management it will also suggest removing most of your desktop environment as well. I guess it depends on how your distribution has configured the package requirements.

I’m using Kubuntu 24.04.
Looks like I’m stalemate then. With pavucontrol my Wireplumber configs are overridden, without it my system audio is broken.

You should be able to functionally replicate your wireplumber settings with pavucontrol (at least the parts the pavucontrol would override)

I don’t think it’s possible.
pavucontrol is very limited in setting up connections between audio nodes and as far as I know pavucontrol it can not handle the complexity I need. jack clients, for example, are completely invisible to pavucontrol, since it is only concerned about pulse stuff.
And even if it was, I would much rather prefer not to use pavucontrol since this is always an extra application that I have to have open when streaming which adds unnecessary clutter to an audio setup that can also be handled by the session manager itself.
I just don’t find the neccessary information how to properly operate it.

what i recalled from your wireplumber settings was just turning certain devices off. This can be done in the “Configuration” tab of pavucontrol.

Yeah, that was a little confusing I know. That was just the first step I tried with the configuration and since this already didn’t work, I didn’t proceed further.
Disabling unneeded nodes was just getting myself familiar with wireplumber configuration. My actual main purpose for using wireplumber is to automatically connect specific inputs to specific outputs, in some cases even 1-to-N.
Having a cleaned up nodegraph, with human readable node names is just the cherry on top.

Thanks for joining in anyway

have you seen this documentation? PipeWire: client.conf

You can do that in qpwgraph. Save patchbay after making connections, then use activated and exclusive and it will remember your connections.

If you want to turn devices on and off, and you are using Kubuntu, I would suggest you use system settings:

For connections, I’m not sure Wireplumber (despite it’s name) is the right approach. You can do this by creating a pulseaudio config file. For example, I have this to set up a pseudo-device and connections for my 18-channel XR18, in order to expose the 2 channel device you see in the screen shot above:

(~/.config/pipewire/pipewire-pulse.conf.d/behringer-xr-18.conf)

context.modules = [
    # Creates a virtual source for X-Air XR18 capture on channel 8
    {   name = libpipewire-module-loopback
        args = {
            node.name = "capture.XR18_mic"
            node.description = "XR18 Mixer Mic"
            capture.props = {
                audio.position = [ AUX7 ]
                node.target = "alsa_input.usb-BEHRINGER_XR18_4C5BB32DFB73_03-00.pro-input-0"
                stream.dont-remix = true
                node.passive = true
            }
            playback.props = {
                node.name = "capture.XR18_mic"
                media.class = "Audio/Source"
                audio.position = [ MONO ]
            }
        }
    }

    # Creates a virtual source for X-Air XR18 capture on channels 17/18
    {   name = libpipewire-module-loopback
        args = {
            node.description = "XR18 Mixer Stereo"
            capture.props = {
                audio.position = [ AUX16 AUX17 ]
                node.target = "alsa_input.usb-BEHRINGER_XR18_4C5BB32DFB73_03-00.pro-input-0"
                stream.dont-remix = true
                node.passive = true
           }
            playback.props = {
                node.name = "capture.XR18_stereo"
                media.class = "Audio/Source"
                audio.position = [ FL FR ]
            }
        }
   }

    # Creates a virtual sink for X-Air XR18 playback on channels 17/18
   {   name = libpipewire-module-loopback
       args = {
           node.description = "XR18 Mixer Stereo"
           capture.props = {
               media.class = "Audio/Sink"
               audio.position = [ FL FR ]
           }
           playback.props = {
               node.name = "playback.XR18_stereo"
               audio.position = [ AUX16 AUX17 ]
               node.target = "alsa_output.usb-BEHRINGER_XR18_4C5BB32DFB73_03-00.pro-output-0"
               stream.dont-remix = true
               node.passive = true
           }
       }
   }
]

This appears in qpwgraph as follows:

Cheers,

Keith

Wow, thanks for your replies, I really appreciate.

@Largos
Yes, kind of. As I said in my initial post, I was digging through Pipewire and Wireplumber docs prior to this post, but there is no information I can actually apply into a real world configuration. It uses jargon and terminology that isn’t really explained without and is so generic that a Pipewire dev probably understands it. I don’t. As I said, these seem to documentation from devs to devs.

@Axel99092
I have tried to use qpwgraph in the past and also carla but it was always very messy and unpleasant to work with. They are actually one major driver why I want to get away from third party patchbays and into configuring this right at the source Pipewire or Wireplumber, because these patchbays are just cumbersome to work with, not very reliable , messy, time consuming, yeah … not for me.

@Majik
That’s quite impressive what you could pull off with your pulse config. Is that also able to connect to jack nodes for example? How did you come up with this, just by reading the docs?
My problem is, with my future perspective of switching to Arch this year I also consider getting rid of Pulse entirely. I already got a virtual box running Arch which has just a bare pipewire setup, without PulseAudio, and it works so far.
Maybe with Wireplumber I was searching at the wrong place and actually PulseAudio is what I’m looking for to configure audio routings, in that case I would use it but if Pipewire/Wireplumber are able to do this without an external package, I would preferably go without PA entirely.

Most desktop software expects the Pulse API for system audio, so it is very unusual to have pipewire without pipewire-pulse module installed.

1 Like

My Kubuntu 24.04 system doesn’t have pulseaudio installed. It’s using Pipewire with pipewire-pulse.

ii  gstreamer1.0-pulseaudio:amd64                            1.24.2-1ubuntu1.3                                amd64        GStreamer plugin for PulseAudio (transitional package)
ii  libcanberra-pulse:amd64                                  0.30-10ubuntu10                                  amd64        PulseAudio backend for libcanberra
ii  libkf5pulseaudioqt3:amd64                                1.3-2build2                                      amd64        Pulseaudio bindings library for Qt
ii  libpulse-mainloop-glib0:amd64                            1:16.1+dfsg1-2ubuntu10.1                         amd64        PulseAudio client libraries (glib support)
ii  libpulse0:amd64                                          1:16.1+dfsg1-2ubuntu10.1                         amd64        PulseAudio client libraries
ii  libpulse0:i386                                           1:16.1+dfsg1-2ubuntu10.1                         i386         PulseAudio client libraries
ii  pipewire-pulse                                           1.4.10-1~24.04.sav0                              amd64        PipeWire PulseAudio daemon
ii  pulseaudio-utils                                         1:16.1+dfsg1-2ubuntu10.1                         amd64        Command line tools for the PulseAudio sound server

TBH I can’t remember exactly how I ended up with this setup, but I did make sure I have a fairly recent Pipewire version (v1.4.10).

Note I still have Pipewire-tools and some libraries, because these are essential to the desktop.

As @ccaudle says, it’s very unusual to have a desktop Linux installation without the Pulse API: almost everything you do outside of Ardour will need the Pulse API.

Strictly speaking, this is a Pipewire config. You will note that the config path is ~/.config/pipewire/pipewire-pulse.conf.d.

It’s configuring the pipewire-pulse module, not Pulseaudio itself, which I do not have installed.

To repeat myself, pulse is an essential part of your system. If you remove it you will break almost all of your audio

Do NOT completely remove Pulseaudio (or Pipewire-pulse) from your system unless you 100% understand what you are doing and what the impact will be. It’s 99.999999% certain that it’s NOT what you actually need. And, as you’ve pointed out, at this point you don’t really understand what’s going on.

If you aren’t sure if you are using legacy Pulseaudio, or the newer pipewire-pulse emulation, run the following command (shown with the output from my system):

$ pactl info
Server String: /run/user/1000/pulse/native
Library Protocol Version: 35
Server Protocol Version: 35
Is Local: yes
Client Index: 1846
Tile Size: 65472
Server Name: PulseAudio (on PipeWire 1.4.10)
Server Version: 15.0.0
Default Sample Specification: float32le 2ch 48000Hz
Default Channel Map: front-left,front-right
Default Sink: input.loopback-3903-14
Default Source: capture.XR18_mic
Cookie: 8554:4aba

Note the line:

Server Name: PulseAudio (on PipeWire 1.4.10)

This means I am running Pipewire with Pulseaudio API emulation, not native Pulseaudio. This is probably what you want.

I’ll post about the configuration stuff separately, because I want to make sure I get this important info across without other info cluttering and confusing things.

Cheers,

Keith

I do not plan to remove PA myself from the system but as I understand it, PA is so to say “the old way” of managing audio on Linux, with Pipewire being the new standard. The pipewire-pulse and pipewire-jack packages are only there for backwards compatability with old systems, as a transition phase. Similar to the current Wayland/X11 situation, with a couple of projects like XWayland or wayback-x11 trying to offer a backwards compatability layer. But you see desktop environments shifting more and more towards Wayland as new standard and gradually ditching X11.
To me it always feels like we are only one announcement from DE devs away that pulse support is ultimately cut for future desktops.
Investing into the Pipewire eco-system, feels more future proof.
But then again, I’m not so deeply involved into the future plans of Linux audio to actually know what’s coming, so if you have insights that say otherwise I’d be happy to know.

On the configuration side:

Not really. They are user docs, but they are more of a reference guide to what all of the configuration items are, rather than a tutorial. And, I agree, there’s a lack of good tutorial information available for Pulseaudio, Pipewire, Wireplumber, etc.

The knowledge I have, which is far from complete, has been gained by messing around with Pulseaudio and Pipewire a lot over the last 10 years. I also explored wireplumber because, like you, I assumed it was what I needed.

My rough description of these (which may not be 100% accurate) is that Pulseaudio (or the Pulseaudio API, using pipewire-pulse) manages the connections. WirePlumber manages the policy. The two work together.

So, for example, if you plug in a Bluetooth headset, WirePlumber instructs Pulseaudio about the new device, and instructs Pulseaudio to switch the default audio device to the headset device.

All the audio connections to desktops apps is via Pulseaudio (or Pulse API via pipewire-pulse).

If you want to change the policy of your desktop system, such as not having it switch to a different audio device when it’s plugged in, then you need to mess with WirePlumber configs.

If you want to configure connections (as I did) then you need Pulseaudio which, as I said, on a Pipewire system is managed via pipewire-pulse, and configured using scripts in ~/.config/pipewire/pipewire-pulse.conf.d.

If you want to disable or otherwise configure individual audio devices, just use KDE System Settings.

The Pipewire documents are quite technical, because Pipewire (and PulseAudio) are complex and powerful systems, and are aimed at a technical audience. And, because of the compatibility, Pipewire inherits some of the architecture & terminology (e.g. “sources” and “sinks”), although the configuration language is different.

As a brief starter, you have the following objects:

Devices
These represent physical hardware devices, audio interfaces.

Nodes
A “node” is an object that produces, consumes, or processes audio data. Devices will, typically, have multiple nodes. For example, a typical audio interface will have a “Capture” node and a “Playback” node. You will also probably have a “Monitor” node which, as I understand it, is a bit of a legacy thing.

Sources and Sinks
These are, more generally in Pipewire, called"Outputs" and “Inputs”, but the PulseAudio terminology has been inherited in a lot of cases for compatibility with desktop apps. These are types of nodes which indicate their purpose/capability.

Ports
Ports are the individual capture, playback, or monitor endpoints and these, typically, correspond to the physical input and output ports on your audio interface.

The above are quite well visualised within qpwgraph or similar connection managers:

Streams
Streams are types of nodes which are created by applications. These may be dynamically created, such as when you launch a YouTube video on your browser, it will create a stream node for that, which will have a pair of output ports.

Where WirePlumber comes in, is there’s a policy in WirePlumber which, when a stream node is created with output ports, it will detect the change and instruct Pulseaudio to connect that to the default device.

Modules
These are “feature addons” to Pipewire which create additional functionality, including Jack and PulseAudio compatibility.

There are various modules (listed here) which do different things. Generally, they will create new nodes.

In my configuration example I used loopback module to create virtual nodes which act as a stereo source/sink which connects to specific ports on my XR18 mixer. You can use loopback to do things like remapping of channels.

In the part of the configuration I show below, I describe the stereo sink/output virtual device. This will create a pair of virtual nodes which appear in qpwgraph as follows:

image

These are actually internally linked, so the “playback_FL” is connected to the “output_AUX16” (and the same for the FR). The “monitor_FL” is the legacy quirk of PulseAudio, as I mentioned before. Personally, I would prefer it would go away or could be suppressed, and I would prefer it if qpwgraph automatically joined these nodes together. But you can’t have everything:

    # Creates a virtual sink for X-Air XR18 playback on channels 17/18
   {   name = libpipewire-module-loopback
       args = {
           # What I want to call the node. this will appear in other apps, like qpwgraph
           node.description = "XR18 Mixer Stereo"

           # What the node looks like. This is an audio sink (output) node
           # It has two output ports labelled "playback_FL" and "playback_FR".
           # Note these names are significant and have meaning in the Linux world as they
           # define the channel mapping behaviour.
           #
           capture.props = {
               media.class = "Audio/Sink"
               audio.position = [ FL FR ]
           }

           # The linked playback node which connects to my XR18 ports
           # This defines the connection to my device (node.target)
           #  as well as the channels on that device to connect to (audio.position)
           # There's also some technical flags which affect behaviour which are
           # out of scope for this overview
           playback.props = {
               node.name = "playback.XR18_stereo"
               audio.position = [ AUX16 AUX17 ]
               node.target = "alsa_output.usb-BEHRINGER_XR18_4C5BB32DFB73_03-00.pro-output-0"
               stream.dont-remix = true
               node.passive = true
           }
       }
   }

As I mentioned above, the channel names are significant. The different names represent different behaviours, and are listed in spa_audio_channel.

That is a fairly simple example. I have messed with Wireplumber a bit, but not as much as with Pipewire.

I think what you need to configure really depends on what you are trying to do. Your previous explanations have been a bit vague, so it’s not really clear if it’s policy (WirePlumber) or connectivity (Pipewire-pulse) that you need to use.

Cheers,

Keith

3 Likes

I consider this to be a misunderstanding.

PulseAudio, as an API, is here to stay for at least the next 10-20 years. Whilst it is possible to develop directly into the PipeWire API, there are relatively few applications doing this, and few significant motivations to do it.

As far as the native Pulseaudio daemon is concerned, that is already happening, but that’s because distros are transitioning to pipewire-pulse.

I doubt a full transition away from Pulseaudio API, where desktop distros ship without pipewire-pulse or any of the pulseaudio-libs, will happen in the next 10 years. In 10 years time, I strongly suspect that the majority of desktop applications which use audio will continue to use the Pulse API, simply because there’s very little reason not to.

IMO and IME, considering deprecating PulseAudio completely (including pipewire-pulse) on your desktop system at this time (2026) is a pointless, misguided, and impossible-to-achieve endeavour. It’s a fool’s errand.

At the moment, almost nothing uses native PipeWire APIs, almost everything uses PulseAudio or Jack.

My personal advice is to park this thought for a decade or so when it may actually be starting to become a reality (or may not) and focus on what you need today.

And that is 100% Pulseaudio and Jack API based, without any question!

And if any apps that directly use PipeWire API do start to appear, you can address that separately and in parallel. I will point out that the configuration for those is pretty similar as for pipewire-pulse.

And in 2040, when PulseAudio configurations are (possibly) no longer required, you can just delete or ignore the old configs.

Cheers,

Keith

As it should be. Exposing a custom new API was IMHO a mistake. It just adds to the fragmentation while not solving any actual issue.

1 Like

Well, to be fair, some new API support was needed for video, as Pipewire supports video which Pulseaudio does not.

I have no view or opinion whether extending the Pulseaudio API to video would have worked or been a good idea instead of creating a completely new API.

I also think the native Pipewire API is used in Automotive apps.

Cheers,

Keith