AAudio 是在 Android 8.0 版本中導入的音訊 API。Android 8.1 版本強化了與 HAL 搭配使用時的延遲時間 以及支援 MMAP 的驅動程式本文件說明硬體抽象化機制 為了支援 AAudio 的 MMAP 功能,就需要變更圖層 (HAL) 及驅動程式 Android。
如要使用 AAudio MMAP 支援功能:
- 回報 HAL 的 MMAP 功能
- 在 HAL 中實作新函式
- 選擇性針對 EXCLUSIVE 模式緩衝區實作自訂 ioctl()
- 提供了額外的硬體資料路徑
- 設定可啟用 MMAP 功能的系統屬性
AAudio 架構
AAudio 是全新的原生 C API,提供 Open SL ES 的替代方案。該公式採用 建立音訊串流的建構工具設計模式。
AAudio 提供低延遲資料路徑。功能處於「專屬」模式 允許用戶端應用程式程式碼直接將寫入記憶體對應的緩衝區 並與 ALSA 驅動程式分享在共用模式下,MMAP 緩衝區會用於 在 AudioServer 中執行的混合程式。在「專屬」模式下,延遲時間會縮短 可大幅降低,因為資料會略過混合器。
在「獨家」模式下,服務會向 HAL 要求 MMAP 緩衝區,並加以管理 專案。MMAP 緩衝區正以 NOIRQ 模式執行,因此並未共用 讀取/寫入計數器,以管理緩衝區的存取權。相反 維護硬體的時間模型,並預測緩衝區何時 讀取。
下圖顯示脈衝程式碼調變 (PCM) 資料流動 然後透過 MMAP FIFO 進入 ALSA 驅動程式。時間戳記會定期 然後傳遞至用戶端的時間模型 透過不可分割的訊息佇列傳送
在共用模式中,也會使用時間模型,但該模型位於 AAudioService 中。
音訊擷取作業會採用類似的模型,但 PCM 資料則會在 就會顯示反向的閃光效果
HAL 變更
針對 tinyALSA,請參閱:
external/tinyalsa/include/tinyalsa/asoundlib.h external/tinyalsa/include/tinyalsa/pcm.c
int pcm_start(struct pcm *pcm); int pcm_stop(struct pcm *pcm); int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, unsigned int *frames); int pcm_get_poll_fd(struct pcm *pcm); int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames); int pcm_mmap_get_hw_ptr(struct pcm* pcm, unsigned int *hw_ptr, struct timespec *tstamp);
如果是舊版 HAL,請參閱:
hardware/libhardware/include/hardware/audio.h hardware/qcom/audio/hal/audio_hw.c
int start(const struct audio_stream_out* stream); int stop(const struct audio_stream_out* stream); int create_mmap_buffer(const struct audio_stream_out *stream, int32_t min_size_frames, struct audio_mmap_buffer_info *info); int get_mmap_position(const struct audio_stream_out *stream, struct audio_mmap_position *position);
HIDL 音訊 HAL:
hardware/interfaces/audio/2.0/IStream.hal hardware/interfaces/audio/2.0/types.hal hardware/interfaces/audio/2.0/default/Stream.h
start() generates (Result retval); stop() generates (Result retval) ; createMmapBuffer(int32_t minSizeFrames) generates (Result retval, MmapBufferInfo info); getMmapPosition() generates (Result retval, MmapPosition position);
回報 MMAP 支援
系統屬性「aaudio.mmap_policy」應設為 2 (AAUDIO_POLICY_AUTO),這樣 音訊架構知道音訊 HAL 支援 MMAP 模式。(請參閱 「啟用 AAudio MMAP 資料路徑」)。
Audio_policy_configuration.xml 檔案也須包含輸出和輸入內容 MMAP/沒有 IRQ 模式專用的設定檔,讓音訊政策管理工具瞭解 MMAP 用戶端建立時要開啟的串流:
<mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ"> <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> </mixPort> <mixPort name="mmap_no_irq_in" role="sink" flags="AUDIO_INPUT_FLAG_MMAP_NOIRQ"> <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/> </mixPort>
開啟及關閉 MMAP 串流
createMmapBuffer(int32_t minSizeFrames) generates (Result retval, MmapBufferInfo info);
您可以呼叫 Tinyalsa 函式來開啟及關閉 MMAP 串流。
查詢 MMAP 位置
回傳到時間模型的時間戳記包含了影格位置, 單一時間 (以奈秒為單位):
getMmapPosition() generates (Result retval, MmapPosition position);
HAL 可以透過呼叫新的 Tinyalsa 函式:
int pcm_mmap_get_hw_ptr(struct pcm* pcm, unsigned int *hw_ptr, struct timespec *tstamp);
共用記憶體的檔案描述元
AAudio MMAP 資料路徑使用記憶體區域, 硬體和音訊服務使用檔案描述元參照共用記憶體 由 ALSA 驅動程式產生的值
核心變更
如果檔案描述元與
/dev/snd/
驅動程式檔案,則 AAudio 服務才能在以下位置使用該檔案:
共用模式。不過,描述元無法傳遞至
專屬模式。/dev/snd/
檔案描述元也會提供
因此用戶端無法存取,因此遭到 SELinux 封鎖。
如要支援「專屬」模式,就必須將
將 /dev/snd/
描述元至 anon_inode:dmabuf
檔案
描述元SELinux 允許將檔案描述元傳送至用戶端。這項服務
也可供 AAudioService 使用。
anon_inode:dmabuf
檔案描述元可以使用
Android Ion 記憶體庫。
詳情請參閱下列外部資源:
- 「Android ION 記憶體配置器」https://lwn.net/Articles/480055/
- 「Android ION 總覽」https://wiki.linaro.org/BenjaminGaignard/ion
- 「整合 ION 記憶體配置器」https://lwn.net/Articles/565469/
HAL 變更
AAudio 服務必須確認這個 anon_inode:dmabuf
是否為
支援。在 Android 10.0 之前,唯一方法就是傳遞 MMAP 的大小
視為負數,例如-2048 (如支援) 而非 2048。Android 10.0 以上版本
也可以設定 AUDIO_MMAP_APPLICATION_SHAREABLE
旗標
mmapBufferInfo |= AUDIO_MMAP_APPLICATION_SHAREABLE;
音訊子系統變更
在音訊的前端位置,AAudio 需要額外的資料路徑 子系統,讓它能與原始 AudioFlinger 路徑平行運作。 這個舊版路徑會用於所有其他系統音效和應用程式音效。 這項功能可能由 DSP 或硬體中的軟體混合器提供 也就是 SOC 中的混合器。
啟用 AAudio MMAP 資料路徑
如果不支援 MMAP 或不支援 MMAP,AAudio 會使用舊版 AudioFlinger 資料路徑。 無法開啟串流。因此,AAudio 能夠與不支援這項功能的音訊裝置搭配使用 支援 MMAP/NOIRQ 路徑。
測試 AAudio 對 MMAP 的支援時,請務必確認自己是否 測試 MMAP 資料路徑,或只是測試舊版資料路徑。 以下說明如何啟用或強制啟用特定資料路徑,以及如何查詢 是串流使用的路徑
系統屬性
您可以透過系統屬性設定 MMAP 政策:
- 1 = AAUDIO_POLICY_NEVER - 僅使用舊版路徑。請勿甚至嘗試使用 MMAP。
- 2 = AAUDIO_POLICY_AUTO - 嘗試使用 MMAP。如果無效或無法使用 然後使用舊版路徑
- 3 = AAUDIO_POLICY_ALWAYS - 僅使用 MMAP 路徑。不要改回使用舊版服務 路徑。
這些設定可能會在裝置 Makefile 中設定,如下所示:
# Enable AAudio MMAP/NOIRQ data path. # 2 is AAUDIO_POLICY_AUTO so it will try MMAP then fallback to Legacy path. PRODUCT_PROPERTY_OVERRIDES += aaudio.mmap_policy=2 # Allow EXCLUSIVE then fall back to SHARED. PRODUCT_PROPERTY_OVERRIDES += aaudio.mmap_exclusive_policy=2
您也可以在裝置啟動後覆寫這些值。 您必須重新啟動音訊伺服器,變更才會生效。 例如,若要啟用 MMAP 的自動模式:
adb root
adb shell setprop aaudio.mmap_policy 2
adb shell killall audioserver
您可以在
「ndk/sysroot/usr/include/aaudio/AAudioTesting.h
」可讓您
使用 MMAP 路徑覆寫政策:
aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);
如要確認串流是否使用 MMAP 路徑,請呼叫:
bool AAudioStream_isMMapUsed(AAudioStream* stream);