从ALSA录制 – 了解内存映射

Im试图使用ALSA从USBaudio设备获取input,并将其作为一系列有signed short值写入磁盘。 我所得到的结果是看起来是有效的数据块散布与大块零。 我猜我有我的缓冲区安装不正确,没有正确使用内存映射。

我正在尝试:

  • 采样率:8K(这是由设备强制)
  • 缓冲区大小:2048
  • 期限大小:512
  • 一个频道

该设备似乎打开正确,并接受各种参数。 经过一些设置后,循环运行如下:

 snd_pcm_avail_update snd_pcm_mmap_begin memcpy data from mmap buffer to array of short snd_pcm_mmap_commit 

memcpy是一个指向short的数组的指针,并且每次传递返回的帧数都是递增的。

在这个logging几秒钟之后,我把它closures,并把随后的缓冲区写入磁盘,作为每一行的一个简单值。 我期望的是在1200和2300赫兹之间变化的一秒或两秒的PCM数据。 我得到的是一些有很多零的数据。

我想知道的是:我的缓冲区和期限值是否合理? 有没有人成功地使用ALSA的内存映射输出?

编辑:一些代码

 const snd_pcm_channel_area_t *areas; snd_pcm_uframes_t offset, frames, size; short* pCID = (short*)malloc( 50000 * sizeof( short )); short* ppCID = pCID; while( size > 0 ) { frames = size; snd_pcm_mmap_begin (device, &areas, &offset, &frames); short* pd = (short*)areas[0].addr; memcpy( ppCID, (pd + (offset*sizeof(short))), frames * sizeof( short )); ppCID += frames; snd_pcm_mmap_commit(device, offset, frames); size -= frames; } 

(清除错误检查清除)
当所有事情都说完之后,我循环访问pCID并写入磁盘。 每行一个值。

Solutions Collecting From Web of "从ALSA录制 – 了解内存映射"

ARM上的USB音频驱动程序存在一个已知的错误 ,其中内核和应用程序的相同缓冲区的映射可能不是缓存一致的。

只有在代码可以直接处理样本而不将其复制到另一个缓冲区的情况下,使用ALSA存储器映射函数才有意义。 如果你复制它们,你就是完全一样snd_pcm_readi已经做了。 换句话说,就是不要使用内存映射。

在捕获时,缓冲区大小对延迟没有影响,所以应尽可能大,以避免可能的超限。

较小的周期大小可以降低延迟时间,但是程序不会执行任何与实时相关的操作,因此您可以使用较大的周期大小来节省一些功耗。

从文档 :“有必要在调用之前直接调用snd_pcm_avail_update()函数,否则这个函数可能会返回错误的可用帧数。” 我会假设问题是,snd_pcm_mmap_begin错误地报告了可用的帧数,所以您正在从尚未写入的区域读取数据。

此外,我不积极,但我不认为阿尔萨mmap函数将阻塞,直到有数据,虽然这可能是其他代码,我没有看到这里覆盖。 这跟文件mmap不是一回事,所以不要开始思考它。 如果你的粉丝开始变得疯狂,一切都变得缓慢,那么当你的代码正在从应用程序切换到内核环境时,并且当有零字节被读取时,它们会连续地返回。

正如前面的海报已经指出,无论如何,这是snd_pcm_readi的完美用例,所以使用它。