USB音效卡解碼器連接Android手機時問題的出現和分析[四] 最終分析和臨時解決方案
農步祥 于 2017.10.13 08:48:57 | 源自: | 版權:原創
平均/總評分:09.50/171

在經歷三篇分析文章從樂之邦Monitor 06 Plus等幾塊USB音效卡由淺入深至幾乎在被谷歌官方git的Android公開源代碼庫淹死的“奇妙冒險”后,我們可以得知,除了供電、個體裝置兼容性和穩定性等硬性限制外,大多數Android 6.0以上的手機、平板以及機頂盒裝置在通過OTG連接USB2.0音頻規范的音效卡 、解碼器耳放時,不僅會出現絕大多數Android手機都存在的SRC現象,輸出的采樣率還會自動鎖定在192kHz這一頻率上。 雖然經歷了長時間測試、分析并詳細描述了這個現象的起因。但這里還是有必要復習一下Android系統在連接USB音效卡時的大致工作機制流程和問題來源,以助于我們[作者、讀者或廠商]最終完成最后一項微小的工作:如何解決這一問題。

Andorid系統連接USB音效卡時SRC依舊存在

這或許是許多音頻愛好者或發燒友最為關心的問題了,只要經過簡單的測試分析,就可以發現在絕大多數Android系統裝置下,其實際的音頻回放工作步驟是和手機內置音頻CODEC的流程是基本一致的,除了海貝音樂等少量繞過系統音頻抽象層HAL工作機制的應用外,一般的影音應用下音頻回放同樣是由于采樣率鎖定而出現SRC現象的,這點無論是基于樂之邦、XMOS等異步USB方案的千元級到萬元級音效卡解碼器裝置或者簡單廉價如HTC U11本體的耳機線都無法避免。如果用戶既不滿意手機本體音質又偏偏喜歡網易云、蘋果音樂、Google Play等在線音樂應用的。那么用戶還是需要忍受一下SRC帶來的音質劣化,當然如果是高清音頻或者SACD發燒友,由于海貝音樂等應用的存在,可以很好地避免這些問題。

采樣率鎖定在192的原因

雖然“大膽假設”的預判方向正確,但“馬虎求證”的過程差點意外翻車,幸運的是通過對Android系統底層運行資訊的分析,大體上我們還是通過系統源代碼和系統運行狀態找到了問題出現的基本原因。首先是可以得知Android確實會趨向于將USB音效卡的預設采樣率設定為硬體支援的最高值。但由于驅動或HAL某些環節的失誤,Android的音頻抽象層HAL支援的最高采樣率為192kHz,這也成為了XMOS等USB高速異步方案即使最高采樣率超過了192kHz[支援384或更高],而預設采樣率鎖定在192kHz的原因。

進一步的深度分析和尋找解決方案

相信對于本站大多數讀者來說,到了這里已經足夠長見識了。和我們在現實生活中遇到的各類問題一樣,發現是非常容易的,但能通過現象分析問題產生的原因就是非常少了,而能夠掌握并解決問題的專家,就和有權限修改Android源代碼的碼農一樣,永遠只是那么一小撮。避免SRC仍是解決Android裝置在音頻應用中音質、耗電等問題一勞永逸的方法,當然這在某些機型[OPPO R11]或者某些應用場合下就是正解。但相信在購買U11耳機線的十幾萬用戶大軍中,有相當大的用戶數量是以云音樂應用為主力的,有心情和財力找一臺連插頭都對不上的R11似乎也是不大可能。

那么對于這些“一般”的Android手機用戶,有沒有辦法去避免SRC呢?解決SRC的方法無非兩種:1,采樣率自動識別切換;2,用戶指定裝置采樣率。前者iOS[ASIO]和Windows WASAPI已經實現,Android 4.X時期有一段時間也實現了采樣率自動切換能力,但當時的帶來的問題就是極大的音頻延遲,因此從Android 5.X開始,谷歌轉而用改進SRC算法的方式達成了音質和延遲的妥協。除非手機或應用廠商愿意向谷歌分享并說服其對Android音頻子系統進行改造,否則終端用戶很難通過自己的能力去實現。

第二種方式就是類似Windows系統自帶的音頻API[通常是DirectSound]那樣,通過驅動面板指定音效卡采樣率了。雖然我們沒有能力靠自己修改源代碼解決Android SRC問題,但如果能通過簡單粗暴的方式解決讓更多人受益也是極好的。因為,在分析完成后,我們通過進一步的測試,又發現了更多關于Android+USB音效卡的有趣的現象。在體驗Android X86以及Android模擬器時,我們也順便在一臺普通的臺式電腦上硬碟安裝Android X86系統,并連接了一塊樂之邦的數字時代2,驚奇地發現其預設的回放采樣率居然是44.1kHz。而通過播放測試和系統日志分析,系統HAL僅能識別44100Hz,并鎖定采樣率,至少證明了采樣率是可以改變的。

這一現象再次引起了我們的興趣,還對Android X86以及手機平板上運行的Android系統的相關日志分析檔案進行了比對,意外讓我們發現:Android的預設采樣率是可以和Windows那樣自行修改的。和上文一樣,以下涉及Android源代碼的分析,對此無興趣或無了解者可直接跳過。

Android的Audio Policy“音頻策略層”

在分析涉及USB音效卡的源碼時,或許會有一些較為專業的讀者會關注Android系統在連接USB音效卡時為何會設定192kHz?畢竟底層的usb.c代碼片段只是分析音效卡的內核驅動所匯報支援的采樣率,那么是誰最終決定系統使用哪個采樣率的呢?在分析源代碼經歷了若干香蕉和蛋糕后,我們很快找到了答案。那就是HAL中被稱為Audio_policy的“音頻策略層”,這個音頻策略層使用C++編寫,所負責的部分即使不需要仔細閱讀源碼,也能從源代碼代碼目錄結構中輕易分析出它要干什么:根據某個系統預設的文本檔案來設定和管理音效卡的驅動設定。這個設定檔案名也能在現成的手機中找出來:/etc/audio_policy.conf

