汽車音響

Android Automotive OS (AAOS) 是以 Android 核心音訊堆疊為基礎, 輔助將應用在車輛的資訊娛樂系統上。 AAOS 負責資訊娛樂聽覺,例如媒體、導航、 ,但就使用 嚴格的可用性與時間規定AAOS 會提供信號 協助車輛管理音訊的機制,最終取決於車輛 讓駕駛人看到應該播放的音效 乘客,確保安全重要聲響和監管音效 不中斷

Android 會管理車輛的媒體體驗,以及外部媒體來源 例如電台調音器應由能夠處理音訊的應用程式 來源的焦點和媒體重要事件

Android 11 針對汽車相關音訊做了以下變更 支援服務:

Android 音效與串流

Automotive 音訊系統會處理下列音訊和串流內容:

以串流為主的架構圖

圖 1. 以串流為主的架構圖

Android 會管理 Android 應用程式發出的音效,控管這些應用程式 並透過 HAL 輸出裝置 音效:

  • 邏輯串流,稱為核心音訊來源 命名法則加上 Audio 屬性 (音訊屬性) 標記。
  • 實體串流,稱為核心音訊的裝置 雜訊,卻沒有背景資訊。

為提高可靠性,外來聲音 (有獨立音訊來源) 安全提示 (例如座椅警告鈴聲) 等來源是在 Android 以外的地方管理,位於 HAL 或獨立硬體。系統實作者必須提供混合器, 接受 Android 提供的一或多個聲音輸入串流,然後將這些音訊 配合要求本身的外部聲音來源播放音樂 。

HAL 實作和外部混合器負責 安全重要外部聲響,並用於混和 Android 提供的 並轉送到適合的揚聲器

Android 音效

應用程式可能有一或多個播放器透過標準 Android 互動 API (例如 AudioManager 用於焦點控製或 MediaPlayer ) 輸出一或多個邏輯串流。這項資料 可以是單聲道或 7.1 環場音效,但會轉送並視為 單一來源。應用程式串流與 AudioAttributes 相關聯 讓系統提示音訊的表示方式。

邏輯串流透過 AudioService 傳送,並轉送至 其中一個) 可用實體輸出串流,而每個串流都是 AudioFlinger 的混合程式混合音訊屬性後 但已無法在實體串流中播放。

然後將每個實體串流傳送到音訊 HAL 以便顯示 因此,在硬體方面在車用應用程式中,算繪硬體可以是本機轉碼器 (與行動裝置類似) 或車輛實體的遠端處理器 更是如此無論採用哪種方式,都是由音訊 HAL 實作負責 實際的樣本資料並使該資料變為可聽狀態

外部串流

不得使用 Android 轉送的音效串流 (用於認證或 時間可能),因此直接傳送給外部混音器。自 Android 11 起, HAL 已可要求集中在外部聲響通知 Android 以便採取適當行動,例如暫停媒體或防止 用於協助其他員工

