Roku SDK Guide v1.0.0

Initial Setup

This library adds a video preview component called VilynxPreview.

The Roku platform doesn't allow playing multiple videos at the same time, therefore it is required to manage every change in the player's status.

In the home screen, we will call the main fullscreen video player object “VideoPlayer”.

There are two possible structures to this code:

  • The VilynxPreview and VideoPlayer are in the same XML.
  • VilynxPreview and the VideoPlayer are in different XMLs.

Both options follow the same logic, with the only difference that everything should be added in the same .xml file and handled by its .brs file in the first option.

Below we will review an example using two different XMLs (option 2).

1. Install

  • Add the folder Vilynx/ to the folder /components
  • Add the file vilynx.brs on the /source folder
  • Every item in the grid screen must have the following structure (there is an example on the main.brs file included in the demo):
item = {
    "title": "Title example",
    "description":"Description example",
    "url":"here goes the fullscreen video url",
    "vilynxUrlForHash":"here goes the Vilynx URL needed to get the corresponding hash"
}

Before adding the items to the grid, it is necessary to call to init the vilynx SDK from your channel main file.

initVilynx("<Vilynx owner token>").

Calling addVilynxItemsToRow(row, itemsArray) will return the row with VilynxItems inserted in the same order:

/**
* "row" is a object type "RoSGNode"
* "itemsArray" is the array of "items" with the indicated schema.
**/
vilynxRow = addVilynxItemsToRow(row, itemsArray)

This row can be appended to the grid.

An example usage can be found on the demo project:

Function setGridContent(list As Object)
  RowItems = createObject("RoSGNode","ContentNode")

  'Set the Vilynx Public Key
  initVilynx("XXXXXXXXXX")

  for each rowAA in list
      row = createObject("RoSGNode","ContentNode")
      row.Title = rowAA.Title


      row = addVilynxItemsToRow(row, rowAA.ContentList)

      RowItems.appendChild(row)
  end for

  return RowItems
End Function

2. Usage of the VilynxPreview component

VilynxPreview comes as a component that has a video player. When you request it to play a video, it will use the VilynxCacheTask (that comes with the SDK) to check if the requested video was previusly cached, if it was play it will from local storage, otherwise it will download it and then play it.

Roku OS only supports caching since version 8.0. The SDK internally checks if cache is available for the device the channel is running, if the device has cache then the SDK will use it. If the cache is not available, then it will download the video to the tmp directory, which contents are not persisted when the channel exits, but improves the overall performance of the channel.

a. On the XML that will contain VilynxPreview

On the .xml file where the VilynxPreview will be added, append the VilynxGridScreen.brs to connect it to Vilynx library.

<script type="text/brightscript" uri="pkg:/components/Vilynx/VilynxGridScreen.brs" />

So now we have 2 scripts on our GridScreen.xml.

In the <children> tag, add the following structure. This will handle the full screen preview.

<VilynxPreview
  id="VilynxPreview"
  width="1280"
  height="720"
  color="0xAAAAAA"
  ShadeOpacity="0.1"/>

<Timer
  id="waitToParentToFinishVideo"
  repeat="false"
  duration="0.5"/>

On the <RowList> element, set the itemComponentName property to VilynxGroup. This way, every new grid element created, will be handled by the vilynx SDK.

itemComponentName="VilynxGroup"

Also, on the GridScreen.xml we have to connect the focused and selected events:

<field id="itemFocused" type="intarray" alias="RowList.rowItemFocused" onChange="OnItemFocused"/>
<field id="itemSelected" type="intarray" alias="RowList.rowItemSelected" onChange="OnItemSelected"/>

b. On the BRS that will contain VilynxPreview

Inside the init() function, call

initVilynxGridScreen()

We can get when the focus changes by the OnItemFocused observer function. When it changes, call startPreviewVideo(vilynxThumbnail, vilynxUrl), then the Vilynx SDK will handle all the events from resolving the cached uri if it exists, to stop and play the new video:

Sub OnItemFocused()
    itemFocused = m.top.itemFocused

    'When an item gains the key focus, set to a 2-element array,
    'where element 0 contains the index of the focused row,
    'and element 1 contains the index of the focused item in that row.
    if itemFocused.Count() = 2 then
    ...
        focusedContent = m.top.content.getChild(row).getChild(cellIndex)

        if focusedContent <> invalid then
            'set focused content to top interface
            m.top.focusedContent = focusedContent

            'set content to description node
            m.Description.content = focusedContent

            'set background wallpaper
            m.Background.uri = focusedContent.hdBackgroundImageUrl
            startVideoPreview(focusedContent.vilynxThumbnail, focusedContent.vilynxUrl)

        end if
    ...
    end if
