車輛音訊外掛程式服務

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) 車用服務。這些呼叫會跨程序進行,因此需要處理序間通訊 (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 外掛程式服務在管理音訊焦點要求時,應考量下列事項:

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

  • 媒體焦點處於啟用狀態時,應用程式要求:

    • 通話用途焦點應能同時或專屬地接收焦點。

    • 導覽使用者焦點應能同時或專屬地接收焦點。

    • 助理使用者焦點應能同時或專屬地接收焦點。

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

雖然上述建議並非詳盡無遺,但有助於確保在沒有任何高優先順序音效活動時,要求聚焦的應用程式能夠取得聚焦。即使高優先順序音效處於啟用狀態,系統仍應尊重延遲焦點要求,並在高優先順序音效停止後獲得焦點。

原始設備製造商 (OEM) 汽車音量服務

車輛音訊服務會透過監聽音訊系統的音量調整,或直接監聽車輛輸入服務的音量按鍵事件,來管理音量按鍵事件。在每個情況下,車輛音訊服務的預設行為是根據目前使用的音訊播放器和音訊內容優先順序清單,決定要變更哪個音量群組。

我們提供兩份音量優先順序清單。第一份清單會依照這個順序考量所有音訊內容。清單會依遞減順序顯示,優先順序最高的項目會顯示在最上方,優先順序最低的項目則顯示在最下方。舉例來說,如果導航音訊和音樂音訊同時啟用,則會在音量鍵事件期間變更導航音量。

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

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

  1. 致電
  2. 媒體
  3. 公告
  4. 語音指令

這份清單也會以遞減順序顯示。這個第二個清單的目的,是讓您透過按鍵事件變更更多常見的音效。不常見的音效 (例如較短的音效) 只能透過音訊設定 UI 管理。

您可以使用 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,指出要將哪些音訊裝置靜音。當焦點變更時,系統會評估所有有效的焦點持有者,並根據這組靜態遮蔽規則判斷應遮蔽哪些項目:

  • 緊急音效會將所有音效調低,但通話音效除外
  • 安全模式會關閉所有聲音,但緊急情況的聲音除外
  • 導航功能會將所有聲音都調小,但安全和緊急聲響除外
  • 除了安全、緊急和導航音效以外,所有音效都會靜音
  • 語音鴨子來電響鈴聲
  • 音樂和廣播應由所有內容暫停

這些規則並非詳盡無遺,原始設備製造商 (OEM) 仍須負責根據這些規範決定如何抑制音效。原始設備製造商 (OEM) 可以根據可用的規範,更積極地控制這些建議。OemCarDuckingService 已在 Android 14 中推出:

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) 車輛服務的參考實作項目,其中實作 OemCarServiceOemCarAudioFocusServiceOemCarAudioDuckingServiceOemCarAudioVolumeService。在後者中,每項服務都會使用 XML 檔案載入靜態行為。舉例來說,OemCarAudioFocusServiceImp 會載入 oem_focus_config.xml,其中包含互動矩陣。矩陣會在呼叫 evaluateAudioFocusRequest 時用於評估焦點要求。

參考測試應用程式偵錯

原始設備製造商 (OEM) 車用服務測試應用程式是 Android 開放原始碼計畫的原始碼的一部分。原始設備製造商 (OEM) 可以根據需求進行變更。如要進行偵錯,請使用 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 則表示無法使用。