From 55b38fadd0d815450a3461f143c525429ab6b0f5 Mon Sep 17 00:00:00 2001
From: Joe Fernandez Users want to play media content from their Android devices bigger, brighter, and louder on
+ connected playback devices such as televisions, stereos,
+ and home theater equipment. As a manufacturer of these devices, allowing Android users to
+ instantly show a picture, play a song, or share a video for friends and family using your product
+ can make it much more compelling and engaging. The Android media router framework allows manufacturers to enable playback on their devices
+ through a standardized interface called a {@link android.support.v7.media.MediaRouteProvider}.
+ A route provider defines a common interface for playing media on a receiver device, making it
+ possible to play media on your equipment from any Android application that supports media
+ routes. This guide discusses how to create a media route provider for a receiver device and make it
+ available to other media playback applications that run on Android. The Android media router framework enables media app developers and media playback device
+ manufacturers to connect through a common API and common user interface. App developers that
+ implement a {@link android.support.v7.media.MediaRouter} interface can then connect to the
+ framework and play content to devices that participate in the media router framework. Media
+ playback device manufacturers can participate in the framework by publishing a {@link
+ android.support.v7.media.MediaRouteProvider} that allows other applications to connect to and
+ play media on the receiver devices. Figure 1 illustrates how an app connects to a receiving
+ device through the media router framework.
+ Figure 1. Overview of how media route provider classes provide communication
+ from a media app to a receiver device.
+ When you build a media route provider for your receiver device, the provider serves the
+following purposes: A media route provider is distributed as part of an Android app. Your route provider can be
+ made available to other apps by extending
+ {@link android.support.v7.media.MediaRouteProviderService} or wrapping your implementation of
+ {@link android.support.v7.media.MediaRouteProvider} with your own service and declaring an intent
+ filter for the media route provider. These steps allow other apps to discover and make use of
+ your media route.
+ Note: The app containing the media route provider can also include a
+ MediaRouter interface to the
+ route provider, but this is not required.
+ There are two main types of playback supported by the media router framework. A media route
+ provider can support one or both types of playback, depending on the capabilities of your playback
+ equipment and the functionality you want to support:
+ The media router APIs are provided as part of the Android Support Library version 18 and higher,
+ in the v7-mediarouter
+ support library. You should use the classes in the
+ {@link android.support.v7.media} package for media route provider functions.
+ These APIs are compatible with devices running Android 2.1 (API level 7) and higher.
+
+ Caution: There is another set of media router APIs provided in the
+ {@link android.media} class package that have been superseded by the
+ v7-mediarouter
+ support library. You should not use the {@link android.media} classes for
+ implementing media route provider functions.
+ In order to use the {@link android.support.v7.media} media router classes, you
+ must add the v7-mediarouter support library package to your app development project. For more
+ information on adding support libraries to your app development project, see
+ Support Library Setup.
+ The media router framework must be able to discover and connect to your media route provider
+ to allow other applications to use your route. In order to do this, the media router framework
+ looks for apps that declare a media route provider intent action. When another app wants to
+ connect to your provider, the framework must be able to invoke and connect to it, so your provider
+ must be encapsulated in a {@link android.app.Service}. The following example code shows the declaration of a media route provider service and the
+ intent filter in a manifest, which allows it to be discovered and used by the media router
+ framework: This manifest example declares a service that wraps the actual media route provider classes.
+ The Android media router framework provides the
+ {@link android.support.v7.media.MediaRouteProviderService} class for use as a service wrapper for
+ media route providers. The following example code demonstrates how to use this wrapper
+ class: Apps connecting to the media router framework can discover your media route through your
+ app's manifest declarations, but they also need to know the capabilities of the media routes you
+ are providing. Media routes can be of different types and have different features, and other apps
+ need to be able to discover these details to determine if they are compatible with your route. The media router framework allows you to define and publish the capabilities of your media
+ route through {@link android.content.IntentFilter} objects, {@link
+ android.support.v7.media.MediaRouteDescriptor} objects and a {@link
+ android.support.v7.media.MediaRouteProviderDescriptor}. This section explains how to use these
+ classes to publish the details of your media route for other apps. As part of the programmatic description of your media route provider, you must specify
+ whether your provider supports remote playback, secondary output, or both. These are the route
+ categories provided by the media router framework: In order to include these settings in a description of your media route, you insert them into
+ an {@link android.content.IntentFilter} object, which you later add to a
+ {@link android.support.v7.media.MediaRouteDescriptor} object: If you specify the {@link android.support.v7.media.MediaControlIntent#CATEGORY_REMOTE_PLAYBACK
+ CATEGORY_REMOTE_PLAYBACK} intent, you must also define what media types and
+ playback controls are supported by your media route provider. The next section describes how to
+ specify these settings for your device. A media route provider for a remote playback device must specify the media types and transfer
+ protocols it supports. You specify these settings using the {@link android.content.IntentFilter}
+ class and the {@link android.content.IntentFilter#addDataScheme addDataScheme()} and
+ {@link android.content.IntentFilter#addDataType addDataType()} methods of that object. The
+ following code snippet demonstrates how to define an intent filter for supporting remote video
+ playback using http, https, and Real Time Streaming Protocol (RTSP): A media route provider that offers remote playback must specify the types of media controls
+ it supports. These are the general types of control that media routes can provide: The following code example demonstrates how to construct an intent filter for supporting
+ basic media route playback controls: For more information about the available playback control intents, see the
+ {@link android.support.v7.media.MediaControlIntent} class. After defining the capabilities of your media route using {@link
+ android.content.IntentFilter} objects, you can then create a descriptor object for publishing to
+ the Android media router framework. This descriptor object contains the specifics of your media
+ route's capabilities so that other applications can determine how to interact with your media
+ route. The following example code demonstrates how to add the previously created intent filters to a
+ {@link android.support.v7.media.MediaRouteProviderDescriptor} and set the descriptor for use by
+ the media router framework: For more information on the available descriptor settings, see the reference documentation
+ for {@link android.support.v7.media.MediaRouteDescriptor} and {@link
+ android.support.v7.media.MediaRouteProviderDescriptor}. When an application connects to your media route provider, the provider receives playback
+ commands through the media router framework sent to your route by other apps. To handle these
+ requests, you must provide an implementation of a {@link
+ android.support.v7.media.MediaRouteProvider.RouteController} class, which processes the commands
+ and handles the actual communication to your receiver device. The media router framework calls the {@link
+ android.support.v7.media.MediaRouteProvider#onCreateRouteController onCreateRouteController()}
+ method of your route provider to obtain an instance of this class and then routes requests to it.
+ These are the key methods of the {@link
+ android.support.v7.media.MediaRouteProvider.RouteController} class, which you must implement for
+ your media route provider: All playback control requests, except for volume changes, are directed to the {@link
+ android.support.v7.media.MediaRouteProvider.RouteController#onControlRequest onControlRequest()}
+ method. Your implementation of this method must parse the control requests and respond to them
+ appropriately. Here is an example implementation of this method which processes commands for a
+ remote playback media route: It is important to understand that the {@link
+ android.support.v7.media.MediaRouteProvider.RouteController} class is intended to act as a wrapper
+ for the API to your media playback equipment. The implementation of the methods in this class is
+ entirely dependent on the programmatic interface provided by your receiving device.In this document
+
+
+ Key Classes
+
+
+ Related Samples
+
+
+ Overview
+
+
+
+
+
+
+Distribution of route providers
+
+Types of playback
+
+
+
+
+
+Media router packages
+
+Creating a Provider Service
+
+
+<service android:name=".provider.SampleMediaRouteProviderService"
+ android:label="@string/sample_media_route_provider_service"
+ android:process=":mrp">
+ <intent-filter>
+ <action android:name="android.media.MediaRouteProviderService" />
+ </intent-filter>
+</service>
+
+
+
+public class SampleMediaRouteProviderService extends MediaRouteProviderService {
+
+ @Override
+ public MediaRouteProvider onCreateMediaRouteProvider() {
+ return new SampleMediaRouteProvider(this);
+ }
+}
+
+
+
+Specifying Route Capabilities
+
+Route categories
+
+
+
+
+
+public final class SampleMediaRouteProvider extends MediaRouteProvider {
+ private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC;
+ static {
+ IntentFilter videoPlayback = new IntentFilter();
+ videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
+ CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>();
+ CONTROL_FILTERS_BASIC.add(videoPlayback);
+ }
+}
+
+
+
+Media types and protocols
+
+
+public final class SampleMediaRouteProvider extends MediaRouteProvider {
+
+ private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC;
+
+ static {
+ IntentFilter videoPlayback = new IntentFilter();
+ videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
+ videoPlayback.addAction(MediaControlIntent.ACTION_PLAY);
+ videoPlayback.addDataScheme("http");
+ videoPlayback.addDataScheme("https");
+ videoPlayback.addDataScheme("rtsp");
+ addDataTypeUnchecked(videoPlayback, "video/*");
+ CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>();
+ CONTROL_FILTERS_BASIC.add(videoPlayback);
+ }
+ ...
+
+ private static void addDataTypeUnchecked(IntentFilter filter, String type) {
+ try {
+ filter.addDataType(type);
+ } catch (MalformedMimeTypeException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+}
+
+
+
+
+Playback controls
+
+
+
+
+
+public final class SampleMediaRouteProvider extends MediaRouteProvider {
+ private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC;
+ static {
+ ...
+ IntentFilter playControls = new IntentFilter();
+ playControls.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
+ playControls.addAction(MediaControlIntent.ACTION_SEEK);
+ playControls.addAction(MediaControlIntent.ACTION_GET_STATUS);
+ playControls.addAction(MediaControlIntent.ACTION_PAUSE);
+ playControls.addAction(MediaControlIntent.ACTION_RESUME);
+ playControls.addAction(MediaControlIntent.ACTION_STOP);
+ CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>();
+ CONTROL_FILTERS_BASIC.add(videoPlayback);
+ CONTROL_FILTERS_BASIC.add(playControls);
+ }
+ ...
+}
+
+
+MediaRouteProviderDescriptor
+
+
+public SampleMediaRouteProvider(Context context) {
+ super(context);
+ publishRoutes();
+}
+
+private void publishRoutes() {
+ Resources r = getContext().getResources();
+ // Create a route descriptor using previously created IntentFilters
+ MediaRouteDescriptor routeDescriptor = new MediaRouteDescriptor.Builder(
+ VARIABLE_VOLUME_BASIC_ROUTE_ID,
+ r.getString(R.string.variable_volume_basic_route_name))
+ .setDescription(r.getString(R.string.sample_route_description))
+ .addControlFilters(CONTROL_FILTERS_BASIC)
+ .setPlaybackStream(AudioManager.STREAM_MUSIC)
+ .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
+ .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
+ .setVolumeMax(VOLUME_MAX)
+ .setVolume(mVolume)
+ .build();
+ // Add the route descriptor to the provider descriptor
+ MediaRouteProviderDescriptor providerDescriptor =
+ new MediaRouteProviderDescriptor.Builder()
+ .addRoute(routeDescriptor)
+ .build();
+
+ // Publish the descriptor to the framework
+ setDescriptor(providerDescriptor);
+}
+
+
+Controlling Routes
+
+
+
+
+
+private final class SampleRouteController extends
+ MediaRouteProvider.RouteController {
+ ...
+
+ @Override
+ public boolean onControlRequest(Intent intent, ControlRequestCallback callback) {
+
+ String action = intent.getAction();
+
+ if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
+ boolean success = false;
+ if (action.equals(MediaControlIntent.ACTION_PLAY)) {
+ success = handlePlay(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_ENQUEUE)) {
+ success = handleEnqueue(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_REMOVE)) {
+ success = handleRemove(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_SEEK)) {
+ success = handleSeek(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_GET_STATUS)) {
+ success = handleGetStatus(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_PAUSE)) {
+ success = handlePause(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_RESUME)) {
+ success = handleResume(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_STOP)) {
+ success = handleStop(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_START_SESSION)) {
+ success = handleStartSession(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_GET_SESSION_STATUS)) {
+ success = handleGetSessionStatus(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_END_SESSION)) {
+ success = handleEndSession(intent, callback);
+ }
+
+ Log.d(TAG, mSessionManager.toString());
+ return success;
+ }
+ return false;
+ }
+ ...
+}
+
+
+Related Samples
+
+
- Note: There is another set of media router APIs provided in the +
+ Caution: There is another set of media router APIs provided in the {@link android.media} that have been superseded by the v7-mediarouter support library. You should not use the {@link android.media} classes for media router functions.
In order to use the {@link android.support.v7.media} media router classes, you must add the v7-mediarouter - support library package to your app development project. + support library package to your app development project. For more + information on adding support libraries to your app development project, see + Support Library Setup.
@@ -211,9 +217,9 @@ page.tags="cast","chromecast","wireless display","miracast" CATEGORY_LIVE_VIDEO} — Output of video to a secondary output device, such as Wireless Display devices.In order to connect to a media route selected by the user, your app must obtain the {@link android.support.v7.media.MediaRouter} framework object and then attach a {@link android.support.v7.media.MediaRouter.Callback} object. The callback object receives messages - from the media router framework when a route selected, changed or disconnected by the user.
+ from the media router framework when a route is selected, changed, or disconnected by the user.To obtain an instance of the {@link android.support.v7.media.MediaRouter} framework object, call {@link android.support.v7.media.MediaRouter#getInstance MediaRouter.getInstance()} @@ -299,11 +305,11 @@ public boolean onCreateOptionsMenu(Menu menu) {
The media router framework communicates with an app through a callback object that you attach to the {@link android.support.v7.media.MediaRouter} framework object. An app that uses the media router framework must extend the {@link - android.support.v7.media.MediaRouter.Callback} object to receive messages when a media route is - connected and provide content to the connected device through that route.
+ android.support.v7.media.MediaRouter.Callback} object in order to receive messages when a + media route is connected. -There are several methods in the callback that can be overwritten to receive messages about - media router events. At the minimum, your implementation of the {@link +
There are several methods in the callback that you can override to receive information about + media router events. At minimum, your implementation of the {@link android.support.v7.media.MediaRouter.Callback} class should override the following methods:
@@ -440,12 +446,12 @@ public class MediaRouterPlaybackActivity extends ActionBarActivity {Note: The media route framework also provides a - {@link android.support.v7.app.MediaRouteDiscoveryFragment} class which takes care of adding and - removing the call back for an activity. + {@link android.support.v7.app.MediaRouteDiscoveryFragment} class, which takes care of adding and + removing the callback for an activity.
Now when you run your application, you should see a Cast button appear in your activity. - When you press the button the media router framework, a route selection dialog appears as shown + When you touch the button, a route selection dialog appears as shown in figure 3, allowing your user to select an available media route. Make sure you have a supported device available on your local network when testing this interface.
diff --git a/docs/html/images/mediarouter/media-route-provider-framework.png b/docs/html/images/mediarouter/media-route-provider-framework.png new file mode 100644 index 000000000000..60cc29a35325 Binary files /dev/null and b/docs/html/images/mediarouter/media-route-provider-framework.png differ diff --git a/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._data.plist b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._data.plist new file mode 100644 index 000000000000..d82ea050f0c0 Binary files /dev/null and b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._data.plist differ diff --git a/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._image1.png b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._image1.png new file mode 100644 index 000000000000..3435e35bbff4 Binary files /dev/null and b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._image1.png differ diff --git a/docs/image_sources/mediarouter/media-route-provider-framework.graffle/data.plist b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/data.plist new file mode 100644 index 000000000000..07791df4a0ed Binary files /dev/null and b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/data.plist differ diff --git a/docs/image_sources/mediarouter/media-route-provider-framework.graffle/image1.png b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/image1.png new file mode 100644 index 000000000000..d6e3e9591212 Binary files /dev/null and b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/image1.png differ diff --git a/docs/image_sources/mediarouter/media-router-framework.graffle/data.plist b/docs/image_sources/mediarouter/media-router-framework.graffle/data.plist new file mode 100644 index 000000000000..ffd82121845b Binary files /dev/null and b/docs/image_sources/mediarouter/media-router-framework.graffle/data.plist differ diff --git a/docs/image_sources/mediarouter/media-router-framework.graffle/image1.png b/docs/image_sources/mediarouter/media-router-framework.graffle/image1.png new file mode 100644 index 000000000000..d6e3e9591212 Binary files /dev/null and b/docs/image_sources/mediarouter/media-router-framework.graffle/image1.png differ -- cgit v1.2.3-59-g8ed1b