磁碟區管理

AAOS 在 CarAudioService 中提供專屬的音量管理功能。它使用固定音量,並預期音量應由硬體放大器在 HAL 下方套用,而非在軟體中套用。它也會將輸出裝置分類為音量群組,以便將相同的增益值套用至與音量群組相關聯的所有裝置。

使用固定磁碟區

AAOS 實作項目應使用硬體放大器,而非軟體混音器來控制音量。為避免副作用,請將 config_useFixedVolume 標記設為 true (視需要重疊):

<resources>
    <!-- Car uses hardware amplifier for volume. -->
    <bool name="config_useFixedVolume">true</bool>
</resources>

如果未設定 config_useFixedVolume 旗標 (或設為 false),應用程式可以呼叫 AudioManager.setStreamVolume(),並依據軟體混音器中的串流類型變更音量。這可能不是理想做法,因為這會對其他應用程式造成潛在影響,而且軟體混合器的音量衰減會導致在硬體放大器接收時,信號中可用的有效位元數減少。

音量群組

音量群組可管理音訊區內一組裝置的音量。每個音量群組都可以獨立控制音量,而產生的增益會在相關聯的裝置上設定,以便由車輛的放大器套用。系統會保留使用者的音量設定,並在使用者登入時載入。

定義磁碟區群組

CarAudioService 會使用 car_audio_configuration.xml 中定義的音量群組:

<audioZoneConfiguration version="2.0">
    <zones>
        <zone name="primary zone" isPrimary="true">
            <volumeGroups>
                <group>
                    <device address="bus0_media_out">
                        <context context="music"/>
                    </device>
                </group>
                <group>
                    <device address="bus1_navigation_out">
                        <context context="navigation"/>
                    </device>
                    <device address="bus2_voice_command_out">
                        <context context="voice_command"/>
                    </device>
                </group>
                ...
            </volumeGroups>
        </zone>
     </zones>
</audioZoneConfiguration>

car_audio_configuration.xml 實作範例。

每個音量群組都應包含一或多個輸出裝置,並附上相關聯的地址。這些位址應對應至 audio_policy_configuration.xml 中定義的輸出裝置。

設定磁碟區群組增益

每個音量群組都有最小、最大和預設增益值,以及步距大小。這些值是根據 audio_policy_configuration.xml 中為與音量群組相關聯的裝置所設定的值決定。

<devicePort tagName="bus0_media_out" role="sink" type="AUDIO_DEVICE_OUT_BUS" address="bus0_media_out">
  <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
  <gains>
    <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
      minValueMB="-3200" maxValueMB="600" defaultValueMB="0" stepValueMB="100"/>
  </gains>
</devicePort>

在初始化期間,音量群組會檢查相關聯裝置的增益值,並按照以下方式設定群組:

  • 步距大小。由音量群組控制的所有裝置都必須相同
  • 最低增益。群組中裝置的最小增益
  • 最大增益。群組中裝置的最高增益
  • 預設增益。群組中裝置的最高預設增益

由於這些值的設定方式,您可以將音量群組的增益值設為超出與音量群組相關聯裝置支援的範圍。在這種情況下,系統會根據音量群組的值是否低於或高於範圍,將增益值設為裝置的最低或最高增益值。

磁碟區群組 ID

系統會根據 XML 檔案中的定義順序,在執行階段識別音量群組。在音訊區域中,ID 的範圍為 0 到 N-1,其中 N 是該區域中的音量群組數量。因此,在不同區域中,磁碟群組 ID 可能會重複。這些 ID 會用於與磁碟區群組相關聯的 CarAudioManager API。任何 API 在沒有 zoneId 的情況下,如果接收 groupId,則會預設為主要音訊區域。

多區域音量管理

每個音訊區域都應包含一或多個音量群組,且每個音量群組只會與單一音訊區域相關聯。這項關係定義為 car_audio_configuration.xml 的一部分。請參閱上文「定義磁區群組」中的範例。

每個區域目前的音量都會保留給與該區域相關聯的使用者。這些設定會依區域而異,也就是說,如果使用者在與主要區域相關聯的螢幕上登入,然後稍後登入與次要音訊區域相關聯的區域,則第一個區域載入和保留的音量會與次要區域不同。

