Mit den IMA SDKs lassen sich Multimedia-Anzeigen ganz einfach in Ihre Websites und Apps einbinden. Mit IMA SDKs können Anzeigen von jedem VAST-konformen Ad-Server angefordert und die Anzeigenwiedergabe in Ihren Apps verwaltet werden. Mit IMA DAI SDKs senden Apps eine Streamanfrage für Anzeigen- und Contentvideos – entweder VOD- oder Liveinhalte. Das SDK gibt dann einen kombinierten Videostream zurück, sodass Sie das Umschalten zwischen Anzeigen- und Inhaltsvideo in Ihrer App nicht verwalten müssen.
Wählen Sie die DAI-Lösung aus, die Sie interessiert
In dieser Anleitung wird gezeigt, wie Sie einen Livestream oder VOD-Stream mit Pod-Auslieferung mit dynamischer Anzeigenbereitstellung mit dem IMA DAI SDK für Roku wiedergeben. Wenn Sie sich eine vollständige Beispielintegration ansehen oder ihr folgen möchten, laden Sie das Beispiel für die Bereitstellung von Pods herunter.
Pod-Auslieferung mit dynamischer Anzeigenbereitstellung – Übersicht
Die Implementierung der Pod-Auslieferung mit dem IMA DAI umfasst zwei Haupt-SDK-Komponenten, die in diesem Leitfaden beschrieben werden:
StreamRequest.createPodLiveStreamRequest()/StreamRequest.createPodVodStreamRequest(): Erstellt ein Objekt, das eine Streamanfrage an die Werbeserver von Google definiert. In diesen Anfragen wird ein Network Code angegeben. Für Pod Liveima.StreamRequestist außerdem ein Custom Asset Key und ein optionaler API-Schlüssel erforderlich.StreamManager: Ein Objekt, das die Kommunikation zwischen dem Videostream und dem IMA DAI SDK verarbeitet, z. B. das Senden von Tracking-Pings und das Weiterleiten von Streamereignissen an den Publisher.
Außerdem müssen Sie eine Anfrage an Ihren Server für die Manifestbearbeitung senden, um das Streammanifest für Ihre App abzurufen. Der genaue Prozess kann je nach VTP variieren.
Vorbereitung
- Lesen Sie sich unsere Seite zur Kompatibilität durch, um sicherzugehen, dass Ihr geplanter Anwendungsfall unterstützt wird.
 - Laden Sie unseren Roku-Beispiel-Player-Code herunter.
 - Stellen Sie den Beispiel-Player-Code auf einem Roku-Gerät bereit, um zu prüfen, ob Ihre Entwicklungsumgebung funktioniert.
 
Spielen Sie Ihr Video ab.
Der bereitgestellte Beispielvideoplayer spielt sofort ein Contentvideo ab. Stelle sicher, dass deine Entwicklungsumgebung richtig eingerichtet ist, indem du den Beispielplayer auf deinem Roku-Gerät bereitstellst.
Videoplayer in einen IMA DAI-Streamplayer umwandeln
So implementieren Sie einen Stream-Player:
Sdk.xml erstellen
Fügen Sie Ihrem Projekt neben MainScene.xml eine neue Datei mit dem Namen Sdk.xml hinzu und fügen Sie den folgenden Boilerplate-Code ein:
Sdk.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>
Sie müssen beide Dateien (MainScene.xml und Sdk.xml) in dieser Anleitung bearbeiten.
IMA DAI SDK-Framework laden
Fügen Sie manifest und Sdk.xml Folgendes hinzu, um das Framework zu laden:
Manifest
bs_libs_required=googleima3
Sdk.xml
<?xml version = "1.0" encoding = "utf-8" ?>
  <component name = "imasdk" extends = "Task">
  <interface>
  </interface>
  <script type = "text/brightscript">
  <![CDATA[
  Library "IMA3.brs"
  ]]>
  </script>
  </component>
