Alsa里面恶心的DAPM
相關文章
音頻系統,Alsa 里面的buff 是怎么計算的?
為什么需要超過48k的采樣音頻?
我在MTK平臺下調試音頻ALSA
音頻幾個重要的參數
openwrt 音頻開發
(干貨)Ai音箱和Linux音頻驅動小談
Android 音頻數據流分析之程序員干架產品經理
正文
做音頻的很多初學者對這個概念真的非常懵,我也是非常懵,所以寫個文章概述一下,以后遇到問題的時候可以回來看看。
DAPM 從字面上看是和電源相關的,但是我們實際代碼里面有非常多的結構體和函數是跟這個又沒有多少關系,動態調整電源是最終的目的,那些使用的結構體,路由,小控件,都是用來協助完成這個事情的。
#我們用到的一些結構體和函數
這是小控件的結構體,也可以理解成一個開關,是一個通路里面的一個節點。
struct?snd_soc_dapm_widget?//一個整理數組 struct?snd_kcontrol_new?//一個小控件下面這個是路由的結構體,路由一般在machine里面和codec里面存在,就是確定音頻通路設置。
struct?snd_soc_dapm_route路由設置的是 sink source 和 control
sink 可以理解成輸出,source 是數據源頭,control 就是輸出是打到哪個通路的開關的。這里有必要說一下,我們正常的source 一般理解是在左邊,但是這里source 在右邊。
下面是設置小控件的一些宏,不同類型的控件節點需要用到不同的宏
SND_SOC_DAPM_INPUT SND_SOC_DAPM_SUPPLY_S SND_SOC_DAPM_SWITCH#實例
#硬件連接圖
#實現開關選項control
static?const?struct?snd_kcontrol_new?wm8900_loutmix_controls[]?=?{
SOC_DAPM_SINGLE("LINPUT3?Bypass?Switch",?WM8900_REG_LOUTMIXCTL1,?7,?1,?0),
SOC_DAPM_SINGLE("AUX?Bypass?Switch",?WM8900_REG_AUXOUT_CTL,?7,?1,?0),
SOC_DAPM_SINGLE("Left?Input?Mixer?Switch",?WM8900_REG_BYPASS1,?7,?1,?0),
SOC_DAPM_SINGLE("Right?Input?Mixer?Switch",?WM8900_REG_BYPASS2,?3,?1,?0),
SOC_DAPM_SINGLE("DACL?Switch",?WM8900_REG_LOUTMIXCTL1,?8,?1,?0),
};
#實現widget,可以理解把contrl整合到 snd_soc_dapm_widget ?結構體里面
static?const?struct?snd_soc_dapm_widget?wm8900_dapm_widgets[]?=?{ /*?Output?*/SND_SOC_DAPM_MIXER("Left?Output?Mixer",?WM8900_REG_POWER3,?3,?0,wm8900_loutmix_controls,ARRAY_SIZE(wm8900_loutmix_controls)),};#實現路由通路配置
static?const?struct?snd_soc_dapm_route?audio_map[]?=?{{"Left?Output?Mixer",?"Left?Input?Mixer?Switch",?"Left?Input?Mixer"},};可以觀察下 Left Input Mixer Switch 這個字符串就用來制定control 打向了哪個開關,跟 wm8900_loutmix_controls 里面的值對應。
合起來就是通過Left Input Mixer Switch 開關把數據源 Left Input Mixer連接到 Left Output Mixer 輸輸出口。
#將上面設置的widget、route和kcontrols串聯起來
static?int?wm8900_add_widgets(struct?snd_soc_codec?*codec) {snd_soc_dapm_new_controls(codec,?wm8900_dapm_widgets,ARRAY_SIZE(wm8900_dapm_widgets));snd_soc_dapm_add_routes(codec,?audio_map,?ARRAY_SIZE(audio_map));snd_soc_dapm_new_widgets(codec);return?0; }?大概就這樣能夠把目標、源、控制開關串聯起來。我在看MTK內核代碼的時候,里面的實現跟這個有些不一樣,主要是新加了一個結構體,但是本質還是串聯這些東西。
MTK平臺差異部分
##Kcontrol
static?const?struct?snd_kcontrol_new?mt8167_afe_o13_mix[]?=?{SOC_DAPM_SINGLE_AUTODISABLE("I02?Switch",?AFE_GAIN1_CONN2,?4,?1,?0),SOC_DAPM_SINGLE_AUTODISABLE("I15?Switch",?AFE_GAIN1_CONN2,?9,?1,?0), };##widget
static?const?struct?snd_soc_dapm_widget?mt8167_afe_pcm_widgets[]?=?{SND_SOC_DAPM_MIXER("O13",?SND_SOC_NOPM,?0,?0,mt8167_afe_o13_mix,?ARRAY_SIZE(mt8167_afe_o13_mix)), };##route
static?const?struct?snd_soc_dapm_route?mt8167_afe_pcm_routes[]?=?{{"O13",?"I15?Switch",?"I15"}, };##串聯注冊
static?const?struct?snd_soc_component_driver?mt8167_afe_pcm_dai_component?=?{.name?=?"mtk-afe-pcm-dai",.dapm_widgets?=?mt8167_afe_pcm_widgets,.num_dapm_widgets?=?ARRAY_SIZE(mt8167_afe_pcm_widgets),.dapm_routes?=?mt8167_afe_pcm_routes,.num_dapm_routes?=?ARRAY_SIZE(mt8167_afe_pcm_routes), }; ret?=?snd_soc_register_component(&pdev->dev,&mt8167_afe_pcm_dai_component,mt8167_afe_pcm_dais,ARRAY_SIZE(mt8167_afe_pcm_dais));實在話,看英語原文感覺還是很舒服的。
英語原文翻譯如下:
Dynamic?Audio?Power?Management?for?Portable?Devices ===================================================1.?Description ==============Dynamic?Audio?Power?Management?(DAPM)?is?designed?to?allow?portable Linux?devices?to?use?the?minimum?amount?of?power?within?the?audio subsystem?at?all?times.?It?is?independent?of?other?kernel?PM?and?as such,?can?easily?co-exist?with?the?other?PM?systems.DAPM?is?also?completely?transparent?to?all?user?space?applications?as all?power?switching?is?done?within?the?ASoC?core.?No?code?changes?or recompiling?are?required?for?user?space?applications.?DAPM?makes?power switching?decisions?based?upon?any?audio?stream?(capture/playback) activity?and?audio?mixer?settings?within?the?device.DAPM?spans?the?whole?machine.?It?covers?power?control?within?the?entire audio?subsystem,?this?includes?internal?codec?power?blocks?and?machine level?power?systems.There?are?4?power?domains?within?DAPM1.?Codec?domain?–?VREF,?VMID?(core?codec?and?audio?power) Usually?controlled?at?codec?probe/remove?and?suspend/resume,?although can?be?set?at?stream?time?if?power?is?not?needed?for?sidetone,?etc.2.?Platform/Machine?domain?–?physically?connected?inputs?and?outputs Is?platform/machine?and?user?action?specific,?is?configured?by?the machine?driver?and?responds?to?asynchronous?events?e.g?when?HP are?inserted3.?Path?domain?–?audio?susbsystem?signal?paths Automatically?set?when?mixer?and?mux?settings?are?changed?by?the?user. e.g.?alsamixer,?amixer.4.?Stream?domain?–?DACs?and?ADCs. Enabled?and?disabled?when?stream?playback/capture?is?started?and stopped?respectively.?e.g.?aplay,?arecord.All?DAPM?power?switching?decisions?are?made?automatically?by?consulting?an?audio routing?map?of?the?whole?machine.?This?map?is?specific?to?each?machine?and consists?of?the?interconnections?between?every?audio?component?(including internal?codec?components).?All?audio?components?that?effect?power?are?called widgets?hereafter.2.?DAPM?Widgets ===============Audio?DAPM?widgets?fall?into?a?number?of?types:-o?Mixer??????–?Mixes?several?analog?signals?into?a?single?analog?signal. o?Mux????????–?An?analog?switch?that?outputs?only?one?of?many?inputs. o?PGA????????–?A?programmable?gain?amplifier?or?attenuation?widget. o?ADC????????–?Analog?to?Digital?Converter o?DAC????????–?Digital?to?Analog?Converter o?Switch?????–?An?analog?switch o?Input??????–?A?codec?input?pin o?Output?????–?A?codec?output?pin o?Headphone??–?Headphone?(and?optional?Jack) o?Mic????????–?Mic?(and?optional?Jack) o?Line???????–?Line?Input/Output?(and?optional?Jack) o?Speaker????–?Speaker o?Supply?????–?Power?or?clock?supply?widget?used?by?other?widgets. o?Pre????????–?Special?PRE?widget?(exec?before?all?others) o?Post???????–?Special?POST?widget?(exec?after?all?others)(Widgets?are?defined?in?include/sound/soc-dapm.h)Widgets?are?usually?added?in?the?codec?driver?and?the?machine?driver.?There?are convenience?macros?defined?in?soc-dapm.h?that?can?be?used?to?quickly?build?a list?of?widgets?of?the?codecs?and?machines?DAPM?widgets.Most?widgets?have?a?name,?register,?shift?and?invert.?Some?widgets?have?extra parameters?for?stream?name?and?kcontrols.2.1?Stream?Domain?Widgets ————————-Stream?Widgets?relate?to?the?stream?power?domain?and?only?consist?of?ADCs (analog?to?digital?converters)?and?DACs?(digital?to?analog?converters).Stream?widgets?have?the?following?format:-SND_SOC_DAPM_DAC(name,?stream?name,?reg,?shift,?invert),NOTE:?the?stream?name?must?match?the?corresponding?stream?name?in?your?codec snd_soc_codec_dai.e.g.?stream?widgets?for?HiFi?playback?and?captureSND_SOC_DAPM_DAC(“HiFi?DAC”,?“HiFi?Playback”,?REG,?3,?1), SND_SOC_DAPM_ADC(“HiFi?ADC”,?“HiFi?Capture”,?REG,?2,?1),2.2?Path?Domain?Widgets ———————–Path?domain?widgets?have?a?ability?to?control?or?affect?the?audio?signal?or audio?paths?within?the?audio?subsystem.?They?have?the?following?form:-SND_SOC_DAPM_PGA(name,?reg,?shift,?invert,?controls,?num_controls)Any?widget?kcontrols?can?be?set?using?the?controls?and?num_controls?members.e.g.?Mixer?widget?(the?kcontrols?are?declared?first)/*?Output?Mixer?*/ static?const?snd_kcontrol_new_t?wm8731_output_mixer_controls[]?=?{ SOC_DAPM_SINGLE(“Line?Bypass?Switch”,?WM8731_APANA,?3,?1,?0), SOC_DAPM_SINGLE(“Mic?Sidetone?Switch”,?WM8731_APANA,?5,?1,?0), SOC_DAPM_SINGLE(“HiFi?Playback?Switch”,?WM8731_APANA,?4,?1,?0), };SND_SOC_DAPM_MIXER(“Output?Mixer”,?WM8731_PWR,?4,?1,?wm8731_output_mixer_controls, ARRAY_SIZE(wm8731_output_mixer_controls)),If?you?dont?want?the?mixer?elements?prefixed?with?the?name?of?the?mixer?widget, you?can?use?SND_SOC_DAPM_MIXER_NAMED_CTL?instead.?the?parameters?are?the?same as?for?SND_SOC_DAPM_MIXER.2.3?Platform/Machine?domain?Widgets ———————————–Machine?widgets?are?different?from?codec?widgets?in?that?they?don’t?have?a codec?register?bit?associated?with?them.?A?machine?widget?is?assigned?to?each machine?audio?component?(non?codec)?that?can?be?independently?powered.?e.g.o?Speaker?Amp o?Microphone?Bias o?Jack?connectorsA?machine?widget?can?have?an?optional?call?back.e.g.?Jack?connector?widget?for?an?external?Mic?that?enables?Mic?Bias when?the?Mic?is?inserted:-static?int?spitz_mic_bias(struct?snd_soc_dapm_widget*?w,?int?event) { gpio_set_value(SPITZ_GPIO_MIC_BIAS,?SND_SOC_DAPM_EVENT_ON(event)); return?0; }SND_SOC_DAPM_MIC(“Mic?Jack”,?spitz_mic_bias),2.4?Codec?Domain —————-The?codec?power?domain?has?no?widgets?and?is?handled?by?the?codecs?DAPM?event handler.?This?handler?is?called?when?the?codec?powerstate?is?changed?wrt?to?any stream?event?or?by?kernel?PM?events.2.5?Virtual?Widgets ——————-Sometimes?widgets?exist?in?the?codec?or?machine?audio?map?that?don’t?have?any corresponding?soft?power?control.?In?this?case?it?is?necessary?to?create a?virtual?widget?–?a?widget?with?no?control?bits?e.g.SND_SOC_DAPM_MIXER(“AC97?Mixer”,?SND_SOC_DAPM_NOPM,?0,?0,?NULL,?0),This?can?be?used?to?merge?to?signal?paths?together?in?software.After?all?the?widgets?have?been?defined,?they?can?then?be?added?to?the?DAPM subsystem?individually?with?a?call?to?snd_soc_dapm_new_control().3.?Codec?Widget?Interconnections ================================Widgets?are?connected?to?each?other?within?the?codec?and?machine?by?audio?paths (called?interconnections).?Each?interconnection?must?be?defined?in?order?to create?a?map?of?all?audio?paths?between?widgets.This?is?easiest?with?a?diagram?of?the?codec?(and?schematic?of?the?machine?audio system),?as?it?requires?joining?widgets?together?via?their?audio?signal?paths.e.g.,?from?the?WM8731?output?mixer?(wm8731.c)The?WM8731?output?mixer?has?3?inputs?(sources)1.?Line?Bypass?Input 2.?DAC?(HiFi?playback) 3.?Mic?Sidetone?InputEach?input?in?this?example?has?a?kcontrol?associated?with?it?(defined?in?example above)?and?is?connected?to?the?output?mixer?via?it’s?kcontrol?name.?We?can?now connect?the?destination?widget?(wrt?audio?signal)?with?it’s?source?widgets./*?output?mixer?*/ {“Output?Mixer”,?“Line?Bypass?Switch”,?“Line?Input”}, {“Output?Mixer”,?“HiFi?Playback?Switch”,?“DAC”}, {“Output?Mixer”,?“Mic?Sidetone?Switch”,?“Mic?Bias”},So?we?have?:-Destination?Widget??<===?Path?Name?<===?Source?WidgetOr:-Sink,?Path,?SourceOr?:-“Output?Mixer”?is?connected?to?the?“DAC”?via?the?“HiFi?Playback?Switch”.When?there?is?no?path?name?connecting?widgets?(e.g.?a?direct?connection)?we pass?NULL?for?the?path?name.Interconnections?are?created?with?a?call?to:-snd_soc_dapm_connect_input(codec,?sink,?path,?source);Finally,?snd_soc_dapm_new_widgets(codec)?must?be?called?after?all?widgets?and interconnections?have?been?registered?with?the?core.?This?causes?the?core?to scan?the?codec?and?machine?so?that?the?internal?DAPM?state?matches?the physical?state?of?the?machine.3.1?Machine?Widget?Interconnections ———————————– Machine?widget?interconnections?are?created?in?the?same?way?as?codec?ones?and directly?connect?the?codec?pins?to?machine?level?widgets.e.g.?connects?the?speaker?out?codec?pins?to?the?internal?speaker./*?ext?speaker?connected?to?codec?pins?LOUT2,?ROUT2??*/ {“Ext?Spk”,?NULL?,?“ROUT2”}, {“Ext?Spk”,?NULL?,?“LOUT2”},This?allows?the?DAPM?to?power?on?and?off?pins?that?are?connected?(and?in?use) and?pins?that?are?NC?respectively.4?Endpoint?Widgets =================== An?endpoint?is?a?start?or?end?point?(widget)?of?an?audio?signal?within?the machine?and?includes?the?codec.?e.g.o?Headphone?Jack o?Internal?Speaker o?Internal?Mic o?Mic?Jack o?Codec?PinsWhen?a?codec?pin?is?NC?it?can?be?marked?as?not?used?with?a?call?tosnd_soc_dapm_set_endpoint(codec,?“Widget?Name”,?0);The?last?argument?is?0?for?inactive?and?1?for?active.?This?way?the?pin?and?its input?widget?will?never?be?powered?up?and?consume?power.This?also?applies?to?machine?widgets.?e.g.?if?a?headphone?is?connected?to?a jack?then?the?jack?can?be?marked?active.?If?the?headphone?is?removed,?then the?headphone?jack?can?be?marked?inactive.5?DAPM?Widget?Events ====================Some?widgets?can?register?their?interest?with?the?DAPM?core?in?PM?events. e.g.?A?Speaker?with?an?amplifier?registers?a?widget?so?the?amplifier?can?be powered?only?when?the?spk?is?in?use./*?turn?speaker?amplifier?on/off?depending?on?use?*/ static?int?corgi_amp_event(struct?snd_soc_dapm_widget?*w,?int?event) { gpio_set_value(CORGI_GPIO_APM_ON,?SND_SOC_DAPM_EVENT_ON(event)); return?0; }/*?corgi?machine?dapm?widgets?*/ static?const?struct?snd_soc_dapm_widget?wm8731_dapm_widgets?= SND_SOC_DAPM_SPK(“Ext?Spk”,?corgi_amp_event);Please?see?soc-dapm.h?for?all?other?widgets?that?support?events.5.1?Event?types —————The?following?event?types?are?supported?by?event?widgets./*?dapm?event?types?*/ #define?SND_SOC_DAPM_PRE_PMU?0x1??/*?before?widget?power?up?*/ #define?SND_SOC_DAPM_POST_PMU?0x2??/*?after?widget?power?up?*/ #define?SND_SOC_DAPM_PRE_PMD?0x4??/*?before?widget?power?down?*/ #define?SND_SOC_DAPM_POST_PMD?0x8??/*?after?widget?power?down?*/ #define?SND_SOC_DAPM_PRE_REG?0x10?/*?before?audio?path?setup?*/ #define?SND_SOC_DAPM_POST_REG?0x20?/*?after?audio?path?setup?*/? 推薦閱讀:
? ??專輯|Linux文章匯總
? ??專輯|程序人生
? ??專輯|C語言
嵌入式Linux
微信掃描二維碼,關注我的公眾號?
總結
以上是生活随笔為你收集整理的Alsa里面恶心的DAPM的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构银行叫号系统
- 下一篇: js 上传文件