Background
It's amazing to see how much effort has been put in to trying to resolve
various sound related problems for the Raspberry Pi. Apparently it must be
the weakest spot for new users to successfully develop with and use ALSA
under Raspbian. Having spent considerable time and effort trying to get my
own RPi3 sound working in different OS versions and in other Linux
distributions as well, I've decided to write the conclusive to-go-to solution
page. At least for the topic of using an external sound card on the latest
Raspbian Stretch.
The ALSA sound system
ALSA is meant to support any kind of *nix based device, regardless of its
hardware configuration and regardless how old is the hardware. Needless,
there is little point in trying to get into the details of
20 years
of its development. We simply apply the essence to a current situation.
However, at no time in history has mankind produced such an amount of useless
and dysfunctional diagrams, as for trying to explain ALSA. The only ones
remotely informative are these two:
Getting the system info
The first step is to figure out what sound, if any, works and what hardware
you already have. There are all sorts of ways to find out details, but for the
average person, most of those details are meaningless. We show the most
important.
What do we want to know about our (sound) system?
We want to know:
- the built-in sound hardware name and versions
- the external sound hardware name and versions
- what kernel drivers (modules) it uses
- what other sound related kernel drivers/modules are loaded
- what sound cards are available
- in what order the sound cards are used and selected by the OS and programs
- if there are any conflicting hardware or sound system programs
From where do you want to play and record sound on your system?
Your options for playing sounds, can be:
- From the internal 3.5 mm audio headphone jack (analog audio)
- From the HDMI connected screen/monitor
- From an external USB sound card
- From a GPIO port
Your options for recording sounds, can be:
- a. From an external USB sound-card (with at least one type of input)
- b. From a file or stream
- c. From a GPIO
In this post, we will tell you how to play and record using the external USB sound card.
A future proof success plan?
With RPi's updates there is a constant flow of new changes and improvements,
often breaking old solutions. The idea here is to make as few changes
to the system as possible or making them obvious if needed. That means,
we prefer to use a by-user configuration to a system wide one. I.e. you should try
to use configuration files in your home directory, rather than in root
owned system files.
TL;DR (Let's get going already!)
Reboot and plugin your external USB sound-card, so we start on the same page...
A. Collect some info
# Check ALSA modules
cat /proc/asound/modules
0 snd_bcm2835
1 snd_usb_audio
# Check sound hardware
cat /proc/asound/cards
0 [ALSA ]: bcm2835 - bcm2835 ALSA
bcm2835 ALSA
1 [Set ]: USB-Audio - C-Media USB Headphone Set
C-Media USB Headphone Set at usb-3f980000.usb-1.5, full speed
# Check info on card-1
amixer -c 1
Simple mixer control 'Headphone',0
Capabilities: pvolume pswitch pswitch-joined
Playback channels: Front Left - Front Right
Limits: Playback 0 - 151
Mono:
Front Left: Playback 104 [69%] [-8.88dB] [on]
Front Right: Playback 104 [69%] [-8.88dB] [on]
Simple mixer control 'Mic',0
Capabilities: pvolume pvolume-joined cvolume cvolume-joined pswitch pswitch-joined cswitch cswitch-joined
Playback channels: Mono
Capture channels: Mono
Limits: Playback 0 - 32 Capture 0 - 16
Mono: Playback 23 [72%] [34.36dB] [off] Capture 0 [0%] [0.00dB] [on]
Simple mixer control 'Auto Gain Control',0
Capabilities: pswitch pswitch-joined
Playback channels: Mono
Mono: Playback [on]
Here we see that the system default (card 0
) is using the bcm2835 ALSA module.
Although we can usually specify what card to use, some software like omxplayer
doesn't have this option, and will fail to produce any sound in various ways.
At this point you could already attempt to configure your ALSA config files.
Some are successful, while many others aren't because it is not obvious how
and where this should be done. What we ultimately want, is to tell our system
to use our external USB sound card.
B. Remove Audio Bloat
Unless you have very good reasons to keep PulseAudio (PA) or
additional JACK server software, you should uninstall them,
if they are there. They tend to interfere with ALSA, as they take control
of many ALSA functions, and all the additional configurations necessary
by those make things incredibly confusing!
sudo apt-get remove pulseaudio
# You can keep `jack*`, but make sure it is not running.
# If it is running you need to stop it, disble it or remove it.
service --status-all
# Disable the running service with:
sudo systemctl disable xxxxx
C. Disable the internal (Broadcom) sound card
The internal soundcard is driven by the kernel module in:
/lib/modules/4.9.59-v7+/kernel/sound/arm/snd-bcm2835.ko
Unless you are planning to use the audio jack (in 1) or HDMI (in 2),
you should disable this kernel module. There are two methods to do this.
- Disable it with a boot config flag
- Prevent it from getting loaded into kernel by the
modprobe.d
daemon
Trying to stay with our minimalistic approach, we choose (1).
# Edit boot config with:
sudo nano /boot/config.txt
# so that:
cat /boot/config.txt
...
# Enable audio (loads snd_bcm2835)
#dtparam=audio=on
dtparam=audio=off
...
# You need to reboot!
sudo reboot now
If for some reason, you prefer to use method (2), then you need to
blacklist the kernel module. To do this, you simply enter the the
word blacklist
, followed by name of the module in any *.conf
file
under /etc/modprobe.d/
. However, there is already an empty, reserved
file there, called raspi-blacklist.conf
for this purpose. However,
after 6 months, you will have forgotten about this, and what it
contains, so you are better off naming it after the module you are
blacklisting.
cd /etc/modprobe.d/
# Manually edit a new file: blacklist-snd_bcm2835.conf
#sudo nano blacklist-snd_bcm2835.conf
# And add the line: blacklist snd_bcm2835
## OR directly with:
sudo tee /etc/modprobe.d/blacklist-snd_bcm2835.conf <<EOF
blacklist snd_bcm2835
EOF
# You need to reboot!
sudo reboot now
What's the difference? None, AFAICT.
After reboot, re-check your sound modules.
$ cat /proc/asound/modules
1 snd_usb_audio
$ cat /proc/asound/cards
1 [Set ]: USB-Audio - C-Media USB Headphone Set
C-Media USB Headphone Set at usb-3f980000.usb-1.5, full speed
Bom! Your annoying bcm2835 (card 0
) is gone, but the index of the USB card is the same!
This is actually good.
Configure your ALSA
As I already mentioned, we want ALSA to use our own USB sound card as
the default. This also means that we want it to have the first available
index in the list of the kernel sound modules. Since the module was
removed above and the index is the same (card 1), we are good. But in
case we need to load bcm2835 again, we are not, as that module would
re-appear as the first one (card 0
).
We simply need to tell ALSA what our defaults PCM card index should be
and in what order they should be prioritized in the kernel.
There are 3 places where you can configure your ALSA.
- the user config in:
~/.asoundrc
- the system config in:
/usr/share/alsa/alsa.conf
- the system module conf in:
/lib/modprobe.d/aliases.conf
The first 2 changes the default devices, whereas the last,
ensure the order of appearance.
We first fix our user specific config to use card 1
.
If you have more than one cards shown, then select the
index of one you want to be default.
#cat ~/.asoundrc
cat << EOF | tee ~/.asoundrc
pcm.!default {
type hw
card 1
}
ctl.!default {
type hw
card 1
}
EOF
Next, we fix the system config, using the same card index numbers as above.
We need to do this, because some system packages would never see your user
config file.
sudo nano /usr/share/alsa/alsa.conf
# then replace:
#defaults.ctl.card 0
#defaults.pcm.card 0
# with:
defaults.ctl.card 1
defaults.pcm.card 1
Now reboot for the changes to take effect.
You should now have a working audio system.
Let's test it!
To perform a proper test, you need proper files to test with. So before
anything, make sure all your sound and video files are actually working.
(I spent considerable time trying to get some h264/mp4 test video to play
audio, only to discover later, that it never had any audio encoded! Duh!)
WARNING If you are trying to test videos that use the MPEG-2
or VC-1
codecs, you have to
buy (!) a codec key
from the RPi organization to be able to fully decode it with the built-in
hardware decoders. Otherwise, you need to convert the files first.
You can check if your codec is enabled with:
# Check with:
vcgencmd codec_enabled MPG2
vcgencmd codec_enabled WVC1
You will need some verified files to test with. You can download and use these if you don't have any.
# get some demo sound and video files
cd ~/Music
wget -Lk http://rpf.io/lamp3 -O example_11k.mp3
wget -Lk http://www.kozco.com/tech/piano2-CoolEdit.mp3 -O pianoTest_48k.mp3
wget -Lk http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_2mb.mp4 -O bbb_720p_2mb.mp4
wget -Lk https://raw.githubusercontent.com/mediaelement/mediaelement-files/master/big_buck_bunny.mp4 -O bbb_360_22k.mp4
Next, let's PLAY!!
# Double-check!
aplay -l && arecord -l
**** List of PLAYBACK Hardware Devices ****
card 1: Set [C-Media USB Headphone Set], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0
**** List of CAPTURE Hardware Devices ****
card 1: Set [C-Media USB Headphone Set], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0
# Play white noise on 2-channels (L/R) on Card-1
speaker-test -c2 -D hw:1,0
# Play a WAV sound file
speaker-test -c2 -D hw:1,0 --test=wav -w /usr/share/sounds/alsa/Front_Center.wav
# Once the correct default card+device is set, and after reboot,
# then full left/right voice test (above) is performed, just by:
speaker-test -c2 -twav
# Record some sounds (with a VU bar):
arecord --device=hw:1,0 --format S16_LE --rate 44100 -c1 -V mono test.wav
# Play recorded sounds
aplay -D plughw:1,0 test.wav
# Play recorded sounds (sample rate have to be equal)
speaker-test -c2 -D plughw:1,0 -r 44100 --test=wav -W $HOME -w test.wav
# Install an MP3 player
sudo apt-get install mpg123
# Play some MP3 file
mpg123 -v -r 44100 some.mp3
# Play an MP3 sound stream
mpg123 http://ice1.somafm.com/u80s-128-mp3
# This plays video, but no sound!
omxplayer -o alsa /opt/vc/src/hello_pi/hello_video/test.h264
# This plays video and sound!
omxplayer -o alsa bbb_720p_2mb.mp4
# The following plays sometimes (!?) and at the wrong speed!
omxplayer -o alsa some.mp3
YOU ARE GOOD TO GO!
[optional] Order of Additional Audio Hardware
NOTE If you use this section you need to change all the card index values in the above sections!
If you have attached additional audio hardware, and it doesn't show up as you want, you can force to re-arrange the order in which the modules appear, in the /lib/modprobe.d/aliases.conf
file.
Some solutions have proposed to make changes in this file. Unfortunately, they are not aware that the RPi default USB sound module is misspelled! So the changes never take effect. The sound kernel module we are concerned with, is called snd_usb_audio
and not snd-usb-audio
. The filename is snd-usb-audio.ko
and located in: /lib/modules/4.9.59-v7+/kernel/sound/usb/
.
Funny enough, the text in the file says it doesn't need to be modified!
sudo nano /lib/modprobe.d/aliases.conf
#--------------------------------------
# For original (out-of-box) use
#--------------------------------------
# replace this:
options snd-usb-audio index=-2
# with this:
options snd_usb_audio index=-2
#--------------------------------------
# To change the index & order
#--------------------------------------
# Set the index value of the cards:
options snd_usb_audio index=0
options snd_bcm2835 index=1
# Set the order:
options snd slots=snd_usb_audio,snd_bcm2835
References: