31

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.
26

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

  • Hm. My pacmd doesn't have 'list-cards' option... – ka3ak Feb 27 '17 at 17:51
5

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

2

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

2

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

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
  • 3
    Please include at least a few words in your answer explaining what the script is and why it's handy. – derobert Aug 22 '14 at 11:16
1

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

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

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

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.