Server Side Ad Insertion using FLMediaTailor
The fl-player-ads-mediatailor library enables playback of AWS Elemental
MediaTailor curated streams with advertisements. To build a MediaTailor player,
use the MediaTailorAdsPlayerBuilder API. The session configuration type selects
the player implementation:
QpSessionConfigurationuses MediaTailor server-side ad tracking.DzSessionConfigurationuses Datazoom and supports client-side or MediaTailor server-side reporting.
| Property | Type | Description |
|---|---|---|
| sessionURL | String | Sets the URL to create remote session with AWS Elemental MediaTailor. |
| contentURL | String | Sets the fallback URL to content playback when MediaTailor session fails. |
| drmLicenseURL | String | Sets the url for DRM keys fetch |
| drmScheme | DRMScheme | Sets content protection scheme |
| sessionConfiguration | SessionConfiguration | Session configuration parameters to create the AWS MediaTailor session. Use QpSessionConfiguration or DzSessionConfiguration. |
| adPlaybackPolicy | AdPlaybackPolicy | Sets the [AdPlaybackPolicy] instance that specifies the policy rules for MediaTailor ads handling. |
| playbackPolicyHandler | PlaybackPolicyHandler | Sets the [PlaybackPolicyHandler] instance that enforces the policy rules related to the content with MediaTailor ads. |
| playbackPolicyHandlerListener | PlaybackPolicyHandler.Listener | Sets the [PlaybackPolicyHandler.Listener] instance that provides the notification for ad playback policy related events. |
| palConfiguration | PALConfiguration | Sets the [PALConfiguration] instance that is used in the [PALSession] initialization. Optionally sets the permission to store user data like cookies, device IDs, and advertising IDs when using [PALSession] calls. |
| httpClientConfig | HttpClientConfiguration | The Http Client configuration details for MediaTailor API calls. |
QpSessionConfiguration
Use QpSessionConfiguration.Builder when Datazoom isn't required. This
configuration always sends reportingMode=server to MediaTailor.
| Parameter | Type | Description |
|---|---|---|
| playerParams | Map<String, String> | Preceding configuration used for session initialization request that defines the player variables and their aliases. |
| originParams | Map<String, String> | Custom origin parameters for the session. |
| manifestParams | Map<String, String> | Query parameters included in the parent manifest and tracking URLs in the response. |
| overlayAvails | OverlayAvailsMode | MediaTailor support for overlay ads is enabled by default. A specific SCTE-35 ad-marker type in the manifest triggers the insertion of an overlay ad. Because some players might not support client-side rendering of overlay ads, you can disable the feature at the session level. |
| availSuppression | AvailSuppression | The MediaTailor avail suppression configuration. |
| adSignaling | Boolean | To enable ad ID signaling, add an adSignaling object as a top level object, and inside, add a parameter called enabled and value of true. The default adSignaling value is disabled. |
| userAgent | String | Custom user agent for MediaTailor session requests. |
| logMode | LogMode | Enables MediaTailor debug logging. LogMode.DEBUG is currently supported and is passed through originParams. |
AvailSuppression
| Parameter | Type | Description |
|---|---|---|
| mode | AvailSuppressionMode | The avail suppression mode. |
| value | String | A time relative to the live edge in a live stream. |
AvailSuppressionMode
| Parameter | Description |
|---|---|
| OFF | Ad suppression is OFF |
| BEHIND_LIVE_EDGE | When set to BEHIND_LIVE_EDGE, MediaTailor doesn't fill ad breaks on or behind the aws.availSuppressionValue time |
| AFTER_LIVE_EDGE_FULL_AVAIL_ONLY | MediaTailor doesn't fill ad breaks on or behind the avail suppression period and full avail suppression policy |
| AFTER_LIVE_EDGE_PARTIAL_AVAIL | MediaTailor doesn't fill ad breaks on or behind the avail suppression period and invoke partial ad break fills when and session starts mid-break |
OverlayAvailsMode
| Parameter | Description |
|---|---|
| ON | Enabling overlaying ads. |
| OFF | Disabling overlaying ads. |
DzSessionConfiguration
Use DzSessionConfiguration.Builder when Datazoom integration is required.
The builder requires a Datazoom configuration ID and the root View for the
ad session.
| Property | Type | Description |
|---|---|---|
configId | String | Datazoom configuration or analytics ID. |
playerRootView | View | Root view used for Datazoom ad-session setup, ad rendering, and event tracking. |
reportingMode | SessionReportingMode | Client tracks ad events with Datazoom. Server lets MediaTailor handle ad tracking while Datazoom remains initialized. Defaults to Client. |
friendlyObstructions | List<AdOverlayUIScope> | Optional ad-overlay metadata for viewability tracking. |
liveAdTrackingMode | AdTrackingMode | Live ad tracking mode. Defaults to PAGINATION; VOD always uses FULL. |
SessionReportingMode
| Parameter | Description |
|---|---|
Server | MediaTailor handles ad tracking server-side while Datazoom remains initialized for reporting. |
Client | Datazoom tracks ad events on the client side. |
Both modes require configId and playerRootView.
AdTrackingMode
AdTrackingMode applies to live Datazoom sessions. VOD playback always uses
FULL tracking.
| Value | Description |
|---|---|
FULL | Fetches all ad tracking events up front. |
PAGINATION | Fetches ad tracking events incrementally. This is the default for live playback. |
PLAYHEAD | Fetches ad tracking events based on the current playhead position. |
PALConfiguration
| Property | Type | Description |
|---|---|---|
| willAdAutoPlay | Boolean | Defines whether the ad will be auto played without waiting for user interaction or not. |
| willAdPlayMuted | Boolean | Defines whether the ad will be played while muted or not. |
| continuousPlayback | Boolean | Defines whether the player intends to continuously play the content videos one after another similar to TV broadcast or video playlist. |
| descriptionUrl | URL | Defines the description URL of the content during which the ad will be played. |
| iconsSupported | Boolean | Defines whether VAST icons are supported by the video player. |
| nonceLengthLimit | Int | Defines the length limit of the generated nonce. |
| omidPartnerName | String | The name of the partner integrating OMID measurement. |
| omidPartnerVersion | String | The version of the partner integrating OMID measurement. |
| playerType | String | The partner provided player type. |
| playerVersion | String | The partner provided player version. |
| ppid | String | The publisher provided ID. |
| videoHeight | Int | The height of the ad video element. |
| videoWidth | Int | The width of the ad video element. |
The client application may optionally provide custom AdPlaybackPolicy and PlaybackPolicyHandler implementation, and also a PALConfiguration instance as MediaTailorAdsPlayerBuilder properties.
MediaTailor player creation use cases
The following use cases are supported by MediaTailorAdsPlayerBuilder for MediaTailorPlayer instance creation:
- The application provides session URL, content URL and PAL configuration and optionally other builder properties.
- The application provides session URL, content URL and optionally other builder properties but not PAL configuration.
- The application provides content URL and PAL configuration and optionally other builder properties but not session URL.
- The application provides content URL and optionally other builder properties but not session URL and PAL configuration.
Create MediaTailor player
Build a Player using MediaTailorAdsPlayerBuilder as an extension of PlayerBuilder (see the MediaTailor Player Creation Use Cases section). Here's a typical setup for building the player:
val mediaTailorAdsPlayerBuilder = MediaTailorAdsPlayerBuilder()
mediaTailorAdsPlayerBuilder.mediaType(MediaType.DASH)
mediaTailorAdsPlayerBuilder.contentURL(contentURL)
// sessionUrl is provided as part of the playback authorization's custom attribute with key `mtSessionUrl`
val sessionUrl: String? = contentAuthToken.custom?.let {
it["mtSessionUrl"] as? String
} ?: run {
null
}
mediaTailorAdsPlayerBuilder.sessionURL(sessionURL)
// if playing DRM protected content
mediaTailorAdsPlayerBuilder.drmScheme(DRMScheme.WIDEVINE)
mediaTailorAdsPlayerBuilder.drmLicenseURL(licenseURL)
val sessionConfiguration = QpSessionConfiguration.Builder().apply {
playerParams(
mapOf(
"deviceType" to "androidmobile",
"uid" to "test-uid-12345",
)
) // contentAuthToken.custom.playerParams from playback Authorization
originParams(
mapOf(
"origin1" to "androidmobile",
"origin2" to "xjhhddli-9189901-uic"
)
)
manifestParams(
mapOf(
"deviceType" to "androidmobile",
"uid" to "test-uid-12345",
)
)
overlayAvails(OverlayAvailsMode.OFF)
availSuppression(
AvailSuppression(AvailSuppressionMode.AFTER_LIVE_EDGE_FULL_AVAIL_ONLY, value = "00:05:00")
)
adSignaling(false)
}.build()
mediaTailorAdsPlayerBuilder.sessionConfiguration(sessionConfiguration)
mediaTailorAdsPlayerBuilder.httpClientConfig(
HttpClientConfiguration(
connectionTimeout = 8,
readTimeout = 8,
userAgent = null,
retryOnNetworkFailure = true,
maxNetworkFailureRetryCount = 2,
baseNetworkFailureRetryDelayMs = 2000,
applicationInterceptors = emptyList()
)
)
mediaTailorAdsPlayerBuilder.playbackPolicyHandlerListener(stateObserver)
coroutineScope.launch {
when (val result: Result<MediaTailorPlayer?, Error?> =
mediaTailorAdsPlayerBuilder.buildAsync(
platformContext = context,
isVODPlayback = false
)
) {
is Result.Success -> {
val mediaTailorPlayer = result.value
mediaTailorPlayer?.let {
it.addListener(stateObserver)
it.addAuxiliaryListener(stateObserver)
it.addListener(internalPlayerListener)
it.registerAdListener(stateObserver)
player = composablePlayerWith(it as Player)
}
}
is Result.Failure -> {
// handle error
}
}
}
The PlayerBuilder build function is deprecated and MUST not be used. Only use buildAsync. This function is declared as a suspend function and MUST be called using a CoroutineScope builder function (for example, using the launch extension function).
Make sure to send the contentUrl via builder mediaTailorAdsPlayerBuilder.contentURL(contentURL) to switch to fallback content seamlessly if MediaTailor session creation fails. This provides a smooth and uninterrupted viewing experience for users.
Datazoom ad tracking mode
When you create a MediaTailor player with Datazoom ad tracking, provide a
Datazoom configuration ID and playerRootView. Both client-side tracking and
server-side reporting with Datazoom are supported.
<FrameLayout
android:id="@+id/playerRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:theme="@style/ThemeOverlay.MaterialComponents.Dark"/>
val playerRootView = findViewById<FrameLayout>(R.id.playerRoot)
val mediaTailorAdsPlayerBuilder = MediaTailorAdsPlayerBuilder()
mediaTailorAdsPlayerBuilder.mediaType(MediaType.DASH)
mediaTailorAdsPlayerBuilder.contentURL(contentURL)
mediaTailorAdsPlayerBuilder.sessionURL(sessionURL)
val sessionConfiguration = DzSessionConfiguration.Builder(
configId = "<DatazoomConfigId>",
playerRootView = playerRootView
).apply {
reportingMode(SessionReportingMode.Client)
liveAdTrackingMode(AdTrackingMode.PAGINATION)
// Optional: register controls and other ad-overlay metadata.
// friendlyObstructions(obstructions)
}.build()
mediaTailorAdsPlayerBuilder.sessionConfiguration(sessionConfiguration)
Datazoom dependencies
To use Datazoom ad tracking, include the following dependencies in your
build.gradle file:
implementation 'io.datazoom.sdk:mediatailor:1.1.4'
implementation 'io.datazoom.sdk:media3:1.1.0'
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 Error Event called when the mediaTailor session is failed to create which means playback is happening with fallback url. Please refer above note to enable fallback url.
- 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 onAdPlaybackProgress(adProgresInfo: AdProgressInfo) {
logger.info { "ad_progress" }
}
override fun onAdEnd(adInfo: AdInfo) {
logger.info { "ad_end" }
}
override fun onAdBreakEnd(adBreakInfo: AdBreakInfo?) {
logger.info { "ad_break_end" }
}
override fun onAdError(error: Error) {
logger.info { "ad_error" }
}
override fun onAdTrackingEvent(adTrackingEvent: AdTrackingEvent) {
logger.info { "ad_tracking_event" }
}
}
adsPlayer.registerAdListener(adEventListener)
Ad Metadata
AdInfo
Represents an advert object.
| Property | Type | Description |
|---|---|---|
| adID | string | The identifier of the advert |
| sequence | number | The sequence of the advert |
| adStartTimeOffsetMs | number | The start playhead position of the advert in milliseconds |
| durationMs | number | The duration of the advert in milliseconds |
| remainingTimeMs | number | Returns the natural playback time remaining for the advert in milliseconds |
| isSkippable | boolean | Indicates if the ad is skippable |
| skipOffsetMs | number | The value of skip offset for the advert, in milliseconds. If the VAST skip offset is not defined then this method returns -1, signifying that the advert cannot be skipped. |
| isFiller | boolean | Whether this advert represents filler content |
| adBreakInfo | AdBreakInfo | The ad break in which the advert belongs in |
| adVastProperties | AdVastProperties | Represents a VAST properties of this advert. |
AdBreakInfo
Represents an ad break object.
| Property | Type | Description |
|---|---|---|
| adBreakID | String | Unique id of the ad break |
| contentTimePosition | AdContentTimePosition | The position of the ad break, can be on of preroll, midroll or postroll |
| adSequencePosition | Int | The sequence position of the ad within the ad break. |
| adBreakStartTimeOffsetMs | Double | The content time offset at which the current ad break was scheduled |
| remainingTimeMs | Double | The natural playback time remaining for the ad break in milliseconds |
| durationMs | Double | The maximum duration of the ad break in milliseconds. |
| totalAds | Int | The total number of ads contained within this ad break. |
| adBreakIndex | Int | The index of the current ad break |
The totalAds read from AdPlayer may not be accurate when it comes from onAdStart event. This may change once ad playback starts. GoogleIMA advises to read totalAds on or after FIRST_QUARTILE ad tracking event, to get a reliable data.
AdVASTProperties
Represents VAST properties of an advert.
| Property | Type | Description |
|---|---|---|
| adSystem | String | The source ad server of the advert. |
| adTitle | String | The common name of the advert. |
| adServingId | String | The identifier used to compare impression-level data across systems. |
| adId | String | The Ad identifier of the creative. |
| creativeId | String | The identifier of the creative. |
| category | String | The category of the advert content. |
| description | String | The longer description of the advert. |
| advertiser | String | The advertiser name. |
| pricing | String | The pricing element of the advert. |
| survey | String | The URI to any resource file having to do with collecting survey data. |
| expires | String | The number of seconds in which the ad is valid for execution. |
| industryIcons | List<IndustryIcon> | The list of IndustryIcon instances. |
| companionAds | List<CompanionAd> | The list of CompanionAd instances. |
| extensions | Extensions | The custom VAST extensions properties. |
| clickThroughURL | String | The click through URL for the ad. |
Handle Ad click event (Client side ad tracking mode)
To handle ad click event in Client side ad tracking mode, clickThroughURL will be provided with
ad metadata(AdInfo.adVastProperties) in onAdStart callback of AdEventListener.
When the MediaTailor Player is created with Client side ad tracking mode, the client application
must notify the MediaTailor Player when an ad is clicked by calling sendAdClick() function on MediaTailorPlayer instance.
Capturing VST parameters
Few key VST measuring metrics like licenseLoadTimeMs, ssaiStreamUrlFetchTimeMs is exposed via StreamInformation which can be accessed as below.
Please make sure to call this APIs only after player entered STARTED state.
// through API
val licenseLoadTimeMs = player?.streamInformation?.streamStartUpTimeData?.ssaiStreamUrlFetchTimeMs // A time taken to load SSAI/DAI stream URL in milliseconds.
val ssaiStreamUrlFetchTimeMs = player?.streamInformation?.streamStartUpTimeData?.licenseLoadTimeMs //A time taken to load DRM license in milliseconds.
Retrieving the MediaTailor session id for Ad Tracking
The adSessionId property provides access to the AWS MediaTailor ad session identifier for advanced tracking and diagnostics.
if (player is ComposablePlayer && player.getComposedPlayer() is AdComposedPlayer) {
val sessionId = (player.getComposedPlayer() as AdComposedPlayer)
.adSessionId
logger.info { "ad session id is $sessionId" }
}