車用音訊外掛程式服務

Android 14 中的全新車輛 OEM 外掛程式服務可設定部分車輛元件。針對音訊,我們推出了三項新的外掛程式服務,讓 OEM 廠商能彈性設定 AAOS 裝置的音訊管理功能:

  • 音訊焦點控制
  • 音量和靜音控制
  • 音訊降低控制

車輛外掛程式服務架構

下圖概述汽車服務,以及這些服務與 OEM 汽車服務的關係。與應用程式程序和車輛服務程序類似,OEM 車輛服務程序會佔用自己的程序空間。

圖片

車輛服務會找出 config_oemCarService 中定義的元件,藉此啟動 OEM 車輛服務。如果設定為空白,表示 OEM 服務不存在,且不會啟動任何服務。元件必須擴充 OemCarService。車輛音訊服務必須覆寫用於取得車輛音訊 OEM 服務的 API:

public final class OemCarServiceImp extends OemCarService {
    @Override
    public OemCarAudioFocusService getOemAudioFocusService();

    @Override
    public OemCarAudioDuckingService getOemAudioDuckingService();

    @Override
    public OemCarAudioVolumeService getOemAudioVolumeService();
}

如需範例,請參閱 packages/services/Car/tests/OemCarServiceTestApp 中定義的參考測試應用程式。

即使這項服務是由車輛服務啟動,也不會自動沿用車輛音訊服務的可用權限。因此,OEM 服務所需的任何權限都應透過適當機制取得。如需範例,請參閱 packages/services/Car/data/etc/com.android.car.oemcarservice.testapp.xml

採用 OEM 服務架構的車輛音訊服務

在 AAOS 中,車用音訊服務會管理下列動作:

  • 音訊路由
  • 音訊焦點
  • 降低其他應用程式音量
  • 音量和靜音

在 Android 14 之前,這項行為大多是靜態的,只能透過設定修改,但僅限於極少數情況。Android 14 推出車輛音訊服務的通訊機制,可與 OEM 定義的元件通訊,管理下列項目:

  • 音訊焦點
  • 降低其他應用程式音量
  • 音量和靜音

下圖顯示車輛音訊服務和車輛原始設備製造商 (OEM) 服務的簡化架構。車輛音訊服務定義了不同的掛鉤,可呼叫車輛 OEM 音訊服務來管理音訊行為。只有在定義相應的 OEM 車輛音訊服務元件時,才會發生後者情況。否則,車輛音訊服務會使用預設行為。

圖片

為確保車輛音訊服務和車輛 OEM 音訊服務一律保持同步,車輛音訊服務會在每次呼叫時,將音訊堆疊目前狀態的必要部分傳遞至車輛 OEM 音訊服務。舉例來說,當車輛音訊服務攔截評估音訊焦點的要求時,會將堆疊的目前狀態傳遞至車輛 OEM 音訊服務。目前狀態包括目前的焦點持有者和目前的焦點失去者。焦點遺失者是仍屬於堆疊,但暫時失去焦點的焦點要求。

車輛音訊服務必須管理車輛中的所有音訊活動。如果車輛音訊服務未管理部分音訊行為,則向車輛 OEM 音訊服務公開的資訊不完整。舉例來說,如果 OEM 註冊自己的音訊焦點政策,覆寫車輛服務中的音訊焦點處理程序,車輛音訊服務就無法向車輛 OEM 音訊服務提供完整資訊。這可能會影響車輛 OEM 音訊服務的決策能力,因為車輛音訊服務可能缺少無法顯示的資訊。

如要執行動作,車輛音訊服務會呼叫 OEM 車輛服務。這些呼叫是在不同程序之間進行,因此需要程序間通訊 (IPC)。IPC 會增加每次呼叫的延遲時間。請務必盡量縮短 OEM 服務的延遲時間。

由於對 OEM 服務的車輛音訊服務呼叫會遭到封鎖,因此 OEM 服務不應在直接 API 評估中呼叫車輛音訊服務。車輛音訊服務會提供必要資訊,因此兩個程序之間的呼叫只需要單向傳輸。

