Server side ad insertion using Google IMA
GoogleIMA
Supported Google IMA SDK versions:
- 3.35.1 - Recommended for ExoPlayer IMA Extension.
- 3.38.0 - Recommended for IMA Standalone.
Specifications
Server-side ads insertion (SSAI), also known as Dynamic Ad Insertion (DAI), provides a combined video stream of ads and content (ads stitching), resulting in a seamless, broadcast-like viewing experience.
QP IMA ads player supports:
- Various ad formats, including standard linear and non-linear in-stream ads, interactive in-stream ads, and skippable ads.
- Multiple ad placements: It can deliver pre-roll, mid-roll, and post-roll ads.
- Ad requests to Google Ad Manager, the Google AdSense network, or any VAST-compliant ad server.
- Replacement for all ad tag parameters used for the upcoming ad requests in a Live IMA DAI Streams.
Gradle Dependencies
- IMA Standalone
- ExoPlayer IMA Extension
For IMA SDK 3.37.0 and above, configure core library desugaring:
android {
defaultConfig {
minSdkVersion 23 // Required for IMA SDK 3.38.0+
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
coreLibraryDesugaringEnabled true
}
}
dependencies {
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.0.4"
}
- No additional gradle configuration required for IMA SDK 3.35.1+.
- The IMA version must be compatible with ExoPlayer Media3.
- We recommend continuing with IMA
3.35.1, which is compatible with Media31.8.0.
Usage
The first step is the creation of an ad request for either client-side ads insertion or server-side ads insertion. The AdRequest instance is an object containing the data used to request ads from the server.
Create SSAI ad request for VOD stream
Create a VodSSAIAdsRequest ad request instance with contentSourceId and videoId properties as mandatory values.
| Name | Type | Description |
|---|---|---|
| contentSourceId | String | Specifies the stream request content source ID used for on-demand streams. |
| videoId | String | Specifies the stream request video ID used for on-demand streams. |
The following snippet shows an ad request creation example:
val format: MediaType = MediaType.DASH
val contentSourceId = "2559737"
val videoId = "tos-dash"
val adRequest = VodSSAIAdsRequest(
format = format,
contentSourceId = contentSourceId,
videoId = videoId
)
Create SSAI ad request for live stream
Create a LiveSSAIAdsRequest ad request instance with assetKey property as a mandatory value.
| Name | Type | Description |
|---|---|---|
| assetKey | String | Specifies the stream request asset key used for live streams. |
The following snippet shows an ad request creation example:
val format: MediaType = MediaType.DASH
val assetKey = "sN_IYUG8STe1ZzhIIE_ksA"
val adRequest = LiveSSAIAdsRequest(
format = format,
assetKey = assetKey
)
Both VodSSAIAdsRequest and LiveSSAIAdsRequest also require that the format property is provided as a mandatory value. Specify the format of the stream request as either MediaType.DASH or MediaType.HLS format.
Optionally, you can provide each VodSSAIAdsRequest or LiveSSAIAdsRequest with adsId, apiKey, streamActivityMonitorId, adTagParameters, manifestSuffix, and contentUrl property values.
| Name | Type | Description |
|---|---|---|
| adsId | String | Specifies an opaque identifier for associated ad playback state, or null if assetKey (for live) or videoId (for VOD) should be used as the ads identifier. |
| apiKey | String | Specifies the stream request API key. This is used for content authentication. |
| streamActivityMonitorId | String | Specifies the ID for debugging the stream with the stream activity monitor. This provides a convenient way to let publishers find a stream log in the stream activity monitor tool. |
| manifestSuffix | String | Specifies the optional stream manifest's suffix, which is appended to the stream manifest's URL. The provided string must be URL-encoded and must not include a leading question mark. |
| contentUrl | String | The url of the content to play. |
| adOverlayUIScopes | AdOverlayUIScope | The list of AdOverlayUIScope instances describing views that are on top of the ad view group. Refer here. |
| loadMediaTimeoutMs | Int | Specifies, in milliseconds, the ad media load timeout. |
| languageTag | String | Specifies IETF BCP 47 language subtag string for the language used to display text for ads related labels such as a label indicating the total number of ads in a pod or a label indicating the click through URL. |
| adTagParameters | Map<String, String> | Specifies a collection of extra parameters to pass to the ad server. When the video player requests a stream, you can override certain parameters of the tag in your stream request. You can only override the parameters specified here: https://support.google.com/dfp_premium/answer/7320899. You can use the dai-ot and dai-ov parameters for stream variant preference (see https://support.google.com/dfp_premium/answer/7320898 for more information). |
Check the list of common primary language subtags at https://en.wikipedia.org/wiki/IETF_language_tag
Performance Optimization
- IMA Standalone
- ExoPlayer IMA Extension
For optimal video start time, initialize the IMA SDK early in your Application class:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// Initialize IMA SDK early for better performance
AdsLoaderManagerFactory.initializeImaSdk(this)
}
}
No additional step required for IMA Extension.
Create ad composed player
AdComposedPlayer manages both content and ad playback. It extends the conventional Player functionality and adds ads rendering to it.
- IMA Standalone
- ExoPlayer IMA Extension
Use the IMADaiAdsPlayerBuilder builder pattern:
val adsPlayerBuilder = IMADaiAdsPlayerBuilder()
adsPlayerBuilder.mediaURL("https://storage.googleapis.com/wvmedia/clear/h264/tears/tears.mpd")
adsPlayerBuilder.mediaType(MediaType.DASH) // MediaType.HLS for HLS streaming
when (val result = adsPlayerBuilder.build(applicationContext, adRequest as SSAIAdsRequest)) {
is Result.Success -> {
val adsPlayer = result.value
// Use adsPlayer for playback
}
is Result.Failure -> {
val error = result.value
// Handle error
}
}
IMADaiAdsPlayerBuilder Methods
| Name | Type | Description |
|---|---|---|
| mediaURL | String | The URL of the media content to play |
| mediaType | MediaType | The media type (MediaType.DASH or MediaType.HLS) |
| adsLoaderManager | AdsLoaderManager | (Optional) Custom ads loader manager instance |
| adPlaybackPolicy | AdPlaybackPolicy | (Optional) Policy for ad playback behavior |
| adUIElementVisibilityPreference | IMAAdUIVisibilityPreference | (Optional) Controls visibility of ad UI elements |
| setStreamURLLoadTimeoutMs | Long | (Optional) Sets the time in milliseconds to wait for the stream URL to be fetched. By default, this is set to 10000 ms (10 seconds). |
Use the IMAAdsPlayerFactory factory pattern:
// Create the content Player first
val contentPlayer = PlayerBuilder()
.mediaURL("https://storage.googleapis.com/wvmedia/clear/h264/tears/tears.mpd")
.mediaType(MediaType.DASH) // MediaType.HLS for HLS streaming
.build(applicationContext)
// Wrap it with AdComposedPlayer
val adsPlayer = with(contentPlayer) { player ->
IMAAdsPlayerFactory.imaAdComposedPlayerWith(
player,
adRequest as SSAIAdsRequest
)
}
Replace all ad tag parameters in a Live IMA DAI stream
You can change ad campaign targeting by replacing all the ad tag parameters used for the upcoming ad requests in a Live IMA DAI Stream.
// When new live program is about to be shown setup new ad campaign
val newAdTagParameters = MutableMap<String, String>()
// populate new ad tag parameters container
adsPlayer.replaceAdTagParameters(newAdTagParameters)
Listen to ad events
You can register an AdEventListener instance with AdComposedPlayer for listening to Ad Events. The following ad events are triggered by AdEventListener callbacks:
- Cue Point availability (available only after obtaining a response from Ad Server)
- Ad Break Start called when the first Ad, in an Ad Break, have started playing. This event may also provide
AdBreakInfometadata for the active Ad Break. - Ad Start called when an Ad has started playing. This event will also provide
AdInfometadata for the active Ad. - Ad Playback Progress called during Ad Break playback when the Ad's progress is updated. This event will also provide
AdProgressInfometadata for the active Ad Break. - Ad End called when an Ad has finished playing. This event will also provide
AdInfometadata for the active Ad. - Ad Break End called when all the Ads, in an Ad Break, have finished playing. This event may also provide
AdBreakInfometadata for the active Ad Break. - Ad Error called when an error has been encountered during Ads playback. This event will also provide
Errormetadata for the active Ad. - Ad Tracking Event called when an ad tracking event sucha as ad's first quartile, midpoint, third quartile etc. is
triggered. This event will also provide
AdTrackingEventmetadata for the active Ad Break or Ad.
val adEventListener = object : AdEventListener {
override fun onAdCuePointsAvailable(cuePoints: LongArray) {
logger.info { "cue_points_available" }
}
override fun onAdBreakStart(adBreakInfo: AdBreakInfo?) {
logger.info { "ad_break_start" }
}
override fun onAdStart(adInfo: AdInfo) {
logger.info { "ad_start" }
}
override fun onAdEnd(adInfo: AdInfo) {
logger.info { "ad_end" }
}
override fun onAdBreakEnd(adBreakInfo: AdBreakInfo?) {
logger.info { "ad_break_end" }
}
}
adsPlayer.registerAdListener(adEventListener)