How to Configure Audio Device Priorities in Pipewire / Wireplumber

Posted by Scott on Aug 1st, 2022

I have several audio devices connected to my Linux desktop machine, including a USB audio interface (a MOTU M4), and a Jabra wireless headset that uses a USB dongle, and appears as its own audio device. I also like to use Bluetooth headphones on a daily basis.

After switching to Pipewire as my audio backend, I found that my default audio device wasn’t switching automatically to what I wanted – I’d always have to set it manually. I’d need to do this when my BT headphones would connect (select the a2dp headphone profile), and then again when I disconnected them (because I wanted to hear sound from my MOTU audio interface, but it would automatically fallback to the Jabra headset device). This is a two-part recipe to fix these issues.

Step 1: Make pipewire automatically select my Bluetooth headphones sink when they connected. This didn’t require any configuration changes. Instead, I have a script which runs on startup of my desktop environment which runs pactl load-module module-switch-on-connect. This is actually a pulseaudio command, but desktop apps still use the pulseaudio interface, which pipewire implements as part of the pipewire-pulse package.

Step 2: Make my default audio device my MOTU M4 audio interface, and stop selecting the Jabra headset device when I disconnect my BT headphones. This turned out to be caused by the fact that the Jabra audio device had a higher priority than my audio interface. Run the command wpctl status to show a list of your audio devices, and make a note of the device number. In this case, I was looking for the M4 device in my list of Audio Sinks. Then you can run wpctl inspect <device-number> to show the details of this audio device. What you’re looking for are the fields priority.driver and priority.session. Larger numbers correspond to a higher priority, but for sinks, they should be kept no larger than 1500 (otherwise a sink’s monitor could end up being selected as a default source – this is called out in the Wireplumber documentation). In my case, the Jabra sink had a priority of 1008, so I chose to set my audio interface to a priority of 1050.

Update May 2024: Wireplumber as of v0.5 no longer uses lua scripts for configuration. Check which version of wireplumber you’re using, and if you’re on 0.5, please refer to this guide to update the lua script below to the new format (and file location). I’ll update this blog post further when I have the time.

To change this configuration, you’d do so in Pipewire’s session manager. The preferred session manager for Pipewire is Wireplumber, which uses lua scripts to apply these kinds of custom configurations. So in my case, I created the file ~/.config/wireplumber/main.lua.d/60-raise-motu-m4-priority.lua with the following code:

rule = {
  matches = {
    {
      { "node.name", "equals", "alsa_output.usb-MOTU_M4_M4MC0570FU-00.Direct__hw_M4__sink" },
    },
  },
  apply_properties = {
    ["priority.driver"] = 1050,
    ["priority.session"] = 1050,
  },
}

table.insert(alsa_monitor.rules,rule)

Then, restart the wireplumber service with systemctl --user restart wireplumber and compare the new output from wpctl inspect. You should now see that the driver and session priorities are what you set them to. And when pipewire automatically switches to a new audio device, the highest priority device should be chosen.

I’ve found Pipewire and Wireplumber’s documentation to be confusing, and there are lots of dead-ends you can go down when researching how to do this. I hope this recipe-style blog post is easier to understand if this is the problem you’re trying to solve.

Many thanks to PleasantlyFlailing on the r/linuxaudio subreddit for suggesting some improvements to this blog post!

How to Disable Audio Devices in Pipewire / Wireplumber

Posted by Scott on Aug 1st, 2022

I’ve recently made the switch to using Pipewire on my Linux desktops. One thing I noticed in my list of audio devices was an entry for my HDMI monitor, which I never planned to use. I also do some music production on my Linux machines, and disabling this audio device would help my patchbay configurations look a bit cleaner.

Pipewire’s documentation is pretty basic, and when searching for this solution online, I went down several incorrect paths. We could really use more recipe-style examples on the web, so here’s mine. This is done using the Wireplumber session manager.

First, identify the audio device to disable using pactl list short. In the output from this, I could see an entry for the audio sink (alsa_output.pci-0000_27_00.1.hdmi-stereo-extra2.monitor) and for the audio device (alsa_card.pci-0000_27_00.1). It’s the alsa_card device that you want to disable, not the sink.

Update September 2024: Wireplumber as of v0.5 completely changed their configuration format from lua to json, and won’t automatically migrate your configuration. Before proceeding, check which version of Wireplumber you have installed.

