Changing the default sound card automatically in Linux

Many people including me usually use a USB sound card or a USB speaker to enjoy noise-free high-fidelity sound. I simply don’t understand why all the main board manufacturers ship with a built-in sound chipset which just sucks. It’s not an exception for all laptops.

In a non-portable system such as a desktop PC, you usually don’t need to change your default sound card because your USB sound card is always connected. However, it’s a whole different story for a laptop computer. USB sound card is often disconnected and connected again. For example, I connected my USB speaker to the docking station. The expected behaviour is that the default sound card is chosen automatically – the sound system should be reconfigured so that my USB speaker becomes the default sound card when I dock to the docking station.

Currently, there’s no desktop environment that addresses this problem AFAIK, so I wrote a quick and dirty script file that reconfigures the sound system automatically when a new sound card is detected. The script assumes that you are running HAL and DBUS, which are very common in modern Linux distributions.

#!/bin/sh
# Path: /usr/local/bin/alsa-watch

# Exit if running already.
if [ "x`pgrep -of 'alsa-watch'`" != "x$" ]; then
  exit 1
fi

# Configure the sound card to the default.
/usr/local/bin/alsa-reconfigure

# Begin monitering.
{
dbus-monitor --system --monitor "type='signal',path='/org/freedesktop/Hal/Manager',interface='org.freedesktop.Hal.Manager'" | while read -r EVT; do
  echo "$EVT" | egrep -qi "(DeviceAdded|DeviceRemoved)"
  if [ "$?" = '0' ]; then
    read -r EVT_VAL
    echo "$EVT_VAL" | egrep -qi '(alsa_playback|sound_card)_[0-9]+"'
    if [ "$?" = '0' ]; then
      # Reconfigure the sound card if a sound card is plugged in or out.
      /usr/local/bin/alsa-reconfigure
    fi
  fi
done
} &

Another required script is alsa-reconfigure. The following is what I put into the alsa-reconfigure script. I reset the volume level here:

#!/bin/sh
# Path: /usr/local/bin/alsa-reconfigure
# Exit if there's no sound card.
[ -f /proc/asound/cards ] || exit 0
cat /proc/asound/cards | grep -qi 'no soundcard' && exit 0

# Prefer USB audio device to other sound cards.
cat /proc/asound/cards | grep -qi USB-Audio
if [ "$?" == "0" ]; then
  CARD=`cat /proc/asound/cards | grep USB-Audio | head -1 | perl -pi -e "s/\s*([0-9])+.*/\1/"`
  USB='y'
else
  CARD=`cat /proc/asound/cards | head -1 | perl -pi -e "s/\s*([0-9])+.*/\1/"`
  USB='n'
fi

# Update ALSA settings.
echo "pcm.foo {
  type dmix
  slave.pcm "hw:$CARD"
  ipc_key 1024
}

pcm.!default {
  type plug
  slave.pcm "foo"
}

ctl.!default {
  type hw
  card $CARD
}
" > /etc/asound.conf
chmod 644 /etc/asound.conf

# Reset the volume. (optional)
if [ "$USB" == 'y' ]; then
  amixer sset 'PCM' 80% > /dev/null 2>&1
else
  amixer sset 'Master' 30% > /dev/null 2>&1
fi

You could also do something different such as restarting PulseAudio daemon:

#!/bin/sh
# Path: /usr/local/bin/alsa-reconfigure
# Exit if there's no sound card.
[ -f /proc/asound/cards ] || exit 0
cat /proc/asound/cards | grep -qi 'no soundcard' && exit 0

# Prefer USB audio device to other sound cards.
cat /proc/asound/cards | grep -qi USB-Audio
if [ "$?" == "0" ]; then
  CARD=`cat /proc/asound/cards | grep USB-Audio | head -1 | perl -pi -e "s/\s*([0-9])+.*/\1/"`
else
  CARD=`cat /proc/asound/cards | head -1 | perl -pi -e "s/\s*([0-9])+.*/\1/"`
fi

# Update ALSA settings. (optional if your Linux distribution uses PulseAudio by default)
echo "pcm.!default {
  type pulse
}

ctl.!default {
  type pulse
}
" > /etc/asound.conf

pkill -f '(^|/)pulseaudio( |$)' > /dev/null 2>&1
sleep 1
pkill -9 -f '(^|/)pulseaudio( |$)' > /dev/null 2>&1

# Restart PulseAudio daemon
pulseaudio \
  --system --daemonize --high-priority --realtime --log-target=syslog \
  --disallow-module-loading --disallow-exit \
  --resample-method=src-sinc-best-quality --no-cpu-limit -n \
  -L "module-native-protocol-unix auth-anonymous=1" \
  -L "module-native-protocol-tcp auth-ip-acl=192.168.0.0/16;127.0.0.0/8" \
  -L "module-rescue-streams" \
  -L "module-alsa-sink device=hw:$CARD" \

I execute alsa-watch in my /etc/rc.local file and it works perfectly for me. 🙂

9 Comments Changing the default sound card automatically in Linux

  1. Trustin Lee

    @steve_l: For the full list of supported USB sound cards, you’d better visit the official ALSA web site. I think most USB sound cards are supported basically because they all use the same protocol.

  2. Laslo Pordi

    Hi Guys!

    The script worked well for me, as for creating the asound.conf, but the Ubuntu still seems to ignore this file, and it still uses the default sound device (the on-board one, and not the usb headset.)

    How can I restart the sound system? Or how can I make Ubuntu notice the new settings and use the headset when it’s plugged?

    Thanks in advance!

  3. Trustin Lee

    @Laslo: I don’t use Ubuntu, so I’m not sure what sound daemon it uses. If it uses PulseAudio, you could use the 3rd script. If it launches ESD, then you need to switch to plain ALSA or PulseAudio. Hope that helps! 🙂

  4. woofer

    Hello everybody,
    First of all, thanks for this scripts, that (almost 😉 ) works for me.
    Because when you have another USB device like webcam, is it possible to choose the usb headset instead of usb webcam (maybe change the perl regexp with the name of usb headset into alsa-reconfigure script?)

    Thanks in advance
    Best regard

  5. joe heckert

    Hi Trustin
    A good piece of shell code you wrote there.
    The scripts work nice on my ubuntu 9.04 (IBM-thinkpad X31) after I changed the top lines from #!/bin/sh to #! /bin/bash.
    I appreciate your work, it was just the bit I was looking for after endless alsa research that makes my external USB-speaker work automatically after plugging in.
    regards
    joe

  6. DcDoM

    Great! Finally a solution which is exactly what you need to have plug-and play behaviour in linux. Great Hack!

    IMHO, the policy you implemented should be the default behaviour of the kernel.

    Thanks a lot!
    DcDoM

Comments are closed.