Customizing my system: pinning PulseAudio's default sink

My MSI monitor kept stealing the audio output every time it woke up. Three lines of PulseAudio config and a MATE autostart entry made it stop. The trail through pactl, switch-on-port-available, and a fresh dotfiles repo.

I work with headphones plugged into my laptop and two external monitors with built-in speakers I never use. AOC on the left, MSI on the right. The music plays into the headphones. Then I take a break, the monitors fall asleep, I move the mouse, the monitors come back, and the music is now blasting out of the MSI's tinny speakers. Every single time.

This is the story of why that happens, and the three lines of PulseAudio config that made it stop.

The symptom

Ubuntu 22.04 with MATE, an AMD Ryzen laptop, one HDMI to the MSI and one USB-C DisplayLink adapter to the AOC. The audio server is PulseAudio, not PipeWire, even though PipeWire is also running for screen capture. The default sink is the laptop analog output (headphones). Everything is fine until DPMS kicks in.

When the MSI sleeps, its HDMI sink reports as unavailable. When it wakes back up, the sink reports available again. PulseAudio sees this and decides the user must want to use the new shiny output, so it switches the default sink to the MSI. The music stream, having no preference of its own, follows the default. The headphones go quiet.

The diagnosis

Two PulseAudio modules are guilty:

$ pactl list short modules | grep switch-on
4    module-switch-on-port-available
5    module-switch-on-connect

The first one reassigns the default sink whenever a port flips to available. The second one does the same when a brand new sink appears. Port-available is what fires on every monitor wake. Switch-on-connect is why the AOC stole the default the first time it was plugged in.

The fix is to unload both. The cleanest way is a per-user override, so the system config stays untouched and the change is reversible by deleting one file.

The fix

Three lines in a personal override at ~/.config/pulse/default.pa:

.include /etc/pulse/default.pa

.ifexists module-switch-on-port-available.so
unload-module module-switch-on-port-available
.endif

.ifexists module-switch-on-connect.so
unload-module module-switch-on-connect
.endif

The include at the top sources the system file first; the unloads happen at the end. Restart PulseAudio with pulseaudio -k and the modules are gone. Toggle the HDMI card off and on with pactl set-card-profile to simulate a monitor sleep cycle, watch pactl get-default-sink stay on the headphones, and the original problem is over.

There is one leftover. With those two switch modules removed, PulseAudio picks the first sink that loads as the default on startup. On this laptop the DisplayLink USB sink usually wins the race against the PCI analog, so after a fresh login the AOC ends up default instead of the headphones. A MATE autostart entry fixes it:

[Desktop Entry]
Type=Application
Name=fer-default-sink
Exec=sh -c 'sleep 6 && pactl set-default-sink alsa_output.pci-0000_05_00.6.analog-stereo'
X-MATE-Autostart-enabled=true
NoDisplay=true

The six-second sleep is the cheap fix for the race: by the time the desktop is fully up, every sink has loaded and pactl just picks the one I actually want.

Where this lives now

Two files on a workstation, two symlinks, and a habit of losing them every time I reinstall. The honest answer was a new private repo, fer-system-settings, with one directory per machine. The live files in the user config tree are symlinks pointing into the repo. Tracking system tweaks in git is older than I am, but I had not had a clean home for them until I needed one badly enough.

The repo is small on purpose. No installer, no chezmoi, no GNU stow, just files, paired with a comment at the top of each one explaining why it exists. The why is the part that decays first if you do not write it down.

What I keep from this

PulseAudio's automatic switching is a sensible default for laptops with one user and one output. The minute you add a USB display, an HDMI monitor with speakers, and a Bluetooth headset, automatic stops being the same word as correct. Unloading the two switch modules and pinning the default explicitly is the lowest-friction way to take the choice back.

A configuration file with no comment is a future mystery. The header in default.pa says exactly which monitor was misbehaving and why. Six months from now I will not remember either.

A system-settings repo is worth starting before you think you need it. Mine had one file on day one and that was enough. The structure is already there for the next tweak, and the next.

May 20, 2026 - written from a laptop with three sinks loaded and exactly the right one selected.

What is Agentic AI? A reading list from the trenches
From chatbots that answer to systems that act. The sources that taught me what an agent really is, and how we use them every day at LTC.