PipeWire

From ArchWiki

PipeWire is a new low-level multimedia framework. It aims to offer capture and playback for both audio and video with minimal latency and support for PulseAudio, JACK, ALSA and GStreamer-based applications.

The daemon based on the framework can be configured to be both an audio server (with PulseAudio and JACK features) and a video capture server.

PipeWire also supports containers like Flatpak and does not rely on the audio and video user groups. Instead, it uses a Polkit-like security model, asking Flatpak or Wayland for permission to record screen or audio.

Installation

Install the pipewire package from the official repositories. There is also lib32-pipewire for multilib support.

Pipewire uses systemd/User for management of the server and automatic socket activation.

Optionally, install pipewire-docs to review the documentation.

Pipewire can work as drop-in replacement for others audio servers. See #Audio for details.

Session manager

Like JACK, PipeWire implements no connection logic internally. The burden of watching for new streams and connect them to the appropriate output device or application is left to an external component known as a session manager.

Currently, the only recommended session manager is:

  • WirePlumber — A more powerful manager and the current recommendation. It is based on a modular design, with Lua plugins that implement the actual management functionality.
https://pipewire.pages.freedesktop.org/wireplumber/ || wireplumber

The following session manager is deprecated in favor of WirePlumber:

  • PipeWire Media Session — A very simple session manager that caters to some basic desktop use cases. It was mostly implemented for testing and as an example for building new session managers.
https://gitlab.freedesktop.org/pipewire/media-session || pipewire-media-session

Switch between session managers by simply installing the appropriate package, which will conflict with and replace the other option.

GUI

  • qpwgraph — Qt-based Graph/Patchbay for PipeWire, inspired by the JACK tool QjackCtl. Saves wire sets.
https://gitlab.freedesktop.org/rncbc/qpwgraph || qpwgraph
  • Helvum — GTK-based patchbay for PipeWire, inspired by the JACK tool catia. Does not save wire sets.
https://gitlab.freedesktop.org/pipewire/helvum || helvum

Configuration

The PipeWire package provides an initial set of configuration files in /usr/share/pipewire. You should not edit these files directly, as package updates will overwrite your changes. To configure PipeWire, you can copy files from /usr/share/pipewire to the alternate system-wide location /etc/pipewire, or to the user location ~/.config/pipewire. An equally named file in a directory with a higher precedence makes the analogous files ignored. [1]

Profiles

Pipewire brings a custom "Pro Audio" profile in addition to the PulseAudio profiles, selectable through pavucontrol. The effect of which is described here: https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/FAQ#what-is-the-pro-audio-profile

Usage

Audio

PipeWire can be used as an audio server, similar to PulseAudio and JACK. It aims to replace both PulseAudio and JACK, by providing a PulseAudio-compatible server implementation and ABI-compatible libraries for JACK clients. See the blog post PipeWire Late Summer Update 2020 for more information.

First, install pipewire-audio. Depending on the type of audio clients, you may also need to take some extra steps.

ALSA clients

Install pipewire-alsa (and remove pulseaudio-alsa if it was installed) to route all applications using the ALSA API through PipeWire.

PulseAudio clients

Install pipewire-pulse. It will replace pulseaudio and pulseaudio-bluetooth. Reboot, re-login or stop pulseaudio.service and start the pipewire-pulse.service user unit to see the effect.

Normally, no further action is needed as the user service pipewire-pulse.socket should be enabled automatically by the package. To check if the replacement is working, run the following command for the Server Name and default input/output:

$ pactl info
...
Server Name: PulseAudio (on PipeWire x.y.z)
...
Default Sink: alsa_output.{bus}-{device}.{profile}
Default Source: alsa_input.{bus}-{device}.{profile}
...
Setting overall or individual channel volume

To adjust output channel volume, the sink needs to be specified using pactl get-sink-volume {sink} using the value of Default Sink: (above) or Name: (below), default sink device (@DEFAULT_SINK@), or Sink # (e.g. 1 below):

$ pactl list sinks | grep -B1 -A9 State:
Sink #1
        State: RUNNING
        Name: alsa_output.pci-0000_2d_00.4.analog-surround-51
...
        Driver: PipeWire
...
        Mute: no
        Volume: front-left: 65536 / 100% / 0.00 dB,   front-right: 65536 / 100% / 0.00 dB,   rear-left: 65536 / 100% / 0.00 dB,   rear-right: 65536 / 100% / 0.00 dB,   front-center: 65536 / 100% / 0.00 dB,   lfe: 65536 / 100% / 0.00 dB
                balance 0.00

Hint: if audio is playing, grep(1) for RUNNING as other devices will be SUSPENDED.

The balance ratio is calculated automatically. To set the overall volume of the default device use:

pactl set-sink-volume @DEFAULT_SINK@ 75%

To set individual channels, provide each channel volume separately:

pactl set-sink-volume @DEFAULT_SINK@ 100% 75% 100% 75% 100% 100%

Source inputs are handled similarly. For further configuration (e.g. regarding modules) see the official upstream Wiki about Migration from PulseAudio and Pipewire-Pulse Configuration.

JACK clients

Install pipewire-jack for JACK support. There is also lib32-pipewire-jack for multilib support.

pw-jack(1) may be used to start JACK clients, but it is technically not required, as it only serves as a wrapper around the PIPEWIRE_REMOTE, PIPEWIRE_DEBUG and PIPEWIRE_LATENCY environment variables.

It is possible to request a custom buffer size by setting a quotient of buffersize/samplerate (which equals the block latency in seconds):

PIPEWIRE_LATENCY="128/48000" application

Bluetooth devices

