DAI용 IMA SDK 설정

플랫폼 선택: HTML5 Android iOS tvOS Cast Roku

IMA SDK를 사용하면 웹사이트와 앱에 멀티미디어 광고를 쉽게 통합할 수 있습니다. IMA SDK는 VAST 호환 광고 서버에서 광고를 요청하고 앱에서 광고 재생을 관리할 수 있습니다. IMA DAI SDK를 사용하면 앱에서 광고 및 콘텐츠 동영상(VOD 또는 라이브 콘텐츠)의 스트림을 요청합니다. 그러면 SDK가 결합된 동영상 스트림을 반환하므로 앱 내에서 광고와 콘텐츠 동영상 간 전환을 관리하지 않아도 됩니다.

관심 있는 DAI 솔루션 선택

종합 서비스 DAI

이 가이드에서는 IMA DAI SDK를 간단한 동영상 플레이어 앱에 통합하는 방법을 보여줍니다. 완료된 샘플 통합을 확인하거나 따라 하려면 GitHub에서 기본 예시를 다운로드하세요.

IMA DAI 개요

IMA DAI를 구현하려면 이 가이드에 설명된 대로 두 가지 주요 SDK 구성요소가 필요합니다.

  • StreamRequest: 스트림 요청을 정의하는 객체입니다. 스트림 요청은 주문형 비디오 또는 라이브 스트림에 대한 요청일 수 있습니다. 라이브 스트림 요청은 애셋 키를 지정하고 VOD 요청은 CMS ID와 동영상 ID를 지정합니다. 두 요청 유형 모두 지정된 스트림에 액세스하는 데 필요한 API 키와 IMA SDK가 Google Ad Manager 설정에 지정된 대로 광고 식별자를 처리하는 Google Ad Manager 네트워크 코드를 선택적으로 포함할 수 있습니다.
  • StreamManager: 동적 광고 삽입 스트림과 DAI 백엔드와의 상호작용을 처리하는 객체입니다. 스트림 관리자는 추적 핑을 처리하고 스트림 및 광고 이벤트를 게시자에게 전달합니다.

기본 요건

동영상 재생

제공된 샘플 동영상 플레이어는 기본적으로 콘텐츠 동영상을 재생합니다. 개발 환경이 올바르게 설정되었는지 확인하려면 샘플 플레이어를 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 광고 프레임워크 로드

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. SDK 로드 이벤트에 응답하도록 onSdkLoaded()onSdkLoadedError() 리스너 서브루틴을 만듭니다.

    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() 서브루틴을 만듭니다. adChoices 아이콘과 같은 광고 UI를 지원하려면 콘텐츠 동영상을 포함하는 노드에 대한 참조도 요청의 일부로 전달해야 합니다.

    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 또는 라이브 스트림 중에서 선택합니다. 다음 예에는 라이브 스트림과 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 객체로 변경하여 대신 라이브 스트림을 사용할 수 있습니다.

스트림 시작

스트림 데이터를 수신 대기하고 playStream() 서브루틴을 호출하는 urlLoadRequested() 서브루틴을 만듭니다.

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

스트림 메타데이터 수신 대기

스트림 재생 중에 실행되고 StreamManager.onMessage()를 사용하여 스트림 메타데이터를 IMA에 전송하는 while 루프로 runLoop() 서브루틴을 만듭니다.

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