googleads / googleads-ima-roku-dai

Apache License 2.0
15 stars 12 forks source link

Error when attempting to use the Video Stitcher API with Roku #7

Closed Shaharbad closed 8 months ago

Shaharbad commented 1 year ago

Hey everyone, I tried following the tutorial of integrating the Video Stitcher API with Roku but it seems like it detecs the following lines as syntax error:

  else if streamData.type = "stitcherVod"
    request = sdk.CreateVideoStitcherVodStreamRequest(
      streamData.adTagUrl,
      streamData.networkCode,
      streamData.contentSourceUrl,
      streamData.region,
      streamData.projectNumber,
      streamData.oAuthToken
    )

What can i do to fix it?

Kiro705 commented 1 year ago

Hello @Shaharbad ,

Is this an error you are seeing in one of this repository's samples? If so could you please share the file and I will take a look.

Otherwise, if this is an error in your own unique IMA Roku implementation, please raise an issue on the IMA SDK technical forum, and someone there will be able to assist you.

Thank you, Jackson IMA SDK team

Shaharbad commented 1 year ago

Hey Kiro, Yes of course. Heres the issue:

<?xml version = "1.0" encoding = "utf-8" ?>

<component name = "imasdk" extends = "Task">
<interface>
  <field id="sdkLoaded" type="Boolean" />
  <field id="streamManagerReady" type="Boolean" />
  <field id="errors" type="stringarray" />
  <field id="streamData" type="assocarray" />
  <field id="urlData" type="assocarray" />
  <field id="adPlaying" type="Boolean" />
  <field id="video" type="Node" />

</interface>

<script type = "text/brightscript">
<![CDATA[
  Library "Roku_Ads.brs"
  Library "IMA3.brs"

  sub init()
    m.top.functionName = "runThread"
  End Sub

  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()
    ' 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

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

  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

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

    request = {}
    streamData = m.top.streamData
    if streamData.type = "live"
      request = sdk.CreateLiveStreamRequest(streamData.asseima dtKey, streamData.apiKey)
    else if streamData.type = "stitcherVod"
      request = sdk.CreateVideoStitcherVodStreamRequest(
        streamData.adTagUrl,
        streamData.networkCode,
        streamData.contentSourceUrl,
        streamData.region,
        streamData.projectNumber,
        streamData.oAuthToken
      )
    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.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

  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

]]>
</script>
</component>
<?xml version="1.0" encoding="utf-8" ?>
<component name="MainScene" extends="Scene" initialFocus = "myVideo">
<script type="text/brightscript">
<![CDATA[
  function init()
    m.video = m.top.findNode("myVideo")
    m.video.notificationinterval = 1
    m.testLiveStream = {
      title: "Live Stream",
      assetKey: "c-rArva4ShKVIAkNfy6HUQ",
      apiKey: "",
      type: "live"
    }
    m.testVodStream = {
      title: "VOD stream"
      contentSourceId: "2548831",
      videoId: "tears-of-steel",
      apiKey: "",
      type: "vod"
    }
    m.testVideoStitcherVodStream = {
      //////MY information
    }
    loadImaSdk()
  end function

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.testVideoStitcherVodStream
  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

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

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

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

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
]]>
</script>

<children>
  <Video id="myVideo" width="1280" height="720" visible="false"/>
</children>

</component>

Those are the file im using, Another question I have is how can i use this api if I have publisher clients? I obviously cant give them sensitive information . How can I use this in scaleability? Will the publishers have to implement all this code inside their app?

Shaharbad commented 9 months ago

@Kiro705 Any updates on this?

thangduo commented 8 months ago

@Shaharbad The syntax error is that BrightScript doesn't support line continuation (see the discussion here for reference). In your case, please update the code to a single long line and that would fix the syntax error.

request = sdk.CreateVideoStitcherVodStreamRequest(streamData.adTagUrl, streamData.networkCode, streamData.contentSourceUrl, streamData.region, streamData.projectNumber, streamData.oAuthToken)