Prepare client for pod serving redirect

  • This guide provides steps for building a client application to load HLS or DASH livestreams with Pod serving API and a manifest manipulator.

  • Prerequisites include configuring a livestream event with the Pod serving redirect DAI type and determining IMA SDK availability for your platform.

  • To initiate a stream, make a POST request to the livestream service method, passing ad targeting parameters, and store the returned stream session ID and other data from the JSON response.

  • Poll for ad metadata by making a GET request to the metadata_url obtained from the stream registration response, saving the tags object and setting a timer based on polling_frequency.

  • Load the stream into your video player using the session ID and listen for ad events by checking timed metadata in your stream's container format.

  • Show ad event data by using the ad event ID to find corresponding TagSegment and AdBreak objects from the ad metadata.

  • Send media verification pings for all ad events except those of type progress by appending the full ad event ID to the media_verification_url and making a GET request.

This guide covers developing a client application to load an HLS or DASH livestream with Pod serving API and your manifest manipulator.

Prerequisites

Before continuing, you must have the following:

Make a stream request

When your user selects a stream, do the following:

  1. Make a POST request to the livestream service method. For details, see Method: stream.

  2. Pass ad targeting parameters in application/x-www-form-urlencoded or application/json formats. This request registers a stream session with Google DAI.

    The following example makes a stream request:

    Form encoding

    const url = `https://dai.google.com/ssai/pods/api/v1/` +
          `network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/stream`;
    
    const params = new URLSearchParams({
            cust_params: 'section=sports&page=golf,tennis'
    }).toString();
    
    const response = await fetch(url, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/x-www-form-urlencoded'
            },
            body: params
    });
    
    console.log(await response.json());
    

    JSON encoding

    const url = `https://dai.google.com/ssai/pods/api/v1/` +
          `network/NETWORK_CODE/custom_asset/CUSTOM_ASSET_KEY/stream`;
    
    const response = await fetch(url, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json'
            },
            body: JSON.stringify({
              cust_params: {
                section: 'sports',
                page: 'golf,tennis'
              }
            })
    });
    
    console.log(await response.json());
    

    If successful, you see output similar to the following:

    {
    "stream_id": "c4a5dad5-aaa8-4550-8acb-7cda3cdb21bb:DLS",
    "media_verification_url": "https://dai.google.com/view/.../event/c14aZDWtQg-ZwQaEGl6bYA/media/",
    "metadata_url": "https://dai.google.com/linear/pods/hls/.../metadata",
    "session_update_url": "https://dai.google.com/linear/.../session",
    "polling_frequency": 10
    }
    
  3. In the JSON response, locate the stream session ID and store other data for subsequent steps.

Poll ad metadata

To poll ad metadata, do the following:

  1. Read the metadata_url value from the stream registration response.

  2. Make an initial GET request to the metadata_url endpoint.

    • Omit the delta_token query parameter. This process lets the server return the full metadata for the stream's Digital Video Recorder (DVR) window. The DVR window contains the timeframe of the broadcast available for a viewer to rewind and play. The response includes a next_delta_token field.
  3. To optimize bandwidth, store the next_delta_token value from the most recent response.

  4. On your next request, send that value as the delta_token query parameter. The server returns only the metadata that changed since that token was generated. Always send the latest token you received. Don't attempt to parse, modify, or construct the token. For details, see Method: metadata.

    The following example fetches ad metadata:

    // Initial request (returns full metadata and next_delta_token)
    let response = await fetch(metadata_url);
    let metadata = await response.json();
    let deltaToken = metadata.next_delta_token;
    
    // Subsequent request (returns only changes since deltaToken)
    if (deltaToken) {
      const url = new URL(metadata_url);
      url.searchParams.append('delta_token', deltaToken);
      response = await fetch(url.toString());
      const deltaMetadata = await response.json();
      // Merge deltaMetadata into your local cache
      mergeMetadata(metadata, deltaMetadata);
      deltaToken = deltaMetadata.next_delta_token;
    }
    

    If successful, you receive the PodMetadata response. If you provide the delta_token parameter, the response contains only the ads, ad breaks, and tags that the server added or updated since the server generated the token. The response also contains a new next_delta_token value. If any ad breaks are outdated, the response also includes an obsolete_ad_break_ids list of the ad breaks to remove from your cache.

    {
      "next_delta_token": "eyJyYW5nZXMiOlt7InMiOjEsImUiOjN9XX0",
      "obsolete_ad_break_ids": ["0003069407"],
      "tags":{
        "google_1022389921":{
          "ad":"0003069408_ad1",
          "ad_break_id":"0003069408",
          "type":"start"
        },
        ...
      },
      "ads":{
        "0003069408_ad1":{
          "ad_break_id":"0003069408",
          "position":1,
          "duration":10.01,
          "title":"External - Pod Midroll 1",
          "clickthrough_url":"https://.../",
          ...
        },
        ...
      },
      "ad_breaks":{
        "0003069408":{
          "type":"mid",
          "duration":30,
          "ads":3
        },
        ...
      }
    }
    
  5. Save the tags object and merge updates into your local cache. If the obsolete_ad_break_ids parameter is present, remove those ad breaks and associated ads and tags from your cache.

  6. Set a timer using the polling_frequency value to regularly request metadata. In each poll, send the next_delta_token value returned in the most recent metadata response as the delta_token query parameter.

