Home | History | Annotate | Download | only in media
      1 page.title=Media Route Provider
      2 page.tags="mediarouteprovider","mediacontrolintent"
      3 @jd:body
      4 
      5 <div id="qv-wrapper">
      6   <div id="qv">
      7     <h2>In this document</h2>
      8     <ol>
      9       <li><a href="#overview">Overview</a>
     10         <ol>
     11           <li><a href="#dist">Distribution of route providers</a></li>
     12           <li><a href="#playback-types">Types of playback</a></li>
     13           <li><a href="#mr-packages">Media router packages</a></li>
     14         </ol>
     15       </li>
     16       <li><a href="#provider-service">Creating a Provider Service</a></li>
     17       <li><a href="#route-caps">Specifying Route Capabilities</a>
     18         <ol>
     19           <li><a href="#route-cat">Route categories</a></li>
     20           <li><a href="#media-types">Media types and protocols</a></li>
     21           <li><a href="#playback-ctrls">Playback controls</a></li>
     22           <li><a href="#mrpd">MediaRouteProviderDescriptor</a></li>
     23         </ol>
     24       </li>
     25       <li><a href="#ctrl-routes">Controlling Routes</a></li>
     26     </ol>
     27     <h2>Key Classes</h2>
     28     <ol>
     29       <li>{@link android.support.v7.media.MediaRouteProvider}</li>
     30       <li>{@link android.support.v7.media.MediaRouteProviderDescriptor}</li>
     31       <li>{@link android.support.v7.media.MediaRouteProvider.RouteController RouteController}</li>
     32     </ol>
     33     <h2>Related Samples</h2>
     34     <ol>
     35       <li><a href="{@docRoot}samples/MediaRouter/index.html">MediaRouter</a></li>
     36     </ol>
     37   </div>
     38 </div>
     39 
     40 <p>Users want to play media content from their Android devices bigger, brighter, and louder on
     41   connected playback devices such as televisions, stereos,
     42   and home theater equipment. As a manufacturer of these devices, allowing Android users to
     43   instantly show a picture, play a song, or share a video for friends and family using your product
     44   can make it much more compelling and engaging.</p>
     45 
     46 <p>The Android media router framework allows manufacturers to enable playback on their devices
     47   through a standardized interface called a {@link android.support.v7.media.MediaRouteProvider}.
     48   A route provider defines a common interface for playing media on a receiver device, making it
     49   possible to play media on your equipment from any Android application that supports media
     50   routes.</p>
     51 
     52 <p>This guide discusses how to create a media route provider for a receiver device and make it
     53   available to other media playback applications that run on Android.</p>
     54 
     55 <h2 id="overview">Overview</h2>
     56 
     57 <p>The Android media router framework enables media app developers and media playback device
     58   manufacturers to connect through a common API and common user interface. App developers that
     59   implement a {@link android.support.v7.media.MediaRouter} interface can then connect to the
     60   framework and play content to devices that participate in the media router framework. Media
     61   playback device manufacturers can participate in the framework by publishing a {@link
     62   android.support.v7.media.MediaRouteProvider} that allows other applications to connect to and
     63   play media on the receiver devices. Figure 1 illustrates how an app connects to a receiving
     64   device through the media router framework.</p>
     65 
     66 <img src="{@docRoot}images/mediarouter/media-route-provider-framework.png" alt="" id="figure1"/>
     67 <p class="img-caption">
     68   <strong>Figure 1.</strong> Overview of how media route provider classes provide communication
     69   from a media app to a receiver device.
     70 </p>
     71 
     72 <p>When you build a media route provider for your receiver device, the provider serves the
     73 following purposes:</p>
     74 
     75 <ul>
     76   <li>Describe and publish the capabilities of the receiver device so other apps can discover it
     77     and use its playback features.</li>
     78   <li>Wrap the programming interface of the receiver device and its communication
     79     transport mechanisms to make the device compatible with the media router framework.</li>
     80 </ul>
     81 
     82 
     83 <h3 id="dist">Distribution of route providers</h3>
     84 
     85 <p>A media route provider is distributed as part of an Android app. Your route provider can be
     86   made available to other apps by extending
     87   {@link android.support.v7.media.MediaRouteProviderService} or wrapping your implementation of
     88   {@link android.support.v7.media.MediaRouteProvider} with your own service and declaring an intent
     89   filter for the media route provider. These steps allow other apps to discover and make use of
     90   your media route.</p>
     91 
     92 <p>
     93   <strong>Note:</strong> The app containing the media route provider can also include a
     94   <a href="{@docRoot}guide/topics/media/mediarouter.html">MediaRouter</a> interface to the
     95   route provider, but this is not required.
     96 </p>
     97 
     98 
     99 <h3 id="playback-types">Types of playback</h3>
    100 
    101 <p>There are two main types of playback supported by the media router framework. A media route
    102   provider can support one or both types of playback, depending on the capabilities of your playback
    103   equipment and the functionality you want to support:</p>
    104 
    105 <ul>
    106   <li><strong>Remote Playback</strong>  This approach uses the receiver device to handle the
    107     content data retrieval, decoding, and playback, while an Android device in the user's hand is
    108     used as a remote control. This approach is used by Android apps that support
    109     <a href="https://developers.google.com/cast/">Google Cast</a>.</li>
    110   <li><strong>Secondary Output</strong>  With this approach, the Android media application
    111     retrieves, renders and streams video or music directly to the receiver device. This approach is
    112     used to support Wireless Display output on Android.</li>
    113 </ul>
    114 
    115 
    116 <h3 id="mr-packages">Media router packages</h3>
    117 
    118 <p>
    119   The media router APIs are provided as part of the Android Support Library version 18 and higher,
    120   in the <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter">v7-mediarouter</a>
    121   support library. You should use the classes in the
    122   {@link android.support.v7.media} package for media route provider functions.
    123   These APIs are compatible with devices running Android 2.1 (API level 7) and higher.
    124 </p>
    125 
    126 <p class="caution">
    127   <strong>Caution:</strong> There is another set of media router APIs provided in the
    128   {@link android.media} class package that have been superseded by the
    129   <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter">v7-mediarouter</a>
    130   support library. You <em>should not</em> use the {@link android.media} classes for
    131   implementing media route provider functions.
    132 </p>
    133 
    134 <p>In order to use the {@link android.support.v7.media} media router classes, you
    135   must add the <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter"
    136   >v7-mediarouter support library package</a> to your app development project. For more
    137   information on adding support libraries to your app development project, see
    138   <a href="{@docRoot}tools/support-library/setup.html">Support Library Setup</a>.
    139 </p>
    140 
    141 
    142 <h2 id="provider-service">Creating a Provider Service</h2>
    143 
    144 <p>The media router framework must be able to discover and connect to your media route provider
    145   to allow other applications to use your route. In order to do this, the media router framework
    146   looks for apps that declare a media route provider intent action. When another app wants to
    147   connect to your provider, the framework must be able to invoke and connect to it, so your provider
    148   must be encapsulated in a {@link android.app.Service}.</p>
    149 
    150 <p>The following example code shows the declaration of a media route provider service and the
    151   intent filter in a manifest, which allows it to be discovered and used by the media router
    152   framework:</p>
    153 
    154 <pre>
    155 &lt;service android:name=".provider.SampleMediaRouteProviderService"
    156     android:label="&#64;string/sample_media_route_provider_service"
    157     android:process=":mrp"&gt;
    158     &lt;intent-filter&gt;
    159         &lt;action android:name="android.media.MediaRouteProviderService" /&gt;
    160     &lt;/intent-filter&gt;
    161 &lt;/service&gt;
    162 </pre>
    163 
    164 <p>This manifest example declares a service that wraps the actual media route provider classes.
    165   The Android media router framework provides the
    166   {@link android.support.v7.media.MediaRouteProviderService} class for use as a service wrapper for
    167   media route providers. The following example code demonstrates how to use this wrapper
    168   class:</p>
    169 
    170 <pre>
    171 public class SampleMediaRouteProviderService extends MediaRouteProviderService {
    172 
    173     &#64;Override
    174     public MediaRouteProvider onCreateMediaRouteProvider() {
    175         return new SampleMediaRouteProvider(this);
    176     }
    177 }
    178 </pre>
    179 
    180 
    181 <h2 id="route-caps">Specifying Route Capabilities</h2>
    182 
    183 <p>Apps connecting to the media router framework can discover your media route through your
    184   app's manifest declarations, but they also need to know the capabilities of the media routes you
    185   are providing. Media routes can be of different types and have different features, and other apps
    186   need to be able to discover these details to determine if they are compatible with your route.</p>
    187 
    188 <p>The media router framework allows you to define and publish the capabilities of your media
    189   route through {@link android.content.IntentFilter} objects, {@link
    190   android.support.v7.media.MediaRouteDescriptor} objects and a {@link
    191   android.support.v7.media.MediaRouteProviderDescriptor}. This section explains how to use these
    192   classes to publish the details of your media route for other apps.</p>
    193 
    194 
    195 <h3 id="route-cat">Route categories</h3>
    196 
    197 <p>As part of the programmatic description of your media route provider, you must specify
    198   whether your provider supports remote playback, secondary output, or both. These are the route
    199   categories provided by the media router framework:</p>
    200 
    201 <ul>
    202   <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_LIVE_AUDIO CATEGORY_LIVE_AUDIO}
    203     &mdash; Output of audio to a secondary output device, such as a wireless-enabled music system.
    204     </li>
    205   <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_LIVE_VIDEO CATEGORY_LIVE_VIDEO}
    206     &mdash; Output of video to a secondary output device, such as Wireless Display devices.</li>
    207   <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_REMOTE_PLAYBACK
    208     CATEGORY_REMOTE_PLAYBACK} &mdash; Play video or audio on a separate device which handles media
    209     retrieval, decoding, and playback, such as
    210     <a href="https://www.google.com/url?q=http://www.google.com/chromecast">Chromecast</a> devices.
    211     </li>
    212 </ul>
    213 
    214 <p>In order to include these settings in a description of your media route, you insert them into
    215   an {@link android.content.IntentFilter} object, which you later add to a
    216   {@link android.support.v7.media.MediaRouteDescriptor} object:</p>
    217 
    218 <pre>
    219 public final class SampleMediaRouteProvider extends MediaRouteProvider {
    220     private static final ArrayList&lt;IntentFilter&gt; CONTROL_FILTERS_BASIC;
    221     static {
    222         IntentFilter videoPlayback = new IntentFilter();
    223         <strong>videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);</strong>
    224         CONTROL_FILTERS_BASIC = new ArrayList&lt;IntentFilter&gt;();
    225         CONTROL_FILTERS_BASIC.add(videoPlayback);
    226     }
    227 }
    228 
    229 </pre>
    230 
    231 <p>If you specify the {@link android.support.v7.media.MediaControlIntent#CATEGORY_REMOTE_PLAYBACK
    232   CATEGORY_REMOTE_PLAYBACK} intent, you must also define what media types and
    233   playback controls are supported by your media route provider. The next section describes how to
    234   specify these settings for your device.</p>
    235 
    236 
    237 <h3 id="media-types">Media types and protocols</h3>
    238 
    239 <p>A media route provider for a remote playback device must specify the media types and transfer
    240   protocols it supports. You specify these settings using the {@link android.content.IntentFilter}
    241   class and the {@link android.content.IntentFilter#addDataScheme addDataScheme()} and
    242   {@link android.content.IntentFilter#addDataType addDataType()} methods of that object. The
    243   following code snippet demonstrates how to define an intent filter for supporting remote video
    244   playback using http, https, and Real Time Streaming Protocol (RTSP):</p>
    245 
    246 <pre>
    247 public final class SampleMediaRouteProvider extends MediaRouteProvider {
    248 
    249     private static final ArrayList&lt;IntentFilter&gt; CONTROL_FILTERS_BASIC;
    250 
    251     static {
    252         IntentFilter videoPlayback = new IntentFilter();
    253         videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
    254         videoPlayback.addAction(MediaControlIntent.ACTION_PLAY);
    255         videoPlayback.addDataScheme("http");
    256         videoPlayback.addDataScheme("https");
    257         videoPlayback.addDataScheme("rtsp");
    258         addDataTypeUnchecked(videoPlayback, "video/*");
    259         CONTROL_FILTERS_BASIC = new ArrayList&lt;IntentFilter&gt;();
    260         CONTROL_FILTERS_BASIC.add(videoPlayback);
    261     }
    262     ...
    263 
    264     private static void addDataTypeUnchecked(IntentFilter filter, String type) {
    265         try {
    266             filter.addDataType(type);
    267         } catch (MalformedMimeTypeException ex) {
    268             throw new RuntimeException(ex);
    269         }
    270     }
    271 }
    272 
    273 </pre>
    274 
    275 
    276 <h3 id="playback-ctrls">Playback controls</h3>
    277 
    278 <p>A media route provider that offers remote playback must specify the types of media controls
    279   it supports. These are the general types of control that media routes can provide:</p>
    280 
    281 <ul>
    282   <li><strong>Playback controls</strong>, such as play, pause, rewind, and fast-forward.</li>
    283   <li><strong>Queuing features</strong>, which allow the sending app to add and remove items
    284     from a playlist which is maintained by the receiver device.</li>
    285   <li><strong>Session features</strong>, which prevent sending apps from interfering with each
    286     other by having the receiver device provide a session id to the requesting app and then checking
    287     that id with each subsequent playback control request.</li>
    288 </ul>
    289 
    290 <p>The following code example demonstrates how to construct an intent filter for supporting
    291   basic media route playback controls:</p>
    292 
    293 <pre>
    294 public final class SampleMediaRouteProvider extends MediaRouteProvider {
    295     private static final ArrayList&lt;IntentFilter&gt; CONTROL_FILTERS_BASIC;
    296     static {
    297         ...
    298         IntentFilter playControls = new IntentFilter();
    299         playControls.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
    300         playControls.addAction(MediaControlIntent.ACTION_SEEK);
    301         playControls.addAction(MediaControlIntent.ACTION_GET_STATUS);
    302         playControls.addAction(MediaControlIntent.ACTION_PAUSE);
    303         playControls.addAction(MediaControlIntent.ACTION_RESUME);
    304         playControls.addAction(MediaControlIntent.ACTION_STOP);
    305         CONTROL_FILTERS_BASIC = new ArrayList&lt;IntentFilter&gt;();
    306         CONTROL_FILTERS_BASIC.add(videoPlayback);
    307         CONTROL_FILTERS_BASIC.add(playControls);
    308     }
    309     ...
    310 }
    311 </pre>
    312 
    313 <p>For more information about the available playback control intents, see the
    314   {@link android.support.v7.media.MediaControlIntent} class.</p>
    315 
    316 
    317 <h3 id="mrpd">MediaRouteProviderDescriptor</h3>
    318 
    319 <p>After defining the capabilities of your media route using {@link
    320   android.content.IntentFilter} objects, you can then create a descriptor object for publishing to
    321   the Android media router framework. This descriptor object contains the specifics of your media
    322   route's capabilities so that other applications can determine how to interact with your media
    323   route.</p>
    324 
    325 <p>The following example code demonstrates how to add the previously created intent filters to a
    326   {@link android.support.v7.media.MediaRouteProviderDescriptor} and set the descriptor for use by
    327   the media router framework:</p>
    328 
    329 <pre>
    330 public SampleMediaRouteProvider(Context context) {
    331     super(context);
    332     publishRoutes();
    333 }
    334 
    335 private void publishRoutes() {
    336     Resources r = getContext().getResources();
    337     // Create a route descriptor using previously created IntentFilters
    338     MediaRouteDescriptor routeDescriptor = new MediaRouteDescriptor.Builder(
    339             VARIABLE_VOLUME_BASIC_ROUTE_ID,
    340             r.getString(R.string.variable_volume_basic_route_name))
    341             .setDescription(r.getString(R.string.sample_route_description))
    342             .addControlFilters(CONTROL_FILTERS_BASIC)
    343             .setPlaybackStream(AudioManager.STREAM_MUSIC)
    344             .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
    345             .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
    346             .setVolumeMax(VOLUME_MAX)
    347             .setVolume(mVolume)
    348             .build();
    349     // Add the route descriptor to the provider descriptor
    350     MediaRouteProviderDescriptor providerDescriptor =
    351             new MediaRouteProviderDescriptor.Builder()
    352             .addRoute(routeDescriptor)
    353             .build();
    354 
    355     // Publish the descriptor to the framework
    356     setDescriptor(providerDescriptor);
    357 }
    358 </pre>
    359 
    360 <p>For more information on the available descriptor settings, see the reference documentation
    361   for {@link android.support.v7.media.MediaRouteDescriptor} and {@link
    362   android.support.v7.media.MediaRouteProviderDescriptor}.</p>
    363 
    364 
    365 <h2 id="ctrl-routes">Controlling Routes</h2>
    366 
    367 <p>When an application connects to your media route provider, the provider receives playback
    368   commands through the media router framework sent to your route by other apps. To handle these
    369   requests, you must provide an implementation of a {@link
    370   android.support.v7.media.MediaRouteProvider.RouteController} class, which processes the commands
    371   and handles the actual communication to your receiver device.</p>
    372 
    373 <p>The media router framework calls the {@link
    374   android.support.v7.media.MediaRouteProvider#onCreateRouteController onCreateRouteController()}
    375   method of your route provider to obtain an instance of this class and then routes requests to it.
    376   These are the key methods of the {@link
    377   android.support.v7.media.MediaRouteProvider.RouteController} class, which you must implement for
    378   your media route provider:</p>
    379 
    380 <ul>
    381   <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onSelect onSelect()}
    382     &mdash; Called when an application selects your route for playback. You use this method to do
    383     any preparation work that may be required before media playback begins.</li>
    384   <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onControlRequest
    385     onControlRequest()} &mdash; Sends specific playback commands to the receiving device.</li>
    386   <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onSetVolume
    387     onSetVolume()} &mdash; Sends a request to the receiving device to set the playback volume to a
    388     specific value.</li>
    389   <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onUpdateVolume
    390     onUpdateVolume()} &mdash; Sends a request to the receiving device to modify the playback
    391     volume by a specified amount.</li>
    392   <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onUnselect
    393     onUnselect()} &mdash; Called when an application unselects a route.</li>
    394   <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onRelease onRelease()}
    395     &mdash; Called when the route is no longer needed by the framework, allowing it to free its
    396     resources.</li>
    397 </ul>
    398 
    399 <p>All playback control requests, except for volume changes, are directed to the {@link
    400   android.support.v7.media.MediaRouteProvider.RouteController#onControlRequest onControlRequest()}
    401   method. Your implementation of this method must parse the control requests and respond to them
    402   appropriately. Here is an example implementation of this method which processes commands for a
    403   remote playback media route:</p>
    404 
    405 <pre>
    406 private final class SampleRouteController extends
    407         MediaRouteProvider.RouteController {
    408     ...
    409 
    410     &#64;Override
    411     public boolean onControlRequest(Intent intent, ControlRequestCallback callback) {
    412 
    413         String action = intent.getAction();
    414 
    415         if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
    416             boolean success = false;
    417             if (action.equals(MediaControlIntent.ACTION_PLAY)) {
    418                 success = handlePlay(intent, callback);
    419             } else if (action.equals(MediaControlIntent.ACTION_ENQUEUE)) {
    420                 success = handleEnqueue(intent, callback);
    421             } else if (action.equals(MediaControlIntent.ACTION_REMOVE)) {
    422                 success = handleRemove(intent, callback);
    423             } else if (action.equals(MediaControlIntent.ACTION_SEEK)) {
    424                 success = handleSeek(intent, callback);
    425             } else if (action.equals(MediaControlIntent.ACTION_GET_STATUS)) {
    426                 success = handleGetStatus(intent, callback);
    427             } else if (action.equals(MediaControlIntent.ACTION_PAUSE)) {
    428                 success = handlePause(intent, callback);
    429             } else if (action.equals(MediaControlIntent.ACTION_RESUME)) {
    430                 success = handleResume(intent, callback);
    431             } else if (action.equals(MediaControlIntent.ACTION_STOP)) {
    432                 success = handleStop(intent, callback);
    433             } else if (action.equals(MediaControlIntent.ACTION_START_SESSION)) {
    434                 success = handleStartSession(intent, callback);
    435             } else if (action.equals(MediaControlIntent.ACTION_GET_SESSION_STATUS)) {
    436                 success = handleGetSessionStatus(intent, callback);
    437             } else if (action.equals(MediaControlIntent.ACTION_END_SESSION)) {
    438                 success = handleEndSession(intent, callback);
    439             }
    440 
    441             Log.d(TAG, mSessionManager.toString());
    442             return success;
    443         }
    444         return false;
    445     }
    446     ...
    447 }
    448 </pre>
    449 
    450 <p>It is important to understand that the {@link
    451   android.support.v7.media.MediaRouteProvider.RouteController} class is intended to act as a wrapper
    452   for the API to your media playback equipment. The implementation of the methods in this class is
    453   entirely dependent on the programmatic interface provided by your receiving device.</p>
    454