Skip ad breaks for a period of time

Last update: 2023-10-02

By default, TVSDK forces an ad break to play when the user seeks over an ad break. You can customize the behavior to skip an ad break if the time elapsed from a previous break completion is within a certain number of minutes.

IMPORTANT

If you have to complete an internal seek to forgive an ad, there might be a slight pause during the playback.

To override the default TVSDK ad break behavior, you can extend the default ad policy selector. There are four ad break policies available:

  • PLAY

  • SKIP

    NOTE

    The SKIP ad break policy might not work as expected for live streams when an ad is present at the live point. For example, for a pre-roll, SKIP will cause a seek to the end of the ad break, which could be greater than the live point. In this case, TVSDK may seek to the middle of an ad.

  • REMOVE_AFTER

  • REMOVE

    NOTE

    The REMOVE ad break policy is slated for deprecation. Adobe recommends that you use the SKIP ad break policy in place of REMOVE.

The following example of a customized ad policy selector skips ads in the next five minutes (wall clock time) after a user has watched an ad break.

  1. When the user finishes watching an ad break, save the current system time.

    @Override
    public void onAdBreakComplete(AdBreak adBreak) {
        ...
        if (isShouldPlayUpcomingAdBreakRuleEnabled()) {
            CustomAdPolicySelector.setLastAdBreakPlayedTime(System.currentTimeMillis());
            ...
        }
    }
    
  2. Extend AdPolicySelector.

    package com.adobe.mediacore.sample.advertising;
    
    import com.adobe.mediacore.MediaPlayerItem;
    import com.adobe.mediacore.MediaPlayerItemConfig;
    import com.adobe.mediacore.timeline.advertising.policy.*;
    import com.adobe.mediacore.timeline.advertising.AdBreakTimelineItem;
    import com.adobe.mediacore.metadata.AdvertisingMetadata;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class CustomAdPolicySelector implements AdPolicySelector {
    
        private static final long MIN_BREAK_INTERVAL = 300000; // 5 minutes for next ad break to be played
        private MediaPlayerItem _mediaPlayerItem;
        private static long _lastAdBreakPlayedTime;
        private AdBreakWatchedPolicy watchedPolicy = AdBreakWatchedPolicy.WATCHED_ON_BEGIN;
    
        public CustomAdPolicySelector(MediaPlayerItem mediaPlayerItem) {
            _mediaPlayerItem = mediaPlayerItem;
            _lastAdBreakPlayedTime = 0;
    
            if (mediaPlayerItem != null) {
                watchedPolicy = extractWatchedPolicy(mediaPlayerItem.getConfig());
            }
        }
    
        @Override
        public AdBreakPolicy selectPolicyForAdBreak(AdPolicyInfo adPolicyInfo) {
            if (shouldPlayAdBreaks() && adPolicyInfo.getAdBreakTimelineItems() != null) {
    
                AdBreakTimelineItem item = adPolicyInfo.getAdBreakTimelineItems().get(0);
    
                // This condition will remove the pre-roll ad from live stream after watching
                if (item.getTime() == 0 && _mediaPlayerItem.isLive()) {
                    return AdBreakPolicy.REMOVE_AFTER_PLAY;
                }
                if (item.getTime() == 0) {
                    return AdBreakPolicy.PLAY;
                }
    
                // This condition will remove every ad break that has been watched once.
                // Comment this section if you want to play watched ad breaks again.
                if (item.isWatched()) {
                    return AdBreakPolicy.SKIP;
                }
    
                return AdBreakPolicy.REMOVE_AFTER_PLAY;
            }
    
            return AdBreakPolicy.SKIP;
        }
    
        @Override
        public List<AdBreakTimelineItem> selectAdBreaksToPlay(AdPolicyInfo adPolicyInfo) {
    
            if (shouldPlayAdBreaks()) {
    
                List<AdBreakTimelineItem> timelineItems = adPolicyInfo.getAdBreakTimelineItems();
                AdBreakTimelineItem item;
                List<AdBreakTimelineItem> selectedItems = new ArrayList<AdBreakTimelineItem>();
    
                if (timelineItems != null && timelineItems.size() > 0) {
    
                    // Seek Forward Condition
                    if (adPolicyInfo.getCurrentTime() <= adPolicyInfo.getSeekToTime()) {
                        item = timelineItems.get(0);
    
                        // Resume logic - This will be helpful in resuming the content
                        // from last saved playback session, and just play the pre-roll ad
                        if(adPolicyInfo.getCurrentTime() == 0) {
                            if(item.getTime() == 0 && !item.isWatched()) {
                                // comment this line if you just need to seek to the user's
                                // last known position without playing pre-roll ad. ZD#820
                                selectedItems.add(item);
                                return selectedItems;
                            }
                            else{
                                return null;
                            }
                        } else {
                            item = timelineItems.get(timelineItems.size()-1);
                            if (!item.isWatched()) {
                                selectedItems.add(item);
                                return selectedItems;
                            }
                        }
    
                        // Seek backward condition
                    } else if (adPolicyInfo.getCurrentTime() > adPolicyInfo.getSeekToTime()) {
                        item = timelineItems.get(0);
    
                        if(!item.isWatched()) {
                            selectedItems.add(item);
                            return selectedItems;
                        } else {
                            return null;
                        }
                    }
                }
            }
            return null;
        }
    
        @Override
        public AdPolicy selectPolicyForSeekIntoAd(AdPolicyInfo adPolicyInfo) {
            // Simple Ad Policy selector
            // if the first ad in the break was watched,
            // skip to the next add after the seek position
            // otherwise, play the ads in the break from the beginning
    
            List<AdBreakTimelineItem> timelineItems = adPolicyInfo.getAdBreakTimelineItems();
            if (timelineItems != null && timelineItems.size() > 0) {
                if (timelineItems.get(0).isWatched()) {
                    return AdPolicy.SKIP_TO_NEXT_AD_IN_AD_BREAK;
                }
            }
    
            // Resume play from the next ad in the break
            return AdPolicy.PLAY_FROM_AD_BREAK_BEGIN;
    
        }
    
        @Override
        public AdBreakWatchedPolicy selectWatchedPolicyForAdBreak(AdPolicyInfo adPolicyInfo) {
            return watchedPolicy;
        }
    
        public static void setLastAdBreakPlayedTime(long lastAdBreakPlayedTime) {
            _lastAdBreakPlayedTime = lastAdBreakPlayedTime;
        }
    
        private boolean shouldPlayAdBreaks() {
            long currentTime = System.currentTimeMillis();
    
            if (_lastAdBreakPlayedTime <= 0) {
                return true;
            }
    
            if (_lastAdBreakPlayedTime > 0 &&
              (currentTime - _lastAdBreakPlayedTime) > MIN_BREAK_INTERVAL) {
                return true;
            }
    
            // return false for not playing Ad if this
            // Ad occurs with 5 minutes of last Ad playback
            return false;
        }
    
        private AdBreakWatchedPolicy extractWatchedPolicy(MediaPlayerItemConfig config) {
            if (config != null) {
                AdvertisingMetadata metadata = config.getAdvertisingMetadata();
                if (metadata != null) {
                    return metadata.getAdBreakWatchedPolicy();
                }
            }
            return AdBreakWatchedPolicy.WATCHED_ON_BEGIN;
        }
    }
    
    

On this page