| page.title=Media Route Provider |
| page.tags="mediarouteprovider","mediacontrolintent" |
| @jd:body |
| |
| <div id="qv-wrapper"> |
| <div id="qv"> |
| <h2>In this document</h2> |
| <ol> |
| <li><a href="#overview">Overview</a> |
| <ol> |
| <li><a href="#dist">Distribution of route providers</a></li> |
| <li><a href="#playback-types">Types of playback</a></li> |
| <li><a href="#mr-packages">Media router packages</a></li> |
| </ol> |
| </li> |
| <li><a href="#provider-service">Creating a Provider Service</a></li> |
| <li><a href="#route-caps">Specifying Route Capabilities</a> |
| <ol> |
| <li><a href="#route-cat">Route categories</a></li> |
| <li><a href="#media-types">Media types and protocols</a></li> |
| <li><a href="#playback-ctrls">Playback controls</a></li> |
| <li><a href="#mrpd">MediaRouteProviderDescriptor</a></li> |
| </ol> |
| </li> |
| <li><a href="#ctrl-routes">Controlling Routes</a></li> |
| </ol> |
| <h2>Key Classes</h2> |
| <ol> |
| <li>{@link android.support.v7.media.MediaRouteProvider}</li> |
| <li>{@link android.support.v7.media.MediaRouteProviderDescriptor}</li> |
| <li>{@link android.support.v7.media.MediaRouteProvider.RouteController RouteController}</li> |
| </ol> |
| <h2>Related Samples</h2> |
| <ol> |
| <li><a href="{@docRoot}samples/MediaRouter/index.html">MediaRouter</a></li> |
| </ol> |
| </div> |
| </div> |
| |
| <p>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.</p> |
| |
| <p>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.</p> |
| |
| <p>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.</p> |
| |
| <h2 id="overview">Overview</h2> |
| |
| <p>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.</p> |
| |
| <img src="{@docRoot}images/mediarouter/media-route-provider-framework.png" alt="" id="figure1"/> |
| <p class="img-caption"> |
| <strong>Figure 1.</strong> Overview of how media route provider classes provide communication |
| from a media app to a receiver device. |
| </p> |
| |
| <p>When you build a media route provider for your receiver device, the provider serves the |
| following purposes:</p> |
| |
| <ul> |
| <li>Describe and publish the capabilities of the receiver device so other apps can discover it |
| and use its playback features.</li> |
| <li>Wrap the programming interface of the receiver device and its communication |
| transport mechanisms to make the device compatible with the media router framework.</li> |
| </ul> |
| |
| |
| <h3 id="dist">Distribution of route providers</h3> |
| |
| <p>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.</p> |
| |
| <p> |
| <strong>Note:</strong> The app containing the media route provider can also include a |
| <a href="{@docRoot}guide/topics/media/mediarouter.html">MediaRouter</a> interface to the |
| route provider, but this is not required. |
| </p> |
| |
| |
| <h3 id="playback-types">Types of playback</h3> |
| |
| <p>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:</p> |
| |
| <ul> |
| <li><strong>Remote Playback</strong> — This approach uses the receiver device to handle the |
| content data retrieval, decoding, and playback, while an Android device in the user's hand is |
| used as a remote control. This approach is used by Android apps that support |
| <a href="https://developers.google.com/cast/">Google Cast</a>.</li> |
| <li><strong>Secondary Output</strong> — With this approach, the Android media application |
| retrieves, renders and streams video or music directly to the receiver device. This approach is |
| used to support Wireless Display output on Android.</li> |
| </ul> |
| |
| |
| <h3 id="mr-packages">Media router packages</h3> |
| |
| <p> |
| The media router APIs are provided as part of the Android Support Library version 18 and higher, |
| in the <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter">v7-mediarouter</a> |
| 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. |
| </p> |
| |
| <p class="caution"> |
| <strong>Caution:</strong> There is another set of media router APIs provided in the |
| {@link android.media} class package that have been superseded by the |
| <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter">v7-mediarouter</a> |
| support library. You <em>should not</em> use the {@link android.media} classes for |
| implementing media route provider functions. |
| </p> |
| |
| <p>In order to use the {@link android.support.v7.media} media router classes, you |
| must add the <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter" |
| >v7-mediarouter support library package</a> to your app development project. For more |
| information on adding support libraries to your app development project, see |
| <a href="{@docRoot}tools/support-library/setup.html">Support Library Setup</a>. |
| </p> |
| |
| |
| <h2 id="provider-service">Creating a Provider Service</h2> |
| |
| <p>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}.</p> |
| |
| <p>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:</p> |
| |
| <pre> |
| <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> |
| </pre> |
| |
| <p>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:</p> |
| |
| <pre> |
| public class SampleMediaRouteProviderService extends MediaRouteProviderService { |
| |
| @Override |
| public MediaRouteProvider onCreateMediaRouteProvider() { |
| return new SampleMediaRouteProvider(this); |
| } |
| } |
| </pre> |
| |
| |
| <h2 id="route-caps">Specifying Route Capabilities</h2> |
| |
| <p>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.</p> |
| |
| <p>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.</p> |
| |
| |
| <h3 id="route-cat">Route categories</h3> |
| |
| <p>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:</p> |
| |
| <ul> |
| <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_LIVE_AUDIO CATEGORY_LIVE_AUDIO} |
| — Output of audio to a secondary output device, such as a wireless-enabled music system. |
| </li> |
| <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_LIVE_VIDEO CATEGORY_LIVE_VIDEO} |
| — Output of video to a secondary output device, such as Wireless Display devices.</li> |
| <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_REMOTE_PLAYBACK |
| CATEGORY_REMOTE_PLAYBACK} — Play video or audio on a separate device which handles media |
| retrieval, decoding, and playback, such as |
| <a href="https://www.google.com/url?q=http://www.google.com/chromecast">Chromecast</a> devices. |
| </li> |
| </ul> |
| |
| <p>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:</p> |
| |
| <pre> |
| public final class SampleMediaRouteProvider extends MediaRouteProvider { |
| private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC; |
| static { |
| IntentFilter videoPlayback = new IntentFilter(); |
| <strong>videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);</strong> |
| CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>(); |
| CONTROL_FILTERS_BASIC.add(videoPlayback); |
| } |
| } |
| |
| </pre> |
| |
| <p>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.</p> |
| |
| |
| <h3 id="media-types">Media types and protocols</h3> |
| |
| <p>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):</p> |
| |
| <pre> |
| 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); |
| } |
| } |
| } |
| |
| </pre> |
| |
| |
| <h3 id="playback-ctrls">Playback controls</h3> |
| |
| <p>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:</p> |
| |
| <ul> |
| <li><strong>Playback controls</strong>, such as play, pause, rewind, and fast-forward.</li> |
| <li><strong>Queuing features</strong>, which allow the sending app to add and remove items |
| from a playlist which is maintained by the receiver device.</li> |
| <li><strong>Session features</strong>, which prevent sending apps from interfering with each |
| other by having the receiver device provide a session id to the requesting app and then checking |
| that id with each subsequent playback control request.</li> |
| </ul> |
| |
| <p>The following code example demonstrates how to construct an intent filter for supporting |
| basic media route playback controls:</p> |
| |
| <pre> |
| 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); |
| } |
| ... |
| } |
| </pre> |
| |
| <p>For more information about the available playback control intents, see the |
| {@link android.support.v7.media.MediaControlIntent} class.</p> |
| |
| |
| <h3 id="mrpd">MediaRouteProviderDescriptor</h3> |
| |
| <p>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.</p> |
| |
| <p>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:</p> |
| |
| <pre> |
| 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); |
| } |
| </pre> |
| |
| <p>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}.</p> |
| |
| |
| <h2 id="ctrl-routes">Controlling Routes</h2> |
| |
| <p>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.</p> |
| |
| <p>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:</p> |
| |
| <ul> |
| <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onSelect onSelect()} |
| — Called when an application selects your route for playback. You use this method to do |
| any preparation work that may be required before media playback begins.</li> |
| <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onControlRequest |
| onControlRequest()} — Sends specific playback commands to the receiving device.</li> |
| <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onSetVolume |
| onSetVolume()} — Sends a request to the receiving device to set the playback volume to a |
| specific value.</li> |
| <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onUpdateVolume |
| onUpdateVolume()} — Sends a request to the receiving device to modify the playback |
| volume by a specified amount.</li> |
| <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onUnselect |
| onUnselect()} — Called when an application unselects a route.</li> |
| <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onRelease onRelease()} |
| — Called when the route is no longer needed by the framework, allowing it to free its |
| resources.</li> |
| </ul> |
| |
| <p>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:</p> |
| |
| <pre> |
| 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; |
| } |
| ... |
| } |
| </pre> |
| |
| <p>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.</p> |