7

I'm trying to switch between the audio outputs of my video card from the command line. I'm able to do that via the GUI settings, as it's shown on the picture. How can I do this programmatically?

enter image description here

On the picture are presented two audio devices wit two outputs each:

  • (green) Device 1 - Built-in Audio with two outputs:

    • Digital Output
    • Headphones
  • (red)      Device 2 - HDMI Audio Controller of NVidia GTX 660. To the video card are connected two monitors:

    • The first monitor is LG TV and it is connected to HDMI-0.

    • The second monitor is LG ULTRAWIDE and it is connected to DVI-I-1.

So I want to switch, via the command-line, between the red outputs (the two monitors). Everything I've found, in my research, is how to switch between the audio devices (sound cards). I've already read few topics as these questions:


When the first monitor LG TV | HDMI-0 is engaged as audio output:

enter image description here

$ pactl list sinks short
8   alsa_output.pci-0000_00_1b.0.analog-stereo  module-alsa-card.c  s16le 2ch 44100Hz   SUSPENDED
16  alsa_output.pci-0000_03_00.1.hdmi-stereo    module-alsa-card.c  s16le 2ch 44100Hz   RUNNING

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

When the second monitor LG ULTRAWIDE | DVI-I-1 is engaged as audio output:

enter image description here

$ pactl list sinks short
8   alsa_output.pci-0000_00_1b.0.analog-stereo  module-alsa-card.c  s16le 2ch 44100Hz   SUSPENDED
17  alsa_output.pci-0000_03_00.1.hdmi-stereo-extra1 module-alsa-card.c  s16le 2ch 44100Hz   RUNNING

$ pacmd list-sinks | grep name:
    name: <alsa_output.pci-0000_00_1b.0.analog-stereo>
    name: <alsa_output.pci-0000_03_00.1.hdmi-stereo-extra1>

The output of pacmd list-cards and pactl list cards is provided here.


You can see (in this particular case) I'm searching for a way to switch between sink 16 and sink 17. But when sink 16 is presented in pactl list sinks, sink 17 is not presented and vice versa. I can switch them only from the GUI settings. Is ithere a way to do that via the command-line?

7
  • pactl set-default-sink alsa_output.pci-0000_00_1b.0.analog-stereo or pactl set-default-sink alsa_output.pci-0000_03_00.1.hdmi-stereo-extra1?
    – Thomas
    Mar 4 '18 at 15:10
  • @Thomas, if I understood your suggestion correctly the result is Failure: No such entity.
    – pa4080
    Mar 4 '18 at 15:21
  • There is not sink alsa_output.pci-0000_03_00.1.hdmi-stereo but alsa_output.pci-0000_03_00.1.hdmi-stereo-extra1. Don't get the point from your link?
    – Thomas
    Mar 4 '18 at 15:25
  • @Thomas, I've updated the question.
    – pa4080
    Mar 4 '18 at 15:43
  • 1
    Hi, @Thomas, thanks to your help I've solved the task. We can find all available profiles for each card name by: pacmd list-cards/pactl list cards. The correct syntax of the commands is: (1) pactl set-card-profile alsa_card.pci-0000_03_00.1 output:hdmi-stereo and (2) pactl set-card-profile alsa_card.pci-0000_03_00.1 output:hdmi-stereo-extra1. (Where alsa_card.pci-0000_03_00.1 is the card name and output:hdmi-stereo* are the profile names.) These commands creates new sinc # and deletes the previews sinc # of this card.
    – pa4080
    Mar 4 '18 at 23:24
8

Thanks to the discussion with @Thomas I realised the proper therms (key words) are profile and card. In the terms of the question profiles are the inputs and outputs. The cards are the audio devices. And the sink numbers are not so important, but we need them.

We can find all available profiles for each card name by the command pacmd list-cards or pactl list cards that outputs the same information:

$ pactl list cards

Card #0
    Name: alsa_card.pci-0000_00_1b.0
    ...
    Profiles:
        input:analog-stereo: Analog Stereo Input (sinks: 0, sources: 1, priority: 60, available: yes)
        output:analog-stereo: Analog Stereo Output (sinks: 1, sources: 0, priority: 6000, available: yes)
        output:analog-stereo+input:analog-stereo: Analog Stereo Duplex (sinks: 1, sources: 1, priority: 6060, available: yes)
        output:analog-surround-21: Analog Surround 2.1 Output (sinks: 1, sources: 0, priority: 800, available: yes)
        ...
    Active Profile: output:iec958-stereo+input:analog-stereo
    ...

Card #1
    Name: alsa_card.pci-0000_03_00.1
    ...
    Profiles:
        output:hdmi-stereo: Digital Stereo (HDMI) Output (sinks: 1, sources: 0, priority: 5400, available: yes)
        output:hdmi-stereo-extra1: Digital Stereo (HDMI 2) Output (sinks: 1, sources: 0, priority: 5200, available: yes)
        output:hdmi-surround-extra1: Digital Surround 5.1 (HDMI 2) Output (sinks: 1, sources: 0, priority: 100, available: yes)
        output:hdmi-surround71-extra1: Digital Surround 7.1 (HDMI 2) Output (sinks: 1, sources: 0, priority: 100, available: yes)
        ...
    Active Profile: output:hdmi-stereo
    ...

