15

I like to switch the sound output from Speaker to USB headphone with a Shortcut. Is there a way to accomplish this?

1

8 Answers 8

8
  1. 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
    
  2. 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 of id. For example:

     pactl set-sink-port alsa_output.pci-0000_00_1b.0.analog-stereo analog-output-headphones
    

Reference: man pactl

4
  • 1
    Thank you. Finally after a long time a working answer :) Commented Feb 15, 2014 at 19:55
  • 1
    Come'n :) you were still waiting, I just fill it in case someone need it come by.
    – user.dz
    Commented Feb 15, 2014 at 20:00
  • Really. I haven't found a solution for that. But i stopped trying to find one a long time ago. Commented Feb 15, 2014 at 20:04
  • 1
    Finally found a solution that works on my machine. Thank you!
    – kohane15
    Commented Apr 4, 2023 at 2:36
8

Automated solution https://ubuntuforums.org/showthread.php?t=1370383 It works on Ubuntu 18.04

  1. Open the terminal and type:

     sudoedit /usr/local/bin/audio-device-switch.sh
    
  2. Copy and paste the below code in nano editor

  3. Save it and close nano editor.

  4. sudo chmod 755 /usr/local/bin/audio-device-switch.sh

  5. System -> Preferences -> Keyboard Shortcuts

  6. Press Add and enter Switch between audio devices as name and audio-device-switch.sh as command and press Apply.

  7. Select the newly added shortcut row and click on the shortcut column. 8. Choose a shortcut combination – e.g. Win + F12.

  8. 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
3
  • 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
    Commented Nov 30, 2020 at 16:44
  • I had to fix the last if and do to match the bash syntax. The script works perfectly!. Commented Dec 22, 2020 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
    Commented Jan 2, 2021 at 9:53
3

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

edit: My new motherboard comes with ALC4080. pactl now lists both the front and the rear output jack as available, although only one of them can actually be in use at the same time. Hence, cycling through the outputs with this script no longer works. The loop gets stuck at the last available output.

1

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;
1
  • 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
    Commented Sep 20, 2021 at 13:52
1

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
1

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
1
  • Worked perfectly for me on KDE Neon, just had to adapt the audio path to /usr/share/sounds/gnome/default/alerts/sonar.ogg 😄
    – Lauloque
    Commented Feb 29 at 15:55
0

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:

  1. Find a command line setting to change back/forth between these settings.

  2. Add these to some key combinations. Systems Settings >> Keyboard >> Shortcuts

3
  • 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? Commented Jun 28, 2012 at 5: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
    Commented Jun 28, 2012 at 7:16
  • 1
    I find that command and successfully run a shortcut to switch between analog and HDMI output, see my answer here. Commented Mar 30, 2017 at 22:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .