I like to switch the sound output from Speaker to USB headphone with a Shortcut. Is there a way to accomplish this?
-
1Closely related: http://askubuntu.com/questions/41858/shortcut-to-switch-between-analog-stereo-output-hdmi-audio-output – Takkat Jun 28 '12 at 06:16
8 Answers
Automated solution https://ubuntuforums.org/showthread.php?t=1370383 It works on Ubuntu 18.04
Open the terminal and type:
sudoedit /usr/local/bin/audio-device-switch.sh
Copy and paste the below code in nano editor
Save it and close nano editor.
sudo chmod 755 /usr/local/bin/audio-device-switch.sh
System -> Preferences -> Keyboard Shortcuts
Press Add and enter Switch between audio devices as name and audio-device-switch.sh as command and press Apply.
Select the newly added shortcut row and click on the shortcut column. 8. Choose a shortcut combination – e.g. Win + F12.
That's all - now you can plug in your plug in your HDMI device and switch the audio output by pressing the chosen shortcut combination.
Code:
#!/bin/bash
declare -i sinks_count=pacmd list-sinks | grep -c index:[[:space:]][[:digit:]]
declare -i active_sink_index=pacmd list-sinks | sed -n -e 's/\*[[:space:]]index:[[:space:]]\([[:digit:]]\)/\1/p'
declare -i major_sink_index=$sinks_count-1
declare -i next_sink_index=0
if [ $active_sink_index -ne $major_sink_index ] ; then
next_sink_index=active_sink_index+1
fi
#change the default sink
pacmd "set-default-sink ${next_sink_index}"
#move all inputs to the new sink
for app in $(pacmd list-sink-inputs | sed -n -e 's/index:[[:space:]]([[:digit:]])/\1/p');
do
pacmd "move-sink-input $app $next_sink_index"
done
#display notification
declare -i ndx=0
pacmd list-sinks | sed -n -e 's/device.description[[:space:]]=[[:space:]]"(.*)"/\1/p' | while read line;
do
if [ $next_sink_index -eq $ndx ] ; then
notify-send -i notification-audio-volume-high "Sound output switched to" "$line"
exit
fi
done

- 181
-
great work! don't try to run the script as root (e.g. with sudo), it will not work. just run as normal user – sotix Nov 30 '20 at 16:44
-
I had to fix the last if and do to match the bash syntax. The script works perfectly!. – Gor Stepanyan Dec 22 '20 at 14:39
-
I just realized, that the indices of sinks are not necessarily counted from 0 to COUNT-1, so you have to get list of indices and then move to the next one from the list – fairtrax Jan 02 '21 at 09:53
Check for port names
pactl list sinks
(I remove non needed sinks output):Sink #1 State: RUNNING Name: alsa_output.pci-0000_00_1b.0.analog-stereo Description: Built-in Audio Analog Stereo Driver: module-alsa-card.c ... Ports: analog-output-speaker: Speakers (priority: 10000, not available) analog-output-headphones: Headphones (priority: 9000, available) Active Port: analog-output-headphones Formats: pcm
Set sink port using
pactl set-sink-port
:pactl set-sink-port 1 analog-output-speaker
or
pactl set-sink-port 1 analog-output-headphones
If you are using a removable device (Example: USB devices), it's better to use sink
name
instead ofid
. For example:pactl set-sink-port alsa_output.pci-0000_00_1b.0.analog-stereo analog-output-headphones
Reference: man pactl

- 48,105
-
1
-
1Come'n :) you were still waiting, I just fill it in case someone need it come by. – user.dz Feb 15 '14 at 20:00
-
Really. I haven't found a solution for that. But i stopped trying to find one a long time ago. – Evenbit GmbH Feb 15 '14 at 20:04
-
1
Since everyone's been adding their solutions, here's mine.
#!/bin/sh
currentline=$(pactl list short sinks | grep -n "$(pactl get-default-sink)" | cut -d: -f 1)
lastline=$(pactl list short sinks | wc -l)
nextline=$(($currentline % $lastline + 1))
nextsink=$(pactl list short sinks | head "-n$nextline" | tail -1 | cut -f 1)
pactl set-default-sink $nextsink
for sinkinput in $(pactl list short sink-inputs | cut -f 1); do
pactl move-sink-input $sinkinput "@DEFAULT_SINK@"
done

- 200
I have Ubuntu 20, and realized, that the indices of devices are not counted from 0 to COUNT-1. So I had to modify the script. This one works now:
#!/bin/bash
declare -i sinks_count=pacmd list-sinks | grep -c index:[[:space:]][[:digit:]]
if [ $sinks_count -eq 0 ] ; then
exit
fi
declare -i active_sink_index=pacmd list-sinks | sed -n -e 's/\*[[:space:]]index: [[:space:]]\([[:digit:]]\)/\1/p'
active_index_position_found=0
let next_sink_index=-1
while read index ;
do
declare -i ind=($(echo $index | tr -dc '[0-9]+'))
if [ $next_sink_index -lt 0 ] ; then
export next_sink_index=$ind
fi
if [ $active_index_position_found -eq 1 ] ; then
export next_sink_index=$ind
break;
fi
if [ $active_sink_index -eq $ind ] ; then
export active_index_position_found=1
fi
done < <(pacmd list-sinks | grep index:[[:space:]][[:digit:]])
#change the default sink
pacmd "set-default-sink ${next_sink_index}"
#move all inputs to the new sink
for app in $(pacmd list-sink-inputs | sed -n -e 's/index:[[:space:]]([[:digit:]] )/\1/p');
do
pacmd "move-sink-input $app $next_sink_index"
done
#display notification
declare -i ndx=0
pacmd list-sinks | sed -n -e 's/device.description[[:space:]]=[[:space:]]"(.*)" /\1/p' | while read line;
do
if [ $next_sink_index -eq $ndx ] ; then
notify-send -i notification-audio-volume-high "Sound output switched to" "$line"
exit
fi
ndx+=1
done;

