2013-02-07 43 views
7

林试图使用ALSA从USB音频设备采取的输入,并将其写入到磁盘作为一系列signed short值。我所得到的结果是看起来像是散布了大块零的有效数据块。我猜测我的缓冲区设置不正确,没有正确使用内存映射。拍摄 - 理解存储器映射

我试图:

  • 采样率:8K(这是由设备被迫)
  • 缓冲区大小:2048
  • 周期大小:512
  • 一个信道

该设备似乎被打开prope并且接受各种参数。一些设置后的循环运行为:

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

的memcpy的是一个指针的短阵列,并且通过帧的数量递增返回的每个通。

在此记录几秒钟后,我将其关闭并将随后的缓冲区写入磁盘,作为每行上的单个短值。我期待的是在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我环路和写入磁盘。每行一个值。

回答

5

有一个known bug与ARM的USB音频驱动程序,在内核和缓存相同的应用程序的地图可能不是高速缓存相干。

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

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

较小的时期尺寸给你更低的延迟,但你的程序没有做任何实时相关的,所以你可以使用较大尺寸期间节省电力的一点点。

1

来自documentation:“在这次调用之前,有必要直接调用snd_pcm_avail_update()函数,否则这个函数会返回错误的可用帧数。”我认为问题在于snd_pcm_mmap_begin错误地报告了可用帧的数量,因此您正在从尚未写入的区域读取数据。

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

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