将参数从 alsa 应用程序传递到内核驱动程序

Passing params from alsa application to kernel driver

我尝试按照从linux用户space(arecord/aplay)到内核驱动程序的参数设置路径。我们以arecords --period-size为例。

这一切都始于 set_params aplay.c 中的功能:

if (period_time > 0)
    err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, 0);
else
    err = snd_pcm_hw_params_set_period_size_near(handle, params, &period_frames, 0);

函数 snd_pcm_hw_params_set_period_size_near() 定义在 [pcm.c : 5186](alsa-lib https://github.com/alsa-project/alsa-lib/blob/master/src/pcm/pcm.c#L5186) 中,我开始头疼了……这个函数开始了一系列调用对我来说没有多大意义的其他功能,似乎不会导致驱动程序的任何结束调用。

_end 标签,所以我跳过了所有像 snd_pcm_hw_param_set_min()snd_pcm_hw_param_set_max() 这样的调用,然后转到 snd_pcm_hw_param_set_last() 希望有一些驱动程序调用,比如:

drv->hw_params_set(...);

但我发现了结束调用:

MASK_INLINE unsigned int snd_mask_min(const snd_mask_t *mask)
{
    int i;
    assert(!snd_mask_empty(mask));
    for (i = 0; i < MASK_SIZE; i++) {
        if (mask->bits[i])
            return ffs(mask->bits[i]) - 1 + (i << 5);
    }
    return 0;
}

其中 return 值应为参数集。

总而言之,我发现 alsa-lib 很难阅读和理解。也许我缺乏一些知识。我的问题很简单,用户 space 参数如何传递给内核驱动程序。你能提供一个软件路径显示调用的接口吗?

谢谢。

hw_params结构包含一个配置space,这是对设备可以支持的所有可能配置的描述。数字参数被描述为间隔(即最小值和最大值),访问和格式为位掩码。

当您更改一个参数时,库会调用内核驱动程序 (SNDRV_PCM_IOCTL_HW_REFINE) 来调整 hw_params 结构中依赖于已更改参数的所有其他参数。

将配置 space 缩减为实际需要的配置后,调用 snd_pcm_hw_params()(→ SNDRV_PCM_IOCTL_HW_PARAMS)为这些参数实际配置设备。 (如果某些参数还没有缩减为单个值,snd_pcm_hw_params() 将随机选择一个。)


snd_pcm_hw_params_set_xxx_near() 更复杂,因为没有 SET_NEAR ioctl。此函数尝试调整间隔,使其最大值或最小值是所需值,然后检查实际最大值或最小值是否更接近。

例如,假设设备支持 1024、2048、4096 和 8192 帧的周期大小。最初,间隔被描述为 [1024, 8192]。当您调用 snd_pcm_hw_params_set_period_size_near(4000) 时,snd_pcm_hw_param_set_near() 辅助函数调用 set_min(4000)set_max(4000)(在 hw_params 结构的单独副本上),因此间隔为 [1024, 4000] 和 [4000, 8192];经过细化后,驱动程序 returns 区间 [1024, 2048] 和 [4096, 8192]。 snd_pcm_hw_param_set_near() 然后发现 4096 最接近所需的值,因此它会在第二个间隔调用 set_first,结果为 [4096, 4096]。