原始設備製造商 (OEM) 車輛音訊服務定義

OEM 車輛音訊焦點服務

車輛音訊服務會註冊音訊政策焦點監聽器,藉此管理應用程式的音訊焦點要求。車輛音訊服務具有管理焦點行為的機制,可根據靜態互動矩陣執行管理。矩陣定義了三種不同的互動:

  • 並行互動。焦點擁有者可以同時維持焦點。

  • 專屬互動。傳入的焦點要求會從目前的焦點持有者取得焦點。

  • 拒絕互動。系統根據目前的焦點持有者拒絕傳入的焦點要求。

雖然這足以應付部分車輛用途,但無法滿足所有互動需求,因為 OEM 需求可能有所不同。為此,我們推出 OemCarAudioFocusService

public interface OEmCarAudioFocusService {
    OemCarAuddioFocusResults evaluateAudioFocusRequest(
        OemCarAudioFocusEvaluationRequest request);
    
    void notifyAudioFocusChange(
        List<AudioFocusEntry> holder,
        List<AudioFocusEntry> losers, int zoneId);
}

每當有需要評估的音訊焦點要求時,車輛音訊服務就會呼叫 evaluateAudioFocusRequest API,這項雙向 API 會封鎖結果回傳。要求包含音訊堆疊目前狀態的相關資訊:

這項資訊可用於評估 newFocusRequest 相較於 focusHolders 中目前焦點持有者和 focusLosers 中目前焦點失利者的表現。API 應會傳回結果:

class OemCarAudioFocusResult {
    int audioZoneId;
    int audioFocusEvaluationResults;
    AudioFocusEntry focusResult;
    List<AudioFocusEntry> newLosers;
    List<AudioFocusEntry> newlyBlocked;
}

這包含 audioFocusEvaluationResults 中的實際評估結果資訊,指出目前要求是否已獲准、延遲或失敗。目前的焦點堆疊如有任何變更,應視堆疊變更的性質,在 newLosersnewlyBlocked 項目中設定。

如果 newLosers 包含先前保留焦點的項目,但現在應永久或暫時失去焦點,系統會從音訊焦點堆疊中進一步移除永久失去焦點的應用程式,並將暫時失去焦點的應用程式移至目前的焦點遺失者堆疊,直到這些應用程式重新取得焦點,或原始焦點要求者放棄焦點為止。無論如何,要求的焦點接聽程式都會收到相應的焦點遺失。

newlyBlocked 清單包含先前位於焦點失去者清單中的項目,但現在遭到新項目封鎖。封鎖可以是永久或暫時的,如果是永久封鎖,系統會從堆疊中移除項目,並將焦點遺失事件傳送至焦點監聽器。如果是暫時失去焦點,項目會保留在焦點遺失者堆疊中,但新的焦點封鎖程式會新增至封鎖程式清單,且不會傳送焦點遺失訊息,因為系統先前已在首次封鎖時傳送過。移除所有目前的封鎖程式後,要求最終會解除封鎖,如果焦點遭到捨棄,要求則會從堆疊中移除。

第二個 API notifyAudioFocusChange 是單向 API,會在每次要求或放棄音訊焦點時呼叫。這個 API 主要用於通知 OEM 服務焦點變更,這可能會影響 OEM 車輛音訊服務的行為。

焦點評估指南

在 AAOS 中,音訊焦點用於管理音訊播放作業,並決定哪些應用程式應遵守規定,為使用者提供最佳體驗。因此,OEM 外掛程式服務在管理音訊焦點要求時,應考量下列事項:

  • 如果沒有任何持續的高優先順序音訊焦點 (例如電話通話、緊急情況或安全),應用程式應能暫時或永久取得音訊焦點。

  • 媒體焦點處於啟用狀態時,要求下列項目的應用程式:

    • 通話使用焦點,應可同時或專屬接收焦點。

    • 瀏覽使用焦點,應能同時或專屬接收焦點。

    • Google 助理的使用焦點,應能同時或專屬接收焦點。

  • 當應用程式處於高優先順序音訊焦點 (例如電話通話、緊急警報或安全警報) 時,系統應視需要授予或延遲任何傳入的延遲音訊焦點要求。

