實施無線電

收音機控制實現基於MediaSessionMediaBrowse ,它們使媒體和語音助手應用程序能夠控制收音機。有關更多信息,請參閱 developer.android.com 上的為汽車構建媒體應用程序

媒體瀏覽樹實現在packages/apps/Car/libs的 car-broadcastradio-support 庫中提供。該庫還包含 ProgramSelector 的擴展,用於與 URI 相互轉換。建議無線電實現使用此庫來構建關聯的瀏覽樹。

媒體源切換器

為了在廣播和媒體中顯示的其他應用程序之間提供無縫轉換,car-media-common 庫包含應集成到廣播應用程序中的類。 MediaAppSelectorWidget可以包含在廣播應用程序的 XML 中(參考媒體和廣播應用程序中使用的圖標和下拉菜單):

<com.android.car.media.common.MediaAppSelectorWidget
     android:id="@+id/app_switch_container"
     android:layout_width="@dimen/app_switch_widget_width"
     android:layout_height="wrap_content"
     android:background="@drawable/app_item_background"
     android:gravity="center" />

此小部件啟動AppSelectionFragment ,它顯示可以切換到的媒體源列表。如果需要提供的 UI 以外的 UI,您可以創建自定義小部件以在應顯示切換器時啟動AppSelectionFragment

AppSelectionFragment newFragment = AppSelectionFragment.create(widget,
            packageName, fullScreen);
    newFragment.show(mActivity.getSupportFragmentManager(), null);

參考無線電應用程序實現中提供了一個示例實現,位於packages/apps/Car/Radio中。

詳細的控制規格

MediaSession (通過MediaSession.Callback )接口為當前播放的廣播節目提供控制機制:

  • onPlayonStop 。 (取消)靜音收音機播放。
  • onPause 。時移暫停(如果支持)。
  • onPlayFromMediaId 。播放頂級文件夾中的任何內容。例如,“播放 FM”或“播放收音機”。
  • onPlayFromUri 。播放特定頻率。例如,“播放 88.5 FM”。
  • onSkipToNext , onSkipToPrevious 。調到下一個或上一個電台。
  • onSetRating 。在收藏夾中添加或刪除。

MediaBrowser 在三種頂級目錄中公開了一個可調的MediaItem

  • 可選程序(站)。這種模式通常由雙調諧器收音機用來指示用戶位置上所有可用的可調諧無線電台。
  • 收藏夾。添加到收藏夾列表的廣播節目,有些可能不可用(超出接收範圍)。
  • 樂隊頻道。當前區域中所有物理上可能的通道(87.9、88.1、88.3、88.5、88.7、88.9、89.1 等)。每個樂隊都有一個單獨的頂級目錄。
MediaBrowserService 樹結構
圖 1. MediaBrowserService 樹結構

每個文件夾 (AM/FM/Programs) 中的每個元素都是一個帶有 URI 的 MediaItem,該 URI 可以與 MediaSession 一起使用來調整。每個頂級文件夾 (AM/FM/Programs) 都是一個帶有 mediaId 的 MediaItem,可以與 MediaSession 一起使用以觸發播放,並由 OEM 自行決定。例如,“播放 FM”、“播放 AM”和“播放收音機”都是使用 mediaId 發送到 OEM 收音機應用的非特定收音機查詢。由廣播應用程序決定從通用請求和 mediaId 播放什麼。

媒體會話

鑑於沒有暫停廣播流的概念,播放、暫停和停止操作並不總是適用於廣播。對於收音機,Stop 動作與靜音流相關,而 Play 與移除靜音相關。

一些收音機調諧器(或應用程序)提供了通過緩存內容然後稍後播放來模擬廣播流暫停的能力。在這種情況下,請使用onPause

從 mediaId 和 URI 操作播放旨在調整到從 MediaBrowser 界面獲取的電台。 mediaId 是廣播應用程序提供的任意字符串,用於強加一個唯一(因此給定 ID 僅指向一個項目)和穩定(因此給定項目在整個會話中具有相同 ID)值,用於識別給定電台. URI 將是一個定義良好的模式。簡而言之,一種 URI 化形式的 ProgramSelector。雖然這保留了唯一性屬性,但它不一定是穩定的,儘管它可以在電台移動到不同頻率時發生變化。

