今天要在linux下搞音频编程,在网上查阅了一下资料,网上很多资料都是在linux下直接对/dev/dsp进行编程的,因为在以往的linux系统中,我们是可以通过cat  xxx.wav /dev/dsp 来很容易的播放一个音频文件,在应用程序中,也可以直接操作/dev/dsp,实现声音的播放:打开->写入(实际上就能播放)->关闭。

然而在换成了ubuntu-12.04 LST后,我发现/dev中根本找不到dsp,之前直接操作/dev/dsp的程序都无法正常运行,而是 can't find /dev/dsp.

经过我再三查找,发现现在基本上都不用dsp了,大多数人都在用ALSA音频编程(其实我也是个菜鸟)。首先介绍一下一些关于ALSA编程的知识:

1、GNU/Linux 系统下三大主流声卡驱动程序集:
Linux 有三个主流的声卡驱动程序集:OSS/Lite(也称为OSS/Free)、OSS/Full
(商业软件)、ALSA(自由软件)。
 
OSS/Lite 是现在linux内核中自带的声卡驱动程序集,最初由 Hannu Savolainen
开发。后来 Hannu 跑去开发 Open Sound System(也就是上面所说的OSS/Full)。
由于 Hannu 的“逃跑”,RH 资助 Alan Cox 增强 Hannu 开发的驱动程序,并使它们
完全模块化。现在 Alan Cox 是内核声卡驱程集的维护人。OSS/Lite 从kernel-2.0开
始并入内核,现在大家使用的声卡驱程默认都是OSS/Lite中的。
 
OSS/Full 是由 4Front Technologies 开发并销售的商业软件。它可以驱动很多
声卡并且可以用在很多 UNIX 系统中。OSS/Full 完全兼容以前基于 OSS/Lite 开发
的应用程序。作为一个商业软件,你虽然可以使用它,但是你得不到它的源代码,并且
你必须为此而付钱。
 
ALSA 是linux内核的下一代标准声卡驱动集。开始时 Jaroslav Kysela 等人为
Gravis UltraSound Card 开发驱动程序,后来该计划改名为 ALSA「先进的linux音频
体系」,因为他们认为 ALSA 比原来内核中的 OSS/Lite 驱动程序集更优秀,完全可以
代替 OSS/Lite。他们是对的,ALSA 支持的声卡比 OSS/Lite 多,完全兼容以前基于
OSS 开发的程序,SMP(多处理器) 与 线程安全设计,并且从 2.5 分支的内核开始,
ALSA 的驱动程序集开始并入内核,大家可以在今年的 2.6 版本的内核中看到使用它们。
 
2、为什么要使用 ALSA 开发音频程序
首先,ALSA 是 linux 以后声卡驱动程序的标准,OSS/Lite 迟早会从内核中去除。
开发基于 ALSA 的音频程序可以保证以后的兼容。
其次,我们简单比较一下开发基于 OSS 与 ALSA 的方法。
OSS 向应用程序提供了一系列的系统接口。开发基于 OSS 的应用程序需要使用
open,close,ioctl,read,write 等低级系统调用来完成音频设备的控制、音频流的输入
输出。
而 ALSA 则为应用程序开发人员提供了一个优秀的音频库。利用该音频库,开发
人员可以方便快捷地开发出自己的应用程序,细节则留给音频库内部处理。当然 ALSA
也提供了类似于 OSS 的系统接口,不过 ALSA 的开发者建议应用程序开发者使用音频
库而不是驱程API。
 
3、那么我该从何开始呢
第一步当然是安装 ALSA 驱动程序与音频库。
当前 ALSA 有两个分支,一个是以前的0.5版本,一个是现在的0.9。ALSA的开发者
已经不支持0.5版本了,所以我们要使用0.9。大家可以在 ALSA 的主页
www.alsa-project.org 上下载安装。这个页面上的信息对大家安装很有用:
www.alsa-project.org/alsa-doc ,建议先浏览一下。
 
