One. Introduction
The ALSA standard is an advanced Linux sound system. It includes kernel driver set, API library and tool support for Linux sound. The ALSA includes a series of kernel drives to support different sound cards and also provides libasound API libraries. Use these writers do not need to open the device, so the programmer will not be troublesome by the underlying thing when the program is written. In contrast OSS / Free drives in kernel level, you need to specify the device name and call IOCTL. To provide backward compatibility, ALSA provides kernel modules to imitate OSS / Free driver, so most programs do not need to be changed. ALSA has the ability to call plugins to extend new devices, including virtual devices that use software simulated. ALSA also provides a set of command line tools including Mixer, Sound File Player, and tools to control some special sound cards.
Two .alsa system:
The ALSA API is mainly divided into the following interfaces:
l Control Interface: Provide flexible way to manage registered sound cards and query the existing sound card.
l PCM interface: Provide capture and playback of managing digital audio.
l Original MIDI interface: Supports MIDI (Musical Instrument Digital Interface), a standard electronic music instruction set. These APIs provide the MIDI bus on the acoustic card. These original excuses work directly on the MIDI event, programmers only need to manage protocols and time.
l Keep interface: Provide a timer on the accessed sound card for a synchronization event that supports sound.
l Sequencer interface: A high-level interface that is higher than the original MIDI interface advanced MIDI programming and sound synchronization. It can handle many MIDI protocols and timers.
l Mixer interface: Control the device on the sound card that controls the sound size.
Third. The transmission of the cache and data of the sound card:
A sound card has a sound card memory to store the recorded sample. When it is filled, it generates an interrupt. The kernel driver uses DMA to transfer data to memory. Similarly, when playback, the sound sample in the memory uses the DMA to the memory of the sound card!
The cache of the sound card is cyclic, only the memory structure in the application is discussed: ALSA divides the data into a continuous fragment and then transmits the unit segment.
4: Typical sound program structure:
Open interface for Capture or Playback
Set Hardware Parameters
(Access Mode, Data Format, Channels, Rate, ETC.)
While there is data to be processed:
Read PCM Data (Capture)
Or Write PCM Data (Playback)
Close Interface
Five. Some examples:
1. Display some types and formats of some PCMs:
#include
#include
int main ()
{
Std :: cout << "ALSA Library Version:" << SND_LIB_VERSION_STR << std :: end1
Std :: cout << "PCM Stream Types: << std :: end1
For (int val = 0; val <= SND_PCM_STREAM_LAST; VAL)
Std :: cout << SND_PCM_STREAM_NAME ((SND_PCM_STREAM_T) VAL) << std :: end1
Std :: cout << std :: endl; std :: cout << "PCM Access Types: << std :: endl;
For (int val = 0; val <= SND_PCM_ACCESS_LAST; VAL)
Std :: cout << SND_PCM_ACCESS_NAME ((SND_PCM_ACCESS_T) VAL) << std :: end1
Std :: cout << std :: endl;
Std :: cout << "PCM Subformats: << std :: end1;
For (int val = 0; val <= SND_PCM_SUBFORMAT_LAST; VAL)
Std :: Cout << SND_PCM_SUBFORMAT_NAME ((SND_PCM_SUBFORMAT_T) VAL) << ("<< SND_PCM_SUBFORMAT_DESCRIPTION (SND_PCM_SUBFORMAT_T) VAL) <<" << std :: endl;
Std :: cout << std :: endl;
Std :: cout << "PCM State: << std :: endl;
For (int val = 0; val <= SND_PCM_STATE_LAST; VAL)
Std :: cout << SND_PCM_STATE_NAME ((SND_PCM_STATE_T) VAL) << std :: end1
Std :: cout << std :: endl;
Std :: cout << "PCM FORMATS: << std :: endl;
For (int val = 0; val <= SND_PCM_FORMAT_LAST; VAL)
Std :: Cout << SND_PCM_FORMAT_NAME ((SND_PCM_FORMAT_T) VAL) << ("<< SND_PCM_FORMAT_DESCRIPTION ((SND_PCM_FORMAT_T) VAL) <<" << "std :: end1
Std :: cout << std :: endl;
}
2. Open PCM device and set parameters
#include
#include
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;
IF ((RC = SND_PCM_OPEN (& Handle, "Default", SND_PCM_STREAM_PLAYBACK, 0) <0)
{
Std :: CERR << "Unable to open pcm devices:" << SND_STRERROR (RC) << std :: endl; exit (1);
}
SND_PCM_HW_PARAMS_ALLOCA (& PARAMS);
SND_PCM_HW_PARAMS_ANY (HANDE, PARAMS);
SND_PCM_HW_PARAMS_SET_ACCESS (Handle, Params, SND_PCM_ACCESS_RW_INTERLEVED);
SND_PCM_HW_PARAMS_SET_FORMAT (Handle, Params, SND_PCM_FORMAT_S16_LE);
SND_PCM_HW_PARAMS_SET_CHANNELS (Handle, Params, 2);
VAL = 44100;
SND_PCM_HW_PARAMS_SET_RATE_NEAR (HANDE, PARAMS, & VAL, & DIR);
IF ((RC = SND_PCM_HW_PARAMS (Handle, Params)) <0)
{
Std :: CERR << "Unable to set hw parameters:" << SND_STRERROR (RC) << std :: end1
Exit (1);
}
Std :: cout << "PCM Handle Name = << SND_PCM_NAME (HANDLE) << std :: end1
Std :: cout << "PCM State =" << SND_PCM_STATE_NAME (SND_PCM_STATE (HANDLE)) << std :: end1
SND_PCM_HW_PARAMS_GET_ACCESS (Params, (SND_PCM_ACCESS_T *) & VAL);
Std :: cout << "Access Type =" << SND_PCM_ACCESS_NAME ((SND_PCM_ACCESS_T) VAL) << std :: end1
SND_PCM_HW_PARAMS_GET_FORMAT (PARAMS, (SND_PCM_FORMAT_T *); & VAL);
Std :: cout << "Format = '" << SND_PCM_FORMAT_NAME ((SND_PCM_FORMAT_T) VAL) << "(" << SND_PCM_FORMAT_DESCRIPTION ((SND_PCM_FORMAT_T) VAL) << "<< std :: end1
SND_PCM_HW_PARAMS_GET_SUBFORMAT (PARAMS, (SND_PCM_SUBFORMAT_T *) & VAL);
Std :: cout << "Subformat = '" <<
SND_PCM_SUBFORMAT_NAME (SND_PCM_SUBFORMAT_T) VAL) << "'(" << SND_PCM_SUBFORMAT_DESCRIPTION ((SND_PCM_SUBFORMAT_T) VAL) << "<<" std :: end1
SND_PCM_HW_PARAMS_GET_CHANNELS (PARAMS, & VAL);
Std :: cout << "channels =" << Val << std :: endl; snd_pcm_hw_params_get_rate (params, & val, & dir);
Std :: cout << "rate =" << VAL << "bps" << std :: endl;
SND_PCM_HW_PARAMS_GET_PERIOD_TIME (Params, & Val, & DIR);
Std :: cout << "Period Time =" << Val << "US" << std :: endl;
SND_PCM_HW_PARAMS_GET_PERIOD_SIZE (Params, & Frames, & Dir);
Std :: cout << "Period size =" << static_cast
SND_PCM_HW_PARAMS_GET_BUFFER_TIME (Params, & Val, & DIR);
Std :: cout << "Buffer Time =" << VAL << "US" << std :: endl;
SND_PCM_HW_PARAMS_GET_BUFFER_SIZE (Params, (SND_PCM_UFRAMES_T *) & VAL);
Std :: cout << "Buffer size =" << Val << "frames" << std :: endl;
SND_PCM_HW_PARAMS_GET_PERIODS (Params, & Val, & DIR);
Std :: cout << "Periods per buffer =" << val << "frames" << std :: endl;
SND_PCM_HW_PARAMS_GET_RATE_NUMDEN (Params, & Val, & Val2);
Std :: cout << "exact rate =" << VAL / VAL2 << "BPS" << std :: end1
Val = SND_PCM_HW_PARAMS_GET_SBITS (params);
Std :: cout << "Significant Bits =" << VAL << std :: endl;
SND_PCM_HW_PARAMS_GET_TICK_TIME (PARAMS, & VAL, & DIR);
Std :: cout << "Tick Time =" << VAL << "US" << std :: endl;
Val = SND_PCM_HW_PARAMS_IS_BATCH (params);
Std :: cout << "is batch =" << val << std :: endl;
Val = SND_PCM_HW_PARAMS_IS_BLOCK_TRANSFER (params); std :: cout << "is block transfer =" << VAL << std :: endl;
Val = SND_PCM_HW_PARAMS_IS_DOUBLE (params);
Std :: cout << "is double =" << VAL << std :: endl;
Val = SND_PCM_HW_PARAMS_IS_HALF_DUPLEX (params);
Std :: cout << "is half duplex =" << val << std :: endl;
VAL = SND_PCM_HW_PARAMS_ION_JOINT_DUPLEX (params);
Std :: cout << "is Joint Duplex =" << Val << std :: endl;
VAL = SND_PCM_HW_PARAMS_CAN_OVERRANGE (params);
Std :: cout << "can overrange =" << VAL << std :: endl;
VAL = SND_PCM_HW_PARAMS_CAN_MMAP_SAMPLE_RESOLUTION (params);
Std :: cout << "can mmap =" << val << std :: endl;
VAL = SND_PCM_HW_PARAMS_CAN_PAUSE (params);
Std :: cout << "can pause =" << val << std :: endl;
VAL = SND_PCM_HW_PARAMS_CAN_RESUME (params);
Std :: cout << "can resume =" << VAL << std :: endl;
Val = SND_PCM_HW_PARAMS_CAN_SYNC_START (params);
Std :: cout << "can sync start =" << VAL << std :: end1
SND_PCM_CLOSE (Handle);
Return 0;
}
3. A simple sound player
#include
#include
int main ()
{
Long loops;
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;
IF ((RC = SND_PCM_OPEN (& Handle, "Default", SND_PCM_STREAM_PLAYBACK, 0) <0) {
Std :: CERR << "Unable to open pcm device:" << SND_STRERROR (RC) << std :: end1
Exit (1);
}
SND_PCM_HW_PARAMS_ALLOCA (& PARAMS);
SND_PCM_HW_PARAMS_ANY (HANDE, PARAMS);
SND_PCM_HW_PARAMS_SET_ACCESS (Handle, Params, SND_PCM_ACCESS_RW_INTERLEVED);
SND_PCM_HW_PARAMS_SET_FORMAT (Handle, Params, SND_PCM_FORMAT_S16_LE);
SND_PCM_HW_PARAMS_SET_CHANNELS (Handle, Params, 2);
VAL = 44100;
SND_PCM_HW_PARAMS_SET_RATE_NEAR (HANDE, PARAMS, & VAL, & DIR);
Frames = 32;
SND_PCM_HW_PARAMS_SET_PERIOD_SIZE_NEAR (HANDLE, PARAMS, & FRAMES, & DIR);
IF ((RC = SND_PCM_HW_PARAMS (Handle, Params)) <0)
{
Std :: CERR << "Unable to set hw paramseters:" << SND_STRERROR (RC) << std :: end1
Exit (1);
}
SND_PCM_HW_PARAMS_GET_PERIOD_SIZE (Params, & Frames, & Dir);
SIZE = frames * 4;
Buffer = new char [size];
SND_PCM_HW_PARAMS_GET_PERIOD_TIME (Params, & Val, & DIR);
LOOPS = 5000000 / VAL;
While (LOOPS> 0) {
LOOPS -;
IF ((RC = Read (0, Buffer, Size) == 0)
{
Std :: CERR << "End of File On Input" << std :: endl;
Break;
}
Else IF (rc! = size)
Std :: CERR << "Short Read: Read" << RC << "Bytes" << std :: endl;
IF ((RC = SND_PCM_WRITEI (Handle, Buffer, Frames) == -EPIPE)
{
Std :: CERR << "underrun occurred" << std :: endl;
SND_PCM_PREPARE (HANDLE);
}
ELSE IF (RC <0)
Std :: CERR << "Error from Writei: << SND_STRERROR (RC) << std :: end1
Else IF (RC! = (int) frames)
Std :: CERR << "Short Write, Write" << rc << "frames" << std :: endl;}
SND_PCM_DRAIN (HANDLE);
SND_PCM_CLOSE (Handle);
Free (buffer);
Return 0;
}
4. A simple record of sound
#include
#include
int main ()
{
Long loops;
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;
IF ((RC = SND_PCM_OPEN (& Handle, "Default", SND_PCM_STREAM_CAPTURE, 0) <0)
{
Std :: CERR << "Unable to open pcm device:" << SND_STRERROR (RC) << std :: end1
Exit (1);
}
SND_PCM_HW_PARAMS_ALLOCA (& PARAMS);
SND_PCM_HW_PARAMS_ANY (HANDE, PARAMS);
SND_PCM_HW_PARAMS_SET_ACCESS (Handle, Params, SND_PCM_ACCESS_RW_INTERLEVED);
SND_PCM_HW_PARAMS_SET_FORMAT (Handle, Params, SND_PCM_FORMAT_S16_LE);
SND_PCM_HW_PARAMS_SET_CHANNELS (Handle, Params, 2);
VAL = 44100;
SND_PCM_HW_PARAMS_SET_PERIOD_SIZE_NEAR (HANDLE, PARAMS, & FRAMES, & DIR);
IF ((RC = SND_PCM_HW_PARAMS (Handle, Params)) <0)
{
Std :: CERR << "Unable to set hw parameters:" << SND_STRERROR (RC) << std :: end1
Exit (1);
}
SND_PCM_HW_PARAMS_GET_PERIOD_SIZE (Params, & Frames, & Dir);
SIZE = frames * 4;
Buffer = new char [size];
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) {
Std :: CERR << "Overrun Occurred" << std :: endl;
SND_PCM_PREPARE (HANDLE);
}
ELSE IF (RC <0)
Std :: CERR << "Error from Read: << SND_STRERROR (RC) << std :: end1
Else IF (RC! = (int) frames)
Std :: CERR << "Short read, read" << rc << "frames" << std :: endl;
RC = Write (1, buffer, size);
IF (rc! = size)
Std :: CERR << "Short Wrote: wrote" << rc << "BYTES" << std :: endl;
}
SND_PCM_DRAIN (HANDLE);
SND_PCM_CLOSE (Handle);
Free (buffer);
Return 0;
}
Compile parameters: g xxx.cpp -o xxx -lasound