44

I use my laptop with an external monitor which has speakers. When the monitor is attached through HDMI I can switch (using the GUI: Sound Setting --> Hardware) between the normal laptop audio output and the monitor output.

I repeat this procedure a lot of time and I started to wonder if I can automate it or, anyway, execute it in a faster way using the shell.

My distro is Ubuntu 12.04 with gnome 3.

EDIT:

I tried using pacmd, but list-sinks gives me only the device I'm currently using:

pacmd list-sinks | grep name:
name: <alsa_output.pci-0000_00_1b.0.hdmi-stereo>

After a switch from GUI:

pacmd list-sinks | grep name:
name: <alsa_output.pci-0000_00_1b.0.analog-stereo>

And if I try to change it I get:

pacmd set-default-sink alsa_output.pci-0000_00_1b.0.hdmi-stereo
Welcome to PulseAudio! Use "help" for usage information.
Sink alsa_output.pci-0000_00_1b.0.hdmi-stereo does not exist.

10 Answers 10

40

In this case the card is always the same. What is changing between a switch and another is the "card-profile".

So the solution which actually worked is:

pacmd set-card-profile <cardindex> <profilename>

In my case I found all the card profiles with:

pacmd list-cards

And after I can switch between monitor and laptop speakers with:

pacmd set-card-profile 0 output:hdmi-stereo

And:

pacmd set-card-profile 0 output:analog-stereo+input:analog-stereo

Where 0 is the index of the card:

pacmd list-cards
Welcome to PulseAudio! Use "help" for usage information.
>>> 1 card(s) available.
    index: 0
    name: <alsa_card.pci-0000_00_1b.0>

And finally, in order to make the switch faster, I set up two alias in my .bashrc file:

alias audio-hdmi='pacmd set-card-profile 0 output:hdmi-stereo+input:analog-stereo'
alias audio-laptop='pacmd set-card-profile 0 output:analog-stereo+input:analog-stereo'

This way I can switch between audio from the monitor or from the laptop (headphones) typing in the shell: audio-hdmi or audio-laptop

4
  • Hm. My pacmd doesn't have 'list-cards' option...
    – ka3ak
    Feb 27, 2017 at 17:51
  • After going through a lot of fiddling, this method worked for me on a i3wm + Debian setup.
    – rajudev
    Jul 21, 2020 at 3:58
  • Mille Grazie <3, finally I have my internal/external soundcard switch alias for :bashrc: External pacmd set-card-profile 1 off && pacmd set-card-profile 0 output:analog-stereo, pacmd set-card-profile 0 off && pacmd set-card-profile 1 output:analog-stereo+input:analog-stereo Apr 4, 2021 at 14:34
  • 1
    Advice for anyone wanting to figure out what your specific setup needs after “output:”: pacmd list-cards > ~/Downloads/output1.txt , then change to the-other-settings and dump as output2.txt. Then diff things, by diff command or e.g more conveniently in vscode “compare selected”... Apr 4, 2021 at 14:36
8

I wrote a small indicator applet that lets you switch the sound output. No shell script but maybe helpful to you or other readers.

https://github.com/lkettenb/sound-output-switcher

Screenshot

4

I created a very small script based on the previous ones, which not only switches the audio but also the video output. It uses the disper to switch between displays.

Here is the code:

#!/bin/bash

CURRENT_PROFILE=$(pacmd list-cards | grep "active profile" | cut -d ' ' -f 3-)

if [ "$CURRENT_PROFILE" = "<output:hdmi-stereo>" ]; then
        pacmd set-card-profile 0 "output:analog-stereo+input:analog-stereo"
        disper -s
else 
        pacmd set-card-profile 0 "output:hdmi-stereo"
        disper -S        
fi

For me it is especially useful since I don't like to clone the displays. I either use one or the other. You may need to adapt the audio profiles to your specific system.

2

You can use pactl, read its man page for more information.

2

You can try this script: https://github.com/giner/helplinux/tree/master/scripts/switch-sound

Tested on Ubuntu 10.04 - 13.04 and Arch Linux

2

Lukas's python script (https://github.com/lkettenb/sound-output-switcher, posted above) to implement a notifier applet works well. It needs the appindicator package. That can be installed with

sudo apt-get install python-appindicator
1
  • 3
    Please include at least a few words in your answer explaining what the script is and why it's handy.
    – derobert
    Aug 22, 2014 at 11:16
2

I created the following python script that does the following:

  1. Toggle the default device to the next device on the list (with wrap around) regardless of the id's
  2. Moves all running applications to this device.
  3. Sends a notifications to the GUI with the device name.
