設定全方位服務 DAI

選取平台: HTML5 Android iOS tvOS Cast Roku

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

IMA DAI 總覽

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

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

必要條件

播放影片

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

將影片播放器轉換為 IMA DAI 串流播放器

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

建立 Sdk.xml

在專案中新增名為 Sdk.xml 的檔案,與 MainScene.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 Advertising Framework。如要載入架構,請在 manifest 和 Sdk.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. 讓該串流播放器實作三個回呼方法:loadUrl、adBreakStarted 和 adBreakEnded。

    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() 子常式中使用的 urlData、adPlaying 和 video 欄位:

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

建立及執行串流要求

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

  1. 建立 loadStream() 子常式,用於建立及要求串流。如要支援廣告 UI (例如 AdChoices 圖示),您也必須在要求中傳遞包含內容影片的節點參照:

    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() 子常式中使用的 streamData 和 streamManagerReady 欄位:

    <field id="streamManagerReady" type="Boolean" />
    <field id="streamData" type="assocarray" />
    
  3. 如果串流管理工具無法使用,請從 runThread() 子常式呼叫 loadStream() 子常式:

    if not m.top.streamManagerReady
      loadStream()
    End If
    
  4. 選取 VOD 或直播。以下範例包含直播和 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 串流。您可以改用直播,方法是將 selectedStream 變數從 m.testVodStream 物件變更為 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

監聽串流中繼資料

建立 runLoop() 子常式,並使用 while 迴圈在串流播放期間執行,然後使用 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