15

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

user.dz
  • 48,105
Evenbit GmbH
  • 4,636
  • 1
    Closely related: http://askubuntu.com/questions/41858/shortcut-to-switch-between-analog-stereo-output-hdmi-audio-output – Takkat Jun 28 '12 at 06:16

8 Answers8

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

  • 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
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

user.dz
  • 48,105
2

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

j2L4e
  • 200
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;

fairtrax
  • 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
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

Netsmile
  • 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
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

RanzQ
  • 1
-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

david6
  • 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
  • 1
    I 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