For Wireplumber < 0.5, the configuration format is lua scripts. For this example, I created the file ~/.config/wireplumber/main.lua.d/51-disable-hdmi-devices.lua with the following code:

rule = {
  matches = {
    {
      { "device.name", "equals", "alsa_card.pci-0000_27_00.1" },
    },
  },
  apply_properties = {
    ["device.disabled"] = true,
  },
}

table.insert(alsa_monitor.rules,rule)

For Wireplumber 0.5 and later, the configuration format is json. For this example, I created the file ~/.config/wireplumber/wireplumber.conf.d/51-disable-hdmi-devices.conf with the following code:

monitor.alsa.rules = [
  {
    matches = [
      {
        device.name = "alsa_card.pci-0000_03_00.1"
      }
    ]
    actions = {
      update-props = {
        device.disabled = true
      }
    }
  }
]

Then, restart the wireplumber service with systemctl --user restart wireplumber and this audio device should now be gone – you won’t see it in your sound settings or in your patchbay diagrams.

On more than one occasion, I’ve found that the device names have changed after a major update – I’m not sure if this is due to a kernel change or a change in pipewire/wireplumber. But if things suddenly stop working and you’re seeing devices you thought you had disabled, go back to running pactl list short and see if your device name has changed.

For reference, I’m using pipewire and wireplumber on Manjaro Linux, which is a rolling release distro and tends to stay pretty close to the upstream software releases. I ultimately learned how to do this via the Arch Wiki page for Wireplumber, though at first I got confused about the need to specify an audio device instead of a sink. That caused me to think this was the wrong solution, and I spun my wheels for more than a week trying other things (e.g, turning the device profile off in pavucontrol) which didn’t work. Another handy reference for the wireplumber 0.5 config change update is this migration guide. Best of luck with your audio configuration journey!

Configuring the GNOME Shell Panel with Firefox and Thunderbird Profiles

Posted by Scott on Apr 2nd, 2020

Mozilla’s Firefox web browser and Thunderbird e-mail clients have a little-known feature known as “Profiles.” Profiles allow you to create fully separate instances of these applications, each with their own customized config preferences and extensions.

I make heavy use of this feature to create separate Firefox profiles for my personal everyday web browser, work web browser, web development browser, etc. With Thunderbird, I use profiles to separate my personal vs. work email.

From the command line, invoking firefox or thunderbird with the -P option will bring up a dialog box, allowing you to chose between your existing profiles, or create/rename/delete profiles:

If you haven’t created any new profiles, you’ll be using a profile named default. On my Ubuntu systems, each of these profiles will be stored under your ~/.mozilla/firefox/ directory (for Firefox) or ~/.thunderbird/ directory (for Thunderbird).

If you want to be able to easily launch these profiles from the GNOME Shell GUI rather than the command line, you can create custom launchers for each profile. I typically do this and choose different icons for each profile to visually tell them apart. To do this, create a .desktop file within your ~/.local/share/applications/ directory. I typically name these files firefox-<profile-name>.desktop. Here’s an example of one:

[Desktop Entry]
Version=1.0
Name=Firefox (WebDev)
Exec=firefox -P webdev -no-remote --class FirefoxWebDev
Comment=firefox
Terminal=false
Icon=/usr/share/icons/oxygen/base/128x128/categories/applications-development-web.png
Type=Application
StartupWMClass=FirefoxWebDev

By default, the Icon setting will search for an icon file (e.g, .svg or .png file) from your current theme within your /usr/share/icons/ directory. Specify an absolute path to the icon file and include its filename extension if you want to use an icon that’s not in your current theme. You can also create custom icons and drop them in your ~/.local/share/icons/ directory.

Note that on the Exec line I’m also starting firefox with two additional options, -no-remote and --class. The -no-remote option prevents conflicts with other instances of Firefox that are running. The --class option specifies a window manager class, which you’ll also set for the StartupWMClass option. You can set this value to any string you like, but it must be unique (i.e, don’t re-use it in another .desktop launcher config).

If you don’t set a custom window manager class, all of your running profiles will be grouped together under the same icon in the GNOME Shell panel. That last subtlety has been an annoyance I’ve wanted to fix for a long time, and learning about it is what prompted me to write this post to share.

References: Mozilla docs on using the profile manager, AskUbuntu post on setting the window manager class

