me
Home | Recipies | Gitea | Github | Atom feed | Donate using Liberapay

Unofficial ALSA API documentation

ALSA has to be the worst documented API in the whole FOSS world, so since I had to go trough the pain of reverse-engineering other programs I thought to save you form the same pain. So I present to you the most half-hassed description of the ALSA API on the interweb.

Official links:

Unofficial links:

Functions

All the functions I encountered and some documentation / explanation


Interfaces


Streams

In ALSA a stream is the collection of audio data flowing from an application to a card (playback), or from a card to an application (capture). ALSA uses the ring buffer to store outgoing (playback) and incoming (capture, record) samples. There are two pointers being maintained to allow a precise communication between application and device; pointing to current processed sample by hardware and last processed sample by application. The modern audio chips allow to program the transfer time periods. It means that the stream of samples is divided to small chunks. Device acknowledges to application when the transfer of a chunk is complete.

The type of stream (or the direction in which sound is flowing) can be either capture or playback and is determined by snd_pcm_stream_t which is defined as:

typedef enum _snd_pcm_stream {
    SND_PCM_STREAM_PLAYBACK = 0, // Playback stream
    SND_PCM_STREAM_CAPTURE,   // Capture stream
    SND_PCM_STREAM_LAST = SND_PCM_STREAM_CAPTURE
} snd_pcm_stream_t;

Hints

Hints are names, descriptions and other information about sound cards, interfaces and others. To get access to those hints there is a family of functions.

snd_device_name_hint

Get hints from a specified card of specified interface

int snd_device_name_hint (int card, const char *iface, void ***hints);

ARGS:

RESULT:

RETURN: (int) 0 on success or negative error code

snd_device_name_get_hint

Extract selected hint form hints array

char* snd_device_name_get_hint (const void *hint, const char *id);

ARGS:

RESULT: RETURN: (char *) gives a pointer to a string containing the requested hint or NULL on error, the result should be freed when done.

snd_device_name_free_hint

Free hints array

int snd_device_name_free_hint (void **hints);

ARGS:

RETURN: (int) 0 on success or negative code on error

Example

Get hints from all pcms of all cards and print them out

#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>

#include <alsa/asoundlib.h>

int main (int argc, char *argv[])
{
    void **hints, **n;
    char *name, *descr, *descr1, *io;

    if (snd_device_name_hint(-1, "pcm", &hints) < 0)
        return -1;
    n = hints;
    while (*n != NULL) {
        name = snd_device_name_get_hint(*n, "NAME");
        descr = snd_device_name_get_hint(*n, "DESC");
        io = snd_device_name_get_hint(*n, "IOID");
        printf("%s\n", name);
        if ((descr1 = descr) != NULL) {
            printf("    ");
            while (*descr1) {
                if (*descr1 == '\n')
                    printf("\n    ");
                else
                    putchar(*descr1);
                descr1++;
            }
            putchar('\n');
        }
            if (name != NULL)
                free(name);
        if (descr != NULL)
            free(descr);
        if (io != NULL)
            free(io);
        n++;
    }
    snd_device_name_free_hint(hints);
    return 0;
}

PCMs

PCM is an abbreviation for “Pulse Code Modulation”. PCM is how digital audio is typically represented in a computer. The audio signal is represented by samples of its instantaneous amplitude taken at regular intervals the representation of each sample can take several forms.

In ALSA we usually use the term PCM to refer to a PCM device, a PCM device is something like an abstract sound card. It can either be a hardware device or a PCM plugin layer device (like dmix, softvol, etc).

Open modes

Blocking mode (0): when opening a PCM in blocked (which is the default mode) the behavior is that if the resources are already in use with another application, then it blocks the caller, until resources are free.

Non blocking mode (SNDPCMNONBLOCK): the non-blocked mode doesn’t block the caller in any way and instead returns -EBUSY (that is EBUSY * -1) error when the resources are not available.

Asynchronous mode (SNDPCMASYNC):

The opening modes affect all the standard I/O operations (such as writing), in the same way the options operate with open(2) and write(2), so instead of making the calling process wait when the resource is not available, operations return -EAGAIN /* EAGAIN * -1 */, which literally means resource temporarily unavailable. The operation mode for successive (to opening) I/O calls can be changed with the snd_pcm_nonblock() function.

In ALSA PCM devices are controlled trough handles, which are basically pointers to a data structure snd_pcm_t that defines it

typedef struct _snd_pcm {
    char *name;
    snd_pcm_type_t type;
    int stream;
    int mode;
    int poll_fd;
    int setup;
    unsigned int access;        /* access mode */
    unsigned int format;        /* SND_PCM_FORMAT_* */
    unsigned int subformat;     /* subformat */
    unsigned int rate;      /* rate in Hz */
    unsigned int channels;      /* channels */
    size_t fragment_size;       /* fragment size */
    unsigned int fragments;     /* fragments */
    unsigned int start_mode;    /* start mode */
    unsigned int ready_mode;    /* ready detection mode */
    unsigned int xrun_mode;     /* xrun detection mode */
    size_t avail_min;       /* min avail frames for wakeup */
    size_t xfer_min;        /* xfer min size */
    size_t xfer_align;      /* xfer size need to be a multiple */
    unsigned int time: 1;       /* timestamp switch */
    size_t boundary;        /* pointers wrap point */
    unsigned int info;      /* Info for returned setup */
    unsigned int msbits;        /* used most significant bits */
    unsigned int rate_master;   /* Exact rate is rate_master / */
    unsigned int rate_divisor;  /* rate_divisor */
    size_t fifo_size;       /* chip FIFO size in frames */
    size_t buffer_size;
    size_t bits_per_sample;
    size_t bits_per_frame;
    size_t *appl_ptr;
    volatile size_t *hw_ptr;
    int mmap_rw;
    snd_pcm_channel_info_t *mmap_channels;
    snd_pcm_channel_area_t *running_areas;
    snd_pcm_channel_area_t *stopped_areas;
    void *stopped;
    snd_pcm_ops_t *ops;
    snd_pcm_fast_ops_t *fast_ops;
    snd_pcm_t *op_arg;
    snd_pcm_t *fast_op_arg;
    void *private;
} snd_pcm_t;

That’s a lot of stuff but luckily we have functions to operate on this struct.

snd_pcm_open

Open a pcm returning it’s handle that is pointer to it’s defining data structure, snd_pcm_t

int snd_pcm_open (snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode);

ARGS:

RESULT:

RETURN: (int) 0 on success or negative code on error

snd_pcm_close

Close a PCM handle freeing the allocated resources

int snd_pcm_close (snd_pcm_t *pcm);

ARGS:

RESULT: RETURN: (int) 0 on success or negative code on error

snd_pcm_nonblock

Change the non-blocking mode on opened PCMs

int snd_pcm_nonblock (snd_pcm_t *pcm, int nonblock);

ARGS:

RESULT: RETURN: (int) 0 on success or negative code on error