PipeWire handles Bluetooth audio devices if the pipewire-audio package is installed.

Automatic profile selection

WirePlumber has profile auto-switching enabled by default. It can automatically switch between HSP/HFP and A2DP profiles whenever an input stream is detected. You can disable it with:

/etc/wireplumber/policy.lua.d/11-bluetooth-policy.lua (or ~/.config/wireplumber/policy.lua.d/11-bluetooth-policy.lua)
bluetooth_policy.policy["media-role.use-headset-profile"] = false

pipewire-media-session has it disabled by default. You can set bluez5.autoswitch-profile property to true to enable it:

/etc/pipewire/media-session.d/bluez-monitor.conf (or ~/.config/pipewire/media-session.d/bluez-monitor.conf)
...
rules = [
    {
        ...
        actions = {
            update-props = {
                ...
                bluez5.autoswitch-profile = true
...

PipeWire patch sets for command line

qpwgraph can be used to visualize and create connections, and also save and load patch sets.

For non-GUI needs, the following are bash scripts to save wiresets, load wiresets, and dewire all connections. For saving and loading, use a command-line parameter for the filename.

pw-savewires
#!/bin/bash

if [[ "$#" -ne 1 ]]; then
	echo
	echo 'usage: pw-savewires filename'
	echo
	exit 0
fi

rm $1 &> /dev/null
while IFS= read -r line; do
	link_on=`echo $line | cut -f 4 -d '"'`
	link_op=`echo $line | cut -f 6 -d '"'`
	link_in=`echo $line | cut -f 8 -d '"'`
	link_ip=`echo $line | cut -f 10 -d '"'`
	echo "Saving: " "'"$link_on:$link_op"','"$link_in:$link_ip"'"
	echo "'"$link_on:$link_op"','"$link_in:$link_ip"'" >> $1
done < <(pw-cli dump short link)
pw-loadwires
#!/bin/python

import sys
import csv
import os

if len(sys.argv) < 2:
	print('\n usage: pw-loadwires filename\n')
	quit()

with open(sys.argv[1], newline='') as csvfile:
	pwwreader = csv.reader(csvfile, delimiter=',', quotechar='"')
	for row in pwwreader:
		print('Loading:  ' + row[0] + ' --> ' + row[1])
		process = os.popen('pw-link ' + row[0] + ' ' + row[1])
pw-dewire
#!/bin/bash
while read -r line; do
	echo 'Dewiring: ' $line '...'
	pw-link -d $line
done < <(pw-cli dump short link {{!}} grep -Eo '^[0-9]+')

Sharing audio devices with computers on the network

While PipeWire itself is not network transparent, its pulse implementation supports network streaming. An easy way to share audio between computers on the network is to use the Avahi daemon for discovery. To enable this functionality, install the pipewire-zeroconf package.

Make sure that the avahi-daemon.service is running (and UDP port 5353 is open if using a firewall) on all computers that will be sharing audio.

Note: Some GUI volume managers hide network cards by default. (ex: in Plasma one has to "Configure Audio Volume..." and check "Show virtual devices".

To share the local audio devices load the appropriate modules on the host (make sure to use the local IP address):

$ pactl load-module module-native-protocol-tcp listen=192.168.1.10
$ pactl load-module module-zeroconf-publish

Then load the discovery module on the clients:

$ pactl load-module module-zeroconf-discover

It is also possible to load the modules automatically by creating a dedicated configuration file:

This article or section needs language, wiki syntax or style improvements. See Help:Style for reference.

Reason: Use context.modules instead of context.exec as below. (Discuss in Talk:PipeWire)
/etc/pipewire/pipewire-pulse.conf.d/50-network-party.conf
context.exec = [
    { path = "pactl" args = "load-module module-native-protocol-tcp" }
    { path = "pactl" args = "load-module module-zeroconf-discover" }
    { path = "pactl" args = "load-module module-zeroconf-publish" }
]
Streaming audio to an AirPlay receiver

It is possible to stream audio to a device that is posing as an AirPlay Receiver. To enable this functionality, load the RAOP Discover module:

$ pactl load-module module-raop-discover

It is also possible to load this module automatically by creating a dedicated configuration file:

/etc/pipewire/pipewire.conf.d/raop-discover.conf (or ~/.config/pipewire/pipewire.conf.d/raop-discover.conf)
context.modules = [
   {
       name = libpipewire-module-raop-discover
       args = { }
   }
]

Some speakers' AirPlay implementations (like Sonos AirPlay 2 speakers) may require opening up ports 6001 and 6002 for incoming UDP traffic on your source device.

Run PipeWire on top of native JACK

PipeWire can also run as a JACK client on top of the native JACK daemon if desired.

See JACK and PipeWire (PipeWire wiki) and JACK Bridge (PipeWire wiki) for more information and additional configuration (like available channels for example).

To use it install the pipewire-jack-client and start JACK. Pipewire should be bridged automatically.

Note: Since pipewire 0.3.81 loading the jackdbus module is done automatically and is no longer necessary.

It can manually be loaded (as explained by pactl(1)) like a PulseAudio module: pactl load-module module-jackdbus-detect before starting jack.

Use ALSA dmix devices as PipeWire sinks

It is possible to have a PipeWire server (or multiple, for each user) output to ALSA via ALSA dmix devices. This allows you to use ALSA as the primary audio output system while being able to use non-ALSA devices such as Bluetooth headphones.

ALSA dmix setup

Suppose you have two cards, PCH and HDMI:

/proc/asound/cards
 0 [PCH            ]: HDA-Intel - HDA Intel PCH
                      HDA Intel PCH at 0xdff40000 irq 146
 1 [HDMI           ]: HDA-Intel - HDA ATI HDMI
                      HDA ATI HDMI at 0xdfe60000 irq 147

and your PCMs look like:

/proc/asound/pcm
00-00: ALC1220 Analog : ALC1220 Analog : playback 1 : capture 1
00-02: ALC1220 Alt Analog : ALC1220 Alt Analog : capture 1
01-03: HDMI 0 : HDMI 0 : playback 1
01-07: HDMI 1 : HDMI 1 : playback 1
01-08: HDMI 2 : HDMI 2 : playback 1
01-09: HDMI 3 : HDMI 3 : playback 1
01-10: HDMI 4 : HDMI 4 : playback 1
01-11: HDMI 5 : HDMI 5 : playback 1

and suppose your ALSA configuration looks something like this:

/etc/asound.conf
ctl.!default {
  type hw
  card PCH
}

pcm.!default {
  type plug
  slave.pcm "dmix:PCH,0"
}

pcm.dhdmi {
  type plug
  slave.pcm "dmix:HDMI,9"
}

In this particular example, the dmix devices would be dmix:PCH,0 and dmix:HDMI,9.

PipeWire dmix setup

This article or section needs expansion.

Reason: Add pipewire-media-session instructions. (Discuss in Talk:PipeWire)

First of all, stop wireplumber from monitoring and adding hardware ALSA devices by commenting out alsa_monitor.enable():

/etc/wireplumber/main.lua.d/90-enable-all.lua (or ~/.config/wireplumber/main.lua.d/90-enable-all.lua)
...
-- Load devices
-- alsa_monitor.enable()
v4l2_monitor.enable()
libcamera_monitor.enable()
...

Now, configure pipewire to use dmix devices. The default configuration file (/usr/share/pipewire/pipewire.conf) contains a commented out example which you can use as a basis.

Add your own element to the context.objects array:

/etc/pipewire/pipewire.conf.d/alsa-dmix.conf (or ~/.config/pipewire/pipewire.conf.d/alsa-dmix.conf)
context.objects = [
    # We do not start with dmix, but with an input device.
    # Do not forget to add an input device.
    # On a friend's Laptop, I saw Zoom having a nervous
    # breakdown and endlessly crying because no input device
    # was configured! You have been warned.
    { factory = adapter
        args = {
            factory.name           = api.alsa.pcm.source
            node.name              = "alsa-mic-internal" # name of pulse device (mpv)
            node.description       = "Mic Internal" # name of pulse device (pavucontrol)
            media.class            = "Audio/Source"
            api.alsa.path          = "hw:PCH,0"
        }
    }
    # Okay, now we add our dmix PCMs
    { factory = adapter
        args = {
            factory.name           = api.alsa.pcm.sink # sink for dmix
            node.name              = "alsa-dmix-internal" # name of pulse device (mpv)
            node.description       = "PCM Internal" # name of pulse device (pavucontrol)
            media.class            = "Audio/Sink" # Sink for dmix
            api.alsa.path          = "dmix:PCH,0"
        }
    }

    { factory = adapter
        args = {
            factory.name           = api.alsa.pcm.sink # sink for dmix
            node.name              = "alsa-dmix-hdmi" # name of pulse device (mpv)
            node.description       = "PCM HDMI" # name of pulse device (pavucontrol)
            media.class            = "Audio/Sink" # Sink for dmix
            # remember this is a non-default dmix from /etc/asound.conf
            api.alsa.path          = "dmix:HDMI,9"
        }
    }
]

As a user (non-root), check out the output of wpctl status, and set the default input(source) and output(sink) devices to your liking with wpctl set-default ID. ID is the number before sink/source names.

Now, you can fully test your configuration.

Switching between device profiles

Some hardware audio devices, like snd_hda_intel, function differently depending on which profile the device is running in. In the case of snd_hda_intel, there are separate profiles for HDMI and analog output.

Switching to HDMI with WirePlumber:

$ wpctl set-profile <device-ID> 3
$ wpctl status
...
├─ Sinks:
│  *   53. Built-in Audio Digital Stereo (HDMI) [vol: 1.00]
...

Switching to analog with WirePlumber:

$ wpctl set-profile <device-ID> 1
$ wpctl status
...
├─ Sinks:
│  *   51. Built-in Audio Analog Stereo        [vol: 0.60]
...

WebRTC screen sharing

Most applications used to rely on X11 for capturing the desktop (or individual applications), for example when using WebRTC in web browsers (e.g. on Google Meet). On Wayland, the screen sharing mechanism is handled through the XDG Desktop Portal and PipeWire, which enables sharing content under Wayland with fine-grained access controls.

Tip: Test whether WebRTC screen sharing is working by using Mozilla's GetUserMedia WebRTC test page.
Note: xdg-desktop-portal 1.10.0 fixed a mismatch between specification and implementation of its D-Bus interface. [2] Hence, some clients may not work with xdg-desktop-portal 1.10.0 or newer.

Firefox (84+) and Chromium (110+) support this method by default, while on older versions of Chromium (73+), one needs to enable WebRTC PipeWire support by setting the corresponding (experimental) flag at the URL chrome://flags/#enable-webrtc-pipewire-capturer or via CLI argument --enable-features=WebRTCPipeWireCapturer.

obs-studio (27+) supports this method by using the new PipeWire capture source.

Video

This article or section needs expansion.

Reason: pipewire-v4l2 (Discuss in Talk:PipeWire)

Although the software is not yet production-ready, it is safe to play around with. Most applications that rely on GStreamer to handle e.g. video streams should work out-of-the-box using the PipeWire GStreamer plugin, see GStreamer#PipeWire. Applications like e.g. cheese are therefore already able to share video input using it.

Using pipewire-v4l2, it should also be possible to use the pw-v4l2 script to preload a library (/lib/pipewire-0.3/v4l2/libpw-v4l2.so) that intercepts v4l2 calls and routes video through pipewire.

Audio post-processing

Pipewire module-filter-chain

Pipewire has an internal module called filter-chain that can create nodes to process audio input and output. See /usr/share/pipewire/filter-chain/ for examples including equalization, virtual surround sound, LADSPA plugins and channel mixing.

Systemwide parametric equalization

Copy the config file to your .config folder:

$ mkdir -p ~/.config/pipewire/pipewire.conf.d
$ cp /usr/share/pipewire/filter-chain/sink-eq6.conf ~/.config/pipewire/pipewire.conf.d/

Then edit sink-eq6.conf to incorporate the desired parameters. For headphones, these can be obtained from Oratory1990's database or, if not listed there, the AutoEQ project.

If you require a pre-amp, modify eq_band_1 to apply a bq_highshelf filter at frequency 0Hz with a negative gain (gains from -120 to +20dB supported):

label = bq_highshelf
control = { "Freq" = 0 "Q" = 1.0 "Gain" = -7.5 }

For more than 6 bands, add more entries to the nodes list and corresponding links connecting one filter ":Out" to the next filter ":In", for instance to increase to 11 bands (preamp + 10):

                    { output = "eq_band_6:Out" input = "eq_band_7:In" }
                    { output = "eq_band_7:Out" input = "eq_band_8:In" }
                    { output = "eq_band_8:Out" input = "eq_band_9:In" }
                    { output = "eq_band_9:Out" input = "eq_band_10:In" }
                    { output = "eq_band_10:Out" input = "eq_band_11:In" }

Restart Pipewire, select "Equalizer Sink" as your default sound output device; this should then apply to all applications.

EasyEffects

EasyEffects (former PulseEffects) is a GTK utility which provides a large array of audio effects and filters to individual application output streams and microphone input streams. Notable effects include an input/output equalizer, output loudness equalization and bass enhancement, input de-esser and noise reduction plug-in. See the GitHub page for a full list of effects.

Note: Firefox has an issue with microphone stream, see Github issue.

In order to use EasyEffects, install easyeffects. See Community Presets for a collection of preset configurations. See AutoEq for collection of algorithmically generated EQ presets for headphones.

Note: For PulseEffects legacy version, see PulseAudio#PulseEffects.

NoiseTorch

NoiseTorch is an alternative way for noise suppression, packaged with noisetorchAUR. There also exists noisetorch-gitAUR.

After starting it the module can be loaded for the selected microphone. It is possible to adjust the voice activation threshold, which should be set to the highest level, not filtering out any actual voice.

You can start audio processing with systemd automatically, see [3]. Note that the noisetorch binary path is different if installed from AUR.

Noise suppression for voice

Install the noise-suppression-for-voice package.

Then simply follow the instructions given on GitHub.

JamesDSP

JamesDSP for Linux (available as jamesdspAUR) provides open-source sound effects for PipeWire and PulseAudio. It uses its own effects engine and without depending on LADSPA, Calf, etc. JamesDSP was initially published as an audio effects processor for Android devices.

Using LADSPA, LV2 and VST plugins with PulseAudio

The factual accuracy of this article or section is disputed.

Reason: Does this section relate to using the pulseaudio daemon or the pipewire's interface for pulseaudio clients? (Discuss in Talk:PipeWire)

You can create input/output destinations to connect PulseAudio to Carla's audio plug-ins.

If you want to choose between the full list of available LADSPA, LV2 and VST plugins, you can apply them using a custom Pulseaudio null sink and Carla Jack host. Install pipewire-pulse, pipewire-jack and carla. At the begin, create a new PulseAudio null sink named default_null_sink.

pactl load-module module-null-sink object.linger=1 media.class=Audio/Sink sink_name=default_null_sink channel_map=FL,FR

Start Carla through Pipewire, pw-jack carla-rack. In Rack tab add whichever plugin you want. Make sure they are stereo type. You can change their order, the one on top of the list will be the first to receive the audio stream, just like in EasyEffects. Afterwards move to Patchbay tab and connect the default_null_sink L/R monitors to Carla inputs, then Carla outputs to the playbacks of your desired device (speakers, earphones, HDMI, etc). Save the configuration to a local folder, i.e. ~/Documents/carla_sink_effects.carxp.

You can test the effects while a multimedia application is reproducing audio, i.e. watching a video on a website through Firefox. There are two methods to do it. The first one, inside Carla Patchbay tab, disconnecting all Firefox connections and linking its L/R outputs to default_null_sink playbacks. The second through pavucontrol, locating Firefox audio stream and redirecting it to default_null_sink (this should remember the connection to automatically redirect the application to the same sink on the next instance).

To apply these settings at startup, create two systemd user service units:

~/.config/systemd/user/jack-carla-rack.service
[Unit]
Description=Load Carla Rack JACK host

[Service]
PassEnvironment="PIPEWIRE_LINK_PASSIVE=true"
Type=exec
ExecStart=/usr/bin/pw-jack carla-rack -n

[Install]
WantedBy=default.target
~/.config/systemd/user/pulseaudio-null-sink@.service
[Unit]
Description=Load %i Pulseaudio null sink
Before=jack-carla-rack.service
After=pipewire-pulse.service

[Service]
Type=oneshot
ExecStart=/usr/bin/pactl load-module module-null-sink object.linger=1 media.class=Audio/Sink sink_name=%i channel_map=FL,FR
ExecStop=/usr/bin/pactl unload-module module-null-sink
RemainAfterExit=yes

[Install]
WantedBy=default.target

Then override jack-carla-rack service specifying the full path of your Carla configuration at Environment directive:

~/.config/systemd/user/jack-carla-rack.service.d/override.conf
[Service]
Environment="CARLA_CONFIG_FILE=/home/username/Documents/carla_sink_effects.carxp"
ExecStart=
ExecStart=/usr/bin/pw-jack carla-rack -n $CARLA_CONFIG_FILE

At last, enable the pulseaudio-null-sink@default_null_sink.service and jack-carla-rack.service user units.

Note that if you set the default_null_sink as the default device in system settings, all applications will be redirected to it and the volume keys will change its level, not the one on the speakers. If you want to control volume speakers, leave them as the default in system settings and redirect your desired application to default_null_sink inside pavucontrol (Pipewire compatibility layer will remember the connection on the next instance of the same application).

Troubleshooting

This article or section is a candidate for merging with PipeWire/Troubleshooting.

Notes: This section is long enough to be split into a dedicated subpage. (Discuss in Talk:PipeWire#Move Troubleshooting into a new separate page)

Audio

Microphone is not detected by PipeWire

PipeWire's alsa-monitor module uses alsa-card-profiles to detect devices by default. If this is not working for you, try to turn off api.alsa.use-acp, or optionally turn on api.alsa.use-ucm.

If using pipewire-media-session:

/etc/pipewire/media-session.d/alsa-monitor.conf (or ~/.config/pipewire/media-session.d/alsa-monitor.conf)
...
rules = [
    {
        ...
        actions = {
        update-props = {
            ...
            api.alsa.use-acp = false
...

Otherwise, if using wireplumber:

/etc/wireplumber/main.lua.d/50-alsa-config.lua (or ~/.config/wireplumber/main.lua.d/50-alsa-config.lua)
...
alsa_monitor.rules = {
    {
        ...
        apply_properties = {
            -- Use ALSA-Card-Profile devices. They use UCM or the profile
            -- configuration to configure the device and mixer settings.
            -- ["api.alsa.use-acp"] = true,
 
            -- Use UCM instead of profile when available. Can be
            -- disabled to skip trying to use the UCM profile.
            ["api.alsa.use-ucm"] = true,
...

Then, restart PipeWire and check available devices:

This article or section is out of date.

Reason: Option --list-targets is no longer available in the recent versions of pw-record; in order to list objects use either wpctl status or pw-cli ls or pw-dump instead. (Discuss in Talk:PipeWire)
$ pw-record --list-targets
Available targets ("*" denotes default): 62
	58: description="Built-in Audio" prio=1872
	60: description="Built-in Audio" prio=2000
*	62: description="Built-in Audio (Loopback PCM)" prio=1984

An alternative solution suggested in this PipeWire issue is to add the microphone manually. First of all, make sure the microphone is detected by ALSA.

$ arecord -l
**** List of CAPTURE Hardware Devices ****
card card_number: card_name, device device_number: device_name
  ...

Choose your microphone from the list, and to further test the microphone, run the following commands.

$ arecord --duration=5 --format=dat --device=hw:card_number,device_number test-mic.wav # record from the mic
$ aplay test-mic.wav # play it

If the microphone is working with arecord, but not detected by PipeWire, try to add a config file to manually add this device.

/etc/pipewire/pipewire.conf.d/microphone.conf (or ~/.config/pipewire/pipewire.conf.d/microphone.conf)
context.objects = [
    { factory = adapter
        args = {
            factory.name           = api.alsa.pcm.source
            node.name              = "microphone"
            node.description       = "Undetected Microphone"
            media.class            = "Audio/Source"
            api.alsa.path          = "hw:card_number,device_number"
        }
    }
]

And then restart PipeWire to reload the config.

Sound does not automatically switch when connecting a new device

To automatically switch to newly connected devices, create this file:

/etc/pipewire/pipewire-pulse.conf.d/switch-on-connect.conf (or ~/.config/pipewire/pipewire-pulse.conf.d/switch-on-connect.conf)
# override for pipewire-pulse.conf file
pulse.cmd = [
    { cmd = "load-module" args = "module-always-sink" flags = [ ] }
    { cmd = "load-module" args = "module-switch-on-connect" }
]

Sound does not automatically switch to Bluetooth headphones

The factual accuracy of this article or section is disputed.

Reason: The linked upstream issue is specific to the xfce pulseaudio panel plugin. (Discuss in Talk:PipeWire)

Run pactl load-module module-switch-on-connect and configure your desktop environment to automatically run that command on login. You might need to execute wpctl set-default <id>. The <id> may be found using output of wpctl status. See wireplumber issue #89 for more details.

No sound after connecting to Bluetooth device

As of 2020-12-07, if there is no sound after connecting a Bluetooth device, you might need to switch the default sink and/or move a sink input to the correct sink. Use pactl list sinks to list the available sinks and pactl set-default-sink to switch the default sink to the Bluetooth device. This can be automated via udev using a script similar to this one.

See this Reddit thread for a discussion of the issue. According to author of the script, the headset profile (HSP) might still have problems.

Low volume

After replacing PulseAudio with Pipewire, sound may work fine, but after a reboot, the volume becomes intolerably low.

Open alsamixer, use F6 to select the proper soundcard, and make sure the ALSA volumes are at 100%. alsactl should maintain this setting after reboot.

Increasing RLIMIT_MEMLOCK

Dec 13 11:11:11 HOST pipewire-pulse[99999]: Failed to mlock memory 0x7f4f659d8000 32832: This is not a problem but for best performance, consider increasing RLIMIT_MEMLOCK

Install realtime-privileges and add your own user to the realtime group.

Alternatively, increasing memlock from 64kB to 128kB seems enough to fix this. If you are running pipewire-pulse under systemd/User, add:

username	soft	memlock	64
username	hard	memlock	128

to /etc/security/limits.d/username.conf

Changing the default sample rate

By default PipeWire sets a fixed global sample rate of 48kHz. If you need to change it (e.g. you own a DAC supporting a higher value), you can set a new default:

/etc/pipewire/pipewire.conf (or ~/.config/pipewire/pipewire.conf)
...
context.properties = {
    ...
    default.clock.rate          = sample_rate
    ...

Changing the allowed sample rate(s)

PipeWire can also change dynamically the output sample rates supported by your DAC. The sample rate follows the sample rate of the audio stream being played.

/etc/pipewire/pipewire.conf (or ~/.config/pipewire/pipewire.conf)
...
context.properties = {
    ...
    default.clock.allowed-rates = [ sample_rate_1 sample_rate_2 sample_rate_3 ... ]
    ...

for example, [ 44100 48000 88200 96000 ].

According to the developer: "PipeWire allows up to 16 different sample rates and will switch when possible". That means, with configuration above, no resampling is done when supported. Since PipeWire 0.3.61 up to 32 different sample rates can be configured.

Consult your hardware manual for supported values of your DAC. Supported rates by the kernel driver codec are listed with the following command.

$ grep -E 'Codec|Audio Output|rates' /proc/asound/card*/codec#*

To check out which output sample rate are configured for a card run:

$ grep rate: /proc/asound/card?/pcm??/sub?/hw_params
/proc/asound/card1/pcm0p/sub0/hw_params:rate: 96000 (96000/1)

In pcm0p or pcm0c c is short for "capture" and p is for "playback".

$ pw-top

also shows sample rate for each card and audio stream.

Sound quality (resampling quality)

If you used PulseAudio with resample-method = speex-float-10 or soxr-vhq, then you might consider uncommenting and changing resample.quality = 4 to 10 or the maximum 15 in stream.properties block in both /etc/pipewire/client.conf and /etc/pipewire/pipewire-pulse.conf (copy them from /usr/share/pipewire/ if they do not exist). Do not forget to restart the pipewire.service and pipewire-pulse.socket user units (never forget pipewire-pulse.socket if you want your configuration changes to be applied).

There is a very little quality difference between 10 and 15, but the CPU load difference is 2-3x. And the latency difference between 4, 10, 15 is yet to be investigated by anybody. resample.quality = 15 on 44100→48000 Hz on Ryzen 2600 causes pipewire or pipewire-pulse processes to cause 4.0% one CPU core load.

You can compare resamplers here: https://src.infinitewave.ca/ (do not pay attention to anything above 18 KHz and over 120 dB). speex is listed as "Xiph.org Speex".

PipeWire uses its own resampling algorithm called Spa. Like with SoX's sox, Speex's speexenc, PipeWire includes its standalone version: spa-resample. Usage:

$ spa-resample -q 15 -f s24 -r 48000 input16bit44100orAnythingElse.wav output24bit48000hz.wav

It is probably somehow possible to use other resamplers by creating your own sink. Or just use a plugin in your music player (e.g., Qmmp has SoX plugin).

External sound card not activated after reconnect

Check ~/.config/pipewire/media-session.d/default-profile if there is any entry with default profile "off" and remove it. If that does not help, remove all files from ~/.config/pipewire/media-session.d/ and restart the pipewire.service user unit.

No Sound or pactl info shows Failure: Connection refused

It means applications are unable to connect to the PipeWire-Pulse service, confirm that /etc/pipewire/pipewire-pulse.conf exists and is not empty and restart the pipewire-pulse.service user unit.

If that does not fix it, run strace -f -o /tmp/pipe.txt pactl info and pastebin /tmp/pipe.txt while seeking help on IRC (#pipewire on OFTC) or the mailing-lists.

Low audio quality on Bluetooth

In case Bluetooth playback stutters, check the unit status of the pipewire.service user unit for errors similar as below:

Feb 17 18:23:01 HOST pipewire[249297]: (bluez_input.18:54:CF:04:00:56.a2dp-sink-60) client too slow! rate:512/48000 pos:370688 status:triggered

If they appear, check the currently selected codec using pactl list sinks and try changing it by setting bluez5.codecs to one of sbc aac ldac aptx aptx_hd. You can also try mSBC support (fixes mic on Sony 1000XM3, i.e. Headphones WH-1000XM3 and Earbuds WF-1000XM3), and the SBC-XQ codec.

With pipewire-media-session:

/etc/pipewire/media-session.d/bluez-monitor.conf (or ~/.config/pipewire/media-session.d/bluez-monitor.conf)
...
properties = {
  ...
  bluez5.enable-msbc = true
  bluez5.enable-sbc-xq = true
  bluez5.codecs = [sbc sbc_xq]
...

With wireplumber:

/etc/wireplumber/bluetooth.lua.d/51-bluez-config.lua (or ~/.config/wireplumber/bluetooth.lua.d/51-bluez-config.lua)
bluez_monitor.properties = {
  ["bluez5.enable-sbc-xq"] = true,
  ["bluez5.enable-msbc"] = true,
  ["bluez5.codecs"] = "[sbc sbc_xq]",
}

Restart PipeWire by restarting the pipewire.service user unit for the changes to take effect.

Noticeable audio delay or audible pop/crack when starting playback

This is caused by node suspension when inactive.

With pipewire-media-session:

Disable this by editing /etc/pipewire/media-session.d/*-monitor.conf depending on where the delay occurs and changing property session.suspend-timeout-seconds to 0 to disable or experiment with other values and see what works.

Alternatively you can comment out the line suspend-node in /etc/pipewire/media-session.d/media-session.conf.

Restart both pipewire.service and pipewire-pulse.service to apply these changes, or alternatively reboot.

With wireplumber, create a new file to overwrite the default configuration:

~/.config/wireplumber/main.lua.d/51-disable-suspension.lua
(or /etc/wireplumber/main.lua.d/51-disable-suspension.lua)
table.insert (alsa_monitor.rules, {
  matches = {
    {
      -- Matches all sources.
      { "node.name", "matches", "alsa_input.*" },
    },
    {
      -- Matches all sinks.
      { "node.name", "matches", "alsa_output.*" },
    },
  },
  apply_properties = {
    ["session.suspend-timeout-seconds"] = 0,  -- 0 disables suspend
  },
})

For bluetooth devices, use the following configuration as well (note the different file location):

~/.config/wireplumber/bluetooth.lua.d/51-disable-suspension.lua
(or /etc/wireplumber/bluetooth.lua.d/51-disable-suspension.lua)
-- Note: bluez_monitor, not alsa_monitor
table.insert (bluez_monitor.rules, {
  matches = {
    {
      -- Matches all sources.
      -- Note: bluez_input, not alsa_input
      { "node.name", "matches", "bluez_input.*" },
    },
    {
      -- Matches all sinks.
      -- Note: bluez_output, not alsa_output
      { "node.name", "matches", "bluez_output.*" },
    },
  },
  apply_properties = {
    ["session.suspend-timeout-seconds"] = 0,  -- 0 disables suspend
  },
})

Restart pipewire.service and wireplumber.service to apply changes.

Instead of disabling suspension entirely, you can also change the timeout value to the desired number of seconds of delay before source suspension.

Some devices implement their own detection of silence and suspension. For them disabling node suspention alone won't work. It's possible to work around them by adding a small amount of noise, making it so the output never goes fully silent:

.../51-disable-suspension.lua
...
    ["session.suspend-timeout-seconds"] = 0,  -- 0 disables suspend
    ["dither.method"] = "wannamaker3",  -- add dither of desired shape
    ["dither.noise"] = 0,  -- add additional bits of noise
...

It may be neccessary to play with dither.noise and dither.method parameters to make it so the noise is sufficiently silent and simultaneously loud enough to prevent detection of silence. See PipeWire documentation.

Audio cutting out when multiple streams start playing

This problem can typically be diagnosed by reading the journal of the pipewire-pulse.service user unit and finding lines similar to:

pipewire-pulse[21740]: pulse-server 0x56009b9d5de0: [Nightly] UNDERFLOW channel:0 offset:370676 underrun:940

According to the official PipeWire troubleshooting guide, to solve this problem for pipewire-media-session:

/etc/pipewire/media-session.d/alsa-monitor.conf (or ~/.config/pipewire/media-session.d/alsa-monitor.conf
api.alsa.headroom = 1024

With wireplumber:

/etc/wireplumber/main.lua.d/50-alsa-config.lua (or ~/.config/wireplumber/main.lua.d/50-alsa-config.lua)
apply_properties = {
    ["api.alsa.headroom"] = 1024,
},

If you experience audio stuttering because of kernel page locking or late scheduling see Gaming#Tweaking kernel parameters for response time consistency.

Audio is distorted

  • For microphones, try navigating to the card that is having issues after running alsamixer and use the arrow keys to reduce any "Mic Boost" or "Internal Mic Boost" options.
  • Follow #Changing the default sample rate, reducing the sample rate to to 44100 (44.1 kHz).

Audio problems after standby

If the sound is missing or otherwise garbled after waking the machine up from sleep, it might help to reinitialize ALSA:

# alsactl init

High latency with USB DACs (e.g. Schiit DACs)

Changing sample rates or formats might help reduce latency with some DACs such as Schiit Hel 2.[4] Using matching rules in pipewire-media-session we can set properties for devices.[5]

Copy the default configuration file /usr/share/pipewire/media-session.d/alsa-monitor.conf into either /etc/pipewire/media-session.d/ or ~/.config/pipewire/media-session.d/. Then append a new rule-block similar to the following one:

/etc/pipewire/media-session.d/alsa-monitor.conf (or ~/.config/pipewire/media-session.d/alsa-monitor.conf)
...
rules = {
    ...
    {
        matches = [
            {
                node.name = "alsa_output.name-of-node"
            }
        ]
        actions = {
            update-props = {
                audio.format = "S24_3LE"
                audio.rate = 96000
                # Following value should be doubled until audio does not cut out or other issues stop occurring
                api.alsa.period-size = 128
...

alsa_output.name-of-node node can be obtained using pw-top.

Your DAC might support a different format or sample rate. You can check what your DAC supports by querying ALSA:

First get the card number of your DAC:

$ aplay -l
...
card 3: S2 [Schiit Hel 2], device 0: USB Audio [USB Audio]
  Subdevices: 0/1
  Subdevice #0: subdevice #0
...

So in this example it would be card 3. Get all supported sample rates and formats:

$ cat /proc/asound/cardX/streamX
...
Playback:
  ...
  Interface 1
    Altset 1
    Format: S16_LE
    Channels: 2
    Endpoint: 0x05 (5 OUT) (ASYNC)
    Rates: 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000
    Data packet interval: 125 us
    Bits: 16
    ...
  Interface 1
    Altset 2
    Format: S24_3LE
    Channels: 2
    Endpoint: 0x05 (5 OUT) (ASYNC)
    Rates: 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000
    Data packet interval: 125 us
    Bits: 24
    ...
  Interface 1
    Altset 3
    Format: S32_LE
    Channels: 2
    Endpoint: 0x05 (5 OUT) (ASYNC)
    Rates: 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000
    Data packet interval: 125 us
    Bits: 32
    ...
...

In this case S16_LE, S24_3LE, S32_LE are the supported formats and 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000 are the supported sample rates across all formats.

No sound from USB DAC until 30% volume

This article or section needs expansion.

Reason: Add pipewire-media-session instructions. (Discuss in Talk:PipeWire)

Some USB DACs will have no sound output until a certain level of volume is reached [6]. Typically this is around 25% - 30% which then leads to an uncomfortably loud initial volume and the inability to maintain a low volume. The solution is to ignore hardware mixer volume control by setting ["api.alsa.soft-mixer"] to true.

To achieve this with wireplumber, you can add onto the /usr/share/wireplumber/main.lua.d/50-alsa-config.lua configuration by adding a configuration fragment using table.insert:

~/.config/wireplumber/main.lua.d/51-volume-fix.lua
table.insert (alsa_monitor.rules, {
    matches = {
      {
        -- This matches all cards.
        { "device.name", "matches", "alsa_card.*" },
      },
    },
    -- Apply properties on the matched object.
    apply_properties = {
      -- Do not use the hardware mixer for volume control. It
      -- will only use software volume. The mixer is still used
      -- to mute unused paths based on the selected port.
      ["api.alsa.soft-mixer"] = true,
    }
  })

Then, restart pipewire. Set your master volume in alsamixer and then save the settings with # alsactl store. You should now be able to use your volume mixer as normal.

Realtime audio does not work

If RTKit error: org.freedesktop.DBus.Error.AccessDenied shows up in the status of the pipewire.service user unit, then the priority of the pipewire daemon was not changed to realtime. See [7] for this issue.

Simultaneous output to multiple sinks on the same sound card

Create a copy of /usr/share/alsa-card-profile/mixer/profile-sets/default.conf so that changes persist across updates. Here we define a profile joining the two default mappings for Analog and HDMI.

/usr/share/alsa-card-profile/mixer/profile-sets/multiple.conf
[General]
auto-profiles = no

[Mapping analog-stereo]
device-strings = front:%f
channel-map = left,right
paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2
paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headphone-mic analog-input-headset-mic
priority = 15

[Mapping hdmi-stereo]
description = Digital Stereo (HDMI)
device-strings = hdmi:%f
paths-output = hdmi-output-0
channel-map = left,right
priority = 9
direction = output

[Profile multiple]
description = Analog Stereo Duplex + Digital Stereo (HDMI) Output
output-mappings = analog-stereo hdmi-stereo
input-mappings = analog-stereo

Now we configure PipeWire's media-session to use the new card-profile for matching devices. Identifying information can be found using $ pw-cli dump device.

/etc/pipewire/media-session.d/alsa-monitor.conf
rules = [
    {
        matches = [ { alsa.card_name = "HDA Intel PCH" } ]
        actions = {
            update-props = {
                api.alsa.use-acp = true
                device.profile-set = "multiple.conf"
                device.profile = "multiple"
                api.acp.auto-profile = false
                api.acp.auto-port = false
            }
        }
    }
]

No notification sounds from Discord

This might cause by having the min.quantum too low, try setting it to more than 700. You can make an override for Discord specifically by appending the following rule to the pulse.rules section of pipewire-pulse.conf.

/etc/pipewire/pipewire-pulse.conf (or ~/.config/pipewire/pipewire-pulse.conf)
...
pulse.rules = [
  ...
    {
        # Discord notification sounds fix
        matches = [ { application.process.binary = "Discord" } ]
        actions = {
            update-props = {
                pulse.min.quantum      = 1024/48000     # 21ms
            }
        }
    }
...

FMOD games crashing under PipeWire

Some games that use an old version of the FMOD audio engine, like Pillars of Eternity, invoke pulseaudio --check and crash if the PulseAudio binary is not present. A workaround is to symlink /bin/pulseaudio to /bin/true.[8]

# ln -s /bin/true /bin/pulseaudio

Note that if you wish to reinstall PulseAudio, you need to remove the symlink.

Auto-switching is not working

If auto-switching is not working it may be an issue with WirePlumber state. As suggested by this comment you can delete WirePlumber's local state and restart the daemon to see if that helps:

$ rm -r ~/.local/state/wireplumber/

Then restart the wireplumber.service user unit.

Missing realtime priority/crackling under load after suspend

Due to a bug from 2011 in rtkit, suspend events cause PipeWire's realtime priority to be revoked and not restored. To disable the protection which causes this, edit rtkit-daemon.service:

/etc/systemd/system/rtkit-daemon.service.d/override.conf
[Service]
ExecStart=
ExecStart=/usr/lib/rtkit-daemon --no-canary

Then restart the rtkit-daemon.service unit and pipewire.service user unit, along with the media session service.

No sound during streaming to RAOP devices (Sonos etc.)

Set up mDNS hostname resolution using either Avahi or systemd-resolved.

Video

OBS (etc.) display nothing, even if they ask for a window/screen

If you are sure that you have xdg-desktop-portal installed as well as either xdg-desktop-portal-gtk or xdg-desktop-portal-kde, check the running state of the daemons.

In OBS, if everything is working, you should see this in stdout:

...
info: [pipewire] desktop selected, setting up screencast
info: [pipewire] created stream 0x5632d7456850
info: [pipewire] playing stream…

For multi-monitor setups the slurp package will allow to capture of all the screens.

See also