開始使用

IMA SDK 可讓您輕鬆將多媒體廣告整合至網站和應用程式。IMA SDK 可從任何 符合 VAST 規定的廣告伺服器要求廣告,並管理您應用程式中的廣告播放。使用 IMA DAI SDK,應用程式會向廣告和內容影片 (VOD 或直播內容) 發出串流要求。SDK 然後會傳回合併影片串流,這樣您就不必管理應用程式內廣告和內容影片之間的切換程序。

本指南示範如何將 IMA SDK 整合到簡單的影片播放器應用程式中。如要查看或按照完整的整合範例進行操作,請從 GitHub 下載基本範例

IMA DAI 總覽

導入 IMA DAI 時,本指南將說明兩個主要 SDK 元件:

  • StreamRequest: 定義串流要求的物件。串流要求可以是隨選影片或直播。要求會指定內容 ID、API 金鑰或驗證權杖和其他參數。
  • StreamManager: 處理動態廣告插播串流以及與 DAI 後端互動的物件。串流管理員也會處理追蹤連線偵測 (ping),並將串流和廣告事件轉送給發布商。

必要條件

開始前必須完成以下事項:

播放影片

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

將影片播放器變成 IMA 動態廣告插播串流播放器

建立 Sdk.xml

在專案中新增名為 Sdk.xmlMainScene.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 廣告架構

IMA SDK 依附於 Roku 廣告架構。如要載入架構,請將以下內容新增至 manifestSdk.xml

資訊清單
bs_libs_required=roku_ads_lib,googleima3
Sdk.xml
Library "Roku_Ads.brs"
Library "IMA3.brs"

載入 IMA SDK

載入 IMA 動態廣告插播串流的第一步,就是載入並初始化 IMA SDK。以下程式碼會載入 IMA SDK 指令碼。

Sdk.xml
<interface>
  <field id="sdkLoaded" type="Boolean" />
  <field id="errors" type="stringarray" />
</interface>
sub init()
  m.top.functionName = "runThread"
End Sub

sub runThread()
  if not m.top.sdkLoaded
    loadSdk()
  End If
End Sub

sub loadSdk()
    If m.sdk = invalid
      m.sdk = New_IMASDK()
    End If
    m.top.sdkLoaded = true
End Sub

現在,請在 MainScene.xml 中啟動這項工作,並移除呼叫來載入內容串流。

MainScene.xml
function init()
  m.video = m.top.findNode("myVideo")
  m.video.notificationinterval = 1
  loadImaSdk()
end function

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

  m.sdkTask.control = "RUN"
end function

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 串流播放器

接下來,您需要使用現有的 roVideoScreen 建立 IMA 串流播放器。這個串流播放器會實作三種回呼方法:loadUrladBreakStartedadBreakEnded。載入串流時也請停用技巧播放功能。如此一來,使用者就不會在廣告插播開始事件前就略過片頭廣告。

Sdk.xml
<interface>
  <field id="sdkLoaded" type="Boolean" />
  <field id="errors" type="stringarray" />
  <field id="urlData" type="assocarray" />
  <field id="adPlaying" type="Boolean" />
  <field id="video" type="Node" />
</interface>

...
sub setupVideoPlayer()
  sdk = m.sdk
  m.player = sdk.createPlayer()
  m.player.top = m.top
  m.player.loadUrl = Function(urlData)
    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
End Sub

建立並執行串流要求

現在您已擁有串流播放器,可以建立並執行串流請求。這個示例包含直播和 VOD 串流的資料。目前正在使用 VOD 串流。 如要使用直播 (而非 VOD),將 selectedStreamm.testVodStream 變更為 m.testLiveStream

如要支援 AdUI (例如 adChoices 圖示),您也必須在請求中傳遞對包含您內容影片的節點參照。

MainScene.xml
function init()
  m.video = m.top.findNode("myVideo")
  m.video.notificationinterval = 1
  m.testLiveStream = {
    title: "Live Stream",
    assetKey: "sN_IYUG8STe1ZzhIIE_ksA",
    apiKey: "",
    type: "live"
  }
  m.testVodStream = {
    title: "VOD stream"
    contentSourceId: "2528370",
    videoId: "tears-of-steel",
    apiKey: "",
    type: "vod"
  }
  loadImaSdk()
end function

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

  selectedStream = m.testVodStream
  m.videoTitle = selectedStream.title
  m.sdkTask.streamData = selectedStream

  m.sdkTask.video = m.video
  m.sdkTask.control = "RUN"
end function
Sdk.xml
<interface>
  <field id="sdkLoaded" type="Boolean" />
  <field id="errors" type="stringarray" />
  <field id="urlData" type="assocarray" />
  <field id="adPlaying" type="Boolean" />
  <field id="video" type="Node" />
  <field id="streamData" type="assocarray" />
  <field id="streamManagerReady" type="Boolean" />
</interface>
sub runThread()
  if not m.top.sdkLoaded
    loadSdk()
  End If
  if not m.top.streamManagerReady
    loadStream()
  End If
End Sub

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

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

  request.player = m.player
  request.videoObject = m.top.video
  ' Required to support UI elements for 'Why This Ad?' and skippability
  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

新增事件監聽器並開始串流

要求串流後,只需再完成幾個步驟:新增事件監聽器以追蹤廣告進度、開始串流,以及將 Roku 訊息轉送至 SDK。請務必將所有訊息轉寄至 SDK,確保廣告播放正確無誤。

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

  selectedStream = m.testVodStream
  m.videoTitle = selectedStream.title
  m.sdkTask.streamData = selectedStream

  m.sdkTask.observeField("urlData", "urlLoadRequested")
  m.sdkTask.video = m.video
  m.sdkTask.control = "RUN"
end function

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

  playStream(data.manifest)
End Sub

Sub playStream(url as Object)
  vidContent = createObject("RoSGNode", "ContentNode")
  vidContent.url = url
  vidContent.title = m.videoTitle
  vidContent.streamformat = "hls"
  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.sdkLoaded
    loadSdk()
  End If
  if not m.top.streamManagerReady
    loadStream()
  End If
  If m.top.streamManagerReady
    runLoop()
  End If
End Sub

Sub runLoop()
  m.top.video.timedMetaDataSelectionKeys = ["*"]

  m.port = CreateObject("roMessagePort")

  ' Listen to all fields.

  ' IMPORTANT: Failure to listen to the position and timedmetadata fields
  ' could result in ad impressions not being reported.
  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
    If currentTime > 3 And not m.top.adPlaying
       m.top.video.enableTrickPlay = true
    End If
  end while
End Sub

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
  m.errorState = True
End Function

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

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

Sdk.xml
  ...

  m.player.loadUrl = Function(urlData)
    m.top.video.enableTrickPlay = false
    m.top.urlData = urlData
  End Function

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

  m.player.adBreakStarted = Function(adBreakInfo as Object)
    print "---- Ad Break Started ---- "
    m.top.adPlaying = True
    m.top.video.enableTrickPlay = false
  End Function

  ...