Select platform: [HTML5](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/html5/get-started/full-service.md.txt "View this page for the HTML5 platform docs.") [Android](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/android/get-started/full-service.md.txt "View this page for the Android platform docs.") [iOS](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/ios/get-started/full-service.md.txt "View this page for the iOS platform docs.") [tvOS](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/tvos/get-started/full-service.md.txt "View this page for the tvOS platform docs.") [Cast](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/cast/get-started/full-service.md.txt "View this page for the Cast platform docs.") [Roku](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/roku/get-started/full-service.md.txt "View this page for the Roku platform docs.")

<br />

This guide demonstrates how to integrate the IMA DAI SDK into a video player
app. If you would like to view or follow along with a completed sample
integration, download the [basic
example](https://github.com/googleads/googleads-ima-roku-dai) from GitHub.


**Note:** The IMA DAI SDK for Roku supports both HLS and DASH streams, with no implementation differences.

<br />


> [!IMPORTANT]
> To use IMA DAI, you must have an [Ad Manager 360 Advanced](https://support.google.com/admanager/answer/3485387) account. If you have an Ad Manager account, contact your account manager for more details. For information about signing up for Ad Manager, visit the [Ad Manager Help Center](https://support.google.com/admanager/answer/7084151).

<br />


**Note:** For information on integrating with other platforms, or on using the IMA client-side SDKs, see [Interactive Media Ads SDKs](https://developers.google.com/interactive-media-ads).

<br />

## IMA DAI overview

Implementing IMA DAI involves two main SDK components as demonstrated in this
guide:

- `

  StreamRequest`: An object that defines a stream request. Stream requests can either be for video-on-demand or live streams. Live stream requests specify an asset key, while VOD requests specify a CMS ID and video ID. Both request types can optionally include an API key needed to access specified streams, and a Google Ad Manager network code for the IMA SDK to handle ads identifiers as specified in Google Ad Manager settings.
- `

  StreamManager`: An object that handles dynamic ad insertion streams and interactions with the DAI backend. The stream manager also handles tracking pings and forwards stream and ad events to the publisher.

## Prerequisites

- Read through our [compatibility page](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/roku/get-started/compatibility) to make sure your intended use case is supported.
- Download our [Roku sample player
  code](https://github.com/googleads/googleads-ima-roku-dai)
- Deploy the sample player code to a Roku device to verify that your development set up is working.

## Play your video

The sample video player provided plays a content video out of the box. Deploy
the sample player to your Roku player to ensure your development environment is
set up properly.

## Turn your video player into an IMA DAI stream player

Follow these steps to implement a stream player.

### Create Sdk.xml

Add a new file to your project alongside `MainScene.xml` called `Sdk.xml`,
and add the following boilerplate:

#### Sdk.xml

```xml
<?xml version = "1.0" encoding = "utf-8" ?>

<component name = "imasdk" extends = "Task">
<interface>
</interface>
<script type = "text/brightscript">
<![CDATA[
  ' Your code goes here.
]]>
</script>
</component>
```

You need to edit both of these files throughout this guide.

### Load the Roku Advertising Framework

The IMA DAI SDK depends on the Roku Advertising Framework. To load the
framework, add the following to `manifest` and `Sdk.xml`:

    bs_libs_required=roku_ads_lib,googleima3

```vbscript
Library "Roku_Ads.brs"
Library "IMA3.brs"
```

### Load the IMA DAI SDK

To load IMA DAI SDK, do the following:

1. Initialize IMA SDK with the `New_IMASDK()` call:

   ```vbscript
   sub loadSdk()
     If m.sdk = invalid
       m.sdk = New_IMASDK()
     End If
     m.top.sdkLoaded = true
   End Sub
   ```
2. Track if IMA has loaded by creating a `sdkLoaded` boolean field:

   ```xml
   <field id="sdkLoaded" type="Boolean" />
   ```
3. Call the `loadSdk()` subroutine from the main `runThread()` subroutine:

   ```vbscript
   if not m.top.sdkLoaded
     loadSdk()
   End If
   ```
4. Create the `loadImaSdk()` function in `MainScene.xml` to create and run the
   `sdkTask` object:

   ```vbscript
   function loadImaSdk() as void
     m.sdkTask = createObject("roSGNode", "imasdk")
     m.sdkTask.observeField("sdkLoaded", "onSdkLoaded")
     m.sdkTask.observeField("errors", "onSdkLoadedError")

     ' Change to m.testLiveStream to demo live instead of VOD.
     selectedStream = m.testVodStream
     m.videoTitle = selectedStream.title
     m.sdkTask.streamData = selectedStream

     m.sdkTask.observeField("urlData", "urlLoadRequested")
     m.sdkTask.video = m.video
     ' Setting control to run starts the task thread.
     m.sdkTask.control = "RUN"
   end function
   ```
5. Call the `loadImaSdk()` function from the `init()` function.

6. Create the `onSdkLoaded()` and `onSdkLoadedError()` listener subroutines to
   respond to SDK load events:

   ```vbscript
   Sub onSdkLoaded(message as Object)
     print "--- onSdkLoaded --- control ";message
   End Sub

   Sub onSdkLoadedError(message as Object)
     print "--- errors in the sdk loading process --- ";message
   End Sub
   ```

### Create an IMA stream player

To create an IMA stream player, do the following:

1. Create a `setupVideoPlayer()` subroutine that does the following:

   1. Use the
      [`createPlayer()`](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/roku/reference/ima.Player.md.txt#.createPlayer)
      method to create the stream player.

   2. Have that stream player implement three callback methods: `loadUrl`,
      `adBreakStarted`, and `adBreakEnded`.

   3. Disable trick play when the stream is loaded to prevents users from
      skipping a pre-roll in the instant the stream starts, before the ad break
      started event is fired.

   ```vbscript
   sub setupVideoPlayer()
     sdk = m.sdk
     m.player = sdk.createPlayer()
     m.player.top = m.top
     m.player.loadUrl = Function(urlData)
       ' This line prevents users from scanning during buffering
       ' or during the first second of the ad before we have a callback from roku.
       ' If there are no prerolls disabling trickplay isn't needed.
       m.top.video.enableTrickPlay = false
       m.top.urlData = urlData
     End Function
     m.player.adBreakStarted = Function(adBreakInfo as Object)
       print "--- Ad Break Started --- "
       m.top.adPlaying = True
       m.top.video.enableTrickPlay = false
     End Function
     m.player.adBreakEnded = Function(adBreakInfo as Object)
       print "--- Ad Break Ended --- "
       m.top.adPlaying = False
       m.top.video.enableTrickPlay = true
     End Function
     m.player.seek = Function(timeSeconds as Double)
       print "--- SDK requested seek to ---" ; timeSeconds
       m.top.video.seekMode = "accurate"
       m.top.video.seek = timeSeconds
     End Function
   End Sub
   ```

   Add a `seek` callback method to support skippable ads. For more details, see
   [Add support for skippable ads](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/roku/get-started/full-service.md.txt#skippables).
2. Add the `urlData`, `adPlaying`, and `video` fields used in the
   `setupVideoPlayer()` subroutine:

   ```xml
   <field id="urlData" type="assocarray" />
   <field id="adPlaying" type="Boolean" />
   <field id="video" type="Node" />
   ```

### Create and execute a stream request

To request your DAI stream, do the following:

1. Create a `loadStream()` subroutine to create and request a stream. To
   support ad UI, such as
   [adChoices icons](https://support.google.com/admanager/answer/2695279), you must
   also pass a reference to the node containing your content video as part of
   your request:

   ```vbscript
   Sub loadStream()
     sdk = m.sdk
     sdk.initSdk()
     setupVideoPlayer()

     request = {}
     streamData = m.top.streamData
     if streamData.type = "live"
       request = sdk.CreateLiveStreamRequest(streamData.assetKey, streamData.apiKey, streamData.networkCode)
     else if streamData.type = "vod"
       request = sdk.CreateVodStreamRequest(streamData.contentSourceId, streamData.videoId, streamData.apiKey, streamData.networkCode)
     else
       request = sdk.CreateStreamRequest()
     end if

     request.player = m.player
     request.adUiNode = m.top.video

     requestResult = sdk.requestStream(request)
     If requestResult <> Invalid
       print "Error requesting stream ";requestResult
     Else
       m.streamManager = Invalid
       While m.streamManager = Invalid
         sleep(50)
         m.streamManager = sdk.getStreamManager()
       End While
       If m.streamManager = Invalid or m.streamManager["type"] <> Invalid or m.streamManager["type"] = "error"
         errors = CreateObject("roArray", 1, True)
         print "error ";m.streamManager["info"]
         errors.push(m.streamManager["info"])
         m.top.errors = errors
       Else
         m.top.streamManagerReady = True
         addCallbacks()
         m.streamManager.start()
       End If
     End If
   End Sub
   ```
2. Add the `streamData` and `streamManagerReady` fields used in the `loadStream()`
   subroutine:

   ```xml
   <field id="streamManagerReady" type="Boolean" />
   <field id="streamData" type="assocarray" />
   ```
3. If the stream manager is not available, call the `loadStream()` subroutine
   from the `runThread()` subroutine:

   ```vbscript
   if not m.top.streamManagerReady
     loadStream()
   End If
   ```
4. Select between a VOD or livestream. The following example has stream
   parameters for a livestream and a VOD stream:

   ```vbscript
   m.testLiveStream = {
     title: "Live Stream",
     assetKey: "c-rArva4ShKVIAkNfy6HUQ",
     networkCode: "21775744923",
     apiKey: "",
     type: "live"
   }
   m.testVodStream = {
     title: "VOD stream"
     contentSourceId: "2548831",
     videoId: "tears-of-steel",
     networkCode: "21775744923",
     apiKey: "",
     type: "vod"
   }
   ```

   By default, this guide uses the VOD stream. You can use the livestream
   instead by changing the `selectedStream` variable from the `m.testVodStream`
   object to the `m.testLiveStream` object.

### Start the stream

Create the `urlLoadRequested()` subroutine to listen for the stream data
and call the `playStream()` subroutine:

```vbscript
Sub urlLoadRequested(message as Object)
  print "Url Load Requested ";message
  data = message.getData()

  playStream(data.manifest, data.format)
End Sub
```

Create the `playStream()` to start stream playback:

```vbscript
Sub playStream(url as String, format as String)
  vidContent = createObject("RoSGNode", "ContentNode")
  vidContent.url = url
  vidContent.title = m.videoTitle
  vidContent.streamformat = format
  m.video.content = vidContent
  m.video.setFocus(true)
  m.video.visible = true
  m.video.control = "play"
  m.video.EnableCookies()
End Sub
```

### Listen for stream metadata

Create the `runLoop()` subroutine with a while loop to run during stream
playback and send stream metadata to IMA using `StreamManager.onMessage()`:

> [!IMPORTANT]
> **Key Point:** You must forward all messages to the SDK to ensure correct ad playback.

```vbscript
Sub runLoop()
  ' Forward all timed metadata events.
  m.top.video.timedMetaDataSelectionKeys = ["*"]

  ' Cycle through all the fields and just listen to them all.
  m.port = CreateObject("roMessagePort")
  fields = m.top.video.getFields()
  for each field in fields
    m.top.video.observeField(field, m.port)
  end for

  while True
    msg = wait(1000, m.port)
    if m.top.video = invalid
      print "exiting"
      exit while
    end if

    m.streamManager.onMessage(msg)
    currentTime = m.top.video.position
    ' Only enable trickplay after a few seconds, in case we start with an ad,
    ' to prevent users from skipping through that ad.
    If currentTime > 3 And not m.top.adPlaying
       m.top.video.enableTrickPlay = true
    End If
  end while
End Sub
```

### Listen to ad events

Now that you are passing stream metadata to IMA, IMA can emit ad events during
ad breaks. Create ad event listeners as needed to respond to ad events:

```vbscript
Function addCallbacks() as Void
  m.streamManager.addEventListener(m.sdk.AdEvent.ERROR, errorCallback)
  m.streamManager.addEventListener(m.sdk.AdEvent.START, startCallback)
  m.streamManager.addEventListener(m.sdk.AdEvent.FIRST_QUARTILE, firstQuartileCallback)
  m.streamManager.addEventListener(m.sdk.AdEvent.MIDPOINT, midpointCallback)
  m.streamManager.addEventListener(m.sdk.AdEvent.THIRD_QUARTILE, thirdQuartileCallback)
  m.streamManager.addEventListener(m.sdk.AdEvent.COMPLETE, completeCallback)
End Function

Function startCallback(ad as Object) as Void
  print "Callback from SDK -- Start called - "
End Function

Function firstQuartileCallback(ad as Object) as Void
  print "Callback from SDK -- First quartile called - "
End Function

Function midpointCallback(ad as Object) as Void
  print "Callback from SDK -- Midpoint called - "
End Function

Function thirdQuartileCallback(ad as Object) as Void
  print "Callback from SDK -- Third quartile called - "
End Function

Function completeCallback(ad as Object) as Void
  print "Callback from SDK -- Complete called - "
End Function

Function errorCallback(error as Object) as Void
  print "Callback from SDK -- Error called - "; error
  ' errors are critical and should terminate the stream.
  m.errorState = True
End Function
```

### Add support for skippable ads (optional)

In order to support skippable ads, you need to add a `seek` method to
the IMA DAI SDK's [player](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/roku/reference/ima.Player.md.txt)
object that programmatically seeks the video to the specified location, in
floating-point seconds.

To support skippable ads, you must also make sure you set the
[`adUiNode`](https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/roku/reference/ima.StreamRequest.md.txt#.adUiNode)
in your request.

```vbscript
m.player.seek = Function(timeSeconds as Double)
  print "--- SDK requested seek to ---" ; timeSeconds
  m.top.video.seekMode = "accurate"
  m.top.video.seek = timeSeconds
End Function
```