A certain profile can be set by command with format as this:

pactl set-card-profile output:hdmi-stereo <card name|number> <profile name>

According to the question for the four mentioned outputs the commands are:

pactl set-card-profile alsa_card.pci-0000_03_00.1 output:hdmi-stereo # LG ULTRAWIDE
pactl set-card-profile alsa_card.pci-0000_03_00.1 output:hdmi-stereo-extra1 # LG TV
pactl set-card-profile alsa_card.pci-0000_00_1b.0 output:iec958-stereo # Digital Output
pactl set-card-profile alsa_card.pci-0000_00_1b.0 output:analog-stereo # Headphones

As it is shown in this answer, when the new profile is set next things to do are:

 pacmd set-default-sink <sink number of the target profile>
 pacmd move-sink-input "$i" <sink number of the target profile> 
 # where $i is the index number of any active input: pacmd list-sink-inputs   

According to my needs, described in the question, I've created the following script:

#!/bin/bash

# Name: /usr/local/bin/audioswitch
# Usage: audioswitch; audioswitch 1; audioswitch 2;  audioswitch 3; audioswitch 4

CARD_1="pci-0000_03_00.1"             ### HDMI Audio Controller of NVidia GTX 660
CARD_1_PROFILE_1="hdmi-stereo"          # LG ULTRAWIDE
CARD_1_PROFILE_2="hdmi-stereo-extra1"   # LG TV
CARD_0="pci-0000_00_1b.0"             ### Built-in Audio
CARD_0_PROFILE_1="iec958-stereo"        # Digital Output
CARD_0_PROFILE_2="analog-stereo"        # Headphones

# Read the user's input
CHOICE="${@}"
choice() {
    if   [ "$CHOICE" == 1 ]; then CARD="$CARD_1"; PROF="$CARD_1_PROFILE_1" # LG ULTRAWIDE
    elif [ "$CHOICE" == 2 ]; then CARD="$CARD_1"; PROF="$CARD_1_PROFILE_2" # LG TV
    elif [ "$CHOICE" == 3 ]; then CARD="$CARD_0"; PROF="$CARD_0_PROFILE_1" # Digital Output
    elif [ "$CHOICE" == 4 ]; then CARD="$CARD_0"; PROF="$CARD_0_PROFILE_2" # Headphones
    else
        echo -e "\nYou should choice between:"
        echo -e "\n\t[1] LG ULTRAWIDE\n\t[2] LG TV\n\t[3] Digital Output\n\t[4] Headphones\n"
        echo -n "Your choice: "; read CHOICE; echo; choice; # call the function again
    fi
}; choice # call the function

# Set the choosen card profile as sink
pactl set-card-profile "alsa_card.${CARD}" "output:${PROF}";

# Set the default sink to the new one
pacmd set-default-sink "alsa_output.${CARD}.${PROF}" &> /dev/null

# Redirect the existing inputs to the new sink
for i in $(pacmd list-sink-inputs | grep index | awk '{print $2}'); do
    pacmd move-sink-input "$i" "alsa_output.${CARD}.${PROF}" &> /dev/null
done

The script is ready to be used with custom keyboard shortcuts, because it can handle the value (1-4) of the first positional parameter. When it is called without additional paraneter it will ask for your choice:

$ audioswitch 

You should choice between:

    [1] LG ULTRAWIDE
    [2] LG TV
    [3] Digital Output
    [4] Headphones

Your choice: 1
5
  • Notes for further improvements: 1; 2; 3.
    – pa4080
    Mar 20 '18 at 11:10
  • I'm using the above script for a bout a year, and it works like a charm! Sometimes the output sound is fuzzy in these cases I'm changing the sink back and fourth, by the script, and the output sound becomes clear.
    – pa4080
    Feb 1 '19 at 16:31
  • very useful script.. I am not getting your point of "The script is ready to be used with custom keyboard shortcuts, because it can handle the value (1-4) of the first positional parameter. When it is called without additional parameter it will ask for your choice:"
    – UnKNOWn
    Jul 30 '20 at 3:03
  • So one needs to set all the 4 commands as keyboard shortcuts rite? Not the one keyboard shortcut that can ask for choice..
    – UnKNOWn
    Jul 30 '20 at 3:05
  • Hi, @PRATAP, yes, you are right. I'm using this script together with another script (based on xrandr) that switches the video output. So my shortcut commands look like: audioswitch 1 && videoswitch 1, audioswitch 2 && videoswitch 2, etc. If you need interactive application - there is a nice gnome extension that allows to switch the audio outputs directly from a toolbar menu.
    – pa4080
    Jul 30 '20 at 5:05

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.