有没有做任务给钱的网站,苏州定制型网站建设,买微单的网站建设,wordpress 移动主菜单声明#xff1a;本博内容均由http://blog.csdn.net/droidphone原创#xff0c;转载请注明出处#xff0c;谢谢#xff01; Control接口 Control接口主要让用户空间的应用程序#xff08;alsa-lib#xff09;可以访问和控制音频codec芯片中的多路开关#xff0c;滑动控件…声明本博内容均由http://blog.csdn.net/droidphone原创转载请注明出处谢谢 Control接口 Control接口主要让用户空间的应用程序alsa-lib可以访问和控制音频codec芯片中的多路开关滑动控件等。对于Mixer混音来说Control接口显得尤为重要从ALSA 0.9.x版本开始所有的mixer工作都是通过control接口的API来实现的。 ALSA已经为AC97定义了完整的控制接口模型如果你的Codec芯片只支持AC97接口你可以不用关心本节的内容。 sound/control.h定义了所有的Control API。如果你要为你的codec实现自己的controls请在代码中包含该头文件。 Controls的定义 要自定义一个Control我们首先要定义3各回调函数infoget和put。然后定义一个snd_kcontrol_new结构 [c-sharp] view plaincopy static struct snd_kcontrol_new my_control __devinitdata { .iface SNDRV_CTL_ELEM_IFACE_MIXER, .name PCM Playback Switch, .index 0, .access SNDRV_CTL_ELEM_ACCESS_READWRITE, .private_value 0xffff, .info my_control_info, .get my_control_get, .put my_control_put }; iface字段指出了control的类型alsa定义了几种类型SNDDRV_CTL_ELEM_IFACE_XXX常用的类型是MIXER当然也可以定义属于全局的CARD类型也可以定义属于某类设备的类型例如HWDEPPCMRAWMIDITIMER等这时需要在device和subdevice字段中指出卡的设备逻辑编号。 name字段是该control的名字从ALSA 0.9.x开始control的名字是变得比较重要因为control的作用是按名字来归类的。ALSA已经预定义了一些control的名字我们再Control Name一节详细讨论。 index字段用于保存该control的在该卡中的编号。如果声卡中有不止一个codec每个codec中有相同名字的control这时我们可以通过index来区分这些controls。当index为0时则可以忽略这种区分策略。 access字段包含了该control的访问类型。每一个bit代表一种访问类型这些访问类型可以多个“或”运算组合在一起。 private_value字段包含了一个任意的长整数类型值。该值可以通过infogetput这几个回调函数访问。你可以自己决定如何使用该字段例如可以把它拆分成多个位域又或者是一个指针指向某一个数据结构。 tlv字段为该control提供元数据。 Control的名字 control的名字需要遵循一些标准通常可以分成3部分来定义control的名字源--方向--功能。 源可以理解为该control的输入端alsa已经预定义了一些常用的源例如MasterPCMCDLine等等。 方向代表该control的数据流向例如PlaybackCaptureBypassBypass Capture等等也可以不定义方向这时表示该Control是双向的playback和capture。 功能根据control的功能可以是以下字符串SwitchVolumeRoute等等。 也有一些命名上的特例 全局的capture和playback Capture SourceCapture VolumeCapture Switch它们用于全局的capture sourceswitch和volume。同理Playback VolumePlayback Switch它们用于全局的输出switch和volume。Tone-controles 音调控制的开关和音量命名为Tone Control - XXX例如Tone Control - SwitchTone Control - BassTone Control - Center。3D controls 3D控件的命名规则3D Control - Switch3D Control - Center3D Control - Space。Mic boost 麦克风音量加强控件命名为Mic Boost或Mic Boost(6dB)。访问标志ACCESS Flags Access字段是一个bitmask它保存了改control的访问类型。默认的访问类型是SNDDRV_CTL_ELEM_ACCESS_READWRITE表明该control支持读和写操作。如果access字段没有定义.access0此时也认为是READWRITE类型。 如果是一个只读controlaccess应该设置为SNDDRV_CTL_ELEM_ACCESS_READ这时我们不必定义put回调函数。类似地如果是只写controlaccess应该设置为SNDDRV_CTL_ELEM_ACCESS_WRITE这时我们不必定义get回调函数。 如果control的值会频繁地改变例如电平表我们可以使用VOLATILE类型这意味着该control会在没有通知的情况下改变应用程序应该定时地查询该control的值。 回调函数 info回调函数 info回调函数用于获取control的详细信息。它的主要工作就是填充通过参数传入的snd_ctl_elem_info对象以下例子是一个具有单个元素的boolean型control的info回调 [c-sharp] view plaincopy static int snd_myctl_mono_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo-type SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo-count 1; uinfo-value.integer.min 0; uinfo-value.integer.max 1; return 0; } type字段指出该control的值类型值类型可以是BOOLEAN, INTEGER, ENUMERATED, BYTES,IEC958和INTEGER64之一。count字段指出了改control中包含有多少个元素单元比如立体声的音量control左右两个声道的音量值它的count字段等于2。value字段是一个联合体unionvalue的内容和control的类型有关。其中boolean和integer类型是相同的。 ENUMERATED类型有些特殊。它的value需要设定一个字符串和字符串的索引请看以下例子 [c-sharp] view plaincopy static int snd_myctl_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { static char *texts[4] { First, Second, Third, Fourth }; uinfo-type SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo-count 1; uinfo-value.enumerated.items 4; if (uinfo-value.enumerated.item 3) uinfo-value.enumerated.item 3; strcpy(uinfo-value.enumerated.name, texts[uinfo-value.enumerated.item]); return 0; } alsa已经为我们实现了一些通用的info回调函数例如snd_ctl_boolean_mono_info()snd_ctl_boolean_stereo_info()等等。 get回调函数 该回调函数用于读取control的当前值并返回给用户空间的应用程序。 [c-sharp] view plaincopy static int snd_myctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct mychip *chip snd_kcontrol_chip(kcontrol); ucontrol-value.integer.value[0] get_some_value(chip); return 0; } value字段的赋值依赖于control的类型如同info回调。很多声卡的驱动利用它存储硬件寄存器的地址、bit-shift和bit-mask这时private_value字段可以按以下例子进行设置 .private_value reg | (shift 16) | (mask 24); 然后get回调函数可以这样实现 static int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int reg kcontrol-private_value 0xff; int shift (kcontrol-private_value 16) 0xff; int mask (kcontrol-private_value 24) 0xff; .... //根据以上的值读取相应寄存器的值并填入value中} 如果control的count字段大于1表示control有多个元素单元get回调函数也应该为value填充多个数值。 put回调函数 put回调函数用于把应用程序的控制值设置到control中。 [c-sharp] view plaincopy static int snd_myctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct mychip *chip snd_kcontrol_chip(kcontrol); int changed 0; if (chip-current_value ! ucontrol-value.integer.value[0]) { change_current_value(chip, ucontrol-value.integer.value[0]); changed 1; } return changed; } 如上述例子所示当control的值被改变时put回调必须要返回1如果值没有被改变则返回0。如果发生了错误则返回一个负数的错误号。 和get回调一样当control的count大于1时put回调也要处理多个control中的元素值。 创建Controls 当把以上讨论的内容都准备好了以后我们就可以创建我们自己的control了。alsa-driver为我们提供了两个用于创建control的API snd_ctl_new1()snd_ctl_add()我们可以用以下最简单的方式创建control [c-sharp] view plaincopy err snd_ctl_add(card, snd_ctl_new1(my_control, chip)); if (err 0) return err; 在这里my_control是一个之前定义好的snd_kcontrol_new对象chip对象将会被赋值在kcontrol-private_data字段该字段可以在回调函数中访问。 snd_ctl_new1()会分配一个新的snd_kcontrol实例并把my_control中相应的值复制到该实例中所以在定义my_control时通常我们可以加上__devinitdata前缀。snd_ctl_add则把该control绑定到声卡对象card当中。 元数据Metadata 很多mixer control需要提供以dB为单位的信息我们可以使用DECLARE_TLV_xxx宏来定义一些包含这种信息的变量然后把control的tlv.p字段指向这些变量最后在access字段中加上SNDRV_CTL_ELEM_ACCESS_TLV_READ标志就像这样 static DECLARE_TLV_DB_SCALE(db_scale_my_control, -4050, 150, 0); static struct snd_kcontrol_new my_control __devinitdata { ... .access SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, ... .tlv.p db_scale_my_control,}; DECLARE_TLV_DB_SCALE宏定义的mixer control它所代表的值按一个固定的dB值的步长变化。该宏的第一个参数是要定义变量的名字第二个参数是最小值以0.01dB为单位。第三个参数是变化的步长也是以0.01dB为单位。如果该control处于最小值时会做出mute时需要把第四个参数设为1。 DECLARE_TLV_DB_LINEAR宏定义的mixer control它的输出随值的变化而线性变化。 该宏的第一个参数是要定义变量的名字第二个参数是最小值以0.01dB为单位。第二个参数是最大值以0.01dB为单位。如果该control处于最小值时会做出mute时需要把第二个参数设为TLV_DB_GAIN_MUTE。 这两个宏实际上就是定义一个整形数组所谓tlv就是Type-Lenght-Value的意思数组的第0各元素代表数据的类型第1个元素代表数据的长度第三个元素和之后的元素保存该变量的数据。 Control设备的建立 Control设备和PCM设备一样都属于声卡下的逻辑设备。用户空间的应用程序通过alsa-lib访问该Control设备读取或控制control的控制状态从而达到控制音频Codec进行各种Mixer等控制操作。 Control设备的创建过程大体上和PCM设备的创建过程相同。详细的创建过程可以参考本博的另一篇文章Linux音频驱动之三PCM设备的创建。下面我们只讨论有区别的地方。 我们需要在我们的驱动程序初始化时主动调用snd_pcm_new()函数创建pcm设备而control设备则在snd_card_create()内被创建snd_card_create()通过调用snd_ctl_create()函数创建control设备节点。所以我们无需显式地创建control设备只要建立声卡control设备被自动地创建。 和pcm设备一样control设备的名字遵循一定的规则controlCxx这里的xx代表声卡的编号。我们也可以通过代码正是这一点下面的是snd_ctl_dev_register()函数的代码 [c-sharp] view plaincopy /* * registration of the control device */ static int snd_ctl_dev_register(struct snd_device *device) { struct snd_card *card device-device_data; int err, cardnum; char name[16]; if (snd_BUG_ON(!card)) return -ENXIO; cardnum card-number; if (snd_BUG_ON(cardnum 0 || cardnum SNDRV_CARDS)) return -ENXIO; /* control设备的名字 */ sprintf(name, controlC%i, cardnum); if ((err snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1, snd_ctl_f_ops, card, name)) 0) return err; return 0; } snd_ctl_dev_register()函数会在snd_card_register()中即声卡的注册阶段被调用。注册完成后control设备的相关信息被保存在snd_minors[]数组中用control设备的此设备号作索引即可在snd_minors[]数组中找出相关的信息。注册完成后的数据结构关系可以用下图进行表述 control设备的操作函数入口 用户程序需要打开control设备时驱动程序通过snd_minors[]全局数组和此设备号可以获得snd_ctl_f_ops结构中的各个回调函数然后通过这些回调函数访问control中的信息和数据最终会调用control的几个回调函数getputinfo。详细的代码我就不贴了大家可以读一下代码/sound/core/control.c。转载于:https://www.cnblogs.com/Ph-one/p/6292597.html