ALSA编程细节分析
[Loong]:之前写过基于ALSA的WAV播放录音程序,见http://blog.csdn.net/sepnic/archive/2011/01/14/6140824.aspx。现在本想好好整理一下ALSA的编程思想,但Google了一下,发现已经有同道做了类似的工作,故将其转载过来,并添加一些本人的疑问以及补充(将会继续补充,原文很多重要的ALSA参数没有提到)。
原文:http://blogold.chinaunix.net/u3/112227/showart_2251390.html
一. 编程细节
按照上面的流程,其中有许多细节我们可以加以控制,这里仅仅指出应用程序需要关心的:
1.1 设备层次
在alsa驱动这一层,目前为止,抽象出了4层设备:
一是hw:0,0;
二是plughw:0,0;
三是default:0;
四是default。
至于一是清楚了,二和二以上可以做数据转换,以支持一个动态的范围,比如你要播放7000hz的东西,那么就可以用二和二以上的。而你用7000hz作为参数,去设置一,就会报错。三和四,支持软件混音。我觉得default:0表示对第一个声卡软件混音,default表示对整个系统软件混音。
这里提出两点:
1.1.1 一般为了让所有的程序都可以发音,为使用更多的默认策略,我们选用三和四,这样少一些控制权,多一些方便。
1.1.2 对不同的层次的设备,相同的函数,结果可能是不一样的。比如,设置Hardware Parameters里的period和buffer size,这个是对硬件的设置,所以,default和default:0这两种设备是不能设置的。
如果直接操作hw:0,0,那么snd_pcm_writei只能写如8的倍数的frame,比如16、24等,否则就会剩下一点不写入而退回,而 default,就可以想写多少就写多少,我们也不必要关心里面具体的策略。
[Loong]:之前都是使用了default,还真没留意过这些设备有何区别。
1.2 Hardware Parameters
说明:之所以叫做Hardware Parameters,是因为alsa这一层api是较为底层的,它允许用户对audio interface和alsa-core两层都做设置。其中对alsa-core设置,叫做Software Parameters,而对audio interface的设置叫做Hardware Parameters。(当然要设置hardware parameters,也肯定是通过alsa驱动来完成,只不过哪些参数是指导硬件的,哪些是指导alsa-core的,分开设置了)
1.2.1 Sample rate: 采样率
1.2.2 Sample format: 采用格式
1.2.3 Number of channels: 声道数
1.2.4 Data access and layout:
简单点说,在一个period以内,数据是按照channel1排完了再排channel2呢,还是一个frame一个frame的来排(frame在alsa里指的是一次采样时间内,两个channel的数据放一块儿就是一个frame)。默认是第二种。
1.2.5 Interrupt interval:
中断间隔,就是靠periods决定的,有函数来设置periods,也就是说这个hardware buffer在一次遍历之内,要中断多少次,来通知alsa-driver来写入或读走数据。比如buffer是8192个frame大,而 period设为4个frame大,那么比如playback,则每当有4个frame大的hardware buffer空间空出,就会中断,通知内核(alsa驱动)来写如数据。这个是影响实时效果的关键。一般不用调整。
1.2.6 Buffer size:
hardware buffer的大小,如果alsa整套体系主要靠这个来做缓冲,那么这个的大小,将影响缓冲效果,但是一般也不调整。
[Loong]:缺少buffer time、peroid time、peroid size等参数说明,这些参数一般情况下都要设置的。
1.3 Software Parameters
1.3.1 snd_pcm_sw_params_set_avail_min (playback_handle, sw_params, 4096)
这个仅用在interrupt-driven模式。这个模式是alsa驱动层的,不是硬件interrupt。它的意思是,用户使用 snd_pcm_wait()时,这个实际封装的是系统的poll调用,表示用户在等待,那么在等待什么呢?对于playback来讲,就是等待下面的声卡的hardware buffer里有一定数量的空间,可以放入新的数据了,对于record来讲,就是等待下面声卡新采集的数据达到了一定数量了。这个一定数量,就是用 snd_pcm_sw_params_set_avail_min来设置,单位是frame。实际运作,没读驱动代码,不是很清楚,可能是alsa驱动根据用户设的这个参数,来设置Hardware Parameters里面的period,也可能是不改变硬件的period,每次硬件中断还是copy到自己的空间,然后数据积累到一定数量再 interrupt应用程序,使之从wait()出来。我不知道,也不必深究。
这种模式的使用,需要用户在snd_pcm_wait()出来以后,调用一个平常的wirtei或readi函数,来写入或读取一定数量的数据。如果用户不用interrupt-driven模式,那么这个函数不必使用。
[Loong]:什么是interrupt-driven模式?
1.3.2 snd_pcm_sw_params_set_start_threshold (playback_handle, sw_params, 0U)
这个函数指导什么时候开启audio interface的AD/DA,就是什么时候启动声卡。
对于playback,假设第三个参数设为320,那么就是说,当用户调用writei,写入的数据,将暂时存在alsa驱动空间里,当这个数据量达到 320帧时,alsa驱动才开始将数据写入hardware buffer,并启动DA转换。对于record,当用户调用readi,这个数据量达到320帧时,alsa驱动才开始启动AD转换,捕捉数据。我一般把它设为0,我没试过非0,如果是非0, 我想第一次的writei和readi一定得够数量才行,否则设备不启动。
这个对实时效果是需要的,将第三个参数设置为0,保证声卡的立即启动。
1.4 what to do about xruns
xrun指的是,声卡period一到,引发一个中断,告诉alsa驱动,要填入数据,或读走数据,但是,问题在于alsa的读取和写入操作必须用户调用writei和readi才会发生的,它不会去缓存数据。如果上层没有用户调用writei和readi,那么就会产生 overrun(录制时,数据都满了,还没被alsa驱动读走)和underrun(需要数据来播放,alsa驱动却不写入数据),统称为xrun。
这个东西,需要用一些函数来设置,比如snd_pcm_sw_params_set_silence_threshold(),是针对playback 的,就是设置当xxx的情况下,就用silence来写入hardware buffer。至于xxx情况,以及写入多少silence,我都不是很清楚,还有,比如xrun到什么情况下,可以停止这个设备等等函数。一般情况下用alsa驱动的默认的xrun处理策略。
但是关于xrun,最好这样写:
while ((pcmreturn = snd_pcm_writei(pcm_handle, data, frames)) < 0) {
snd_pcm_prepare(pcm_handle);
fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>/n");
}
就是说,如果这次读/写距离上次读/写,时间可能过长,那么这次去读/写的时候,device已经xrun了,在不知道alsa驱动对xrun的默认策略的情况下,最好调用snd_pcm_prepare()来重新准备好设备,然后再开始下一次读写。
1.5 transfer chunk size
这个应该是用不上的,我没找到文档里有用这个的。
[Loong]:这个其实是非常重要的,如果snd_pcm_writei/ snd_pcm_readi不是每次写入chunk size数据的话,那么放音/录音不是你所期望的声音。详细见:http://alsa-project.org/main/index.php/FramesPeriods
ALSA编程细节分析相关推荐
- alsa buffer原理_【关于alsa buffer】ALSA编程细节分析
二. 编程细节 按照上面的流程,其中有许多细节我们可以加以控制,这里仅仅指出应用程序需要关心的: 1.1 设备层次 在alsa驱动这一层,目前为止,抽象出了4层设备: 一是hw:0,0: 二是plug ...
- 【Java 并发编程】线程池机制 ( 线程池执行任务细节分析 | 线程池执行 execute 源码分析 | 先创建核心线程 | 再放入阻塞队列 | 最后创建非核心线程 )
文章目录 一.线程池执行任务细节分析 二.线程池执行 execute 源码分析 一.线程池执行任务细节分析 线程池执行细节分析 : 核心线程数 101010 , 最大小成熟 202020 , 非核心线 ...
- java原生的编译软件_原生态Java 程序员容易忽视的编程细节
Java是Java程序设计语言和Java平台的总称,要想学好一门语言,打好基础最关键的,学习一种新的编程语言比学习新的口头语言要容易得多.然而,在这两种学习过程中,都要付出额外的努力去学习不带口音地说 ...
- 文件数据IO 的细节分析
文件数据IO 的细节分析: 参考: Linux设备驱动开发详解:基于最新的Linux4.0内核:宋宝华编著. 编程离不开数据, 所以数据获取是编程的第一步. 1.文件打开方式 数据IO可以是阻塞式式的 ...
- 长文梳理Muduo库核心代码及优秀编程细节剖析
一.前言: 代码地址: https://github.com/yyg192/Cpp11-Muduo-MultiReactor Muduo库是陈硕个人开发的Tcp网络编程库,支持Reactor模型.本 ...
- WinForm编程细节
原作者:黄启清(www.cnblogs.com/happyqq) 日期:2008-4-19 这是我在Cnblogs里面的第一篇原创文章,以前在百度贴吧里面写的都是网络安全方面的文章. 希望Cnblog ...
- java超线程_超线程多核心下Java多线程编程技术分析
在学习编程的过程中,我觉得不止要获得课本的知识,更多的是通过学习技术知识提高解决问题的能力,这样我们才能走在最前方,本文主要讲述超线程多核心下Java多线程编程技术分析,更多Java专业知识,广州疯狂 ...
- 非洲瓜哇JAVA布的特点_java语言的基本特性以及编程细节
前言 java语言的学习是一个体系,所以如果想要对java的编程有一个很精通的一个掌握,它离不开很多基础的知识点,比如JVM的原理.java多线程并发编程.数据结构等等.所以我这里对我学习的java的 ...
- 多用户企业文件管理系统源码_固定资产管理系统的细节分析
固定资产管理系统的细节分析是什么?固定资产管理系统的应用在很多企业中都越来越普遍,固定资产管理系统作为信息化管理系统,能有效延长资产使用寿命.提升资产使用效能.降低资产故障率及残值.降低维护与维修成本 ...
最新文章
- 高性能server分析 - Hadoop的RpcServer
- 我如何一分钱没花学完AI课程,入职新浪算法工程师
- 前端学习(1752):前端调试值之网络请求的监控
- c汇编语言程序框架培训,[010][x86汇编语言]学习用户程序的编写(c08.asm)
- python排序算法的时间复杂度_Python算法的时间复杂度和空间复杂度(实例解析)
- jmeter接口性能测试实例
- 逻辑删除还是物理删除
- 咋让计算机名字改为办公用计算机,让电脑变成历史:三星DeX将三星S8变成“办公电脑”...
- 正六面体染色(java)
- android 日语输入法,Android日语输入法Simeji使用示例
- Solidity入门-开发众筹智能合约
- 赫斌C语言全案文,自用笔记,给后来者一点思路
- python开发小程序拼团_拼团商城模式开发(如何开发)
- 微分,泰勒公式及其在图像处理中的应用
- Java怎么做一个简单网页呢?
- 高等数学——讲透求极限两大方法,夹逼法与换元法
- 信息可视化大屏展板(附下载连接)
- 查询邮件服务器MX记录
- javascript 矩阵_JavaScript问题解决器:旋转图像矩阵
- 解除网页屏蔽的另一种方法