一.介绍
ALSA标准是一个先进的linux声音体系。它包含内核驱动集合,API库和工具对Linux声音进行支持。ALSA包含一系列内核驱动对不同的声卡进行支持,还提供了libasound的API库。用这些进行写程序不需要打开设备等操作,所以编程人员在写程序的时候不会被底层的东西困扰。与此相反OSS/Free驱动在内核层次调用,需要指定设备名和调用ioctl。为提供向后兼容,ALSA提供内核模块模仿OSS/Free驱动,所以大多数的程序不需要改动。ALSA拥有调用插件的能力对新设备提供扩展,包括那些用软件模拟出来的虚拟设备。ALSA还提供一组命令行工具包括mixer, sound file player和工具控制一些特别的声卡的特别的作用。
二.ALSA体系:
ALSA API被主要分为以下几种接口:
l控制接口:提供灵活的方式管理注册的声卡和对存在的声卡进行查询。
lPCM接口:提供管理数字音频的捕捉和回放。
l原始MIDI接口:支持MIDI (Musical Instrument Digital Interface),一种标准电子音乐指令集。这些API提供访问声卡上的MIDI总线。这些原始借口直接工作在TheMIDI事件上,程序员只需要管理协议和时间。
l记时接口:为支持声音的同步事件提供访问声卡上的定时器。
l音序器接口:一个比原始MIDI接口高级的MIDI编程和声音同步高层接口。它可以处理很多的MIDI协议和定时器。
l混音器接口:控制发送信号和控制声音大小的声卡上的设备。
三.声卡的缓存和数据的传输:
一块声卡有一个声卡内存用来存储记录的样本。当它被写满时就产生中断。内核驱动就使用DMA将数据传输到内存中。同样地,当在播放时就将内存中的声音样本使用DMA传到声卡的内存中!
声卡的缓存是环状的,这里只讨论应用程序中的内存结构:ALSA将数据分成连续的片段然后传到按单元片段传输。
四:典型的声音程序结构:
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
五.一些例子:
1.显示一些PCM的类型和格式:
#include <iostream>
#include <alsa/asoundlib.h>
int main()
{
std::cout << "ALSA library version: " << SND_LIB_VERSION_STR << std::endl;
std::cout << "PCM stream types: " << std::endl;
for (int val=0; val <= SND_PCM_STREAM_LAST; ++val)
std::cout << snd_pcm_stream_name((snd_pcm_stream_t)val) << std::endl;
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::endl;
std::cout << std::endl;
std::cout << "PCM subformats: " << std::endl;
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 states: " << std::endl;
for (int val=0; val <= SND_PCM_STATE_LAST; ++val)
std::cout << snd_pcm_state_name((snd_pcm_state_t)val) << std::endl;
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::endl;
std::cout << std::endl;
}
2.打开PCM设备和设置参数
#include <iostream>
#include <alsa/asoundlib.h>
int main()
{
intrc;
snd_pcm_t*handle;
snd_pcm_hw_params_t*params;
unsigned intval, val2;
intdir;
snd_pcm_uframes_tframes;
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(¶ms);
snd_pcm_hw_params_any(handle, params);
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
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(handle, params, &val, &dir);
if ( (rc = snd_pcm_hw_params(handle, params)) < 0)
{
std::cerr << "unable to set hw parameters: " << snd_strerror(rc) << std::endl;
exit(1);
}
std::cout << "PCM handle name = " << snd_pcm_name(handle) << std::endl;
std::cout << "PCM state = " << snd_pcm_state_name(snd_pcm_state(handle)) << std::endl;
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::endl;
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::endl;
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::endl;
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<int>(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::endl;
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_is_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::endl;
snd_pcm_close(handle);
return 0;
}
3.一个简单的声音播放程序
#include <iostream>
#include <alsa/asoundlib.h>
int main()
{
longloops;
intrc;
intsize;
snd_pcm_t*handle;
snd_pcm_hw_params_t*params;
unsigned intval;
intdir;
snd_pcm_uframes_tframes;
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::endl;
exit(1);
}
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(handle, params);
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
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(handle, 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::endl;
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::endl;
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.一个简单的记录声音的程序
#include <iostream>
#include <alsa/asoundlib.h>
int main()
{
longloops;
intrc;
intsize;
snd_pcm_t*handle;
snd_pcm_hw_params_t*params;
unsigned intval;
intdir;
snd_pcm_uframes_tframes;
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::endl;
exit(1);
}
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(handle, params);
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
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::endl;
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::endl;
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 write: wrote " << rc << " bytes" << std::endl;
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
return 0;
}
编译的参数:g++ xxx.cpp -o xxx -lasound
转载地址:http://blog.chinaunix.net/space.php?uid=20664418&do=blog&cuid=2058301
相关推荐
详细介绍linux下 alsa声卡的原理及驱动,数据流程 等
Linux ALSA声卡驱动原理分析- 设备打开过程和数据流程 pptx
--根据源码分析ALSA架构,有图有码(代码,不是马赛克:)),理解非常容易; --ASoC的软硬件架构分析; --具体讲解PCM、Controls、dai; --ASoC架构中的Machine; --ASoC架构中的Codec(举例代码分析); --ASoC架构中的...
以前在自己电脑上遇到的问题,自己记录了一下,希望能帮到大家!
ALSA是Advanced Linux Sound Architecture,高级Linux声音架构的简称,它在Linux操作系统上提供了音频和MIDI(Musical Instrument Digital Interface,音乐设备数字化接口)的支持。
alsa驱动文档
主要介绍了arm linux利用alsa驱动并使用usb音频设备的相关资料,需要的朋友可以参考下
Linux_ALSA声卡驱动原理分析-_设备打开过程和数据流程
Linux ALSA声卡驱动开发最佳实践 pptx
转载,详述了alsa-lib函数流程,帮助理解设备打开和pcm数据传输流程,难得的好文档。
该资源是ALSA项目-C库参考中的sample,包括四个文件(latency.c,pcm.c,pcm_min.c,rawmidi.c,timer.c),对使用alsa-lib应用编程有参考意义
Linux平台下的ALSA声音编程.pdf
Linux ALSA声卡驱动原理分析- 设备打开过程和数据流程.pptx
实践linux, alsa下的speex 回声消除 . http://blog.csdn.net/sunkwei/article/details/6447736
Linux系统自带的声卡驱动程序能够支持的声卡很少, ALSA是一套声卡驱动程序包,它可以支持大多数流行的声卡。模块化架构,支持全双工,数字音频等声卡特性。本文详细介绍ALSA的全部安装配置过程和注意事项,还会给...
一、ALSA架构简介 二、最佳实践的目标、目的、方法 三、具体步骤 四、总结
linux alsa声卡架构图
LinuxALSA声卡驱动之六:ASoC架构中的Machine[归纳].pdf
基于ALSA架构的开发的技术文档,也是自己总结的最好的资料,分析ALSA架构的源码,并给出开发alsa声卡的实例。