Grumpy middle-aged software developer who found a home in Sofia, Bulgaria.
Tech notes, hand-drawn arts and city photos.

How to change audio outputs in Linux / PulseAudio with a shell script / command line

If you want to have a shell script which does quick switching between your audio inputs / outputs. Useful for creating hotkeys, panel shortcuts etc.

Why?
Investigation story
The script to switch audio outputs

Why?

I have two audio cards, the internal one is connected to a high quality speaker for listening music, the external USB one is connected to a headset. Don't ask why :) it has it's reasons. What I wanted is to quickly switch between them.

Sure KDE offers a widget for doing that, as well as PulseAudio (which works under PipeWire now) offers pavucontrol, but they require several clicks – open the widget / application, find a device, change profile etc. I wanted one-click solution.

Investigation story

Then there is the pactl command line utility for managing PulseAudio.

man pactl or pactl --help reveals a bunch of commands. There is the list command which probably detects which audio outputs I have?

pactl list returns a ton of data to me.

pactl list short still too much.

pactl list short cards seems to be what I need.

$ pactl list short cards
704     alsa_card.pci-0000_07_00.1      alsa
705     alsa_card.pci-0000_07_00.6      alsa
3075    alsa_card.usb-046d_C270_HD_WEBCAM_200901010001-02       alsa
3110    alsa_card.usb-GeneralPlus_USB_Audio_Device-00   alsa
3111    alsa_card.usb-Sony_Interactive_Entertainment_Wireless_Controller-00     alsa

Well, now I know how PulseAudio sees my audio equipment. Can I manage it?

Checking the list of commands yet another time, I found set-card-profile command. That might be the one. I could try it, but it wants card id and profile name.

Digging into the long list of data returned by pactl list, I found both.

$ pactl list
...
Card #705
Name: alsa_card.pci-0000_07_00.6
...
device.product.name = "Family 17h (Models 10h-1fh) HD Audio Controller"
...
Profiles:
off: Off (sinks: 0, sources: 0, priority: 0, available: yes)
output:analog-stereo+input:analog-stereo: Analog Stereo Duplex (sinks: 1, sources: 1, priority: 6565, available: no)
output:analog-stereo: Analog Stereo Output (sinks: 1, sources: 0, priority: 6500, available: yes)
output:iec958-stereo+input:analog-stereo: Digital Stereo (IEC958) Output + Analog Stereo Input (sinks: 1, sources: 1, priority: 5565, available: no)
output:iec958-stereo: Digital Stereo (IEC958) Output (sinks: 1, sources: 0, priority: 5500, available: yes)
input:analog-stereo: Analog Stereo Input (sinks: 0, sources: 1, priority: 65, available: no)
pro-audio: Pro Audio (sinks: 2, sources: 2, priority: 1, available: yes)
...
Card #3110
Name: alsa_card.usb-GeneralPlus_USB_Audio_Device-00
...
device.product.name = "USB Audio Device"
...
Profiles:
off: Off (sinks: 0, sources: 0, priority: 0, available: yes)
output:analog-stereo+input:mono-fallback: Analog Stereo Output + Mono Input (sinks: 1, sources: 1, priority:6501, available: yes)
output:analog-stereo: Analog Stereo Output (sinks: 1, sources: 0, priority: 6500, available: yes)
output:iec958-stereo+input:mono-fallback: Digital Stereo (IEC958) Output + Mono Input (sinks: 1, sources: 1,priority: 5501, available: yes)
output:iec958-stereo: Digital Stereo (IEC958) Output (sinks: 1, sources: 0, priority: 5500, available: yes)
pro-audio: Pro Audio (sinks: 1, sources: 1, priority: 1, available: yes)
input:mono-fallback: Mono Input (sinks: 0, sources: 1, priority: 1, available: yes)
available: yes)
pro-audio: Pro Audio (sinks: 1, sources: 1, priority: 1, available: yes)
input:mono-fallback: Mono Input (sinks: 0, sources: 1, priority: 1, available: yes)
...

The script to switch audio outputs

#!/usr/bin/env bash

card_name=$1
case $card_name in
	headset)
		card_code=$(pactl list cards short | grep alsa_card.usb-GeneralPlus_USB_Audio_Device-00 | cut -f 1)
		card_profile=output:analog-stereo+input:mono-fallback
		;;
	internal)
		card_code=$(pactl list cards short | grep alsa_card.pci-0000_07_00.6 | cut -f 1)
		card_profile=output:analog-stereo
		;;
	*)
		echo "Please specify \"internal\" or \"headset\""
		exit 1
esac


cards=$(pactl list cards short | cut -f 1)
for card in $cards; do
	pactl set-card-profile $card off
done

pactl set-card-profile $card_code $card_profile

Enjoy :)

#tech #linux #shellscript #shellscripting #audio #pulseaudio #pipewire