雖然上述建議並非詳盡無遺,但可確保在沒有作用中的高優先權音效時,要求焦點的應用程式應能取得焦點。即使高優先順序音效處於啟用狀態,系統仍應遵守延遲的焦點要求,並在停止播放高優先順序音效後,允許要求取得焦點。

OEM 車輛音量服務

車輛音訊服務會監聽音訊系統的音量調整作業,或直接監聽車輛輸入服務的音量鍵事件,藉此管理音量鍵事件。在上述任一情況下,車輛音訊服務的預設行為是根據作用中的音訊播放器和音訊內容優先順序清單,判斷要變更哪個音量群組。

我們提供兩份音量優先順序清單。第一個清單會依這個順序考量所有音訊情境。清單會依優先順序由高至低排序,最高優先順序位於頂端,最低優先順序位於底部。舉例來說,如果導航音訊和音樂音訊同時處於啟用狀態,則在音量鍵事件期間會變更導航音量。

  1. 導覽
  2. 撥打電話
  3. 音樂
  4. 公告
  5. 語音指令
  6. 來電響鈴
  7. 系統音效
  8. 安全性
  9. 鬧鐘
  10. 通知
  11. 車輛狀態
  12. 緊急

為簡化音量鍵事件管理,車輛音訊服務提供第二個音訊內容優先順序清單:

  1. 撥打電話
  2. 媒體
  3. 公告
  4. 語音指令

這份清單也會依遞減順序排列。第二個清單的目的,是允許透過重要事件變更更常見的聲音。不常見的音效 (例如較短的音效) 只能透過音訊設定使用者介面管理。

實際的音量版本可透過 audioVolumeAdjustmentContextsVersion 設定。設定可以設為 12 (預設為 2)。

為提供更彈性的音量管理方式,Android 14 推出 OemCarAudioVolumeService

public interface OemCarAudioVolumeService {
    OemCarvolumeChangeInfo getSuggestedGroupForVolumeChange(
OemCarAudioVolumeRequest request, int volumeAdjustment);
}

OEM 車輛音訊音量服務只有一個方法,會接收 volumeAdjustmentOemCarAudioVolumeRequest

class OemCarAudioVolumeRequest {
    int audioZoneId;
    int callState;
    List<AudioAttributes> activePlaybackAttributes;
    List<AudioAttributes> duckedAttributes;
    List<CarVolumeGroupInfo> volumeGroupState;
}

要求的 activePlaybackAttributes 具有有效的音訊屬性。duckedAttributes 是目前所有已迴避的音訊屬性。volumeGroupState 是磁碟區群組的目前狀態。要求代表音訊堆疊的目前狀態,可用於判斷應變更哪個音量群組。結果應以 OemCarVolumeChangeInfo 形式傳回:

class OemCarVolumeChangeInfo {
    boolean change;
    CarVolumeGroupInfo volumeGroupChanged;
}

change 布林值表示音量是否已變更,true 則表示音量已變更,且應更新音量群組。volumeGroupChanged 是實際應變更的音量群組。這個群組應根據傳遞至 API 的原始 volumeAdjustment 參數進行變更。舉例來說,如果結果指出應將導覽音量群組設為靜音,則布林值會是 true,且傳回的音量群組應為導覽音量群組。

OEM 汽車音量調降服務

車輛音訊服務會監控音訊焦點變化,並傳送訊號至 AudioControl HAL,指出要調降哪些音訊裝置的音量,藉此管理音訊調降。焦點變更時,系統會評估所有有效的焦點持有者,根據這組靜態閃避規則判斷應閃避的項目:

  • 警報聲會將通話音效以外的所有音效調低音量
  • 安全模式會關閉緊急救援音效以外的所有音效
  • 導覽會關閉所有音效,但安全和緊急音效除外
  • Call ducks everything except safety, emergency, and navigation sounds
  • Voice 會調低來電鈴聲
  • 所有內容都應降低音樂和公告的音量