Dealing with the Great Firewall of China – October 2016 Notes

Posted by Scott on Nov 5th, 2016

Last month I visited Beijing, China and had to work remotely during my trip. At work we rely on a number of Google services, so I needed a reliable way to circumvent the Great Firewall of China (GFW). After doing a decent amount of research, I learned that just running a SOCKS proxy via SSH is likely to run into problems, so I used a couple of commercial VPNs, as well as a private Shadowsocks server I had set up on various ports of a Digital Ocean droplet. The idea being to have a couple of fall-back methods to tunnel through the GFW in case my primary one stopped working. I thought it might be useful to report on what worked well, and what was most challenging about this.

Given that I’m a Linux user and needed solutions that were Linux-friendly, I settled on two highly recommended commercial VPNs – ExpressVPN and Astrill. I also sprung for the added “VIP” add-on to Astrill that gives you access to a few additional VPN endpoints that presumably have lower utilization. In summary, Astrill was the clear winner, especially with the VIP add-on. Though no matter which VPN service I was using, there was a lot of fiddling that had to be done to test the latency of different proxy endpoints. There wasn’t one I could just set and forget.

Finding usable wifi in Beijing is another story, and proved to be a frustrating problem. My local resident friend told me that the Chinese tend to use the internet for recreation rather than getting work done, so the vast majority of folks packed in coffee shops are streaming video to watch movies or TV shows. My own observations backed this up, and it was easy to notice this, as a sizable proportion of these folks don’t bother to use headphones when watching their entertainment (grumble). So I found the only times I had really solid wifi speeds were when I found a coffee shop that was mostly empty, and probably half the time I gave up on the wifi and just tethered to my phone’s data connection. For most of my work I was running remote builds over SSH, and I found my phone’s data connection was laggy in a more consistent way than when I tried to use wifi in a busy cafe.

Regarding SIM cards in China, I have some tips to share as well. I ended up buying a prepaid China Unicom SIM with 2 GB of data from Amazon before I left for my trip, which was incredibly convenient. The way this works is you buy the SIM online, they send it to you, and you have to activate it over email with the seller. Once the SIM is activated, the 90-day lifetime of the SIM doesn’t start until you actually begin to use it, so you can complete the activation well before your trip and then pop the SIM card into your phone once you land in China. I have no complaints about dealing with the seller LvyCom on Amazon and would definitely recommend them.

So how was ExpressVPN? Decent and reliable, but not especially fast. I found it helped significantly to change the connection type from “auto” to “udp”, but Astrill’s Openweb connection type still beat it when it came to speeds. But to set expectations – generally the speeds were still slow. My friend had an 80 Mbit home internet connection which I tested without the VPN enabled, but once I enabled a VPN, the best I could get from it was around 3-5 Mbit. This was generally only good enough to watch YouTube videos at 480p. My friend was quite surprised when I told him I always watch YouTube at home at 1080p resolution with no hiccups or delays.

Shadowsocks turned out to be the least reliable method of tunneling out of China, sometimes working well and sometimes not working at all. Since it’s a lot of extra effort to set up a Shadowsocks server compared to just using a commercial VPN, I don’t think it’s necessary unless you want to have that extra peace of mind.

Overall I was able to get work done while in China, but it was regularly a frustrating experience to deal with the lack of bandwidth and annoying latency on SSH terminal sessions. Oh, and bring good headphones if you plan to try to work from coffee shops!

Photos from my recent trip to Beijing can be found here. For news about the GFW and VPNs, I recommend greatfire.org.

Setting up the LIVA Mini PC (BayTrail Atom) as a Headless Server with Ubuntu Xenial 16.04

Posted by Scott on Apr 26th, 2016

A while back I had picked up a neat little fanless Intel Atom computer based on the BayTrail N2807 CPU. It’s a dual-core system running at 1.6 GHz and has 2 GB of RAM and onboard flash disk, and seemed ideal as a micro server for my home LAN.

The device turned out to be a bit flaky to set up, so I thought I’d share my installation notes here. There are multiple revisions of this mini PC, and I believe I have one of the first versions. The case looks like this:

LIVA Mini PC

LIVA Mini PC

First, I created a USB flash drive with the Ubuntu 16.04 server install image using Ubuntu’s Startup Disk Creator app. Then, plug in an HDMI monitor and wired keyboard to the Liva. Hit F7 when the BIOS screen comes up and select the flash drive to start the installer.