處理音量鍵事件

Android 定義了幾個用於控制音量的鍵碼,包括 KEYCODE_VOLUME_UPKEYCODE_VOLUME_DOWNKEYCODE_VOLUME_MUTE。根據預設,Android 會將音量鍵事件轉送至應用程式。車用系統實作項目應將這些重要事件強制轉送至 CarAudioService,然後視需要呼叫 setGroupVolumesetMasterMute

如要強制執行這項行為,請將 config_handleVolumeKeysInWindowManager 標記設為 true

<resources>
    <bool name="config_handleVolumeKeysInWindowManager">true</bool>
</resources>

音量鍵事件目前無法區分要用於哪個區域,因此系統會假設這些事件都與主要音訊區域相關。收到音量鍵事件時,CarAudioService 會擷取目前播放器的音訊內容,然後調整包含與最高優先順序音訊內容相關聯的輸出裝置的音量群組,藉此決定要調整哪個音量群組。優先順序會根據 CarVolume.AUDIO_CONTEXT_VOLUME_PRIORITY 中定義的固定順序決定。

淡出和平衡

兩個版本的 AudioControl HAL 都包含用於設定車輛淡出和平衡的 API。CarAudioManager 有對應的系統 API,可將值傳遞至 AudioControl HAL。這些 API 需要使用 android.car.permission.CAR_CONTROL_AUDIO_VOLUME

AudioControl API 如下:

  • setBalanceTowardRight(float value):將揚聲器音量調至車輛的右側 (+) 或左側 (-)。0.0 是居中,+1.0 是完全右移,-1.0 是完全左移,如果值超出 -1 到 1 的範圍,則會發生錯誤。
  • setFadeTowardFront(float value):將揚聲器音量調高 (+) 或調低 (-)。0.0 代表居中,+1.0 代表完全向前,-1.0 代表完全向後,如果值超出 -1 到 1 的範圍,則會發生錯誤。

原始設備製造商 (OEM) 可自行決定如何套用這些值,以及如何向使用者顯示這些值。這些設定可以只套用至媒體,也可以套用至整個主機板上的所有 Android 音效。

Android 11 也推出了支援功能,可將音訊效果套用至輸出裝置。有了這個選項,您就可以在適當的輸出裝置上透過音訊效果管理淡出和平衡,而非透過這些 API。

降低其他應用程式音量

當車輛降低某個串流的增益值,以便更清楚地聽到同時播放的另一個串流時,就會發生音訊降低現象。在 AAOS 中,音訊調低功能由 HAL 實作,因為 Android 以外可能有許多 OS 無法控制的音訊。在 Android 11 中,HAL 可用來做出靜音決策的主要資訊,是兩個輸出裝置是否都有有效的串流。

何時要降低音量

雖然各個原始設備製造商 (OEM) 可自行決定 HAL 如何處理靜音功能,但我們建議遵循以下一般準則。在 Android 中播放多個串流的情況最常發生在兩個應用程式/服務同時保有音訊焦點時。請參閱「互動矩陣」一文,瞭解 Android 何時可能會授予並行焦點,進而瞭解兩個不同的串流何時可能同時播放。

請注意,任何由 Android 混合在一起的串流都會在任何增益套用前完成。因此,任何在與其他內容同時播放時應進行淡出處理的串流,都應導向至不同的輸出裝置,以便 HAL 在混合前套用淡出處理。

建議的靜音行為

以下是可能同時發生的互動,建議您套用隱藏功能:

  • EMERGENCY:將 SAFETY 以外的所有音訊設為靜音或降低音量,確保駕駛人能聽到聲音
  • SAFETY. 將 EMERGENCY 以外的所有音量降低,確保駕駛人能聽到聲音
  • NAVIGATION。除了 SAFETYEMERGENCY 以外,其他都設為 Duck
  • CALL。Duck 所有 SAFETYEMERGENCYNAVIGATION 以外的項目
  • VOICE. Duck CALL_RING
  • 原始設備製造商 (OEM) 可自行決定要將哪些聲音設為活動 VEHICLE_SOUNDS,以及是否應將其他聲音調低,以確保駕駛人能聽見這些聲音。
  • MUSICANNOUNCEMENT 應由所有項目隱藏。這項規則的主要例外狀況是觸控互動音效,目前會以 SYSTEM_SOUND 播放