IMA DAI SDK initialisieren
Als Erstes müssen Sie das IMA DAI SDK laden und initialisieren, um Ihren IMA-Stream für die dynamische Anzeigenbereitstellung zu laden. Damit wird das IMA DAI SDK-Skript initialisiert.
Sdk.xml
<?xml version="1.0" encoding="utf-8" ?>
  <component name="IMASDKTask" extends="Task">
  <interface>
    <field id="IMASDKInitialized" type="Boolean" />
    <field id="errors" type="stringarray" />
  </interface>
  <script type = "text/brightscript">
  <![CDATA[
    Library "IMA3.brs"
    sub init()
      m.top.functionName = "runThread"
    end sub
    sub runThread()
      if not m.top.IMASDKInitialized
        initializeIMASDK()
      end if
    end sub
    sub initializeIMASDK()
        if m.sdk = invalid
          m.sdk = New_IMASDK()
        end if
        m.top.IMASDKInitialized = true
    end sub
  ]]>
  </script>
  </component>
Starten Sie diese Aufgabe jetzt in MainScene.xml und entfernen Sie den Aufruf zum Laden des Inhaltsstreams.
MainScene.xml
<?xml version="1.0" encoding="utf-8" ?>
<component extends="Scene" initialFocus="myVideo" name="MainScene">
  <script type="text/brightscript">
  <![CDATA[
  function init()
    m.video = m.top.findNode("myVideo")
    m.video.notificationinterval = 1
    runIMASDKTask()
  end function
  function runIMASDKTask()
    m.IMASDKTask = createObject("roSGNode", "IMASDKTask")
    m.IMASDKTask.observeField("IMASDKInitialized", "handleIMASDKInitialized")
    m.IMASDKTask.observeField("errors", "handleIMASDKErrors")
    m.IMASDKTask.control = "RUN"
  end function
  sub handleIMASDKInitialized()
    ' Follow your manifest manipulator (VTP) documentation to register a user
    ' streaming session if needed.
  end sub
  sub handleIMASDKErrors(message as object)
    print "------ IMA DAI SDK failed  ------"
    if message <> invalid and message.getData() <> invalid
      print "IMA DAI SDK Error ";message.getData()
    end if
  end sub
  ]]>
  </script>
  <children>
    <Video height="720" id="myVideo" visible="false" width="1280"/>
  </children>
</component>
IMA-Streamplayer erstellen
Als Nächstes müssen Sie mit Ihrem vorhandenen roVideoScreen einen IMA-Streamplayer erstellen.
Pod-Bereitstellung in Livestreams
Für Livestreams implementiert dieser Stream-Player drei Callback-Methoden: streamInitialized, adBreakStarted und adBreakEnded.
Deaktiviere auch die Trickplay-Funktion, wenn der Stream geladen wird. So wird verhindert, dass Nutzer einen Pre-Roll-Spot sofort nach Beginn überspringen, bevor das Ereignis „ad break started“ ausgelöst wird.
Sdk.xml
<?xml version="1.0" encoding="utf-8" ?>
  <component name="IMASDKTask" extends="Task">
  <interface>
    <field id="IMASDKInitialized" type="Boolean" />
    <field id="errors" type="stringarray" />
    <field id="urlData" type="assocarray" />
    <field id="adPlaying" type="Boolean" />
    <field id="videoNode" type="Node" />
  </interface>
  <script type="text/brightscript">
  ...
  sub runThread()
    if not m.top.IMASDKInitialized
      initializeIMASDK()
    end if
    setupPlayerCallbacks()
  end sub
  ...
  sub initializeIMASDK()
    if m.ima = invalid
      ima = New_IMASDK()
      ima.initSdk()
      m.ima = ima
    end if
    m.top.IMASDKInitialized = true
  end sub
  sub setupPlayerCallbacks()
    m.player = m.ima.createPlayer()
    m.player.top = m.top
    m.player.streamInitialized = function(urlData)
      m.top.videoNode.enableTrickPlay = false
      m.top.urlData = urlData
    end function
    m.player.adBreakStarted = function(adBreakInfo)
      print "------ Ad break started ------"
      m.top.adPlaying = true
      m.top.videoNode.enableTrickPlay = false
    end function
    m.player.adBreakEnded = function(adBreakInfo)
      print "------ Ad break ended ------"
      m.top.adPlaying = false
      m.top.videoNode.enableTrickPlay = true
    end function
  end sub
  </script>
...
</component>
Pod-Auslieferung von VOD-Streams
Für VOD-Streams implementiert dieser Stream-Player vier Callback-Methoden: streamInitialized, loadUrl, adBreakStarted und adBreakEnded. Achten Sie darauf, dass im streamInitialized-Callback StreamManager.loadThirdPartyStream() aufgerufen wird. Andernfalls wird die Funktion loadUrl nicht vom SDK ausgelöst.
In diesem Schritt fordern Sie auch eine Stream-URL von Ihrem Videotechnologiepartner (VTP) mit einer in loadAdPodStream() erhaltenen Stream-ID an. Rufen Sie dann StreamManager.loadThirdPartyStream() mit dem Ad-Pod-Manifest und allen Untertiteln auf, die von Ihrem VTP zurückgegeben werden.
Deaktiviere auch die Trickplay-Funktion, wenn der Stream geladen wird. So wird verhindert, dass Nutzer einen Pre-Roll-Spot sofort nach Beginn überspringen, bevor das Ereignis „ad break started“ ausgelöst wird.
Sdk.xml
<?xml version="1.0" encoding="utf-8" ?>
  <component name="IMASDKTask" extends="Task">
  <interface>
    <field id="IMASDKInitialized" type="Boolean" />
    <field id="errors" type="stringarray" />
    <field id="adStitchedStreamInfo" type="assocarray" />
    <field id="adPlaying" type="Boolean" />
    <field id="videoNode" type="Node" />
    <field id="streamParameters" type="assocarray" />
  </interface>
  <script type="text/brightscript">
  ...
  sub runThread()
    if not m.top.IMASDKInitialized
      initializeIMASDK()
    end if
    setupPlayerCallbacks()
  end sub
  ...
  sub initializeIMASDK()
    if m.ima = invalid
      ima = New_IMASDK()
      ima.initSdk()
      m.ima = ima
    end if
    m.top.IMASDKInitialized = true
  end sub
  sub loadThirdPartyStream(adStitchedManifest as string, subtitleConfig as dynamic)
    m.streamManager.loadThirdPartyStream(adStitchedManifest, subtitleConfig)
  end sub
  sub setupPlayerCallbacks()
    m.player = m.ima.createPlayer()
    m.player.top = m.top
    m.player.streamInitialized = function(urlData)
      adStitchedManifest = m.top.streamParameters.VTPManifest.replace("[[STREAMID]]", urlData.streamId)
      loadThirdPartyStream(adStitchedManifest, m.top.streamParameters.subtitleConfig)
    end function
    m.player.loadUrl = function(streamInfo)
      m.top.adStitchedStreamInfo = streamInfo
    end function
    m.player.adBreakStarted = function(adBreakInfo)
      print "------ Ad break started ------"
      m.top.adPlaying = true
      m.top.videoNode.enableTrickPlay = false
    end function
    m.player.adBreakEnded = function(adBreakInfo)
      print "------ Ad break ended ------"
      m.top.adPlaying = false
      m.top.videoNode.enableTrickPlay = true
    end function
  end sub
  </script>
...
</component>
Livestream- oder VOD-Streamanfrage für die Pod-Auslieferung erstellen und ausführen
Nachdem Sie einen Stream-Player haben, können Sie eine Stream-Anfrage erstellen und ausführen.
In diesem Beispiel sind Daten für einen Pod Serving-Stream in m.testPodServingStream gespeichert.
Pod-Bereitstellung in Livestreams
Speichern Sie im m.testPodServingStream-Objekt die Parameter, die Google Ad Manager benötigt, um den betreffenden Stream zu identifizieren, z. B. einen Netzwerkcode und einen benutzerdefinierten Asset-Schlüssel. Speichern Sie auch die Manifest-URL, die für den Zugriff auf Ihren Manifestbearbeitungsserver verwendet wird. In diesem Fall muss der Manifest-URL die Google-Stream-ID hinzugefügt werden, nachdem die Streamanfrage zurückgegeben wurde.
Damit die AdUI, z. B. Datenschutzinfo-Symbole, unterstützt werden kann, müssen Sie in Ihrer Anfrage auch einen Verweis auf den Knoten übergeben, der Ihr Inhaltsvideo enthält.
MainScene.xml
function init()
  m.video = m.top.findNode("myVideo")
  m.video.notificationinterval = 1
  m.testPodServingStream = {
    title: "Test live stream for DAI Pod Serving",
    assetKey: "test-live-stream",
    networkCode: "your-network-code",
    manifest: "https://.../master.m3u8?stream_id=[[STREAMID]]",
    apiKey: ""
  }
  runIMASDKTask()