The main issue I ran into was during the disk partitioning step. If I chose one of the guided partitioning options, the process wouldn’t complete, and raised an error about “Identical mount points for two file systems” on the flash storage.

After several unsuccessful attempts to try other options, I found a solution that worked. First, choose manual partitioning mode. Select the entire disk, and create a new partition table. Then select the free space and have it create partitions automatically. At this point I could save these changes and have the installer proceed past the partitioning step.

Everything else in the installer is pretty straightforward. Once I had everything set up the way I wanted, I disconnected the monitor and keyboard and intended to use the system as a headless server. However, the system refused to boot without a monitor attached. I tried several modifications to my GRUB bootloader command line to try to work around this, but had no luck. If someone knows the customization to make here, please let me know and I’ll update this post with the info.

Instead, I chose the lazy option. You can buy “dummy” HDMI connectors that emulate a monitor – for example here’s one that you can use.

Once I connected that to my Liva Mini PC, it was able to boot up headless and the device is now usable to me again.

I hope this information might be useful to others trying to make use of this handy mini PC system.

Embedded Linux Conference Europe and our Second Yocto Project Developer Day

Posted by Scott on Oct 25th, 2012

In early November I’ll be in Barcelona for the European Embedded Linux Conference. Once again, I’ll also be involved with running another Yocto Project Developer Day on Nov. 8, the day after ELC-E officially ends.

The intro level hands-on lab class I’ll be teaching has been reworked considerably based on feedback I received from the first event we did in February, to allow for more independent learning/exercises. And as before, we’ll have some hands-on labs for experienced Yocto Project developers as well in addition to a panel discussion.

I’m really excited to help people get started using our build system, and to meet our OpenEmbedded contributors from across the pond. Don’t be a stranger!

Screencast Video for New Yocto Developers

Posted by Scott on Feb 20th, 2012

After teaching a very successful Yocto Project hands-on lab at the Intel Developer Forum last September, I learned that there was a lot of demand for training resources along these lines. Rather than having me fly out to various Intel sites to teach these courses, I decided it would be better to develop some hands-on labs in video format, so we’d have some “scalable” training materials to meet the demand.

The first screencast video was publicly released last week at the Embedded Linux Conference in Redwood City, CA. It’s a half-hour long and combines some introductory theory with hands-on exercises you can follow along with.

Getting Started with the Yocto Project – New Developer Screencast Tutorial from Yocto Project on Vimeo.

Note: You’ll probably want to view the video in full-screen mode when viewing the more detailed slides and during the live demos. You can also directly download the video in Windows Media format (300 MB) or Ogg Theora format (500 MB).

Topics covered include:

  • An overview of the Poky build system
  • How the Poky sources are organized (types of metadata and where to find them)
  • How to build your first Linux image and run it under emulation
  • An introduction to recipes and an explanation of the most common types of metadata, using actual recipe examples
  • An introduction to layers
  • Where to obtain Yocto BSPs from
  • How simple it is to download and enable a Yocto BSP
  • Where to find further project resources (documentation, mailing lists, git repository, bugzilla)


By the end of this screencast, a new user will understand fundamental concepts about the build system, and be able to start their exploration of the Yocto Project with a solid foundation of knowledge.

Quite honestly, creating this screencast was pretty agonizing, as the video editing tools Linux offers are either horribly complicated or extremely unstable. Perhaps at some point I’ll write up everything I learned about screencasting and give a talk for PLUG. 🙂

This won’t be the last screencast, but I can’t promise a timetable for the next one just yet.

Embedded Linux Conference and Yocto Developer Day

Posted by Scott on Feb 12th, 2012

I’ll be in Redwood City, CA next week for the Linux Foundation’s Embedded Linux Conference. Additionally, I’ll be helping to run the Yocto Developer Day on Tuesday, Feb. 14th.

We’ve got a full day of presentations and hands-on labs geared toward embedded Linux development with Yocto, both for new users as well as more experienced folks. I’ll be teaching the intro hands-on lab with Jessica Zhang, as well as presenting Techniques for Troubleshooting Common Build Errors in the intermedite developer track.

Most of all, I’m really looking forward to meeting members of the OpenEmbedded and Yocto community in person. So please say hello if you’ll be at either of these events!

Next »

Blog Badges



[FSF Associate Member]

Archives