按照設計,不使用onPlayFromSearch 。是客戶端(配套應用程序)從 MediaBrowser 樹中選擇搜索結果的責任。將該責任轉移到無線電應用程序會增加複雜性,需要關於字符串查詢應該如何出現的正式合同,並導致不同硬件平台上的用戶體驗不均衡。

注意:廣播應用程序不包含有助於搜索未通過 MediaBrowser 界面向客戶端公開的電台名稱的附加信息。

跳到下一個或上一個站點取決於當前上下文:

  • 當應用程序從收藏夾列表中調到一個電台時,該應用程序可以從收藏夾列表移到下一個電台。
  • 收聽節目列表中的電台可能會導致調諧到下一個可用電台,根據頻道號排序。
  • 收聽任意頻道可能會導致調諧到下一個物理頻道,即使沒有廣播信號也是如此。

無線電應用程序處理這些操作。

錯誤處理

TransportControls操作(播放、停止和下一步)不提供有關操作是否成功的反饋。指示錯誤的唯一方法是將 MediaSession 狀態設置為STATE_ERROR並帶有錯誤消息。

無線電應用程序必須處理這些操作並執行它們或設置錯誤狀態。如果不是立即執行播放命令,則在執行命令時,應將播放狀態更改為STATE_CONNECTING (在直接調諧的情況下)或STATE_SKIPPING_TO_PREVIOUS / NEXT

客戶端應觀察PlaybackState並驗證會話是否將當前程序更改為請求的內容或進入錯誤狀態。 STATE_CONNECTING不得超過 30 秒。然而,直接調諧到給定的 AM/FM 頻率應該執行得更快。

添加和刪除收藏夾

MediaSession 有評分支持,可以用來控制收藏夾。 onSetRating類型的評分調用RATING_HEART將當前調諧的電台添加到收藏夾列表或從中刪除。

與傳統預設相反,當每個保存的收藏夾分配到一個數字槽(通常為 1 到 6)時,此模型假定一個無序且無界的收藏夾列表。結果,基於預設的系統將與onSetRating操作不兼容。

MediaSession API 的限制是只能添加或刪除當前調諧到的電台。例如,必須先選擇項目,然後才能刪除它們。這只是 MediaBrowser 客戶端的限制,例如配套應用程序。收音機應用程序沒有類似的限制。當應用程序不支持收藏夾時,此部分是可選的。

媒體瀏覽器

為了表達對給定區域有效的頻率或物理頻道名稱(當調諧到適合給定無線電技術的任意頻道時),列出了每個頻段的所有有效頻道(頻率)。在美國地區,這相當於 87.8 到 108.0 MHz 範圍內的 101 個 FM 頻道(使用 0.2MHz 間隔)和 530 到 1700 kHz 範圍內的 117 個 AM 頻道(使用 10kHz 間隔)。由於高清廣播使用相同的頻道空間,因此不單獨介紹。

當前可用的廣播節目列表是平坦的,因為這不允許顯示方案,例如按直接音頻廣播 (DAB) 合奏進行分組。

收藏夾列表中的條目可能無法調整。例如,如果給定程序超出範圍。收音機應用程序可能會或可能不會檢測到該條目是否可以預先調諧。如果是這樣,它可能不會將該條目標記為可播放。

