前言
- Android 的音頻是一個(gè)相當(dāng)復(fù)雜的部分。從應(yīng)用到框架、hal、kernel、最后到硬件,每個(gè)部分的知識(shí)點(diǎn)都相當(dāng)?shù)亩?。而android 這部分代碼在版本之間改動(dòng)很大、其中充斥著各種workaround的處理,讓人看的云里霧里。網(wǎng)上相應(yīng)的分析文章也很多,有些就貼大段的代碼 是很不容易理解的。
- 本系列就遵循從整體到局部, 從簡(jiǎn)單到復(fù)雜來(lái)分析。很多時(shí)候可能是帶著問題來(lái)看文章。而寫博客的目的 一是記錄分析的過(guò)程,從迷茫 混亂到清晰 有序的關(guān)鍵概念和流程的理解。二是對(duì)系統(tǒng)或者框架思想的一個(gè)整體理解,為解決問題打下基礎(chǔ)。
- 總體的一個(gè)理解:借用android 官網(wǎng)的一張圖, 從應(yīng)用層開始,所有封裝中的音頻數(shù)據(jù)經(jīng)過(guò)解碼后為pcm數(shù)據(jù)(或者音頻的裸數(shù)據(jù)),這個(gè)數(shù)據(jù)就拷貝到framework層,framework根據(jù)設(shè)備和配置文件中定義的路由情況,將應(yīng)用層指定的數(shù)據(jù)送到對(duì)應(yīng)的設(shè)備進(jìn)行輸出。
本篇文章的目標(biāo)包括以下幾點(diǎn)
- 從開機(jī)出發(fā)理解android audioservice 中audioflinger、audiopolicy提供怎樣的服務(wù)。
- 從播放出發(fā)理解android的音頻數(shù)據(jù)如何一路送到硬件。
- 從vendor.auio-hal出發(fā)理解hal層提供了怎樣的服務(wù)。
音頻服務(wù)audioserver
-
首先從開機(jī)啟動(dòng)的音頻相關(guān)服務(wù)audioserver開始
- 開機(jī)init.rc文件中和音頻有關(guān)的service audioserver其包括android 音頻框架兩個(gè)最重要的服務(wù)audioflinger 和audiopolicy。當(dāng)然這兩個(gè)服務(wù)之間并沒有相互隔離的很開,有些函數(shù)會(huì)在這兩個(gè)服務(wù)直接相互調(diào)用。
-
audioflinger的作用:
- 跟HAL層的接口進(jìn)行交互的地方, 包括load具體的某個(gè)module的實(shí)現(xiàn),open相應(yīng)的stream、往stream中寫數(shù)據(jù)。
- 為每個(gè)open的stream 創(chuàng)建相對(duì)應(yīng)的線程,并維護(hù)線程和dev之間的關(guān)系,創(chuàng)建線程的時(shí)機(jī)是在成功open stream之后。
- 維護(hù)和暴露給外部接口相對(duì)應(yīng)的track,對(duì)外部track寫到stream的數(shù)據(jù)進(jìn)行處理包括mix、格式轉(zhuǎn)換、采樣率轉(zhuǎn)換、音效處理、音量處理等等。
- 創(chuàng)建patch,為音頻輸入和輸出直接創(chuàng)建通路和線程, 使輸入的數(shù)據(jù)直接輸出到輸出設(shè)備,而不需要通過(guò)應(yīng)用層。
- 根據(jù)配置track的模式、生成不同的線程,對(duì)數(shù)據(jù)進(jìn)行不同的處理 主要有三種分別為direct(track的數(shù)據(jù)直接寫到hal)、mix(經(jīng)過(guò)混音 格式轉(zhuǎn)換等處理)、offload (不經(jīng)過(guò)解碼數(shù)據(jù)直接寫到dsp中。
-
audiopolicy的作用:
- 載入音頻audio_policy_configuration.xml配置文件,并將配置文件中的moules、module、port、profile、routes抽象成代碼中的各種概念比如modules、device、port等等。并在解析到attach device后 去調(diào)用audioflinger的openOutput stream打開設(shè)備.
- 保存路由的信息、這里面包括xml定義的 和 通過(guò)外部注冊(cè)到policy的mix。
- track 啟動(dòng)播放的時(shí)候 會(huì)調(diào)用audiopolicy的接口getoutputfromattr 通過(guò)attr獲取輸出的設(shè)備。獲取設(shè)備后同時(shí)可以找到對(duì)應(yīng)的線程,這樣往track寫的數(shù)據(jù) 就會(huì)寫到hal。
音頻數(shù)據(jù)鏈路
-
簡(jiǎn)單的來(lái)講 外部通過(guò)解碼或者未解碼的數(shù)據(jù) buffer 寫到track(這個(gè)track 可以是應(yīng)用層也可以是framework層,應(yīng)用層的調(diào)用到mediaPlayerservice 中的AudioOutput 其繼承了AudioSink,audioSink是外部用的),
-
從前面的分析可以往這個(gè)track寫數(shù)據(jù)最終都會(huì)要通過(guò)output device對(duì)應(yīng)的線程里面去寫的。可以看出這兩個(gè)是屬于不同的進(jìn)程。一個(gè)是mediaserver 一個(gè)是audioserver,其數(shù)據(jù)交互是通過(guò)匿名共享內(nèi)存來(lái)實(shí)現(xiàn)。 這個(gè)共享內(nèi)存在audioflinger創(chuàng)建track的時(shí)候分配的。在mediaserver 往track寫數(shù)據(jù)的時(shí)候,會(huì)把數(shù)據(jù)拷貝到這個(gè)共享內(nèi)存中,然后audioflinger 把數(shù)據(jù)從共享內(nèi)存中拷貝出來(lái) 經(jīng)過(guò)一系列處理寫到hal中。
hal 提供什么樣的作用
hal的功能有定義的一系列的接口,主要就是打開聲卡設(shè)備、然后往聲卡設(shè)備里面寫數(shù)據(jù)。hal提供給外部audioFlinger的主要接口是openDevice 和open_output_stream。不同vendor實(shí)現(xiàn)的方式不一樣,目前看到的大部分的實(shí)現(xiàn)是基于tinyalsa提供的接口來(lái)實(shí)現(xiàn)對(duì)聲卡控件的操作和聲卡的讀寫。
-
open_output_stream
實(shí)現(xiàn)是創(chuàng)建了stream_out結(jié)構(gòu)體,并賦值實(shí)現(xiàn)stream_out結(jié)構(gòu)體中的不同函數(shù)指針。并將這個(gè)結(jié)構(gòu)體返回給外部調(diào)用。這個(gè)會(huì)轉(zhuǎn)換為外部的結(jié)構(gòu)體 AudioStreamOut。 這個(gè)結(jié)構(gòu)體會(huì)傳遞到audioFlinger 創(chuàng)建MixerThread中,后續(xù)應(yīng)用調(diào)用audiotrack的write 函數(shù)會(huì)調(diào)用到hal層的write函數(shù)hal層使用tinyalsa 或者alsa的寫到內(nèi)核驅(qū)動(dòng)中。
-
out_write
hal中只有在out_write里面才會(huì)真正的去打開底層的硬件 進(jìn)行數(shù)據(jù)的寫入。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-686997.html
總結(jié):
總的來(lái)說(shuō), 外部 framework audioflinger 通過(guò)hal提供的接口創(chuàng)建出dev 和stream以用來(lái)獲取hal層的能力,相關(guān)的接口實(shí)現(xiàn)在audio hal中有定義,然后audioFlinger 通過(guò)調(diào)用dev和stream的指針函數(shù)來(lái)操作hal,主要的接口有打開設(shè)備 打開流 寫數(shù)據(jù) 讀數(shù)據(jù)等等。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-686997.html
到了這里,關(guān)于Android 音頻框架 基于android 12的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!