ALSA声卡驱动中的DAPM详解之二:widget-具备路径和电源管理信息的kcontrol

本文深入探讨了DAPM框架的设计思想与工作原理,重点介绍了其核心组件widget和path,以及它们如何解决音频硬件控制中的复杂问题。

上一篇文章中,我们介绍了音频驱动中对基本控制单元的封装:kcontrol。利用kcontrol,我们可以完成对音频系统中的mixer,mux,音量控制,音效控制,以及各种开关量的控制,通过对各种kcontrol的控制,使得音频硬件能够按照我们预想的结果进行工作。同时我们可以看到,kcontrol还是有以下几点不足:

 

  • 只能描述自身,无法描述各个kcontrol之间的连接关系;
  • 没有相应的电源管理机制;
  • 没有相应的时间处理机制来响应播放、停止、上电、下电等音频事件;
  • 为了防止pop-pop声,需要用户程序关注各个kcontrol上电和下电的顺序;
  • 当一个音频路径不再有效时,不能自动关闭该路径上的所有的kcontrol;

 

/*****************************************************************************************************/
声明:本博内容均由http://blog.youkuaiyun.com/droidphone原创,转载请注明出处,谢谢!
/*****************************************************************************************************/

为此,DAPM框架正是为了要解决以上这些问题而诞生的,DAPM目前已经是ASoc中的重要组成部分,让我们先从DAPM的数据结构开始,了解它的设计思想和工作原理。

 

DAPM的基本单元:widget


 

 

文章的开头,我们说明了一下目前kcontrol的一些不足,而DAPM框架为了解决这些问题,引入了widget这一概念,所谓widget,其实可以理解为是kcontrol的进一步升级和封装,她同样是指音频系统中的某个部件,比如mixer,mux,输入输出引脚,电源供应器等等,甚至,我们可以定义虚拟的widget,例如playback stream widget。widget把kcontrol和动态电源管理进行了有机的结合,同时还具备音频路径的连结功能,一个widget可以与它相邻的widget有某种动态的连结关系。在DAPM框架中,widget用结构体snd_soc_dapm_widget来描述:

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. struct snd_soc_dapm_widget {  
  2.         enum snd_soc_dapm_type id;  
  3.         const char *name;               /* widget name */  
  4.   
  5.         ......  
  6.         /* dapm control */  
  7.         int reg;                                /* negative reg = no direct dapm */  
  8.         unsigned char shift;                    /* bits to shift */  
  9.         unsigned int value;                             /* widget current value */  
  10.         unsigned int mask;                      /* non-shifted mask */  
  11.         ......  
  12.   
  13.         int (*power_check)(struct snd_soc_dapm_widget *w);  
  14.   
  15.         int (*event)(struct snd_soc_dapm_widget*, struct snd_kcontrol *, int);  
  16.   
  17.         /* kcontrols that relate to this widget */  
  18.         int num_kcontrols;  
  19.         const struct snd_kcontrol_new *kcontrol_news;  
  20.         struct snd_kcontrol **kcontrols;  
  21.   
  22.         /* widget input and outputs */  
  23.         struct list_head sources;  
  24.         struct list_head sinks;  
  25.         ......  
  26. };  

snd_soc_dapm_widget结构比较大,为了简洁一些,这里我没有列出该结构体的完整字段,不过不用担心,下面我会说明每个字段的意义:

 

id    该widget的类型值,比如snd_soc_dapm_output,snd_soc_dapm_mixer等等。

*name    该widget的名字

*sname    代表该widget所在stream的名字,比如对于snd_soc_dapm_dai_in类型的widget,会使用该字段。

*codec *platform    指向该widget所属的codec和platform。

list    所有注册到系统中的widget都会通过该list,链接到代表声卡的snd_soc_card结构的widgets链表头字段中。

*dapm    snd_soc_dapm_context结构指针,ASoc把系统划分为多个dapm域,每个widget属于某个dapm域,同一个域代表着同样的偏置电压供电策略,比如,同一个codec中的widget通常位于同一个dapm域,而平台上的widget可能又会位于另外一个platform域中。

*priv    有些widget可能需要一些专有的数据,可以使用该字段来保存,像snd_soc_dapm_dai_in类型的widget,会使用该字段来记住与之相关联的snd_soc_dai结构指针。

*regulator    对于snd_soc_dapm_regulator_supply类型的widget,该字段指向与之相关的regulator结构指针。

*params    目前对于snd_soc_dapm_dai_link类型的widget,指向该dai的配置信息的snd_soc_pcm_stream结构。

