1--- 2title: Ad insertion 3--- 4 5ExoPlayer can be used for both client-side and server-side ad insertion. 6 7## Client-side ad insertion ## 8 9In client-side ad insertion, the player switches between loading media from 10different URLs as it transitions between playing content and ads. Information 11about ads is loaded separately from the media, such as from an XML [VAST][] or 12[VMAP][] ad tag. This can include ad cue positions relative to the start of the 13content, the actual ad media URIs and metadata such as whether a given ad is 14skippable. 15 16When using ExoPlayer's `AdsMediaSource` for client-side ad insertion, the player 17has information about the ads to be played. This has several benefits: 18 19* The player can expose metadata and functionality relating to ads via its API. 20* [ExoPlayer UI components][] can show markers for ad positions automatically, 21 and change their behavior depending on whether ad is playing. 22* Internally, the player can keep a consistent buffer across transitions between 23 ads and content. 24 25In this setup, the player takes care of switching between ads and content, which 26means that apps don't need to take care of controlling multiple separate 27background/foreground players for ads and content. 28 29When preparing content videos and ad tags for use with client-side ad insertion, 30ads should ideally be positioned at synchronization samples (keyframes) in the 31content video so that the player can resume content playback seamlessly. 32 33### Declarative ad support ### 34 35An ad tag URI can be specified when building a `MediaItem`: 36 37~~~ 38MediaItem mediaItem = 39 new MediaItem.Builder() 40 .setUri(videoUri) 41 .setAdsConfiguration( 42 new MediaItem.AdsConfiguration.Builder(adTagUri).build()) 43 .build(); 44~~~ 45{: .language-java} 46 47To enable player support for media items that specify ad tags, it's necessary to 48build and inject a `DefaultMediaSourceFactory` configured with an 49`AdsLoader.Provider` and an `AdViewProvider` when creating the player: 50 51~~~ 52MediaSource.Factory mediaSourceFactory = 53 new DefaultMediaSourceFactory(context) 54 .setAdsLoaderProvider(adsLoaderProvider) 55 .setAdViewProvider(playerView); 56ExoPlayer player = new ExoPlayer.Builder(context) 57 .setMediaSourceFactory(mediaSourceFactory) 58 .build(); 59~~~ 60{: .language-java} 61 62Internally, `DefaultMediaSourceFactory` will wrap the content media source in an 63`AdsMediaSource`. The `AdsMediaSource` will obtain an `AdsLoader` from the 64`AdsLoader.Provider` and use it to insert ads as defined by the media item's ad 65tag. 66 67ExoPlayer's `StyledPlayerView` and `PlayerView` UI components both 68implement `AdViewProvider`. The IMA extension provides an easy to use 69`AdsLoader`, as described below. 70 71### Playlists with ads ### 72 73When playing a [playlist][] with multiple media items, the default behavior is 74to request the ad tag and store ad playback state once for each media ID, 75content URI and ad tag URI combination. This means that users will see ads for 76every media item with ads that has a distinct media ID or content URI, even if 77the ad tag URIs match. If a media item is repeated, the user will see the 78corresponding ads only once (the ad playback state stores whether ads have been 79played, so they are skipped after their first occurrence). 80 81It's possible to customize this behavior by passing an opaque ads identifier 82with which ad playback state for a given media item is linked, based on object 83equality. Here is an example where ad playback state is linked to the ad tag 84URI only, rather than the combination of the media ID and ad tag URI, by 85passing the ad tag URI as the ads identifier. The effect is that ads will load 86only once and the user will not see ads on the second item when playing the 87playlist from start to finish. 88 89~~~ 90// Build the media items, passing the same ads identifier for both items, 91// which means they share ad playback state so ads play only once. 92MediaItem firstItem = 93 new MediaItem.Builder() 94 .setUri(firstVideoUri) 95 .setAdsConfiguration( 96 new MediaItem.AdsConfiguration.Builder(adTagUri) 97 .setAdsId(adTagUri) 98 .build()) 99 .build(); 100MediaItem secondItem = 101 new MediaItem.Builder() 102 .setUri(secondVideoUri) 103 .setAdsConfiguration( 104 new MediaItem.AdsConfiguration.Builder(adTagUri) 105 .setAdsId(adTagUri) 106 .build()) 107 .build(); 108player.addMediaItem(firstItem); 109player.addMediaItem(secondItem); 110~~~ 111{: .language-java} 112 113### IMA extension ### 114 115The [ExoPlayer IMA extension][] provides `ImaAdsLoader`, making it easy to 116integrate client-side ad insertion into your app. It wraps the functionality of 117the [client-side IMA SDK][] to support insertion of VAST/VMAP ads. For 118instructions on how to use the extension, including how to handle backgrounding 119and resuming playback, please see the [README][]. 120 121The [demo application][] uses the IMA extension, and includes several sample 122VAST/VMAP ad tags in the sample list. 123 124#### UI considerations #### 125 126`StyledPlayerView` and `PlayerView` hide controls during playback of ads 127by default, but apps can toggle this behavior by calling 128`setControllerHideDuringAds`, which is defined on both views. The IMA SDK will 129show additional views on top of the player while an ad is playing (e.g., a 'more 130info' link and a skip button, if applicable). 131 132Since advertisers expect a consistent experience across apps, the IMA SDK does 133not allow customization of the views that it shows while an ad is playing. It is 134therefore not possible to remove or reposition the skip button, change the 135fonts, or make other customizations to the visual appearance of these views. 136{:.info} 137 138The IMA SDK may report whether ads are obscured by application provided views 139rendered on top of the player. Apps that need to overlay views that are 140essential for controlling playback must register them with the IMA SDK so that 141they can be omitted from viewability calculations. When using `StyledPlayerView` 142or `PlayerView` as the `AdViewProvider`, they will automatically register 143their control overlays. Apps that use a custom player UI must register overlay 144views by returning them from `AdViewProvider.getAdOverlayInfos`. 145 146For more information about overlay views, see 147[Open Measurement in the IMA SDK][]. 148 149#### Companion ads #### 150 151Some ad tags contain additional companion ads that can be shown in 'slots' in an 152app UI. These slots can be passed via 153`ImaAdsLoader.Builder.setCompanionAdSlots(slots)`. For more information see 154[Adding Companion Ads][]. 155 156#### Standalone ads #### 157 158The IMA SDK is designed for inserting ads into media content, not for playing 159standalone ads by themselves. Hence playback of standalone ads is not supported 160by the IMA extension. We recommend using the [Google Mobile Ads SDK][] instead 161for this use case. 162 163### Using a third-party ads SDK ### 164 165If you need to load ads via a third-party ads SDK, it's worth checking whether 166it already provides an ExoPlayer integration. If not, implementing a custom 167`AdsLoader` that wraps the third-party ads SDK is the recommended approach, 168since it provides the benefits of `AdsMediaSource` described above. 169`ImaAdsLoader` acts as an example implementation. 170 171Alternatively, you can use ExoPlayer's [playlist support][] to build a sequence 172of ads and content clips: 173 174~~~ 175// A pre-roll ad. 176MediaItem preRollAd = MediaItem.fromUri(preRollAdUri); 177// The start of the content. 178MediaItem contentStart = 179 new MediaItem.Builder() 180 .setUri(contentUri) 181 .setClippingConfiguration( 182 new ClippingConfiguration.Builder() 183 .setEndPositionMs(120_000) 184 .build()) 185 .build(); 186// A mid-roll ad. 187MediaItem midRollAd = MediaItem.fromUri(midRollAdUri); 188// The rest of the content 189MediaItem contentEnd = 190 new MediaItem.Builder() 191 .setUri(contentUri) 192 .setClippingConfiguration( 193 new ClippingConfiguration.Builder() 194 .setStartPositionMs(120_000) 195 .build()) 196 .build(); 197 198// Build the playlist. 199player.addMediaItem(preRollAd); 200player.addMediaItem(contentStart); 201player.addMediaItem(midRollAd); 202player.addMediaItem(contentEnd); 203~~~ 204{: .language-java} 205 206## Server-side ad insertion ## 207 208In server-side ad insertion (also called dynamic ad insertion, or DAI), the 209media stream contains both ads and content. A DASH manifest may point to both 210content and ad segments, possibly in separate periods. For HLS, see the Apple 211documentation on [incorporating ads into a playlist][]. 212 213When using server-side ad insertion the client may need to report tracking 214events to an ad SDK or ad server. For example, the media stream may include 215timed events that need to be reported by the client (see [supported formats][] 216for information on what timed metadata formats are supported by ExoPlayer). Apps 217can listen for timed metadata events from the player, e.g., via 218`ExoPlayer.addMetadataOutput`. 219 220The IMA extension currently only handles client-side ad insertion. It does not 221provide any integration with the DAI part of the IMA SDK. 222{:.info} 223 224[VAST]: https://www.iab.com/wp-content/uploads/2015/06/VASTv3_0.pdf 225[VMAP]: https://www.iab.com/guidelines/digital-video-multiple-ad-playlist-vmap-1-0-1/ 226[ExoPlayer UI components]: {{ site.baseurl }}/ui-components.html 227[ExoPlayer IMA extension]: https://github.com/google/ExoPlayer/tree/release-v2/extensions/ima 228[client-side IMA SDK]: https://developers.google.com/interactive-media-ads/docs/sdks/android 229[README]: https://github.com/google/ExoPlayer/tree/release-v2/extensions/ima 230[demo application]: {{ site.baseurl }}/demo-application.html 231[Open Measurement in the IMA SDK]: https://developers.google.com/interactive-media-ads/docs/sdks/android/omsdk 232[Adding Companion Ads]: https://developers.google.com/interactive-media-ads/docs/sdks/android/companions 233[playlist]: {{ site.baseurl }}/playlists.html 234[playlist support]: {{ site.baseurl }}/playlists.html 235[incorporating ads into a playlist]: https://developer.apple.com/documentation/http_live_streaming/example_playlists_for_http_live_streaming/incorporating_ads_into_a_playlist 236[supported formats]: {{ site.baseurl }}/supported-formats.html 237[Google Mobile Ads SDK]: https://developers.google.com/admob/android/quick-start 238