【问题标题】:determining the time-stamp of sampled audio确定采样音频的时间戳
【发布时间】:2018-01-17 14:46:27
【问题描述】:

我继承了一个使用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);
    }

}

但是,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;

我有#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;

但在明显的位置似乎没有_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;
   }
}

timeStamp 似乎是单调时钟,而不是像我想的那样获取一天中的时间(ALSA 文档没有具体说明)。

我刚收到“1970-01-11T08:33:42:894822” 符合:

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

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

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

【问题讨论】:

    标签: c alsa


    【解决方案1】:

    必须通过调用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 是一种隐藏类型,因为它在不同的库版本中可以有不同的大小。 必须动态分配;见this example。

    【讨论】:

    • 这有帮助,但“最后一次指针更新的时间戳”是什么意思?我已经使用 snd_pcm_readn() 检索了一些样本。 “指针”是 ALSA 内部的东西。这是我的呼叫解除阻塞并返回的时间(即读取指针移动,因为我读了一些东西)?或者缓冲区最后一次获得新音频的时间(写指针移动)?我想将我读过的样本与音频到达麦克风时的时间戳匹配相关联(允许小的固定偏移量)。我不想知道我上次获取数据的时间,因为该数据可能已被缓冲一段时间。
    • 如果 snd_pcm_sw_params_set_tstamp_mode() 没有设置,我们还应该假设 snd_pcm_status_get_tstamp() 是未定义的行为吗?
    • 硬件指针是缓冲区中硬件读取或写入样本的位置。它会在每个周期后更新,或者在您询问状态时更新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-15
    • 2011-04-29
    • 2010-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-04
    相关资源
    最近更新 更多