> [!NOTE]
> **Note:** Before moving forward with this guide, you must complete the steps in [Set up the player class](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/html5/hbbtv-player.md.txt).

In `ads_manager.js`, define a wrapper class for the IMA SDK StreamManager that
makes stream requests, gets the ad pod manifest, listens to IMA stream events,
and passes emsg events to the IMA SDK.

In `ads_manager.js`, the IMA HbbTV sample app sets up the following methods:

- `requestStream()`
- `onStreamEvent()`
- `onEmsgEvent()`
- `loadAdPodManifest()`

## Initialize ads manager

Initialize the ads manager class and set listeners for the IMA stream events. In
this call, set the emsg event handler with the
`VideoPlayer.setEmsgEventHandler()` method.

> [!IMPORTANT]
> **Key Point:** The IMA SDK does not support ad UI on HbbTV. Don't pass the `adUiElement` parameter in the `StreamManager` constructor. Passing `adUiElement` can lead to Ad Manager serving incompatible ads.

```javascript
/**
 * Wraps IMA SDK ad stream manager.
 * @param {!VideoPlayer} videoPlayer Reference an instance of the wrapper from
 * video_player.js.
 */
var AdManager = function(videoPlayer) {
  this.streamData = null;
  this.videoPlayer = videoPlayer;
  // Ad UI is not supported for HBBTV, so no 'adUiElement' is passed in the
  // StreamManager constructor.
  this.streamManager = new google.ima.dai.api.StreamManager(
      this.videoPlayer.videoElement);
  this.streamManager.addEventListener(
      [
        google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED,
        google.ima.dai.api.StreamEvent.Type.ERROR,
        google.ima.dai.api.StreamEvent.Type.CLICK,
        google.ima.dai.api.StreamEvent.Type.STARTED,
        google.ima.dai.api.StreamEvent.Type.FIRST_QUARTILE,
        google.ima.dai.api.StreamEvent.Type.MIDPOINT,
        google.ima.dai.api.StreamEvent.Type.THIRD_QUARTILE,
        google.ima.dai.api.StreamEvent.Type.COMPLETE,
        google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED,
        google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED,
        google.ima.dai.api.StreamEvent.Type.AD_PROGRESS,
        google.ima.dai.api.StreamEvent.Type.PAUSED,
        google.ima.dai.api.StreamEvent.Type.RESUMED
      ],
      this.onStreamEvent.bind(this),
      false);

  this.videoPlayer.setEmsgEventHandler(this.onEmsgEvent, this);
};
```

## Make a request for an ad pod stream

Create the `AdManager.requestStream()` method to create a `PodStreamRequest`
object using your Google Ad Manager network code and the stream's custom asset
key. Test your HbbTV app using the IMA sample DASH pod serving stream with the
following stream parameters:

- **Network code** : `'21775744923'`
- **Custom asset key** : `'hbbtv-dash'`

```javascript
/**
 * Makes a pod stream request.
 * @param {string} networkCode The network code.
 * @param {string} customAssetKey The custom asset key.
 */
AdManager.prototype.requestStream = function (networkCode, customAssetKey) {
  var streamRequest = new google.ima.dai.api.PodStreamRequest();
  var secretKey = getStreamSecretKeys();

  streamRequest.networkCode = networkCode;
  streamRequest.customAssetKey = customAssetKey;
  streamRequest.format = 'dash';

  if (secretKey.STREAM_CREATE_SECRET) {
    var expirationTime = Math.trunc(new Date().getTime() / 1000) + 3600;
    var params = {
      custom_asset_key: customAssetKey,
      exp: expirationTime,
      network_code: networkCode
    };
    streamRequest.authToken =
        this.generateAuthToken(params, secretKey.STREAM_CREATE_SECRET);
    debugView.log('AdsManager: make Auth-PodStreamRequest');
  } else {
    debugView.log('AdsManager: make PodStreamRequest without auth');
  }

  this.streamManager.requestStream(streamRequest);
};
```

## Listen to ad stream events

Create the `AdManager.onStreamEvent()` method to handle your app's response to
the IMA stream events, `STREAM_INITIALIZED`, `AD_BREAK_STARTED`, and
`AD_BREAK_ENDED`.

```javascript
/**
 * Handles IMA playback events.
 * @param {!Event} event The event object.
 */
AdManager.prototype.onStreamEvent = function(event) {
  switch (event.type) {
    // Once the stream response data is received, generate pod manifest url
    // for the video stream.
    case google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED:
      debugView.log('IMA SDK: stream initialized');
      this.streamData = event.getStreamData();
      break;
    case google.ima.dai.api.StreamEvent.Type.ERROR:
      break;
    // Hide video controls while ad is playing.
    case google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED:
      debugView.log('IMA SDK: ad break started');
      this.adPlaying = true;
      this.adBreakStarted = true;
      break;
    // Show video controls when ad ends.
    case google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED:
      debugView.log('IMA SDK: ad break ended');
      this.adPlaying = false;
      this.adBreakStarted = false;
      break;
    // Update ad countdown timers.
    case google.ima.dai.api.StreamEvent.Type.AD_PROGRESS:
      break;
    default:
      debugView.log('IMA SDK: ' + event.type);
      break;
  }
};
```

## Handle ad stream metadata

To pass the emsg event info to IMA, create the `AdManager.onEmsgEvent()` method
using the `StreamManager.processMetadata()` method. The video player class calls
this method with the `VideoPlayer.setEmsgEventHandler()` method.

```javascript
/**
 * Callback on Emsg event.
 * Instructs IMA SDK to fire back VAST events accordingly.
 * @param {!Event} event The event object.
 */
AdManager.prototype.onEmsgEvent = function(event) {
  var data = event.event.messageData;
  var pts = event.event.calculatedPresentationTime;
  if ((data instanceof Uint8Array) && data.byteLength > 0) {
    this.streamManager.processMetadata('ID3', data, pts);
  }
};
```

## Load the ad pod manifest

Create the `AdManager.loadAdPodManifest()` method to preload the ad pod manifest
with the video player. Construct an authenticated manifest URL using the
structure in [Method: DASH pod manifest](https://developers.google.com/ad-manager/dynamic-ad-insertion/api/pod-serving/reference/live.md.txt#method_dash_pod_manifest).

```javascript
/**
 * Creates DAI pod url and instructs video player to load manifest.
 * @param {string} networkCode The network code.
 * @param {string} customAssetKey The custom asset key.
 * @param {number} podDuration The duration of the ad pod.
 */
AdManager.prototype.loadAdPodManifest = function (networkCode, customAssetKey, podDuration) {
  if (!this.streamData) {
    debugView.log('AdsManager: No stream data available.');
    return;
  }

  var adBreakId = this.getAdBreakId();
  var expirationTime = Math.trunc(new Date().getTime() / 1000) + 3600;

  var params = {
    ad_break_id: adBreakId,
    custom_asset_key: customAssetKey,
    exp: expirationTime,
    network_code: networkCode,
    pd: podDuration
  };

  var secretKey = getStreamSecretKeys();
  var token = this.generateAuthToken(params, secretKey.MANIFEST_SECRET);
  var encodedToken = encodeURIComponent(token);

  var manifestUrl = 'https://dai.google.com/linear/pods/v1/dash/network/' +
    networkCode + '/custom_asset/' + customAssetKey + '/stream/' +
    this.streamData.streamId + '/ad_break_id/' + adBreakId +
    '/manifest.mpd?pd=' + podDuration + '&auth-token=' + encodedToken;

  this.videoPlayer.preload(manifestUrl);
};
```

The
[HbbTV sample app](https://github.com/googleads/googleads-ima-html5-dai/tree/main/hbbtv)
uses a randomly generated unique `adBreakId` value. In production apps, the
`adBreakId` value is an alphanumeric string, for example `ab-001`, that
increments by one for each ad break. Verify the `adBreakId` value is the same
value for all viewers of the ad break. To get an `adBreakId` value, we
recommend using the
[DAI Ad Break API](https://developers.google.com/ad-manager/dynamic-ad-insertion/api/ad-break.md.txt).
In a production environment, include the `adBreakId` value and `podDuration`
value in the HbbTV stream event `AD_BREAK_ANNOUNCE`.

> [!IMPORTANT]
> **Important:** You must authenticate your ad pod manifest request. Without authentication, Google Ad Manager can't serve ads in the ad pod manifest. To authenticate the request, either schedule your ad break with the DAI Ad Break API or include the `auth-token` [query parameter](https://developers.google.com/ad-manager/dynamic-ad-insertion/api/pod-serving/reference/live.md.txt#query_parameters) in the ad pod manifest request URL.

Next, create the main application class for your HbbTV app that interacts with
the HbbTV broadcast.