為了識別頂級文件夾,應用了藍牙使用的相同機制。也就是說, MediaDescription對象的 Extras 包包含一個調諧器特定字段,就像藍牙對EXTRA_BT_FOLDER_TYPE所做的那樣。對於廣播電台,這導致在公共 API 中定義以下新字段:

  • EXTRA_BCRADIO_FOLDER_TYPE = "android.media.extra.EXTRA_BCRADIO_FOLDER_TYPE" 。以下值之一:
    • BCRADIO_FOLDER_TYPE_PROGRAMS = 1 。當前可用的程序。
    • BCRADIO_FOLDER_TYPE_FAVORITES = 2 。收藏夾。
    • BCRADIO_FOLDER_TYPE_BAND = 3 。給定頻段的所有物理信道。

    無需定義任何特定於廣播的自定義元數據字段,因為所有相關數據都適合現有的MediaBrowser.MediaItem方案:

    • 程序名稱(RDS PS、DAB 服務名稱)。 MediaDescription.getTitle
    • 調頻頻率。 URI(請參閱ProgramSelector )或MediaDescription.getTitle (如果條目位於BROADCASTRADIO_FOLDER_TYPE_BAND文件夾中)。
    • 無線電特定標識符(RDS PI、DAB SId)。 MediaDescription.getMediaUri解析為 ProgramSelector。

    通常,不需要為當前節目或收藏夾列表中的條目獲取 FM 頻率(因為客戶端應該對媒體 ID 進行操作)。但是,如果出現這種需求(例如,出於顯示目的),它會出現在 URI 中並且可以解析為ProgramSelector 。也就是說,不建議使用 URI 來選擇當前會話中的項目。有關詳細信息,請參閱ProgramSelector

    為避免與性能或活頁夾相關的問題,MediaBrowser 服務必須支持分頁:

    注意:默認情況下,分頁在onLoadChildren()變體中默認實現,沒有選項處理。

    來自所有類型列表(原始頻道、找到的節目和收藏夾)的相關條目可能具有不同的 mediaId(這取決於廣播應用程序;支持庫會有所不同)。大多數情況下,原始頻道和節目的 URI(以 ProgramSelector 形式)會有所不同(不帶 RDS 的 FM 除外);但在找到的程序和收藏的程序之間幾乎相同(例如,當 AF 更新時除外)。

    對來自不同類型列表的條目具有不同的 mediaId 可以對它們採取不同的操作。您可以遍歷onSkipToNext上的收藏夾列表或所有程序列表,具體取決於最近選擇的MediaItem的文件夾(請參閱MediaSession )。

    特殊調音動作

    節目列表允許用戶調到特定的電台,但不允許用戶提出諸如“調到 FM”之類的一般請求,這可能導致調到 FM 波段上最近收聽的電台。

    為支持此類操作,一些頂級目錄設置了FLAG_PLAYABLE標誌(以及用於文件夾的FLAG_BROWSABLE )。

    行動調到如何發行
    播放電台任何無線電頻道startService(ACTION_PLAY_BROADCASTRADIO)
    playFromMediaId(MediaBrowser. getRoot() )
    播放調頻任何 FM 頻道從 FM 頻段的 mediaId 播放

    調諧到哪個程序取決於應用程序。這通常是給定列表中最近調諧到的頻道。有關ACTION_PLAY_BROADCASTRADIO的詳細信息,請參閱一般播放意圖

    發現和服務連接

    PackageManager 可以直接找到 MediaBrowserService 服務廣播電台樹。為此,請使用ACTION_PLAY_BROADCASTRADIO意圖(請參閱通用播放意圖)和MATCH_SYSTEM_ONLY標誌調用resolveService 。要查找所有服務於無線電的服務(可能不止一項,例如單獨的 AM/FM 和衛星),請使用queryIntentServices

    解析的服務也將處理android.media.browse.MediaBrowserService綁定意圖。這已通過 GTS 驗證。

    要連接到選定的 MediaBrowserService,請為給定的服務組件創建MediaBrowser實例並connect 。建立連接後,可以通過getSessionToken獲取 MediaSession 的句柄。

    Radio 應用程序可以限制允許在其服務的onGetRoot實現中連接的客戶端包。該應用程序應該允許系統應用程序在沒有白名單的情況下進行連接。白名單的詳細信息,請參見接受助手應用包和簽名

    如果源特定的應用程序(例如,收音機應用程序)安裝在沒有此類源支持的設備上,它仍會宣傳自己處理ACTION_PLAY_BROADCASTRADIO意圖,但其 MediaBrowser 樹不​​會包含特定於收音機的標籤。因此,願意檢查給定源是否在設備上可用的客戶端必須:

    1. 發現無線電服務(為ACTION_PLAY_BROADCASTRADIO調用resolveService )。
    2. 為其創建MediaBrowser ,然後連接到它。
    3. 使用額外的MediaItem EXTRA_BCRADIO_FOLDER_TYPE

    注意:在大多數情況下,客戶端必須掃描所有可用的 MediaBrowser 樹以檢測給定設備的所有可用源。

    樂隊名稱

    樂隊列表由一組頂級目錄表示,其中文件夾類型標記設置為BCRADIO_FOLDER_TYPE_BAND 。他們的MediaItem的標題是代表樂隊名稱的本地化字符串。在大多數情況下,它與英文翻譯相同,但客戶不能依賴該假設。

    為了提供查找某些波段的穩定機制,為波段文件夾添加了一個額外的標籤: EXTRA_BCRADIO_BAND_NAME_EN 。這是樂隊的非本地化名稱,只能採用以下預定義值之一:

    • AM
    • FM
    • DAB
    • SXM

    如果樂隊不在此列表中,則不應設置樂隊名稱標籤。但是,如果樂隊在列表中,它必須有一個標籤集。高清廣播沒有列舉單獨的頻段,因為它使用與 AM/FM 相同的底層媒體。

    一般遊戲意圖

    每個專用於播放給定源(如收音機或 CD)的應用程序必須處理一般播放意圖,以開始播放可能從非活動狀態(例如,啟動後)的某些內容。如何選擇播放內容取決於應用程序,但通常是最近播放的廣播節目或 CD 曲目。
    為每個音頻源定義了一個單獨的意圖:

    • android.car.intent.action.PLAY_BROADCASTRADIO
    • android.car.intent.action.PLAY_AUDIOCD : CD-DA 或 CD-Text
    • android.car.intent.action.PLAY_DATADISC : 像 CD/DVD 一樣的光數據光盤,但不是 CD-DA(可能是混合模式 CD)
    • android.car.intent.action.PLAY_AUX :不指定哪個 AUX 端口
    • android.car.intent.action.PLAY_BLUETOOTH
    • android.car.intent.action.PLAY_USB :不指定哪個USB設備
    • android.car.intent.action.PLAY_LOCAL :本地媒體存儲(內置閃存)

    選擇 Intent 用於通用播放命令,因為它們同時解決了兩個問題:通用播放命令本身和服務發現。擁有這種意圖的額外好處是可以在不打開 MediaBrowser 會話的情況下執行這種簡單的操作。

    服務發現實際上是通過這些意圖解決的更重要的問題。通過這種方式,服務發現的過程既簡單又明確(請參閱發現和服務連接)。

    為了使某些客戶端實現更容易,有另一種發出此類播放命令的方法(也必須由廣播應用程序實現):發出帶有根節點的playFromMediaId的 playFromMediaId(用作 mediaId)。雖然根節點不是可播放的,但它的 rootId 是一個任意字符串,可以作為 mediaId 使用。但是,客戶不需要了解這種細微差別。

    程序選擇器

    雖然 mediaId 足以從 MediaBrowserService 中選擇一個頻道,但它會綁定到一個會話並且在提供者之間不一致。在某些情況下,客戶端可能需要一個絕對指針(例如絕對頻率)來在會話和設備之間維護它。

    在數字無線電廣播時代,光頻率不足以調諧到特定電台。因此,請使用ProgramSelector調諧到模擬或數字頻道。 ProgramSelector由兩部分組成:

    • 主要標識符。給定廣播電台的唯一且穩定的標識符,不會更改但可能不足以調諧到該電台。例如,RDS PI 代碼,在美國可能會被翻譯成呼號。
    • 次要標識符。用於調諧到該電台的附加標識符(例如頻率),可能包括來自其他無線電技術的標識符。例如,DAB 台可能具有模擬廣播後備。

    要使 ProgramSelector 適合基於 MediaBrowser/MediaSession 的解決方案,請定義一個 URI 模式以對其進行序列化。架構定義如下:

    broadcastradio://program/<primary ID type>/<primary ID>?
    <secondary ID type>=<secondary ID>&<secondary ID type>=<secondary ID>
    

    在此示例中,輔助標識符部分(在問號 ( ? ) 之後)是可選的,可以刪除以提供用作mediaId的穩定標識符。例如:

    • broadcastradio://program/RDS_PI/1234?
      AMFM_FREQUENCY=88500&AMFM_FREQUENCY=103300
    • broadcastradio://program/AMFM_FREQUENCY/102100
    • broadcastradio://program/DAB_SID_EXT/14895264?RDS_PI=1234

    程序的權限部分(又名主機)為以後的program擴展提供了一定的空間。標識符類型字符串在IdentifierType的 HAL 2.x 定義中精確指定為它們的名稱,值格式是十進製或十六進制(帶0x前綴)數字。

    所有供應商特定的標識符都由VENDOR_前綴表示。例如, VENDOR_0代表VENDOR_STARTVENDOR_1代表VENDOR_START + 1 。此類 URI 特定於生成它們的無線電硬件,不能在不同 OEM 製造的設備之間傳輸。

    這些 URI 必須分配給頂級單選文件夾下的每個 MediaItem。此外,MediaSession 必須同時支持playFromMediaIdplayFromUri 。但是,URI 主要用於無線電元數據提取(例如 FM 頻率)和持久存儲。無法保證 URI 可用於所有媒體項(例如,當框架尚不支持主要 ID 類型時)。另一方面,媒體 ID 始終有效。不建議客戶端使用 URI 從當前 MediaBrowser 會話中選擇項目。相反,請使用playFromMediaId 。也就是說,服務應用程序不是可選的,缺少的 URI 是為有充分理由的情況保留的。

    最初的設計在方案部分之後使用了一個冒號而不是://序列。但是,對於絕對分層 URI 引用, android.net.Uri不支持前者。

    其他來源類型

    可以類似地處理其他音頻源。例如,輔助輸入和音頻 CD 播放器。

    單個應用程序可以服務於多種類型的源。在這種情況下,建議您為每種類型的源創建單獨的 MediaBrowserService。即使在具有多個服務源/MediaBrowserServices 的設置中,強烈建議在單個應用程序中使用單個 MediaSession。

    音頻光盤

    與音頻 CD 類似,為此類磁盤提供服務的應用程序將使用單個可瀏覽條目(或更多,如果系統具有 CD 更換器)公開 MediaBrowser,該條目又將包含給定 CD 的所有軌道。如果系統不知道每張 CD 上的軌道(例如,當所有磁盤一次插入盒式磁帶並且它沒有全部讀取它們時),那麼整個磁盤的 MediaItem 將只是PLAYABLE ,而不是BROWSABLE+PLAYABLE 。如果給定插槽中沒有磁盤,則該項目既不能PLAYABLE也不能BROWSABLE (但每個插槽必須始終存在於樹中)。

    音頻 CD 樹結構
    圖 2.音頻 CD 樹結構

    這些條目的標記方式與廣播電台文件夾的標記方式相似——它們將包含 MediaDescription API 中定義的額外字段:

    • EXTRA_CD_TRACK :對於音頻 CD 上的每個MediaItem ,基於 1 的軌道號。
    • EXTRA_CD_DISK :基於 1 的磁盤編號。

    對於啟用 CD-Text 的系統和兼容磁盤,頂級 MediaItem 將具有磁盤的標題。同樣,曲目的 MediaItems 將具有曲目的標題。

    輔助輸入

    提供輔助輸入的應用程序公開了一個 MediaBrowser 樹,其中有一個條目(或多個,當存在多個端口時)表示端口中的 AUX。相應的 MediaSession 獲取其 mediaId 並在獲得playFromMediaId請求後切換到該源。

    輔助樹結構
    圖 3. AUX 樹結構

    每個 AUX MediaItem 條目都會有一個額外的字段EXTRA_AUX_PORT_NAME設置為端口的非本地化名稱,不帶“AUX”短語。例如,“AUX 1”將設置為“1”,“AUX front”設置為“front”,“AUX”設置為空字符串。在非英語語言環境中,名稱標籤將保持相同的英語字符串。不太可能與EXTRA_BCRADIO_BAND_NAME_EN ,這些值是 OEM 定義的,並且不受預定義列表的限制。

    如果硬件可以檢測到連接到 AUX 端口的設備,則硬件應將 MediaItem 標記為PLAYABLE ,僅當輸入連接時。如果沒有任何連接到此端口,則仍應枚舉硬件(但不是PLAYABLE )。如果硬件沒有這種能力,則 MediaItem 必須始終設置為PLAYABLE

    額外字段

    因此,必須定義以下額外鍵:

    • EXTRA_CD_TRACK = "android.media.extra.CD_TRACK"
    • EXTRA_CD_DISK = "android.media.extra.CD_DISK"
    • EXTRA_AUX_PORT_NAME = "android.media.extra.AUX_PORT_NAME"

    客戶需要查看頂級 MediaItem 中設置了EXTRA_CD_DISKEXTRA_AUX_PORT_NAME額外字段的元素。

    詳細示例

    以下示例解決了作為此設計一部分的源類型的 MediaBrowser 樹結構。

    廣播電台 MediaBrowserService(處理ACTION_PLAY_BROADCASTRADIO ):

    • 車站(可瀏覽)
      EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_PROGRAMS
      • 英國廣播公司一號(可播放)
        URI: broadcastradio://program/RDS_PI/1234?AMFM_FREQUENCY=90500
      • ABC 88.1(可播放)
        URI: broadcastradio://program/RDS_PI/5678?AMFM_FREQUENCY=88100
      • ABC 88.1 HD1(可播放)
        URI: broadcastradio://program/HD_STATION_ID_EXT/158241DEADBEEF?AMFM_FREQUENCY=88100&RDS_PI=5678
      • ABC 88.1 HD2(可播放)
        URI: broadcastradio://program/HD_STATION_ID_EXT/158242DEADBEFE
      • 90.5 FM(可播放)——沒有 RDS 的 FM
        URI: broadcastradio://program/AMFM_FREQUENCY/90500
      • 620 AM(可播放)
        URI: broadcastradio://program/AMFM_FREQUENCY/620
      • 英國廣播公司一號(可播放)
        URI: broadcastradio://program/DAB_SID_EXT/1E24102?RDS_PI=1234
    • 收藏夾(可瀏覽、可播放)
      EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_FAVORITES
      • 英國廣播公司一號(可播放)
        URI: broadcastradio://program/RDS_PI/1234?AMFM_FREQUENCY=101300
      • BBC 2 台(不可播放)
        URI: broadcastradio://program/RDS_PI/1300?AMFM_FREQUENCY=102100
    • AM(可瀏覽、可播放)
      EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BAND
      EXTRA_BCRADIO_BAND_NAME_EN="AM"
      • 530 AM(可播放)
        URI: broadcastradio://program/AMFM_FREQUENCY/530
      • 540 AM(可播放)
        URI: broadcastradio://program/AMFM_FREQUENCY/540
      • 550 AM(可播放)
        URI: broadcastradio://program/AMFM_FREQUENCY/550
    • FM(可瀏覽、可播放)
      EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BAND
      EXTRA_BCRADIO_BAND_NAME_EN="FM"
      • 87.7 FM(可播放)
        URI: broadcastradio://program/AMFM_FREQUENCY/87700
      • 87.9 FM(可播放)
        URI: broadcastradio://program/AMFM_FREQUENCY/87900
      • 88.1 FM(可播放)
        URI: broadcastradio://program/AMFM_FREQUENCY/88100
    • DAB(可播放)
      EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BAND
      EXTRA_BCRADIO_BAND_NAME_EN="DAB"

    音頻 CD MediaBrowserService(處理ACTION_PLAY_AUDIOCD ):

    • 光盤 1(可播放)
      EXTRA_CD_DISK=1
    • 光盤 2(可瀏覽、可播放)
      EXTRA_CD_DISK=2
      • 曲目 1(可播放)
        EXTRA_CD_TRACK=1
      • 曲目 2(可播放)
        EXTRA_CD_TRACK=2
    • 我的音樂 CD(可瀏覽、可播放)
      EXTRA_CD_DISK=3
      • 獨自一人(可玩)
        EXTRA_CD_TRACK=1
      • Reise,Reise(可玩)
        EXTRA_CD_TRACK=2
    • 空槽 4(不可玩)
      EXTRA_CD_DISK=4

    AUX MediaBrowserService(處理ACTION_PLAY_AUX ):

    • AUX 前置(可播放)
      EXTRA_AUX_PORT_NAME="front"
    • AUX 後方(可播放)
      EXTRA_AUX_PORT_NAME="rear"