ALSA Programming HOWTO
According to ALSA write a simple PCM application, we first need to open a handle for the PCM device (Handle), and then specify the direction of the PCM stream is played or captured (playback or capture), we can also configure some of the parameters we want, for example, Buffer size, sample rate, PCM data format, and so on. So we have a broad framework, simple and efficient, as follows:
/* Handle for the PCM device * * declares a device handle.
snd_pcm_t *pcm_handle;
/* Playback Stream/Set the direction of the audio stream to play
snd_pcm_stream_t stream = Snd_pcm_stream_playback;
/* This structure contains information about * * Declares a hardware configuration structure that is used to configure the appropriate parameters.
/* The hardware and can is used to specify the * * configuration to is used for the
PCM stream. * *
Snd_pcm_h w_params_t *hwparams;
PCM devices have "PLUGHW" and "HW" interfaces in the Alsa interface, but we use the default interface "defaults" here,
Char *pcm_name;//define device name
Pcm_name = StrDup ("Default");
Then we assign a hardware configuration structure
/* Allocate The snd_pcm_hw_params_t structure on the stack. * *
Snd_pcm_hw_params_alloca (&hwparams);
Now we can turn on the device,
/* Open PCM. The last parameter of this function is the mode. */////
If This is set to 0, the standard mode is used. Possible /
* Other values are Snd_pcm_nonblock and Snd_pcm_async. *////
If Snd_pcm_nonblock is used, read/write access to the/
* * PCM device'll return immediately.
Rocessed by the soundcard. */
if (Snd_pcm_open (&pcm_handle, Pcm_name, stream, 0) < 0) {
fprintf (stderr, "Error opening PCM device%s \ n ", pcm_name);
return ( -1);
}
The next part is the most important, the front is basically the process of things, next to say is some of the configuration parameters of the device, to understand that I think it is more important to configure the parameters are: access type, sampling rate, sampling format, channel number, number of period and the size of the period, These parameters are described in detail in the previous section, and if you have questions you can click: http://blog.csdn.net/liuchen_csdn/article/details/52095813
The structure of the configuration hardware initialization, ALSA has given the corresponding function, we can mechanically:
/* Init hwparams with full configuration spaces *
/if (Snd_pcm_hw_params_any (Pcm_handle, Hwparams) < 0) {
fprint F (stderr, "Can not configure this PCM device.\n");
return ( -1);
}
Here's an example: let's assume that the sound card is configured with the following format: Stereo 16Bit Little endian data, sampled at 44100HZ, and then we'll configure our sound card with this parameter:
int rate = 44100; /* Sample rate *
/int exact_rate; /* Sample rate returned by
/* snd_pcm_hw_params_set_rate_near
/int dir; /* Exact_rate = = Rate--> dir = 0
/* exact_rate < rate --> dir =-1 */
* exact_rate > rate
--> dir = 1 *
/int periods = 2; /* Number of Periods * *
snd_pcm_uframes_t periodsize = 8192;/* periodsize (bytes) * *
The configuration parameters described above have the access type parameter, which specifies how the multipath data is stored in buffer, divided into two types: interleaved and noninterleaved, for the former, it means in each cycle (period) Left and right channel data is interleaved, and for the latter, it is in each cycle (period) first to collect the left channel data stored in the buffer, and then sampling the right-hand channel data in buffer, examples are as follows:
/* Set access type. This can is either///////////* snd_pcm_access_rw_noninterleaved. *///* There are also access types for mmaped/* Access, but this is beyond the scope */* of this introd Uction. */if (snd_pcm_hw_params_set_access (Pcm_handle, Hwparams, snd_pcm_access_rw_interleaved) < 0) {fprintf (Stder
R, "Error setting access.\n");
Return (-1); /* Set Sample Format */if (Snd_pcm_hw_params_set_format (Pcm_handle, Hwparams, Snd_pcm_format_s16_le) < 0)
{fprintf (stderr, "Error setting format.\n");
Return (-1); }/* Set sample rate. If the exact rate is not supported/* by the hardware, use nearest possible.
* * Exact_rate = rate; if (Snd_pcm_hw_params_set_rate_near (Pcm_handle, Hwparams, &exact_rate, 0) < 0) {fprintf (stderr, "Error Setti
ng rate.\n ");
Return (-1); } if (Rate!= Exact_rate) {fprintf (stderr, "the rate%d Hz is isn't supported by your hardware.\n Using%d Hz
Instead.\n ", rate, exact_rate); }/* Set number of channels/if (Snd_pcm_hw_params_set_channels (Pcm_handle, Hwparams, 2) < 0) {Fprint
F (stderr, "Error setting channels.\n");
Return (-1); }/* Set number of periods. Periods used to be called fragments. */if (Snd_pcm_hw_params_set_periods (Pcm_handle, hwparams, periods, 0) < 0) {fprintf (stderr, "Error setting
Periods.\n ");
Return (-1); }Then we want to set the size of the buffer, the size of the buffer is determined by the setting of the function, sometimes the parameters are bytes, sometimes need to specify the number of frames, a frame of data size includes all the data size of the channel, such as Stereo 16-bit data, It's one frame is 4Bytes.
/* Set buffer size (in frames). The resulting latency is given by
/* Latency = periodsize * Periods/(Rate * bytes_per_frame) /
if (snd_p Cm_hw_params_set_buffer_size (Pcm_handle, Hwparams, (periodsize * periods) >>2) < 0) {
fprintf (stderr, " Error setting buffersize.\n ");
return ( -1);
}
For the interpretation of the >>2 (periodsize * periods), periodsize This is the number of bytes per period, and the periods specifies the number of cycles that the buffer can hold, and >>2 means dividing by 4, Why divide by four? This is because each frame occupies 4Bytes of bytes, so the result of this (periodsize * periods) >>2 is to assign a total number of frames to be accommodated period cycles.
If your hardware buffer does not support 2^n, you can use Snd_pcm_hw_params_set_buffer_size_near. This function, it will allocate adjacent buffer space.
When all parameters are configured, we want to make these parameters work on the PCM device:
* Apply HW parameter settings
to/* PCM device and prepare device /
if Snd_pcm_hw_params (Pcm_handle, HWPA Rams) < 0) {
fprintf (stderr, "Error setting HW params.\n");
return ( -1);
}
After PCM device configuration, we can play the data, but also note that for interleaved write access, we call:
/* Write Num_frames frames from buffer data to/
* The PCM device pointed to by Pcm_handle. *
/* Returns The number of frames actually written./* snd_pcm_sframes_t Snd_pcm_writei
(pcm_handle, data, Num_f Rames);
For noninterleaved access, we call:
/* Write Num_frames frames from buffer data to/
* The PCM device pointed to by Pcm_handle. *
/* Returns The number of frames actually written./* snd_pcm_sframes_t Snd_pcm_writen
(pcm_handle, data, num_ Frames);
<<<<<<<<<<<<<< the above part is for the playback section, the following section is for the Audio capture section >>>>> >>>>>>>>>>>>>>>>>
It is not possible to use only one PCM device handle to collect and play audio data at the same time, so we have to declare two handles to achieve synchronization. Here are just a few different points:
[1]: The direction of PCM data flow is different
/* Capture Stream * *
snd_pcm_stream_t stream_capture = snd_pcm_stream_capture;
[2]: Parameter configuration and playback, here omitted ...
[3]: Capture function is different AH:
/* Read Num_frames frames from the PCM device/
* pointed to by Pcm_handle to buffer capdata. * * *
Returns The number of frames actually read. * *
Snd_pcm_readn (pcm_capture_handle, Capdata, num_frames);
[4]:
As in the case of playback, we have to take care that application calls the Read function before the capture buffer of The soundcard is completely filled. Otherwise there would be a buffer overrun.
int Pcmreturn;
while ((Pcmreturn = Snd_pcm_readi (Pcm_capture_handle, Capdata, periodsize>>2)) < 0) {
snd_pcm_prepare (pcm _capture_handle);
fprintf (stderr, "<<<<<<<<<<<<<<< Buffer overrun >>>>> >>>>>>>>>>\n ");
}
This is the end of the introduction, the next post will be posted code for reference