end function
function runIMASDKTask()
  m.IMASDKTask = createObject("roSGNode", "IMASDKTask")
  m.IMASDKTask.streamParameters = m.testPodservingStream
  m.IMASDKTask.videoNode = m.video
  m.IMASDKTask.observeField("IMASDKInitialized", "handleIMASDKInitialized")
  m.IMASDKTask.observeField("errors", "handleIMASDKErrors")
  m.IMASDKTask.control = "RUN"
end function
Sdk.xml
<interface>
  <field id="IMASDKInitialized" type="Boolean" />
  <field id="errors" type="stringarray" />
  <field id="urlData" type="assocarray" />
  <field id="adPlaying" type="Boolean" />
  <field id="videoNode" type="Node" />
  <field id="streamParameters" type="assocarray" />
</interface>
...
sub runThread()
  if not m.top.IMASDKInitialized
    initializeIMASDK()
  end if
  setupPlayerCallbacks()
  loadAdPodStream()
end sub
sub loadAdPodStream()
  request = m.ima.CreatePodLiveStreamRequest(m.top.streamParameters.assetKey, m.top.streamParameters.networkCode, m.top.streamParameters.apiKey)
  ' Set the player object so that the request can trigger the player's
  ' callbacks at stream initialization or playback events.
  request.player = m.player
  ' Set the video node for the IMA DAI SDK to create ad UI as its child nodes.
  request.adUiNode = m.top.video
  requestResult = m.ima.requestStream(request)
  if requestResult <> invalid
    print "Error requesting stream ";requestResult
    return
  end if
  m.streamManager = invalid
  while m.streamManager = invalid
    sleep(50)
    m.streamManager = m.ima.getStreamManager()
  end while
  if m.streamManager = invalid
    errors = CreateObject("roArray", 1, True)
    invalidStreamManagerError = "Invalid stream manager"
    print invalidStreamManagerError
    errors.push(invalidStreamManagerError)
    m.top.errors = errors
    return
  end if
  if m.streamManager["type"] <> invalid and m.streamManager["type"] = "error"
    errors = CreateObject("roArray", 1, True)
    print "Stream request returns an error. " ; m.streamManager["info"]
    errors.push(m.streamManager["info"])
    m.top.errors = errors
    return
  end if
  setupStreamManager()
  m.streamManager.start()
end sub
Pod-Auslieferung von VOD-Streams
Im m.testPodServingStream-Objekt speichern Sie den Netzwerkcode, der in der Streamanfrage verwendet wird, damit Google Ad Manager eine Stream-ID bereitstellen kann. Speichern Sie außerdem die Manifest-URL, die für den Zugriff auf das nutzerspezifische Manifest verwendet wird, auf Ihrem Server zur Manifestbearbeitung.
Damit AdUI wie das Datenschutzinfo-Symbol unterstützt werden kann, müssen Sie in Ihrer Anfrage auch einen Verweis auf den Knoten übergeben, der Ihr Inhaltsvideo enthält.
MainScene.xml
sub init()
  m.video = m.top.findNode("myVideo")
  m.video.notificationinterval = 1
  m.testPodServingStream = {
    title: "Pod Serving VOD Stream",
    networkCode: "your-network-code",
    VTPManifest: "https://.../manifest.m3u8?gam-stream-id=[[STREAMID]]",
    subtitleConfig: []
  }
  runIMASDKTask()
end sub
sub runIMASDKTask()
  m.IMASDKTask = createObject("roSGNode", "IMASDKTask")
  m.IMASDKTask.streamParameters = m.testPodservingStream
  m.IMASDKTask.videoNode = m.video
  m.IMASDKTask.observeField("IMASDKInitialized", "handleIMASDKInitialized")
  m.IMASDKTask.observeField("errors", "handleIMASDKErrors")
  m.IMASDKTask.control = "RUN"
end sub
Sdk.xml
sub runThread()
  if not m.top.IMASDKInitialized
    initializeIMASDK()
  end if
  setupPlayerCallbacks()
  loadAdPodStream()
