汽車音響

Android 汽車作業系統 (AAOS) 基於核心 Android 音訊堆疊構建,支援作為車輛資訊娛樂系統運行的用例。 AAOS 負責資訊娛樂聲音(即媒體、導航和通訊),但不直接負責具有嚴格可用性和定時要求的提示音和警告。雖然 AAOS 提供信號和機制來幫助車輛管理音頻,但最終還是由車輛來決定應該為駕駛員和乘客播放哪些聲音,確保安全關鍵聲音和監管聲音能夠在無幹擾的情況下正確聽到。中斷。

由於 Android 管理車輛的媒體體驗,因此無線電調諧器等外部媒體來源應由應用程式表示,這些應用程式可以處理來源的音訊焦點和媒體鍵事件。

Android 11 對汽車相關音訊支援進行了以下更改:

Android 聲音與串流

汽車音響系統處理以下聲音和串流:

以流為中心的架構圖

圖 1.以流為中心的架構圖

Android 管理來自 Android 應用程式的聲音,控制這些應用程式並根據聲音類型將它們的聲音路由到 HAL 上的輸出裝置:

  • 邏輯流,在核心音訊術語中稱為來源,以音訊屬性標記。
  • 物理流,在核心音訊術語中被稱為設備,混合後沒有上下文資訊。

為了可靠性,外部聲音(來自獨立來源,例如安全帶警告鈴聲)在 Android 外部、HAL 之下甚至在單獨的硬體中進行管理。系統實現者必須提供一個混音器,接受來自 Android 的一個或多個聲音輸入流,然後以適當的方式將這些流與車輛所需的外部聲源組合起來。

HAL 實作和外部混音器負責確保聽到安全關鍵的外部聲音,並在 Android 提供的串流中混合並將它們路由到合適的揚聲器。

安卓聲音

應用程式可能具有一個或多個透過標準 Android API 進行互動的播放器(例如,用於焦點控制的AudioManager或用於串流的MediaPlayer ),以發出一個或多個邏輯音訊資料流。此資料可以是單通道單聲道或 7.1 環繞聲,但被路由並視為單一來源。應用程式流與AudioAttributes相關聯,AudioAttributes 向系統提供如何表達音訊的提示。

邏輯流透過 AudioService 傳送,並路由到一個(且僅一個)可用的實體輸出流,每個輸出流都是 AudioFlinger 內混音器的輸出。音訊屬性混合到物理流後,它們就不再可用。

然後,每個物理流都被傳送到音頻 HAL 以在硬體上渲染。在汽車應用程式中,渲染硬體可以是本地編解碼器(類似於行動裝置)或車輛實體網路上的遠端處理器。無論哪種方式,音訊 HAL 實現的工作就是提供實際的樣本數據並使其可聽。

外部串流

不應透過 Android 路由的聲音串流(出於認證或計時原因)可能會直接傳送到外部混音器。從 Android 11 開始,HAL 現在能夠請求這些外部聲音的焦點,以通知 Android,以便它可以採取適當的操作,例如暫停媒體或阻止其他人獲得焦點。

如果外部串流是應與 Android 產生的聲音環境互動的媒體來源(例如,開啟外部調諧器時停止 MP3 播放),則這些外部串流應由 Android 應用程式表示。此類應用程式將代表媒體來源而不是 HAL 請求音訊焦點,並根據需要啟動/停止外部來源來回應焦點通知,以適應 Android 焦點策略。該應用程式還負責處理媒體按鍵事件,例如播放/暫停。控制此類外部設備的建議機制是HwAudioSource

輸出裝置

在音訊 HAL 級別,設備類型AUDIO_DEVICE_OUT_BUS提供用於車輛音訊系統的通用輸出設備。總線設備支援可尋址連接埠(其中每個連接埠都是實體流的端點),並且預計將成為車輛中唯一支援的輸出設備類型。

系統實作可以使用一個總線連接埠來處理所有 Android 聲音,在這種情況下,Android 將所有內容混合在一起並將其作為一個串流提供。或者,HAL 可以為每個CarAudioContext提供一個總線端口,以允許並發傳送任何聲音類型。這使得 HAL 實現可以根據需要混合和迴避不同的聲音。

音訊上下文到輸出設備的分配是透過car_audio_configuration.xml完成​​的。

麥克風輸入

擷取音訊時,音訊 HAL 會收到一個openInputStream調用,其中包含一個AudioSource參數,指示應如何處理麥克風輸入。

VOICE_RECOGNITION來源(特別是 Google Assistant)需要具有迴聲消除效果(如果可用)的立體聲麥克風串流,但不對其應用其他處理。波束成形預計由助手完成。

多通道麥克風輸入

若要從具有兩個以上通道(立體聲)的裝置擷取音頻,請使用通道索引遮罩而不是位置索引遮罩(例如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 中的音訊上下文是:

汽車音訊上下文關聯屬性用法
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 應將音訊路由到哪個裝置。

每個音訊區域的焦點也是獨立維護的。這使得不同區域中的應用程式能夠獨立產生音訊而不會相互幹擾,同時應用程式仍然尊重其區域內焦點的變化。 CarAudioService中的CarZonesAudioFocus負責管理每個區域的焦點。

配置多區域音訊

圖 2. 配置多區域音頻

音訊哈爾

汽車音訊實現依賴於標準 Android Audio HAL,其中包括以下內容:

  • IDevice.hal 。建立輸入和輸出流,處理主音量和靜音,並使用:
    • createAudioPatch 。在設備之間建立外部-外部補丁。
    • IDevice.setAudioPortConfig()為每個物理流提供音量。
  • IStream.hal 。與輸入和輸出變體一起,管理進出硬體的音訊樣本流。

汽車設備類型

以下設備類型與汽車平台相關。

設備類型描述
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
  • 設備連接埠。包含可從此模組存取的所有輸入和輸出裝置(包括永久連接的裝置和可移動裝置)的裝置描述符清單。
    • 對於每個輸出設備,您可以定義由最小/最大/預設/步長值(以毫貝爾為單位)組成的增益控制(1 毫貝爾 = 1/100 dB = 1/1000 Bel)。
    • devicePort 實例上的位址屬性可用於尋找設備,即使存在多個設備類型與AUDIO_DEVICE_OUT_BUS相同的設備。
  • 混合連接埠。包含音訊 HAL 公開的所有輸出和輸入流的清單。每個 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>