我继承了一个使用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
返回&#39;右边&#39;时间戳:
//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文档没有指定)。
我刚刚得到&#34; 1970-01-11T08:33:42:894822&#34; 符合:
cat / proc / timer_list | grep现在 现在是894831565155289 nsecs
我可以获得now - monotonic
的基准时间,但对于声称为SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY的时钟而言,这似乎是错误的。所以我总结一下我的设置代码或理解是错误的。
那是我刚读过的样本的时间标记()吗?
答案 0 :(得分:2)
必须使用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。