第二步是参考文档与例子。
在 ALSA 的文档页面上有两篇为应用程序开发者提供的文章:
Howto use the ALSA API [
http://www.op.net/~pbd/alsa-audio.html ]
当然,还有音频库API的在线参考:
 
 要是你已经完成以上几步的话,那么你就应该开始开发了。
4. ALSA设备文件结构

我们从alsa在Linux中的设备文件结构开始我们的alsa之旅. 看看我的电脑中的alsa驱动的设备文件结构:

$ cd /dev/snd
$ ls -l crw-rw----+ root audio , -- : controlC0
crw-rw----+ root audio , -- : midiC0D0
crw-rw----+ root audio , -- : pcmC0D0c
crw-rw----+ root audio , -- : pcmC0D0p
crw-rw----+ root audio , -- : pcmC0D1p
crw-rw----+ root audio , -- : seq
crw-rw----+ root audio , -- : timer
$

我们可以看到以下设备文件:

    controlC0 -->                 用于声卡的控制,例如通道选择,混音,麦克风的控制等
midiC0D0 --> 用于播放midi音频
pcmC0D0c --〉 用于录音的pcm设备
pcmC0D0p --〉 用于播放的pcm设备
seq --〉 音序器
timer --〉 定时器

其中,C0D0代表的是声卡0中的设备0,pcmC0D0c最后一个c代表capture,pcmC0D0p最后一个p代表playback,这些都是alsa-driver中的命名规则。从上面的列表可以看出,我的声卡下挂了6个设备,根据声卡的实际能力,驱动实际上可以挂上更多种类的设备,在include/sound/core.h中,定义了以下设备类型:

#define SNDRV_DEV_TOPLEVEL  ((__force snd_device_type_t) 0) 
#define SNDRV_DEV_CONTROL ((__force snd_device_type_t) 1)
#define SNDRV_DEV_LOWLEVEL_PRE ((__force snd_device_type_t) 2)
#define SNDRV_DEV_LOWLEVEL_NORMAL ((__force snd_device_type_t) 0x1000)
#define SNDRV_DEV_PCM ((__force snd_device_type_t) 0x1001)
#define SNDRV_DEV_RAWMIDI ((__force snd_device_type_t) 0x1002)
#define SNDRV_DEV_TIMER ((__force snd_device_type_t) 0x1003)
#define SNDRV_DEV_SEQUENCER ((__force snd_device_type_t) 0x1004)
#define SNDRV_DEV_HWDEP ((__force snd_device_type_t) 0x1005)
#define SNDRV_DEV_INFO ((__force snd_device_type_t) 0x1006)
#define SNDRV_DEV_BUS ((__force snd_device_type_t) 0x1007)
#define SNDRV_DEV_CODEC ((__force snd_device_type_t) 0x1008)
#define SNDRV_DEV_JACK ((__force snd_device_type_t) 0x1009)
#define SNDRV_DEV_LOWLEVEL ((__force snd_device_type_t) 0x2000)  

通常,我们更关心的是pcm和control这两种设备。

5.一些例子,这些例子在官方文档也有,请自行查阅

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=; 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=; 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=; 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=; 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=; 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()
{
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, )) < )
{
std::cerr << "unable to open pcm devices: " << snd_strerror(rc) << std::endl;
exit();
} snd_pcm_hw_params_alloca(&params); 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, ); val = ; snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); if ( (rc = snd_pcm_hw_params(handle, params)) < )
{
std::cerr << "unable to set hw parameters: " << snd_strerror(rc) << std::endl;
exit();
} 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 ;
}
3.)一个简单的声音播放程序
 #include <iostream>
#include <alsa/asoundlib.h> 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, )) < )
{
std::cerr << "unable to open pcm device: " << snd_strerror(rc) << std::endl;
exit();
} snd_pcm_hw_params_alloca(&params); 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, ); val = ; snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); frames = ;
snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir); if ( (rc = snd_pcm_hw_params(handle, params)) < )
{
std::cerr << "unable to set hw paramseters: " << snd_strerror(rc) << std::endl;
exit();
} snd_pcm_hw_params_get_period_size(params, &frames, &dir);
size = frames * ;
buffer = new char[size]; snd_pcm_hw_params_get_period_time(params, &val, &dir); loops = / val; while (loops > ) {
loops--;
if ( (rc = read(, buffer, size)) == )
{
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 < )
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 ;
}
4.)一个简单的记录声音的程序
 #include <iostream>
