如何使用ALSA的snd_pcm_writei()?

时间:2010-02-01 23:43:29

标签: c++ c alsa

有人可以解释snd_pcm_writei

的方式
snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer,
                                 snd_pcm_uframes_t size)

作品?

我这样使用过它:

for (int i = 0; i < 1; i++) {
   f = snd_pcm_writei(handle, buffer, frames);

   ...
}

http://pastebin.com/m2f28b578

的完整源代码

这是否意味着我不应该给snd_pcm_writei()数字 buffer中的所有帧,但只有

sample_rate * latency = frames

所以,如果我,例如有: sample_rate = 44100 潜伏期= 0.5 [s] all_frames = 100000

我应该给snd_pcm_writei()的帧数是

sample_rate * latency = frames 44100 * 0.5 = 22050

和for循环的迭代次数应该是?:

(int)100000/22050 = 4;框架= 22050

和一个额外的,但只有

100000 mod 22050 = 11800

帧?

这是怎么回事?

路易丝

http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html#gf13067c0ebde29118ca05af76e5b17a9

4 个答案:

答案 0 :(得分:6)

frames 应该是您想要从缓冲区写入的帧数(样本)。系统的声音驱动程序将立即开始将这些样本传输到声卡,它们将以恒定速率播放。

延迟是在几个地方引入的。在等待传输到卡上时,驱动程序缓冲的数据存在延迟。至少有一个缓冲区充满了在任何给定时刻传输到卡上的数据,并且在应用程序端有缓冲,这是你似乎关注的。

要减少应用程序端的延迟,您需要编写适合您的最小缓冲区。如果您的应用程序执行DSP任务,那通常就是一个窗口的数据。

在循环中编写小缓冲区没有任何优势 - 只需继续编写所有内容 - 但有一点需要理解:为了最大限度地减少延迟,应用程序应该写入驱动程序不会比驱动程序写入更快数据到声卡,或者你最终堆积更多数据并累积越来越多的延迟。

对于使声音驱动程序与锁定步骤相对容易生成数据的设计,请查看基于向声音播放引擎注册回调函数的jack(http://jackaudio.org/)。事实上,如果你真的担心延迟,你可能最好不要使用插孔而不是自己动手。

答案 1 :(得分:3)

我做了一些测试,以确定为什么snd_pcm_writei()似乎不适合我,使用我在ALSA教程中找到的几个示例,我得出的结论是,简单示例之前正在执行snd_pcm_close ()声音设备可以播放发送给它的完整流。

我将速率设置为11025,使用128字节的随机缓冲区,并将循环snd_pcm_writei()设置为每秒声音的11025/128。两秒钟需要86 * 2个电话snd_pcm_write()才能获得两秒钟的声音。

为了给设备足够的时间将数据转换为音频,我在snd_pcm_writei()循环之后使用了for循环来延迟执行snd_pcm_close()函数。

经过测试,我必须得出结论,在调用snd_pcm_close函数之前,示例代码没有提供足够的样本来克服设备延迟,这意味着close函数的延迟小于{{1}功能。

答案 2 :(得分:3)

我认为设备关闭“过早”的原因是您需要在snd_pcm_drain(handle);之前调用snd_pcm_close(handle);,以确保在设备关闭之前播放所有数据。

答案 3 :(得分:0)

如果未正确设置ALSA驱动程序的启动阈值(如果是大约2秒),则需要调用snd_pcm_start()以在snd_pcm_writei()之后立即启动数据呈现。 或者您可以在ALSA设备的SW参数中设置适当的阈值。

REF: