4 min read

為什麼 ALSA Loopback 在 Amlogic S905X4 上抓不到音訊

Table of Contents

在 Android TV 平台上做 ACR(Automatic Content Recognition)需要擷取裝置正在播放的音訊做指紋比對。ALSA loopback 是第一個想到的方案。在 Amlogic S905X4 上花了一天驗證,結論是:loopback 硬體沒壞,但它監聽的那條線上沒有信號。

問題出在 Amlogic Audio HAL 的路由設計。AudioFlinger 的 PCM 資料寫進 TDM-B 之後,HAL 在音訊到達硬體 I/O 腳位之前就把它攔走,送進 Dolby MS12 DSP 做混音和處理,再透過一條 ALSA 完全看不到的內部 SPDIF 路徑送到 HDMI TX。Loopback 設備指向的是 TDMOUT_B 的硬體輸出腳位——那裡什麼都沒有。


S905X4 的音訊硬體架構

7 個 PCM 裝置與 Loopback 的關係

S905X4 在一張 ALSA card(AML-AUGESOUND)上掛了 7 個 PCM 裝置:

裝置類型角色
0TDM-A未使用(dummy)
1TDM-BAudioFlinger 主要輸出(T9015 DAC)
2TDM-CI2S 到 HDMI
3PDM麥克風輸入
4SPDIF數位音訊 I/O(光纖/同軸)
5SPDIF-B次要數位輸出
6LOOPBACK-A僅擷取用的 loopback

AudioFlinger 寫入裝置 1(TDM-B)。Loopback 的 mixer control 設定指向 TDMOUT_B(control #22 → TDMIN_B,control #23 → TDMOUT_B)。看起來應該能抓到音訊。

音訊實際走的路徑

從 ALSA userspace 的角度,TDM-B 看起來像一個普通的音訊輸出——/proc/asound/card0/pcm1p/info 沒有任何異常。但實際上 HAL 在音訊到達 TDM-B 的硬體腳位之前就攔截了它:

AudioFlinger
  → ALSA Device 1 (TDM-B) — HAL 接手點
    → Amlogic Audio HAL
      → Dolby MS12 DSP(混音、DRC、EQ)
        → 內部 SPDIF encoder(不暴露給 ALSA)
          → HDMI TX

Loopback 監聽的是 TDMOUT_B 的硬體 I/O 腳位。但 TDM-B 的 speaker 輸出是靜音的(mixer control #69 SPK mute = On),因為 HAL 在 PCM 到達腳位前就把它導走了。Loopback 指向的是一條空線。

關鍵的診斷 control 是 #65(HDMITX Audio Source Select),它的值是 Spdif——這直接告訴你 HDMI TX 從內部 SPDIF bus 讀音訊,不是從任何 TDM 輸出。一旦知道這個,就知道基於 TDM 的 loopback 不可能抓到 HDMI 音訊。


實測驗證

A/B 測試:繞過 HAL vs 走 AudioFlinger

為了確認是路由問題而不是 loopback 硬體壞了,做了對照測試:

測試做了什麼Loopback 來源結果
1tinyplay 直接寫 WAV 到 TDM-A(裝置 0)TDMOUT_A-18 dB(有音訊)
2tinyplay 直接寫 WAV 到 TDM-C(裝置 2)TDMOUT_C-25 dB(有音訊)
3播放影片,擷取 AudioFlinger 輸出TDMOUT_B-999 dB(靜音)
4取消 SPK 靜音,播放 UI 音效TDMOUT_B-999 dB(靜音)

測試 1-2 繞過 HAL——tinyplay 直接把 PCM 寫到 ALSA 裝置,音訊真的到達硬體腳位,loopback 正常擷取。測試 3-4 走 AudioFlinger → HAL → MS12 路徑,音訊在腳位之前就被轉走了。

SPDIF 內部迴路的陷阱

Mixer control #14(Audio spdifin source)有一個 spdifout 選項,聽起來可以把 SPDIF 輸出迴路到輸入。實測結果:靜音。

原因是平台上有兩個不同的「SPDIF」:

  • ALSA SPDIF(裝置 4):物理 SPDIF I/O,用於外接光纖/同軸
  • HAL 內部 SPDIF:MS12 DSP 處理後送往 HDMI TX 的路徑,不暴露給 ALSA

Control #14 的 spdifout 迴路的是 ALSA SPDIF 裝置自己,不是 HAL 的 HDMI 路徑。這兩條是不同的 bus。

備註:這個判斷基於 control 命名和靜音測試結果推論,未透過 kernel source 或暫存器 dump 直接確認。

Control #29 的未啟用路由選項

Control #29(Audio In Source)有一些看起來有用的選項:TDMIN_LBLOOPBACK_A/BSPDIFIN_LBFRHDMIRX。這些名稱暗示 SoC 矽片可能支援 post-MS12 音訊的內部路由。但全部測試結果為 null。

可能的原因:驅動沒有接線、需要搭配其他 control 或 DTS 設定、需要特定的取樣率。沒有查看 kernel source(sound/soc/amlogic/auge/),所以無法確認。


ACR 的替代方案

硬體 loopback 不可行之後,剩下兩條路:

策略擷取點覆蓋範圍限制
AudioPlaybackCaptureAudioFlinger 層(HAL 之上)非 DRM 內容兩個阻擋點
HAL post-MS12 tapMS12 DSP 之後(需要 vendor 修改)所有內容含 DRM需要晶片廠配合

AudioPlaybackCapture 的兩個阻擋點

AudioPlaybackCapture 在 AudioFlinger 層擷取,不依賴硬體,所以不受 loopback 路由問題影響。但它有兩個阻擋點:

  1. allowAudioPlaybackCapture=false:Netflix 等 app 在 manifest 中明確 opt out,AudioFlinger 對這些 session 回傳靜音 buffer。

  2. Tunneled Playback:Widevine L1 內容(Netflix 4K、Disney+ 等)的音訊解碼在 TEE 內部執行,透過 Android tunneled playback 路徑直接從 secure decoder 送到 HAL,音訊從頭到尾不經過 AudioFlinger。AudioPlaybackCapture 抓不到根本沒進 AudioFlinger 的東西。這個限制比 manifest flag 更根本。

實際覆蓋率取決於 app 組合——有多少觀看時間是非 DRM、非 tunneled 的內容(FAST 頻道、免費廣告支持內容等)。

HAL post-MS12 tap

要完整覆蓋(DRM + tunneled + HDMI-in),需要在 HAL 層做一個 post-MS12 的 loopback tap。Control #29 的那些 null 選項暗示矽片可能有這個能力,但需要晶片廠把它接上。

如果要向晶片廠提需求,關鍵規格:tap 必須輸出 downmixed LPCM,在解碼之後、重新編碼之前(例如在 Dolby MAT 封裝之前)。如果 tap 點在編碼之後,拿到的是壓縮 bitstream,ACR 指紋比對用不了。


總結:Debug 方法論

這次調查中最有效的 debug 方式是從輸出端往回追。Control #65(HDMITX Audio Source Select = Spdif)直接告訴你 HDMI TX 的音源是內部 SPDIF bus,不是 TDM——如果一開始就檢查這個 control,可以省下好幾個小時的 loopback 測試。

幾個具體的 takeaway:

  • ALSA 裝置編號在這個平台上有誤導性。 裝置 1(TDM-B)看起來像普通音訊輸出,但 HAL 在 PCM 到達硬體腳位前就攔截了。從 userspace 看不出來。
  • MS12 從 ALSA 的角度是黑盒。 音訊進了 DSP 之後,剩下的路徑完全由 HAL 控制,ALSA 沒有能見度。
  • Mixer control 選項存在不代表它能用。 spdifout 迴路和 SPDIFIN_LB 內部路由都是存在的選項,但都產生靜音。永遠用 tinycap + sox 實測,不要只看 control 名稱。
  • 診斷 SoC 音訊路由時,先查輸出端的 source select control。 它直接告訴你音訊從哪條 bus 來,省去逐條測試的時間。

備註:測試結果基於 Amlogic S905X4 單一 SoC。其他 Amlogic 型號(S905X3、S928X 等)的音訊路由可能不同。Control #29 的內部路由選項未搭配 DTS 變更或其他 control 組合測試,不排除可啟用的可能。