Server-side ad insertion (SSAI) for tvOS

Server-side ad insertion (SSAI) allows you to serve ads that are dynamically inserted into video content at the server level before content is delivered to the viewer's device. This is in contrast to client-side ad insertion (CSAI), where the viewer's device inserts ads during playback. Ad insertion on the server side is typically in real-time or near real-time. SSAI offers several advantages over CSAI, such as:

  • Server-level ad insertion makes advertisements less susceptible to ad blockers used by viewers, resulting in higher delivery rates.
  • SSAI allows for more precise ad targeting based on real-time viewer data, leading to higher ad relevance and engagement.
  • Ads are seamlessly integrated into the video stream. Therefore, viewers experience smooth playback without buffering or quality degradation during ad transitions.

This page explains how to configure the Wowza Flowplayer Apple SDK to work with Google's Interactive Media Ads Dynamic Ad Insertion (IMA DAI) SDK.

Before you start

For Google's IMA DAI integration to work with the Wowza Flowplayer Apple SDK for iOS or tvOS, you need the following:

info

DAI Pod Serving is a beta intended for Ad Manager publishers and video technology partners who either have an in-house manifest manipulation service or are currently using third-party manifest manipulation that's already integrated with DAI.

Configure DAI ads with Wowza Video

If you're using the MediaOVP media type to load your video, you can configure DAI media and advertisements in Wowza Video. This section describes how to set up DAI ads to load with your video content from Wowza Video, then use those configurations with the Apple SDK. At this time, we only support Google's VOD full service solution in Wowza Video.

  1. Begin by adding your video content on the Videos page in Wowza Video.
  2. Once you create the video, go to the video's Metadata tab and note the media Id . This serves as the mediaId value to load Wowza media when using our SDKs. For more, see Retrieve a video ID .
  3. Go to Advertising > Ad schedules in Wowza video to create your ad schedule . To set up a DAI ad schedule, see Create a Google Ad Manager DAI ad schedule in Wowza Video. Save your ad schedule.
  4. Go to Players > Configurations in Wowza Video to add a new player configuration . When you add the player configuration, select the ad schedule you created in step 4 from the Ad Schedule dropdown. Save your changes.
  5. Once you create the player configuration, go to the General tab for this configuration and note the configuration Id . This serves as the playerId value to load Wowza media when working with our SDKs.

After the previous steps, you can use the mediaId and playerId values to load the Wowza Video media. These example values are placeholders and must be replaced with your own:

Copy
Copied
let platformMedia = MediaOVP(mediaId: "[your-media-id]", playerId: "[player-configuration-id]")
let player.load(ovp: platformMedia)

Configure DAI media programmatically

The MediaDAI structure allows you to work with Google's Interactive Media Ads Dynamic Ad Insertion (IMA DAI) SDK to inject server-side ads into your player. We support both of Google's Full service and Pod serving DAI solutions. You can use these Google IMA sample streams when testing HLS streams with your workflows.

To successfully load DAI media, leverage the MediaDAI structure and types in the following table when initializing the player.

Parameters Description
stream
object
Defines the stream content to be played. Can be used with the following types:
  • DAIStreamVOD for full-service VOD stream requests.
  • DAIStreamPodVOD for pod-serving VOD stream requests.
  • DAIStreamLive for full-service live stream requests.
  • DAIStreamPodLive for pod-serving live stream requests.

Get pod-serving stream data

Pod-serving scenarios require the DAIStreamPodData structure to fetch the content URL and associated subtitles when you're working with a manifest manipulator or third-party partner. This struct takes the required properties in the following table.

Property Description
streamURL
String
Holds the URL of the video stream as provided by a manifest manipulator or third-party partner using pod serving. For DAI live pod serving, a stream_id query parameter is appended to the URL. If the streamURL for a DAI live pod request already contains a stream_id parameter, it's overwritten by the stream ID received from the DAI SDK.
subtitles
Array
Holds an optional array of dictionaries, with each dictionary representing a set of subtitles for a specific language. If present, the subtitles are loaded with the stream.

DAI VOD stream parameters

This table summarizes the parameters to include when using the MediaDAI structure with the DAIStreamVOD (full service) and DAIStreamPodVOD (pod serving) types. You can see which parameters are optional or required, as well as determine when to use them with full-service or pod-serving video-on-demand (VOD) requests. For more, see these Google IMA DAI SDK references:

