当前位置: 代码迷 >> Android >> Android 的传媒路由功能应用与框架解析
  详细解决方案

Android 的传媒路由功能应用与框架解析

热度:107   发布时间:2016-04-28 04:56:59.0
Android 的媒体路由功能应用与框架解析

一、功能描述

       Android 媒体路由API被设计用来允许多种媒体(视频、音乐、图片)在与ANDROID设备连接(无线或有线)的辅助设备(如电视、立体声、家庭戏院系统、音乐播放机)上显示和播放,使用该框架和API,允许Android用户立即在辅助设备上显示图片、播放音乐、共享视频等。

   媒体路由框架提供两种播放输出类型:远端播放和辅助输出。远端播放类型指的是辅助设备处理媒体内容的接收、解码和回放,而Android设备(如手机)只起远程控制作用,ANDROID应用使用该类型用来支持Google Cast辅助输出类型则是应用本身处理媒体内容(视频或音乐),包括媒体内容的引出和处理,并把处理结果直接呈现和串流到辅助接收设备上,辅助接收设备只是呈现媒体处理后的最终内容,如Android系统中使用该方式用来支持Wireless Display输出。

   如下图是应用使用媒体路由框架播放内容的有关类的高层视图:

 

 

       媒体路由框架用来提供和抽象已连接的媒体辅助输出的逻辑路径。

         媒体应用通过一个MediaRouter对象(媒体路由框架提供的一个对象)来使用媒体路由框架,用来选择媒体路由,并经过媒体路由框架的路由连接到选择的最终接收设备。

       Android系统从4.3版本开始提供了一个媒体路由服务,用来对ANDROID系统自带的本地显示和声音输出设备的路由支持,如speaker、有线耳机、USB耳机,蓝牙A2DP输出、HDMI输出、Wireless Display输出等。这些媒体路由设备被称为框架提供的系统媒体路由。

    对于没有被媒体路由框架支持的媒体播放硬件,可以通过实现一个应用,在此应用中通过使用ANDROID提供的媒体路由支持库v7-mediarouter( v7-mediarouter支持库是版本为V18及以上的Android Support支持库的一部分),继承v7-mediarouter支持库中提供的MediaRouteProviderServiceMediaRouteProvider基类,实现一个继承这些基类的特定MediaRouteProviderService服务和一个针对特定硬件的特定的MediaRouteProvider对象,以此实现对特定媒体播放硬件的路由支持。这种用户实现的媒体路由称为用户媒体路由。

由于v7-mediarouter路由支持库兼容于ANDROID2.1以上的版本,因此可以使用该库在ANDROID2.1以上的系统上开发针对特定媒体播放辅助硬件的媒体路由应用。

        每个辅助设备(除了蓝牙输出设备)为了支持媒体路由必须继承和实现一个特定MediaRouteProvider和创建和实现相关的RouteController对象。

    如以上媒体路由框架视图所示,用户通过MediaRouter对象对媒体路由的选择最终由媒体路由框架传递和路由到选择路由对应的MediaRouteProvider对象,对选择的媒体设备的操作由媒体路由框架转发到MediaRouteProvider对象关联的MediaRouteProvider.RouteController对象,由MediaRouteProvider.RouteController对象完成对媒体设备的实际操作,包括转发应用发送来的媒体播放控制命令或其它请求以及处理实际的与媒体硬件的通讯。

   媒体路由提供方在实现MediaRouteProvider时需要定义一个MediaRouteProviderDescriptor对象和几个MediaRouteProviderDescriptor对象及IntentFilter对象来描述媒体路由设备的路由能力

   对设备中的每一个可路由的媒体硬件,对于其支持的每一个媒体路由类别,需要定义一个IntentFilter对象,并添加到描述该媒体硬件某个路由能力的MediaRouteDescriptor对象中,并把MediaRouteDescriptor对象增加到MediaRouteProviderDescriptor对象中。

二、框架描述

      如下是媒体路由框架内部主要相关类的一个类图。由这些类图中的类具体负责对系统提供的媒体设备和设备厂商提供的媒体设备的媒体播放路由支持。

     

 

    这些类都位于v7-mediarouter支持库中。主要包含如下类:

    一)、  MediaRouter

    该类是用户使用媒体框架的接口类,由该类为用户提供媒体路由操作的API接口。

        MediaRouter主要包含如下API

       1) public static MediaRouter getInstance(Context context)

      应用为了使用媒体路由框架,必须首先调用该接口获得一个MediaRouter对象实例MediaRouter对象内部包含一个全局属性  sGlobal,sGlobal属性维护一个类型为MediaRouter类的一个内部类GlobalMediaRouter的单一实例,用来维护媒体路由的全局状态,MediaRouter对象的实例方法一般都是通过sGlobal来与媒体路由框架交互。该属性必须在MediaRouter对象初始化之前实例化,并只能有一个对象,因此采用了单例模式。

2)  public List<RouteInfo> getRoutes()

