播放音频时 Alsa 缓冲区溢出

Posted

技术标签:

【中文标题】播放音频时 Alsa 缓冲区溢出【英文标题】:Alsa Buffer overrun while playback of audio 【发布时间】:2014-07-09 18:06:29 【问题描述】:

我已将IMX 板背靠背连接到电脑。 我在板上运行一个二进制文件,它每 5.7 毫秒发送 1024 个字节的音频帧。 pc接收帧并使用

printf("snd_pcm_avail %d \n",snd_pcm_avail (FMWK.FMWK_Handler.playback_handle));

err = snd_pcm_writei(FMWK.FMWK_Handler.playback_handle, OutputPointer, PERIOD_BYTES);

播放时,每 6 秒我就会损坏管道

播放成功时的日志

snd_pcm_avail 32 
snd_pcm_avail 17 
snd_pcm_avail 81 
snd_pcm_avail 25 
snd_pcm_avail 89 
snd_pcm_avail 32 
snd_pcm_avail 17 
snd_pcm_avail 81 
snd_pcm_avail 32 
snd_pcm_avail 17 
snd_pcm_avail 81 
snd_pcm_avail 25 
snd_pcm_avail 89 
snd_pcm_avail 32 
snd_pcm_avail 17 
snd_pcm_avail 81 

大约减少了 56 当 5 秒后使用率增加并且缓冲区溢出 buffer_size=256 的配置限制

日志:

snd_pcm_avail 89 
snd_pcm_avail 112 
snd_pcm_avail 96 
snd_pcm_avail 120 
snd_pcm_avail 104 
snd_pcm_avail 129 
snd_pcm_avail 153 
snd_pcm_avail 137 
snd_pcm_avail 160 
snd_pcm_avail 184 
snd_pcm_avail 168 
snd_pcm_avail 193 
snd_pcm_avail 176 
snd_pcm_avail 201 
snd_pcm_avail 224 
snd_pcm_avail 209 
snd_pcm_avail 232 
snd_pcm_avail 217 
snd_pcm_avail 240 
snd_pcm_avail -32 
   (AVB Info)     12:26:11 PM.606306  (Slave)               ==> Broken pipe
snd_pcm_avail 256 
snd_pcm_avail 48 

我将 period_size 设置为 128

我不确定我是否在 snd_pcm 的初始配置中遗漏了什么?是44.1khz音频。

【问题讨论】:

这些音频帧从何而来?您如何测量 5.7 毫秒? 我们在发送端实现了一个定时器,它每 5.7ms 发送 1024 个字节。 @user3659653:您不得使用系统计时器(使用 ALSA)来确定何时发送下一帧。是的,理智的事情是期待,这是可行的。但不幸的是,进程调度程序的粒度本身是毫秒级的,因此您无法将时间精确到 +/-0.1 毫秒。它更像是您可以有效获得的 +/-2ms 精度。此外,DAC 时钟和您的系统定时器时钟不会同步运行(这是 PC 架构的一个巨大设计愚蠢,可以通过外围互连标准的下一个修订版轻松消除),因此您必须只依赖在 DAC 采样时钟上。 Datenwolf 感谢您的回复。我如何从 DAC 导出时序,因为在用户空间中没有要读取的抽象或接口。如何获得用户空间的编解码器时钟,是否有任何提供此 ADC/DAC 时钟的 alsa 接口? 如何回复发送方和接收方的 DAC 时钟?..有什么方法可以获取 DAC/ADC 的时序? 【参考方案1】:

发生的情况是,您的程序无法跟上设备对 PCM 数据的播放。当“Broken pipe”发生时,音频设备会等待新的样本,但您的程序没有及时交付它们。

您遇到的情况是在线音频系统的祸根;不幸的是,现有的 Linux 音频架构 (ALSA) 并不能很好地发挥作用; PulseAudio + RealtimeKit 尝试(恕我直言,不是很成功)通过做奇怪而疯狂的巫术来避免让 ALSA 司机挨饿;由于某些驱动程序被破坏并且没有正确报告播放头的位置,事情并没有变得更好。

在你的情况下,你可以做两件事:

使用更大的帧(缓冲区中的更多样本) 对更多帧进行排队(将多个缓冲区排队)并在队列中保持最少数量的帧

【讨论】:

Datenwolf 感谢您的回复。但是根据avail值,不是pcm有大量数据用于播放,但不是以相同的速率播放吗?我会尝试第二个选项。【参考方案2】:

音频设备通常有自己的采样时钟,它与系统时钟不同步。

因此您不能使用系统时钟来控制将样本发送到设备的速度;它会在几乎所有系统上运行太快或太慢。

要以正确的速度发送样本,只需尝试尽可能快地编写样本;如果缓冲区已满,snd_pcm_write* 会自动等待。

如果您无法从接收方控制发送方的速度(因为它们不在同一台机器上,并且您没有提供反馈的协议),则必须测量发送方和接收方的相对速度,并重新采样适当的数据。

【讨论】:

是的,时钟同步是计算机音频的主要祸根。正如您可能知道或可能不知道的那样,我目前正在为 Linux 开发一个新的音频子系统,并且代码的主要部分处理使时钟不匹配的麻烦消失。我永远无法理解为什么 PC 平台不简单地添加一个系统范围的分布式 10MHz 时钟,所有定时器都来自该时钟。这会让事情变得简单得多:如果 GPU 的垂直回扫基于与音频 DAC 采样时钟完全相同的时钟,那么您将在视频帧和音频帧之间建立完美的关系。 当然,所有专业设备都使用外部字时钟工作,一切都会同步到。音频接口、摄像头、显卡等一切都连接到一个通用时钟,突然间所有问题都消失了。 CL -> 如果它们在两个独立的系统中运行,我们如何获得相对的 ADC 和 DAC 速度。是否有任何 ioctl 或 alsa 接口为用户空间应用程序提供 ADC/DAC 的时钟。 您必须对样本进行计数。

以上是关于播放音频时 Alsa 缓冲区溢出的主要内容,如果未能解决你的问题,请参考以下文章

soritong MP3播放器缓冲区溢出漏洞分析

libUpnp缓冲区溢出拒绝服务等漏洞分析

何时更新 ALSA 音频驱动程序缓冲区指针

缓冲区溢出及堆栈/堆操纵

为啥缓冲区未满时字节缓冲区会出现缓冲区溢出异常

McAfee提示“缓冲区溢出”,该怎么处理?