I have a set of nice wireless headphones which I use from time to time, in addition to my speakers and normal microphone.

I'd like to write a script to switch between one input and output source and another, essentially a switch between my headphones and my speakers+microphone.

I'd like to change between this:

...and this:

Is there a way for me script a transfer between the two inputs and outputs? Essentially I'm looking for something like this:


if [ "$CURRENT_INPUT" == "Vengeance 2000" ]; then
    set-current-input "HD Pro Webcam C920"
    set-current-input "Vengeance 2000"

if ["$CURRENT_OUTPUT" == "Vengeance 2000" ]; then
    set-current-output "Built-in Audio"
    set-current-output "Vengeance 2000"

Is there a way to script this?


7 Answers 7


As @Teresa-e-Junior pointed out pactl is the tool to use:

First of all we might want to get the IDs of our PA sinks. On my system this is what I get:

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

Sink 1 is currently my default sink.
But now I want all my current and future streams to be played via HDMI (i.e. sink 0).

There is a command to set the default sink for PulseAudio, but it doesn't seem to have any effect on my PC:

$ pacmd set-default-sink 0 #doesn't work on my PC :(

Instead, new streams seem to be connected to the sink that had a stream moved to it most recently.

So let's tell pactl to move all currently playing streams to sink 0. We'll first need to list them:

$ pactl list short sink-inputs
290     1       176     protocol-native.c       float32le 2ch 44100Hz
295     1       195     protocol-native.c       float32le 2ch 44100Hz

Ok, we've got two streams (IDs 290 and 295) that are both attached to sink 1.
Let's move them to sink 0:

$ pactl move-sink-input 290 0
$ pactl move-sink-input 295 0

So, that should be it. Now we just have to make a script that does the work for us:


if [ -z "$1" ]; then
    echo "Usage: $0 <sinkId/sinkName>" >&2
    echo "Valid sinks:" >&2
    pactl list short sinks >&2
    exit 1


pactl list short sink-inputs|while read stream; do
    streamId=$(echo $stream|cut '-d ' -f1)
    echo "moving stream $streamId"
    pactl move-sink-input "$streamId" "$newSink"

You can call it with either a sink ID or a sink name as parameter (i.e. either 0 or something like alsa_output.pci-0000_01_00.1.hdmi-surround).

Now you could attach this script to a udev event or key shortcut.

  • 1
    Related: askubuntu.com/a/14083/6645 Commented May 10, 2013 at 19:47
  • 3
    $ pacmd set-default-sink INDEX is still needed for my script otherwise keyboard commands for changing volume continue to use the old sink source.
    – myol
    Commented Apr 4, 2018 at 1:50
  • This post needs to be updated to reflect what pacmd set-default-sink actually does, instead of expressing sadness over what it doesn't do. And you are right @myol, I have the same problem. Commented May 30, 2018 at 18:20
  • 1
    This script is awesome! Exactly what I've been looking for. :) Thank you.
    – Friederike
    Commented Dec 8, 2018 at 11:32
  • Unfortunately does not work, when no sound is played at the time of switching. So you need to switch sound devices while sound is already active and cannot do it preemptive before. Is there a solution for it?
    – ford04
    Commented Jul 31, 2020 at 23:32

The following commands can be used to manipulate the PulseAudio sound server:

pacmd - Used to reconfigure a PulseAudio sound server during runtime.
pactl - Used to control a running PulseAudio sound server.

Here are some examples of how they function:

pacmd list-sinks :: list name or index number of possible sinks

pacmd set-default-sink [sinkname] :: set the default output sink

pacmd set-default-source [sourcename] :: set the default input

pacmd set-sink-volume [index] [volume] :: set the sink volume

pacmd set-source-volume index volume :: volume control range 0 - 65536 (the lower the number the lower the volume)

These are only a few that I've pulled out of the wiki & man page. Reference this for more detailed information. Or you can view either commands --help or man page.

There is also a command line tool already out there that serves this purpose. It's name is ponymix. It's a command line mixer for PulseAudio. The link provided is to the projects github. It's developed by a friend and fellow Arch Linux Trusted User / Developer. If you're not running Arch you could just compile it from source using make and sudo make install.

$ ponymix --help
    usage: ponymix [options] <command>... 
 -h, --help              display this help and exit    
 -c, --card CARD         target card (index or name)
 -d, --device DEVICE     target device (index or name)
 -t, --devtype TYPE      device type
 -N, --notify            use libnotify to announce volume changes
     --source            alias to -t source
     --input             alais to -t source
     --sink              alias to -t sink
     --output            alias to -t sink
     --sink-input        alias to -t sink-input
     --source-output     alias to -t source-output
Device Commands:
  help                   display this message
  defaults               list default devices (default command)
  set-default            set default device by ID
  list                   list available devices
  list-short             list available devices (short form)
  list-cards             list available cards
  list-cards-short       list available cards (short form)
  get-volume             get volume for device
  set-volume VALUE       set volume for device
  get-balance            get balance for device
  set-balance VALUE      set balance for device
  adj-balance VALUE      increase or decrease balance for device
  increase VALUE         increase volume
  decrease VALUE         decrease volume
  mute                   mute device
  unmute                 unmute device
  toggle                 toggle mute
  is-muted               check if muted
Application Commands:
  move DEVICE            move target device to DEVICE
  kill DEVICE            kill target DEVICE
Card Commands:
  list-profiles          list available profiles for a card
  list-profiles-short    list available profiles for a card(short form)
  get-profile            get active profile for card
  set-profile PROFILE    set profile for a card
  • Hey thank you for this answer! It helped me a ton with an issue related to this one.
    – KlaymenDK
    Commented Aug 16, 2018 at 10:44
  • Using e.g. pacmd set-source-volume 1 10000 did work to adjust the volume of my livestream through ffmpeg, but I wasn't able to lower the volume anything lower than 10000, it doesn't seem to have any effect. Higher values gave higher volume, though. Using one of those cheap USB-to-jack adapters. Commented Sep 5, 2020 at 17:33

On my laptop running Fedora 20, HDMI output is not listed as a sink in the default profile, but as a different profile itself.

I have only 1 sink like this, nice music playing on my laptop speakers:

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

If I run pactl set-card-profile 0 output:hdmi-stereo then nice music is playing through HDMI. I get:

$ pactl list short sinks
14  alsa_output.pci-0000_00_1b.0.hdmi-stereo    module-alsa-card.c  s16le 2ch 44100Hz   RUNNING

To get back to default I just run pactl set-card-profile 0 output:analog-stereo+input:analog-stereo. Either way the default is there again if I reboot.

The list of profiles for my card is somewhere on pactl list cards output.

  • This info was already provided by the accepted answer. Please don't copy other user's answers unless you have something more to add. This just rehashes the other answer and provided nothing new or useful!
    – slm
    Commented Dec 28, 2013 at 1:14
  • 11
    set-card-profile wasn't mentioned previously, and that's the most important info on this answer.
    – Spidey
    Commented Mar 2, 2014 at 15:03

Extending the accepted answer by @cinelli, I've come up with a script that

  • toggles between exactly two sinks / output devices that have to be defined in the script,
  • toggles the streams AND the default sink, so media keys on the keyboard work and
  • leaves my echo cancellation module untouched.

Change as needed!


# Small script to switch between two hardcoded sound output devices

# Set patterns for devices to be toggled. Have to match to second column
# in output of "pactl list short sinks".
# (Could also hardcode the full names, but this might be a little more robust)

# Discover which sink (output device) is active, and set up toggles
while read -r stream; do
  echo "$stream"
  if echo "$stream" | grep -q "RUNNING"; then
    currentSink=$(echo "$stream" | cut -f2)
  if echo "$stream" | grep -q "$TOGGLE1"; then
    toggle1Sink=$(echo "$stream" | cut -f2)
  if echo "$stream" | grep -q "$TOGGLE2"; then
    toggle2Sink=$(echo "$stream" | cut -f2)