end Sub

When the main video must play, due Roku limitations, there is need to tell the SDK to stop playing/buffering the current preview. That must be done calling this function. Since we connected the selected event to videoPlayerGridWillStart(), we call it inside this function:

Sub OnItemSelected()
    videoPlayerGridWillStart()
end Sub

c. Usage of the VilynxPreview component

XML with VideoPlayer:

Get the parent .XML file and connect it to Vilynx library:

<script type="text/brightscript" uri="pkg:/components/Vilynx/VilynxHomeScene.brs" />

On the <children&gt> tag, add the following XML code:

<Timer
  id="waitToFinishVilynxVideo"
  repeat="false"
  duration="0.5"/>

BRS with VideoPlayer:

On the Init() function, add call the following function to init the component.

initVilynxHomeScreen()

To play the videoPlayer, call this function:

videoPlayerHomeWillStart()

Then the following callback must be implemented and the videoPlayer can be safely started within this function:

videoPlayerCanPlay()

The same should happen AFTER video player is stopped:

videoPlayerDidStop()

d. Troubleshooting

In case of OnVideoPlayerStateChange(), for videoPlayer.state = "finished";, it could be necessary to force the video to stop (i.e. videoPlayer.control = "stop") before calling.

videoPlayerDidStop()

Beware that all the playing videos or showing components logic will be handled by the Vilynx Library. If other components control the videoPlayer behaviour, this can create conflicts and unexpected results.

3. Predownloading videos

The SDK comes with a task named VilynxDownloadTask, that if the device has cache available you can use it to start downloading videos before the user has selected them. For example, when using a grid with rows, when an item is selected you can request the previous and next video.

An example of this usage comes with the demo channel on GridScreen.brs source file:

Sub launchDownloadTask(videoUrl as String, videoWidth as Integer)
    m.vilynxDownloadTask = createObject("roSGNode", "VilynxDownloadTask")
    m.vilynxDownloadTask.videoUrl = videoUrl
    m.vilynxDownloadTask.videoWidth = videoWidth

    m.vilynxDownloadTask.control = "RUN"
end sub

Sub OnItemFocused()
  itemFocused = m.top.itemFocused
  '? ">> GridScreen > OnItemFocused"; itemFocused

  'When an item gains the key focus, set to a 2-element array,
  'where element 0 contains the index of the focused row,
  'and element 1 contains the index of the focused item in that row.
  if itemFocused.Count() = 2 then
      'get content node by index from grid

      'Get the row
      row = itemFocused[0]
      'Get the cell index inside the row
      cellIndex = itemFocused[1]
      'Get the child count to know the limits of our objects array
      childCount = m.top.content.getChild(row).getChildCount()
      print "Row is: " + Str(row) + " cellIndex: " + Str(cellIndex) + " child count: " + Str(childCount)

      'If the previous item is greater than 0, just request the previous item
      if cellIndex - 1 >= 0
          previousPreview = m.top.content.getChild(row).getChild(cellIndex - 1)
          launchDownloadTask(previousPreview.vilynxUrl, m.VilynxPreview.boundingRect().width)
      else
          'If it is less than 0, we go to the end og the array (childCount - 1) and request that item
          previousPreview = m.top.content.getChild(row).getChild(childCount - 1)
          launchDownloadTask(previousPreview.vilynxUrl, m.VilynxPreview.boundingRect().width)
      end if

      ' If the next item is not out of bounds, requests that item
      if cellIndex + 1 < childCount
          nextPreview = m.top.content.getChild(row).getChild(cellIndex + 1)
          launchDownloadTask(nextPreview.vilynxUrl, m.VilynxPreview.boundingRect().width)
      else
          ' If it was out, go to the start of the array and request that item
          nextPreview = m.top.content.getChild(row).getChild(0)
          launchDownloadTask(nextPreview.vilynxUrl, m.VilynxPreview.boundingRect().width)
      end if
      ...
end Sub

launchDownloadTask(videoUrl as String, videoWidth as Integer) will create a VilynxDownloadTask Task node that will start downloading the video if needed. The first parameter of the function is just the Vilynx video preview url, and the second one is the width of the current player. Based on the width the SDK will choose which resolution of the video should be requested.

The library will check if the video was already downloaded, and will not download it again if it was.

Download SDK + Example

To get access to our SDKs, please contact us at info@vilynx.com.