1 page.title=ExoPlayer 2 page.tags="audio","video","adaptive","streaming","DASH","smoothstreaming" 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></li> 10 <li><a href="#trackrenderer">TrackRenderer</a></li> 11 <li><a href="#samplesource">SampleSource</a> 12 <ol> 13 <li><a href="#mediaextractor">Providing media using MediaExtractor</a></li> 14 <li><a href="#adaptive-playback">Providing media for adaptive playback</a> 15 <ol> 16 <li><a href="#format-selection">Format selection for adaptive playback</a></li> 17 </ol> 18 </li> 19 </ol> 20 <li><a href="#events">Player Events</a> 21 <ol> 22 <li><a href="#high-events">High level events</a></li> 23 <li><a href="#low-events">Low level events</a></li> 24 </ol> 25 </li> 26 <li><a href="#sending-messages">Sending messages to components</a></li> 27 <li><a href="#customizing">Customizing ExoPlayer</a> 28 <ol> 29 <li><a href="#custom-guidelines">Custom component guidelines</a></li> 30 </ol> 31 </li> 32 <li><a href="#drm">Digital Rights Management</a></li> 33 </ol> 34 <h2>Key Classes</h2> 35 <ol> 36 <li>{@link android.media.MediaCodec}</li> 37 <li>{@link android.media.MediaExtractor}</li> 38 <li>{@link android.media.AudioTrack}</li> 39 </ol> 40 <h2>Related Samples</h2> 41 <ol> 42 <li><a class="external-link" href="https://github.com/google/ExoPlayer"> 43 ExoPlayer Project</a></li> 44 <li><a class="external-link" href="http://google.github.io/ExoPlayer/doc/reference/packages.html"> 45 Class Reference</a></li> 46 </ol> 47 </div> 48 </div> 49 50 51 <p>Playing videos and music is a popular activity on Android devices. The Android framework 52 provides {@link android.media.MediaPlayer} as a quick solution for playing media with minimal 53 code, and the {@link android.media.MediaCodec} and {@link android.media.MediaExtractor} classes 54 are provided for building custom media players. The open source project, ExoPlayer, is a 55 solution between these two options, providing a pre-built player that you can extend.</p> 56 57 <p>ExoPlayer supports features not currently provided by 58 {@link android.media.MediaPlayer}, including Dynamic adaptive streaming 59 over HTTP (DASH), SmoothStreaming, and persistent caching. ExoPlayer can be extended 60 to handle additional media formats, and because you include it as part of your app code, 61 you can update it along with your app.</p> 62 63 <p>This guide describes how to use ExoPlayer for playing Android supported media formats, as well as 64 DASH and SmoothStreaming playback. This guide also discusses ExoPlayer events, messages, DRM 65 support and guidelines for customizing the player.</p> 66 67 <p class="note"> 68 <strong>Note:</strong> ExoPlayer is an open source project that is not part of the Android 69 framework and is distributed separately from the Android SDK. The project contains a library and 70 a demo app that shows both simple and more advanced use of ExoPlayer:</p> 71 72 <ul> 73 <li><a class="external-link" href="https://github.com/google/ExoPlayer/tree/master/library"> 74 ExoPlayer Library</a> — This part of the project contains the core library classes.</li> 75 <li><a class="external-link" href="https://github.com/google/ExoPlayer/tree/master/demo/src/main/java/com/google/android/exoplayer/demo/simple"> 76 Simple Demo</a> — This part of the app demonstrates a basic use of ExoPlayer.</li> 77 <li><a class="external-link" href="https://github.com/google/ExoPlayer/tree/master/demo/src/main/java/com/google/android/exoplayer/demo/full"> 78 Full Demo</a> — This part of the app demonstrates more advanced features, 79 including the ability to select between multiple audio tracks, a background audio mode, 80 event logging and DRM protected playback. </li> 81 </ul> 82 83 84 <h2 id="overview">Overview</h2> 85 86 <p>ExoPlayer is a media player built on top of the {@link android.media.MediaExtractor} and 87 {@link android.media.MediaCodec} APIs released in Android 4.1 (API level 16). At the core of this 88 library is the {@code ExoPlayer} class. This class maintains the players global state, but makes few 89 assumptions about the nature of the media being played, such as how the media data is obtained, 90 how it is buffered or its format. You inject this functionality through ExoPlayers {@code 91 prepare()} method in the form of {@code TrackRenderer} objects.</p> 92 93 <p>ExoPlayer provides default {@code TrackRenderer} implementations for audio and 94 video, which make use of the {@link android.media.MediaCodec} and {@link android.media.AudioTrack} 95 classes in the Android framework. Both renderers require a {@code SampleSource} object, from which 96 they obtain individual media samples for playback. Figure 1 shows the high level object model for 97 an ExoPlayer implementation configured to play audio and video using these components.</p> 98 99 <img src="{@docRoot}images/exoplayer/object-model.png" alt="" id="figure1" /> 100 <p class="img-caption"> 101 <strong>Figure 1.</strong> High level object model for an ExoPlayer configured to play audio 102 and video using {@code TrackRenderer} objects 103 </p> 104 105 106 <h2 id="trackrenderer">TrackRenderer</h2> 107 108 <p>A {@code TrackRenderer} processes a component of media for playback, such as 109 video, audio or text. The ExoPlayer class invokes methods on its {@code TrackRenderer} instances from a 110 single playback thread, and by doing so causes each media component to be rendered as the global 111 playback position is advanced. The ExoPlayer library provides {@code MediaCodecVideoTrackRenderer} as 112 the default implementations rendering video and {@code MediaCodecAudioTrackRenderer} for audio. 113 Both implementations make use of {@link android.media.MediaCodec} to decode individual media 114 samples. They can handle all audio and video formats supported by a given Android device 115 (see <a href="http://developer.android.com/guide/appendix/media-formats.html">Supported Media 116 Formats</a> for details). The ExoPlayer library also provides an implementation for rendering 117 text called {@code TextTrackRenderer}. 118 </p> 119 120 <p>The code example below outlines the main steps required to instantiate an ExoPlayer to play video 121 and audio using the standard {@code TrackRenderer} implementations.</p> 122 123 <pre> 124 // 1. Instantiate the player. 125 player = ExoPlayer.Factory.newInstance(RENDERER_COUNT); 126 // 2. Construct renderers. 127 MediaCodecVideoTrackRenderer videoRenderer = 128 MediaCodecAudioTrackRenderer audioRenderer = ... 129 // 3. Inject the renderers through prepare. 130 player.prepare(videoRenderer, audioRenderer); 131 // 4. Pass the surface to the video renderer. 132 player.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, 133 surface); 134 // 5. Start playback. 135 player.setPlayWhenReady(true); 136 ... 137 player.release(); // Dont forget to release when done! 138 </pre> 139 140 <p>For a complete example, see the {@code SimplePlayerActivity} in the ExoPlayer demo app, which 141 correctly manages an ExoPlayer instance with respect to both the {@link android.app.Activity} and 142 {@link android.view.Surface} lifecycles.</p> 143 144 145 <h2 id="samplesource">SampleSource</h2> 146 147 <p>A standard {@code TrackRenderer} implementation requires a {@code SampleSource} to 148 be provided in its constructor. A {@code SampleSource} object provides format information and 149 media samples to be rendered. The ExoPlayer library provides {@code FrameworkSampleSource} and 150 {@code ChunkSampleSource}. The {@code FrameworkSampleSource} class uses {@link 151 android.media.MediaExtractor} to request, buffer and extract the media samples. The {@code 152 ChunkSampleSource} class provides adaptive playback using DASH or SmoothStreaming, and 153 implements networking, buffering and media extraction within the ExoPlayer library.</p> 154 155 156 <h3 id="mediaextractor">Providing media using MediaExtractor</h3> 157 158 <p> 159 In order to render media formats supported by the Android framework, the {@code 160 FrameworkSampleSource} class uses {@link android.media.MediaExtractor} for networking, 161 buffering and sample extraction functionality. By doing so, it supports any media container format 162 supported by the version of Android where it is running. For more information about media formats 163 supported by Android, see <a href="{@docRoot}guide/appendix/media-formats.html">Supported 164 Media Formats</a>. 165 </p> 166 167 <p>The diagram in Figure 2 shows the object model for an ExoPlayer implementation using 168 {@code FrameworkSampleSource}.</p> 169 170 <img src="{@docRoot}images/exoplayer/frameworksamplesource.png" alt="" id="figure2" /> 171 <p class="img-caption"> 172 <strong>Figure 2.</strong> Object model for an implementation of ExoPlayer that renders 173 media formats supported by Android using {@code FrameworkSampleSource} 174 </p> 175 176 <p>The following code example outlines how the video and audio renderers are constructed to 177 load the video from a specified URI.</p> 178 179 <pre> 180 FrameworkSampleSource sampleSource = new FrameworkSampleSource( 181 activity, uri, null, 2); 182 MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer( 183 sampleSource, null, true, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 0, 184 mainHandler, playerActivity, 50); 185 MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer( 186 sampleSource, null, true); 187 </pre> 188 189 <p>The ExoPlayer demo app provides a complete implementation of this code in 190 {@code DefaultRendererBuilder}. The {@code SimplePlaybackActivity} class uses it to play one 191 of the videos available in the demo app. Note that in the example, video and audio 192 are muxed, meaning they are streamed together from a single URI. The {@code FrameworkSampleSource} 193 instance provides video samples to the {@code videoRenderer} object and audio samples to the 194 {@code audioRenderer} object as they are extracted from the media container format. It is also 195 possible to play demuxed media, where video and audio are streamed separately from different URIs. 196 This functionality can be achieved by having two {@code FrameworkSampleSource} instances instead 197 of one.</p> 198 199 200 <h3 id="adaptive-playback">Providing media for adaptive playback</h3> 201 202 <p>ExoPlayer supports adaptive streaming, which allows the quality of the 203 media data to be adjusted during playback based on the network conditions. DASH 204 and SmoothStreaming are examples of adaptive streaming technologies. Both these approaches 205 load media in small chunks (typically 2 to 10 seconds in duration). Whenever a chunk of media 206 is requested, the client selects from a number of possible formats. For example, a client may 207 select a high quality format if network conditions are good, or a low quality format if network 208 conditions are bad. In both techniques, video and audio are streamed separately.</p> 209 210 <p>ExoPlayer supports adaptive playback through use of the {@code ChunkSampleSource} class, 211 which loads chunks of media data from which individual samples can be extracted. Each {@code 212 ChunkSampleSource} requires a {@code ChunkSource} object to be injected through its constructor, 213 which is responsible for providing media chunks from which to load and read samples. The {@code 214 DashMp4ChunkSource} and {@code SmoothStreamingChunkSource} classes provide DASH and SmoothStreaming 215 playback using the FMP4 container format. The {@code DashWebMChunkSource} class uses the WebM 216 container format to provide DASH playback.</p> 217 218 <p>All of the standard {@code ChunkSource} implementations require a {@code FormatEvaluator} and 219 a {@code DataSource} to be injected through their constructors. The {@code FormatEvaluator} 220 objects select from the available formats before each chunk is loaded. The {@code DataSource} 221 objects are responsible for actually loading the data. Finally, the {@code ChunkSampleSources} 222 require a {@code LoadControl} object that controls the chunk buffering policy.</p> 223 224 <p>The object model of an ExoPlayer configured for a DASH adaptive playback is shown in the 225 diagram below. This example uses an {@code HttpDataSource} object to stream the media over the 226 network. The video quality is varied at runtime using the adaptive implementation of {@code 227 FormatEvaluator}, while audio is played at a fixed quality level.</p> 228 229 <img src="{@docRoot}images/exoplayer/adaptive-streaming.png" alt="" id="figure3" /> 230 <p class="img-caption"> 231 <strong>Figure 3.</strong> Object model for a DASH adaptive playback using ExoPlayer 232 </p> 233 234 <p>The following code example outlines how the video and audio renderers are constructed.</p> 235 236 <pre> 237 Handler mainHandler = playerActivity.getMainHandler(); 238 LoadControl loadControl = new DefaultLoadControl( 239 new BufferPool(BUFFER_SEGMENT_SIZE)); 240 BandwidthMeter bandwidthMeter = new BandwidthMeter(); 241 242 // Build the video renderer. 243 DataSource videoDataSource = new HttpDataSource(userAgent, 244 HttpDataSource.REJECT_PAYWALL_TYPES, bandwidthMeter); 245 ChunkSource videoChunkSource = new DashMp4ChunkSource(videoDataSource, 246 new AdaptiveEvaluator(bandwidthMeter), videoRepresentations); 247 ChunkSampleSource videoSampleSource = new ChunkSampleSource(videoChunkSource, 248 loadControl, VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true); 249 MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer( 250 videoSampleSource, null, true, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 251 0, mainHandler, playerActivity, 50); 252 253 // Build the audio renderer. 254 DataSource audioDataSource = new HttpDataSource(userAgent, 255 HttpDataSource.REJECT_PAYWALL_TYPES, bandwidthMeter); 256 ChunkSource audioChunkSource = new DashMp4ChunkSource(audioDataSource, 257 new FormatEvaluator.FixedEvaluator(), audioRepresentation); 258 SampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource, 259 loadControl, AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true); 260 MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer( 261 audioSampleSource, null, true); 262 </pre> 263 264 <p>In this code, {@code videoRepresentations} and {@code audioRepresentation} are {@code 265 Representation} objects, each of which describes one of the available media streams. In the DASH 266 model, these streams are parsed from a media presentation description (MPD) file. The ExoPlayer 267 library provides a {@code MediaPresentationDescriptionParser} class to obtain {@code 268 Representation} objects from MPD files.</p> 269 270 <p class="note"> 271 <strong>Note:</strong> Building Representation objects from MPD files is not required. You can 272 build Representation objects from other data sources if necessary. 273 </p> 274 275 <p>The ExoPlayer demo app provides complete implementation of this code in 276 {@code DashVodRendererBuilder}. The {@code SimplePlaybackActivity} class uses this builder to 277 construct renderers for playing DASH sample videos in the demo app. It asynchronously fetches a 278 specified MPD file in order to construct the required {@code Representation} objects. For an 279 equivalent SmoothStreaming example, see the {@code SmoothStreamingRendererBuilder} class in the 280 demo app.</p> 281 282 283 <h4 id="format-selection">Format selection for adaptive playback</h4> 284 285 <p>For DASH and SmoothStreaming playback, consider both static format selection at the 286 start of playback and dynamic format selection during playback. Static format selection should be 287 used to filter out formats that should not be used throughout the playback, for example formats 288 with resolutions higher than the maximum supported by the playback device. Dynamic selection varies 289 the selected format during playback, typically to adapt video quality in response to changes in 290 network conditions.</p> 291 292 <h5 id="static-selection">Static format selection</h5> 293 294 <p>When preparing a player, you should consider filtering out some of the available formats if 295 they are not useable for playback. Static format selection allows you to filter out 296 formats that cannot be used on a particular device or are not compatible with your player. 297 For audio playback, this often means picking a single format to play and discarding the others.</p> 298 299 <p>For video playback, filtering formats can be more complicated. Apps should first 300 eliminate any streams that whose resolution is too high to be played by the device. For H.264, 301 which is normally used for DASH and SmoothStreaming playback, ExoPlayers {@code MediaCodecUtil} 302 class provides a {@code maxH264DecodableFrameSize()} method that can be used to determine what 303 resolution streams the device is able to handle, as shown in the following code example:</p> 304 305 <pre> 306 int maxDecodableFrameSize = MediaCodecUtil.maxH264DecodableFrameSize(); 307 Format format = representation.format; 308 if (format.width * format.height <= maxDecodableFrameSize) { 309 // The device can play this stream. 310 videoRepresentations.add(representation); 311 } else { 312 // The device isn't capable of playing this stream. 313 } 314 </pre> 315 316 <p>This approach is used to filter {@code Representations} in the {@code DashVodRendererBuilder} 317 class of the ExoPlayer demo app, and similarly to filter track indices in {@code 318 SmoothStreamingRendererBuilder}.</p> 319 320 <p>In addition to eliminating unsupported formats, it should be noted that the ability to 321 seamlessly switch between H.264 streams of different resolution is an optional decoder feature 322 available in Android 4.3 (API level 16) and higher, and so is not supported by all devices. The 323 availability of an adaptive H.264 decoder can be queried using {@code MediaCodecUtil}, as shown in 324 the following code example:</p> 325 326 <pre> 327 boolean isAdaptive = MediaCodecUtil.getDecoderInfo(MimeTypes.VIDEO_H264).adaptive; 328 </pre> 329 330 <p>The {@code MediaCodecVideoTrackRenderer} class is still able to handle resolution changes on 331 devices that do not have adaptive decoders, however the switch is not seamless. Typically, the 332 switch creates a small discontinuity in visual output lasting around 50-100ms. For devices that 333 do not provide an adaptive decoder, app developers may choose to adapt between formats at 334 a single fixed resolution so as to avoid discontinuities. The ExoPlayer demo app 335 implementation does not pick a fixed resolution.</p> 336 337 338 <h5 id="dynamic-selection">Dynamic format selection</h5> 339 340 <p>During playback, you can use a {@code FormatEvaluator} to dynamically select from the 341 available video formats. The ExoPlayer library provides a {@code FormatEvaluator.Adaptive} 342 implementation for dynamically selecting between video formats based on the current network 343 conditions.</p> 344 345 <p>This class provides a simple, general purpose reference implementation, however you are 346 encouraged to write your own {@code FormatEvaluator} implementation to best suit your particular 347 needs.</p> 348 349 350 <h2 id="events">Player Events</h2> 351 352 <p>During playback, your app can listen for events generated by the ExoPlayer that indicate the 353 overall state of the player. These events are useful as triggers for updating the app user 354 interface such as playback controls. Many ExoPlayer components also report their own component 355 specific low level events, which can be useful for performance monitoring.</p> 356 357 358 <h3 id="high-events">High level events</h3> 359 360 <p>ExoPlayer allows instances of {@code ExoPlayer.Listener} to be added and removed using its 361 {@code addListener()} and {@code removeListener()} methods. Registered listeners are notified of 362 changes in playback state, as well as when errors occur that cause playback to fail. For more 363 information about the valid playback states and the possible transitions between them, see the 364 ExoPlayer source code.</p> 365 366 <p>Developers who implement custom playback controls should register a listener and use it to 367 update their controls as the players state changes. An app should also show an 368 appropriate error to the user if playback fails.</p> 369 370 <h3 id="low-events">Low level events</h3> 371 372 <p>In addition to high level listeners, many of the individual components provided by the 373 ExoPlayer library allow their own event listeners. For example, {@code 374 MediaCodecVideoTrackRenderer} has constructors that take a {@code 375 MediaCodecVideoTrackRenderer.EventListener}. In the ExoPlayer demo app, {@code SimplePlayerActivity} 376 acts as a listener so that it can adjust the dimensions of the target surface to have the correct 377 height and width ratio for the video being played:</p> 378 379 <pre> 380 @Override 381 public void onVideoSizeChanged(int width, int height) { 382 surfaceView.setVideoWidthHeightRatio(height == 0 ? 1 : (float) width / height); 383 } 384 </pre> 385 386 <p>The {@code RendererBuilder} classes in the ExoPlayer demo app inject the activity as the 387 listener, for example in the {@code DashVodRendererBuilder} class:</p> 388 389 <pre> 390 MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer( 391 videoSampleSource, null, true, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 392 0, <strong>mainHandler, playerActivity</strong>, 50); 393 </pre> 394 395 <p>Note that you must pass a {@link android.os.Handler} object to the renderer, which determines 396 the thread on which the listeners methods are invoked. In most cases, you should use a 397 {@link android.os.Handler} associated with the apps main thread, as is the case in this example. 398 </p> 399 400 <p>Listening to individual components can be useful for adjusting UI based on player events, as 401 in the example above. Listening to component events can also be helpful for logging performance 402 metrics. For example, {@code MediaCodecVideoTrackRenderer} notifies its listener of dropped video 403 frames. A developer may wish to log such metrics to track playback performance in their 404 app.</p> 405 406 <p>Many components also notify their listeners when errors occur. Such errors may or may not 407 cause playback to fail. If an error does not cause playback to fail, it may still result in 408 degraded performance, and so you may wish to log all errors in order to track playback 409 performance. Note that an ExoPlayer instance always notifies its high level listeners of errors that 410 cause playback to fail, in addition to the listener of the individual component from which the error 411 originated. Hence, you should display error messages to users only from high level listeners. 412 Within individual component listeners, you should use error notifications only for informational 413 purposes.</p> 414 415 416 <h2 id="sending-messages">Sending messages to components</h2> 417 418 <p>Some ExoPlayer components allow changes in configuration during playback. By convention, you make 419 these changes by passing asynchronous messages through the ExoPlayer to the component. 420 This approach ensures both thread safety and that the configuration change is 421 executed in order with any other operations being performed on the player.</p> 422 423 <p>The most common use of messaging is passing a target surface to 424 {@code MediaCodecVideoTrackRenderer}:</p> 425 426 <pre> 427 player.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, 428 surface); 429 </pre> 430 431 <p>Note that if the surface needs to be cleared because 432 {@link android.view.SurfaceHolder.Callback#surfaceDestroyed 433 SurfaceHolder.Callback.surfaceDestroyed()} has been invoked, then you must send this 434 message using the blocking variant of {@code sendMessage()}:</p> 435 <p> 436 437 <pre> 438 player.blockingSendMessage(videoRenderer, 439 MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, null); 440 </pre> 441 442 <p>You must use a blocking message because the contract of {@link 443 android.view.SurfaceHolder.Callback#surfaceDestroyed surfaceDestroyed()} requires that the 444 app does not attempt to access the surface after the method returns. The {@code 445 SimplePlayerActivity} class in the demo app demonstrates how the surface should be set and 446 cleared.</p> 447 448 449 <h2 id="customizing">Customizing ExoPlayer</h2> 450 451 <p>One of the main benefits of ExoPlayer over {@link android.media.MediaPlayer} is the ability to 452 customize and extend the player to better suit the developers use case. The ExoPlayer library 453 is designed specifically with this in mind, defining a number of abstract base classes and 454 interfaces that make it possible for app developers to easily replace the default implementations 455 provided by the library. Here are some use cases for building custom components:</p> 456 457 <ul> 458 <li><strong>{@code TrackRenderer}</strong> - You may want to implement a custom 459 {@code TrackRenderer} to handle media types other than audio and video. The {@code 460 TextTrackRenderer} class within the ExoPlayer library is an example of how to implement a 461 custom renderer. You could use the approach it demonstrates to render custom 462 overlays or annotations. Implementing this kind of functionality as a {@code TrackRenderer} 463 makes it easy to keep the overlays or annotations in sync with the other media being played.</li> 464 <li><strong>{@code SampleSource}</strong> - If you need to support a container format not 465 already handled by {@link android.media.MediaExtractor} or ExoPlayer, consider implementing a 466 custom {@code SampleSource} class.</li> 467 <li><strong>{@code FormatEvaluator}</strong> - The ExoPlayer library provides {@code 468 FormatEvaluator.Adaptive} as a simple reference implementation that switches between different 469 quality video formats based on the available bandwidth. App developers are encouraged to 470 develop their own adaptive {@code FormatEvaluator} implementations, which can be designed to 471 suit their use specific needs.</li> 472 <li><strong>{@code DataSource}</strong> - ExoPlayers upstream package already contains a 473 number of {@code DataSource} implementations for different use cases, such as writing and 474 reading to and from a persistent media cache. You may want to implement you own 475 {@code DataSource} class to load data in another way, such as a custom 476 protocol or HTTP stack for data input.</li> 477 </ul> 478 479 480 <h3 id="custom-guidelines">Custom component guidelines</h3> 481 482 <p>If a custom component needs to report events back to the app, we recommend that you 483 do so using the same model as existing ExoPlayer components, where an event listener is passed 484 together with a {@link android.os.Handler} to the constructor of the component.</p> 485 486 <p>We recommended that custom components use the same model as existing ExoPlayer components to 487 allow reconfiguration by the app during playback, as described in 488 <a href="#sending-messages">Sending messages to components</a>. 489 To do this, you should implement a {@code ExoPlayerComponent} and receive 490 configuration changes in its {@code handleMessage()} method. Your app should pass 491 configuration changes by calling ExoPlayers {@code sendMessage()} and {@code 492 blockingSendMessage()} methods.</p> 493 494 495 <h2 id="drm">Digital Rights Management</h2> 496 497 <p>On Android 4.3 (API level 18) and higher, ExoPlayer supports Digital Rights Managment (DRM) 498 protected playback. In order to play DRM protected content with ExoPlayer, your app must 499 inject a {@code DrmSessionManager} into the {@code MediaCodecVideoTrackRenderer} and {@code 500 MediaCodecAudioTrackRenderer} constructors. A {@code DrmSessionManager} object is responsible for 501 providing the {@code MediaCrypto} object required for decryption, as well as ensuring that the 502 required decryption keys are available to the underlying DRM module being used.</p> 503 504 <p>The ExoPlayer library provides a default implementation of {@code DrmSessionManager}, called 505 {@code StreamingDrmSessionManager}, which uses {@link android.media.MediaDrm}. The session 506 manager supports any DRM scheme for which a modular DRM component exists on the device. All 507 Android devices are required to support Widevine modular DRM (with L3 security, although many 508 devices also support L1). Some devices may support additional schemes such as PlayReady.</p> 509 510 <p>The {@code StreamingDrmSessionManager} class requires a {@code MediaDrmCallback} to be 511 injected into its constructor, which is responsible for actually making provisioning and key 512 requests. You should implement this interface to make network requests to your license 513 server and obtain the required keys. The {@code WidevineTestMediaDrmCallback} class in the 514 ExoPlayer demo app sends requests to a Widevine test server.</p> 515