1*30877f79SAndroid Build Coastguard Worker--- 2*30877f79SAndroid Build Coastguard Workertitle: Customization 3*30877f79SAndroid Build Coastguard Worker--- 4*30877f79SAndroid Build Coastguard Worker 5*30877f79SAndroid Build Coastguard WorkerAt the core of the ExoPlayer library is the `Player` interface. A `Player` 6*30877f79SAndroid Build Coastguard Workerexposes traditional high-level media player functionality such as the ability to 7*30877f79SAndroid Build Coastguard Workerbuffer media, play, pause and seek. The default implementation `ExoPlayer` is 8*30877f79SAndroid Build Coastguard Workerdesigned to make few assumptions about (and hence impose few restrictions on) 9*30877f79SAndroid Build Coastguard Workerthe type of media being played, how and where it is stored, and how it is 10*30877f79SAndroid Build Coastguard Workerrendered. Rather than implementing the loading and rendering of media directly, 11*30877f79SAndroid Build Coastguard Worker`ExoPlayer` implementations delegate this work to components that are injected 12*30877f79SAndroid Build Coastguard Workerwhen a player is created or when new media sources are passed to the player. 13*30877f79SAndroid Build Coastguard WorkerComponents common to all `ExoPlayer` implementations are: 14*30877f79SAndroid Build Coastguard Worker 15*30877f79SAndroid Build Coastguard Worker* `MediaSource` instances that define media to be played, load the media, and 16*30877f79SAndroid Build Coastguard Worker from which the loaded media can be read. `MediaSource` instances are created 17*30877f79SAndroid Build Coastguard Worker from `MediaItem`s by a `MediaSource.Factory` inside the player. They can also 18*30877f79SAndroid Build Coastguard Worker be passed directly to the player using the [media source based playlist API]. 19*30877f79SAndroid Build Coastguard Worker* A `MediaSource.Factory` that converts `MediaItem`s to `MediaSource`s. The 20*30877f79SAndroid Build Coastguard Worker `MediaSource.Factory` is injected when the player is created. 21*30877f79SAndroid Build Coastguard Worker* `Renderer`s that render individual components of the media. `Renderer`s are 22*30877f79SAndroid Build Coastguard Worker injected when the player is created. 23*30877f79SAndroid Build Coastguard Worker* A `TrackSelector` that selects tracks provided by the `MediaSource` to be 24*30877f79SAndroid Build Coastguard Worker consumed by each of the available `Renderer`s. A `TrackSelector` is injected 25*30877f79SAndroid Build Coastguard Worker when the player is created. 26*30877f79SAndroid Build Coastguard Worker* A `LoadControl` that controls when the `MediaSource` buffers more media, and 27*30877f79SAndroid Build Coastguard Worker how much media is buffered. A `LoadControl` is injected when the player is 28*30877f79SAndroid Build Coastguard Worker created. 29*30877f79SAndroid Build Coastguard Worker* A `LivePlaybackSpeedControl` that controls the playback speed during live 30*30877f79SAndroid Build Coastguard Worker playbacks to allow the player to stay close to a configured live offset. A 31*30877f79SAndroid Build Coastguard Worker `LivePlaybackSpeedControl` is injected when the player is created. 32*30877f79SAndroid Build Coastguard Worker 33*30877f79SAndroid Build Coastguard WorkerThe concept of injecting components that implement pieces of player 34*30877f79SAndroid Build Coastguard Workerfunctionality is present throughout the library. The default implementations of 35*30877f79SAndroid Build Coastguard Workersome components delegate work to further injected components. This allows many 36*30877f79SAndroid Build Coastguard Workersub-components to be individually replaced with implementations that are 37*30877f79SAndroid Build Coastguard Workerconfigured in a custom way. 38*30877f79SAndroid Build Coastguard Worker 39*30877f79SAndroid Build Coastguard Worker## Player customization ## 40*30877f79SAndroid Build Coastguard Worker 41*30877f79SAndroid Build Coastguard WorkerSome common examples of customizing the player by injecting components are 42*30877f79SAndroid Build Coastguard Workerdescribed below. 43*30877f79SAndroid Build Coastguard Worker 44*30877f79SAndroid Build Coastguard Worker### Configuring the network stack ### 45*30877f79SAndroid Build Coastguard Worker 46*30877f79SAndroid Build Coastguard WorkerExoPlayer supports Android's default network stack, as well as Cronet and 47*30877f79SAndroid Build Coastguard WorkerOkHttp. In each case it's possible to customize the network stack for your use 48*30877f79SAndroid Build Coastguard Workercase. The following example shows how to customize the player to use Android's 49*30877f79SAndroid Build Coastguard Workerdefault network stack with cross-protocol redirects enabled: 50*30877f79SAndroid Build Coastguard Worker 51*30877f79SAndroid Build Coastguard Worker~~~ 52*30877f79SAndroid Build Coastguard Worker// Build a HttpDataSource.Factory with cross-protocol redirects enabled. 53*30877f79SAndroid Build Coastguard WorkerHttpDataSource.Factory httpDataSourceFactory = 54*30877f79SAndroid Build Coastguard Worker new DefaultHttpDataSource.Factory().setAllowCrossProtocolRedirects(true); 55*30877f79SAndroid Build Coastguard Worker 56*30877f79SAndroid Build Coastguard Worker// Wrap the HttpDataSource.Factory in a DefaultDataSource.Factory, which adds in 57*30877f79SAndroid Build Coastguard Worker// support for requesting data from other sources (e.g., files, resources, etc). 58*30877f79SAndroid Build Coastguard WorkerDefaultDataSource.Factory dataSourceFactory = 59*30877f79SAndroid Build Coastguard Worker new DefaultDataSource.Factory(context, httpDataSourceFactory); 60*30877f79SAndroid Build Coastguard Worker 61*30877f79SAndroid Build Coastguard Worker// Inject the DefaultDataSourceFactory when creating the player. 62*30877f79SAndroid Build Coastguard WorkerExoPlayer player = 63*30877f79SAndroid Build Coastguard Worker new ExoPlayer.Builder(context) 64*30877f79SAndroid Build Coastguard Worker .setMediaSourceFactory(new DefaultMediaSourceFactory(dataSourceFactory)) 65*30877f79SAndroid Build Coastguard Worker .build(); 66*30877f79SAndroid Build Coastguard Worker~~~ 67*30877f79SAndroid Build Coastguard Worker{: .language-java} 68*30877f79SAndroid Build Coastguard Worker 69*30877f79SAndroid Build Coastguard WorkerThe same approach can be used to configure and inject `HttpDataSource.Factory` 70*30877f79SAndroid Build Coastguard Workerimplementations provided by the [Cronet extension] and the [OkHttp extension], 71*30877f79SAndroid Build Coastguard Workerdepending on your preferred choice of network stack. 72*30877f79SAndroid Build Coastguard Worker 73*30877f79SAndroid Build Coastguard Worker### Caching data loaded from the network ### 74*30877f79SAndroid Build Coastguard Worker 75*30877f79SAndroid Build Coastguard WorkerTo temporarily cache media, or for 76*30877f79SAndroid Build Coastguard Worker[playing downloaded media]({{ site.baseurl }}/downloading-media.html#playing-downloaded-content), 77*30877f79SAndroid Build Coastguard Workeryou can inject a `CacheDataSource.Factory` into the `DefaultMediaSourceFactory`: 78*30877f79SAndroid Build Coastguard Worker 79*30877f79SAndroid Build Coastguard Worker~~~ 80*30877f79SAndroid Build Coastguard WorkerDataSource.Factory cacheDataSourceFactory = 81*30877f79SAndroid Build Coastguard Worker new CacheDataSource.Factory() 82*30877f79SAndroid Build Coastguard Worker .setCache(simpleCache) 83*30877f79SAndroid Build Coastguard Worker .setUpstreamDataSourceFactory(httpDataSourceFactory); 84*30877f79SAndroid Build Coastguard Worker 85*30877f79SAndroid Build Coastguard WorkerExoPlayer player = new ExoPlayer.Builder(context) 86*30877f79SAndroid Build Coastguard Worker .setMediaSourceFactory( 87*30877f79SAndroid Build Coastguard Worker new DefaultMediaSourceFactory(cacheDataSourceFactory)) 88*30877f79SAndroid Build Coastguard Worker .build(); 89*30877f79SAndroid Build Coastguard Worker~~~ 90*30877f79SAndroid Build Coastguard Worker{: .language-java} 91*30877f79SAndroid Build Coastguard Worker 92*30877f79SAndroid Build Coastguard Worker### Customizing server interactions ### 93*30877f79SAndroid Build Coastguard Worker 94*30877f79SAndroid Build Coastguard WorkerSome apps may want to intercept HTTP requests and responses. You may want to 95*30877f79SAndroid Build Coastguard Workerinject custom request headers, read the server's response headers, modify the 96*30877f79SAndroid Build Coastguard Workerrequests' URIs, etc. For example, your app may authenticate itself by injecting 97*30877f79SAndroid Build Coastguard Workera token as a header when requesting the media segments. 98*30877f79SAndroid Build Coastguard Worker 99*30877f79SAndroid Build Coastguard WorkerThe following example demonstrates how to implement these behaviors by 100*30877f79SAndroid Build Coastguard Workerinjecting a custom `DataSource.Factory` into the `DefaultMediaSourceFactory`: 101*30877f79SAndroid Build Coastguard Worker 102*30877f79SAndroid Build Coastguard Worker~~~ 103*30877f79SAndroid Build Coastguard WorkerDataSource.Factory dataSourceFactory = () -> { 104*30877f79SAndroid Build Coastguard Worker HttpDataSource dataSource = httpDataSourceFactory.createDataSource(); 105*30877f79SAndroid Build Coastguard Worker // Set a custom authentication request header. 106*30877f79SAndroid Build Coastguard Worker dataSource.setRequestProperty("Header", "Value"); 107*30877f79SAndroid Build Coastguard Worker return dataSource; 108*30877f79SAndroid Build Coastguard Worker}; 109*30877f79SAndroid Build Coastguard Worker 110*30877f79SAndroid Build Coastguard WorkerExoPlayer player = new ExoPlayer.Builder(context) 111*30877f79SAndroid Build Coastguard Worker .setMediaSourceFactory(new DefaultMediaSourceFactory(dataSourceFactory)) 112*30877f79SAndroid Build Coastguard Worker .build(); 113*30877f79SAndroid Build Coastguard Worker~~~ 114*30877f79SAndroid Build Coastguard Worker{: .language-java} 115*30877f79SAndroid Build Coastguard Worker 116*30877f79SAndroid Build Coastguard WorkerIn the code snippet above, the injected `HttpDataSource` includes the header 117*30877f79SAndroid Build Coastguard Worker`"Header: Value"` in every HTTP request. This behavior is *fixed* for every 118*30877f79SAndroid Build Coastguard Workerinteraction with an HTTP source. 119*30877f79SAndroid Build Coastguard Worker 120*30877f79SAndroid Build Coastguard WorkerFor a more granular approach, you can inject just-in-time behavior using a 121*30877f79SAndroid Build Coastguard Worker`ResolvingDataSource`. The following code snippet shows how to inject 122*30877f79SAndroid Build Coastguard Workerrequest headers just before interacting with an HTTP source: 123*30877f79SAndroid Build Coastguard Worker 124*30877f79SAndroid Build Coastguard Worker~~~ 125*30877f79SAndroid Build Coastguard WorkerDataSource.Factory dataSourceFactory = new ResolvingDataSource.Factory( 126*30877f79SAndroid Build Coastguard Worker httpDataSourceFactory, 127*30877f79SAndroid Build Coastguard Worker // Provide just-in-time request headers. 128*30877f79SAndroid Build Coastguard Worker dataSpec -> dataSpec.withRequestHeaders(getCustomHeaders(dataSpec.uri))); 129*30877f79SAndroid Build Coastguard Worker~~~ 130*30877f79SAndroid Build Coastguard Worker{: .language-java} 131*30877f79SAndroid Build Coastguard Worker 132*30877f79SAndroid Build Coastguard WorkerYou may also use a `ResolvingDataSource` to perform 133*30877f79SAndroid Build Coastguard Workerjust-in-time modifications of the URI, as shown in the following snippet: 134*30877f79SAndroid Build Coastguard Worker 135*30877f79SAndroid Build Coastguard Worker~~~ 136*30877f79SAndroid Build Coastguard WorkerDataSource.Factory dataSourceFactory = new ResolvingDataSource.Factory( 137*30877f79SAndroid Build Coastguard Worker httpDataSourceFactory, 138*30877f79SAndroid Build Coastguard Worker // Provide just-in-time URI resolution logic. 139*30877f79SAndroid Build Coastguard Worker dataSpec -> dataSpec.withUri(resolveUri(dataSpec.uri))); 140*30877f79SAndroid Build Coastguard Worker~~~ 141*30877f79SAndroid Build Coastguard Worker{: .language-java} 142*30877f79SAndroid Build Coastguard Worker 143*30877f79SAndroid Build Coastguard Worker### Customizing error handling ### 144*30877f79SAndroid Build Coastguard Worker 145*30877f79SAndroid Build Coastguard WorkerImplementing a custom [LoadErrorHandlingPolicy][] allows apps to customize the 146*30877f79SAndroid Build Coastguard Workerway ExoPlayer reacts to load errors. For example, an app may want to fail fast 147*30877f79SAndroid Build Coastguard Workerinstead of retrying many times, or may want to customize the back-off logic that 148*30877f79SAndroid Build Coastguard Workercontrols how long the player waits between each retry. The following snippet 149*30877f79SAndroid Build Coastguard Workershows how to implement custom back-off logic: 150*30877f79SAndroid Build Coastguard Worker 151*30877f79SAndroid Build Coastguard Worker~~~ 152*30877f79SAndroid Build Coastguard WorkerLoadErrorHandlingPolicy loadErrorHandlingPolicy = 153*30877f79SAndroid Build Coastguard Worker new DefaultLoadErrorHandlingPolicy() { 154*30877f79SAndroid Build Coastguard Worker @Override 155*30877f79SAndroid Build Coastguard Worker public long getRetryDelayMsFor(LoadErrorInfo loadErrorInfo) { 156*30877f79SAndroid Build Coastguard Worker // Implement custom back-off logic here. 157*30877f79SAndroid Build Coastguard Worker } 158*30877f79SAndroid Build Coastguard Worker }; 159*30877f79SAndroid Build Coastguard Worker 160*30877f79SAndroid Build Coastguard WorkerExoPlayer player = 161*30877f79SAndroid Build Coastguard Worker new ExoPlayer.Builder(context) 162*30877f79SAndroid Build Coastguard Worker .setMediaSourceFactory( 163*30877f79SAndroid Build Coastguard Worker new DefaultMediaSourceFactory(context) 164*30877f79SAndroid Build Coastguard Worker .setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)) 165*30877f79SAndroid Build Coastguard Worker .build(); 166*30877f79SAndroid Build Coastguard Worker~~~ 167*30877f79SAndroid Build Coastguard Worker{: .language-java} 168*30877f79SAndroid Build Coastguard Worker 169*30877f79SAndroid Build Coastguard WorkerThe `LoadErrorInfo` argument contains more information about the failed load to 170*30877f79SAndroid Build Coastguard Workercustomize the logic based on the error type or the failed request. 171*30877f79SAndroid Build Coastguard Worker 172*30877f79SAndroid Build Coastguard Worker### Customizing extractor flags ### 173*30877f79SAndroid Build Coastguard Worker 174*30877f79SAndroid Build Coastguard WorkerExtractor flags can be used to customize how individual formats are extracted 175*30877f79SAndroid Build Coastguard Workerfrom progressive media. They can be set on the `DefaultExtractorsFactory` that's 176*30877f79SAndroid Build Coastguard Workerprovided to the `DefaultMediaSourceFactory`. The following example passes a flag 177*30877f79SAndroid Build Coastguard Workerthat enables index-based seeking for MP3 streams. 178*30877f79SAndroid Build Coastguard Worker 179*30877f79SAndroid Build Coastguard Worker~~~ 180*30877f79SAndroid Build Coastguard WorkerDefaultExtractorsFactory extractorsFactory = 181*30877f79SAndroid Build Coastguard Worker new DefaultExtractorsFactory() 182*30877f79SAndroid Build Coastguard Worker .setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING); 183*30877f79SAndroid Build Coastguard Worker 184*30877f79SAndroid Build Coastguard WorkerExoPlayer player = new ExoPlayer.Builder(context) 185*30877f79SAndroid Build Coastguard Worker .setMediaSourceFactory( 186*30877f79SAndroid Build Coastguard Worker new DefaultMediaSourceFactory(context, extractorsFactory)) 187*30877f79SAndroid Build Coastguard Worker .build(); 188*30877f79SAndroid Build Coastguard Worker~~~ 189*30877f79SAndroid Build Coastguard Worker{: .language-java} 190*30877f79SAndroid Build Coastguard Worker 191*30877f79SAndroid Build Coastguard Worker### Enabling constant bitrate seeking ### 192*30877f79SAndroid Build Coastguard Worker 193*30877f79SAndroid Build Coastguard WorkerFor MP3, ADTS and AMR streams, you can enable approximate seeking using a 194*30877f79SAndroid Build Coastguard Workerconstant bitrate assumption with `FLAG_ENABLE_CONSTANT_BITRATE_SEEKING` flags. 195*30877f79SAndroid Build Coastguard WorkerThese flags can be set for individual extractors using the individual 196*30877f79SAndroid Build Coastguard Worker`DefaultExtractorsFactory.setXyzExtractorFlags` methods as described above. To 197*30877f79SAndroid Build Coastguard Workerenable constant bitrate seeking for all extractors that support it, use 198*30877f79SAndroid Build Coastguard Worker`DefaultExtractorsFactory.setConstantBitrateSeekingEnabled`. 199*30877f79SAndroid Build Coastguard Worker 200*30877f79SAndroid Build Coastguard Worker~~~ 201*30877f79SAndroid Build Coastguard WorkerDefaultExtractorsFactory extractorsFactory = 202*30877f79SAndroid Build Coastguard Worker new DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true); 203*30877f79SAndroid Build Coastguard Worker~~~ 204*30877f79SAndroid Build Coastguard Worker{: .language-java} 205*30877f79SAndroid Build Coastguard Worker 206*30877f79SAndroid Build Coastguard WorkerThe `ExtractorsFactory` can then be injected via `DefaultMediaSourceFactory` as 207*30877f79SAndroid Build Coastguard Workerdescribed for customizing extractor flags above. 208*30877f79SAndroid Build Coastguard Worker 209*30877f79SAndroid Build Coastguard Worker## MediaSource customization ## 210*30877f79SAndroid Build Coastguard Worker 211*30877f79SAndroid Build Coastguard WorkerThe examples above inject customized components for use during playback of all 212*30877f79SAndroid Build Coastguard Worker`MediaItem`s that are passed to the player. Where fine-grained customization is 213*30877f79SAndroid Build Coastguard Workerrequired, it's also possible to inject customized components into individual 214*30877f79SAndroid Build Coastguard Worker`MediaSource` instances, which can be passed directly to the player. The example 215*30877f79SAndroid Build Coastguard Workerbelow shows how to customize a `ProgressiveMediaSource` to use a custom 216*30877f79SAndroid Build Coastguard Worker`DataSource.Factory`, `ExtractorsFactory` and `LoadErrorHandlingPolicy`: 217*30877f79SAndroid Build Coastguard Worker 218*30877f79SAndroid Build Coastguard Worker~~~ 219*30877f79SAndroid Build Coastguard WorkerProgressiveMediaSource mediaSource = 220*30877f79SAndroid Build Coastguard Worker new ProgressiveMediaSource.Factory( 221*30877f79SAndroid Build Coastguard Worker customDataSourceFactory, customExtractorsFactory) 222*30877f79SAndroid Build Coastguard Worker .setLoadErrorHandlingPolicy(customLoadErrorHandlingPolicy) 223*30877f79SAndroid Build Coastguard Worker .createMediaSource(MediaItem.fromUri(streamUri)); 224*30877f79SAndroid Build Coastguard Worker~~~ 225*30877f79SAndroid Build Coastguard Worker{: .language-java} 226*30877f79SAndroid Build Coastguard Worker 227*30877f79SAndroid Build Coastguard Worker## Creating custom components ## 228*30877f79SAndroid Build Coastguard Worker 229*30877f79SAndroid Build Coastguard WorkerThe library provides default implementations of the components listed at the top 230*30877f79SAndroid Build Coastguard Workerof this page for common use cases. An `ExoPlayer` can use these components, but 231*30877f79SAndroid Build Coastguard Workermay also be built to use custom implementations if non-standard behaviors are 232*30877f79SAndroid Build Coastguard Workerrequired. Some use cases for custom implementations are: 233*30877f79SAndroid Build Coastguard Worker 234*30877f79SAndroid Build Coastguard Worker* `Renderer` – You may want to implement a custom `Renderer` to handle a 235*30877f79SAndroid Build Coastguard Worker media type not supported by the default implementations provided by the 236*30877f79SAndroid Build Coastguard Worker library. 237*30877f79SAndroid Build Coastguard Worker* `TrackSelector` – Implementing a custom `TrackSelector` allows an app 238*30877f79SAndroid Build Coastguard Worker developer to change the way in which tracks exposed by a `MediaSource` are 239*30877f79SAndroid Build Coastguard Worker selected for consumption by each of the available `Renderer`s. 240*30877f79SAndroid Build Coastguard Worker* `LoadControl` – Implementing a custom `LoadControl` allows an app 241*30877f79SAndroid Build Coastguard Worker developer to change the player's buffering policy. 242*30877f79SAndroid Build Coastguard Worker* `Extractor` – If you need to support a container format not currently 243*30877f79SAndroid Build Coastguard Worker supported by the library, consider implementing a custom `Extractor` class. 244*30877f79SAndroid Build Coastguard Worker* `MediaSource` – Implementing a custom `MediaSource` class may be 245*30877f79SAndroid Build Coastguard Worker appropriate if you wish to obtain media samples to feed to renderers in a 246*30877f79SAndroid Build Coastguard Worker custom way, or if you wish to implement custom `MediaSource` compositing 247*30877f79SAndroid Build Coastguard Worker behavior. 248*30877f79SAndroid Build Coastguard Worker* `MediaSource.Factory` – Implementing a custom `MediaSource.Factory` 249*30877f79SAndroid Build Coastguard Worker allows an application to customize the way in which `MediaSource`s are created 250*30877f79SAndroid Build Coastguard Worker from `MediaItem`s. 251*30877f79SAndroid Build Coastguard Worker* `DataSource` – ExoPlayer’s upstream package already contains a number of 252*30877f79SAndroid Build Coastguard Worker `DataSource` implementations for different use cases. You may want to 253*30877f79SAndroid Build Coastguard Worker implement you own `DataSource` class to load data in another way, such as over 254*30877f79SAndroid Build Coastguard Worker a custom protocol, using a custom HTTP stack, or from a custom persistent 255*30877f79SAndroid Build Coastguard Worker cache. 256*30877f79SAndroid Build Coastguard Worker 257*30877f79SAndroid Build Coastguard WorkerWhen building custom components, we recommend the following: 258*30877f79SAndroid Build Coastguard Worker 259*30877f79SAndroid Build Coastguard Worker* If a custom component needs to report events back to the app, we recommend 260*30877f79SAndroid Build Coastguard Worker that you do so using the same model as existing ExoPlayer components, for 261*30877f79SAndroid Build Coastguard Worker example using `EventDispatcher` classes or passing a `Handler` together with 262*30877f79SAndroid Build Coastguard Worker a listener to the constructor of the component. 263*30877f79SAndroid Build Coastguard Worker* We recommended that custom components use the same model as existing ExoPlayer 264*30877f79SAndroid Build Coastguard Worker components to allow reconfiguration by the app during playback. To do this, 265*30877f79SAndroid Build Coastguard Worker custom components should implement `PlayerMessage.Target` and receive 266*30877f79SAndroid Build Coastguard Worker configuration changes in the `handleMessage` method. Application code should 267*30877f79SAndroid Build Coastguard Worker pass configuration changes by calling ExoPlayer’s `createMessage` method, 268*30877f79SAndroid Build Coastguard Worker configuring the message, and sending it to the component using 269*30877f79SAndroid Build Coastguard Worker `PlayerMessage.send`. Sending messages to be delivered on the playback thread 270*30877f79SAndroid Build Coastguard Worker ensures that they are executed in order with any other operations being 271*30877f79SAndroid Build Coastguard Worker performed on the player. 272*30877f79SAndroid Build Coastguard Worker 273*30877f79SAndroid Build Coastguard Worker[Cronet extension]: https://github.com/google/ExoPlayer/tree/release-v2/extensions/cronet 274*30877f79SAndroid Build Coastguard Worker[OkHttp extension]: https://github.com/google/ExoPlayer/tree/release-v2/extensions/okhttp 275*30877f79SAndroid Build Coastguard Worker[LoadErrorHandlingPolicy]: {{ site.exo_sdk }}/upstream/LoadErrorHandlingPolicy.html 276*30877f79SAndroid Build Coastguard Worker[media source based playlist API]: {{ site.baseurl }}/media-sources.html#media-source-based-playlist-api 277*30877f79SAndroid Build Coastguard Worker 278