在Android開(kāi)發(fā)中,音頻模塊的調(diào)試往往是“老大難”——多聲卡無(wú)法區(qū)分、多設(shè)備同時(shí)輸出沒(méi)聲音、HDMI錄音崩潰…這些問(wèn)題不僅影響用戶體驗(yàn),還會(huì)消耗大量開(kāi)發(fā)時(shí)間。
瑞芯微(Rockchip)針對(duì)RK平臺(tái)推出的MultiAudio方案,專門解決Android原生音頻框架的局限,同時(shí)提供了一套清晰的調(diào)試方法論。今天這篇文章,就從實(shí)戰(zhàn)角度出發(fā),帶大家搞定RK Android平臺(tái)的音頻調(diào)試,覆蓋基礎(chǔ)操作、常見(jiàn)Bug解決、多設(shè)備控制等核心場(chǎng)景。

一、先搞懂:Android原生音頻的“痛點(diǎn)”與MultiAudio解決方案
在聊調(diào)試前,我們得先明白“為什么需要調(diào)試”——Android原生音頻框架存在不少局限,這也是RK MultiAudio方案的出發(fā)點(diǎn):
1.多聲卡“認(rèn)不出、用不了”:即使設(shè)備支持多個(gè)聲卡(比如雙HDMI、SPDIF),原生系統(tǒng)會(huì)按AudioPolicy優(yōu)先級(jí)選最高的,無(wú)法讓不同聲卡同時(shí)輸出不同聲音;多個(gè)同類型聲卡(如雙HDMI)更是無(wú)法區(qū)分。
2.多設(shè)備錄音需適配:Android 12雖支持多設(shè)備同時(shí)錄音,但原生代碼默認(rèn)不支持,需要廠商針對(duì)性開(kāi)發(fā)。
3.多APP音頻沖突:系統(tǒng)音頻焦點(diǎn)機(jī)制會(huì)導(dǎo)致多屏同時(shí)播放視頻時(shí)出現(xiàn)暫停,影響多場(chǎng)景使用(如會(huì)議投屏+本地播放)。
而RK MultiAudio方案正好補(bǔ)上這些短板,核心能力包括:
?多HDMI/DP插拔識(shí)別+聲音分離(HDMI_0/HDMI_1、DP_0/DP_1獨(dú)立輸出);
?第三方APP按包名指定聲卡(如MX Player走揚(yáng)聲器、RockVideoPlayer走HDMI);
?多HDMI IN同時(shí)錄音(HDMIIN_0/HDMIIN_1獨(dú)立錄音);
?多設(shè)備音量同步調(diào)節(jié)與保存。
二、基礎(chǔ)調(diào)試:先搞定“聲卡識(shí)別”與“驅(qū)動(dòng)驗(yàn)證”
調(diào)試的第一步,是確認(rèn)“硬件通路是否正常”——也就是聲卡是否被正確識(shí)別、驅(qū)動(dòng)是否能工作。這兩步操作簡(jiǎn)單,但卻是排查問(wèn)題的基礎(chǔ)。
1.查看聲卡:確認(rèn)設(shè)備是否被系統(tǒng)識(shí)別
通過(guò)adb執(zhí)行命令,查看當(dāng)前系統(tǒng)已注冊(cè)的聲卡:
cat/proc/asound/cards
以RK3588為例,正常輸出會(huì)類似這樣(能看到揚(yáng)聲器、HDMI IN、HDMI 0/1等聲卡):
0[rockchipes8388 ]: rockchip-es8388 - rockchip-es8388rockchip-es83881[rockchiphdmiin ]: rockchip_hdmiin - rockchip,hdmiinrockchip,hdmiin2[rockchiphdmi0 ]: rockchip-hdmi0 - rockchip-hdmi0rockchip-hdmi03[rockchiphdmi1 ]: rockchip-hdmi1 - rockchip-hdmi1rockchip-hdmi1
如果某塊聲卡沒(méi)出現(xiàn)(比如HDMI 0缺失),先排查硬件連接(如HDMI線是否插好),再檢查DTS配置是否正確。
2.測(cè)試驅(qū)動(dòng):驗(yàn)證聲卡能否正常出聲
確認(rèn)聲卡識(shí)別后,用tinyplay工具測(cè)試驅(qū)動(dòng)是否正常(需系統(tǒng)集成tinyalsa工具集)。
以測(cè)試HDMI 0聲卡(對(duì)應(yīng)上述輸出中的索引“2”)為例:
1.準(zhǔn)備一個(gè)WAV格式的音頻文件(如test.wav),推到設(shè)備的/data目錄;
2.執(zhí)行命令播放:
tinyplay/data/test.wav -D2-d0
?-D:指定聲卡索引(這里“2”對(duì)應(yīng)rockchiphdmi0);
?-d:指定設(shè)備編號(hào)(通常為0)。
如果能正常聽(tīng)到聲音,說(shuō)明HDMI 0聲卡驅(qū)動(dòng)沒(méi)問(wèn)題;若沒(méi)聲音,優(yōu)先排查驅(qū)動(dòng)配置(如DTS中聲卡節(jié)點(diǎn)是否啟用)。
三、實(shí)戰(zhàn):5大常見(jiàn)音頻Bug及解決方案
調(diào)試中最頭疼的是“明明配置了,卻出問(wèn)題”——我們整理了RK平臺(tái)最常遇到的5類音頻Bug,附詳細(xì)解決步驟。
1.問(wèn)題1:更新代碼后,HDMI突然沒(méi)聲音(之前正常)
?現(xiàn)象:代碼同步到最新后,HDMI無(wú)音頻輸出,查看聲卡卻能識(shí)別到。
?原因:新框架支持多HDMI識(shí)別,若系統(tǒng)只有1路HDMI,上層會(huì)默認(rèn)調(diào)用“hdmi0”聲卡,但DTS中聲卡名可能配置成了“hdmi1”,導(dǎo)致匹配失敗。
?解決:修改DTS文件,將聲卡名改為“rockchip-hdmi0”:
# 找到 DTS 中 HDMI 聲卡節(jié)點(diǎn)rockchiphdmi1: rockchip-hdmi1 {- rockchip,card-name ="rockchip-hdmi1"+ rockchip,card-name ="rockchip-hdmi0"};
2.問(wèn)題2:UBoot開(kāi)Logo后,HDMI沒(méi)聲音(插拔線后恢復(fù))
?現(xiàn)象:開(kāi)啟UBoot Logo顯示后,HDMI開(kāi)機(jī)無(wú)聲音,手動(dòng)插拔一次HDMI線才正常。
?原因:HDMI的extcon(外部連接狀態(tài)控制器)狀態(tài)更新不及時(shí),系統(tǒng)誤以為HDMI未連接。
?解決:修改DRM驅(qū)動(dòng)代碼,強(qiáng)制同步extcon狀態(tài):
在drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c中添加狀態(tài)同步邏輯:
mutex_lock(&hdmi->mutex);if(result != hdmi->last_connector_result) {dev_dbg(hdmi->dev,"read_hpd result: %d", result);// 同步 extcon 狀態(tài)extcon_set_state_sync(hdmi->extcon, EXTCON_DISP_HDMI, result == connector_status_connected);handle_plugged_change(hdmi, result == connector_status_connected);hdmi->last_connector_result = result;}mutex_unlock(&hdmi->mutex);
3.問(wèn)題3:SPDIF與其他聲卡同時(shí)出聲,聲音斷斷續(xù)續(xù)
?現(xiàn)象:SPDIF(光纖/同軸)與揚(yáng)聲器/ HDMI同時(shí)播放時(shí),音頻卡頓、斷連。
?原因:1)DMA音頻流位置計(jì)算錯(cuò)誤;2)聲卡MCLK配置不合理。
?解決:兩步操作:
a.集成3個(gè)關(guān)鍵Kernel補(bǔ)丁(修復(fù)DMA與PM問(wèn)題):
修復(fù)DMA流位置計(jì)算:ALSA: pcm_dmaengine: always get stream position from DMA driver
修復(fù)DMA runtime PM失衡:dmaengine: pl330: Fix unbalanced runtime PM
提升DMA循環(huán)傳輸效率:dmaengine: pl330: Improve dma cyclic transfers efficiency
a.修改DTS中SPDIF聲卡節(jié)點(diǎn),添加MCLK配置:
spdif_tx0_sound: spdif-tx0-sound {status ="okay";compatible ="simple-audio-card";+ simple-audio-card,mclk-fs = <128>;// 添加這行simple-audio-card,name ="rockchip,spdif-tx0";// 其他配置...};
4.問(wèn)題4:HDMI IN錄音時(shí),偶爾出現(xiàn)Audio服務(wù)崩潰
?現(xiàn)象:用HDMI IN錄制外部音頻(如機(jī)頂盒信號(hào))時(shí),Audio服務(wù)突然崩潰,日志提示“TimeCheck超時(shí)”。
?原因:HDMI IN錄音的等待時(shí)間過(guò)短,導(dǎo)致超時(shí)觸發(fā)服務(wù)重啟。
?解決:修改I2S-TDM驅(qū)動(dòng),延長(zhǎng)錄音等待時(shí)間:
在sound/soc/rockchip/rockchip_i2s_tdm.c中添加超時(shí)配置:
staticintrockchip_i2s_tdm_trigger(structsnd_pcm_substream *substream,intcmd){// 其他邏輯...break;+ // 針對(duì)錄音流,延長(zhǎng)等待時(shí)間到 500ms+ if(substream->stream == SNDRV_PCM_STREAM_CAPTURE) {+ substream->wait_time = msecs_to_jiffies(500);+ }returnret;}
5.問(wèn)題5:更新代碼后,聲卡完全沒(méi)聲音(優(yōu)先級(jí)沖突)
?現(xiàn)象:同步代碼后,所有聲卡都沒(méi)聲音,查看proc/asound/cards能識(shí)別到聲卡。
?原因:RK默認(rèn)代碼基于多聲卡設(shè)備(如RK3588 EVB1支持4路聲卡),優(yōu)先級(jí)為HDMI0 > HDMI1 > DP0 > DP1;若實(shí)際設(shè)備只有1路HDMI1,系統(tǒng)仍優(yōu)先調(diào)用HDMI0(但無(wú)對(duì)應(yīng)聲卡),導(dǎo)致所有聲音無(wú)輸出。
?解決:修改WiredAccessoryManager.java,屏蔽HDMI0的優(yōu)先級(jí)判斷:
# 文件路徑:frameworks/base/services/core/java/com/android/server/WiredAccessoryManager.javaelseif(headset==BIT_HDMI_AUDIO) {- Slog.d(TAG,"hdmi_0 plug");- outDevice=AudioManager.DEVICE_OUT_HDMI;+ // 屏蔽 HDMI0 識(shí)別,避免優(yōu)先級(jí)沖突+ // Slog.d(TAG, "hdmi_0 plug");+ // outDevice = AudioManager.DEVICE_OUT_HDMI;}elseif(headset==BIT_HDMI_AUDIO_1) {Slog.d(TAG,"hdmi_1 plug");outDevice=AudioManager.DEVICE_OUT_HDMI_1;
四、實(shí)用技巧:多設(shè)備輸出與HDMI IN錄音的調(diào)用方法
除了調(diào)試,掌握MultiAudio的核心調(diào)用方式,能讓開(kāi)發(fā)更高效。
1.多設(shè)備輸出:指定聲卡的2種方式
(1)JAVA層通過(guò)AudioSessionId控制
在MediaPlayer初始化時(shí),通過(guò)setAudioSessionId指定聲卡,必須在setDataSource前調(diào)用:
MediaPlayermp=newMediaPlayer();// 指定聲卡:PRIMARY(57)=揚(yáng)聲器,HDMI0(65),DP0(73),HDMI1(81),DP1(89)mp.setAudioSessionId(65);// 聲音從 HDMI0 輸出mp.setDataSource("/data/test.mp4");mp.prepare();mp.start();
(2)按APP包名綁定聲卡
適合需要固定APP輸出設(shè)備的場(chǎng)景(如會(huì)議軟件固定走HDMI),修改AudioTrack.cpp:
String8 appPackage =String8(mPackageName);// RockVideoPlayer 走 HDMI0,gallery3d 走 HDMI1,MX Player 走揚(yáng)聲器if(strstr(appPackage.string(),"RockVideoPlayer")) {sessionid = (audio_session_t)65;}elseif(strstr(appPackage.string(),"gallery3d")) {sessionid = (audio_session_t)81;}elseif(strstr(appPackage.string(),"mxtech")) {// MX Player 包名含 mxtechsessionid = (audio_session_t)57;}
同時(shí)需要:
?打開(kāi)MultiAudioTest宏(在frameworks/av/media/libaudioclient/include/media/AudioTrack.h中設(shè)為1);?解決音頻焦點(diǎn)沖突:在MediaFocusControl.java 中添加focusChangeHint=3,避免多APP同時(shí)播放時(shí)暫停。
2. HDMI IN錄音:調(diào)用HDMIIN音頻源
通過(guò)AudioRecord初始化時(shí)指定MediaRecorder.AudioSource.HDMIIN,即可錄制HDMI外部輸入的聲音:
// 參數(shù):音頻源(HDMIIN)、采樣率、聲道配置、格式、緩沖區(qū)大小AudioRecordaudioRecord=newAudioRecord(MediaRecorder.AudioSource.HDMIIN,44100,// 采樣率 44.1kHzAudioFormat.CHANNEL_IN_STEREO,// 立體聲AudioFormat.ENCODING_PCM_16BIT,// 16bit PCM4096// 緩沖區(qū)大小);// 開(kāi)始錄音audioRecord.startRecording();
五、擴(kuò)展:用AudioPatch優(yōu)化TvInput音頻延時(shí)
如果開(kāi)發(fā)TvInput相關(guān)功能(如電視信號(hào)輸入),可以用AudioPatch替代傳統(tǒng)的AudioStream,進(jìn)一步降低音頻延時(shí)(但錄屏無(wú)法捕獲TvInput預(yù)覽聲音,需根據(jù)需求選擇)。
核心修改:在TvInputHardwareManager.java中屏蔽AudioStream調(diào)用,啟用AudioPatch:
// 屏蔽原 AudioStream 邏輯// mAudioStream.start(6);// mAudioStream.stop();// 啟用 AudioPatchif(mAudioPatch !=null) {mAudioManager.releaseAudioPatch(mAudioPatch);}// 創(chuàng)建 AudioPatch 連接 HDMI IN 音頻源mAudioManager.createAudioPatch(audioPatchArray,newAudioPortConfig[] { sourceConfig },newAudioPortConfig[] { sinkConfig });
六、總結(jié)與支持
RK Android平臺(tái)的音頻調(diào)試,核心是“先確認(rèn)基礎(chǔ)通路(聲卡+驅(qū)動(dòng)),再定位上層邏輯(優(yōu)先級(jí)、狀態(tài)同步)”。MultiAudio方案不僅解決了原生框架的局限,其配套的調(diào)試方法也能覆蓋大部分場(chǎng)景。
希望這篇指南能幫你少踩坑,高效搞定音頻調(diào)試!如果覺(jué)得有用,歡迎點(diǎn)贊、轉(zhuǎn)發(fā),也歡迎在評(píng)論區(qū)分享你的調(diào)試經(jīng)驗(yàn)~
-
HDMI
+關(guān)注
關(guān)注
34文章
1899瀏覽量
160453 -
Android
+關(guān)注
關(guān)注
12文章
4023瀏覽量
133955 -
音頻
+關(guān)注
關(guān)注
31文章
3186瀏覽量
85518
發(fā)布評(píng)論請(qǐng)先 登錄
如何對(duì)基于RK3288平臺(tái)的Simple card聲卡進(jìn)行調(diào)試呢
RK系列開(kāi)發(fā)板音頻驅(qū)動(dòng)適配指南(二)
一文搞定RK平臺(tái)Wi-Fi/BT調(diào)試!從配置到問(wèn)題解決全攻略
RK平臺(tái)新聲卡添加與驅(qū)動(dòng)調(diào)試指南
一文吃透RK平臺(tái)OTA升級(jí)開(kāi)發(fā):從邏輯到調(diào)試的完整指南
RK平臺(tái)聲卡基礎(chǔ)知識(shí)總結(jié)(基于ALSA框架)
RK平臺(tái)Linux IOMMU開(kāi)發(fā):從原理到實(shí)戰(zhàn)
一文打通Rockchip DP調(diào)試:從原理到實(shí)戰(zhàn),覆蓋RK3399/RK3576/RK3588全平臺(tái)
RK3326音頻調(diào)試避坑指南:從“錄不了”到“全功能跑通”的實(shí)戰(zhàn)歷程
RK3326平臺(tái)GC2385攝像頭調(diào)試實(shí)戰(zhàn):從報(bào)錯(cuò)到功能正常的完整排查指南
深入解析RK平臺(tái)GPIO驅(qū)動(dòng):從原理到調(diào)試,開(kāi)發(fā)者必看指南
RK3576音頻調(diào)試全紀(jì)錄
RK?平臺(tái)?USB?攝像頭成像調(diào)試指南:從信號(hào)到畫(huà)質(zhì)的全流程優(yōu)化
深入解析rk平臺(tái)Android Bootloader核心代碼:從啟動(dòng)流程到AVB驗(yàn)證
RK3576 Android15音頻開(kāi)發(fā)必看:alsa_route核心文件解析與修改場(chǎng)景
RK Android平臺(tái)音頻調(diào)試指南:從基礎(chǔ)到實(shí)戰(zhàn),解決多設(shè)備輸出、聲卡異常等核心問(wèn)題
評(píng)論