Content player playheads on iOS

This pages explains how to create a custom playhead adapter if the player you are using is not supported by the official playhead adapters found on our Git repository.

  1. Overview
  2. Sample playhead adapters
  3. Create a custom playhead adapter

Overview

To be able to trigger Ad breaks at the right moment, the SVSAdManager needs to monitor your content's playback.

This is made possible through playhead adapters that are binded to your content player. A playhead adapter is a class that implements the SVSContentPlayerPlayHead protocol. This protocol is made up of 4 methods returning:

  • Content player's total duration
  • Content player's current time
  • Content player's volume level
  • Whether or not the content player is currently playing

Smart provides open source playhead adapters for the most popular content players, and you can also create your own adapter very easily.

Sample playhead adapters

For your convenience, Smart provides some open sourced playhead adapters on Github.

You can download them on the public repository.

You will find ready to use playhead adapters for:

  • AVPlayer
  • JWPlayer SDK
  • BrightCove Player SDK
  • OOyala player SDK

These adapters are plug and play. Download the class corresponding to your content player, initialize it as documented in the adapter and you'll be able to pass it to the SVSAdManager when starting it.

Create a custom playhead adapter

If you use another content player, and you cannot access the AVPlayer instance it is based on, you will have to create your own player playhead adapter.

It is pretty straightforward, you just have to create a class that implements the SVSContentPlayerPlayHead protocol.



// Declaration of your Player class
// MyPlayerClass.h

// This is what public APIs you content player is likely to have
// This will change depending on which player you use...
@interface MyPlayerClass : NSObject // (or whatever...)
- (NSTimeInterval)currentTime;
- (NSTimeInterval)duration;
- (float)volumeLevel;
- (BOOL)isPlaying;
@end

/////////////////////////////////////////////////////

// Declaration of your custom Playhead Adapter class
// MyCustomPlayheadAdapter.h

@protocol SVSContentPlayerPlayHead;
@class AVPlayer;

@interface MyCustomPlayheadAdapter : NSObject 

// Initialize an instance of MyCustomPlayheadAdapter.
- (instancetype)initWithMyPlayerInstance:(MyPlayerClass *)player unknownContentDuration:(BOOL)unknownContentDuration;

@end

/////////////////////////////////////////////////////

// Implementation of your custom Playhead Adapter class
// MyCustomPlayheadAdapter.m

@interface MyCustomPlayheadAdapter ()
@property (nonatomic, weak) MyPlayerClass *player;
@property (nonatomic, assign) BOOL infiniteDuration;
@end

@implementation MyCustomPlayheadAdapter

- (instancetype)initWithMyPlayerInstance:(MyPlayerClass *)instance unknownContentDuration:(BOOL)unknownContentDuration; {
    self = [super init];

    if (self) {
        self.player = player;
        self.infiniteDuration = unknownContentDuration;
    }

    return self;
}

#pragma mark - SVSContentPlayerPlayHead Protocol

- (NSTimeInterval)contentPlayerCurrentTime {
    // You need to return the current time of your player instance
    return [self.player currentime];
}

- (NSTimeInterval)contentPlayerTotalTime {
    // If duration is unknown, return the constant to flag this kind of content: kSVSContentPlayerTotalDurationInfinite.
    // This will allow the SVSAdManager to properly display ad breaks without using cuePoints but interval and offset.
    if (self.infiniteDuration) {
        return kSVSContentPlayerTotalDurationInfinite;
    }
    return [self.player duration];
}

- (float)contentPlayerVolumeLevel {
    // You need to return the current volume level of your player instance
    return [self.player volumeLevel];
}

- (BOOL)contentPlayerIsPlaying {
    // You need to return whether or not your player is currently playing
    return [self.player isPlaying];
}

@end

Note that you might want to distinguish between content with known duration and (streamed) content with unknown duration directly at initialization. This is very important for ad breaks to be displayed properly when you stream live content.