Moving from Jack+Pulseaudio to Pipewire

Updated at by

My previous setup involved using pulseaudio server with jack. Qjackctl was used to launch jackdbus and Carla hosted a few plugins and provided graph editing. Desktop apps, games used pulseaudio and music software like Ardour and ToanLib-GFX used jack. Jack worked with a overall roundtrip latency of 6ms measured with jack_iodelay.

Setting up

Fedora Core 39 came preinstalled with pulseaudio and wireplumber. Here's my Behringer UMC204HD along with a HDMI and webcam.

$ wp-ctl status
...
Audio
 ├─ Devices:
 │      37. UMC204HD 192k                       [alsa]
 │      56. TU106 High Definition Audio Controller [alsa]
 │     198. Logitech Webcam C925e               [alsa]

Disable devices

I don't use webcam or the HDMI output so they just clutter the audio graph in qpwgraph.

Wireplumber piles up it's configuration from /usr/share/wireplumber + /etc/wireplumber + ~/.config/wireplumber. Alsa default configuration lands on /usr/share/wireplumber/main.lua.d/50-alsa-config.lua, so I'll disable the devices in number 51.

Get the device name with wpctl

$ wpctl inspect 56|grep device.name
* device.name = "alsa_card.pci-0000_01_00.1"

Append alsa_monitor.rules in ~/.config/wireplumber/main.lua.d/51-disaa-paskaa.lua

table.insert(alsa_monitor.rules,  
  { matches = { { { "device.name", "equals", "alsa_card.pci-0000_01_00.1" } } },
  apply_properties = { ["device.disabled"] = true } } )

Restart wireplumber systemctl --user restart wireplumber and puff.

48kHz everything, Pipewire

As most of my samples, Ardour projects and good chunk of external sources have 48kHz sample rate and I wan't to prevent resampling whenever possible... and between drafting this post the 44.1kHz was dropped from pipewire default allowed rates. Nice :-]

Jack clients 48kHz and latency.

Extend jack configuration, force rates in ~/.config/pipewire/jack.conf.d/jack.conf

jack.properties = {
  node.latency       = 128/48000
  node.rate          = 1/48000
  node.quantum       = 128/48000
  node.lock-quantum  = true
  node.force-quantum = 128
}

Pro-Audio profile, stereo vs. 4 channel

ALSA UCM profile for Behringer UMC204HD in default configuration split output nicely into 2 nodes with 2 channels which I could control easily by switching default-sink from monitors to headphones. For some reason using the UCM profile also prevented pipewire from setting buffer lower than 480. gitlab.freedesktop.org : Alsa-lib changes period size 480.

Also without pro-audio profile, after a resync happened there was a chance that output nodes were reconfigured with huge period-size/period-num which ment a 500ms delay was introduced to all outputs.

spa.alsa: umc204hd_stereo_out:U192k,0,2,3: follower avail:466 delay:466 target:544 thr:64, resync (0 suppressed)

After enabling pro-audio profile, interface presents itself as a single 4 channel output node. With the default audio positions [FL FR RL RR] => [AUX0 AUX1 AUX3 AUX4], games with multichannel audio would blast FL FR from my monitors and RL RR channels via headphones :-]

Enabled pro-audio profile and set period-size, period-num in ~/.config/wireplumber/main.lua.d/52-alsa-bufferit.lua

table.insert(alsa_monitor.rules, { 
    matches = { { { "device.name", "equals", "alsa_card.usb-BEHRINGER_UMC204HD_192k-00" } } },
    apply_properties = { 
      ["api.alsa.period-size"] = 128,
      ["api.alsa.period-num"] = 2,
      ["device.profile"] = "pro-audio",
    } 
})

Tinkering with pipewire loopback device

For pulseaudio/pipewire clients I created a nice stereo default-sink with a loopback device in ~/.config/pipewire/pipewire.conf.d/loopback.conf

context.modules = [
  { name = libpipewire-module-loopback
    args = {
      node.name = "benkku"
      capture.props = {
        media.class = "Audio/Sink"
        audio.position = [ FL FR ]
      }
      playback.props = {
        audio.position = [ FL FR ]
        stream.dont-remix = true
        node.passive = true
        node.autoconnect = false
      }
    }
  }
]

From my window manager I call shell script which uses pw-link to remove or add links from the loopback to desired output. Eg.

$ wire hon    # connect loopback to headphone output
pw-link output.benkku:output_FL alsa_output.usb-BEHRINGER_UMC204HD_192k-00.pro-output-0:playback_AUX2 2> /dev/null
pw-link output.benkku:output_FR alsa_output.usb-BEHRINGER_UMC204HD_192k-00.pro-output-0:playback_AUX3 2> /dev/null

$ wire aoff   # disconnects all loopback<->output links
pw-link -d output.benkku:output_FL alsa_output.usb-BEHRINGER_UMC204HD_192k-00.pro-output-0:playback_AUX0 2> /dev/null
# repeated 3 more times for each combo

Random stuff

How to see which rate alsa driver is currently using? My USB interface has U192k symlink in the /proc/asound path.

$ cat /proc/asound/U192k/*/*/hw_params
...
rate: 48000 (48000/1)
period_size: 1024

These might differ from the ones reported by pw-top

$ pw-top -b
...
R   53   1024  48000  18.3us   0.2us  0.00  0.00    0    S32LE 2 48000 alsa_input.usb-BEHRINGER_UMC204HD_192k-00.pro-input-0
R   55      0      0   7.2us   4.4us  0.00  0.00    0    S32LE 4 48000  + alsa_output.usb-BEHRINGER_UMC204HD_192k-00.pro-output-0

Or ones reported by wpctl inspect <nodeId>

$ wpctl inspect 55
...
api.alsa.period-num = "32"
api.alsa.period-size = "1024"

Leave a comment