如果外部串流是應與音效互動的媒體來源 環境 (例如在載入完成後停止播放 MP3 內容 外部調諧器開啟時,外部串流應以 Android 應用程式。這類應用程式會代表媒體來源要求音訊焦點 並會回應焦點通知 配合 Android 焦點,視需要開始/停止外部來源 政策。應用程式也負責處理媒體重要事件,例如 播放/暫停。控管這類外部裝置的其中一種機制是 HwAudioSource

輸出裝置

音訊 HAL 等級:裝置類型:AUDIO_DEVICE_OUT_BUS 提供用於車輛音響系統的一般輸出裝置。公車 裝置支援可定址的連接埠 (每個連接埠都是 且應該是 中唯一支援的輸出裝置類型。 例如車輛

系統實作時,可在下列位置為所有 Android 音效使用一個公車連接埠 在這種情況下,Android 會結合所有元素並在單一串流中傳送。 或者,HAL 可以為每個 CarAudioContext 提供一個公車連接埠,以便 並行傳送這使 HAL 可以 實作以視需求混合及消除不同聲音

將音訊情境指派給輸出裝置是透過以下方式完成: car_audio_configuration.xml

麥克風輸入

擷取音訊時,音訊 HAL 會收到 openInputStream 呼叫,其中包括 AudioSource 引數,指出 應該處理麥克風輸入

VOICE_RECOGNITION 來源 (具體來說是 Google 助理) 預期的立體聲麥克風串流, 消除回音 (如有),但不套用其他處理程序。 Google 助理應一律採用波束成形技術。

多聲道麥克風輸入

如要透過含有超過兩個聲道 (立體聲) 的裝置擷取音訊,請使用 頻道索引遮罩,而不採用位置索引遮罩 (例如 CHANNEL_IN_LEFT)。範例:

final AudioFormat audioFormat = new AudioFormat.Builder()
    .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
    .setSampleRate(44100)
    .setChannelIndexMask(0xf /* 4 channels, 0..3 */)
    .build();
final AudioRecord audioRecord = new AudioRecord.Builder()
    .setAudioFormat(audioFormat)
    .build();
audioRecord.setPreferredDevice(someAudioDeviceInfo);

setChannelMasksetChannelIndexMask 皆有 設定後,AudioRecord 只會使用 setChannelMask (最多兩個頻道)。

並行擷取

自 Android 10 起,Android 架構支援並行擷取 ,但為了保護使用者隱私,我們會設下限制。裝置 包括限制的虛擬資料來源 系統會忽略 AUDIO_SOURCE_FM_TUNER,因此允許 與一般輸入 (如麥克風) 同時擷取。 HwAudioSources 也不會視為並行作業 。

適用於AUDIO_DEVICE_IN_BUS裝置或 次要 AUDIO_DEVICE_IN_FM_TUNER 裝置必須明確依賴 識別這些裝置並使用 AudioRecord.setPreferredDevice() 略過 Android 預設來源選取邏輯。

音訊使用情形

AAOS 主要使用 AudioAttributes.AttributeUsages 轉送、調整數量和管理焦點由於用量指的是 「原因」的向量表示或是顯示目前的串流因此,所有串流 和音訊焦點要求應指定播放音訊的使用情況。時間 未在建立 AudioAttributes 物件時特別設定,則使用 預設為 USAGE_UNKNOWN。雖然目前 與 USAGE_MEDIA,此行為不應依賴於媒體 播放。

系統使用情況

而 Android 11 導入了系統用量。使用情形 與先前建立的用法類似,差別只在於需要使用系統 API 以及 android.permission.MODIFY_AUDIO_ROUTING而 系統使用案例包括:

  • USAGE_EMERGENCY
  • USAGE_SAFETY
  • USAGE_VEHICLE_STATUS
  • USAGE_ANNOUNCEMENT

如要建構包含系統用途的 AudioAttributes,請使用 AudioAttributes.Builder#setSystemUsage 而不是 setUsage。以非系統方式呼叫這個方法 會導致系統擲回 IllegalArgumentException。此外,如果 會在建構工具上設定系統使用量和用量 IllegalArgumentException建構時。

查看哪些用量與 AudioAttributes 相關聯 呼叫 AudioAttributes#getSystemUsage。 此方法會傳回相關的用量或系統用量。

音訊情境

為簡化 AAOS 音訊的設定,我們將類似使用方式分組 放入 CarAudioContext。這些音訊情境會用於 CarAudioService:定義轉送、音量群組和音訊焦點 以自動化做法管理成本

Android 11 的音訊情境如下:

CarAudioContext 相關聯的屬性使用資訊
MUSIC UNKNOWN, GAME, MEDIA
NAVIGATION ASSISTANCE_NAVIGATION_GUIDANCE
VOICE_COMMAND ASSISTANT, ASSISTANCE_ACCESSIBILITY
CALL_RING NOTIFICATION_RINGTONE
CALL VOICE_COMMUNICATION, VOICE_COMMUNICATION_SIGNALING
ALARM ALARM
NOTIFICATION NOTIFICATION, NOTIFICATION_*
SYSTEM_SOUND ASSISTANCE_SONIFICATION
EMERGENCY EMERGENCY
SAFETY SAFETY
VEHICLE_STATUS VEHICLE_STATUS
ANNOUNCEMENT ANNOUNCEMENT

音訊情境和使用方式的對照表。醒目顯示的資料列是新的 系統使用

多區域音訊

汽車業為並行使用者帶來一系列新的用途 與平台互動,並希望使用不同的媒體。適用對象 舉例來說,駕駛人可以在後座在車廂中播放音樂 是透過後置顯示器觀看 YouTube 影片多區域音訊功能可讓 讓不同的音訊來源在不同區域同時播放 。

Android 10 開始的多區域音訊功能可讓原始設備製造商 (OEM) 設定音訊 到個別可用區中每個可用區都是車輛內部的一組裝置 含有專屬磁碟區群組、情境路徑設定和焦點 以自動化做法管理成本透過這種方式,將主機櫃可以設為單一音訊 區域,而後置顯示器的耳機插孔則設為第二個區域。

區域定義為 car_audio_configuration.xml 的一部分。 CarAudioService 會讀取設定,並協助 AudioService 根據相關聯的可用區轉送音訊串流每個可用區都仍會定義 基於結構定義和應用程式 UID 的轉送規則。當玩家 CarAudioService 會決定玩家在哪個可用區 或與 AudioFlinger 的使用情況有關 應將音訊轉送至

每個音訊區域的焦點也會分開維護。這樣一來, 在不同可用區中獨立產生音訊 幹擾彼此,同時讓應用程式仍會尊重 成為區域內的焦點CarZonesAudioFocus 範圍: CarAudioService 負責管理 可用區

設定多區域音訊

圖 2. 設定多區域音訊

音訊 HAL

Automotive 音訊導入作業仰賴標準 Android Audio HAL。 包括:

  • IDevice.hal。建立輸入和輸出串流。 會處理主要磁碟區和靜音,並使用:
    • createAudioPatch。在裝置之間建立外部修補程式。
    • IDevice.setAudioPortConfig() 可為每個實體串流提供音量。
  • IStream.hal。除了輸入和輸出變化版本 管理與硬體之間的音訊樣本串流。

Automotive 裝置類型

以下裝置類型與汽車平台相關。

裝置類型 說明
AUDIO_DEVICE_OUT_BUS Android 的主要輸出內容 (這就是 Android 所有音訊 )做為區分串流的位址 這兩種情境的關聯
AUDIO_DEVICE_OUT_TELEPHONY_TX 用於轉送至手機無線電進行傳輸的音訊。
AUDIO_DEVICE_IN_BUS 用於未分類的輸入內容。
AUDIO_DEVICE_IN_FM_TUNER 僅適用於廣播電台輸入。
AUDIO_DEVICE_IN_TV_TUNER 供電視裝置使用 (如有)。
AUDIO_DEVICE_IN_LINE 用於 AUX 輸入插孔。
AUDIO_DEVICE_IN_BLUETOOTH_A2DP 透過藍牙接收的音樂。
AUDIO_DEVICE_IN_TELEPHONY_RX 用於與手機相關聯的行動網路無線電接收音訊 呼叫。

設定音訊裝置

Android 可以看到的音訊裝置必須 /audio_policy_configuration.xml,其中包含下列元件:

  • 模組名稱。支援「primary」(適用於汽車用途)、 「A2DP」、「remote_submix」和「USB」。模組名稱和對應的音訊 驅動程式應編譯為 audio.primary.$(variant).so
  • devicePorts。包含所有輸入和輸出的裝置描述元清單 裝置 (包括永久連接裝置和卸除式裝置), 以便透過這個模組存取
    • 您可以為每部輸出裝置定義增益控制 min/max/default/step 值,以毫貝表示 (1 毫貝 = 1/100 dB = 1/1000 bel)。
    • devicePort 執行個體上的 address 屬性可用來找出 即使您有多部裝置使用相同的裝置類型 AUDIO_DEVICE_OUT_BUS
  • MixPorts。包含由公開伺服器公開的所有輸出和輸入串流清單 音訊輸出裝置每個 MixPort 執行個體可視為 Android AudioService。
  • 路徑。定義輸入與輸出之間的可能連線清單 或在串流和裝置之間切換

以下範例定義了輸出裝置 bus0_phone_out,其中所有 Android 音訊串流混合了 Mixer_bus0_phone_out 參數。路徑 將「mixer_bus0_phone_out」的串流輸出到裝置 bus0_phone_out

<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
    <modules>
        <module name="primary" halVersion="3.0">
            <attachedDevices>
                <item>bus0_phone_out</item>
<defaultOutputDevice>bus0_phone_out</defaultOutputDevice>
            <mixPorts>
                <mixPort name="mixport_bus0_phone_out"
                         role="source"
                         flags="AUDIO_OUTPUT_FLAG_PRIMARY">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                            samplingRates="48000"
                            channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
            </mixPorts>
            <devicePorts>
                <devicePort tagName="bus0_phone_out"
                            role="sink"
                            type="AUDIO_DEVICE_OUT_BUS"
                            address="BUS00_PHONE">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                            samplingRates="48000"
                            channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                    <gains>
                        <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
                                minValueMB="-8400"
                                maxValueMB="4000"
                                defaultValueMB="0"
                                stepValueMB="100"/>
                    </gains>
                </devicePort>
            </devicePorts>
            <routes>
                <route type="mix" sink="bus0_phone_out"
                       sources="mixport_bus0_phone_out"/>
            </routes>
        </module>
    </modules>
</audioPolicyConfiguration>