ALSA接口中的SIZE都是以Frame为单位

Frame Byte=Sample_bits * Channels / 8。

例如:

snd_pcm_readi

snd_pcm_writei

snd_pcm_sw_params_set_avail_min

snd_pcm_sw_params_set_start_threshold

snd_pcm_readi ()

snd_pcm_sframes_t snd_pcm_readi ( snd_pcm_t *pcm,

void*     buffer,

snd_pcm_uframes_t  size

                                                          )

Read interleaved frames from a PCM.

Parameters:

  pcm  PCM handle
  buffer  frames containing buffer
  size  frames to be read
Returns:
a positive number of frames actually read otherwise a negative error code
Return values:
  -EBADFD  PCM is not in the right state (SND_PCM_STATE_PREPARED orSND_PCM_STATE_RUNNING)
  -EPIPE  an overrun occurred
  -ESTRPIPE  a suspend event occurred (stream is suspended and waiting for an application recovery)

If the blocking behaviour was selected and it is running, then routine waits until all requested frames are filled. The returned number of frames can be less only if a signal or underrun occurred.

If the non-blocking behaviour is selected, then routine doesn’t wait at all.

/

snd_pcm_writei()

snd_pcm_sframes_t snd_pcm_writei (snd_pcm_t * pcm,

const void * buffer,

snd_pcm_uframes_t size

)

Write interleaved frames to a PCM.

Parameters:
  pcm  PCM handle
  buffer  frames containing buffer
  size  frames to be written
Returns:
a positive number of frames actually written otherwise a negative error code
Return values:
  -EBADFD  PCM is not in the right state (SND_PCM_STATE_PREPARED orSND_PCM_STATE_RUNNING)
  -EPIPE  an underrun occurred
  -ESTRPIPE  a suspend event occurred (stream is suspended and waiting for an application recovery)

If the blocking behaviour is selected and it is running, then routine waits until all requested frames are played or put to the playback ring buffer. The returned number of frames can be less only if a signal or underrun occurred.

If the non-blocking behaviour is selected, then routine doesn’t wait at all.

一. 编程细节

按照上面的流程,其中有许多细节我们可以加以控制,这里仅仅指出应用程序需要关心的:

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】

二. 编程细节

TODO LIST:以后把下面两点补上:

2.1 一般读写模式

2.2 interrupt-driven

它非常清晰的告诉了用户,你需要读取数据或写入数据了。这样允许用户即时的作出操作:比如现在让用户从wait()出来,用户知道需要比如写入数据了,它可以决定写入真实的数据,或者写如silence,或者其他。而用一般读写模式,你不会即时知道下层的需求,所以相当于你只能在你下一次读/写的时候,判断有没有xrun,其他你什么都做不了。

TODO: 再好好想想这个模式,其实我不确定实际使用上有什么好?

alsa的 snd_pcm_readi 和 snd_pcm_writei相关推荐

  1. 转 alsa录音放音执行流程详解

    前言: linux中,无论是oss还是alsa体系,录音和放音的数据流必须分析清楚.先分析alsa驱动层,然后关联到alsa库层和应用层. 链接分析: core/pcm_native.c文件中.mma ...

  2. linux alsa 录音程序,转 alsa录音放音执行流程详解

    前言: linux中,无论是oss还是alsa体系,录音和放音的数据流必须分析清楚.先分析alsa驱动层,然后关联到alsa库层和应用层. 链接分析: core/pcm_native.c文件中.mma ...

  3. alsa-lib应用层接口分析

    ALSA lib接口调用简介 ALSA逻辑,在我当前看来,总共有两条线:1.录放音流控,2.amixer cset控件. 录放音流控(自定义名称),相当于操作OSS的/dev/dsp设备,可以设置三大 ...

  4. alsa声音编程介绍

    http://blog.csdn.net/q553716434/article/details/7881552 period(周期):硬件中中断间的间隔时间.它表示输入延时. 声卡接口中有一个指针来指 ...

  5. linux内核之alsa,Linux操作系统Alsa音频编程

    一.前序 这里了解一下各个参数的含义以及一些基本概念. 声音是连续模拟量,计算机将它离散化之后用数字表示,就有了以下几个名词术语. 样本长度(sample):样本是记录音频数据最基本的单位,计算机对每 ...

  6. alsa 音频编程简单的例子 (总结)

    1.源代码安装alsa 库,否则编译例子不会通过.原文引用http://apps.hi.baidu.com/share/detail/17289294 2.编译简单的播放和录音的例子.   引用原文h ...

  7. Alsa音频应用编程

    前序:这里了解一下各个参数的含义以及一些基本概念. 样本长度(sample):样本是记录音频数据最基本的单位,常见的有8位和16位. 通道数(channel):该参数为1表示单声道,2则是立体声. 桢 ...

  8. linux下lamealsa进行音频流操作(三)alsa音频编程教程

    1. ALSA音频编程介绍   ALSA 代表高级 Linux 声音架构.它由一组内核驱动程序.一个应用程序编程接口 (API) 库和用于在 Linux 下支持声音的实用程序组成.在本文中,我简要概述 ...

  9. ALSA(Advanced Linux Sound Architecture)声卡编程介绍

    转载地址:http://mysuperbaby.iteye.com/blog/932729 英文原文: http://www.linuxjournal.com/article/6735 period( ...

最新文章

  1. Redis(5种数据类型)
  2. 为memcached增加缓存依赖的程序实现
  3. OPEN(SAP) UI5 学习入门系列之四:更好的入门系列-官方Walkthrough
  4. 一次搭建Spark集群(standalone、yarn、高可用)
  5. 通过千千静听歌词服务器下载歌词(Delphi版)
  6. javascript的offset、client、scroll使用方法
  7. 虚拟机安装MySQL教程
  8. 2021非常全的接口测试面试题及参考答案
  9. PDF的文档转成HTML乱序,PDF文档怎么转换成HTML文件?用迅捷PDF转换器就不难!
  10. 鼠标手是否算工伤 专家:法定职业病才能获赔
  11. PTA Easy chemistry 化学方程式等价判定 string 状态机
  12. python 挂起_Python Killing挂起函数
  13. windows:服务启动、暂停、停止按钮不能点击,是灰色如何解决
  14. 201512683信息检索知识
  15. JCreator的配置
  16. 操作系统原理_田丽华(4)线程
  17. python网络编程培训
  18. 什么是CDN网络加速
  19. 2022年最高效,踏实的Python学习笔记以及Python学习规划
  20. Java开发中的23种设计模式详解

热门文章

  1. 第一章:OpenCV简介
  2. 区块链是个噱头吗?麦腾:可以帮助经济体系
  3. Orange API 网关部署安装总结
  4. SAP中的client(也叫集团)的意义(中文版)
  5. Python爬虫工程师是干什么的?能赚多少钱?需要掌握哪些技术?
  6. 安装教程之Windows 11安装Linux子系统并运行Linux GUI应用
  7. 一个月薪1万的程序员给我上了震撼一课
  8. Q版疯狂大炮游戏android×××
  9. 【源代码】 用Eclipse编写的Java小程序——自动售卖机
  10. Android TabLayout自定义指示器之三角形效果实现