Page Summary
-
This guide explains how to insert ad breaks using the Ad pod Timing Metadata (ATM) method for precise timing and duration, including pre-roll ads.
-
To implement this, you need a livestream event set up for Pod serving redirect Dynamic Ad Insertion (DAI) type in Google Ad Manager.
-
Retrieving ad pod timing metadata requires generating and using a signed HMAC token with the ATM API.
-
Pre-roll and mid-roll ad timing metadata are requested through specific ATM API calls, requiring different parameters.
-
Ad segments are stitched into the content manifest by replacing ad markers with discontinuity tags and inserting ad and/or slate segment URLs based on the ATM API response.
This guide describes how to insert ad breaks using the Ad pod Timing Metadata (ATM) method to fetch the precise timing and duration for ad breaks, including pre-roll ads.
To insert pre-roll ads and manage the return to content after mid-roll ad breaks, we recommend calling the following APIs:
- Ad pod Timing Metadata (ATM) API: query ad pod decision results, including ad and slate durations.
- Ad segment endpoint: request ad or slate segments with the option to terminate the current ad pod.
Optionally, for high concurrency livestream events, we recommend calling Early Ad Break Notification (EABN) API to schedule ad decisions before the ad break begins.
Prerequisites
To get started, you need a livestream event set up for the Pod serving redirect Dynamic Ad Insertion (DAI) type. Choose one of the following methods:
- Ad Manager UI: Set up a livestream for DAI.
- Ad Manager API: Use a client library (available
options) to call
LiveStreamEventService.createLiveStreamEventsmethod. Set theLiveStreamEvent.dynamicAdInsertionTypeparameter toPOD_SERVING_REDIRECT.
Retrieve the content stream
When a user selects a livestream event, the client app makes a stream request to Google Ad Manager. In the stream response, the app extracts the Google DAI session ID and metadata to include in the stream manifest request.
The following example passes a Google DAI session ID to a manifest manipulator:
https://MANIFEST_MANIPULATOR_URL/manifest.m3u8?DAI_stream_ID=SESSION_ID&network_code=NETWORK_CODE&DAI_custom_asset_key=CUSTOM_ASSET_KEY
When processing the video content playback request, store the Google DAI session ID and CUSTOM_ASSET_KEY from the request to prepare for ad stitching.
Retrieve ad pod timing metadata
To retrieve the ad pod timing, follow these steps:
- Generate an HMAC token.
- Call the ATM API with the HMAC token.
Request timing metadata for pre-roll ads
Verify pre-roll settings for your livestream event using the following options:
To retrieve the pre-roll ad decision results, make a request to the ATM API.
The following example makes an ATM request for pre-roll ads:
curl "https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/pod.json?stream_id=SESSION_ID&ad_break_id=preroll&auth-token=your_signed_HMAC_token"
Request timing metadata for mid-roll ads
To retrieve ad pod metadata for mid-rolls, follow these steps:
- Parse the livestream manifest to find the ad markers that contain the timing and duration for each mid-roll ad break.
- Call the ATM API endpoint to request the precise ad pod and slate duration. The API returns a JSON object with the ad pod's decision results.
The following example makes an ATM request for mid-roll ads:
curl "https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/pod.json?stream_id=SESSION_ID&ad_break_id=AD_BREAK_ID&pd=AD_BREAK_DURATION&auth-token=your_signed_HMAC_token"
If successful, you see output similar to the following JSON object:
{
"status": "final",
"ads": [
{
"duration_ms": 5046,
"variants": {
"devrel1428000": {
"segment_extension": "ts",
"segment_durations": {
"timescale": 1000,
"values": [
5045
]
}
},
"devrel1928000": {
"segment_extension": "ts",
"segment_durations": {
"timescale": 1000,
"values": [
5045
]
}
}
}
}
],
"slate": {
"duration_ms": 0,
"variants": {
"devrel1428000": {
"segment_extension": "ts",
"segment_durations": {
"timescale": 1000,
"values": [
5005,
...
5046
]
}
},
"devrel1928000": {
"segment_extension": "ts",
"segment_durations": {
"timescale": 1000,
"values": [
5005,
...
5046
]
}
}
}
}
}
Stitch ads into content manifest
The following sections walk you through how to modify the livestream manifest and add the ad segments.
Identify ad break segments and insert discontinuities
As you process each variant manifest, identify the EXT-X-CUE-IN and
EXT-X-CUE-OUT tags in your stream, indicating the start and end of an ad
break.
Replace the EXT-X-CUE-IN and EXT-X-CUE-OUT tags with the
EXT-X-DISCONTINUITY elements for the client video player to switch between
content and ads.
The following example manifest replaces the EXT-X-CUE-IN and EXT-X-CUE-OUT
tags:
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:5.000,
contentorigin.com/1.ts
#EXTINF:5.000,
contentorigin.com/2.ts
#EXT-X-CUE-OUT:17.450
#EXTINF:5.000,
contentorigin.com/3.ts
#EXTINF:5.000,
contentorigin.com/4.ts
#EXTINF:5.000,
contentorigin.com/5.ts
#EXTINF:2.450,
contentorigin.com/6.ts
#EXT-X-CUE-IN
#EXTINF:5.000,
contentorigin.com/7.mp4
#EXTINF:5.000,
contentorigin.com/8.mp4
The following example shows a replaced manifest:
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:5.000,
contentorigin.com/1.ts
#EXTINF:5.000,
contentorigin.com/2.ts
#EXTINF:5.000,
#EXT-X-DISCONTINUITY
{... Insert ad segments here ...}
#EXT-X-DISCONTINUITY
#EXTINF:5.000,
contentorigin.com/7.mp4
#EXTINF:5.000,
contentorigin.com/8.mp4
Google DAI ad segments are not encrypted. If your content is encrypted, remove
encryption by inserting EXT-X-KEY:METHOD=NONE element prior to the first ad
segment of each ad break. At the end of the ad break, add encryption back by
inserting an appropriate EXT-X-KEY.
Keep track of the start time, duration, and index of the upcoming ad break.
Build ad segment URLs
Replace the content segments between the EXT-X-DISCONTINUITY tags with URLs
for each ad segment. To determine how many ad segments to insert, use the
ads.segment_durations.values provided in the JSON response from the ATM API.
To return to content before the ad pod is complete, such as when detecting an
EXT-X-CUE-IN tag, your manifest
manipulator must add the d= parameter to the URL of the final ad segment.
This parameter shortens the segment to avoid affecting the client video player's
timeline.
The following example assembles a pre-roll ad segment URL to the manifest. Note that ad segments use a zero-based index:
https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/ad_break_id/preroll/ad/0/profile/ENCODING_PROFILE/0.ts?stream_id=SESSION_ID
The following example assembles a mid-roll ad segment URL to the manifest:
https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/ad_break_id/AD_BREAK_ID/ad/0/profile/ENCODING_PROFILE/0.ts?stream_id=SESSION_ID
The following example inserts ad segments to the manifest:
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:5.000,
contentorigin.com/1.ts
#EXTINF:5.000,
contentorigin.com/2.ts
#EXT-X-DISCONTINUITY
#EXTINF:5.000,
https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/ad_break_id/AD_BREAK_ID/ad/0/profile/ENCODING_PROFILE/0.ts?stream_id=SESSION_ID
#EXTINF:5.000,
https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/ad_break_id/AD_BREAK_ID/ad/0/profile/ENCODING_PROFILE/1.ts?stream_id=SESSION_ID
#EXTINF:5.000,
https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/ad_break_id/AD_BREAK_ID/ad/0/profile/ENCODING_PROFILE/2.ts?stream_id=SESSION_ID
#EXTINF:2.450,
https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/ad_break_id/AD_BREAK_ID/ad/0/profile/ENCODING_PROFILE/3.ts?stream_id=SESSION_ID
#EXT-X-DISCONTINUITY
#EXTINF:5.000,
contentorigin.com/7.mp4
#EXTINF:5.000,
contentorigin.com/8.mp4
Build slate segments
To fill the gap between ad and content, insert slate segments.
Use the slates.segment_durations.values array from the ATM API's JSON response
to determine the duration of each slate segment. Loop the sequence of segment
durations as needed to fill the entire ad break.
To return to content before the ad pod is complete, such as when detecting an
EXT-X-CUE-IN tag, add the d= parameter to the URL of the final slate
segment. This parameter shortens the segment to avoid affecting the client video
player's timeline. The value for the d= parameters must be an integer,
representing the duration in milliseconds to shorten the segment.
The following example assembles a slate segment:
https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/ad_break_id/AD_BREAK_ID/slate/0/profile/ENCODING_PROFILE/0.ts?stream_id=SESSION_ID
The slate/0 in the example represents the slate iteration number. Refer to
your client video player's compatibility and caching capability to determine
whether to start at 0 and increment this number for each loop of the slate,
or keep it at 0 for all iterations.
Manage the return to content
After your manifest manipulator inserts all segments from the ad pod, your manifest manipulator must transition back to the content stream. To transition back to the content stream, choose one of the following methods. Each method requires a final re-alignment segment to keep the stream timeline accurate.
Fill and Re-align: Insert the slate segments and loop the slate.
Fill the duration and insert EXT-X-DISCONTINUITY elements between each slate
iteration. For the last segment, append the d= parameter in milliseconds
to match the content start.
Immediate Return: Insert a single re-alignment slate segment by using
the d= parameter and following with content.
The video player transitions back to the content without an altered timeline.
The following example creates a transition by filling the remainder of the ad break duration with slate segments.
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:5.000,
contentorigin.com/1.ts
#EXTINF:5.000,
contentorigin.com/2.ts
#EXT-X-DISCONTINUITY
#EXTINF:5.000,
https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/ad_break_id/AD_BREAK_ID/ad/0/profile/ENCODING_PROFILE/0.ts?stream_id=SESSION_ID
#EXTINF:5.000,
https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/ad_break_id/AD_BREAK_ID/ad/0/profile/ENCODING_PROFILE/1.ts?stream_id=SESSION_ID
#EXTINF:5.000,
https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/ad_break_id/AD_BREAK_ID/slate/0/profile/ENCODING_PROFILE/0.ts?stream_id=SESSION_ID
#EXT-X-DISCONTINUITY
#EXTINF:2.450,
https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/ad_break_id/AD_BREAK_ID/slate/0/profile/ENCODING_PROFILE/1.ts?stream_id=SESSION_ID&d=2450
#EXT-X-DISCONTINUITY
#EXTINF:5.000,
contentorigin.com/7.mp4
#EXTINF:5.000,
contentorigin.com/8.mp4
In this method, your manifest
manipulator loops the slate as needed and appends the d= URL parameter only
to the last slate segment. This process aligns precisely with the scheduled
start of the underlying content.
The following example shows how to use a single slate segment with the d=
parameter to help keep the player timeline accurate when you don't
fill the entire remaining break with looped slates.
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:5.000,
contentorigin.com/1.ts
#EXTINF:5.000,
contentorigin.com/2.ts
#EXT-X-DISCONTINUITY
#EXTINF:5.000,
https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/ad_break_id/AD_BREAK_ID/ad/0/profile/ENCODING_PROFILE/0.ts?stream_id=SESSION_ID
#EXTINF:5.000,
https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/ad_break_id/AD_BREAK_ID/ad/0/profile/ENCODING_PROFILE/1.ts?stream_id=SESSION_ID
#EXTINF:5.000,
https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/ad_break_id/AD_BREAK_ID/ad/0/profile/ENCODING_PROFILE/2.ts?stream_id=SESSION_ID
#EXT-X-DISCONTINUITY
#EXTINF:2.450,
https://dai.google.com/linear/pods/v1/adv/network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/ad_break_id/AD_BREAK_ID/slate/0/profile/ENCODING_PROFILE/0.ts?stream_id=SESSION_ID&d=2450
#EXT-X-DISCONTINUITY
#EXTINF:5.000,
contentorigin.com/7.mp4
#EXTINF:5.000,
contentorigin.com/8.mp4
Optional: Schedule an ad break
To enhance your fill rate, send an Early Ad Break Notification (EABN) with the ad pod duration, custom targeting parameters, and SCTE-35 signal data. For more details, see Send early ad break notifications.