設定 DAI 專用的 IMA SDK

選取平台: HTML5 Android iOS tvOS Cast Roku

使用 IMA SDK,即可輕鬆將多媒體廣告整合至網站和應用程式。IMA SDK 可向任何 符合 VAST 規定的廣告伺服器請求廣告,並在應用程式中管理廣告播放。應用程式可透過 IMA DAI SDK,對廣告和內容影片 (隨選影片或直播內容) 提出串流請求。SDK 接著會傳回合併的影片串流,因此您不必在應用程式中管理廣告和內容影片之間的切換。

選取您感興趣的 DAI 解決方案

全方位服務 DAI

本指南說明如何將 IMA DAI SDK 整合至簡易影片播放器應用程式。如要查看或跟著操作完整的範例整合,請從 GitHub 下載基本範例

IMA DAI 總覽

如本指南所示,導入 IMA DAI 需要兩個主要 SDK 元件:

  • StreamRequest: 定義串流要求的物件。串流要求可以是隨選影片或直播串流。直播串流請求會指定素材資源金鑰,而 VOD 請求則會指定 CMS ID 和影片 ID。這兩種要求類型都可以選擇性地加入存取指定串流所需的 API 金鑰,以及 Google Ad Manager 聯播網代碼,供 IMA SDK 處理廣告 ID,如 Google Ad Manager 設定中所指定。
  • StreamManager: 這個物件會處理動態廣告插播串流,以及與 DAI 後端的互動。串流管理工具也會處理追蹤 Ping,並將串流和廣告事件轉送給發布商。

必要條件

播放影片

提供的範例影片播放器可直接播放內容影片。將範例播放器部署至 Roku 播放器,確保開發環境設定正確無誤。

將影片播放器變成 IMA DAI 串流播放器

請按照下列步驟導入串流播放器。

建立 Sdk.xml

在專案中新增 MainScene.xml 旁邊的 Sdk.xml 檔案,並加入下列樣板:

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>

在本指南中,您需要編輯這兩個檔案。

載入 Roku Advertising Framework

IMA DAI SDK 依附於 Roku 廣告架構。如要載入架構,請在 manifestSdk.xml 中加入下列內容:

bs_libs_required=roku_ads_lib,googleima3
Library "Roku_Ads.brs"
Library "IMA3.brs"

載入 IMA DAI SDK

如要載入 IMA DAI SDK,請按照下列步驟操作:

  1. 使用 New_IMASDK() 呼叫初始化 IMA SDK:

    sub loadSdk()
      If m.sdk = invalid
        m.sdk = New_IMASDK()
      End If
      m.top.sdkLoaded = true
    End Sub
    
  2. 建立 sdkLoaded 布林值欄位,追蹤 IMA 是否已載入:

    <field id="sdkLoaded" type="Boolean" />
    
  3. 從主要 runThread() 副常式呼叫 loadSdk() 副常式:

    if not m.top.sdkLoaded
      loadSdk()
    End If
    
  4. MainScene.xml 中建立 loadImaSdk() 函式,以建立及執行 sdkTask 物件:

    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. init() 函式呼叫 loadImaSdk() 函式。

  6. 建立 onSdkLoaded()onSdkLoadedError() 接聽程式子常式,以回應 SDK 載入事件:

    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
    

建立 IMA 串流播放器

如要建立 IMA 串流播放器,請按照下列步驟操作:

  1. 建立可執行下列作業的 setupVideoPlayer() 副程式:

    1. 使用 createPlayer() 方法建立串流播放器。

    2. 讓該串流播放器實作三種回呼方法:loadUrladBreakStartedadBreakEnded

    3. 載入串流時停用快轉功能,避免使用者在串流開始時,於廣告中斷開始事件觸發前略過片頭廣告。

    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
    

    新增 seek 回呼方法,支援可略過的廣告。詳情請參閱「新增支援可略過廣告」。

  2. 新增 setupVideoPlayer() 副程式中使用的 urlDataadPlayingvideo 欄位:

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

建立及執行串流要求

如要要求 DAI 串流,請按照下列步驟操作:

  1. 建立 loadStream() 副常式,以建立及要求串流。如要支援廣告使用者介面 (例如「廣告選擇」圖示),您也必須在要求中傳遞含有內容影片的節點參照:

    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. loadStream() 副常式中新增 streamDatastreamManagerReady 欄位:

    <field id="streamManagerReady" type="Boolean" />
    <field id="streamData" type="assocarray" />
    
  3. 如果沒有串流管理員,請從 runThread() 副常式呼叫 loadStream() 副常式:

    if not m.top.streamManagerReady
      loadStream()
    End If
    
  4. 選取 VOD 或直播。以下範例包含直播和隨選影片串流的串流參數:

    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"
    }
    

    根據預設,本指南會使用 VOD 串流。您可以將 m.testVodStream 物件的 selectedStream 變數變更為 m.testLiveStream 物件,改用直播。

開始直播

建立 urlLoadRequested() 副常式,監聽串流資料並呼叫 playStream() 副常式:

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

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

建立 playStream(),開始播放串流:

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

監聽串流中繼資料

使用 while 迴圈建立 runLoop() 副常式,在串流播放期間執行,並使用 StreamManager.onMessage() 將串流中繼資料傳送至 IMA:

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

監聽廣告事件

現在您已將串流中繼資料傳遞至 IMA,IMA 就能在廣告插播期間發出廣告事件。視需要建立廣告事件監聽器,以便回應廣告事件:

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

新增對可略過廣告的支援 (選用)

如要支援可略過廣告,您需要在 IMA DAI SDK 的 player 物件中加入 seek 方法,以程式輔助方式將影片搜尋至指定位置 (以浮點秒數表示)。

如要支援可略過廣告,請務必在要求中設定 adUiNode

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