Bootstrap

Android MediaBrowser 各组件使用概览

一,前期基础知识储备

如何快速开发一款音频应用?基于已有的合作应用进行开发,比如百度的车载Carlife系统对QQ音乐,喜马拉雅等的调用。 音乐应用被第三方的Android app打开,并获取其中的歌单,曲目列表,同时控制其播放。

百度CarLife-百度旗下手机智能连接车机产品| 富百科软件站

Spotify - 一家在线音乐流服务平台,和其合作的厂商也是采用这种实现方式,官方SDK说明如下:

The Spotify SDK allows your application to interact with the Spotify app running in the background as a service. The capabilities of this API include getting metadata for the currently playing track and context, issuing basic playback commands and initiating playback of tracks.

合作方开发一个客户端应用,与作为服务端的Spotify进行交互,获取播放条目,并控制播放状态。

通俗一点,就是自己开发一个应用,作为一个进程,Spotify播放器是一个应用,作为一个进程,然后通过客户端/服务器设计,实现一个进程控制另一个进程的播放状态。

Spotify Android SDK

这种实现方式就是使用Android中的MediaBrowser与MediaBrowserService,Android官方文档

音频 Activity 和 BrowserService

MediaBrowserService 提供两个主要功能:

  1. 当您使用 MediaBrowserService 时,具有 MediaBrowser 的其他组件和应用可以发现您的服务,创建自己的媒体控制器,连接到您的媒体会话,并控制播放器。Wear OS 和 Android Auto 应用才得以访问您的媒体应用。
  2. 此外,它还提供了一个可选的 Browsing API。应用可以不使用此功能。通过 Browsing API,客户端可以查询服务并构建其内容层次结构的表示,这可能表示播放列表、媒体库或其他类型的集合。

Android Media Hacks

二,上代码,具体实现

Client需要创建MediaBrowser,Server需要实现MediaBrowserService,在建⽴连接后,两端之间的交互主要通过MediaController和MediaSession。两个类之间通过预先定义的callback进⾏交互,
MediaSession控制着播放器的播放,MediaController来控制着UI的变化。

实现具体分三步:

1. 构建媒体浏览器服务
说明了如何创建包含媒体会话的媒体浏览器服务,管理客户端连接以及在播放音频时成为前台服务。
2. 构建媒体浏览器客户端
说明了如何创建包含界面和媒体控制器的媒体浏览器客户端 Activity,以及如何与媒体浏览器服务进行连接和通信。
3. 媒体会话回调
说明了媒体会话回调方法如何管理媒体会话、媒体浏览器服务以及其他应用组件(如通知和广播接收器)。

1. 构建媒体浏览器服务

该步骤通常在播放器内部实现,客户端不必关注,客户端只需调用创建好的服务即可。

1)声明Service

必须在其清单中声明带有 Intent 过滤器的 MediaBrowserService。

    <service android:name=".MediaPlaybackService">
      <intent-filter>
        <action android:name="android.media.browse.MediaBrowserService" />
      </intent-filter>
    </service>

2)初始化媒体会话
当服务收到 onCreate() 生命周期回调方法时,它应该执行以下步骤:

  • 创建并初始化媒体会话
  • 设置媒体会话回调
  • 设置媒体会话令牌

3)管理客户端连接
MediaBrowserService 有两个方法来处理客户端连接:onGetRoot() 控制对服务的访问,onLoadChildren() 使客户端能够构建和显示 内容层次结构菜单。

2. 构建媒体浏览器客户端

  • 说明了如何创建包含界面和媒体控制器的媒体浏览器客户端 Activity

  • 以及如何与媒体浏览器服务进行连接和通信。

要完成客户端/服务器设计,您必须构建包含界面代码、关联的 MediaController 和 MediaBrowser 的 Activity 组件。

MediaBrowser 执行两项重要功能:

  • 连接到 MediaBrowserService;

  • 并在连接后为您的界面创建 MediaController。

1)连接到 MediaBrowserService

创建客户端 Activity 后,它会连接到 MediaBrowserService。这里涉及一点握手和跳跃。修改 Activity 的生命周期回调,如下所示:

  • onCreate() 构造 MediaBrowserCompat。传入 MediaBrowserService 的名称和已定义的 MediaBrowserCompat.ConnectionCallback

  • onStart() 连接到 MediaBrowserService。这里体现了 MediaBrowserCompat.ConnectionCallback 的神奇之处。如果连接成功,onConnect() 回调会创建媒体控制器,将其链接到媒体会话,将您的界面控件链接到 MediaController,并注册控制器以接收来自媒体会话的回调。

  • onResume() 设置音频流,以便您的应用响应设备上的音量控制。

  • onStop() 断开 MediaBrowser 的连接,并在 Activity 停止时取消注册 MediaController.Callback。