Parameters Required Applies to DAI solution Description
backupStream
String
Optional VOD Full service/Pod serving Optional back-up stream to use in case the main stream fails to play.
bookmark
Double
Optional VOD Full service/Pod serving Indicates the time (in seconds) where you want to start the DAI VOD stream. This value represents the content time to skip to. Any ad time occurring before the bookmark value is appended to the content time and start position. See Bookmarking for iOS or Bookmarking for tvOS.
contentSourceID
String
Required VOD Full service Serves as a unique identifier for the published content from a CMS. To retrieve this ID in the Media RSS (MRSS) feed from Google, create the content source in your Google Ad Manager UI. Helps Google's ad service systems associate the correct ad inventory and ad targeting criteria with the specific content being streamed. For more, see Google's API reference.
loadStreamData(streamID)
function
Required VOD Pod serving Function that takes a single parameter, streamID of type String, and returns a DAIStreamPodData object asynchronously. The DAIStreamPodData object represents the stream source and subtitles (if any) obtained from a manifest manipulator or third-party partner. The provided URL is then used internally to load and play the video content.
networkCode
String
Required VOD Pod serving Network code for the publisher making the stream request. Corresponds to the network code for your Ad Manager 360 account. Helps Google's ad serving systems route ad request and responses to the correct publisher account and manage ad inventory effectively. For more, see Google's API reference.
videoID
String
Required VOD Full service Identifier for each individual video asset the Google MRSS feed uses to populate the content source library. Helps Google's ad serving systems to associate ad targeting criteria and ad insertion policies with specific videos. For more, see Google's API reference.
Example

The following code snippet illustrates how to use the load() method to inject DAI media into the player. The example first initializes the DAI stream object for VOD content with required parameters. It then uses the created stream to initialize the MediaDAI object and load the stream in your player.

VOD full serviceVOD pod serving (Beta)
Copy
Copied
// Ensure you have a valid backup stream URL or set it to nil if not available
let backupStreamURL: URL? = URL(string: "https://example.com/backup")

// Create DAIStreamVOD object and define parameters
let stream = DAIStreamVOD(
    contentSourceID: "[your-content-source-id]",
    videoID: "[your-video-id]",
    backupStream: backupStreamURL
)

// Create MediaDAI object
let media  = MediaDAI(stream: stream)

// Load the media into the player
let player.load(dai: media)
Copy
Copied
// Fetch and return the stream URL and existing subtitles from your video technology partner (VTP) API calls
// Ensure your implementation handles potential errors and returns a valid URL for the given streamID
// Return nil for subtitles if there are none
public var loadStreamData: (_ streamID: String) async throws -> DAIStreamPodData = { streamID in
    let (url, subtitles) = try await myAPIForFetchingStreamData(streamID: streamID)
    return DAIStreamPodData(streamURL: url, subtitles: subtitles)
}

// Define the backup stream URL or use nil if there's no backup
let backupStreamURL: URL? = URL(string: "https://example.com/backup")

let stream = DAIStreamPodVOD(
    networkCode: "[your-network-code]", 
    loadStreamData: loadStreamData, 
    backupStream: backupStreamURL
)

let mediaDAI = MediaDAI(stream: stream)
let player.load(dai: mediaDAI)

DAI live stream parameters

This table summarizes the parameters to include when using the MediaDAI structure with DAIStreamLive (full service) and DAIStreamPodLive (pod serving) types. You can see which parameters are optional or required, as well as determine when to use them with full-service or pod-serving live stream requests. For more, see these Google IMA DAI SDK references:

Parameters Required Applies to DAI solution Description
apiKey
String
Optional Live Full service/Pod serving Represents an API key needed for authentication or authorization when retrieving a stream ID from the DAI service.
assetKey
String
Required Live Full service Determines which live stream should play. The live stream request asset key identifier can be found in the DFP UI. For more, see Google's API reference.
backupStream
String
Optional Live Full service/Pod serving Optional back-up stream to use in case the main stream fails to play.
customAssetKey
String
Required Live Pod serving The custom asset key that identifies your pod serving event in Ad Manager 360. This can be created by your manifest manipulator or third-party pod serving partner. For more, see Google's API reference.
networkCode
String
Required Live Pod serving Network code for the publisher making the stream request. Corresponds to the network code for your Ad Manager 360 account. Helps Google's ad serving systems route ad request and responses to the correct publisher account and manage ad inventory effectively. For more, see Goolge's API reference.
streamData: DAIStreamPodData
Object
Required Live Pod serving Holds the data related to the stream and encapsulates it in a DAIStreamPodData object. This data is provided by your manifest manipulator or third-party partner using pod serving.
Example

