Skip to main content

Direct Ad Playback Control

Even when implementing channel replacement ads without utilizing the playlist manipulation features provided by the Flower SDK, you can still integrate ads by using the SDK's linear TV live channel ad request functionality. In this case, ad integration follows these steps:

  1. Inform Entering a Live Channel (enterChannel): Pass information such as the ad tag URL and channel ID when starting stream playback.
  2. Request a Live Channel Ad (requestChannelAd): Request information about ads that can be played in the current channel.
  3. Play the Ad: When the SDK returns an ad list, play the ads according to the host application's logic.

Step-by-Step Details

1. Inform Entering a Live Channel – enterChannel

FlowerAdsManager.enterChannel()

Notifies the SDK of live broadcast entry. The following describes the parameters:

ParameterTypeDescription
adTagUrlstringAd tag URL issued by the Flower backend system
You must file a request to Anypoint Media to receive an adTagUrl.
contentIdstringUnique channel ID
Must be registered in the Flower backend system
extraParamsmap(Optional) Additional pre-agreed information for targeting
mediaPlayerAdapterMediaPlayerAdapterMediaPlayerAdapter interface implementation object
For more details, refer to the Direct Player Control documentation.
adTagHeadersmap(Optional) HTTP header information to add when requesting ads

Example

private fun playLinearTv() {
// TODO GUIDE: Inform channel enter
// arg0: adTagUrl, url from flower system
// You must file a request to Anypoint Media to receive an adTagUrl.
// arg1: channelId, unique channel id in your service
// arg2: extraParams, values you can provide for targeting
// arg3: mediaPlayerAdapter, interface that provides methods to control playback,
// manage media items, and retrieve player state
// arg4: adTagHeaders, (Optional) values included in headers for ad request
flowerAdView.adsManager.enterChannel(
"https://ad_request",
"100",
mapOf("custom-param" to "custom-param-value"),
mediaPlayerAdapter,
mapOf("custom-ad-header" to "custom-ad-header-value"),
)
}

2. Request a Live Channel Ad – requestChannelAd

FlowerAdsManager.requestChannelAd()

Requests ads for the current live channel. This method returns a coroutine Flow<FlowerAd> that emits each ad sequentially as it becomes available. The following describes the parameters:

ParameterTypeDescription
transactionIdLongUnique cue event ID
Must be different for each ad request
adDurationLongRequested ad duration in milliseconds
uniqueProgramIdIntUnique program ID for the ad request
Must be registered in the Flower backend system
timeoutLongAd request timeout in milliseconds
Important: Must be set to the time difference between the current playback position and the point at which the ad marker occurs.

Return value: Flow<FlowerAd> — a coroutine Flow that emits playable FlowerAd objects.

Behavior
  • If a request is made with the same transactionId as a previous request, the method returns emptyFlow().
  • If no ads are available or a timeout occurs, the Flow throws FlowerError(message).

FlowerAd

Represents an ad returned by the Flower SDK:

ParameterTypeDescription
idStringAd ID
durationLongDuration of the ad (ms)
creativesList<FlowerCreative>List of playable creative media

FlowerCreative

Represents ad creative assets returned by the SDK:

ParameterTypeDescription
typeStringMedia MIME type
widthIntMedia width (px)
heightIntMedia height (px)
urlStringMedia URL

Example

val transactionId = parseScte35EventId()
val cueDuration = 30000L // 30 seconds
val uniqueProgramId = 1 // Unique program ID for the cue
val timeout = 5000L // 5 seconds timeout for ad request

// TODO GUIDE: Request linear tv ad using Flow
// Returns Flow<FlowerAd> that emits each ad as it becomes available.
// Throws FlowerError if no ads are available or a timeout occurs.
// Returns emptyFlow() if a duplicate transactionId is used.
lifecycleScope.launch {
flowerAdView.adsManager.requestChannelAd(
transactionId,
cueDuration,
uniqueProgramId,
timeout,
).catch { e ->
Log.e("FlowerSDK Example", "Ad request failed: ${e.message}")
}.collect { flowerAd ->
Log.i("FlowerSDK Example", "Received ad: ${flowerAd.id}")
playFlowerAd(flowerAd)
}
}

3. Play the Ad

The returned ad list should be played replacing the original stream according to the ad marker (such as SCTE-35). When each FlowerAd is playing, the host application must call FlowerAd.start() with the FlowerAdTracker implementation to report to the ad server.

If the returned ad list is empty, it should be treated as a no-ad scenario due to reasons such as a timeout, and the original stream should continue playing during the ad marker.

If the ad list is not empty, the ad creatives should be played sequentially at the start of the ad marker in the original stream. The method of playing the ads may vary depending on the host application's logic.

Ad Playback Time Detection – MediaPlayerAdapter

The SDK uses the MediaPlayerAdapter to detect ad playback time and handle ad interactions such as "more info", skip, and event tracking. Therefore, the implementation of the MediaPlayerAdapter passed to enterChannel() is critical for accurate ad behavior.

The following describes the implementation guidelines for each method:

MethodReturn TypeDescription
getCurrentMedia()MediaReturns the URL, duration, and current playback position of the currently playing ad creative. This is the most important method — accurate values are required for ad tracking to work correctly.
getVolume()KotlinWrapped<Float>Returns the audio volume level (0.0–1.0)
isPlaying()KotlinWrapped<Boolean>Returns whether the player is currently playing
getHeight()KotlinWrapped<Int>Returns the video height in pixels (0 if unknown)
pause()UnitPauses the playback
stop()UnitStops the player and releases resources
resume()UnitResumes the playback
enqueuePlayItem(playItem)UnitQueues the next play item
removePlayItem(playItem)UnitRemoves a matching play item from the queue
playNextItem()UnitPlays the next item in the queue
seekToPosition(...)UnitSeeks to the specified position. No implementation is required for this approach.
getCurrentAbsoluteTime(isPrintDetails)KotlinWrapped<Double>Returns the current absolute playback time in ms. No implementation is required for this approach.
getPlayerType()String?Returns the player type identifier (for Google PAL SDK)
getPlayerVersion()String?Returns the player version string (for Google PAL SDK)
Importance of getCurrentMedia()

getCurrentMedia() is the core method the SDK uses to track ad playback progress. The urlOrId, duration, and position values in the returned Media object must be accurate for ad skip, "more info", and event tracking to function correctly.