Skip to main content

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:

  1. Various ad formats, including standard linear and non-linear in-stream ads, interactive in-stream ads, and skippable ads.
  2. Multiple ad placements: It can deliver pre-roll, mid-roll, and post-roll ads.
  3. Ad requests to Google Ad Manager, the Google AdSense network, or any VAST-compliant ad server.
  4. Replacement for all ad tag parameters used for the upcoming ad requests in a Live IMA DAI Streams.

Gradle Dependencies

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"
}

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.

NameTypeDescription
contentSourceIdStringSpecifies the stream request content source ID used for on-demand streams.
videoIdStringSpecifies 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.

NameTypeDescription
assetKeyStringSpecifies 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.

NameTypeDescription
adsIdStringSpecifies 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.
apiKeyStringSpecifies the stream request API key. This is used for content authentication.
streamActivityMonitorIdStringSpecifies 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.
manifestSuffixStringSpecifies 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.
contentUrlStringThe url of the content to play.
adOverlayUIScopesAdOverlayUIScopeThe list of AdOverlayUIScope instances describing views that are on top of the ad view group. Refer here.
loadMediaTimeoutMsIntSpecifies, in milliseconds, the ad media load timeout.
languageTagStringSpecifies 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.
adTagParametersMap<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).
note

Check the list of common primary language subtags at https://en.wikipedia.org/wiki/IETF_language_tag

Performance Optimization

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)
}
}

Create ad composed player

AdComposedPlayer manages both content and ad playback. It extends the conventional Player functionality and adds ads rendering to it.

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

NameTypeDescription
mediaURLStringThe URL of the media content to play
mediaTypeMediaTypeThe media type (MediaType.DASH or MediaType.HLS)
adsLoaderManagerAdsLoaderManager(Optional) Custom ads loader manager instance
adPlaybackPolicyAdPlaybackPolicy(Optional) Policy for ad playback behavior
adUIElementVisibilityPreferenceIMAAdUIVisibilityPreference(Optional) Controls visibility of ad UI elements
setStreamURLLoadTimeoutMsLong(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).

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:

  1. Cue Point availability (available only after obtaining a response from Ad Server)
  2. Ad Break Start called when the first Ad, in an Ad Break, have started playing. This event may also provide AdBreakInfo metadata for the active Ad Break.
  3. Ad Start called when an Ad has started playing. This event will also provide AdInfo metadata for the active Ad.
  4. Ad Playback Progress called during Ad Break playback when the Ad's progress is updated. This event will also provide AdProgressInfo metadata for the active Ad Break.
  5. Ad End called when an Ad has finished playing. This event will also provide AdInfo metadata for the active Ad.
  6. Ad Break End called when all the Ads, in an Ad Break, have finished playing. This event may also provide AdBreakInfo metadata for the active Ad Break.
  7. Ad Error called when an error has been encountered during Ads playback. This event will also provide Error metadata for the active Ad.
  8. 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 AdTrackingEvent metadata 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)