I configured the alsa default device via /etc/asound.conf, which requires specifying the index number of the device as defined in /proc/asound/cards.
The problem is that the index assigned to a given device may change at boot, which makes the configuration incorrect, so alsa no longer uses the correct device. Contrary to some online advice, specifying the name of the device in /etc/asound.conf does not work.
I ended up writing a dash shell script that creates a user-specific alsa configuration file at /home/$USER/.asoundrc that over-rides the system configuration.
The script accepts arguments to specify the alsa default device name, and optionally to redirect output through jackd.
I have the script run at each login to set the default alsa device. I also execute the script with appropriate arguments at startup and shutdown of jack using the setup options in QjackCtl:
I'm posting the complete (voluminously commented) script here in case anyone finds it useful.
Code: Select all
#!/bin/dash
########################################################################
# #
# set-alsa-default-device.sh #
# #
# This script is designed to set the default alsa audio device by #
# referring to it by name instead of index number. #
# #
# The index numbers may change as devices are added or removed, #
# or randomly at each reboot, so specifying the alsa default device #
# via the index number can be problematic. #
# #
# For example, this output indicates that the device #
# named 'PCH' has the index number '2': #
# #
# cat /proc/asound/cards #
# 0 [HDMI ]: HDA-Intel - HDA Intel HDMI #
# HDA Intel HDMI at 0xf7914000 irq 34 #
# 1 [CH345 ]: USB-Audio - CH345 #
# QinHeng CH345 at usb-0000:00:14.0-14, full speed #
# 2 [PCH ]: HDA-Intel - HDA Intel PCH #
# HDA Intel PCH at 0xf7910000 irq 35 #
# 3 [NVidia ]: HDA-Intel - HDA NVidia #
# HDA NVidia at 0xf7080000 irq 17 #
# #
# ... but on the next boot, 'PCH' had become index number '1': #
# #
# cat /proc/asound/cards #
# 0 [HDMI ]: HDA-Intel - HDA Intel HDMI #
# HDA Intel HDMI at 0xf7914000 irq 34 #
# 1 [PCH ]: HDA-Intel - HDA Intel PCH #
# HDA Intel PCH at 0xf7910000 irq 35 #
# 2 [NVidia ]: HDA-Intel - HDA NVidia #
# HDA NVidia at 0xf7080000 irq 17 #
# 3 [CH345 ]: USB-Audio - CH345 #
# QinHeng CH345 at usb-0000:00:14.0-14, full speed #
# #
# The script sets the default alsa device by writing a user-specific #
# alsa configuration file at '/home/$USER/.asoundrc'. #
# #
# Note: Any existing file will be over-written! Back up as required. #
# #
# The entries 'defaults.pcm.card' (output) and 'defaults.ctl.card' #
# (input) are created, referencing the device's name and index #
# number as listed in /proc/asound/cards. #
# #
# Specify the audio device to set as default by supplying the #
# device name as a case-sensitive command argument, eg. #
# 'set-alsa-default-device.sh PCH' to set PCH as alsa default #
# #
# If no such device name is supplied, the value of the script #
# variable 'devdef' will be used. Edit as required. #
# #
# Optionally send all alsa output to the jackd audio server by #
# adding the keyword 'jack' as a command argument, eg. #
# 'set-alsa-default-device.sh PCH jack' to use PCH + jack #
# or #
# 'set-alsa-default-device.sh jack' to use 'devdef' value + jack #
# #
# #
# Supplying more than two command line arguments, or an incorrect #
# audio device name, will result in the script terminating with #
# an error message and a return value of '1'. #
# #
########################################################################
# Path to user's alsa configuration file
rc_path="/home/$USER/.asoundrc"
# Device name to use if none supplied as script argument
devdef='PCH'
# Variable to indicate if redirection to jackd server is required.
# Redirection occurs only if the variable 'jack' is set to 'true'.
jack=0
# Get the script arguments, if any. Maximum of two arguments.
# The arguments are optional, and could be comprised of:
# - one alsa audio device name as listed in /proc/asound/cards,
# and/or
# - the keyword 'jack' to indicate that the output should be
# redirected to jackd.
# If no arguments are supplied, the value of the script variable
# 'devdef' is used.
if [ "$#" -eq '0' ]
then
d="$devdef"
elif [ "$#" -eq '1' ]
then
if [ "$1" = 'jack' ]
then
jack='true'
d="$devdef"
else
d="$1"
fi
elif [ "$#" -eq '2' ]
then
if [ "$1" = 'jack' ]
then
jack='true'
d="$2"
elif [ "$2" = 'jack' ]
then
jack='true'
d="$1"
else
echo "Error: when supplying two arguments, one of the arguments must be the keyword 'jack' to indicate redirection via the jackd audio server."
exit 1
fi
else
echo 'Error: Maximum of two arguments.'
exit 1
fi
# Get the contents of '/proc/asound/cards''
cards="$(cat /proc/asound/cards)"
# Get the index number of the device specified in the variable 'd'
device="$(printf '%s' "$cards" | grep "\[$d")"
# Check that the return string is not zero-length
if [ -z "$device" ]
then
echo "Device '$d' not found in list of devices in '/proc/asound/cards'"
exit 1
fi
# Get the first field of the output, ignoring leading spaces
i="$(printf '%s' "$device" | awk '{print $1}')"
# Check that i is an integer
if [ -n "$i" ] && [ "$i" -eq "$i" ] 2>/dev/null
then
# Prepend comment char to each line of 'cards' variable
cards="$(printf '%s' "$cards" | sed 's/^/#/')"
cat << EOF1 > "$rc_path"
# Alsa default device set to '$d' as index '$i' from /proc/asound/cards:
$cards
# Output:
defaults.pcm.card $i
# Input:
defaults.ctl.card $i
EOF1
# Append jackd redirection if required
if [ "$jack" = 'true' ]
then
cat << 'EOF2' >> "$rc_path"
# Send all alsa output through jackd.
# Note: jack must be running or alsa applications will fail.
pcm.!default {
type plug
slave.pcm "jack"
hint.description "Jack Audio"
}
EOF2
fi
else
echo "Failed to get index of device '$d' from '/proc/asound/cards'"
exit 1
fi