确定采样音频的时间戳

Bru*_*ams 5 c alsa

我继承了一个使用snd_pcm_readn(). 确定应该与检索到的每个样本相关联的时间戳的最可靠方法是什么?

据推测,ALSA 或捕获卡本身会进行某种缓冲,这意味着 clock_gettime() 可能存在可变错误(尤其是因为这是一个多线程应用程序)。

在我看来,它应该是这样的:

if((alsa_result = snd_pcm_readn(card->capture_handle,
         card->capture_buff,
         card->buffer_size)) == 0)
{

    snd_pcm_status_t pcm_status;
    snd_timestamp_t  snd_timestamp; //actually a struct timeval under the hood
    if (snd_pcm_status(card->capture_handle, &pcm_status) == 0)
    {
       snd_pcm_status_get_tstamp(&pcm_status, &snd_timestamp);
       // translate timeval into milliseconds
       const uint64_t millis = (snd_timestamp.tv_sec * (uint64_t)1000) + (snd_timestamp.tv_usec / 1000);
    }
Run Code Online (Sandbox Code Playgroud)

}

但是,snd_timestamp 指的是什么时间?它是检索到的第一个样本还是最后一个样本,我们是否需要考虑自 snd_pcm_readn() 返回以来可能已捕获的样本?

我发现的 ALSA 文档在细节上很粗略。snd_pcm_status_get_tstamp()如果时间戳未启用(例如,请参阅https://www.kernel.org/doc/html/v4.10/sound/designs/timestamping.html),它甚至有效。

参考好的(最好是在线的)ALSA 相关阅读材料的奖励积分。


与此相关,我目前无法编译上面的代码,因为它说:

error: storage size of ‘pcm_status’ isn’t known
  snd_pcm_status_t pcm_status;
Run Code Online (Sandbox Code Playgroud)

我有#include <alsa/pcm.h>和:

>grep -r _snd_pcm_status /usr/include/
/usr/include/alsa/pcm.h: typedef struct _snd_pcm_status snd_pcm_status_t;
Run Code Online (Sandbox Code Playgroud)

_snd_pcm_status在明显的位置似乎没有定义。


2017 年 8 月 11 日更新

正如指出的 snd_pcm_status_t 是不透明的,必须由 ALSA 分配。我仍然无法snd_pcm_status_get_tstamp返回“正确”的时间戳:

//setup code...
if ((alsa_error = snd_pcm_sw_params_malloc(&sw_params)) < 0)
{
   //handle error
}
if ((alsa_error = snd_pcm_sw_params_set_tstamp_mode(card->capture_handle, sw_params, SND_PCM_TSTAMP_ENABLE)) < 0)
{
   //handle error
}
if ((alsa_error = snd_pcm_sw_params_set_tstamp_mode(card->capture_handle, sw_params, SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY)) < 0)
{
   //handle error
}
snd_pcm_sw_params_free(sw_params);


// later on
if((alsa_result = snd_pcm_readn(card->capture_handle,
     card->capture_buff,
     card->buffer_size)) == 0)
{   
   time_t timeStamp = 0;
   snd_timestamp_t  snd_timestamp = {0,0}; //actually a struct timeval
   if (snd_pcm_status(card->capture_handle, card->status) == 0)
   {
       snd_pcm_status_get_tstamp(card->status, &snd_timestamp);
       timeStamp = snd_timestamp.tv_sec;
   }
}
Run Code Online (Sandbox Code Playgroud)

timeStamp 似乎是单调时钟,而不是像我所要求的那样获取一天中的时间(ALSA 文档未指定)。

我刚收到符合以下条件的“1970-01-11T08:33:42:894822”:

cat /proc/timer_list | grep 现在是 894831565155289 纳秒

我只能得到一个基本时间,now - monotonic但这对于声称是 SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY 的时钟来说似乎是错误的。所以我得出结论我的设置代码或理解有问题。

那是我刚刚 readn() 的样本的时间戳吗?

CL.*_*CL. 4

snd_pcm_sw_params_set_tstamp_mode()必须通过使用SND_PCM_TSTAMP_NONE/调用在软件参数中启用时间戳ENABLE

时间戳可以使用不同的时钟;snd_pcm_sw_params_set_tstamp_type()通过使用SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY//MONOTONIC调用来选择一个MONOTONIC_RAW

可以使用 检索上次启动或停止流的时间戳snd_pcm_status_get_trigger_tstamp()。可以使用 检索最后一次指针更新的时间戳snd_pcm_status_get_tstamp()。(对应的指针位置,带snd_pcm_status_get_avail()。)

snd_pcm_status_t是一种隐藏类型,因为它在不同的库版本中可以具有不同的大小。必须动态分配;参见这个例子