#include <alsa/asoundlib.h> 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, )) < )
{
std::cerr << "unable to open pcm device: " << snd_strerror(rc) << std::endl;
exit();
} snd_pcm_hw_params_alloca(&params); 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, ); val = ;
snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir); if ( (rc = snd_pcm_hw_params(handle, params)) < )
{
std::cerr << "unable to set hw parameters: " << snd_strerror(rc) << std::endl;
exit();
} snd_pcm_hw_params_get_period_size(params, &frames, &dir); size = frames * ;
buffer = new char[size]; snd_pcm_hw_params_get_period_time(params, &val, &dir); loops = / val; while (loops > )
{
loops --;
rc = snd_pcm_readi(handle, buffer, frames);
if (rc == -EPIPE)
{
std::cerr << "overrun occurred" << std::endl;
snd_pcm_prepare(handle);
}
else if (rc < )
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(, 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 ;
}

注意:编译的时候记得加上参数,g++ xxx.cpp -o xxx -lasound;如果编译时出现如下错误:alsa/asoundlib.h: No such file or directory

缺少一个库:

apt-get install libasound2-dev

OK!

 

ubuntu alsa的更多相关文章

  1. Ubuntu下声卡驱动解决方法alsa

    一.首先介绍一下什么是ALSA : Advanced Linux Sound Architecture 的简称为 ALSA ,译成中文的意思是先进的Linux声音架构(这是google翻译的):一谈到 ...

  2. Ubuntu 杂音 alsa*

    $ sudo alsactl init # 初始化 $ sudo alsactl store # 存储状态 会调的话可以 $ alsamixer

  3. ubuntu声音系统

    查看声卡:cat /proc/asound/cards 显示所有ALSA的组件:cat /proc/asound/device aplay -l ubuntu使用pulseaudio,是ALSA(先进 ...

  4. sysv-rc-conf管理Ubuntu server开机启动服务

    在RedHat中,都是使用chkconfig来管理服务的,但是在Ubuntu Server中,却有一个更好的工具,chkconfig也是可以使用的.今天来说一下sysv-rc-conf sysv-rc ...

  5. ubuntu入门

    Ubuntu的发音 Ubuntu,源于非洲祖鲁人和科萨人的语言,发作 oo-boon-too 的音.了解发音是有意义的,您不是第一个为此困惑的人,当然,也不会是最后一个:) 大多数的美国人读 ubun ...

  6. ubuntu下编译VLC

    ubuntu下编译VLC 标签(空格分隔): ubuntu vlc 视频 编译 [TOC] 1.下载VLC源码包并解压 VLC的源码包在VLC的官网有,可以直接下载.也可以使用git来clone一个. ...

  7. ubuntu中的Wine详解

    什么是wine?(转自百度百科,具体看百科) wine,是一款优秀的Linux系统平台下的模拟器软件,用来将Windows系统下的软件在Linux系统下稳定运行,该软件更新频繁,日臻完善,可以运行许多 ...

  8. Ubuntu升级没有声音的解决方法

    自从安装U14.04LTS版本后,每次开机都会弹出update窗,以前因为网络速度慢没更新成功过,这回环境允许就尝试了下这个过程,很顺利,可更新后没声音了,找了N中方法来解决,像更改配置文件/etc/ ...

  9. Ubuntu下编译内核

    一.下载源代码和编译软件的准备 下载内核源代码:http://www.kernel.org/ 注意,点击2.6.25内核的F版,即完整版. 如果你懒得去网站点联接,运行下列命令:  代码: $cd ~ ...

随机推荐

  1. PHP——安装wampserver丢失MSVCR110.dll

    win8系统 64位,在安装wampserver时显示计算机丢失MSVCR110.dll   1.首先是打开浏览器,在浏览器的地址栏里输入 http://www.microsoft.com/zh-CN ...

  2. .NET中使用FastReport实现打印功能

    FastReport是功能非常强大的报表工具,在本篇文章中讲解如何使用FastReport实现打印功能. 一.新建一个窗体程序,窗体上面有设计界面和预览界面两个按钮,分别对应FastReport的设计 ...

  3. Java设计模式(18)策略模式(Strategy模式)

    Strategy是属于设计模式中 对象行为型模式,主要是定义一系列的算法,把这些算法一个个封装成单独的类. Stratrgy应用比较广泛,比如,公司经营业务变化图,可能有两种实现方式,一个是线条曲线, ...

  4. 12 extremely useful hacks for JavaScript

    In this post I will share 12 extremely useful hacks for JavaScript. These hacks reduce the code and ...

  5. 【转】web前端到底怎么学?干货资料!

    一般据我经验,在喜欢并且决定和她恋爱之前,我都会做一下充分准备和调查,有必要了解和研究清楚 ‘她’ 的几个特性和习惯 web前端的基本工作职责 和基础技能(要清楚) web前端的分类和门派(简要概述, ...

  6. 工行金邦达USBKey 在Mac OS的 Parallels Desktop 的虚拟Win7出现“ PKCS11

    由于经常用到支付宝的工行付款,所以在我的mac os中安装了Parallels Desktop 7(Win7旗舰版),但随之而来的问题是,运行PD后,再插入工行的USBkey,运行工具箱后出现“PKC ...

  7. USB学习笔记连载(十二):USB描述符

    USB设备是端口,接口,配置的集合,USB协议是以各种USB描述符来表征USB设备的功能.计算机通过这些描述符来获得USB设备的功能. USB描述符包括: USB标准设备描述符,USB集线器描述符.H ...

  8. 【转】]监听SMS消息/编程实现短信拦截

    当设备接收到一条新的SMS消息时,就会广播一个包含了android.provider.Telephony.SMS_RECEIVED动作的Intent.注意,这个动作是一个字符串值,SDK 1.0不再包 ...

  9. Python之使用PIL实现cv2

    有时候使用cv2需要安装opencv,但是opencv安装比较麻烦,因为需要编译过程. 所以,我们可以使用PIL对cv2的一些常用接口进行复现. 这里我们实现了cv2的imread(), imwrit ...

  10. C艹复合类型(字符串)

    在C艹中有两种字符串形式, 一种是C-风格, 另一种是C艹风格的 初始化: char str[10] = {'a', 'c', 'd', '\0'};char str[20]= “aaa”; stri ...