LINUX ALSA Sound Card Programming (1)

xiaoxiao2021-03-06  62

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 (frames) << "frames" << std :: endl

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

转载请注明原文地址:https://www.9cbs.com/read-106648.html

New Post(0)