done < <(pactl list short sinks)

# Set up where to switch to
if [ "$currentSink" = "$toggle1Sink" ]; then

# Switch streams AND default sink
pactl list short sink-inputs|while read -r stream; do
    streamId=$(echo "$stream"|cut '-d ' -f1)
    # exclude echo cancellation module, but switch all other streams
    # You can, but don't have to remove if condition if no such module present
    if [ "$streamId" != "0" ]; then
      echo "moving stream $streamId"
      pactl move-sink-input "$streamId" "$newSink"
    # Also switch default sink, so media control keys work correctly
    pactl set-default-sink "$newSink"

I could not comment since this is a new account but I added some code on @mreithub's answer and made it so that it cycles through audio outputs automatically.

BACKGROUND_RED="`tput setaf 1` "
$BACKGROUND_WHITE="`tput setaf 6` "
FORGROUND_BLACK="`tput setaf 0` "
DIM="`tput dim` "
INVERT="`tput smso`"
BOLD="`tput bold` "
RESET="`tput sgr0` "
CLEAR="`tput clear` "

echo -e "$CLEAR" 
pactl list short sinks >&2
# ------------------------------------

if [ -z "$1" ]; then
   echo -en "Usage: $0 <sinkId/sinkName>" >&2
   echo -en "Valid sinks:" >&2
   exit 1

if [ "$1" == '-' ]; then
   echo -en "$INVERT$BACKGROUND_WHITE Current sink : $RESET    " >&2
   currentSink=$(pactl list short sinks | grep RUNNING | awk '{print $1}' | head -1)
   if [ -e $currentSink ];then
       currentSink=$(pactl list short sinks | awk '{print $1}' | head -1)
   pactl list short sinks | grep "^$currentSink" | awk '{print $1,$2}' >&2
   sinks=( $(pactl list short sinks | awk '{print $1}') )
   for (( index=0; index <= (${#sinks[@]} * 2); index++ )); do
       if [ "${sinks[$((index % ${#sinks[@]}))]}" == "$currentSink" ]; then
           newSink="${sinks[$((++index % ${#sinks[@]}))]}"
   echo "-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_"
   echo -en "$INVERT$BACKGROUND_RED New sink : $RESET     "
   pactl list short sinks | grep --color "^$newSink" | awk '{print $1,$2}' >&2

pacmd set-default-sink "$newSink" >&2

pactl list short sink-inputs|while read stream; do
   streamId=$(echo -en $stream|cut '-d ' -f1)
   echo -e "$FORGROUND_BLACK$DIM moving stream $streamId $RESET" >&2
   pactl move-sink-input "$streamId" "$newSink" >&2

It appears to be much simpler now on Ubuntu 22.04. No need to change PulseAudio's configuration or to move active streams.

Here is just what is necessary for me to switch from the speakers and microphone of my computer, to the ones of my headset:


if [ "$(pactl get-default-sink)" = "alsa_output...<first-device-speaker>" ]; then
    pactl set-default-sink "alsa_output...<second-device-speaker>"
    pactl set-default-source "alsa_input...<second-device-microphone>"
    pactl set-default-sink "alsa_output...<first-device-speaker>"
    pactl set-default-source "alsa_input...<first-device-microphone>"

I assigned a keyboard shortcut to this script, and I can switch from one device to another easily. Active streams switch instantly.

To get the list of available sinks and sources:

  • pactl list short sinks
  • pactl list short sources

Here's a quick and simple way to choose the output device from the cli:

alias out='pacmd set-default-sink $(pacmd list-sinks|grep -e "name:" -e "index:"|fzf|cut -d: -f2-)'

Then just type out Enter and select the index of the one you want.

Add it to your ~/.bash_aliases. You might have to apt-get install fzf.

You must log in to answer this question.

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