Linux ALSA驱动之四:Control设备创建流程源码分析(5.18)上
Control接口主要让用户空间的应用程序(alsa-lib)可以访问和控制音频codec芯片中的多路开关,滑动控件等。对于 Mixer (混音)来说,Control接口显得尤为重要,从ALSA 0.9.x版本开始,所有的mixer工作都是通过control接口的API来实现的。
ALSA已经为AC97定义了完整的控制接口模型,如果你的Codec芯片只支持AC97接口,你可以不用关心本节的内容。
定义了所有的Control API。如果你要为你的codec实现自己的controls,请在代码中包含该头文件。
1、snd_kcontrol_new
struct snd_kcontrol_new { snd_ctl_elem_iface_t iface; /* interface identifier */ unsigned int device; /* device/client number */ unsigned int subdevice; /* subdevice (substream) number */ const char *name; /* ASCII name of item */ unsigned int index; /* index of item */ unsigned int access; /* access rights */ unsigned int count; /* count of same elements */ snd_kcontrol_info_t *info; snd_kcontrol_get_t *get; snd_kcontrol_put_t *put; union { snd_kcontrol_tlv_rw_t *c; const unsigned int *p; } tlv; unsigned long private_value; };
iface:表示control的类型,用SNDRV_CTL_ELEM_IFACE_XXX来定义。通常使用MIXER,也可以定于属于全局的CARD类型,如果定义为属于莫雷设备的类型,例如HWDEP、PCMRAWMIDI、TIMER等,此时必须在device和subdevice字段中支出卡的设备逻辑编号。
name:表示control的名字,用户层可以通过这个名字访问这个control,后续会细聊
index:存放这个 control 的索引号。如果声卡下不止一个codec。每个codec有相同的名字的control。此时就需要通过index来区分这些controls,当index为0,则可以忽略这种区分策略。
access:访问权限的控制,READ,WRITE,READWRITE等。每一个bit代表一种访问类型,这些访问类型可以多个或运算组合在一起使用。
private_value:包含了一个人员的长整数类型的值,该值可以通过info、get、put这几个回调函数访问。
tlv:该字段为control提供元数据。
2、control的名字
control的名字需要遵循一些标准,通常可以分成3部分来定义control的名字:源--方向--功能。
源:可以理解为该control的输入端,alsa已经预定义了一些常用的源,例如:Master,PCM,CD,Line等等。
方向:代表该control的数据流向,例如:Playback,Capture,Bypass,Bypass Capture等等,也可以不定义方向,这时表示该Control是双向的(playback和capture)。
功能:根据control的功能,可以是以下字符串:Switch,Volume,Route等等。
也有一些命名上的特例:
1、全局的capture和playback:"Capture Source",“Capture Volume”,“Capture Switch”,他们用于全局的capture source、switch和volume。同样的“Playback Volume”,“Playeback Switch”,它们用于全局的输出switch和volume。
2、Tone-controles:音调控制的开关和音量命名为:Tomw Control-XXX,例如,“Tone-Control-Switch”,“Tone Control-Bass”,“Tone Control-Center”。
3、3D controls:3D控件的命名规则:“3D Control-Switch”,“3D Control-Center”,“3D Control-Space”。
4、MIC boost:麦克风音量加强空间命名为:“MIC Boost”或“MIC Bosst(6dB)”。
3、访问标志(ACCESS Flags)
Access字段是一个bitmask,它保存了改control的访问类型。默认的访问类型是:SNDDRV_CTL_ELEM_ACCESS_READWRITE,表明该control支持读和写操作。如果access字段没有定义(.access==0),此时也认为是READWRITE类型。
如果是一个只读control,access应该设置为:SNDDRV_CTL_ELEM_ACCESS_READ,这时,我们不必定义put回调函数。类似地,如果是只写control,access应该设置为:SNDDRV_CTL_ELEM_ACCESS_WRITE,这时,我们不必定义get回调函数。
如果control的值会频繁地改变(例如:电平表),我们可以使用VOLATILE类型,这意味着该control会在没有通知的情况下改变,应用程序应该定时地查询该control的值。
4、元数据(METADATA)
很多mixer control需要提供以dB为单位的信息,我们可以使用DECLARE_TLV_xxx宏来定义一些包含这种信息的变量,然后把control的tlv.p字段指向这些变量,最后,在access字段中加上SNDRV_CTL_ELEM_ACCESS_TLV_READ标志,例如:
static const DECLARE_TLV_DB_SCALE(snd_cx88_db_scale, -6300, 100, 0); static const struct snd_kcontrol_new snd_cx88_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .name = "Analog-TV Volume", .info = snd_cx88_volume_info, .get = snd_cx88_volume_get, .put = snd_cx88_volume_put, .tlv.p = snd_cx88_db_scale, };