Настройка IMA SDK для DAI

Выберите платформу: HTML5 Android iOS tvOS Cast Roku

SDK IMA упрощают интеграцию мультимедийной рекламы в ваши веб-сайты и приложения. SDK IMA могут запрашивать рекламу с любого рекламного сервера , совместимого с VAST , и управлять воспроизведением рекламы в ваших приложениях. С SDK IMA DAI приложения отправляют запрос на потоковое видео, включающее рекламу и контент — либо видео по запросу, либо прямой эфир. Затем SDK возвращает объединенный видеопоток, так что вам не нужно управлять переключением между рекламой и контентом внутри вашего приложения.

Выберите интересующее вас решение DAI.

В этом руководстве показано, как воспроизводить прямые трансляции или видео по запросу (VOD) из DAI Pod Serving с помощью SDK IMA DAI для Roku. Чтобы посмотреть или проследить за завершенной интеграцией, скачайте пример Pod Serving .

Обзор системы подачи напитков в капсулах IMA DAI

Реализация Pod Serving с использованием IMA DAI включает в себя два основных компонента SDK, которые демонстрируются в этом руководстве:

  • StreamRequest.createPodLiveStreamRequest() / StreamRequest.createPodVodStreamRequest() : Создает объект, определяющий запрос потока на рекламные серверы Google. Эти запросы указывают сетевой код , а Pod Live ima.StreamRequest также требует пользовательский ключ ресурса и необязательный ключ API .
  • StreamManager : Объект, который обрабатывает обмен данными между видеопотоком и SDK IMA DAI, например, отправляет запросы на отслеживание и пересылает события потока издателю.

Кроме того, вам необходимо отправить запрос на сервер обработки манифеста , чтобы получить манифест потока для отображения вашим приложением. Точный процесс может различаться в зависимости от партнера по видеотехнологиям (VTP).

Предварительные требования

  • Ознакомьтесь с нашей страницей совместимости , чтобы убедиться в поддержке предполагаемого вами варианта использования.
  • Скачайте наш пример кода для Roku-плеера .
  • Разверните пример кода плеера на устройстве Roku, чтобы убедиться в работоспособности вашей среды разработки.

Воспроизвести ваше видео

В предоставленном примере видеоплеера видео воспроизводится без дополнительных настроек. Установите пример плеера на ваше устройство 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>

В ходе выполнения инструкций этого руководства вам необходимо отредактировать оба файла ( MainScene.xml и Sdk.xml ).

Загрузите фреймворк IMA DAI SDK.

Для загрузки фреймворка добавьте следующее в manifest и Sdk.xml :

проявление

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>

Инициализируйте SDK IMA DAI.

Первым шагом для загрузки потока динамической вставки рекламы IMA является загрузка и инициализация SDK IMA DAI. Следующий скрипт инициализирует SDK IMA DAI.

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>

Теперь запустите эту задачу в MainScene.xml и удалите вызов для загрузки потока контента.

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-стриминга

Далее вам необходимо использовать существующий roVideoScreen для создания проигрывателя IMA-потоков.

Прямая трансляция, подкасты

Для прямых трансляций этот проигрыватель использует три метода обратного вызова: streamInitialized , adBreakStarted и adBreakEnded .

Также отключите функцию «просмотра рекламного ролика» при загрузке потока. Это предотвратит пропуск пользователями преролла в момент его начала, до того, как сработает событие начала рекламной паузы.

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>

VOD-стриминг Под-сервис

Для потокового воспроизведения видео по запросу этот проигрыватель реализует четыре метода обратного вызова: streamInitialized , loadUrl , adBreakStarted и adBreakEnded . В методе обратного вызова streamInitialized обязательно вызовите StreamManager.loadThirdPartyStream() . В противном случае SDK не запустит функцию loadUrl .

На этом этапе вы также запрашиваете URL-адрес потока у вашего партнера по видеотехнологиям (VTP) с идентификатором потока, полученным в loadAdPodStream() . Затем вызовите функцию StreamManager.loadThirdPartyStream() с манифестом рекламного блока и любыми субтитрами, возвращенными вашим VTP.

Также отключите функцию «просмотра рекламного ролика» при загрузке потока. Это предотвратит пропуск пользователями преролла в момент его начала, до того, как сработает событие начала рекламной паузы.

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>

Создайте и выполните запрос на потоковую передачу в режиме реального времени или по запросу (VOD Pod Serving).

После создания потокового проигрывателя вы можете создать и выполнить запрос на воспроизведение потока. В этом примере данные для потока Pod Serving хранятся в m.testPodServingStream .

Прямая трансляция, подкасты

В объекте m.testPodServingStream храните параметры, необходимые Google Ad Manager для идентификации потока, такие как сетевой код и пользовательский ключ ресурса. Также храните URL-адрес манифеста, используемый для доступа к вашему серверу обработки манифеста. В данном случае в URL-адрес манифеста необходимо добавить идентификатор потока Google после получения запроса на поток.

Для поддержки AdUI, например, значков adChoices, необходимо также передать ссылку на узел, содержащий ваш видеоконтент, в составе запроса.

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

VOD-стриминг Под-сервис

В объекте m.testPodServingStream вы будете хранить сетевой код, используемый в запросе потока, чтобы Google Ad Manager мог предоставить идентификатор потока. Также сохраните URL-адрес манифеста, используемый для доступа к манифесту конкретного пользователя на вашем сервере для работы с манифестами.

Для поддержки AdUI, например, значков adChoices, необходимо также передать ссылку на узел, содержащий ваш видеоконтент, в составе запроса.

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

Добавьте обработчики событий и запустите поток.

Прямая трансляция, подкасты

После запроса на трансляцию остается выполнить всего несколько действий: добавить обработчики событий для отслеживания прогресса показа рекламы и пересылать сообщения Roku в SDK. Важно пересылать все сообщения в SDK для обеспечения корректного воспроизведения рекламы. В противном случае, данные о просмотрах рекламы будут отображаться некорректно.

На этом шаге вы также добавляете функцию для замены макроса [[STREAMID]] на идентификатор потока и передаете URL-адрес завершенного запроса манифеста видеоплееру. В данной реализации идентификатор потока получается на этом шаге, но в зависимости от вашей интеграции с VTP он может быть доступен и до этого шага.

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

VOD-стриминг Под-сервис

После запроса на трансляцию остается выполнить всего несколько действий: добавить обработчики событий для отслеживания прогресса показа рекламы и пересылать сообщения Roku в SDK. Важно пересылать все сообщения в SDK для обеспечения корректного воспроизведения рекламы. В противном случае, данные о просмотрах рекламы будут отображаться некорректно.

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