end sub
sub loadAdPodStream()
  request = m.ima.CreatePodVodStreamRequest(m.top.streamParameters.networkCode)
  ' Set the player object so that the request can trigger the player
  ' callbacks at stream initialization or playback events.
  request.player = m.player
  ' Set the video node for the IMA DAI SDK to create ad UI as its child nodes.
  request.adUiNode = m.top.video
  requestResult = m.ima.requestStream(request)
  if requestResult <> invalid
    print "Error requesting stream ";requestResult
    return
  end if
  m.streamManager = invalid
  while m.streamManager = invalid
    sleep(50)
    m.streamManager = m.ima.getStreamManager()
  end while
  if m.streamManager = invalid
    errors = CreateObject("roArray", 1, True)
    invalidStreamManagerError = "Invalid stream manager"
    print invalidStreamManagerError
    errors.push(invalidStreamManagerError)
    m.top.errors = errors
    return
  end if
  if m.streamManager["type"] <> invalid and m.streamManager["type"] = "error"
    errors = CreateObject("roArray", 1, True)
    print "Stream request returns an error. " ; m.streamManager["info"]
    errors.push(m.streamManager["info"])
    m.top.errors = errors
    return
  end if
  setupStreamManager()
  m.streamManager.start()
end sub
Event-Listener hinzufügen und Stream starten
Pod-Bereitstellung in Livestreams
Nachdem du deinen Stream angefordert hast, musst du nur noch wenige Dinge tun: Füge Event-Listener hinzu, um den Fortschritt der Anzeigen zu verfolgen, und leite Roku-Nachrichten an das SDK weiter. Es ist wichtig, dass Sie alle Nachrichten an das SDK weiterleiten, damit Anzeigen korrekt wiedergegeben werden. Andernfalls werden Anzeigenaufrufe nicht richtig erfasst.
In diesem Schritt fügen Sie auch eine Funktion hinzu, um das Makro [[STREAMID]] durch die Stream-ID zu ersetzen und die vollständige Manifestanfrage-URL an den Videoplayer zu übergeben.
Bei dieser Implementierung wird die Stream-ID in diesem Schritt abgerufen. Je nach VTP-Integration ist sie jedoch möglicherweise schon vor diesem Schritt verfügbar.
MainScene.xml
function runIMASDKTask()
  m.IMASDKTask = createObject("roSGNode", "IMASDKTask")
  m.IMASDKTask.streamParameters = m.testPodservingStream
  m.IMASDKTask.videoNode = m.video
  m.IMASDKTask.observeField("IMASDKInitialized", "handleIMASDKInitialized")
  m.IMASDKTask.observeField("errors", "handleIMASDKErrors")
  m.sdkTask.observeField("adStitchedStreamInfo", "loadAdStitchedStream")
  m.sdkTask.control = "RUN"
end function
sub loadAdStitchedStream(message as object)
  print "Ad pod stream information ";message
  adPodStreamInfo = message.getData()
  manifest = m.testPodservingStream.manifest.Replace("[[STREAMID]]", adPodStreamInfo.streamId)
  playStream(manifest, adPodStreamInfo.format)
end sub
sub playStream(url as string, format as string)
  vidContent = createObject("RoSGNode", "ContentNode")
  vidContent.url = url
  vidContent.title = m.testPodservingStream.title
  vidContent.streamformat = format
  m.video.content = vidContent
  m.video.setFocus(true)
  m.video.visible = true
  m.video.control = "play"
  m.video.EnableCookies()
end sub
Sdk.xml
sub runThread()
  if not m.top.IMASDKInitialized
    initializeIMASDK()
  end if
  setupPlayerCallbacks()
  loadAdPodStream()
  if m.streamManager <> invalid
    runLoop()
  end if
end sub
sub runLoop()
  m.top.videoNode.timedMetaDataSelectionKeys = ["*"]
  ' IMPORTANT: Failure to listen to the position and timedmetadata fields
  ' could result in ad impressions not being reported.
  m.port = CreateObject("roMessagePort")
  m.top.videoNode.observeField("position", m.port)
  m.top.videoNode.observeField("timedMetaData", m.port)
  m.top.videoNode.observeField("timedMetaData2", m.port)
  m.top.videoNode.observeField("state", m.port)
  while True
    msg = wait(1000, m.port)
    if m.top.videoNode = invalid
      print "exiting"
      exit while
    end if
    m.streamManager.onMessage(msg)
    currentTime = m.top.videoNode.position
    if currentTime > 3 And not m.top.adPlaying
      m.top.videoNode.enableTrickPlay = true
    end if
  end while
