Media Router
当用户连接他们的电视,家庭影院系统和音乐播放器与无线技术,他们希望能够在这些大型,更响亮的设备从Android应用播放内容。启用这种播放可以把你的一个设备,一个用户的应用程序到一个共享的经验,喜悦和激励多个用户。
Android的媒体路由器的API旨在使这些辅助设备的媒体显示和回放。还有您可以使用使用这些API来播放内容两种主要的方法:
远程回放 - 这种方法使用的接收设备来处理内容的数据检索,解码和回放,同时在用户手中的Android设备被用作遥控器。这种方法是由谷歌支持的Android演员使用的应用程序。
辅助输出 - 通过这种方法,您的应用程序检索,呈现和直接流视频或音乐到接收设备。这种方法被用来支持Android上的无线显示输出。
本指南说明了您的应用程序可以如何提供媒体使用这些方法的执行二次播放设备。
概观
媒体路由器的API支持范围广泛的媒体输出,通过有线和无线方式播放连接到Android设备的设备。为了使这些连接,媒体路由器架构抽象的音频和视频输出Android设备的逻辑路径。这种架构使您的应用程序快速通道媒体内容连接播放设备,如家庭影院和音响系统,提供Android的媒体途径支持。
为了你的应用程序中使用这个框架,你必须得到MediaRouter框架对象的实例,并附加MediaRouter.Callback对象聆听到可用的媒体路线事件。通过媒体路线引导内容经过路线的关联MediaRouteProvider(除少数特殊情况下,诸如蓝牙输出设备)。下图提供了您的应用程序可以用来播放与媒体路由器框架内容类的高级视图。
图1.概述应用使用的主要媒体路由器类。
不是由媒体路由器框架支持的媒体播放硬件的制造商可以添加用于通过实现媒体RouteProvider和分发其作为一个应用程序的设备的支持。有关实现媒体提供者路线的详细信息,请参阅媒体RouteProvider参考文档和V7-mediarouter支持库样本
<sdk>/extras/android/compatibility/v7/mediarouter
.
媒体路由器包
媒体路由器API提供作为Android的支持库版本18和更高的一部分,在V7-mediarouter支持库。具体来说,应该在android.support.v7.media包媒体路由器功能使用类。这些API与运行Android 2.1(API 7级)和较高的设备兼容。
注意:有另一套在已经被取代了V7-mediarouter支持库的android.media提供的媒体路由器的API。你不应该使用android.media类媒体路由器功能。
为了使用android.support.v7.media媒体路由器类,则必须将V7-mediarouter支持库包添加到您的应用程序开发项目。有关添加支持库到你的应用程序开发项目的更多信息,请参阅支持库设置。
铸造用户界面
实现媒体路由器API Android应用应包括投放按钮作为用户界面的一部分,允许用户选择一个媒体路线起到辅助输出设备上的媒体。媒体路由器框架为按钮,你应该用它来帮助用户识别和使用功能,在您的应用程序的标准接口。图2显示了演员按钮应该出现的应用程序。
图2.操作栏的右侧所示的钮扣。
注意:当实现,提供了一个媒体路由器接口必须从Android支持库扩展要么ActionBarActivity或FragmentActivity,即使活动的Android:是的minSdkVersion11 API或更高。
铸按钮
落实演员按钮用户界面的推荐方法是从ActionBarActivity扩展您的活动,并使用onCreateOptionsMenu()方法来添加一个选项菜单。该按钮必须使用MediaRouteActionProvider类作为其行动:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" > <item android:id="@+id/media_route_menu_item" android:title="@string/media_route_menu_title" app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider" app:showAsAction="always" /> </menu>有关在您的应用程序执行操作栏的更多信息,请参阅操作栏开发人员指南。
图3.可用的媒体路线,按演员按钮后显示的列表。
媒体的航线上出现的列表,远程回放,辅助输出或其他人,由您app.You定义的类型通过创建一个MediaRouteSelector,它接受由您创建的框架和其他媒体的路线供应商提供的MediaControlIntent对象定义这些类型或其他开发人员。该框架提供的路线类别如下:
CATEGORY_LIVE_AUDIO - 音频的输出到辅助输出设备,诸如启用无线的音乐系统。
CATEGORY_LIVE_VIDEO - 视频输出到第二输出设备,如无线显示设备。
CATEGORY_REMOTE_PLAYBACK - 播放处理媒体检索,解码和回放,如Chromecast装置一个单独的设备上的视频或音频。
当创建一个MediaRouteSelector对象,请使用MediaRouteSelector.Builder类来创建对象并设置上的媒体播放类别(控制类),如下面的代码示例:
public class MediaRouterPlaybackActivity extends ActionBarActivity { private MediaRouteSelector mSelector; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Create a route selector for the type of routes your app supports. mSelector = new MediaRouteSelector.Builder() // These are the framework-supported intents .addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO) .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO) .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) .build(); } }媒体路由器框架使用这个选择对象来选择你的应用支持,如图3。一旦你定义了这个选择,你将其连接到与演员菜单项关联的MediaRouteActionProvider对象的媒体路线提供了接口,如图所示下面的代码示例:
@Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); // Inflate the menu and configure the media router action provider. getMenuInflater().inflate(R.menu.sample_media_router_menu, menu); // Attach the MediaRouteSelector to the menu item MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider)MenuItemCompat.getActionProvider( mediaRouteMenuItem); mediaRouteActionProvider.setRouteSelector(mSelector); // Return true to show the menu. return true; }一旦你取得了这些更改您的应用程序,你可能期望的演员按钮出现在您的活动。可惜的是,它没有(除非你的设备已经与无线显示配对)。在大多数情况下,还必须与媒体路由框架,这是在下一节讨论连接。
private final MediaRouter.Callback mMediaRouterCallback = new MediaRouter.Callback() { @Override public void onRouteSelected(MediaRouter router, RouteInfo route) { Log.d(TAG, "onRouteSelected: route=" + route); if (route.supportsControlCategory( MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){ // remote playback device updateRemotePlayer(route); } else { // secondary output device updatePresentation(route); } } @Override public void onRouteUnselected(MediaRouter router, RouteInfo route) { Log.d(TAG, "onRouteUnselected: route=" + route); if (route.supportsControlCategory( MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){ // remote playback device updateRemotePlayer(route); } else { // secondary output device updatePresentation(route); } } @Override public void onRoutePresentationDisplayChanged( MediaRouter router, RouteInfo route) { Log.d(TAG, "onRoutePresentationDisplayChanged: route=" + route); if (route.supportsControlCategory( MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){ // remote playback device updateRemotePlayer(route); } else { // secondary output device updatePresentation(route); } } }定义媒体路由器回调对象后,仍然需要将其附加到主媒体路由器框架对象。下一节讨论适当的方式来连接你的回调媒体路线。
public class MediaRouterPlaybackActivity extends ActionBarActivity { private MediaRouter mMediaRouter; private MediaRouteSelector mSelector; private Callback mMediaRouterCallback; // your app works with so the framework can discover them. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Get the media router service. mMediaRouter = MediaRouter.getInstance(this); ... } // Add the callback on start to tell the media router what kinds of routes // your app works with so the framework can discover them. @Override public void onStart() { mMediaRouter.addCallback(mSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); super.onStart(); } // Remove the selector on stop to tell the media router that it no longer // needs to discover routes for your app. @Override public void onStop() { mMediaRouter.removeCallback(mMediaRouterCallback); super.onStop(); } ... }你应该添加,只有在在onStart()和的onStop()生命周期方法去除媒体路由器回调。不包括在onResume()或的onPause()方法,这些调用。
private void updateRemotePlayer(RouteInfo route) { // Changed route: tear down previous client if (mRoute != null && mRemotePlaybackClient != null) { mRemotePlaybackClient.release(); mRemotePlaybackClient = null; } // Save new route mRoute = route; // Attach new playback client mRemotePlaybackClient = new RemotePlaybackClient(this, mRoute); // Send file for playback mRemotePlaybackClient.play(Uri.parse( "http://archive.org/download/Sintel/sintel-2048-stereo_512kb.mp4"), "video/mp4", null, 0, null, new ItemActionCallback() { @Override public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus, String itemId, MediaItemStatus itemStatus) { logStatus("play: succeeded for item " + itemId); } @Override public void onError(String error, int code, Bundle data) { logStatus("play: failed - error:"+ code +" - "+ error); } }); } }该RemotePlaybackClient类提供了管理内容播放的其他方法。这里有几个来自RemotePlaybackClient类的主要方法回放:
public class SamplePresentation extends Presentation { public SamplePresentation(Context outerContext, Display display) { super(outerContext, display); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Notice that we get resources from the context of the Presentation Resources resources = getContext().getResources(); // Inflate a layout. setContentView(R.layout.presentation_with_media_router_content); // Add presentation content here: // Set up a surface view for visual interest mSurfaceView = (GLSurfaceView)findViewById(R.id.surface_view); mSurfaceView.setRenderer(new CubeRenderer(false)); } }创建演示文稿控制器
private void updatePresentation(RouteInfo route) { // Get its Display if a valid route has been selected Display selectedDisplay = null; if (route != null) { selectedDisplay = route.getPresentationDisplay(); } // Dismiss the current presentation if the display has changed or no new // route has been selected if (mPresentation != null && mPresentation.getDisplay() != selectedDisplay) { mPresentation.dismiss(); mPresentation = null; } // Show a new presentation if the previous one has been dismissed and a // route has been selected. if (mPresentation == null && selectedDisplay != null) { // Initialize a new Presentation for the Display mPresentation = new SamplePresentation(this, selectedDisplay); mPresentation.setOnDismissListener( new DialogInterface.OnDismissListener() { // Listen for presentation dismissal and then remove it @Override public void onDismiss(DialogInterface dialog) { if (dialog == mPresentation) { mPresentation = null; } } }); // Try to show the presentation, this might fail if the display has // gone away in the meantime try { mPresentation.show(); } catch (WindowManager.InvalidDisplayException ex) { // Couldn't show presentation - display was already removed mPresentation = null; } } }意:当用户连接到一个无线显示,媒体路由器框架自动提供,它是一个连接的设备上显示屏幕内容的通知。