音訊偵錯

本文說明用於偵錯 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

編譯時間設定

  1. cd frameworks/av/services/audioflinger
  2. 編輯Configuration.h
  3. 將「#define TEE_SINK」取消註解。
  4. 重新建構 libaudioflinger.so
  5. adb root
  6. adb remount
  7. 將新的 libaudioflinger.so 推送或同步到裝置的 /system/lib

執行階段設定

  1. adb shell getprop | grep ro.debuggable
    確認輸出內容為:[ro.debuggable]: [1]
  2. adb shell
  3. ls -ld /data/misc/audioserver

    確認輸出結果如下:

    drwx------ media media ... media
    

    如果目錄不存在,請按照以下方式建立目錄:

    mkdir /data/misc/audioserver
    chown media:media /data/misc/audioserver
    
  4. echo af.tee=# > /data/local.prop
    如果 af.tee 值是下文所述的數字,
  5. chmod 644 /data/local.prop
  6. reboot

af.tee 屬性的值

af.tee 的值是介於 0 到 7 之間的數字,表示 也就是每個特徵一個位元的總和 請前往 AudioFlinger.cppAudioFlinger::AudioFlinger() 查看程式碼 ,不過以下簡要:

  • 1 = 輸入
  • 2 = FastMixer 輸出
  • 4 = 每個音軌的「AudioRecord」和「AudioTrack」

深度緩衝區或一般混音器都沒有長度限制 但你可以使用「4」取得類似的結果

測試並獲取資料

  1. 執行音訊測試。
  2. adb shell dumpsys media.audio_flinger
  3. 請在 dumpsys 輸出內容中尋找一行,如下所示:
    tee copied to /data/misc/audioserver/20131010101147_2.wav
    這是 PCM .wav 檔案。
  4. 然後adb pull任何感興趣的 /data/misc/audioserver/*.wav 檔案。 請注意,追蹤專屬傾印檔案名稱不會顯示在 dumpsys 輸出, 但仍會在賽道關閉後儲存到 /data/misc/audioserver
  5. 分享檔案前,請先查看轉儲檔案,確認是否有隱私權疑慮。

建議

如要取得更實用的結果,請嘗試下列建議:

  • 停用觸控音效和按鍵操作,減少測試輸出的中斷。
  • 將所有音量最大化。
  • 停用透過麥克風錄音或錄音的應用程式。 。
  • 只有在測試群組關閉時,系統才會儲存音軌專屬的傾印檔案; 您可能需要強制關閉應用程式,才能傾印測試群組專屬資料
  • 測試後立即執行 dumpsys; 可用的錄製內容有限。
  • 為確保您不會遺失轉儲檔案 定期將這些檔案上傳至代管商 系統只會保留少數傾印檔案; 達到這個上限後,就會移除較舊的傾印。

還原

如前所述,請勿啟用 Tee 接收器功能。 請按照下列步驟還原版本和裝置:

  1. 將原始碼變更還原為 Configuration.h
  2. 重新建構 libaudioflinger.so
  3. 推送或同步處理還原的libaudioflinger.so 的「/system/lib」。
  4. adb shell
  5. rm /data/local.prop
  6. rm /data/misc/audioserver/*.wav
  7. reboot

media.log

ALOGx 巨集

Android SDK 中的標準 Java 語言記錄 API 為 android.util.Log

Android NDK 中對應的 C 語言 API 是 __android_log_print<android/log.h> 中宣告。

在 Android 架構的原生部分 建議使用 ALOGEALOGWALOGIALOGV 等。這些宣告在 <utils/Log.h>,以及本文目的: (統稱為 ALOGx)。

這些 API 都很容易使用且容易理解,因此相當普遍 整個 Android 平台上特別是 mediaserver 程序,包括 AudioFlinger 音效伺服器 廣泛ALOGx

不過,ALOGx 和好友有一些限制:

  • 容易受到「記錄垃圾內容」的影響:記錄緩衝區為共用資源 因此很容易因為不相關的記錄項目而溢出 缺少資訊ALOGV 變化版本在以下位置停用: 編譯時間。但當然,這也可能導致記錄為垃圾內容 如果已啟用的話
  • 基礎核心系統呼叫可能會封鎖 優先順序反轉、評估的干擾,以及 不準確這屬於 與時間緊迫的執行緒有關,例如 FastMixerFastCapture
  • 如果停用特定記錄以減少垃圾記錄, 那麼被記錄擷取的任何資訊都會遺失。 特定記錄無法溯及既往

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 之前:

media.log 之前的架構

圖 1. media.log 之前的架構

重要須知:

  • init 分支和執行 mediaserver
  • init 會偵測 mediaserver 的死亡情形,並視需要重組。
  • 未顯示ALOGx記錄。

下圖顯示元件的新關係 將 media.log 新增至架構後:

media.log 之後的架構

圖 2. media.log 之後的架構

重要變更:

  • 用戶端會使用 NBLOG API 建構記錄項目,並附加至項目 共用記憶體中的環形緩衝區
  • MediaLogService 隨時可以傾印循環緩衝區的內容。
  • 循環緩衝區的設計在設計時, 共用回憶集錦不會異常終止 MediaLogService,而且它仍可 盡量傾印不受損毀影響的緩衝區。
  • 循環緩衝區具有非阻塞性,且進行寫入時不會鎖定 新項目和讀取現有項目
  • 不需要核心系統呼叫寫入或讀取環形緩衝區 (選用時間戳記除外)。

適用商家

在 Android 4.4 中,AudioFlinger 中只有幾個記錄點 使用 media.log 系統。雖然新的 API 因為 ALOGx 很容易使用,所以不是非常困難。 建議您瞭解這些產品的新記錄系統 尤其是在非必要時 我們特別建議將必須採用的 AudioFlinger 執行緒使用 經常執行,且不封鎖某些項目,例如 FastMixerFastCapture 執行緒。

使用方法

新增記錄檔

首先,您必須在程式碼中新增記錄。

FastMixerFastCapture 執行緒中,請使用類似下方的程式碼:

logWriter->log("string");
logWriter->logf("format", parameters);
logWriter->logTimestamp();

這個 NBLog 時間軸僅供 FastMixerFastCapture 個執行緒, 不需要相互排除

在其他 AudioFlinger 執行緒中,請使用 mNBLogWriter

mNBLogWriter->log("string");
mNBLogWriter->logf("format", parameters);
mNBLogWriter->logTimestamp();

針對 FastMixerFastCapture 以外的執行緒, 執行緒的 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_harness1。方法如下:

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