2)自定义 MediaBrowserCompat.ConnectionCallback

当您的 Activity 构造 MediaBrowserCompat 时,您必须创建 ConnectionCallback 的实例。修改其 onConnected() 方法以从 MediaBrowserService 检索媒体会话令牌,并使用该令牌创建 MediaControllerCompat

    private void connectToSession(MediaSessionCompat.Token token) throws RemoteException {
        // MediaSessionCompat 与 MediaControllerCompat 关联
        mMediaController = new MediaControllerCompat(mContext, token);
        // 音频变化监听
        mMediaController.registerCallback(mMediaControllerCallback);
        // 获取TransportControls 执行play pause next pre操作
        mTransportControls = mMediaController.getTransportControls();
        MediaMetadataCompat metadata = mMediaController.getMetadata();
        PlaybackStateCompat pbState = mediaController.getPlaybackState();
    }

3)将界面连接到媒体控制器

MediaControllerCompat.TransportControls mTransportControls;
mTransportControls = mMediaController.getTransportControls();

TransportControls 方法向服务的媒体会话发送回调。确保为每个控件定义了相应的 MediaSessionCompat.Callback 方法。

4)与媒体会话保持同步

界面应显示媒体会话的当前状态(通过其 PlaybackState 和元数据来描述)。
要在媒体会话的状态或元数据每次发生更改时从媒体会话接收回调,请使用以下两种方法定义
 

媒体控制器,在客户端中开发者不仅可以使用控制器向Service中的媒体会话发送指令,还可以通过设置MediaControllerCompat.Callback回调方法接收媒体会话的状态,从而根据相应的状态刷新界面UI。MediaController的创建需要媒体会话的配对令牌,因此需在浏览器成功连接服务的回调执行创建的操作。

3. 媒体会话回调

您的媒体会话回调调用多个 API 中的方法来控制播放器,管理音频焦点以及与媒体会话和媒体浏览器服务通信。请注意,响应回调的 MediaSession 逻辑必须保持一致。回调的行为不得依赖于调用方的身份,该调用方可能是运行 MediaSession 的同一应用中的 Activity,也可能是任何其他带有已连接到 MediaSession 的 MediaController 应用中的 Activity。

    MediaSessionCompat.Callback callback = new
        MediaSessionCompat.Callback() {
            @Override
            public void onPlay() {}
            public void onStop() {}
            public void onPause() {}
			public void onSkipToNext(){}
			public void onSkipToPrevious()
			public void onSeekTo(long pos) {}
			public void onFastForward(){}
			public void onRewind(){}
			public void onSetRepeatMode(int repeatMode)
			... ...
        };

通过设置MediaSessionCompat.Callback回调来接收媒体控制器MediaController发送的指令。当收到指令时会触发Callback中各个指令对应的回调方法(回调方法中会执行播放器相应的操作,如播放、暂停等)。

最后总结一下:

使用的关键类:

  •  MediaBrowserServiceCompat 媒体浏览器服务
  •  MediaBrowserCompat 媒体浏览器
  •  MediaControllerCompat 媒体控制器
  •  MediaSessionCompat 媒体会话

关键流程梳理:

  1. MediaBrowserServiceCompat继承自Service,为运行在后台的音频服务;
  2. MediaBrowserCompat 运行于前台,通过MediaSessionCompat与MediaBrowserServiceCompat建立连接,从而获取到一个MediaControllerCompat用于控制前台音频播放;
  3. MediaControllerCompat UI界面控制音频播放进度、播放速度、上一曲、下一曲音频播放等等;
  4. MediaSessionCompat - 运行于后台的MediaBrowserServiceCompat与运行于前台的MediaBrowserCompat通过MediaSessionCompat来建立连接;
  5. MediaSessionCompat.Callback 用户通过MediaControllerCompat对UI的操作,会通过MediaSessionCompat.Callback 回调到Service端,来操纵“播放器”进行播放、暂停、快进、上一曲、下一曲等操作;
  6. MediaControllerCompat.Callback Service端播放器播放完成、播放下一曲等操作,通过MediaControllerCompat.Callback回调到UI页面,操纵UI的变化。

官方项目示例:android-MediaBrowserService

一个MediaBrowser开源项目 Android_MediaBrowser_Demo -可以验证上述播放流程

参考文章:

MediaBrowserCompat MediaBrowserServiceCompat

Android 媒体播放框架MediaSession分析与实践

Android基于MediaBroswerService的App实现概述

;