# Client video player app for VOD streams

The Google DAI Pod Serving API lets you perform server-side ad insertion powered
by Google Ads while maintaining control of your own video stitching.

> [!IMPORTANT]
> **Key Point:** Before considering this API, check to see if there is already an IMA DAI SDK for your platform of choice. The IMA DAI SDK is recommended on platforms where it is available. The Pod Serving API is intended to be used only on platforms that don't have an IMA DAI SDK.

This guide shows you how to interact with the Pod Serving API and achieve
similar functionality with the IMA DAI SDK. For specific questions about
supported functionality, contact your Google account manager.

The Pod Serving API supports pod serving streams in either HLS or MPEG-DASH
streaming protocols. This guide focuses on HLS streams and highlights the key
differences between HLS and MPEG-DASH in specific steps.

To integrate the Pod Serving API into your app for VOD streams, complete the
following steps:

## Make a stream registration request to Ad Manager

Make a POST request to the stream registration endpoint. You receive in turn a
JSON response containing the stream ID to send to your manifest manipulation
server and associated Pod Serving API endpoints.

#### API endpoint

    POST: /ondemand/pods/api/v1/network/{network_code}/stream_registration
    Host: dai.google.com
    Content-Type: application/json

#### Path parameters

|---|---|
| `{network_code}` | Your Google Ad Manager 360 network code |

#### JSON body parameters