获得当前发现的所有媒体路由信息的一个列表,媒体路由框架对于每一个发现的媒体路由都用一个RouteInfo对象表示。一个媒体路由提供设备可能包含多个媒体路由。

3)public List<ProviderInfo> getProviders()

     获得当前发现的媒体路由提供设备的MediaRouteProvider信息的列表,用ProviderInfo对象表示。

4)  public RouteInfo getDefaultRoute()

返回播放媒体内容的系统默认路由,媒体路由框架必须提供一个默认媒体路由。

5)public RouteInfo getSelectedRoute()

返回用户当前选择的媒体路由。该路由也必须存在。

6)  public void  selectRoute(RouteInforoute)

      用来选择特定的路由。

7)  public boolean isRouteAvailable(MediaRouteSelector selector, int flags)

       判断是否存在一个与特定MediaRouteSelector相匹配的媒体路由,如存在则返回True

       MediaRouteSelector用来描述应用希望发现和使用的媒体路由的能力。

8)  public void addCallback(MediaRouteSelector selector, Callback callback)

登记一个具体的MediaRouter.Callback回调对象,并用来启动与特定MediaRouteSelector相匹配的媒体路由的发现,以及监听发现的媒体路由的相关事件,如用户已选择连接到某个媒体路由设备、某个媒体路由设备的特性发生改变或者断开某个媒体路由等事件。

  应用为了使用相关的媒体路由,必须调用该函数来启动媒体路由的发现,并通过登记的回调函数接收相关的事件。

9) public void removeCallback(Callback callback)

       注销先前登记的回调。

10)public void addRemoteControlClient(ObjectremoteControlClient)

增加一个对选择的路由进行音量控制的控制客户端。该控制客户端必须已经使用AudioManager.registerRemoteControlClient方法登记于AudioManager服务中。该接口用于远程控制路由类型。

11)、public void removeRemoteControlClient(Object remoteControlClient)

       注销先前登记的RemoteControlClient对象。

二)MediaRouteProviderMediaRouteProvider. RouteController

     这两个类都是抽象类。MediaRouteProvider及其控制类主要提供如下功能:

    1. MediaRouteProvider的功能是描述和发布接收设备的能力;

    2. MediaRouteProvider. RouteController封装接收设备的编程接口和它的通讯传输机制,以便使设备与媒体框架兼容。

媒体路由框架中提供和实现了MediaRouteProvider类的两个派生类及其控制类:RegisteredMediaRouteProviderRegisteredMediaRouteProvider.ControllerSystemMediaRouteProvider及有关的LegacyImpl.DefaultRouteControllerJellybeanImpl.SystemRouteController控制类,分别对用户添加的媒体路由和系统自带的媒体路由提供支持。

每个非系统提供的辅助设备为了支持媒体路由,必须实现一个专用的MediaRouteProvider类的派生类及其控制类,并通过RegisteredMediaRouteProvider类登记到媒体框架中

每个具体的MediaRouteProvider可能提供对多个媒体路由的支持,对MediaRouteProvider支持的每一个媒体路由需要创建一个独立RouteController对象来与该媒体路由交互。

 每个RouteController对象在具体MediaRouteProvider类的onCreateRouteController函数中创建,onCreateRouteController函数中需要根据媒体路由提供描述中的包含的媒体路由数创建相应的RouteController对象。


三)、媒体路由提供服务(MediaRouteProviderService)

       MediaRouteProviderService类作为一个抽象的service类,用来提供对用户提供的具体MediaRouteProvider类的封装。每一个非系统提供的媒体接收设备要支持媒体路由,在其应用包中必须实现一个MediaRouteProviderService服务的派生类和一个MediaRouteProvider类的特定实现

       MediaRouteProviderService服务的派生类中需要实现MediaRouteProviderService服务的虚函数onCreateMediaRouteProvider,在该函数中实例化特定的MediaRouteProvider类。

    在特定的MediaRouteProvider类的实例化函数中调用其publishRoutes函数来描述和发布要支持的媒体播放硬件的路由能力,以便系统中其它应用能够确定是否能够和如何与之交互。媒体设备路由能力用MediaRouteProviderDescriptor对象描述。

       publishRoutes函数通过调用MediaRouteProvidersetDescriptor函数来发布该MediaRouteProvider支持的媒体设备路由能力

  

四)、RegisteredMediaRouteProviderRegisteredMediaRouteProvider.Controller

 RegisteredMediaRouteProviderMediaRouteProvider类的子类,RegisteredMediaRouteProvider是对媒体路由框架不支持的媒体播放硬件添加路由支持的主要的一个类。

 RegisteredMediaRouteProvider对象和其包含的Controller对象是应用中实现的MediaRouteProvider对象和其对应的RouteController对象在媒体路由框架中的映射,两者存在一一对应关系,两者通过MediaRouteProviderService相联系。

 RegisteredMediaRouteProvider对每一个发现的包含媒体路由提供服务的应用,在媒体路由框架中创建和添加一个RegisteredMediaRouteProvider对象,并通过该对象与应用中的媒体路由提供服务进行绑定。