reg shift mask     这3个字段用来控制该widget的电源状态,分别对应控制信息所在的寄存器地址,位移值和屏蔽值。

value  on_val  off_val    电源状态的当前只,开启时和关闭时所对应的值。

power invert    用于指示该widget当前是否处于上电状态,invert则用于表明power字段是否需要逻辑反转。

active connected    分别表示该widget是否处于激活状态和连接状态,当和相邻的widget有连接关系时,connected位会被置1,否则置0。

new   我们定义好的widget(snd_soc_dapm_widget结构),在注册到声卡中时需要进行实例化,该字段用来表示该widget是否已经被实例化。

ext    表示该widget当前是否有外部连接,比如连接mic,耳机,喇叭等等。

force    该位被设置后,将会不管widget当前的状态,强制更新至新的电源状态。

ignore_suspend new_power power_checked    这些电源管理相关的字段。

subseq    该widget目前在上电或下电队列中的排序编号,为了防止在上下电的过程中出现pop-pop声,DAPM会给每个widget分配合理的上下电顺序。

*power_check    用于检查该widget是否应该上电或下电的回调函数指针。
event_flags    该字段是一个位或字段,每个位代表该widget会关注某个DAPM事件通知。只有被关注的通知事件会被发送到widget的事件处理回调函数中。

*event    DAPM事件处理回调函数指针。

num_kcontrols *kcontrol_news **kcontrols    这3个字段用来描述与该widget所包含的kcontrol控件,例如一个mixer控件或者是一个mux控件。

 

sources sinks    两个链表字段,两个widget如果有连接关系,会通过一个snd_soc_dapm_path结构进行连接,sources链表用于链接所有的输入path,sinks链表用于链接所有的输出path。

power_list    每次更新整个dapm的电源状态时,会根据一定的算法扫描所有的widget,然后把需要变更电源状态的widget利用该字段链接到一个上电或下电的链表中,扫描完毕后,dapm系统会遍历这两个链表执行相应的上电或下电操作。

dirty    链表字段,widget的状态变更后,dapm系统会利用该字段,把该widget加入到一个dirty链表中,稍后会对dirty链表进行扫描,以执行整个路径的更新。

inputs    该widget的所有有效路径中,连接到输入端的路径数量。

outputs    该widget的所有有效路径中,连接到输出端的路径数量。

*clk    对于snd_soc_dapm_clock_supply类型的widget,指向相关联的clk结构指针。

以上我们对snd_soc_dapm_widget结构的各个字段所代表的意义一一做出了说明,这里只是让大家现有个概念,至于每个字段的详细作用,我们会在以后相关的章节中提及。

widget的种类


 

在DAPM框架中,把各种不同的widget划分为不同的种类,snd_soc_dapm_widget结构中的id字段用来表示该widget的种类,可选的种类都定义在一个枚举中:

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. /* dapm widget types */  
  2. enum snd_soc_dapm_type {......}  

下面我们逐个解释一下这些widget的种类:

 

 

  • snd_soc_dapm_input     该widget对应一个输入引脚。
  • snd_soc_dapm_output    该widget对应一个输出引脚。
  • snd_soc_dapm_mux    该widget对应一个mux控件。
  • snd_soc_dapm_virt_mux    该widget对应一个虚拟的mux控件。
  • snd_soc_dapm_value_mux    该widget对应一个value类型的mux控件。
  • snd_soc_dapm_mixer    该widget对应一个mixer控件。
  • snd_soc_dapm_mixer_named_ctl    该widget对应一个mixer控件,但是对应的kcontrol的名字不会加入widget的名字作为前缀。
  • snd_soc_dapm_pga    该widget对应一个pga控件(可编程增益控件)。
  • snd_soc_dapm_out_drv    该widget对应一个输出驱动控件
  • snd_soc_dapm_adc    该widget对应一个ADC 
  • snd_soc_dapm_dac    该widget对应一个DAC 
  • snd_soc_dapm_micbias    该widget对应一个麦克风偏置电压控件
  • snd_soc_dapm_mic    该widget对应一个麦克风。
  • snd_soc_dapm_hp    该widget对应一个耳机。
  • snd_soc_dapm_spk    该widget对应一个扬声器。
  • snd_soc_dapm_line     该widget对应一个线路输入。
  • snd_soc_dapm_switch       该widget对应一个模拟开关。
  • snd_soc_dapm_vmid      该widget对应一个codec的vmid偏置电压。
  • snd_soc_dapm_pre      machine级别的专用widget,会先于其它widget执行检查操作。
  • snd_soc_dapm_post    machine级别的专用widget,会后于其它widget执行检查操作。
  • snd_soc_dapm_supply           对应一个电源或是时钟源。
  • snd_soc_dapm_regulator_supply  对应一个外部regulator稳压器。
  • snd_soc_dapm_clock_supply      对应一个外部时钟源。
  • snd_soc_dapm_aif_in            对应一个数字音频输入接口,比如I2S接口的输入端。
  • snd_soc_dapm_aif_out          对应一个数字音频输出接口,比如I2S接口的输出端。
  • snd_soc_dapm_siggen            对应一个信号发生器。
  • snd_soc_dapm_dai_in           对应一个platform或codec域的输入DAI结构。
  • snd_soc_dapm_dai_out        对应一个platform或codec域的输出DAI结构。
  • snd_soc_dapm_dai_link         用于链接一对输入/输出DAI结构。

 

