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. 🙂
Silly question: which USB sound adapters work well with linux, and for full 6+1 optical out signals? Is there a list?
@steve_l: Most Logitech USB speakers and headsets worked perfectly for me. If you are looking for a USB sound card, I’d recommend you one from AUDIOTRAK – http://www.audiotrak.net/products/mayaex5ce/
@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.
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!
@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! 🙂
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
for you information, that’s work with “grep -v NAME_WEB_CAM” into alsa-reconfigure script.
BR
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
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