本文說明用於偵錯 Android 音訊的一些提示與秘訣。
茶水槽
「Tee 接收器」為 AudioFlinger 偵錯功能,僅適用於自訂版本 保留近期音訊的一小段內容,以供日後分析之用。 這可讓觀眾比較實際播放或錄製的內容 比預期的差
為保護隱私,Tee 接收器在編譯和編譯期間都預設為停用 指令如要使用 Tee 接收器,請重新編譯 以及設定屬性務必先停用 偵錯;正式環境版本不應啟用 Tee 接收器。
本節的操作說明適用於 Android 7.x 以上版本。Android 裝置
5.x 和 6.x,將 /data/misc/audioserver
替換為
/data/misc/media
。此外,您必須使用 userdebug 或
工程部門。如果您使用使用者偵錯版本,請透過下列指令停用驗證狀態:
adb root && adb disable-verity && adb reboot
編譯時間設定
cd frameworks/av/services/audioflinger
- 編輯
Configuration.h
。 - 將「
#define TEE_SINK
」取消註解。 - 重新建構
libaudioflinger.so
。 adb root
adb remount
- 將新的
libaudioflinger.so
推送或同步到裝置的/system/lib
。
執行階段設定
adb shell getprop | grep ro.debuggable
確認輸出內容為:[ro.debuggable]: [1]
adb shell
ls -ld /data/misc/audioserver
確認輸出結果如下:
drwx------ media media ... media
如果目錄不存在,請按照以下方式建立目錄:
mkdir /data/misc/audioserver
chown media:media /data/misc/audioserver
echo af.tee=# > /data/local.prop
如果af.tee
值是下文所述的數字,chmod 644 /data/local.prop
reboot
af.tee 屬性的值
af.tee
的值是介於 0 到 7 之間的數字,表示
也就是每個特徵一個位元的總和
請前往 AudioFlinger.cpp
的 AudioFlinger::AudioFlinger()
查看程式碼
,不過以下簡要:
- 1 = 輸入
- 2 = FastMixer 輸出
- 4 = 每個音軌的「AudioRecord」和「AudioTrack」
深度緩衝區或一般混音器都沒有長度限制 但你可以使用「4」取得類似的結果
測試並獲取資料
- 執行音訊測試。
adb shell dumpsys media.audio_flinger
- 請在
dumpsys
輸出內容中尋找一行,如下所示:
tee copied to /data/misc/audioserver/20131010101147_2.wav
這是 PCM .wav 檔案。 - 然後
adb pull
任何感興趣的/data/misc/audioserver/*.wav
檔案。 請注意,追蹤專屬傾印檔案名稱不會顯示在dumpsys
輸出, 但仍會在賽道關閉後儲存到/data/misc/audioserver
。 - 分享檔案前,請先查看轉儲檔案,確認是否有隱私權疑慮。
建議
如要取得更實用的結果,請嘗試下列建議:
- 停用觸控音效和按鍵操作,減少測試輸出的中斷。
- 將所有音量最大化。
- 停用透過麥克風錄音或錄音的應用程式。 。
- 只有在測試群組關閉時,系統才會儲存音軌專屬的傾印檔案; 您可能需要強制關閉應用程式,才能傾印測試群組專屬資料
- 測試後立即執行
dumpsys
; 可用的錄製內容有限。 - 為確保您不會遺失轉儲檔案 定期將這些檔案上傳至代管商 系統只會保留少數傾印檔案; 達到這個上限後,就會移除較舊的傾印。
還原
如前所述,請勿啟用 Tee 接收器功能。 請按照下列步驟還原版本和裝置:
- 將原始碼變更還原為
Configuration.h
。 - 重新建構
libaudioflinger.so
。 - 推送或同步處理還原的
libaudioflinger.so
的「/system/lib
」。 adb shell
rm /data/local.prop
rm /data/misc/audioserver/*.wav
reboot
media.log
ALOGx 巨集
Android SDK 中的標準 Java 語言記錄 API 為 android.util.Log
Android NDK 中對應的 C 語言 API 是
__android_log_print
在 <android/log.h>
中宣告。
在 Android 架構的原生部分
建議使用 ALOGE
、ALOGW
、
ALOGI
、ALOGV
等。這些宣告在
<utils/Log.h>
,以及本文目的:
(統稱為 ALOGx
)。
這些 API 都很容易使用且容易理解,因此相當普遍
整個 Android 平台上特別是 mediaserver
程序,包括 AudioFlinger 音效伺服器
廣泛ALOGx
。
不過,ALOGx
和好友有一些限制:
-
容易受到「記錄垃圾內容」的影響:記錄緩衝區為共用資源
因此很容易因為不相關的記錄項目而溢出
缺少資訊
ALOGV
變化版本在以下位置停用: 編譯時間。但當然,這也可能導致記錄為垃圾內容 如果已啟用的話 -
基礎核心系統呼叫可能會封鎖
優先順序反轉、評估的干擾,以及
不準確這屬於
與時間緊迫的執行緒有關,例如
FastMixer
和FastCapture
。 - 如果停用特定記錄以減少垃圾記錄, 那麼被記錄擷取的任何資訊都會遺失。 特定記錄無法溯及既往
NBLOG、media.log 和 MediaLogService
NBLOG
API 與相關聯的 media.log
處理程序和 MediaLogService
這些服務構成了新的媒體記錄系統,具體來說
專為解決上述問題而設計我們會大致使用
「media.log」可以參照上述三者,但嚴格說 NBLOG
是
C++ Logging API,media.log
是 Linux 程序名稱,而 MediaLogService
是一項用於檢查記錄的 Android 繫結器服務。
media.log
的「時間軸」是系列叢書
其相對排序保留的記錄項目。
按照慣例,每個執行緒都應使用專屬的時間軸。
優點
media.log
系統的優點在於:
- 除非需要,否則不會在主要記錄中濫填大量資料。
- 即使
mediaserver
當機或停止運作,還是可以檢查。 - 依時間軸進行非封鎖。
- 降低對效能的干擾。 (當然,記錄形式完全不會侵擾)。
建築
下圖顯示 mediaserver
程序的關係
和 init
程序,在導入 media.log
之前:
重要須知:
init
分支和執行mediaserver
。init
會偵測mediaserver
的死亡情形,並視需要重組。- 未顯示
ALOGx
記錄。
下圖顯示元件的新關係
將 media.log
新增至架構後:
重要變更:
-
用戶端會使用
NBLOG
API 建構記錄項目,並附加至項目 共用記憶體中的環形緩衝區 -
MediaLogService
隨時可以傾印循環緩衝區的內容。 -
循環緩衝區的設計在設計時,
共用回憶集錦不會異常終止
MediaLogService
,而且它仍可 盡量傾印不受損毀影響的緩衝區。 - 循環緩衝區具有非阻塞性,且進行寫入時不會鎖定 新項目和讀取現有項目
- 不需要核心系統呼叫寫入或讀取環形緩衝區 (選用時間戳記除外)。
適用商家
在 Android 4.4 中,AudioFlinger 中只有幾個記錄點
使用 media.log
系統。雖然新的 API
因為 ALOGx
很容易使用,所以不是非常困難。
建議您瞭解這些產品的新記錄系統
尤其是在非必要時
我們特別建議將必須採用的 AudioFlinger 執行緒使用
經常執行,且不封鎖某些項目,例如
FastMixer
和 FastCapture
執行緒。
使用方法
新增記錄檔
首先,您必須在程式碼中新增記錄。
在 FastMixer
和 FastCapture
執行緒中,請使用類似下方的程式碼:
logWriter->log("string"); logWriter->logf("format", parameters); logWriter->logTimestamp();
這個 NBLog
時間軸僅供 FastMixer
和
FastCapture
個執行緒,
不需要相互排除
在其他 AudioFlinger 執行緒中,請使用 mNBLogWriter
:
mNBLogWriter->log("string"); mNBLogWriter->logf("format", parameters); mNBLogWriter->logTimestamp();
針對 FastMixer
和 FastCapture
以外的執行緒,
執行緒的 NBLog
時間軸可由執行緒使用,且
分秒必爭「NBLog::Writer
」不提供任何
每個時間軸的隱含互斥,因此確保所有記錄都會發生
在其中的執行緒互斥鎖 mLock
中。
新增記錄後,請重新建構 AudioFlinger。
注意:
每個執行緒都需要獨立的 NBLog::Writer
時間軸。
以確保執行緒安全,因為時間軸設計會省略互斥鎖。如果發生以下情況:
如果希望多個執行緒使用相同的時間軸,你可以使用
現有的 Mutex (如上述 mLock
中所述)。或者,您也可以
使用 NBLog::LockedWriter
包裝函式,而非 NBLog::Writer
。
不過,這會反過這個 API 的主要優勢:
行為
完整的 NBLog
API 位於 frameworks/av/include/media/nbaio/NBLog.h
。
啟用 media.log
media.log
預設為停用。只在資源啟用時
ro.test_harness
為 1
。方法如下:
adb root
adb shell
echo ro.test_harness=1 > /data/local.prop
chmod 644 /data/local.prop
reboot
連線在重新啟動時中斷,因此:
adb shell
ps media
現在會顯示兩個程序:
- media.log
- 媒體伺服器
請記下 mediaserver
的程序 ID,供稍後使用。
顯示時間軸
您可以隨時手動要求記錄轉儲。 這個指令會顯示所有使用中和最近時間軸的記錄,然後清除這些記錄:
dumpsys media.log
請注意,由於設計時間表各自獨立, 而且沒有合併時間軸的設施
在媒體伺服器終止後復原記錄檔
現在請嘗試終止 mediaserver
程序:kill -9 #
,其中 # 為
您先前記下的程序 ID您應該會看到來自 media.log
的轉儲
在主要 logcat
中,顯示引發當機情況的所有記錄。
dumpsys media.log