Page 1 of 1

Audio on Linux, a small introduction

PostPosted: Thu Sep 05, 2013 11:32 pm
by hansvi
Getting to understand how the Linux sound system works may be a pain in the backside. Once you get to know it a bit better, it turns out it's not the evil monster it appears to be from a distance. Here is a small intro and some things I wish I'd known a lot earlier. I'll just mention some currently popular systems: ALSA, PulseAudio, and PortAudio.

ALSA is part of the linux kernel. It provides device drivers and a few common tools like aplay, arecord, and so on.
PulseAudio Is a sound server. It's a service started by init. It's like a big virtual mixer and switchboard, providing ways to interact witch the sound system without necessarily needing to know where the sound is going.
PortAudio is a cross-platform audio library. It saves the lives and mental health of people who want to play a sound in their cross-platform application.

When interacting with sound devices, you have to know their name. The name consists of multiple parts. The first is the interface:
pulse - it's a virtual device that connects you to the PulseAudio server
hw - directly access the hardware.
plughw - it's like hw, but instead of directly accessing the hardware, it goes through a software convertor if needed

For pulse, that's all you need. You can just type
Code: Select all
aplay -D pulse sound.wav

and it will send the sound.wav file to the PulseAudio server and you'll hear it if everything goes well.

For hw and plughw, you'll need to specify a specific card number. You can list the playback and record devices with these two commands:
Code: Select all
aplay -l
arecord -l

One way to specify a device is to give its number as seen in the device lists. I used to do it that way but there is a better alternative. Anyway, let's give some examples:

Code: Select all
# play on the first sound card using the hw interface
aplay -D hw:0 sound.wav
# play on the second sound card using the plughw interface
aplay -D plughw:1 sound.wav

You don't have to use the number though, and I don't recomend it because it might change if you modify your setup. Let's take a look at the output of aplay -l:
card 0: Intel [HDA Intel], device 0: ALC889 Analog [ALC889 Analog]
Subdevices: 0/1
Subdevice #0: subdevice #0
card 0: Intel [HDA Intel], device 1: ALC889 Digital [ALC889 Digital]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 1: SDR [Peaberry SDR], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0

You can use the name directly following the card number to identify your sound card, e.g.:

Code: Select all
# play on the first sound card using the hw interface
aplay -D hw:Intel sound.wav
# play on the second sound card using the hw interface
aplay -D hw:SDR sound.wav

Sound cards can also have multiple inputs and outputs. Those are called the devices. You specify it this way:
Code: Select all
# play on the first device of the first sound card using the hw interface
aplay -D hw:Intel,0 sound.wav
# play on the second device of the first sound card using the hw interface (the digital output of the internal sound card)
aplay -D hw:Intel,1 sound.wav

The Peaberry V2 USB audio only supports a single data format: 96kHz, 24bit per sample, "packed". Meanwhile, most applications are written for consumer style audio cards, and those often have internal hardware that supports a plethora of formats and data rates. So the software just chooses a convenient format (e.g. 48000, 16 bit), and expects that the sound card can handle this. With the Peaberry, this is not the case. That means that the application fails to open the sound card, and gives an error.

If this happens, you need to use the plughw interface so that the Linux sound system can automatically convert this for you. The full audio device name then becomes "plughw:SDR".

And then there's PortAudio. An application using portaudio will often supply you with a list of cards that you can choose from. There's just one tiny little problem: it doesn't let you choose between hw and plughw. Remember what we just said about the Peaberry requiring plughw? Well, you guessed it, portaudio always chooses hw.

But there is a solution! You just create a new "virtual" card, and you specify that this card uses the plughw filter, and connects to hw:SDR. this can be done by making a .asoundrc file in your home directory and putting this in it:
Code: Select all
pcm.plugSDR {
        type plug
        slave {
                pcm "hw:SDR"

Then you restart alsa:
Code: Select all
/etc/init.d/alsa-utils restart

Et voilĂ ! PortAudio will now have an entry called "plugSDR", and your application will open it!

One last thing I'd like to share: I sometimes hear windows users talk about some software called virtual audio cable or something, allowing you to send output from one application to another. On Linux, this is natively supported. As root, just type
Code: Select all
modprobe snd-aloop

and you have a loopback card with 2 devices with each 8 subdevices (independant channels). You can now send and receive data from device 0 to 1 and vice versa:

Example: on the first console, play a wav file and send it to Loopback device 0 subdevice 0:
Code: Select all
aplay -D hw:Loopback,0,0 sound.wav

On the second console, record the sound coming from Loopback device 1 subdevice 0:
Code: Select all
arecord -D plughw:Loopback,1,0 test.wav

This example uses the first channel (subdevice 0), there are 7 more you can use.

I hope this can be of help, feel free to reply with remarks, corrections, clarifications, or questions.

Hans Van Ingelgom

* Wikipedia article about PulseAudio
* A good explanation of asoundrc