将参数从 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]。
我尝试按照从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]。