电台控制实现基于 MediaSession
和
MediaBrowse
,媒体和语音助理应用:
控制无线装置如需了解详情,请参阅
在 developer.android.com 上构建车载媒体应用。
car-broadcastradio-support 中提供了媒体浏览树实现。
packages/apps/Car/libs
中的库。此库还包含
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" />
此 widget 会启动 AppSelectionFragment
,后者会显示一个
可切换到的媒体来源列表。如果需要其他界面
您可以创建自定义小部件,在调用AppSelectionFragment
切换器。
AppSelectionFragment newFragment = AppSelectionFragment.create(widget, packageName, fullScreen); newFragment.show(mActivity.getSupportFragmentManager(), null);
参考电台应用实现中提供了一个实现示例,
位于 packages/apps/Car/Radio
。
详细的控制规范
MediaSession
(通过 MediaSession.Callback
)
接口为当前正在播放的电台节目提供了控制机制:
onPlay
、onStop
。将电台播放(取消)静音。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 等)。每个频段都有一个单独的顶层目录。
每个文件夹 (AM/FM/Programs) 中的每个元素都是一个 MediaItem,具有可用于 来调整 MediaSession每个顶级文件夹 (AM/FM/Programs) 都是一个 MediaItem,其 mediaId 符合 可与 MediaSession 搭配使用以触发播放,具体由 OEM 自行决定。对于 例如,“播放 FM”“播放 AM”以及“播放电台”都是使用 要发送到 OEM 电台应用的 mediaId。从电台应用播放什么内容由电台应用决定 通用请求和 mediaId。
MediaSession
由于还没有暂停广播流的概念,因此播放、暂停和停止操作 并不总是适用于电台使用电台时,“停止”操作与将直播静音 而 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 客户端的限制,例如 配套应用。电台应用没有类似的限制。此部分为可选内容 当应用不支持收藏夹时。
MediaBrowser
为了表示哪些频率或实体频道名称(调谐时 适用于给定无线电技术的任意频道)均适用于 则会列出每个频段的所有有效信道(频率)。 在美国地区,这相当于有 101 个 FM 频道,范围为 87.8 到 87.8 108.0 MHz 范围(使用 0.2MHz 间隔)和 117 AM 信道,在 530 范围内 1700 kHz(间隔为 10 kHz)。HD 电台使用相同的信道空间 不会单独显示。
当前可播放的电台节目列表是空的,不允许播放 显示架构,例如按直接音频广播 (DAB) 集成分组。
“收藏夹”列表中的条目可能无法正常播放。例如,如果给定的 程序超出了范围。电台应用不一定能检测该条目 可以预先调整到在这种情况下,电台应用可能不会将条目标记为可播放。
为了识别顶级文件夹,系统会采用与蓝牙相同的机制。
也就是说,
MediaDescription
的 Extra 捆绑包
对象包含调谐器专用字段,就像蓝牙处理
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
。 - FM 频率。URI(请参阅
ProgramSelector)或
MediaDescription.getTitle
(如果条目位于BROADCASTRADIO_FOLDER_TYPE_BAND
文件夹中)。 - 电台专属标识符(RDS PI,DAB SId)。
MediaDescription.getMediaUri
解析到 ProgramSelector。
通常,无需针对 当前节目或收藏夹列表(因为客户端应在媒体上操作) ID)。不过,如果出现此类需求(例如,出于展示目的), 存在于 URI 中,并且可以解析为
ProgramSelector
。 尽管如此,我们不建议您使用 URI 在当前所选内容中选择项目 会话。有关详情,请参阅ProgramSelector
。为避免发生与性能或 binder 相关的问题,MediaBrowser 服务必须支持分页:
注意:默认情况下,在
onLoadChildren()
变体。所有类型列表(原始频道、已找到的节目和 收藏)可能具有不同的 mediaId(由电台应用决定;支持 会有所不同)。URI(采用 ProgramSelector 形式) 原始频道与大多数情况下找到的节目之间有什么区别(FM 除外) 但找到的节目和收藏的节目之间大致相同(除了 例如,在更新广告资源预测时)。
为来自不同类型列表的条目使用不同的 mediaId 会导致 可以对其执行不同的操作。您可以遍历收藏列表或
onSkipToNext
上的“所有程序”列表,具体取决于 已选择MediaItem
(请参阅 MediaSession)。特殊调谐操作
节目列表可让用户调到特定电台,但不允许用户 发出一些一般性请求(例如“调到 FM”),这可能会导致调谐到 收听 FM 频段的电台。
为了支持此类操作,部分顶层目录包含
FLAG_PLAYABLE
标志设置(以及FLAG_BROWSABLE
) 表示文件夹)。操作 调谐目标 如何发出 播放电台 任意电台频道 startService(ACTION_PLAY_BROADCASTRADIO)
或
playFromMediaId(MediaBrowser.getRoot())
播放 FM 任意 FM 频道 从 FM 频段的 mediaId
播放具体调到哪个节目由应用决定。这是 通常是指定列表中最近调到的频道。如需详细了解
ACTION_PLAY_BROADCASTRADIO
,参见 常规播放 intent。发现和服务连接
PackageManager
可以直接找到提供广播电台的 MediaBrowserService 树。为此,请调用resolveService
以及ACTION_PLAY_BROADCASTRADIO
intent(请参阅 常规播放 intent)和MATCH_SYSTEM_ONLY
标志。查找所有提供电台的服务 可能会不止一个;例如单独的 AM/FM 和卫星),请使用queryIntentServices
。已解析的服务处理
android.media.browse.MediaBrowserService
绑定 意图。此操作已通过 GTS 验证。如需连接到所选的 MediaBrowserService, 创建 给定服务组件的
MediaBrowser
实例和connect
。 建立连接后,可以通过getSessionToken
。电台应用可以限制允许在
onGetRoot
服务的实现应用应允许系统应用进行连接 而无需列入白名单如需详细了解白名单,请参阅 接受 Google 助理应用软件包和签名。如果特定于来源的应用(例如,电台应用)安装在 设备,则仍会通告自己处理
ACTION_PLAY_BROADCASTRADIO
intent,但其 MediaBrowser 树 不包含电台专用标记。因此,客户端愿意检查给定的 来源在设备上可用,必须:- 探索电台服务(为以下号码调用
resolveService
:ACTION_PLAY_BROADCASTRADIO
)。 - 创建
MediaBrowser
,然后与其连接。 - 通过
EXTRA_BCRADIO_FOLDER_TYPE
确定是否存在MediaItem
extra。
注意 :在大多数情况下,客户端必须扫描所有 可用的 MediaBrowser 树,以检测给定设备的所有可用来源。
频段名称
频段列表由一组具有文件夹类型的顶层目录表示 代码设为
BCRADIO_FOLDER_TYPE_BAND
。对方的MediaItem
title 是表示频段名称的本地化字符串。在大多数情况下 这与英语翻译相同,但客户不能依赖这种假设。为了提供一种稳定的机制来查找特定频段, 为频段文件夹添加了额外的标记
EXTRA_BCRADIO_BAND_NAME_EN
。这是 乐队的非本地化名称,并且只能采用以下某个预定义值:AM
FM
DAB
如果频段不在此列表中,则不应设置频段名称标记。 但是,如果频段在列表中,则必须设置标记。HD 电台不能 列举单独的频段,因为它使用与 AM/FM 相同的底层媒介。
常规播放 intent
每个专用于播放指定来源(如电台或 CD)的应用都必须处理 常规 play intent 开始播放一些内容,可能是 处于非活跃状态(例如,启动后)。至于如何选择内容 但通常是最近播放过的电台节目或 CD 曲目 intent:
android.car.intent.action.PLAY_BROADCASTRADIO
android.car.intent.action.PLAY_AUDIOCD
:CD-DA 或 CD-Textandroid.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
:本地媒体存储空间 (内置 Flash)
之所以选择将 intent 用于常规播放命令,是因为它们解决 同时解决两个问题:常规的播放命令本身和服务发现。 拥有此类意图的另一个好处是, 无需打开 MediaBrowser 会话的简单操作。
服务发现实际上是通过这些服务来解决的 intent。通过这种方式,服务发现的过程简单且明确(请参阅 发现和服务连接)。
为了简化某些客户端实现,有一种替代方法 发出此类“播放”命令(该命令也必须由电台应用实现): 发出
playFromMediaId
并传入根节点的 rootId(用作 mediaId)。虽然 根节点 并非为可播放,其 rootId 是任意字符串 它可作为 mediaId 使用。不过,客户端不是必需的 来理解这种细微差别。ProgramSelector
虽然使用
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_START
,VENDOR_1
xVENDOR_START
+ 1。此类 URI 仅适用于 生成它们的无线电硬件,不能在设备之间传输 不同原始设备制造商 (OEM) 制造的产品。必须将这些 URI 分配给顶级电台下的每个 MediaItem 文件夹中。此外,MediaSession 必须同时支持
playFromMediaId
和playFromUri
。不过,URI 主要用于电台 元数据提取(例如 FM 频率)和永久性存储。没有任何 可以保证 URI 可用于所有媒体项(例如,当主 ID 类型不受框架支持)。另一方面,媒体 ID 始终有效。 不建议客户端使用 URI 从 当前 MediaBrowser 会话触发。相反,应使用playFromMediaId
。也就是说, 对于服务应用而言不是可选的,并且保留缺失的 URI 以用于合理情形。最初的设计使用一个冒号来代替
://
序列 。不过,Google Cloud 不支持android.net.Uri
,适用于绝对分层 URI 引用。其他来源类型
其他音频来源也可以通过类似方式处理。例如,辅助输入和 音频 CD 播放器。
单个应用可以提供多种类型的来源。在这种情况下, 建议为 每种类型的来源即使在具有多个提供的来源/MediaBrowserService 的设置中, 强烈建议在单个 应用。
音频 CD
与音频 CD 类似,提供此类磁盘的应用 公开具有单个可浏览条目(或多个,如果系统具有 CD 换碟机),而该 CD 会反过来包含指定 CD 的所有曲目。如果系统 并不了解每张 CD 上的曲目(例如,当所有磁盘 但未能读取所有墨盒的内容) 整个磁盘的 MediaItem 将只是
PLAYABLE
,而不是BROWSABLE
+PLAYABLE
。如果整个集群中没有磁盘 给定的广告位,则商品既不是PLAYABLE
,也不是BROWSABLE
(但每个广告位必须始终存在于树中)。这些条目的标记方式与广播电台文件夹类似 是;它们会包含 MediaDescription API 中定义的其他 extra 字段:
EXTRA_CD_TRACK
:对于音频 CD 上的每个MediaItem
, 从 1 开始的曲目编号。EXTRA_CD_DISK
:从 1 开始的磁盘编号。
对于支持 CD-Text 的系统和兼容磁盘,顶级 MediaItem 将 包含磁盘标题同样,曲目的 MediaItem 将包含 曲目的标题。
辅助输入
提供辅助输入的应用公开了具有单个(或多个 表示端口中的 AUX)。相应的 MediaSession 将获取其 mediaId,并在收到
playFromMediaId
请求后切换到该来源。每个 AUX MediaItem 条目都有一个额外的字段
EXTRA_AUX_PORT_NAME
设置为端口的非本地化名称 没有“AUX”词组。例如:“AUX 1”应设置为“1”、“AUX” 前”移至“前端”和“AUX”一个空字符串。在非英语语言区域,名称为 则使用同一个英文字符串。对于EXTRA_BCRADIO_BAND_NAME_EN
,值由 OEM 定义,而非 预定义的列表如果硬件可以检测到连接到 AUX 端口的设备,则硬件应标记 作为
PLAYABLE
的 MediaItem。硬件应 如果没有任何连接,则仍会枚举(而非PLAYABLE
) 端口。如果硬件没有此类功能,则 MediaItem 必须始终设置为PLAYABLE
。extra 字段
定义以下字段:
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_DISK
或EXTRA_AUX_PORT_NAME
个额外字段 。详细示例
以下示例说明了 。
广播电台 MediaBrowserService(处理
ACTION_PLAY_BROADCASTRADIO
):- 电台(可浏览)
EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_PROGRAMS
- BBC One(可播放)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
- BBC One(可播放)URI:
broadcastradio://program/DAB_SID_EXT/1E24102?RDS_PI=1234
- BBC One(可播放)URI:
- 收藏夹(可浏览、可播放)
EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_FAVORITES
- BBC One(可播放)URI:
broadcastradio://program/RDS_PI/1234?AMFM_FREQUENCY=101300
- BBC Two(不可播放)URI:
broadcastradio://program/RDS_PI/1300?AMFM_FREQUENCY=102100
- BBC One(可播放)URI:
- AM(可浏览、可播放):
EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BANDEXTRA_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
- 530 AM(可播放)URI:
- FM(可浏览、可播放):
EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BANDEXTRA_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
- 87.7 FM(可播放)URI:
- DAB(可播放):
EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BANDEXTRA_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
- 曲目 1(可播放)
- 我的音乐 CD(可浏览、可播放)
EXTRA_CD_DISK=3
- All By Myself(可播放)
EXTRA_CD_TRACK=1
- Reise,Reise(可播放)
EXTRA_CD_TRACK=2
- All By Myself(可播放)
- 空槽位 4(不可播放)
EXTRA_CD_DISK=4
AUX MediaBrowserService(处理
ACTION_PLAY_AUX
):- AUX front(可播放)
EXTRA_AUX_PORT_NAME="front"
- AUX rear(可播放)
EXTRA_AUX_PORT_NAME="rear"