English Original: http://www.linuxjournal.com/article/6735
Period (cycle): The interval between interrupts in the hardware. It represents the input delay.
There is a pointer in the sound card interface to indicate the current read and write location in the hardware buffer of the sound card. As long as the interface is running, the pointer will loop to a location in the buffer.
Frame size = sizeof (one sample) * Nchannels
The cache (buffer) and the period (size) size configured in ALSA are stored as frames (frames) in runtime.
Period_bytes = Frames_to_bytes (runtime, runtime->period_size);
Bytes_to_frames ()
The period and buffer sizes is not dependent on the sample format because they is measured in frames; You don't need to the change them.
Introduction to ALSA Sound programming
The ALSA represents the Advanced Linux Sound Architecture (Architecture). It consists of a series of kernel-driven, application-compilation interfaces (APIs) and utilities that support sound under Linux. In this article, I will briefly describe the basic framework of the ALSA project and its software composition. The main focus is on PCM interface programming, including examples of programs you can automate.
The reason you're using alsa may be because it's new, but it's not the only sound API available. Alsa is a good choice if you want to perform low-level sound operations to maximize control of sound and maximize performance, or if you use features that are not available in other sound APIs. If you have already written an audio program, you may want to add local support for the ALSA sound card driver. If you are not interested in audio, just want to play audio files, then the Advanced API will be a better choice, such as sdl,openal and those provided by the desktop environment of the toolset. In addition, you can only use ALSA in Linux environments that have ALSA support.
ALSA history
The cause of the ALSA project was that the sound card driver under Linux (Oss/free drivers) was not being actively maintained. And behind the new sound card technology. Jaroslav Kysela earlier wrote a sound card driver, and began the ALSA project, casually, more developers to join the development team, more sound cards are supported, the structure of the API has been reorganized.
Linux kernel 2.5 During the development process, ALSA was incorporated into the official source tree. After kernel 2.6 was released, Alsa was built into a stable kernel version and would be widely used.
Digital Audio Basics
The sound is made up of varying air pressure. It is converted into electronic form by a converter such as a microphone. A modulo/number (ADC) converter converts an analog voltage into a discrete sample value. The sound is sampled at a fixed time interval, and the rate of sampling is called the sample rate. The sample is output to a digital/analog (DAC) converter, such as a loudspeaker, which is then converted to the original analog signal.
The sample size is represented as a bit. Sample size is one of the factors that affect the accuracy of the sound being converted into a digital signal. Another major factor is the sampling rate. In the Nyquist (Nyquist) theory, aliasing can be avoided as long as the Nyquist frequency of the discrete system is higher than the maximum frequency or bandwidth of the sampled signal.
ALSA Foundation
ALSA is made up of sound card drivers for many sound cards, and it also provides a library of APIs called Libasound. Application developers should use Libasound instead of the Alsa interface in the kernel. Because Libasound provides the most advanced and programming-friendly programming interface. and provide a device logic naming function, so that developers do not even need to know similar device files such as low-level interface. Instead, the Oss/free driver is programmed at the kernel system call level, which requires the developer to provide the device file name and use Ioctrl to implement the corresponding function. For backwards compatibility, ALSA provides kernel modules to emulate OSS so that many applications developed on the OSS basis do not require any changes to run on ALSA. In addition, the Libaoss library can emulate OSS, which does not require a kernel module.
The ALSA includes plug-in capabilities, which can be used to extend the new sound card driver, including virtual sound cards that are fully software-enabled. ALSA provides a range of command-line-based toolsets, such as mixer (mixer), audio file player (Aplay), and tools to control specific properties of specific sound cards.
ALSA Architecture
The ALSA API can be decomposed into several main interfaces:
1 Control Interface: Provides common functionality for managing the sound card registration and requesting available devices
2 PCM Interface: manages digital audio playback (playback) and recording (capture) interfaces. The following summary of this article focuses on this interface, as it is the most commonly used interface for developing digital audio programs.
3 Raw MIDI Interface: Supports MIDI (musical instrument Digital Interface), standard electronic musical instruments. These APIs provide access to the MIDI bus on the sound card. This raw interface is based on MIDI event work, and the programmer is responsible for managing the protocol and time processing.
4 Timer Interface: Provides access to the time processing hardware on the sound card for synchronous audio events.
5 Sequencer (Sequencer) connector
6 Mixer (Mixer) interface
Device naming
The API library uses logical device names instead of device files. The device name can be the real hardware name or the plugin name. The hardware name uses a format such as Hw:i,j. Where I is the card number, J is the device number on this sound card. The first sound device is hw:0,0. This alias refers to the first sound device by default and is actually used in the example in this article. The plugin uses a different unique name. For example, PLUGHW: Represents a plug-in that does not provide access to hardware devices, but rather provides software features such as sample rate conversions that the hardware itself does not support.
Sound caching and data transfer
Each sound card has a hardware buffer to hold the recorded samples. When the buffer is full enough, the sound card will produce an interrupt. The kernel sound card driver then uses the Direct memory (DMA) Access channel to transfer the sample to the in-memory application cache. Similarly, for playback, any application uses DMA to transfer its own cache data to the hardware buffers of the sound card.
So the hardware buffers are ring caches. This means that when the data reaches the end of the buffer, it will return to the starting position of the buffer. ALSA maintains a pointer to the hardware cache and the current location of the data operation in the application cache. From the outside of the kernel, we are only interested in the application's buffers, so this article only discusses application buffers.
The size of the application buffer can be controlled by Alsa library function calls. The buffer can be very large, and one transfer operation may result in unacceptable delay, which we call delay (latency). To solve this problem, ALSA splits the buffer into a series of cycles (period) (Oss/free called Fragment fragments). ALSA transmits data as a unit of period.
A cycle (period) stores some frames (frames). Each frame contains a sample of the time at which a point was fetched. For stereo devices, a frame will contain samples on two channels. Figure 1 shows the decomposition process: a buffer is decomposed into cycles, then a frame, then a sample. The figure contains some hypothetical values. The left and right channel information in the diagram is stored alternately in a single frame. This is called interleaved (interleaved) mode. In non-interleaved mode, all sample data for one channel is stored after data from another channel.
Over and under Run
When a sound card is active, data is always transmitted continuously in the hardware buffers and application cache intervals. But there are exceptions. In the recording example, if the application does not read the data quickly enough, the loop buffers will be overwritten with the new data. The loss of this data is known as overrun. In the playback example, if the application writes data to a buffer that is not fast enough, the buffer will "starve". Such errors are referred to as "underrun". In ALSA documentation, these two situations are sometimes collectively referred to as "Xrun". Properly designed applications can minimize xrun and can recover from them.
A typical sound program.
Programs that use PCM typically resemble the following pseudo-code:
Turn on playback or recording interface
Set hardware parameters (access mode, data format, number of channels, sample rate, etc.)
While there is data to be processed:
Read PCM data (recording)
or write PCM data (playback)
Close interface
We'll see some code that works in the next article. I recommend that you test run the code on your Linux system. Review the output and try to modify the recommended code. The list of all instances related to this article can be obtained from ftp: ftp.ssc.com/pub/lj/listings/issue126/6735.tgz.
Listing 1. Display Some PCM Types and Formats
#include <alsa/asoundlib.h> int main () {int val; printf ("Alsa Library version:%s/n", snd_lib_version_str); printf ( "/NPCM stream types:/n"); for (val = 0; Val <= snd_pcm_stream_last; val++) printf ("%s/n", Snd_pcm_stream_name ((snd_pcm_stream_t) val)); printf ("/NPCM access types:/n"); for (val = 0; Val <= snd_pcm_access_last; val++) printf ("%s/n", Snd_pcm_access_name ((snd_pcm_access_t) val)); printf ("/NPCM formats:/n"); for (val = 0; Val <= snd_pcm_format_last; val++) if (Snd_pcm_format_name ((snd_pcm_format_t) val)! = NULL) printf ("%s" (% s)/n ", Snd_pcm_format_name ((snd_pcm_format_t) val), Snd_pcm_format_description ((snd_pcm_format_t) val)); printf ("/NPCM subformats:/n"); for (val = 0; Val <= snd_pcm_subformat_last; val++) printf ("%s (%s)/n", Snd_pcm_subformat_name ((snd_pcm_subformat_t) v AL), Snd_pcm_subformat_description ((snd_pcm_subformat_t) val)); printf ("/NPCM states:/n"); for (val = 0; Val <= snd_pcm_state_last; val++) printf ("%s/n", Snd_pcm_state_name (snd_pcm_state_t) (Val)); return 0; }
Listing one shows some of the PCM data types and parameters used by the ALSA. The first thing to do is include the header file. These header files contain declarations for all library functions. One of them is to display the version of the ALSA library.
The remainder of this program iterates over some PCM data types, starting with the stream type. ALSA provides the symbolic constant name for the last value of each iteration, and provides a function function to display a description string for a particular value. You will see that ALSA supports many formats, in my 1.0.15 version, supports up to 36 formats.
This program must be linked to the Alsalib library by adding the-lasound option at compile time. Some ALSA library functions use Dlopen functions and floating-point operations, so you may also need to add-LDL,-LM options.
The following is the makefile of the program:
cc=gcc
Target=test
src=$ (wildcard *.c)
Object= ${SRC:.C=.O}
Includes=-i/usr/include/alsa
Ldflags=-lasound
all:$ (TARGET)
$ (OBJECT): $ (SRC)
$ (CC)-C $ (includes) $<
$ (TARGET): $ (OBJECT)
$ (CC)-O $@ $< $ (ldflags)
. Phony:clean
Clean
@rm-RF $ (OBJECT) $ (TARGET) *~
Listing 2. Opening PCM Device and Setting Parameters
/* This example opens the default PCM device, sets some parameters, and then displays the value of the most of the hardware PA Rameters. It does not perform any sound playback or recording. */* Use the newer ALSA API */#define ALSA_PCM_NEW_HW_PARAMS_API/* All of the ALSA library APIs is defined * in this hea Der */#include <alsa/asoundlib.h> int main () {int rc; snd_pcm_t *handle; snd_pcm_hw_params_t *params; unsigned int Val, Val2; int dir; snd_pcm_uframes_t frames; /* Open PCM device for playback. */rc = Snd_pcm_open (&handle, "Default", Snd_pcm_stream_playback, 0); if (RC < 0) {fprintf (stderr, "Unable to open PCM device:%s/n", Snd_strerror (RC)), exit (1),}/* Allocate a hardware P Arameters object. */Snd_pcm_hw_params_alloca (¶MS); /* Fill it in with default values. */Snd_pcm_hw_params_any (handle, params); /* Set the desired hardware parameters. */* Interleaved mode */snd_pcm_hw_params_set_access (handle, params, snd_pcm_access_rw_interleaved); /* Signed 16-bit Little-endian format */Snd_pcm_hw_params_set_format (handle, params, snd_pcm_format_s16_le); /* Channels (Stereo) */snd_pcm_hw_params_set_channels (handle, params, 2); /* 44100 Bits/second sampling rate (CD quality) */val = 44100; Snd_pcm_hw_params_set_rate_near (handle, params, &val, &dir); /* Write The parameters to the driver */rc = Snd_pcm_hw_params (handle, params); if (RC < 0) {fprintf (stderr, "Unable to set HW parameters:%s/n", Snd_strerror (RC)), exit (1),}/* Display information About the PCM interface */printf ("PCM Handle name = '%s '//n", Snd_pcm_name (handle)); printf ("PCM state =%s/n", Snd_pcm_state_name (Snd_pcm_state (handle))); Snd_pcm_hw_params_get_access (params, (snd_pcm_access_t *) &val); printf ("Access type =%s/n", Snd_pcm_access_name ((snd_pcm_access_t) val)); Snd_pcm_hw_params_get_format (params, &val); printf ("format = '%s ' (%s)/n", Snd_pcm_format_name ((snd_pcm_format_t) val), Snd_pcm_format_description ((snd_pcm_ format_t) (Val)); Snd_pcm_hw_params_get_Subformat (params, (snd_pcm_subformat_t *) &val); printf ("Subformat = '%s ' (%s)/n", Snd_pcm_subformat_name ((snd_pcm_subformat_t) val), Snd_pcm_subformat_description (( snd_pcm_subformat_t) (Val)); Snd_pcm_hw_params_get_channels (params, &val); printf ("channels =%d/n", Val); Snd_pcm_hw_params_get_rate (params, &val, &dir); printf ("rate =%d bps/n", Val); Snd_pcm_hw_params_get_period_time (params, &val, &dir); printf ("Period time =%d us/n", Val); Snd_pcm_hw_params_get_period_size (params, &frames, &dir); printf ("Period size =%d frames/n", (int) frames); Snd_pcm_hw_params_get_buffer_time (params, &val, &dir); printf ("Buffer time =%d us/n", Val); Snd_pcm_hw_params_get_buffer_size (params, (snd_pcm_uframes_t *) &val); printf ("Buffer size =%d frames/n", Val); Snd_pcm_hw_params_get_periods (params, &val, &dir); printf ("periods per buffer =%d frames/n", Val); Snd_pcm_hw_params_get_rate_numden (params, &val, &val2); printf ("Exact rate =%d/%d bPs/n ", Val, Val2); val = snd_pcm_hw_params_get_sbits (params); printf ("significant bits =%d/n", Val); Snd_pcm_hw_params_get_tick_time (params, &val, &dir); printf ("Tick time =%d us/n", Val); val = Snd_pcm_hw_params_is_batch (params); printf ("is batch =%d/n", Val); val = Snd_pcm_hw_params_is_block_transfer (params); printf ("is block transfer =%d/n", Val); val = snd_pcm_hw_params_is_double (params); printf ("is double =%d/n", Val); val = Snd_pcm_hw_params_is_half_duplex (params); printf ("is half duplex =%d/n", Val); val = Snd_pcm_hw_params_is_joint_duplex (params); printf ("is joint duplex =%d/n", Val); val = Snd_pcm_hw_params_can_overrange (params); printf ("Can overrange =%d/n", Val); val = snd_pcm_hw_params_can_mmap_sample_resolution (params); printf ("Can mmap =%d/n", Val); val = snd_pcm_hw_params_can_pause (params); printf ("Can pause =%d/n", Val); val = Snd_pcm_hw_params_can_resume (params); printf ("Can resume =%d/n", Val); val = Snd_pcm_hw_params_can_sync_start (params); printf"Can sync start =%d/n", Val); Snd_pcm_close (handle); return 0; }
Listing 2 opens the default PCM device, sets some hardware parameters, and prints out the most commonly used hardware parameter values. It does not do any playback or recording of the operation. Snd_pcm_open Open the default PCM device and set the access mode to playback. This function returns a handle that is stored in the first function argument. The handle is used in the subsequent function. Like any other function, this function returns an integer. If the return value is less than 0, an error occurs with the code function call. If something goes wrong, we use SND_ERRSTR to open the error message and exit.
In order to set the hardware parameters of the audio stream, we need to assign a variable of type Snd_pcm_hw_param. Assign to function macro Snd_pcm_hw_params_alloca. Next, we use the function Snd_pcm_hw_params_any to initialize the variable and pass the previously opened PCM stream handle.
Next, we call the API to set the hardware parameters we need. These functions require three parameters: a PCM stream handle, a parameter type, and a parameter value. We set the stream to interleaved mode, 16-bit sample size, 2 channels, 44100bps sample rate. For sample rates, sound hardware does not necessarily support the exact sample rate we set, but we can use the function snd_pcm_hw_params_set_rate_near to set the sample rate closest to the sample rate we specify. In fact, the hardware parameters will only work if we call the function Snd_pcm_hw_params.
The remainder of the program obtains and prints some PCM stream parameters, including the period and buffer size. The results may vary depending on the sound hardware.
After running the program, do the experiment and change some code. Change the device name to hw:0,0 and see if the result will change. Set different hardware parameters and observe the changes in the results.
Listing 3. Simple Sound Playback
/* This example reads standard from input and writes to the default PCM device for 5 seconds of data. */* Use the newer ALSA API */#define ALSA_PCM_NEW_HW_PARAMS_API #include <alsa/asoundlib.h> int main () {long loo ps int RC; int size; Snd_pcm_t *handle; snd_pcm_hw_params_t *params; unsigned int val; int dir; snd_pcm_uframes_t frames; Char *buffer; /* Open PCM device for playback. */rc = Snd_pcm_open (&handle, "Default", Snd_pcm_stream_playback, 0); if (RC < 0) {fprintf (stderr, "Unable to open PCM device:%s/n", Snd_strerror (RC)), exit (1),}/* Allocate a hardware P Arameters object. */Snd_pcm_hw_params_alloca (¶MS); /* Fill it in with default values. */Snd_pcm_hw_params_any (handle, params); /* Set the desired hardware parameters. */* Interleaved mode */snd_pcm_hw_params_set_access (handle, params, snd_pcm_access_rw_interleaved); /* Signed 16-bit Little-endian format */Snd_pcm_hw_params_set_format (handle, params, snd_pcm_format_s16_le); /* Channels (Stereo) */Snd_pcm_hw_params_set_channels (handle, params, 2); /* 44100 Bits/second sampling rate (CD quality) */val = 44100; Snd_pcm_hw_params_set_rate_near (handle, params, &val, &dir); /* Set period size to frames. */frames = 32; Snd_pcm_hw_params_set_period_size_near (handle, params, &frames, &dir); /* Write The parameters to the driver */rc = Snd_pcm_hw_params (handle, params); if (RC < 0) {fprintf (stderr, "Unable to set HW parameters:%s/n", Snd_strerror (RC)), exit (1),}/* Use a buffer large Enough to hold one period */snd_pcm_hw_params_get_period_size (params, &frames, &dir); Size = frames * 4; /* 2 Bytes/sample, 2 channels */buffer = (char *) malloc (size); /* We want to loop for 5 seconds */Snd_pcm_hw_params_get_period_time (params, &val, &dir); /* 5 seconds in microseconds divided by * period time */loops = 5000000/val; while (Loops > 0) {loops--; rc = Read (0, buffer, size), if (rc = = 0) {fprintf (stderr, "End of File on input/n"); Brea K }else if (rc! = size) {fprintf (stderr, "short read:read%d bytes/n", RC);} rc = Snd_pcm_writei (handle, buffer, frames); if (rc = =-epipe) {/* Epipe means underrun */fprintf (stderr, "underrun occurred/n"); Snd_pcm_prepare (handle);} else if (RC < 0) {fprintf (stderr, "error from Writei:%s/n", Snd_strerror (RC));} else if (rc! = (int) frames) {fprintf (stderr, "short write, write%d frames/n", RC);}} Snd_pcm_drain (handle); Snd_pcm_close (handle); Free (buffer); return 0; }
Listing 3 extends the previous example. Some sound samples are written to the sound card for sound playback. In this example, we read the data from the standard input, read enough data for each period, and then write them to the sound card until the 5-second data is fully transferred.
The beginning of this program is the same as the previous version---Open the PCM device and set the hardware parameters. We used the size of the cycle chosen by the ALSA itself, and requested a buffer of that magnitude to store the sample. Then we find out the cycle time so that we can figure out how many cycles this program will take to be able to play for 5 seconds.
In the loop that processes the data, we read the data from the standard input and populate the buffer with a sample of the cycle. The errors are then checked and handled, which can be caused by the end of the file being reached, or the length of the data being read inconsistent with the length of the data I expected.
We call Snd_pcm_writei to send the data. It operates much like a kernel write system call, except that the size parameter here is calculated as a frame. We check its return code value. A return value of Epipe indicates that a underrun has occurred, allowing the PCM audio stream to enter the Xrun state and stop processing the data. The standard way to recover from this state is to call the Snd_pcm_prepare function and put the PCM stream in the prepared state so that the next time we stream the data to the PCM, it will be able to start processing the data again. If the error code we get is not epipe, we print out the error code and continue. Finally, if the number of frames written is not what we expect, an error message is printed.
The program loops until the 5-second frame is fully transmitted, or the input stream reads to the end of the file. Then we call the Snd_pcm_drain to put all of the sound samples that have not been transferred out of the transmission completely, and finally close the audio stream, releasing the buffer that was dynamically allocated before exiting.
We can see that this program is useless unless the standard input is redirected to other files. Try to run the program with the device/dev/urandom, which generates random data:
./example3 </dev/urandom
Random data produces 5 seconds of white noise.
Then, try redirecting the standard input to the device/dev/null and/dev/zero and comparing the results. Change some parameters, such as sample rate and data format, and see the results change.
Listing 4. Simple sound Recording
/* This example reads from the default PCM device and writes to standard output for 5 seconds of data. */* Use the newer ALSA API */#define ALSA_PCM_NEW_HW_PARAMS_API #include <alsa/asoundlib.h> int main () {long loo ps int RC; int size; Snd_pcm_t *handle; snd_pcm_hw_params_t *params; unsigned int val; int dir; snd_pcm_uframes_t frames; Char *buffer; /* Open PCM Device for recording (capture). */rc = Snd_pcm_open (&handle, "Default", Snd_pcm_stream_capture, 0); if (RC < 0) {fprintf (stderr, "Unable to open PCM device:%s/n", Snd_strerror (RC)), exit (1),}/* Allocate a hardware P Arameters object. */Snd_pcm_hw_params_alloca (¶MS); /* Fill it in with default values. */Snd_pcm_hw_params_any (handle, params); /* Set the desired hardware parameters. */* Interleaved mode */snd_pcm_hw_params_set_access (handle, params, snd_pcm_access_rw_interleaved); /* Signed 16-bit Little-endian format */Snd_pcm_hw_params_set_format (handle, params, snd_pcm_format_s16_le); /* Channels (Stereo) */snd_pcm_hw_params_set_channels (handle, params, 2); /* 44100 Bits/second sampling rate (CD quality) */val = 44100; Snd_pcm_hw_params_set_rate_near (handle, params, &val, &dir); /* Set period size to frames. */frames = 32; Snd_pcm_hw_params_set_period_size_near (handle, params, &frames, &dir); /* Write The parameters to the driver */rc = Snd_pcm_hw_params (handle, params); if (RC < 0) {fprintf (stderr, "Unable to set HW parameters:%s/n", Snd_strerror (RC)), exit (1),}/* Use a buffer large Enough to hold one period */snd_pcm_hw_params_get_period_size (params, &frames, &dir); Size = frames * 4; /* 2 Bytes/sample, 2 channels */buffer = (char *) malloc (size); /* We want to loop for 5 seconds */Snd_pcm_hw_params_get_period_time (params, &val, &dir); loops = 5000000/val; while (Loops > 0) {loops--; rc = Snd_pcm_readi (handle, buffer, frames); if (rc = =-epipe) {/* Epipe means overrun */ fprintf (stderr, "overrun occurred/n"); Snd_pcm_prepis (handle); } else if (RC < 0) {fprintf (stderr, "error from read:%s/n", Snd_strerror (RC));} else if (RC! = (int) frames) {Fprint F (stderr, "short read, read%d frames/n", RC); rc = Write (1, buffer, size); if (rc! = size) fprintf (stderr, "short write:wrote%d bytes/n", RC); } snd_pcm_drain (handle); Snd_pcm_close (handle); Free (buffer); return 0; }
Listing 4 is similar to the program in Listing 3, except for the sound Crawl (recording) when the program is here. When you open the PCM device we specify the open mode as Snd_pcm_stream_cpature. In the main loop, we call Snd_pcm_readi to read the data from the sound card and write them to the standard output. Similarly, we check for overrun, if present, to be treated in the same way as in the previous precedent.
The program running listing 4 will record nearly 5 seconds of sound data and send them to standard output. You can also redirect to a file. If you have a microphone connected to your sound card, you can use a mix program (mixer) to set the recording source and level. In the same way, you can run a CD player program and set the recording source to CD. Try to run Program 4 and direct the output to a file, and then run Program 3 to play the sound data in the file:
./listing4 > Sound.raw
./listing3 < Sound.raw
If your sound card supports full duplex, you can connect two programs through a pipe so you can hear the recorded sound from your sound card:
./listing4 |./listing3
In the same way, you can experiment to see how the sample rate and the change in the sample format will have an impact.
Advanced Features
In the previous example, the PCM stream operates in blocking mode, that is, the PCM interface call will not return until the data has been delivered. In an event-driven interactive program, it is often unacceptable to block applications for long periods of time. The ALSA supports opening the audio stream in nonblocking mode so that the read-write function calls back immediately. If the data transfer is suspended and the call cannot be processed, ALSA is returning an ebusy error code.
Many graphics applications use callbacks to handle events. The ALSA supports an asynchronous way to open a PCM audio stream. This allows a registered callback function to be called when the sample data for a cycle is passed.
The Snd_pcm_readi and Snd_pcm_writei calls used here are similar to the read and write system calls under Linux. The letter I indicates that the processed frames are interleaved (interleaved). The corresponding function of non-interactive mode exists in Alsa. Many devices under Linux also support mmap system calls, which map device memory to main memory so that data can be maintained with pointers. The ALSA also runs in mmap mode to open a PCM channel, which allows valid 0 copies (zero copy) to access the sound data.
Summarize
I hope this article will inspire you to try to write some ALSA programs. With the 2.6 kernel being widely used in the Linux release (distributions), ALSA will also be widely used. Its advanced features will help the Linux audio program to move forward better.
Jaroslav Kysela and Takashi Lwai helped to review the draft of this article and made valuable comments, and expressed appreciation
Original Address http://hi.baidu.com/dillisbest/blog/item/819b1013b8cf075af919b8a9.html