RegisteredMediaRouteProvider中包含的Controller对象用来把用户对该硬件相应的媒体路由的请求通过与MediaRouteProviderService服务的连接转发到应用提供的媒体路由提供对象和相应的控制器对象。

五)、RegisteredMediaRouteProviderWatcher

 RegisteredMediaRouteProviderWatcher负责监视与扫描安装的应用包,用来发现应用包中包含的媒体路由提供服务。

 对于发现的每一个媒体路由提供服务,RegisteredMediaRouteProviderWatcher除了创建和添加一个RegisteredMediaRouteProvider实例,并调用该实例的相关接口与新发现的媒体路由提供服务绑定,在与媒体路由提供服务绑定时调用媒体路由服务的onCreateMediaRouteProvider函数创建媒体路由提供服务封装的具体的MediaRouteProvider对象。

 还调用GlobalMediaRouter对象的addProvider函数创建相应的RouteInfoProviderInfo对象并添加到媒体路由框架中,用来代表新发现的媒体路由和媒体路由提供者。  

RegisteredMediaRouteProviderWatcherPackageManager交互使用PackageManagerqueryIntentServices接口来扫描安装的应用包。

六)、SystemMediaRouteProvider及其派生类LegacyImplJellybeanImp,LegacyImplJellybeanImp对应的控制类DefaultRouteControllerSystemRouteController。另外还有JellybeanImpl的派生类JellybeanMr1ImplJellybeanMr2Impl。以及相关的关联类MediaRouterJellybeanMediaRouterJellybeanMr1MediaRouterJellybeanMr2

        SystemMediaRouteProviderMediaRouteProvider抽象类的直接派生类。

这些类共同负责对应用提供系统内置的媒体路由功能。这些类通过android.media.MediaRouter接口来查询系统提供的系统媒体路由。

为了支持不同的ANDROID版本,SystemMediaRouteProvider类的这些派生类,用来提供对不同版本的支持。这些类的派生关系如下:

  

        Jellybean以上版本(SDK API版本号为16)对应的具体MediaRouteProvider类为JellybeanImplJellybeanMr1以上的版本(API版本号为17)对应的具体MediaRouteProvider类为JellybeanMr1Impl类,JellybeanMr1版本添加了对辅助显示路由的支持,因此JellybeanMr1Impl类添加了这方面的路由能力,JellybeanMr2以上的版本(API的版本号为18)对应的具体MediaRouteProvider类为JellybeanMr2Impl类,这些MediaRouteProvider类的控制器都是SystemRouteController。 Jellybean以下版本的的具体MediaRouteProvider类为LegacyImpl,其对应的控制器DefaultRouteController

         LegacyImpl的媒体路由只提供音乐类型的媒体播放路由能力,其通过AudioManager与声音服务交互实现声音路由功能。对应的DefaultRouteController控制器对象也是通过AudioManager的API用来设置和更新媒体播放的音量

 Jellybean及以后的版本系统提供了媒体路由服务,并提供了多种类型的媒体路由。为了与系统媒体路由服务的交互并支持不同的版本,v7-mediarouter支持库对不同版本提供了不同的接口类,对应JellybeanMr2版本的MediaRouterJellybeanMr2类,对应JellybeanMr1版本的MediaRouterJellybeanMr1类,以及对应Jellybean版本的MediaRouterJellybean类,这些接口类通过android.media.MediaRouter对象与系统提供的媒体路由服务交互。

由于JellybeanMr1开始提供辅助显示设备的路由支持,因此MediaRouterJellybeanMr1类还提供了与DisplayManager的接口。

七)RemoteControlClientCompat抽象类及其内部具体派生类RemoteControlClientCompat.LegacyImpl   RemoteControlClientCompat.JellybeanImpl

      对于远端播放类型的媒体路由,应用端需要提供一个RemoteControlClient对象用来提供对该种路由类型设备的操作。   RemoteControlClientCompatRemoteControlClient对象通过v7-mediarouter支持库与系统实现交互的包装接口类。RemoteControlClient的派生类RemoteControlClientCompat.LegacyImp用来支持Jellybean以前的版本,目前什么也没有实现。RemoteControlClientCompat.JellybeanImpl则是对Jellybean以后的版本提供支持的具体RemoteControlClientCompat实现。

      RemoteControlClientCompat.JellybeanImpl也是通过MediaRouterJellybean接口类与系统媒体路由交互。

三、主要流程 

      现在来看一下应用使用媒体路由功能的主要系统流程。

3.1 路由的发现

       媒体路由的发现流程通过调用媒体路由支持库中的MediaRouter类的实例函数addCallback来启动。整个流程如下:

3.2媒体路由的选择

       媒体路由的选择通过调用媒体路由支持库中MediaRouter类的实例函数selectRoute函数来启动。整个流程如下:

 


                                              版权所有,转载时请尊重原创清楚注明链接和出处!



  相关解决方案