車用音訊外掛程式服務

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);
}

每當有需要評估的音訊焦點要求時,車輛音訊服務就會呼叫 API evaluateAudioFocusRequest,這項雙向 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 鴨子 (安全性、緊急情況和導航音效除外)
  • 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 車用服務測試應用程式是 Android 開放原始碼計畫原始碼的一部分。原始設備製造商可根據需求進行變更。如要進行偵錯,請使用 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 則表示服務尚未準備就緒。