|
|
|
@ -1,13 +1,54 @@ |
|
|
|
|
Title: Unofficial ALSA API documentation |
|
|
|
|
Author: Alessandro Mauri |
|
|
|
|
|
|
|
|
|
# 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: |
|
|
|
|
|
|
|
|
|
* ALSA documentation [main page](https://www.alsa-project.org/alsa-doc/alsa-lib/index.html) |
|
|
|
|
- The [PCM interface](https://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Unofficial links: |
|
|
|
|
|
|
|
|
|
* [Userspace documentaion](https://alsa.opensrc.org/) |
|
|
|
|
|
|
|
|
|
## Functions |
|
|
|
|
All the functions I encountered and some documentation / explanation |
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
### Interfaces |
|
|
|
|
TODO |
|
|
|
|
[//]: # (TODO explain what interfaces are) |
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
### 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: |
|
|
|
|
|
|
|
|
|
```c |
|
|
|
|
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 |
|
|
|
@ -112,3 +153,123 @@ int main (int argc, char *argv[]) |
|
|
|
|
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 soundcard. 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 behaviour is that if the resources are already in use with another |
|
|
|
|
application, then it blocks the caller, until resources are free. |
|
|
|
|
|
|
|
|
|
**Non blocking mode (SND_PCM_NONBLOCK)**: 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 (SND_PCM_ASYNC)**: |
|
|
|
|
|
|
|
|
|
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 temporarly |
|
|
|
|
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 |
|
|
|
|
|
|
|
|
|
```c |
|
|
|
|
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 luckly 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` |
|
|
|
|
|
|
|
|
|
```c |
|
|
|
|
int snd_pcm_open (snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode); |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
ARGS: |
|
|
|
|
|
|
|
|
|
* `(const char)name`: PCM name identifier |
|
|
|
|
* `(snd_pcm_stream_t)stream`: wanted stream |
|
|
|
|
* `(int)mode`: mode of opening, valid modes are |
|
|
|
|
- 0: blocking mode |
|
|
|
|
- SND_PCM_NONBLOCK: non blocking mode |
|
|
|
|
- SND_PCM_ASYNC: async notification mode |
|
|
|
|
|
|
|
|
|
RESULT: |
|
|
|
|
|
|
|
|
|
* `(snd_pcm_t)pcmp`: PCM handle, link to the PCM's defining struct. After use |
|
|
|
|
the handle should be passed to `snd_pcm_close()` to close and free the resources. |
|
|
|
|
|
|
|
|
|
RETURN: `(int)` 0 on success or negative code on error |
|
|
|
|
|
|
|
|
|
#### `snd_pcm_close` |
|
|
|
|
Close a PCM handle freeing the allocated resources |
|
|
|
|
|
|
|
|
|
```c |
|
|
|
|
int snd_pcm_close (snd_pcm_t *pcm); |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
ARGS: |
|
|
|
|
|
|
|
|
|
* `(snd_pcm_t *)pcm`: the PCM handle to close |
|
|
|
|
|
|
|
|
|
RESULT: RETURN: `(int)` 0 on success or negative code on error |
|
|
|
|
|
|
|
|
|
#### `snd_pcm_nonblock` |
|
|
|
|