通過閱讀audio_policy.conf檔案,我們大致可以得知這個設定檔案管理著Android的內置以及外置音頻裝置的采樣率、位率等常規設定。而在USB裝置采樣率生命部分,它是這么寫的:

可以看出,USB裝置的采樣率和位率,并不是具體的數字,而是一個叫dynamic的變量?到這里或許會有無證碼農提出疑問了:dynamic不就是動態的意思嗎?難道Android系統天生就支援采樣率的動態切換?遺憾的是在分析Audio_policy的源代碼后,dynamic這個變量確實存在,但只是被轉換為普通的文本“Dynamic”,并沒有找到任何負責采樣率識別和轉換的部分的運算,經過系統日志分析,更精彩的來了,這個Dynamic通過Audio_policy硬生生把他作為一個可選采樣率傳遞給了底層硬體驅動。

在上一篇源代碼分析中可以得知,usb.c根本是不認識Dynamic這個所謂“動態”采樣率的,會被直接過濾掉。當然這是不是384000采樣率“消失”的元兇就根本無從得知了,或許HAL或AudioFlinger在傳遞采樣率參數期間還做了別的事情。至少到Android 8.0[@Nexus6P]為止,這個動態采樣率切換仍舊是無法實現的。

臨時解決方案

讀到這里,或許已經有人想到這個最“簡單”的解決方法了:沒錯,就是修改/etc/audio_policy.conf。對于網易云用戶來說,只要將usb_device下的sampling_rates從dynamic修改為44100后重新啟動手機,就能將USB音效卡的初始采樣率從192000變更為44100了……雖然影音應用無法得兼,在高清視訊等普遍使用48kHz音軌時會SRC至44.1kHz播放,但至少已經做到了可控,對于強迫癥用戶來說,還可以設定一下音效卡回放的位率[XMOS、樂之邦方案預設是32bit,可以切換至24、16bit,語法可參考設定文本其它區域]。要說明的是,如果試圖通過在配置檔案列舉采樣率的方法實現動態采樣率切換[如44100|48000|96000],是無效的。至于高清音頻應用,這一修改并不會對海貝音樂等本來就繞過HAL的應用程式帶來造成兼容性影響。

不過,audio_policy.conf是系統檔案,也就意味著用戶需要破解手機獲得root權限來修改了。這一方法簡單粗暴有效,發現和解決過程似乎不如調教某K860那么有挑戰性,但這也意味著裝置會失去保修,而修改時由于手癢或手殘很容易造成配置檔案語法錯誤導致系統無聲甚至無法正常啟動的慘劇,另外這個檔案并不是通用的,無法通過簡單的復制粘貼來解決。因此我們不鼓勵推薦用戶自己動手,而是直接反饋給裝置廠商來通過系統更新修正更為廣譜有效。當然,也可以等待到某天谷歌真的實現動態采樣率切換了,將SRC問題徹底扔進垃圾桶里。

 

轉發到新浪微博 轉發到騰訊微博 RSS訂閱 收藏本文 本文代碼
請您評分 1 2 3 4 5 6 7 8 9 10
017.087.***.***
017.087.***.***
46
222.078.144.***
222.078.144.***
發表于2017.10.29 22:16:34
45
203.156.222.***
203.156.222.***
發表于2017.10.25 08:28:16
44
106.039.041.***
106.039.041.***
發表于2017.10.24 01:58:23
43
180.118.067.***
180.118.067.***
發表于2017.10.20 20:39:23
42
發表于2017.10.20 20:39:07
41
183.031.098.***
183.031.098.***
發表于2017.10.17 21:54:21
39
113.092.***.***
113.092.***.***
三星note8 + UD-503來測試一波:
自帶音樂app & 蝦米音樂,
播放16bit 44.1kHz MP3,輸出48kHz,估計特殊處理了;
播放16bit 192kHz flac,輸出192kHz;
播放DSD64 dff,輸出192kHz。
到這里還算正常。
播放24bit 48kHz flac,輸出192kHz……
嘛理解不能。
——詳細閱讀
發表于2017.10.17 19:19:12
38
呃 這bug 這是倆人沒協調好的節奏 dynamic應該是其中一個開發者的一廂情愿
此帖使用LE X820提交
發表于2017.10.17 12:26:43
37
182.131.010.***
182.131.010.***
發表于2017.10.17 10:09:52
36
218.104.207.***
218.104.207.***
發表于2017.10.16 08:44:54
35
用海貝音樂看,輸出的都是48000啊,不支援44100?
發表于2017.10.16 08:43:46
34
118.161.078.***
118.161.078.***
發表于2017.10.16 00:27:41
33
060.017.207.***
060.017.207.***
發表于2017.10.15 18:41:05
32
171.216.***.***
171.216.***.***
改了以后u11的線能鎖定44.1了?
此帖使用Win10提交
發表于2017.10.15 12:27:46
31
221.011.061.***
221.011.061.***
發表于2017.10.15 08:43:04
30
221.002.***.***
221.002.***.***

此帖使用REDMI NOTE 4提交
發表于2017.10.14 19:02:33
29
123.147.***.***
123.147.***.***
25L還可以看看vendor檔案夾下還有沒有配置檔案
此帖使用QK8692提交
發表于2017.10.14 17:40:02
28
提示本貼可以匿名回復 ,您現在正處在潛水狀態
回復
驗證碼
1662 為防止廣告機貼垃圾,不得已而為之
表情
正文