- 111
-
This still didn't work for me. I got the following error when I tried to run the script.
Sink 2945029504090482540 does not exist
– Heisenberg Sep 20 '21 at 13:52
It was not working with two digit indices. In my case Nvidia HDMI sink was with index 23. Here is a working solution :)
#!/bin/bash
declare -i sinks_count=pacmd list-sinks | grep -Pc 'index:\s+\d+'
if [ $sinks_count -eq 0 ] ; then
exit
fi
declare -i active_sink_index=pacmd list-sinks | grep -Po '\*\s+index:\s+\K\d+'
active_index_position_found=0
let next_sink_index=-1
while read index ;
do
declare -i ind=($(echo $index | tr -dc '[0-9]+'))
if [ $next_sink_index -lt 0 ] ; then
export next_sink_index=$ind
fi
if [ $active_index_position_found -eq 1 ] ; then
export next_sink_index=$ind
break;
fi
if [ $active_sink_index -eq $ind ] ; then
export active_index_position_found=1
fi
done < <(pacmd list-sinks | grep -Po 'index:\s+\K\d+')
#change the default sink
pacmd "set-default-sink ${next_sink_index}"
#move all inputs to the new sink
for app in $(pacmd list-sink-inputs | grep -Po 'index:\s+\K\d+');
do
pacmd "move-sink-input $app $next_sink_index"
done
The only script version that worked for me was thew one @rosetta-stoned shared above. Scripts from other comments did not. [OS: Ubuntu Mate 22.04 LTS (Jammy Jellyfish) 64-bit]
I further extended the script with a line to play a sound. This way you can hear sound in the devices as you keep switching output devices. Hearing sound in the desired device will mean you don't need to swap around anymore.
#!/bin/bash
declare -i sinks_count=pacmd list-sinks | grep -Pc 'index:\s+\d+'
if [ $sinks_count -eq 0 ] ; then
exit
fi
declare -i active_sink_index=pacmd list-sinks | grep -Po '\*\s+index:\s+\K\d+'
active_index_position_found=0
let next_sink_index=-1
while read index ;
do
declare -i ind=($(echo $index | tr -dc '[0-9]+'))
if [ $next_sink_index -lt 0 ] ; then
export next_sink_index=$ind
fi
if [ $active_index_position_found -eq 1 ] ; then
export next_sink_index=$ind
break;
fi
if [ $active_sink_index -eq $ind ] ; then
export active_index_position_found=1
fi
done < <(pacmd list-sinks | grep -Po 'index:\s+\K\d+')
#change the default sink
pacmd "set-default-sink ${next_sink_index}"
#move all inputs to the new sink
for app in $(pacmd list-sink-inputs | grep -Po 'index:\s+\K\d+');
do
pacmd "move-sink-input $app $next_sink_index"
done
paplay /usr/share/sounds/mate/default/alerts/sonar.ogg

- 11
- 2
-
Worked perfectly for me on KDE Neon, just had to adapt the audio path to
/usr/share/sounds/gnome/default/alerts/sonar.ogg
– L0Lock Feb 29 '24 at 15:55
I added support for "prev" and "next" arguments, since I have quite a few devices to choose from. Just bind 2 keys.
#!/bin/bash
declare direction="$1"
declare -i sinks_count=pacmd list-sinks | grep -Pc 'index:\s+\d+'
if [ $sinks_count -eq 0 ] ; then
exit
fi
declare -i active_sink_index=pacmd list-sinks | grep -Po '\*\s+index:\s+\K\d+'
readarray -t indexes < <(pacmd list-sinks | grep -Po 'index:\s+\K\d+')
declare indexes_count=${#indexes[@]}
declare active_index=-1
for i in "${!indexes[@]}"; do
if [[ "${indexes[$i]}" = "${active_sink_index}" ]]; then
active_index=$i;
fi
done
declare next_index=$((( $active_index + 1 ) % $indexes_count))
declare prev_index=$((( $active_index - 1 ) % $indexes_count))
declare next_sink_index=${indexes[$next_index]}
declare prev_sink_index=${indexes[$prev_index]}
declare sink_to_use="${next_sink_index}"
if [ "$direction" = "prev" ] ; then
sink_to_use="${prev_sink_index}"
fi
Change the default sink
pacmd "set-default-sink ${sink_to_use}"
Move all inputs to the new sink
for app in $(pacmd list-sink-inputs | grep -Po 'index:\s+\K\d+');
do
pacmd "move-sink-input $app $sink_to_use"
done

- 1
Do this in 2 steps:
Find a command line setting to change back/forth between these settings.
Add these to some key combinations. Systems Settings >> Keyboard >> Shortcuts

- 14,499
-
How can one find out, what command line setting is needed to switch the sound output? Is there a way to trace what happens, when I do it with the GUI? – Evenbit GmbH Jun 28 '12 at 05:43
-
No, you need to use amixer (command line) and/or alsamixer (char-mode) in a terminal. These are old-school, and require some effort to master. Start by adding output from amixer -c 0 to your question .. – david6 Jun 28 '12 at 07:16
-
1I find that command and successfully run a shortcut to switch between analog and HDMI output, see my answer here. – Pablo Bianchi Mar 30 '17 at 22:40