正确设置Alsa缓冲区大小,奇怪的API

6

我目前正在进行一个需要使用Alsa进行采样的项目。我正在尝试正确配置所有内容,但我卡在如何正确确定读取大小的问题上。

对于我的任务,有两个似乎很有用的原语:

snd_pcm_hw_params_get_period_time
snd_pcm_hw_params_get_buffer_size

第一个名称表明输出将是采样周期的时间长度,但这很奇怪:如果我设置采样率为f = 44100Hz,采样周期(以纳秒为单位)应为T0 = 1e9 / 44100 ~= 22676 ns,而该函数将回答T1 = 725 us = 725000 ns

同时,即使我被要求使用非锁定原语,我仍在尝试分析对“readi”加锁所需的时间,并且结果显示,在最佳情况下,采样需要T2 = 8028603 ns,最差情况下需要T3 = 12436217 ns

最后,我无法弄清楚以下两个的含义:

snd_pcm_hw_params_get_buffer_time
snd_pcm_hw_params_get_period_size

我不明白如何测量缓冲时间和大小,但是前者返回与get_buffer_size相同的值,而后者返回与get_period_time相同的值。
有什么提示吗?
3个回答

6

ALSA有一些奇怪的^W特定术语:

  • 帧(Frames):样本x通道(例如:立体声帧由两个样本组成,单声道帧由1个样本组成,...)
  • 周期(Period):设备确认传输到应用程序的传输后的样本数(通常通过中断完成)。

*_size函数似乎返回帧大小。

希望对你有所帮助。


它们的返回值由返回类型snd_uframe_t(对于*_size)和unsigned(对于*_time)清晰地表示,但我不明白“缓冲时间”和“周期大小”的含义。 - Dacav
周期大小: val 返回帧数的近似周期大小缓冲时间(当然取决于当前配置): val 返回以微秒为单位的缓冲时间 - ninjalj
是的,文档中有相同的函数名称信息内容,但缓冲时间是什么?缓冲区具有一定的“大小”,而不是“时间”。 - Dacav

5
这是我的声卡初始化函数。
首先,我设置所需的参数。
static
int init_soundcard (snd_pcm_t *handle, unsigned *rate, uint8_t channels,
                    snd_pcm_uframes_t *nframes, unsigned *period)
{
    snd_pcm_hw_params_t *hwparams;
    int err;

    snd_pcm_hw_params_alloca(&hwparams);

    err = snd_pcm_hw_params_any(handle, hwparams);
    if (err < 0) return err;

    err = snd_pcm_hw_params_set_rate_near(handle, hwparams, rate, NULL);
    if (err < 0) return err;

    err = snd_pcm_hw_params_set_access(handle, hwparams,
                                       SND_PCM_ACCESS_RW_INTERLEAVED);
    if (err < 0) return err;

    err = snd_pcm_hw_params_set_format(handle, hwparams,
                                       SND_PCM_FORMAT_S16_LE);
    if (err < 0) return err;

    err = snd_pcm_hw_params_set_channels(handle, hwparams, channels);
    if (err < 0) return err;

当每个参数都被正确设置后,这些参数将应用于句柄:

    err = snd_pcm_hw_params(handle, hwparams);
    if (err < 0) return err;

应用之后,勇敢的程序员可以按以下方式获取所需数据:

get_period_size_min() 返回包含采样的缓冲区的最小帧大小。具有此大小的缓冲区足够宽。

    err = snd_pcm_hw_params_get_period_size_min(hwparams, nframes, NULL);
    if (err < 0) return err;

这是相当反直觉的,但正确的采样周期并不是像人们可能认为的那样由1/rate给出的。可以通过使用get_period_time()原语来获得采样周期!

    err = snd_pcm_hw_params_get_period_time(hwparams, period, NULL);
    if (err < 0) return err;

    return 0;
}

2

根据我使用和阅读ALSA库的理解,这个周期与硬件中断有关。如果你使用

snd_pcm_hw_params_get_period_size()

它将返回通过中断传递给硬件的帧数。同样,如果您使用

snd_pcm_hw_params_get_period_time()

您将获得以微秒(10^-6)为单位插入这些帧的时间。因此,如果

真实

的采样率可以通过以下方式获得:

snd_pcm_hw_params_get_period_size()*1000000/snd_pcm_hw_params_get_period_time()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接