正确调整 Alsa 缓冲区大小,奇怪的 API

发布于 2024-09-11 14:14:50 字数 704 浏览 8 评论 0原文

我目前正在开展一个项目,需要我使用 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 相同的值。

有什么提示吗?

I'm currently working on a project that requires me to do some sampling with Alsa. I'm trying to configure correctly everything but I'm stuck on how to correctly size my reading.

There are two primitives that seem to be interesting for my task:

snd_pcm_hw_params_get_period_time
snd_pcm_hw_params_get_buffer_size

The name of the first one suggests that the output will be the time length of a sampling period, however that's weird: if I'm setting the sampling rate on f = 44100Hz the sampling period (in nanoseconds) should be T0 = 1e9 / 44100 ~= 22676 ns while the function will answer T1 = 725 us = 725000 ns.

Meanwhile, even if I've been asked to use non-locking primitives, I'm trying to profile the time required for locking 'readi', and it turns out that the sample requires T2 = 8028603 ns in the best case time and T3 = 12436217 ns in the worst case.

Finally I can't figure out what's the meaning of the following two:

snd_pcm_hw_params_get_buffer_time
snd_pcm_hw_params_get_period_size

I don't get how could I measure the buffer in time and the period in size, However the former returns the same value as get_buffer_size, while the latter returns the same value as get_period_time.

Any hint?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不甘平庸 2024-09-18 14:14:50

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

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

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

华泰

ALSA has some weird^Wspecific terminology:

  • Frames: samples x channels (i.e: stereo frames are composed of two samples, mono frames are composed of 1 sample,...)
  • Period: Number of samples tranferred after which the device acknowledges the transfer to the apllication (usually via an interrupt).

The *_size functions appear to return sizes in frames.

HTH

剪不断理还乱 2024-09-18 14:14:50

这是我的声卡初始化函数。

首先,我设置所需的参数。

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;
}

This is my soundcard initialization function.

First of all I set needed parameters

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;

When every parameter has been setted correctly, the parameters are applied to the handle:

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

After it has been applied the brave programmer can obtain the required data as follows:

get_period_size_min() gives the minimum size in frames of the buffer that will contain the sampling. A buffer having this size is wide enough.

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

This is pretty counter-intuitive, but the correct sampling period is not given by 1/rate as one may think. One can obtain the sampling period by using the get_period_time() primitive!

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

    return 0;
}
Hello爱情风 2024-09-18 14:14:50

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

snd_pcm_hw_params_get_period_size()

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

snd_pcm_hw_params_get_period_time()

You will get the time in us (10^-6) ,这些帧将被插入。因此可以获得“真实”采样率

snd_pcm_hw_params_get_period_size()*1000000/snd_pcm_hw_params_get_period_time()

From what I understood using and reading the ALSA library, this period is related to the hardware interruptions being made. If you use

snd_pcm_hw_params_get_period_size()

It will return you the number of frames passed to the hw by interruption. Similarly, if you use

snd_pcm_hw_params_get_period_time()

You will get the time in us (10^-6) that those frames will be inserted. So the "real" sampling rate can be obtained if

snd_pcm_hw_params_get_period_size()*1000000/snd_pcm_hw_params_get_period_time()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文