|---|---|
| `targeting_parameters` | A JSON object containing the ad [targeting parameters](https://support.google.com/admanager/answer/7320899). **Required** |

### Response JSON

|---|---|
| `media_verification_url` | The base URL to ping playback tracking events. A complete media verification URL is formed by appending an *ad event ID* to this base URL. |
| `metadata_url` | The URL to request *ad pod metadata*. |
| `stream_id` | The string used to identify the current stream session. |
| `valid_for` | The amount of time left until the current stream session expires, in `dhms` (days, hours, minutes, seconds) format. For example, `2h0m0.000s` represents a duration of 2 hours. |
| `valid_until` | The time at which the current stream session expires, as an ISO 8601 datetime string in `yyyy-MM-dd'T'hh:mm:ss.sssssssss[+|-]hh:mm` format. |

#### Example request (cURL)

    curl -X POST \
         -d '{"targeting_parameters":{"url":"http://example.com"}}' \
         -H 'Content-Type: application/json' \
      https://dai.google.com/ondemand/pods/api/v1/network/21775744923/stream_registration

#### Example response

    {
      "media_verification_url": "https://dai.google.com/.../media/",
      "metadata_url": "https://dai.google.com/.../metadata",
      "stream_id": "6e69425c-0ac5-43ef-b070-c5143ba68541:CHS",
      "valid_for": "8h0m0s",
      "valid_until": "2023-03-24T08:30:26.839717986-07:00"
    }

In case of errors, standard HTTP error codes are returned with no JSON response
body.

Parse the JSON response and store the relevant values.

> [!TIP]
> **Tip:** The URLs provided in the API response are subject to change without notice. Therefore, use the URLs as provided in the API response rather than constructing them yourself. This helps ensure that your code continues to work correctly when the URLs change.

## Request the stream manifest from the manifest manipulator

Each manifest manipulator has a different request and response formats. Contact
your manipulator provider to understand their specific requirements. If you're
implementing your own manifest manipulator, read the [manifest manipulator
guide](https://developers.google.com/dynamic-ad-insertion/api/podserving/vod/manipulator) to understand the
requirements for this component.

In general, you need to pass the stream ID that was returned by the
registration endpoint above to your manifest manipulator for it to build
session-specific manifests. Unless explicitly stated by your manifest
manipulator, the response to your manifest request is a video stream containing
both content and ads.

#### Example request (cURL)

    curl https://{manifest_manipulator}/video/1331997/stream/6e69425c-0ac5-43ef-b070-c5143ba68541:CHS/vod_manifest.m3u8

#### Example response (HLS)

    #EXTM3U
    #EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs0",LANGUAGE="en",NAME="English",AUTOSELECT=YES,DEFAULT=YES,URI="abcd1234_     subitles-en.vtt"
    #EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080,CODECS="avc1.42e00a,mp4a.40.2"
    abcd1234_video-1080p.m3u8

## Play the stream

Load the manifest that you received from the manifest manipulation server into a
video player and start the playback.

## Request ad pod metadata from Ad Manager

Make a `GET` request to the `metadata_url` that you received in step one. This
step must occur after you've received the stitched manifest from your manifest
manipulator. In return, you receive a JSON object containing the following
parameters:

|---|---|
| `tags` | A set of key-value pairs containing all ad events that appear in the stream. The keys are either the first 17 characters of an ad event ID that appear in the stream's timed metadata, or in the case of events of type `progress`, the full ad event ID. Each value is an object containing the following parameters: |---|---| | `ad` | The ID of an ad that matches a key in the `ads` object. | | `ad_break_id` | The ID of an ad break that matches a key in the `ad_breaks` object. | | `type` | The type of ad event. Ad event types are: |---|---| | `start` | Fired at the beginning of the ad. | | `firstquartile` | Fired at the end of the first quartile. | | `midpoint` | Fired at the midpoint of the ad. | | `thirdquartile` | Fired at the end of the third quartile. | | `complete` | Fired at the end of the ad. | | `progress` | Fired periodically throughout the ad, to notify the app that an ad break is playing. | | |
| `ads` | A set of key-value pairs describing all ads that appear in the stream. The keys are ad IDs that match the values found in the `tags` object listed above. Each value is an object containing the following parameters: |---|---| | `ad_break_id` | The ID of an ad break that matches a key in the `ad_breaks` object. | | `position` | The position at which this ad appears within the set of ads in the ad break, in floating point seconds. | | `duration` | The length of the ad in floating point seconds. | | `clickthrough_url` | The URL that should open when a user interacts with this ad, if supported. | |
| `ad_breaks` | A set of key-value pairs describing all ad breaks that appear in the stream. The keys are ad break IDs that match values found in the `tags` and `ads` objects listed above. Each value is an object containing the following parameters: |---|---| | `type` | The type of ad break. Ad break types are `pre` (pre-roll), `mid` (mid-roll), and `post` (post-roll). | | `duration` | The length of the ad break in floating point seconds. | | `ads` | The number of ads in this ad break. | |

Store these values to associate with timed metadata events within your video
stream.

#### Example request (cURL)

    curl https://dai.google.com/.../metadata

#### Example response

    {
      "tags":{
        "google_5555555555":{
          "ad":"0000229834_ad1",
          "ad_break_id":"0000229834",
          "type":"firstquartile"
        },
        "google_1234567890123456789":{
          "ad":"0000229834_ad1",
          "ad_break_id":"0000229834",
          "type":"progress"
        },
        ...
      },
      "ads":{
        "0000229834_ad1":{
          "ad_break_id":"0000229834",
          "position":1,
          "duration":15,
          "clickthrough_url":"https://.../",
          ...
        },
              ...
      },
      "ad_breaks":{
        "0000229834":{
          "type":"mid",
          "duration":15,
          "ads":1
        },
        ...
      }
    }

## Listen for ad events

Listen for timed metadata through triggered ad events in the audio/video stream
of your video player.

For MPEG-TS streams, the metadata appears as in-band ID3 v2.3 tags. Each
metadata tag has the ID `TXXX`, and the value begins with the string `google_`
followed by a series of characters. This value is the *ad event ID*.

The `XXX` in `TXXX` is not a placeholder. The string `TXXX` is the ID3 tag ID
reserved for "user defined text".

#### Example ID3 tag

    TXXXgoogle_1234567890123456789

For MP4 streams, these are sent as in-band emsg events that emulate ID3 v2.3
tags. Each relevant emsg box has a `scheme_id_uri` value of either
`https://aomedia.org/emsg/ID3` or
`https://developer.apple.com/streaming/emsg-id3` and a `message_data` value
beginning with `ID3TXXXgoogle_`. This `message_data` value, without the
`ID3TXXX` prefix, is the *ad event ID*.

#### Example emsg box

The data structure could vary, depending on your media player library.

If the ad event ID is `google_1234567890123456789` the response looks like
this:

    {
      "scheme_id_uri": "https://developer.apple.com/streaming/emsg-id3",
      "presentation_time": 27554,
      "timescale": 1000,
      "message_data": "ID3TXXXgoogle_1234567890123456789",
      ...
    }

Some media player libraries automatically present emsg events that emulate ID3
tags as native ID3 tags. In this case, MP4 streams present identical ID3 tags
as MPEG_TS.

## Update the client video player app's UI

Each ad event ID can be matched to a key in the `tags` object from step 4.
Matching these values is a two-step process:

1. Check the `tags` object for a key matching the full ad event ID. If
   a match is found, retrieve the event type and its associated `ad` and
   `ad_break` objects. These events should have the type `progress`.

   If a match is not found for the full ad event ID, check the `tags`
   object for a key matching the first 17 characters of the ad event ID.
   Retrieve the event type and the associated `ad` and `ad_break` objects.
   This should retrieve all events with types other than `progress`.
2. Use this retrieved information to update your player's UI. For example, when
   you receive a `start` or the first `progress` event, hide your player's seek
   controls and display an overlay describing the current ad's position in the
   ad break, for example: "Ad 1 of 3".

#### Example ad event IDs

    google_1234567890123456789 // Progress event ID
    google_5555555555123456789 // First Quartile event ID

#### Example tags object

    {
      "google_5555555555":{
        "ad":"0000229834_ad1",
        "ad_break_id":"0000229834",
        "type":"firstquartile"
      },
      "google_1234567890123456789":{
        "ad":"0000229834_ad1",
        "ad_break_id":"0000229834",
        "type":"progress"
      },
      ...
    }

## Send media verification pings

A media verification ping must be sent to Ad Manager every time an ad event
with a type other than `progress` is received.

To generate the complete media verification URL of an ad event, append the full
ad event ID to the `media_verification_url` value from the stream registration
response.

Make a GET request with the complete URL. If the verification request is
successful, you receive an HTTP response with status code `202`.
Otherwise, you get the HTTP error code `404`.

> [!TIP]
> **Tip:** Ad events of type `progress` shouldn't be sent to Ad Manager. These events are meant to inform the client video player app that an ad break is playing in situations where the start event might not have been received. For example, if the user seeks to a position or begins playback at a specific timestamp that is in the middle of an ad, they won't receive a start event. Progress events sent to Ad Manager are discarded which could negatively impact an app's performance.

#### Example request (cURL)

    curl https://{...}/media/google_5555555555123456789

#### Example successful response

    HTTP/1.1 202 Accepted

## Additional resources

- [IMA SDK documentation](https://developers.google.com/interactive-media-ads)
- [DAI player implementation types
  comparison](https://support.google.com/admanager/answer/9840889)