這些規則並非詳盡無遺,原始設備製造商仍須負責根據這些規範,判斷如何調降音量。OEM 可以根據可用需求,更積極地控管這些建議。Android 14 推出 OemCarDuckingService

class OemCarAudioDuckingService {
List<AudioAttributes>   evaluateAttributesToDuck(
        OemCarAudioVolumeRequest request);
}

當音訊焦點變更時,車輛音訊服務會呼叫這個 API。這項服務會重複使用原始設備製造商 (OEM) 車輛音量服務中導入的 OemCarAudioVolumeRequest,並包含相關資訊,可協助您決定要降低哪些屬性的音量。系統會將要透過 API 降低音量的音訊屬性清單,與目前的音訊狀態進行比較:

  • 目前音訊屬性已調低音量:

    • 在清單中,繼續閃避
    • 不在清單中,已關閉閃避功能
  • 目前未調降音量的音訊屬性:

    • 在清單中,已迴避
    • 不在清單中,已關閉閃避功能

車輛音訊服務接著會判斷音訊屬性所屬的音訊輸出裝置,並分別將這些裝置新增至音訊閃避輸出裝置清單或未閃避音訊裝置清單。這項資訊最終會傳送至 AudioControl HAL,在硬體層級執行必要的音量調降作業。

下圖是使用 OEM 閃避服務時,音訊閃避控制項的簡化序列圖,適用於焦點要求:

圖片

當應用程式透過公開音訊管理員 API 要求「管理音訊焦點」時,就會啟動這個序列。要求會轉送至車輛音訊服務,以判斷結果。決定音訊焦點後,車輛音訊服務會呼叫 OemCarAudioDuckingService 評估降低其他應用程式音量,判斷應降低哪些音訊屬性。evaluateAttributesToDuck API 傳回結果後,系統會計算要調降音量的音訊裝置,最後將資訊傳送至 AudioControl,對音訊硬體套用調降音量設定。

OEM 車輛音訊服務參考實作

AAOS 在 packages/services/Car/tests/OemCarServiceTestApp 中提供 OEM 車輛服務的參考實作,其中實作了 OemCarService,以及 OemCarAudioFocusServiceOemCarAudioDuckingServiceOemCarAudioVolumeService。如果是後者,每項服務都會使用 XML 檔案載入靜態行為。舉例來說,OemCarAudioFocusServiceImp 會載入 oem_focus_config.xml,其中包含互動矩陣。矩陣用於評估呼叫 evaluateAudioFocusRequest 時的焦點要求。

參考測試應用程式偵錯

OEM 車用服務測試應用程式是 AOSP 原始碼的一部分。原始設備製造商可根據需求進行變更。如要進行偵錯,請使用 config_oemCarService 設定啟用測試應用程式。

<!-- This is the component name for the OEM customization service. OEM can choose to implement
this service to customize car service behavior for different policies. If OEMs choose to
implement it, they have to implement a service extending OemCarService exposed by car-lib,
and implement the required component services.
If the component name is invalid, CarService would not connect to any OEM service.
Component name can not be a third party package. It should be pre-installed -->
<string name="config_oemCarService" translatable="false">
com.android.car.oemcarservice.testapp/.OemCarServiceImpl
</string>

如要確認 OEM 車用服務使用車用服務 dump 指令,請執行下列操作:

adb shell dumpsys car_service --oem-service

結果可能如下所示:

***CarOemProxyService dump***
  mIsFeatureEnabled: true
  mIsOemServiceBound: true
  mIsOemServiceReady: true
  mIsOemServiceConnected: true
  mInitComplete: true
  OEM_CAR_SERVICE_CONNECTED_TIMEOUT_MS: 5000
  OEM_CAR_SERVICE_READY_TIMEOUT_MS: 5000
  mComponentName: com.android.car.oemcarservice.testapp/.OemCarServiceImpl

每批 dump 資訊中的每個布林值,都會決定功能和服務的狀態。舉例來說,傾印資訊 mIsOemServiceReady 會指定服務是否可供使用,其中 true 表示服務已準備就緒,false 則表示服務尚未準備就緒。