end sub
sub setupStreamManager()
  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 sub
sub startCallback(ad as object)
  print "Callback from SDK -- Start called - "
end sub
sub firstQuartileCallback(ad as object)
  print "Callback from SDK -- First quartile called - "
end sub
sub midpointCallback(ad as object)
  print "Callback from SDK -- Midpoint called - "
end sub
sub thirdQuartileCallback(ad as object)
  print "Callback from SDK -- Third quartile called - "
end sub
sub completeCallback(ad as object)
  print "Callback from SDK -- Complete called - "
end sub
function errorCallback(error as object)
  print "Callback from SDK -- Error called - " ; error
  m.errorState = True
end function
Pod-Auslieferung von VOD-Streams
Nachdem du deinen Stream angefordert hast, musst du nur noch wenige Dinge tun: Füge Event-Listener hinzu, um den Fortschritt der Anzeigen zu verfolgen, und leite Roku-Nachrichten an das SDK weiter. Es ist wichtig, dass Sie alle Nachrichten an das SDK weiterleiten, damit Anzeigen korrekt wiedergegeben werden. Andernfalls werden Anzeigenaufrufe nicht richtig erfasst.
MainScene.xml
sub runIMASDKTask()
  m.IMASDKTask = createObject("roSGNode", "IMASDKTask")
  m.IMASDKTask.streamParameters = m.testPodservingStream
  m.IMASDKTask.videoNode = m.video
  m.IMASDKTask.observeField("IMASDKInitialized", "handleIMASDKInitialized")
  m.IMASDKTask.observeField("errors", "handleIMASDKErrors")
  m.sdkTask.observeField("adStitchedStreamInfo", "loadAdStitchedStream")
  m.sdkTask.control = "RUN"
end sub
sub loadAdStitchedStream(message as object)
  print "Ad pod stream information ";message
  adPodStreamInfo = message.getData()
end sub
sub playStream(url as string, format as string, subtitleConfig as object)
  vidContent = createObject("RoSGNode", "ContentNode")
  vidContent.title = m.testPodservingStream.title
  vidContent.url = url
  vidContent.subtitleConfig = subtitleConfig
  vidContent.streamformat = format
  m.video.content = vidContent
  m.video.setFocus(true)
  m.video.visible = true
  m.video.control = "play"
  m.video.EnableCookies()
end sub
Sdk.xml
sub runThread()
  if not m.top.IMASDKInitialized
    initializeIMASDK()
  end if
  setupPlayerCallbacks()
  loadAdPodStream()
  if m.streamManager <> invalid
    runLoop()
  end if
end sub
sub runLoop()
  m.top.videoNode.timedMetaDataSelectionKeys = ["*"]
  ' IMPORTANT: Failure to listen to the position and timedmetadata fields
  ' could result in ad impressions not being reported.
  m.port = CreateObject("roMessagePort")
  m.top.videoNode.observeField("position", m.port)
  m.top.videoNode.observeField("timedMetaData", m.port)
  m.top.videoNode.observeField("timedMetaData2", m.port)
  m.top.videoNode.observeField("state", m.port)
  while True
    msg = wait(1000, m.port)
    if m.top.videoNode = invalid
      exit while
    end if
    m.streamManager.onMessage(msg)
    currentTime = m.top.videoNode.position
    if currentTime > 3 and not m.top.adPlaying
      m.top.videoNode.enableTrickPlay = true
    end if
  end while
end sub
sub setupStreamManager()
  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 sub
sub startCallback(ad as object)
  print "Callback from SDK -- Start called - "
end sub
sub firstQuartileCallback(ad as object)
  print "Callback from SDK -- First quartile called - "
end sub
sub midpointCallback(ad as object)
  print "Callback from SDK -- Midpoint called - "
end sub
sub thirdQuartileCallback(ad as object)
  print "Callback from SDK -- Third quartile called - "
end sub
sub completeCallback(ad as object)
  print "Callback from SDK -- Complete called - "
end sub
sub errorCallback(error as object)
  print "Callback from SDK -- Error called - " ; error
  m.errorState = True
end sub