widget之间的连接器:path


 

之前已经提到,一个widget是有输入和输出的,而且widget之间是可以动态地进行连接的,那它们是用什么来连接两个widget的呢?DAPM为我们提出了path这一概念,path相当于电路中的一根跳线,它把一个widget的输出端和另一个widget的输入端连接在一起,path用snd_soc_dapm_path结构来描述:

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. struct snd_soc_dapm_path {  
  2.         const char *name;  
  3.   
  4.         /* source (input) and sink (output) widgets */  
  5.         struct snd_soc_dapm_widget *source;  
  6.         struct snd_soc_dapm_widget *sink;  
  7.         struct snd_kcontrol *kcontrol;  
  8.   
  9.         /* status */  
  10.         u32 connect:1;  /* source and sink widgets are connected */  
  11.         u32 walked:1;   /* path has been walked */  
  12.         u32 walking:1;  /* path is in the process of being walked */  
  13.         u32 weak:1;     /* path ignored for power management */  
  14.   
  15.         int (*connected)(struct snd_soc_dapm_widget *source,  
  16.                          struct snd_soc_dapm_widget *sink);  
  17.   
  18.         struct list_head list_source;  
  19.         struct list_head list_sink;  
  20.         struct list_head list;  
  21. };  

当widget之间发生连接关系时,snd_soc_dapm_path作为连接者,它的source字段会指向该连接的起始端widget,而它的sink字段会指向该连接的到达端widget,还记得前面snd_soc_dapm_widget结构中的两个链表头字段:sources和sinks么?widget的输入端和输出端可能连接着多个path,所有输入端的snd_soc_dapm_path结构通过list_sink字段挂在widget的souces链表中,同样,所有输出端的snd_soc_dapm_path结构通过list_source字段挂在widget的sinks链表中。这里可能大家会被搞得晕呼呼的,一会source,一会sink,不要紧,只要记住,连接的路径是这样的:起始端widget的输出-->path的输入-->path的输出-->到达端widget输入。

 



                                                                                   图1    widget通过path进行连接

另外,snd_soc_dapm_path结构的list字段用于把所有的path注册到声卡中,其实就是挂在snd_soc_card结构的paths链表头字段中。如果你要自己定义方法来检查path的当前连接状态,你可以提供自己的connected回调函数指针。

connect,walked,walking,weak是几个辅助字段,用于帮助所有path的遍历。

widget的连接关系:route


通过上一节的内容,我们知道,一个路径的连接至少包含以下几个元素:起始端widget,跳线path,到达端widget,在DAPM中,用snd_soc_dapm_route结构来描述这样一个连接关系:

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. struct snd_soc_dapm_route {  
  2.         const char *sink;  
  3.         const char *control;  
  4.         const char *source;  
  5.         int (*connected)(struct snd_soc_dapm_widget *source,  
  6.                          struct snd_soc_dapm_widget *sink);  
  7. };  

sink指向到达端widget的名字字符串,source指向起始端widget的名字字符串,control指向负责控制该连接所对应的kcontrol名字字符串,connected回调则定义了上一节所提到的自定义连接检查回调函数。该结构的意义很明显就是:source通过一个kcontrol,和sink连接在一起,现在是否处于连接状态,请调用connected回调函数检查。

 

这里直接使用名字字符串来描述连接关系,所有定义好的route,最后都要注册到dapm系统中,dapm会根据这些名字找出相应的widget,并动态地生成所需要的snd_soc_dapm_path结构,正确地处理各个链表和指针的关系,实现两个widget之间的连接,具体的连接代码分析,我们留到以后的章节中讨论。

