1*30877f79SAndroid Build Coastguard Worker--- 2*30877f79SAndroid Build Coastguard Workertitle: Ad insertion 3*30877f79SAndroid Build Coastguard Worker--- 4*30877f79SAndroid Build Coastguard Worker 5*30877f79SAndroid Build Coastguard WorkerExoPlayer can be used for both client-side and server-side ad insertion. 6*30877f79SAndroid Build Coastguard Worker 7*30877f79SAndroid Build Coastguard Worker## Client-side ad insertion ## 8*30877f79SAndroid Build Coastguard Worker 9*30877f79SAndroid Build Coastguard WorkerIn client-side ad insertion, the player switches between loading media from 10*30877f79SAndroid Build Coastguard Workerdifferent URLs as it transitions between playing content and ads. Information 11*30877f79SAndroid Build Coastguard Workerabout ads is loaded separately from the media, such as from an XML [VAST][] or 12*30877f79SAndroid Build Coastguard Worker[VMAP][] ad tag. This can include ad cue positions relative to the start of the 13*30877f79SAndroid Build Coastguard Workercontent, the actual ad media URIs and metadata such as whether a given ad is 14*30877f79SAndroid Build Coastguard Workerskippable. 15*30877f79SAndroid Build Coastguard Worker 16*30877f79SAndroid Build Coastguard WorkerWhen using ExoPlayer's `AdsMediaSource` for client-side ad insertion, the player 17*30877f79SAndroid Build Coastguard Workerhas information about the ads to be played. This has several benefits: 18*30877f79SAndroid Build Coastguard Worker 19*30877f79SAndroid Build Coastguard Worker* The player can expose metadata and functionality relating to ads via its API. 20*30877f79SAndroid Build Coastguard Worker* [ExoPlayer UI components][] can show markers for ad positions automatically, 21*30877f79SAndroid Build Coastguard Worker and change their behavior depending on whether ad is playing. 22*30877f79SAndroid Build Coastguard Worker* Internally, the player can keep a consistent buffer across transitions between 23*30877f79SAndroid Build Coastguard Worker ads and content. 24*30877f79SAndroid Build Coastguard Worker 25*30877f79SAndroid Build Coastguard WorkerIn this setup, the player takes care of switching between ads and content, which 26*30877f79SAndroid Build Coastguard Workermeans that apps don't need to take care of controlling multiple separate 27*30877f79SAndroid Build Coastguard Workerbackground/foreground players for ads and content. 28*30877f79SAndroid Build Coastguard Worker 29*30877f79SAndroid Build Coastguard WorkerWhen preparing content videos and ad tags for use with client-side ad insertion, 30*30877f79SAndroid Build Coastguard Workerads should ideally be positioned at synchronization samples (keyframes) in the 31*30877f79SAndroid Build Coastguard Workercontent video so that the player can resume content playback seamlessly. 32*30877f79SAndroid Build Coastguard Worker 33*30877f79SAndroid Build Coastguard Worker### Declarative ad support ### 34*30877f79SAndroid Build Coastguard Worker 35*30877f79SAndroid Build Coastguard WorkerAn ad tag URI can be specified when building a `MediaItem`: 36*30877f79SAndroid Build Coastguard Worker 37*30877f79SAndroid Build Coastguard Worker~~~ 38*30877f79SAndroid Build Coastguard WorkerMediaItem mediaItem = 39*30877f79SAndroid Build Coastguard Worker new MediaItem.Builder() 40*30877f79SAndroid Build Coastguard Worker .setUri(videoUri) 41*30877f79SAndroid Build Coastguard Worker .setAdsConfiguration( 42*30877f79SAndroid Build Coastguard Worker new MediaItem.AdsConfiguration.Builder(adTagUri).build()) 43*30877f79SAndroid Build Coastguard Worker .build(); 44*30877f79SAndroid Build Coastguard Worker~~~ 45*30877f79SAndroid Build Coastguard Worker{: .language-java} 46*30877f79SAndroid Build Coastguard Worker 47*30877f79SAndroid Build Coastguard WorkerTo enable player support for media items that specify ad tags, it's necessary to 48*30877f79SAndroid Build Coastguard Workerbuild and inject a `DefaultMediaSourceFactory` configured with an 49*30877f79SAndroid Build Coastguard Worker`AdsLoader.Provider` and an `AdViewProvider` when creating the player: 50*30877f79SAndroid Build Coastguard Worker 51*30877f79SAndroid Build Coastguard Worker~~~ 52*30877f79SAndroid Build Coastguard WorkerMediaSource.Factory mediaSourceFactory = 53*30877f79SAndroid Build Coastguard Worker new DefaultMediaSourceFactory(context) 54*30877f79SAndroid Build Coastguard Worker .setAdsLoaderProvider(adsLoaderProvider) 55*30877f79SAndroid Build Coastguard Worker .setAdViewProvider(playerView); 56*30877f79SAndroid Build Coastguard WorkerExoPlayer player = new ExoPlayer.Builder(context) 57*30877f79SAndroid Build Coastguard Worker .setMediaSourceFactory(mediaSourceFactory) 58*30877f79SAndroid Build Coastguard Worker .build(); 59*30877f79SAndroid Build Coastguard Worker~~~ 60*30877f79SAndroid Build Coastguard Worker{: .language-java} 61*30877f79SAndroid Build Coastguard Worker 62*30877f79SAndroid Build Coastguard WorkerInternally, `DefaultMediaSourceFactory` will wrap the content media source in an 63*30877f79SAndroid Build Coastguard Worker`AdsMediaSource`. The `AdsMediaSource` will obtain an `AdsLoader` from the 64*30877f79SAndroid Build Coastguard Worker`AdsLoader.Provider` and use it to insert ads as defined by the media item's ad 65*30877f79SAndroid Build Coastguard Workertag. 66*30877f79SAndroid Build Coastguard Worker 67*30877f79SAndroid Build Coastguard WorkerExoPlayer's `StyledPlayerView` implements `AdViewProvider`. The IMA extension 68*30877f79SAndroid Build Coastguard Workerprovides an easy to use `AdsLoader`, as described below. 69*30877f79SAndroid Build Coastguard Worker 70*30877f79SAndroid Build Coastguard Worker### Playlists with ads ### 71*30877f79SAndroid Build Coastguard Worker 72*30877f79SAndroid Build Coastguard WorkerWhen playing a [playlist][] with multiple media items, the default behavior is 73*30877f79SAndroid Build Coastguard Workerto request the ad tag and store ad playback state once for each media ID, 74*30877f79SAndroid Build Coastguard Workercontent URI and ad tag URI combination. This means that users will see ads for 75*30877f79SAndroid Build Coastguard Workerevery media item with ads that has a distinct media ID or content URI, even if 76*30877f79SAndroid Build Coastguard Workerthe ad tag URIs match. If a media item is repeated, the user will see the 77*30877f79SAndroid Build Coastguard Workercorresponding ads only once (the ad playback state stores whether ads have been 78*30877f79SAndroid Build Coastguard Workerplayed, so they are skipped after their first occurrence). 79*30877f79SAndroid Build Coastguard Worker 80*30877f79SAndroid Build Coastguard WorkerIt's possible to customize this behavior by passing an opaque ads identifier 81*30877f79SAndroid Build Coastguard Workerwith which ad playback state for a given media item is linked, based on object 82*30877f79SAndroid Build Coastguard Workerequality. Here is an example where ad playback state is linked to the ad tag 83*30877f79SAndroid Build Coastguard WorkerURI only, rather than the combination of the media ID and ad tag URI, by 84*30877f79SAndroid Build Coastguard Workerpassing the ad tag URI as the ads identifier. The effect is that ads will load 85*30877f79SAndroid Build Coastguard Workeronly once and the user will not see ads on the second item when playing the 86*30877f79SAndroid Build Coastguard Workerplaylist from start to finish. 87*30877f79SAndroid Build Coastguard Worker 88*30877f79SAndroid Build Coastguard Worker~~~ 89*30877f79SAndroid Build Coastguard Worker// Build the media items, passing the same ads identifier for both items, 90*30877f79SAndroid Build Coastguard Worker// which means they share ad playback state so ads play only once. 91*30877f79SAndroid Build Coastguard WorkerMediaItem firstItem = 92*30877f79SAndroid Build Coastguard Worker new MediaItem.Builder() 93*30877f79SAndroid Build Coastguard Worker .setUri(firstVideoUri) 94*30877f79SAndroid Build Coastguard Worker .setAdsConfiguration( 95*30877f79SAndroid Build Coastguard Worker new MediaItem.AdsConfiguration.Builder(adTagUri) 96*30877f79SAndroid Build Coastguard Worker .setAdsId(adTagUri) 97*30877f79SAndroid Build Coastguard Worker .build()) 98*30877f79SAndroid Build Coastguard Worker .build(); 99*30877f79SAndroid Build Coastguard WorkerMediaItem secondItem = 100*30877f79SAndroid Build Coastguard Worker new MediaItem.Builder() 101*30877f79SAndroid Build Coastguard Worker .setUri(secondVideoUri) 102*30877f79SAndroid Build Coastguard Worker .setAdsConfiguration( 103*30877f79SAndroid Build Coastguard Worker new MediaItem.AdsConfiguration.Builder(adTagUri) 104*30877f79SAndroid Build Coastguard Worker .setAdsId(adTagUri) 105*30877f79SAndroid Build Coastguard Worker .build()) 106*30877f79SAndroid Build Coastguard Worker .build(); 107*30877f79SAndroid Build Coastguard Workerplayer.addMediaItem(firstItem); 108*30877f79SAndroid Build Coastguard Workerplayer.addMediaItem(secondItem); 109*30877f79SAndroid Build Coastguard Worker~~~ 110*30877f79SAndroid Build Coastguard Worker{: .language-java} 111*30877f79SAndroid Build Coastguard Worker 112*30877f79SAndroid Build Coastguard Worker### IMA extension ### 113*30877f79SAndroid Build Coastguard Worker 114*30877f79SAndroid Build Coastguard WorkerThe [ExoPlayer IMA extension][] provides `ImaAdsLoader`, making it easy to 115*30877f79SAndroid Build Coastguard Workerintegrate client-side ad insertion into your app. It wraps the functionality of 116*30877f79SAndroid Build Coastguard Workerthe [client-side IMA SDK][] to support insertion of VAST/VMAP ads. For 117*30877f79SAndroid Build Coastguard Workerinstructions on how to use the extension, including how to handle backgrounding 118*30877f79SAndroid Build Coastguard Workerand resuming playback, please see the [README][]. 119*30877f79SAndroid Build Coastguard Worker 120*30877f79SAndroid Build Coastguard WorkerThe [demo application][] uses the IMA extension, and includes several sample 121*30877f79SAndroid Build Coastguard WorkerVAST/VMAP ad tags in the sample list. 122*30877f79SAndroid Build Coastguard Worker 123*30877f79SAndroid Build Coastguard Worker#### UI considerations #### 124*30877f79SAndroid Build Coastguard Worker 125*30877f79SAndroid Build Coastguard Worker`StyledPlayerView` hides its transport controls during playback of ads by 126*30877f79SAndroid Build Coastguard Workerdefault, but apps can toggle this behavior by calling 127*30877f79SAndroid Build Coastguard Worker`setControllerHideDuringAds`. The IMA SDK will show additional views on top of 128*30877f79SAndroid Build Coastguard Workerthe player while an ad is playing (e.g., a 'more info' link and a skip button, 129*30877f79SAndroid Build Coastguard Workerif applicable). 130*30877f79SAndroid Build Coastguard Worker 131*30877f79SAndroid Build Coastguard WorkerSince advertisers expect a consistent experience across apps, the IMA SDK does 132*30877f79SAndroid Build Coastguard Workernot allow customization of the views that it shows while an ad is playing. It is 133*30877f79SAndroid Build Coastguard Workertherefore not possible to remove or reposition the skip button, change the 134*30877f79SAndroid Build Coastguard Workerfonts, or make other customizations to the visual appearance of these views. 135*30877f79SAndroid Build Coastguard Worker{:.info} 136*30877f79SAndroid Build Coastguard Worker 137*30877f79SAndroid Build Coastguard WorkerThe IMA SDK may report whether ads are obscured by application provided views 138*30877f79SAndroid Build Coastguard Workerrendered on top of the player. Apps that need to overlay views that are 139*30877f79SAndroid Build Coastguard Workeressential for controlling playback must register them with the IMA SDK so that 140*30877f79SAndroid Build Coastguard Workerthey can be omitted from viewability calculations. When using `StyledPlayerView` 141*30877f79SAndroid Build Coastguard Workeras the `AdViewProvider`, it will automatically register its control overlays. 142*30877f79SAndroid Build Coastguard WorkerApps that use a custom player UI must register overlay views by returning them 143*30877f79SAndroid Build Coastguard Workerfrom `AdViewProvider.getAdOverlayInfos`. 144*30877f79SAndroid Build Coastguard Worker 145*30877f79SAndroid Build Coastguard WorkerFor more information about overlay views, see 146*30877f79SAndroid Build Coastguard Worker[Open Measurement in the IMA SDK][]. 147*30877f79SAndroid Build Coastguard Worker 148*30877f79SAndroid Build Coastguard Worker#### Companion ads #### 149*30877f79SAndroid Build Coastguard Worker 150*30877f79SAndroid Build Coastguard WorkerSome ad tags contain additional companion ads that can be shown in 'slots' in an 151*30877f79SAndroid Build Coastguard Workerapp UI. These slots can be passed via 152*30877f79SAndroid Build Coastguard Worker`ImaAdsLoader.Builder.setCompanionAdSlots(slots)`. For more information see 153*30877f79SAndroid Build Coastguard Worker[Adding Companion Ads][]. 154*30877f79SAndroid Build Coastguard Worker 155*30877f79SAndroid Build Coastguard Worker#### Standalone ads #### 156*30877f79SAndroid Build Coastguard Worker 157*30877f79SAndroid Build Coastguard WorkerThe IMA SDK is designed for inserting ads into media content, not for playing 158*30877f79SAndroid Build Coastguard Workerstandalone ads by themselves. Hence playback of standalone ads is not supported 159*30877f79SAndroid Build Coastguard Workerby the IMA extension. We recommend using the [Google Mobile Ads SDK][] instead 160*30877f79SAndroid Build Coastguard Workerfor this use case. 161*30877f79SAndroid Build Coastguard Worker 162*30877f79SAndroid Build Coastguard Worker### Using a third-party ads SDK ### 163*30877f79SAndroid Build Coastguard Worker 164*30877f79SAndroid Build Coastguard WorkerIf you need to load ads via a third-party ads SDK, it's worth checking whether 165*30877f79SAndroid Build Coastguard Workerit already provides an ExoPlayer integration. If not, implementing a custom 166*30877f79SAndroid Build Coastguard Worker`AdsLoader` that wraps the third-party ads SDK is the recommended approach, 167*30877f79SAndroid Build Coastguard Workersince it provides the benefits of `AdsMediaSource` described above. 168*30877f79SAndroid Build Coastguard Worker`ImaAdsLoader` acts as an example implementation. 169*30877f79SAndroid Build Coastguard Worker 170*30877f79SAndroid Build Coastguard WorkerAlternatively, you can use ExoPlayer's [playlist support][] to build a sequence 171*30877f79SAndroid Build Coastguard Workerof ads and content clips: 172*30877f79SAndroid Build Coastguard Worker 173*30877f79SAndroid Build Coastguard Worker~~~ 174*30877f79SAndroid Build Coastguard Worker// A pre-roll ad. 175*30877f79SAndroid Build Coastguard WorkerMediaItem preRollAd = MediaItem.fromUri(preRollAdUri); 176*30877f79SAndroid Build Coastguard Worker// The start of the content. 177*30877f79SAndroid Build Coastguard WorkerMediaItem contentStart = 178*30877f79SAndroid Build Coastguard Worker new MediaItem.Builder() 179*30877f79SAndroid Build Coastguard Worker .setUri(contentUri) 180*30877f79SAndroid Build Coastguard Worker .setClippingConfiguration( 181*30877f79SAndroid Build Coastguard Worker new ClippingConfiguration.Builder() 182*30877f79SAndroid Build Coastguard Worker .setEndPositionMs(120_000) 183*30877f79SAndroid Build Coastguard Worker .build()) 184*30877f79SAndroid Build Coastguard Worker .build(); 185*30877f79SAndroid Build Coastguard Worker// A mid-roll ad. 186*30877f79SAndroid Build Coastguard WorkerMediaItem midRollAd = MediaItem.fromUri(midRollAdUri); 187*30877f79SAndroid Build Coastguard Worker// The rest of the content 188*30877f79SAndroid Build Coastguard WorkerMediaItem contentEnd = 189*30877f79SAndroid Build Coastguard Worker new MediaItem.Builder() 190*30877f79SAndroid Build Coastguard Worker .setUri(contentUri) 191*30877f79SAndroid Build Coastguard Worker .setClippingConfiguration( 192*30877f79SAndroid Build Coastguard Worker new ClippingConfiguration.Builder() 193*30877f79SAndroid Build Coastguard Worker .setStartPositionMs(120_000) 194*30877f79SAndroid Build Coastguard Worker .build()) 195*30877f79SAndroid Build Coastguard Worker .build(); 196*30877f79SAndroid Build Coastguard Worker 197*30877f79SAndroid Build Coastguard Worker// Build the playlist. 198*30877f79SAndroid Build Coastguard Workerplayer.addMediaItem(preRollAd); 199*30877f79SAndroid Build Coastguard Workerplayer.addMediaItem(contentStart); 200*30877f79SAndroid Build Coastguard Workerplayer.addMediaItem(midRollAd); 201*30877f79SAndroid Build Coastguard Workerplayer.addMediaItem(contentEnd); 202*30877f79SAndroid Build Coastguard Worker~~~ 203*30877f79SAndroid Build Coastguard Worker{: .language-java} 204*30877f79SAndroid Build Coastguard Worker 205*30877f79SAndroid Build Coastguard Worker## Server-side ad insertion ## 206*30877f79SAndroid Build Coastguard Worker 207*30877f79SAndroid Build Coastguard WorkerIn server-side ad insertion (also called dynamic ad insertion, or DAI), the 208*30877f79SAndroid Build Coastguard Workermedia stream contains both ads and content. A DASH manifest may point to both 209*30877f79SAndroid Build Coastguard Workercontent and ad segments, possibly in separate periods. For HLS, see the Apple 210*30877f79SAndroid Build Coastguard Workerdocumentation on [incorporating ads into a playlist][]. 211*30877f79SAndroid Build Coastguard Worker 212*30877f79SAndroid Build Coastguard WorkerWhen using server-side ad insertion, the client may need to resolve the media 213*30877f79SAndroid Build Coastguard WorkerURL dynamically to get the stitched stream, it may need to display ads overlays 214*30877f79SAndroid Build Coastguard Workerin the UI or it may need to report events to an ads SDK or ad server. 215*30877f79SAndroid Build Coastguard Worker 216*30877f79SAndroid Build Coastguard WorkerExoPlayer's `DefaultMediaSourceFactory` can delegate all these tasks to a 217*30877f79SAndroid Build Coastguard Workerserver-side ad insertion `MediaSource` for URIs using the `ssai://` scheme: 218*30877f79SAndroid Build Coastguard Worker 219*30877f79SAndroid Build Coastguard Worker``` 220*30877f79SAndroid Build Coastguard WorkerPlayer player = 221*30877f79SAndroid Build Coastguard Worker new ExoPlayer.Builder(context) 222*30877f79SAndroid Build Coastguard Worker .setMediaSourceFactory( 223*30877f79SAndroid Build Coastguard Worker new DefaultMediaSourceFactory(dataSourceFactory) 224*30877f79SAndroid Build Coastguard Worker .setServerSideAdInsertionMediaSourceFactory(ssaiFactory)) 225*30877f79SAndroid Build Coastguard Worker .build(); 226*30877f79SAndroid Build Coastguard Worker``` 227*30877f79SAndroid Build Coastguard Worker 228*30877f79SAndroid Build Coastguard Worker### IMA extension ### 229*30877f79SAndroid Build Coastguard Worker 230*30877f79SAndroid Build Coastguard WorkerThe [ExoPlayer IMA extension][] provides `ImaServerSideAdInsertionMediaSource`, 231*30877f79SAndroid Build Coastguard Workermaking it easy to integrate with IMA's server-side inserted ad streams in your 232*30877f79SAndroid Build Coastguard Workerapp. It wraps the functionality of the [IMA DAI SDK for Android][] and fully 233*30877f79SAndroid Build Coastguard Workerintegrates the provided ad metadata into the player. For example, this allows 234*30877f79SAndroid Build Coastguard Workeryou to use methods like `Player.isPlayingAd()`, listen to content-ad transitions 235*30877f79SAndroid Build Coastguard Workerand let the player handle ad playback logic like skipping already played ads. 236*30877f79SAndroid Build Coastguard Worker 237*30877f79SAndroid Build Coastguard WorkerIn order to use this class, you need to set up the 238*30877f79SAndroid Build Coastguard Worker`ImaServerSideAdInsertionMediaSource.AdsLoader` and the 239*30877f79SAndroid Build Coastguard Worker`ImaServerSideAdInsertionMediaSource.Factory` and connect them to the player: 240*30877f79SAndroid Build Coastguard Worker 241*30877f79SAndroid Build Coastguard Worker``` 242*30877f79SAndroid Build Coastguard Worker// MediaSource.Factory to load the actual media stream. 243*30877f79SAndroid Build Coastguard WorkerDefaultMediaSourceFactory defaultMediaSourceFactory = 244*30877f79SAndroid Build Coastguard Worker new DefaultMediaSourceFactory(dataSourceFactory); 245*30877f79SAndroid Build Coastguard Worker// AdsLoader that can be reused for multiple playbacks. 246*30877f79SAndroid Build Coastguard WorkerImaServerSideAdInsertionMediaSource.AdsLoader adsLoader = 247*30877f79SAndroid Build Coastguard Worker new ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(context, adViewProvider) 248*30877f79SAndroid Build Coastguard Worker .build(); 249*30877f79SAndroid Build Coastguard Worker// MediaSource.Factory to create the ad sources for the current player. 250*30877f79SAndroid Build Coastguard WorkerImaServerSideAdInsertionMediaSource.Factory adsMediaSourceFactory = 251*30877f79SAndroid Build Coastguard Worker new ImaServerSideAdInsertionMediaSource.Factory(adsLoader, defaultMediaSourceFactory); 252*30877f79SAndroid Build Coastguard Worker// Configure DefaultMediaSourceFactory to create both IMA DAI sources and 253*30877f79SAndroid Build Coastguard Worker// regular media sources. If you just play IMA DAI streams, you can also use 254*30877f79SAndroid Build Coastguard Worker// adsMediaSourceFactory directly. 255*30877f79SAndroid Build Coastguard WorkerdefaultMediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory); 256*30877f79SAndroid Build Coastguard Worker// Set the MediaSource.Factory on the Player. 257*30877f79SAndroid Build Coastguard WorkerPlayer player = 258*30877f79SAndroid Build Coastguard Worker new ExoPlayer.Builder(context) 259*30877f79SAndroid Build Coastguard Worker .setMediaSourceFactory(defaultMediaSourceFactory) 260*30877f79SAndroid Build Coastguard Worker .build(); 261*30877f79SAndroid Build Coastguard Worker// Set the player on the AdsLoader 262*30877f79SAndroid Build Coastguard WorkeradsLoader.setPlayer(player); 263*30877f79SAndroid Build Coastguard Worker``` 264*30877f79SAndroid Build Coastguard Worker 265*30877f79SAndroid Build Coastguard WorkerLoad your IMA asset key, or content source id and video id, by building an URL 266*30877f79SAndroid Build Coastguard Workerwith `ImaServerSideAdInsertionUriBuilder`: 267*30877f79SAndroid Build Coastguard Worker 268*30877f79SAndroid Build Coastguard Worker``` 269*30877f79SAndroid Build Coastguard WorkerUri ssaiUri = 270*30877f79SAndroid Build Coastguard Worker new ImaServerSideAdInsertionUriBuilder().setAssetKey(assetKey).build(); 271*30877f79SAndroid Build Coastguard Workerplayer.setMediaItem(MediaItem.fromUri(ssaiUri)); 272*30877f79SAndroid Build Coastguard Worker``` 273*30877f79SAndroid Build Coastguard Worker 274*30877f79SAndroid Build Coastguard WorkerFinally, release your ads loader once it's no longer used: 275*30877f79SAndroid Build Coastguard Worker``` 276*30877f79SAndroid Build Coastguard WorkeradsLoader.release(); 277*30877f79SAndroid Build Coastguard Worker``` 278*30877f79SAndroid Build Coastguard Worker 279*30877f79SAndroid Build Coastguard WorkerCurrently only a single IMA server-side ad insertion stream is supported in the 280*30877f79SAndroid Build Coastguard Workersame playlist. You can combine the stream with other media but not with another 281*30877f79SAndroid Build Coastguard WorkerIMA server-side ad insertion stream. 282*30877f79SAndroid Build Coastguard Worker{:.info} 283*30877f79SAndroid Build Coastguard Worker 284*30877f79SAndroid Build Coastguard Worker#### UI considerations #### 285*30877f79SAndroid Build Coastguard Worker 286*30877f79SAndroid Build Coastguard WorkerThe same [UI considerations as for client-side ad insertion][] apply to 287*30877f79SAndroid Build Coastguard Workerserver-side ad insertion too. 288*30877f79SAndroid Build Coastguard Worker 289*30877f79SAndroid Build Coastguard Worker#### Companion ads #### 290*30877f79SAndroid Build Coastguard Worker 291*30877f79SAndroid Build Coastguard WorkerSome ad tags contain additional companion ads that can be shown in 'slots' in an 292*30877f79SAndroid Build Coastguard Workerapp UI. These slots can be passed via 293*30877f79SAndroid Build Coastguard Worker`ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots)`. 294*30877f79SAndroid Build Coastguard WorkerFor more information see [Adding Companion Ads][]. 295*30877f79SAndroid Build Coastguard Worker 296*30877f79SAndroid Build Coastguard Worker### Using a third-party ads SDK ### 297*30877f79SAndroid Build Coastguard Worker 298*30877f79SAndroid Build Coastguard WorkerIf you need to load ads via a third-party ads SDK, it’s worth checking whether 299*30877f79SAndroid Build Coastguard Workerit already provides an ExoPlayer integration. If not, it's recommended to 300*30877f79SAndroid Build Coastguard Workerprovide a custom `MediaSource` that accepts URIs with the `ssai://` scheme 301*30877f79SAndroid Build Coastguard Workersimilar to `ImaServerSideAdInsertionMediaSource`. 302*30877f79SAndroid Build Coastguard Worker 303*30877f79SAndroid Build Coastguard WorkerThe actual logic of creating the ad structure can be delegated to the general 304*30877f79SAndroid Build Coastguard Workerpurpose `ServerSideAdInsertionMediaSource`, which wraps a stream `MediaSource` 305*30877f79SAndroid Build Coastguard Workerand allows the user to set and update the `AdPlaybackState` representing the ad 306*30877f79SAndroid Build Coastguard Workermetadata. 307*30877f79SAndroid Build Coastguard Worker 308*30877f79SAndroid Build Coastguard WorkerOften, server-side inserted ad streams contain timed events to notify the player 309*30877f79SAndroid Build Coastguard Workerabout ad metadata. Please see [supported formats][] for information on what 310*30877f79SAndroid Build Coastguard Workertimed metadata formats are supported by ExoPlayer. Custom ads SDK `MediaSource`s 311*30877f79SAndroid Build Coastguard Workercan listen for timed metadata events from the player, e.g., via 312*30877f79SAndroid Build Coastguard Worker`ExoPlayer.addMetadataOutput`. 313*30877f79SAndroid Build Coastguard Worker 314*30877f79SAndroid Build Coastguard Worker[VAST]: https://www.iab.com/wp-content/uploads/2015/06/VASTv3_0.pdf 315*30877f79SAndroid Build Coastguard Worker[VMAP]: https://www.iab.com/guidelines/digital-video-multiple-ad-playlist-vmap-1-0-1/ 316*30877f79SAndroid Build Coastguard Worker[ExoPlayer UI components]: {{ site.baseurl }}/ui-components.html 317*30877f79SAndroid Build Coastguard Worker[ExoPlayer IMA extension]: https://github.com/google/ExoPlayer/tree/release-v2/extensions/ima 318*30877f79SAndroid Build Coastguard Worker[client-side IMA SDK]: https://developers.google.com/interactive-media-ads/docs/sdks/android 319*30877f79SAndroid Build Coastguard Worker[README]: https://github.com/google/ExoPlayer/tree/release-v2/extensions/ima 320*30877f79SAndroid Build Coastguard Worker[demo application]: {{ site.baseurl }}/demo-application.html 321*30877f79SAndroid Build Coastguard Worker[Open Measurement in the IMA SDK]: https://developers.google.com/interactive-media-ads/docs/sdks/android/omsdk 322*30877f79SAndroid Build Coastguard Worker[Adding Companion Ads]: https://developers.google.com/interactive-media-ads/docs/sdks/android/companions 323*30877f79SAndroid Build Coastguard Worker[playlist]: {{ site.baseurl }}/playlists.html 324*30877f79SAndroid Build Coastguard Worker[playlist support]: {{ site.baseurl }}/playlists.html 325*30877f79SAndroid Build Coastguard Worker[incorporating ads into a playlist]: https://developer.apple.com/documentation/http_live_streaming/example_playlists_for_http_live_streaming/incorporating_ads_into_a_playlist 326*30877f79SAndroid Build Coastguard Worker[supported formats]: {{ site.baseurl }}/supported-formats.html 327*30877f79SAndroid Build Coastguard Worker[Google Mobile Ads SDK]: https://developers.google.com/admob/android/quick-start 328*30877f79SAndroid Build Coastguard Worker[IMA DAI SDK for Android]: https://developers.google.com/interactive-media-ads/docs/sdks/android/dai 329*30877f79SAndroid Build Coastguard Worker[UI considerations as for client-side ad insertion]: #ui-considerations 330