Reputation: 21
I am currently using Eclipse IDE with the Roku Developer Plugin to create a channel. I have experience in programming and code but brightscript has been a little more difficult for me to find my comfort with.
I have successfully created a channel that streams sufficiently. What I'm trying to do now is test the inclusion of RAF. I have tried looking through the code of an existing RAF template along with my current working streaming program.
Unfortunately the calls and variable names are different enough, and my ignorance is high enough I'm struggling to connect some dots. As I included the RAF library and code, or the code I thought I needed, the video no longer plays when I press the play button. The channel loads and the preview/details load just when I press play it does nothing.
Here is the code for that section of code on the page.
Sub onItemSelected()
' first button is Play
if m.top.itemSelected = 0
m.videoPlayer = CreateObject("roSGNode", "Video")
m.videoPlayer.id="videoPlayer"
m.videoPlayer.translation="[0, 0]"
m.videoPlayer.width="1280"
m.videoPlayer.height="720"
m.videoPlayer.content = m.top.content
'show video player
m.top.AppendChild(m.videoPlayer)
m.videoPlayer.visible = true
m.videoPlayer.setFocus(true)
m.videoPlayer.control = "play"
m.videoPlayer.observeField("state", "OnVideoPlayerStateChange")
m.videoPlayer.observeField("visible", "onVideoVisibleChange")
'THIS IS THE CODE I ADDED FROM THE RAF EXAMPLE
'EVERYTHING IN BELOW THIS UNTIL THE END OF THE
'SUB IF REMOVED THE VIDEO PLAYS.
'--------------------------------------------------------------------------------
adIface = Roku_Ads() 'RAF initialize
print "Roku_Ads library version: " + adIface.getLibVersion()
adIface.setDebugOutput(true) 'for debug pupropse
'Indicates whether the default Roku backfill ad service URL
'should be used in case the client-configured URL fails (2 retries)
'to return any renderable ads.
adIface.setAdPrefs(true, 2)
' Normally, would set publisher's ad URL here. Uncomment following line to do so.
' adIface.setAdUrl(m.videoContent.adUrl)
' Otherwise uses default Roku ad server (with single preroll placeholder ad)
'Returns available ad pod(s) scheduled for rendering or invalid, if none are available.
adPods = adIface.getAds()
playContent = true
'render pre-roll ads
if adPods <> invalid and adPods.count() > 0 then
playContent = adIface.showAds(adPods)
endif
while(true)
msg = wait(0, m.port)
msgType = type(msg)
if msgType = "roSGScreenEvent"
if msg.isScreenClosed() then return
else if msgType = "roSGNodeEvent"
if (msg.GetNode() = "DetailsScreen")
if msg.GetField() = "position" then
'render mid-roll ads
curPos = m.video.position
videoEvent = createPlayPosMsg(curPos)
adPods = adIface.getAds(videoEvent)
if adPods <> invalid and adPods.count() > 0
m.video.control = "stop"
playContent = adIface.showAds(adPods)
if playContent then
m.video.seek = curPos
m.video.control = "play"
endif
endif
else if msg.GetField() = "state" then
curState = m.video.state
if curState = "finished" then
'render post-roll ads
videoEvent = createPlayPosMsg(curPos, true)
adPods = adIface.getAds(videoEvent)
m.video.control = "stop"
if adPods <> invalid and adPods.count() > 0
adIface.showAds(adPods)
end if
exit while
endif
else if msg.GetField() = "navBack" then
'back button handling
if msg.GetData() = true then
m.video.control = "stop"
exit while
endif
end if
end if
end if
end while
'----------------------------------------------------------------------
'THIS IS THE END OF THE RAF CODE I INSERTED INTO THE VIDEO TEMPLATE.
end if
End Sub
On Eclipse it gives me an error that I have tried researching and figuring out but as I mentioned I'm stuck.
Current Function:
086: m.videoPlayer.control = "play"
087: m.videoPlayer.observeField("state", "OnVideoPlayerStateChange")
088: m.videoPlayer.observeField("visible", "onVideoVisibleChange")
089:
090: 'THIS IS THE CODE I ADDED FROM THE RAF EXAMPLE
091: 'EVERYTHING IN BELOW THIS UNTIL THE END OF THE
092: 'SUB IF REMOVED THE VIDEO PLAYS.
093: '--------------------------------------------------------------------------------
094:* adIface = Roku_Ads() 'RAF initialize
095: print "Roku_Ads library version: " + adIface.getLibVersion()
096:
097: adIface.setDebugOutput(true) 'for debug pupropse
098:
Function Call Operator ( ) attempted on non-function. (runtime error &he0) in pkg:/components/screens/DetailsScreen/DetailsScreen.brs(94)
094: adIface = Roku_Ads() 'RAF initialize
Backtrace:
#0 Function onitemselected() As Void
file/line: pkg:/components/screens/DetailsScreen/DetailsScreen.brs(94)
Local Variables:
global Interface:ifGlobal
m roAssociativeArray refcnt=2 count:7
adiface <uninitialized>
adpods <uninitialized>
playcontent <uninitialized>
msg <uninitialized>
msgtype <uninitialized>
curpos <uninitialized>
videoevent <uninitialized>
curstate <uninitialized>
roku_ads <uninitialized>
createplayposmsg <uninitialized>
Threads:
ID Location Source Code
0 pkg:/source/main.brs(34) msg = wait(0, port)
1* ...ailsScreen/DetailsScreen.brs(94) adIface = Roku_Ads() 'RAF initialize
*selected
Brightscript Debugger>
I'm hoping to narrow down how to modify my channel to make this work. I did leave out this code:
'RAF content params
adIface.setContentId(m.videoContent.contentId)
adIface.SetContentGenre(m.videoContent.contentGenre)
'Nielsen content params
adIface.enableNielsenDAR(true)
adIface.setContentLength(m.videoContent.conntentLength)
adIface.setNielsenProgramId(m.videoContent.nielsenProgramId)
adIface.setNielsenGenre(m.videoContent.nielsenGenre)
adIface.setNielsenAppId(m.videoContent.nielsenAppId)
Didnt want to work with Nielson stuff yet but not sure if I need to include it to make RAF work.
Thank you for your time, truly.
Upvotes: 1
Views: 988
Reputation: 21
Thank you everyone for your assistance. Nas Banov, I looked over the RAF example you linked to GitHub and I think I understand what I need to do just having difficulty seeing the road.
I have actually added the seperate .brs file to handle the RAF implementation as you suggested. The video is loaded into a grid from an external XML document as follows:
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
<channel>
<title></title>
<link />
<description></description>
<language></language>
<pubDate></pubDate>
<image>
<title></title>
<url></url>
<width>-1</width>
<height>-1</height>
</image>
<item>
<title></title>
<link></link>
<description></description>
<pubDate></pubDate>
<guid isPermaLink="false"></guid>
<media:content channels="2" bitrate="1328.0" duration="53"
fileSize="8731706" framerate="23.976" height="720"
type="video/mp4" width="1280" isDefault="true" url="">
<media:description></media:description>
<media:keywords></media:keywords>
<media:thumbnail url="" />
<media:title></media:title>
</media:content>
</item>
</channel>
</rss>
I was thinking of adding the Nielson Necessary fields to this XML if I find a way to push the xml entries into the RAF integration for reporting.
This is the Details portion of the menu selection. After pressing a button on the Grid layout the Details screen loads. Here i reference the PlayerTasks.brs which has the RAF integration code in it.
' ********** Copyright 2016 Roku Corp. All Rights Reserved. **********
' inits details screen
' sets all observers
' configures buttons for Details screen
Function Init()
? "[DetailsScreen] init"
m.top.observeField("visible", "onVisibleChange")
m.top.observeField("focusedChild", "OnFocusedChildChange")
m.buttons = m.top.findNode("Buttons")
m.poster = m.top.findNode("Poster")
m.description = m.top.findNode("Description")
m.background = m.top.findNode("Background")
' create buttons
result = []
for each button in ["Play", "Second button"]
result.push({title : button})
end for
m.buttons.content = ContentList2SimpleNode(result)
m.top.content=m.buttons.content
End Function
' set proper focus to buttons if Details opened and stops Video if Details closed
Sub onVisibleChange()
? "[DetailsScreen] onVisibleChange"
if m.top.visible = true then
m.buttons.jumpToItem = 0
m.buttons.setFocus(true)
else if m.videoPlayer <> invalid
m.videoPlayer.visible = false
m.videoPlayer.control = "stop"
m.poster.uri=""
m.background.uri=""
end if
End Sub
' set proper focus to Buttons in case if return from Video PLayer
Sub OnFocusedChildChange()
if m.top.isInFocusChain() and not m.buttons.hasFocus() and not m.videoPlayer.hasFocus() then
m.buttons.setFocus(true)
end if
End Sub
' set proper focus on buttons and stops video if return from Playback to details
Sub onVideoVisibleChange()
if m.videoPlayer.visible = false and m.top.visible = true
m.buttons.setFocus(true)
m.videoPlayer.control = "stop"
'clear video player content, for proper start of next video player
m.videoPlayer.content = invalid
'remove video player
m.top.removeChild(m.videoPlayer)
end if
End Sub
' event handler of Video player msg
Sub OnVideoPlayerStateChange()
if m.videoPlayer.state = "error"
' error handling
m.videoPlayer.visible = false
else if m.videoPlayer.state = "playing"
' playback handling
playContent()
else if m.videoPlayer.state = "finished"
m.videoPlayer.visible = false
end if
End Sub
sub playContent()
content = m.buttons.content
if content <> invalid then
m.video.content = content
m.video.visible = false
m.PlayerTask = CreateObject("roSGNode", "PlayerTask")
m.PlayerTask.observeField("state", "taskStateChanged")
m.PlayerTask.video = m.video
m.PlayerTask.control = "RUN"
end if
end sub
sub taskStateChanged(event as Object)
print "Player: taskStateChanged(), id = "; event.getNode(); ", "; event.getField(); " = "; event.getData()
state = event.GetData()
if state = "done" or state = "stop"
exitPlayer()
end if
end sub
' on Button press handler
Sub onItemSelected()
' first button is Play
if m.top.itemSelected = 0
m.videoPlayer = CreateObject("roSGNode", "Video")
m.videoPlayer.id="videoPlayer"
m.videoPlayer.translation="[0, 0]"
m.videoPlayer.width="1280"
m.videoPlayer.height="720"
m.videoPlayer.content = m.top.content
'show video player
m.top.AppendChild(m.videoPlayer)
m.videoPlayer.visible = true
m.videoPlayer.setFocus(true)
m.videoPlayer.control = "play"
m.videoPlayer.observeField("state", "OnVideoPlayerStateChange")
m.videoPlayer.observeField("visible", "onVideoVisibleChange")
end if
End Sub
' Content change handler
Sub OnContentChange()
m.description.content = m.top.content
m.description.Description.width = "770"
m.poster.uri = m.top.content.hdBackgroundImageUrl
m.background.uri = m.top.content.hdBackgroundImageUrl
End Sub
'///////////////////////////////////////////'
' Helper function convert AA to Node
Function ContentList2SimpleNode(contentList as Object, nodeType = "ContentNode" as String) as Object
result = createObject("roSGNode",nodeType)
if result <> invalid
for each itemAA in contentList
item = createObject("roSGNode", nodeType)
item.setFields(itemAA)
result.appendChild(item)
end for
end if
return result
End Function
Function OnkeyEvent(key, press) as Boolean
? ">>> Details >> OnkeyEvent"
result = false
if press AND key = "back" AND m.videoPlayer <> invalid AND m.videoPlayer.visible
m.videoPlayer.visible = false
result = true
end if
return result
End Function
I added the "PlayContent" subroutine which points to the .brs file with the RAF integration. Added the TaskStateChanged event as I noticed it was missing. I am getting stuck at the section that has [m.PlayerTask.video = m.video]
Invalid value for left-side of expression. (runtime error &he4)
Can't seem to figure out where I can pass the values of the parsed XML document into the playertasks section to get it working. I'm understanding what I need to do just can't find easy enough documentation to get it.
'*********************************************************************
'** (c) 2016-2017 Roku, Inc. All content herein is protected by U.S.
'** copyright and other applicable intellectual property laws and may
'** not be copied without the express permission of Roku, Inc., which
'** reserves all rights. Reuse of any of this content for any purpose
'** without the permission of Roku, Inc. is strictly prohibited.
'*********************************************************************
Library "Roku_Ads.brs"
sub init()
m.top.functionName = "playContentWithAds"
m.top.id = "PlayerTask"
end sub
sub playContentWithAds()
video = m.top.video
' `view` is the node under which RAF should display its UI (passed as 3rd argument of showAds())
view = video.getParent()
RAF = Roku_Ads()
'RAF.clearAdBufferScreenLayers() ' in case it was set earlier
'RAF.enableAdBufferMessaging(true, true) ' could have been cleared by custom screen
'RAF.setAdBufferScreenContent({})
content = video.content
RAF.setAdUrl(content.ad_url)
' for generic measurements api
RAF.setContentGenre(content.categories) 'if unset, ContentNode has it as []
' Nielsen DAR specific measurements
if content.nielsen_app_id <> invalid:
RAF.enableNielsenDAR(true)
RAF.setNielsenAppId(content.nielsen_app_id)
RAF.setNielsenGenre(content.nielsen_genre)
RAF.setNielsenProgramId(content.nielsen_program_id)
RAF.setContentLength(content.length)
end if
' log tracking events
' logObj = {
' log : Function(evtType = invalid as Dynamic, ctx = invalid as Dynamic)
' if GetInterface(evtType, "ifString") <> invalid
' print "*** tracking event " + evtType + " fired."
' if ctx.companion = true then
' print "***** companion = true"
' end if
' if ctx.errMsg <> invalid then print "***** Error message: " + ctx.errMsg
' if ctx.adIndex <> invalid then print "***** Ad Index: " + ctx.adIndex.ToStr()
' if ctx.ad <> invalid and ctx.ad.adTitle <> invalid then print "***** Ad Title: " + ctx.ad.adTitle
' else if ctx <> invalid and ctx.time <> invalid
' print "*** checking tracking events for ad progress: " + ctx.time.ToStr()
' end if
' End Function
' }
' logFunc = Function(obj = Invalid as Dynamic, evtType = invalid as Dynamic, ctx = invalid as Dynamic)
' obj.log(evtType, ctx)
' End Function
' RAF.setTrackingCallback(logFunc, logObj)
adPods = RAF.getAds() 'array of ad pods
keepPlaying = true 'gets set to `false` when showAds() was exited via Back button
' show the pre-roll ads, if any
if adPods <> invalid and adPods.count() > 0
keepPlaying = RAF.showAds(adPods, invalid, view)
end if
port = CreateObject("roMessagePort")
if keepPlaying then
video.observeField("position", port)
video.observeField("state", port)
video.visible = true
video.control = "play"
video.setFocus(true) 'so we can handle a Back key interruption
end if
curPos = 0
adPods = invalid
isPlayingPostroll = false
while keepPlaying
msg = wait(0, port)
if type(msg) = "roSGNodeEvent"
if msg.GetField() = "position" then
' keep track of where we reached in content
curPos = msg.GetData()
' check for mid-roll ads
adPods = RAF.getAds(msg)
if adPods <> invalid and adPods.count() > 0
print "PlayerTask: mid-roll ads, stopping video"
'ask the video to stop - the rest is handled in the state=stopped event below
video.control = "stop"
end if
else if msg.GetField() = "state" then
curState = msg.GetData()
print "PlayerTask: state = "; curState
if curState = "stopped" then
if adPods = invalid or adPods.count() = 0 then
exit while
end if
print "PlayerTask: playing midroll/postroll ads"
keepPlaying = RAF.showAds(adPods, invalid, view)
adPods = invalid
if isPlayingPostroll then
exit while
end if
if keepPlaying then
print "PlayerTask: mid-roll finished, seek to "; stri(curPos)
video.visible = true
video.seek = curPos
video.control = "play"
video.setFocus(true) 'important: take the focus back (RAF took it above)
end if
else if curState = "finished" then
print "PlayerTask: main content finished"
' render post-roll ads
adPods = RAF.getAds(msg)
if adPods = invalid or adPods.count() = 0 then
exit while
end if
print "PlayerTask: has postroll ads"
isPlayingPostroll = true
' stop the video, the post-roll would show when the state changes to "stopped" (above)
video.control = "stop"
end if
end if
end if
end while
print "PlayerTask: exiting playContentWithAds()"
end sub
Thank you everyone for helping me figure this out. Things have changed so much since when I focused on software development.
Upvotes: -1
Reputation: 29020
Also note you cannot invoke RAF from a render thread - which will be the next issue, looking at your code. It should either be done from the main thread or from a task thread (see https://github.com/rokudev/RAF4RSG-sample ).
Upvotes: 1
Reputation: 954
Make sure you have library imported at the top of your file:
Library "Roku_Ads.brs"
And entry in manifest file:
bs_libs_required=roku_ads_lib
Upvotes: 3