使用靜音功能時的其他注意事項

導航或助理等部分應用程式/服務可能會使用多個玩家來完成操作。原始設備製造商應避免根據串流資料停止透過這些輸出裝置傳送的時間,過度積極地取消靜音,以確保使用者不會在導航或助理應用程式開始播放下一個內容時,讓媒體暫時恢復至最大音量。

如果車輛有多個音訊階段,且隔離效果良好,您也可以選擇將音訊傳送至車輛的不同區域,而非降低音量。舉例來說,您可以將導航指示傳送至駕駛座椅頭枕的揚聲器,同時在車內以正常音量播放音樂。

安全性關鍵音效

雖然 Android 11 推出了 HAL 音訊焦點 API,但仍須由 HAL 確保安全性至關重要的音訊優先於其他音訊。即使 HAL 為 USAGE_EMERGENCY 保留音訊焦點,也無法保證 Android 中的應用程式和服務不會播放音訊。當播放安全性重要音效時,HAL 會決定應混合或靜音哪些 Android 串流。

設定音量設定 UI

AAOS 會將音量設定 UI 與音量群組設定分開 (可重疊,如「設定音量群組」一節所述)。這樣一來,如果日後磁區群組設定有所變更,就不需要進行變更。

在「車輛設定」使用者介面中,packages/apps/Car/Settings/res/xml/car_volume_items.xml 檔案包含與每個定義的 AudioAttributes.USAGE 相關聯的 UI 元素 (標題和圖示資源)。這個檔案會使用與每個 VolumeGroup 中首個已辨識用途相關聯的資源,提供定義 VolumeGroups 的合理算繪。

舉例來說,以下範例將 VolumeGroup 定義為同時包含 voice_communicationvoice_communication_signalling。車輛設定 UI 的預設實作會使用與 voice_communication 相關聯的資源算繪 VolumeGroup,因為這是檔案中的第一個資源。

<carVolumeItems xmlns:car="http://schemas.android.com/apk/res-auto">
    <item car:usage="voice_communication"
          car:title="@*android:string/volume_call"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="voice_communication_signalling"
          car:title="@*android:string/volume_call"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="media"
          car:title="@*android:string/volume_music"
          car:icon="@*android:drawable/ic_audio_media"/>
    <item car:usage="game"
          car:title="@*android:string/volume_music"
          car:icon="@*android:drawable/ic_audio_media"/>
    <item car:usage="alarm"
          car:title="@*android:string/volume_alarm"
          car:icon="@*android:drawable/ic_audio_alarm"/>
    <item car:usage="assistance_navigation_guidance"
          car:title="@string/navi_volume_title"
          car:icon="@drawable/ic_audio_navi"/>
    <item car:usage="notification_ringtone"
          car:title="@*android:string/volume_ringtone"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="assistant"
          car:title="@*android:string/volume_unknown"
          car:icon="@*android:drawable/ic_audio_vol"/>
    <item car:usage="notification"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="notification_communication_request"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="notification_communication_instant"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="notification_communication_delayed"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="notification_event"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="assistance_accessibility"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="assistance_sonification"
          car:title="@*android:string/volume_unknown"
          car:icon="@*android:drawable/ic_audio_vol"/>
    <item car:usage="unknown"
          car:title="@*android:string/volume_unknown"
          car:icon="@*android:drawable/ic_audio_vol"/>
</carVolumeItems>

上述設定中使用的屬性和值會在 packages/apps/Car/Settings/res/values/attrs.xml 中宣告。音量設定 UI 會使用下列以 VolumeGroup 為基礎的 CarAudioManager API:

  • getVolumeGroupCount(),瞭解應繪製多少個控制項。
  • getGroupMinVolume()getGroupMaxVolume() 取得下限和上限。
  • getGroupVolume() 取得目前的音量。
  • registerVolumeChangeObserver() 以便在音量有變更時收到通知。