Load the stream into your video player

After you have the session ID from the registration response, pass the ID to your manifest manipulator, or construct a manifest URL to load the stream into a video player.

To pass the session ID, see your manifest manipulator documentation. If you develop a manifest manipulator, see Manifest manipulator for livestream.

The following example assembles a manifest URL:

https://<your_manifest_manipulator_url>/manifest.m3u8?DAI_stream_ID=SESSION_ID&network_code=NETWORK_CODE&DAI_custom_asset_key=CUSTOM_ASSET_KEY"

When your player is ready, begin playback.

Listen for ad events

Check your stream's container format for the timed metadata:

  • HLS streams with Transport Stream (TS) containers use timed ID3 tags to carry timed metadata. For details, see About the Common Media Application Format with HTTP Live Streaming (HLS).

  • DASH streams use EventStream elements to specify events in the manifest.

  • DASH streams use InbandEventStream elements when the segments contain Event Message (emsg) boxes for payload data, including ID3 tags. For details, see InbandEventStream.

  • CMAF streams, including DASH and HLS, use emsg boxes containing ID3 tags.

To retrieve ID3 tags from your stream, refer to your video player's guide. For details, see Handle timed metadata guide

To retrieve the ad event ID from ID3 tags, do the following:

  1. Filter the events by scheme_id_uri with urn:google:dai:2018 or https://aomedia.org/emsg/ID3.
  2. Extract the byte array from the message_data field.

    The following example decodes the emsg data into JSON:

    {
      "scheme_id_uri": "https://developer.apple.com/streaming/emsg-id3",
      "presentation_time": 27554,
      "timescale": 1000,
      "message_data": "ID3TXXXgoogle_1022389921",
      ...
    }
    
  3. Filter the ID3 tags with the format TXXXgoogle_{ad_event_ID}:

    TXXXgoogle_1022389921
    

Show ad event data

To find the TagSegment object, do the following:

  1. Retrieve the ad metadata tags object from Poll ad metadata. The tags object is an array of TagSegment objects.

  2. Use the full ad event ID to find a TagSegment object with the type progress.

  3. Use the first 17 characters of the ad event ID to find a TagSegment object of other types.

    Because your client app polls ad metadata periodically, a delay might occur between when your video player encounters an ID3 tag in the stream and when the associated metadata is available. If your client app doesn't find an ID3 tag in the stored tags, keep the tag in a queue and re-process the tag after the next metadata poll. Keep the tag in the queue until processing finishes.

  4. After you have the TagSegment, use the ad_break_id property as the key to find the AdBreak object in the ad metadata ad_breaks object.

    The following example finds an AdBreak object:

    {
      "type":"mid",
      "duration":15,
      "ads":1
    }
    
  5. Use the TagSegment and AdBreak data to show information about the ad position in the ad break. For example, Ad 1 of 3.

Send media verification pings

For every ad event, except the progress type, send a media verification ping. Google DAI discards progress events, and sending these events frequently might impact your app performance.

To generate the complete media verification URL of an ad event, do the following:

  1. From the stream response, append the full ad event ID to the media_verification_url value.

  2. Make a GET request with the complete URL:

    // media_verification_url: "https://dai.google.com/view/.../event/c14aZDWtQg-ZwQaEGl6bYA/media/"
    const completeUrl = `${media_verification_url}google_1022389921`;
    
    const response = await fetch(completeUrl);
    

    If successful, you receive a code status 202 response. Otherwise, you receive a 404 error code.

You can use the Stream Activity Monitor (SAM) to inspect a historical log of all ad events. For details, see monitor and troubleshoot a livestream