#!/usr/bin/env python3
import subprocess
# Toggle default device to the next device (wrap around the list)
cards_info = subprocess.run(['pacmd','list-sinks'], stdout=subprocess.PIPE)
card_indexes = subprocess.run(['grep', 'index'], stdout=subprocess.PIPE, input=cards_info.stdout)
indexes_list = card_indexes.stdout.decode().splitlines()
card_descriptions = subprocess.run(['grep', 'device.description'], stdout=subprocess.PIPE, input=cards_info.stdout)
indices = [i for i, s in enumerate(indexes_list) if '*' in s]
if (len(indices) != 1):
    print("Error finding default device")
    exit(1)
default_index = indices[0]
next_default = 0
if (default_index != (len(indexes_list) - 1)):
    next_default = default_index + 1
next_default_index =  (indexes_list[next_default].split("index: ",1)[1])
subprocess.run(['pacmd','set-default-sink %s' %(next_default_index)], stdout=subprocess.PIPE)

# Move all existing applications to the new default device
inputs_info = subprocess.run(['pacmd','list-sink-inputs'], stdout=subprocess.PIPE)
inputs_indexes = subprocess.run(['grep', 'index'], stdout=subprocess.PIPE, input=inputs_info.stdout)
inputs_indexes_list = inputs_indexes.stdout.decode().splitlines()
for line in inputs_indexes_list:
    input_index =  (line.split("index: ",1)[1])
    subprocess.run(['pacmd','move-sink-input %s %s' %(input_index, next_default_index)], stdout=subprocess.PIPE)

# Send notification to the GUI
descriptions_list = card_descriptions.stdout.decode().splitlines()
if (len(descriptions_list) == len(indexes_list)):
    description =  (descriptions_list[next_default].split("= ",1)[1])[1:-1]
    args = ["notify-send", "Default audio card changed", 'Default audio card was set to %s' %(description)]
    subprocess.run(args, stdout=subprocess.PIPE)

Assigned a keyboard shortcut to the script, and my life is happy now

0

As I told here (probably a duplicate), an alternative to Sound Switcher Indicator (which requieres adding a PPA):

In one line

In my case was hdmi-stereo-extra1+input profile, so in one line would be: [[ $(pacmd list-cards | grep "active profile" | cut -d " " -f 3-) = "<output:hdmi-stereo-extra1+input:analog-stereo>" ]] && pacmd set-card-profile 0 "output:analog-stereo+input:analog-stereo" || pacmd set-card-profile 0 "output:hdmi-stereo-extra1+input:analog-stereo".

You can use a custom shortcut to execute it with bash -c (will warn you if there is any conflict with other shortcut):

enter image description here

Also you can add an alias to your .bashrc.

In a script

I made some changes based on @user829996 (and here @user56655) answer:

#!/bin/bash
set -euo pipefail # strict mode

activeProfile() { pacmd list-cards | grep "active profile" | cut -d " " -f 3-; }
CURRENT_PROFILE="$(eval activeProfile)"

# If it doesn't work run  pacmd list-cards  and try the other outputs from profile section
ANALOG_PROFILE="output:analog-stereo+input:analog-stereo"
HDMI_PROFILE="output:hdmi-stereo-extra1+input:analog-stereo"

if [ "$CURRENT_PROFILE" = "<output:hdmi-stereo-extra1+input:analog-stereo>" ] ; then
  pacmd set-card-profile 0 "$ANALOG_PROFILE"
else
    pacmd set-card-profile 0 "$HDMI_PROFILE"
fi

activeProfile
0

If useful. I've got bluetooth headphones and needed to setup switching betweed headset and a2dp profiles for them. Solved with adding these functions:

talk() {
  card=$(pacmd list-cards | grep 'name:' | grep bluez | cut -d: -f2 | sed -e 's/[< >]//g')
  pacmd set-card-profile $card headset_head_unit
}

mus() {
  card=$(pacmd list-cards | grep 'name:' | grep bluez | cut -d: -f2 | sed -e 's/[< >]//g')
  pacmd set-card-profile $card a2dp_sink
}
0

I was specifically trying to switch between internal speakers and a headset plugged into the audio jack. That is registered by Pulse Audio as the same card, but different ports. All of the suggestions with pacmd set-card-profile weren't working for me. Instead, what I needed to do was:

  1. get information on what ports were available, by running pacmd list-sinks. Figure out which index you want, and then look under ports. For me it looked like:
2 sink(s) available.
    index: 0
        name: <alsa_output.pci-0000_1b_00.1.analog-stereo>
...
    ports:
        analog-output-speaker: Speakers (priority 10000, latency offset 0 usec, available: no)
            properties:
                device.icon_name = "audio-speakers"
        analog-output-headphones: Headphones (priority 9900, latency offset 0 usec, available: yes)
            properties:
                device.icon_name = "audio-headphones"
    active port: <analog-output-speaker>
  1. To switch, I took the name of the sink (see the line underneath index where it says name), and combined it with the port:
pactl set-sink-port alsa_output.pci-0000_1b_00.1.analog-stereo analog-output-headphones

Then I did the same thing for the microphone, but everywhere it says sink[s] above, switch it to source[s].

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.