转载于:https://www.cnblogs.com/Ph-one/p/6297382.html

内容概要:本文系统阐述了企业新闻发稿在生成式引擎优化(GEO)时代下的全渠道策略与效果评估体系,涵盖当前企业传播面临的预算、资源、内容与效果评估四大挑战,并深入分析2025年新闻发稿行业五大趋势,包括AI驱动的智能化转型、精准化传播、首发内容价值提升、内容资产化及数据可视化。文章重点解析央媒、地方官媒、综合门户自媒体四类媒体资源的特性、传播优势与发稿策略,提出基于内容适配性、时间节奏、话题设计的策略制定方法,并构建涵盖品牌价值、销售转化与GEO优化的多维评估框架。此外,结合“传声港”工具实操指南,提供AI智能投放、效果监测、自媒体管理与舆情应对的全流程解决方案,并针对科技、消费、B2B、区域品牌四大行业推出定制化发稿方案。; 适合人群:企业市场/公关负责人、品牌传播管理者、数字营销从业者及中小企业决策者,具备一定媒体传播经验并希望提升发稿效率与ROI的专业人士。; 使用场景及目标:①制定科学的新闻发稿策略,实现从“流量思维”向“价值思维”转型;②构建央媒定调、门户扩散、自媒体互动的立体化传播矩阵;③利用AI工具实现精准投放与GEO优化,提升品牌在AI搜索中的权威性与可见性;④通过数据驱动评估体系量化品牌影响力与销售转化效果。; 阅读建议:建议结合文中提供的实操清单、案例分析与工具指南进行系统学习,重点关注媒体适配性策略与GEO评估指标,在实际发稿中分阶段试点“AI+全渠道”组合策略,并定期复盘优化,以实现品牌传播的长期复利效应。
【EI复现】基于主从博弈的新型城镇配电系统产消者竞价策略【IEEE33节点】(Matlab代码实现)内容概要:本文介绍了基于主从博弈理论的新型城镇配电系统中产消者竞价策略的研究,结合IEEE33节点系统进行建模与仿真分析,采用Matlab代码实现。研究聚焦于产消者(兼具发电与用电能力的主体)在配电系统中的竞价行为,运用主从博弈模型刻画配电公司与产消者之间的交互关系,通过优化算法求解均衡策略,实现利益最大化与系统运行效率提升。文中详细阐述了模型构建、博弈机制设计、求解算法实现及仿真结果分析,复现了EI期刊级别的研究成果,适用于电力市场机制设计与智能配电网优化领域。; 适合人群:具备电力系统基础知识Matlab编程能力,从事电力市场、智能电网、能源优化等相关领域的研究生、科研人员及工程技术人员。; 使用场景及目标:①学习主从博弈在电力系统中的建模方法;②掌握产消者参与电力竞价的策略优化技术;③复现EI级别论文的仿真流程与结果分析;④开展配电网经济调度与市场机制设计的相关课题研究。; 阅读建议:建议读者结合提供的Matlab代码,深入理解博弈模型的数学表达与程序实现细节,重点关注目标函数构建、约束条件处理及算法收敛性分析,可进一步拓展至多主体博弈或多时间尺度优化场景。
【BFO-BP】基于鳑鲏鱼优化算法优化BP神经网络的风电功率预测研究(Matlab代码实现)内容概要:本文研究了基于鳑鲏鱼优化算法(BFO)优化BP神经网络的风电功率预测方法,并提供了相应的Matlab代码实现。通过将生物启发式优化算法与传统BP神经网络相结合,利用鳑鲏鱼算法优化BP网络的初始权重阈值,有效提升了模型的收敛速度与预测精度,解决了传统BP神经网络易陷入局部最优、训练效率低等问题。该方法在风电功率预测这一典型非线性时序预测任务中展现出良好的适用性优越性,有助于提升风电并网的稳定性与调度效率。; 适合人群:具备一定机器学习与优化算法基础,从事新能源预测、电力系统调度或智能算法研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①应用于风电场短期或超短期功率预测,提高电网调度的准确性;②作为智能优化算法与神经网络结合的典型案例,用于学习BFO等群智能算法在实际工程问题中的优化机制与实现方式;③为类似非线性系统建模与预测问题提供可复现的技术路线参考。; 阅读建议:建议读者结合Matlab代码深入理解算法实现细节,重点关注BFO算法的种群初始化、适应度函数设计、参数更新机制及其与BP网络的耦合方式,同时可通过更换数据集或对比其他优化算法(如PSO、GA)进一步验证模型性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值