The following code snippet illustrates how to use the load() method to inject DAI media into the player. This example first initializes the DAI stream object for live content with required parameters. It then uses the created stream to initialize the MediaDAI object and load the stream in your player.

Live full serviceLive pod serving
Copy
Copied
// Create DAIStreamLive object and define parameters
let stream = DAIStreamLive(
    apiKey: "[your-api-key]", 
    assetKey: "[your-asset-key]"
)

// Create MediaDAI object
let mediaDAI = MediaDAI(stream: stream)

// Load the media into the player
let player.load(dai: mediaDAI)
Copy
Copied
let streamData = DAIStreamPodData(streamURL: URL, subtitles: [[String: String]]? = nil)

// Define the backup stream URL or use nil if there's no backup
let backupStreamURL: URL? = URL(string: "https://example.com/backup")

let stream = DAIStreamPodLive(
    networkCode: "[your-network-code]", 
    streamData: streamData, 
    customAssetKey: "[your-custom-asset-key]", 
    apiKey: "[your-api-key]",
    backupStream: backupStreamURL
)

let media  = MediaDAI(stream: stream)
let player.load(dai: media)

Listen for DAI events

When working with DAI stream content, you can use the delegate method or the NotificationCenter class to consume player-emitted events. See the FlowplayerDAIDelegate or the DAI stream notifications sections for information about capturing DAI stream events, such as stream errors, stream state changes, and stream ad playback progress.

Handle DAI stream errors

If an error is related to a DAI-stream, it returns the AdError object. For error descriptions, see the AdError custom error type.

Supported features

When using the Wowza Flowplayer Apple SDK, you can take advantage of the supported DAI features described in this section. These DAI features can be implemented when adding the player to your iOS or tvOS applications.

Bookmarking

In the Google IMA DAI SDK, bookmarking refers to the capability of saving a user's viewing session progress. This feature can only be used with VOD full-service and pod-serving DAI content, where users pause or stop watching and then resume later at their last watched position.

Bookmarking can be especially important in scenarios where content includes dynamically-inserted advertisements. If a user stops watching in the middle of an ad break, bookmarking ensures they can resume playback without having to re-watch previously seen ads. Overall, bookmarking provides a seamless experience and continuity in video playback so users can pick up where they left off.

Example

The following example loads a DAI VOD full service stream and sets the bookmark value to 20 seconds. Therefore, if a 10 second pre-roll ad was part of the DAI stream, the player would account for the ad time and start the DAI stream at 30 seconds.

Copy
Copied
// Ensure you have a valid backup stream URL or set it to nil if not available
let backupStreamURL: URL? = URL(string: "https://example.com/backup")

// Create DAIStreamVOD object and define parameters
let stream = DAIStreamVOD(
    contentSourceID: "[your-content-source-id]",
    videoID: "[your-video-id]",
    // Skip to 20 seconds in the DAI stream and also account for any ad time
    bookmark: 20,
    backupStream: backupStreamURL
)

// Create MediaDAI object
let media  = MediaDAI(stream: stream)

// Load the media into the player
let player.load(dai: media)

For more, see Google's IMA DAI SDK for iOS bookmarks or IMA DAI SDK for tvOS bookmarks topics.

Snapback

The snapback feature is automatically integrated into the Wowza Flowplayer Apple SDK when you play a DAI VOD full-service or pod-serving stream. It doesn't apply to DAI live-stream content. There's no additional configuration to use it.

With the snapback feature, you can make sure that if dynamic ad insertion is enabled for the stream, viewers cannot seek past your mid-roll ads. For example, when a user seeks past an ad break, you can take them back to the start of that ad break. You can then return them to their seek location after the ad break is finished. Overall, the snapback feature ensures that any ads that were scheduled to play are appropriately handled.

For more, see Google's IMA DAI SDK for iOS snapback or IMA DAI SDK for tvOS snapback topics.