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