I'm trying to add VAST video pre-roll ads to the SThree sample Roku SDK project (the "Simple Grid with Video and Details page (.zip)" version).
I can get it to work on app start by putting the following code into main.brs
:
library "Roku_Ads.brs"
...
Sub RunUserInterface()
...
raf = Roku_Ads()
raf.setAdPrefs(false) 'disable back-filled ads
raf.setDebugOutput(true)
raf.setAdUrl("http://pubads.g.doubleclick.net/gampad/ads?slotname=/82114269/Video/fallbacktest&sz=1920x1080&url=[http://roku.com&unviewed_position_start=1&output=vast&impl=s&env=vp&gdfp_req=1&ad_rule=0&description_url=http%3A%2F%2Fapps.roku.com&vad_type=linear&sdkv=roku&min_ad_duration=0&max_ad_duration=60000&rdid=ROKU_ADS_TRACKING_ID&is_lat=ROKU_ADS_LIMIT_TRACKING&idtype=rida&correlator=ROKU_ADS_TIMESTAMP&scor=ROKU_ADS_TIMESTAMP&pod=POD_NUM&ppos=POD_POSITION&cust_params=genre%3DROKU_ADS_CONTENT_GENRE%26ua%3DROKU_ADS_USER_AGENT%26ai%3DROKU_ADS_APP_ID]http://roku.com&unviewed_position_start=1&output=vast&impl=s&env=vp&gdfp_req=1&ad_rule=0&description_url=http%3A%2F%2Fapps.roku.com&vad_type=linear&sdkv=roku&min_ad_duration=0&max_ad_duration=60000&rdid=ROKU_ADS_TRACKING_ID&is_lat=ROKU_ADS_LIMIT_TRACKING&idtype=rida&correlator=ROKU_ADS_TIMESTAMP&scor=ROKU_ADS_TIMESTAMP&pod=POD_NUM&ppos=POD_POSITION&cust_params=genre%3DROKU_ADS_CONTENT_GENRE%26ua%3DROKU_ADS_USER_AGENT%26ai%3DROKU_ADS_APP_ID")
adPods = raf.getAds()
shouldPlayContent = raf.showAds(adPods)
I however don't want to play an ad on startup, I want to play an ad before a video play. So I figure I can just add the lines above to components/screens/DetailsScreen/DetailsScreen.brs
:
' on Button press handler
Sub onItemSelected()
' first button is Play
if m.top.itemSelected = 0
'START ADDING FOR PRE-ROLL
raf = Roku_Ads()
raf.setAdPrefs(false) 'disable back-filled ads
raf.setDebugOutput(true)
raf.setAdUrl("http://pubads.g.doubleclick.net/gampad/ads?slotname=/82114269/Video/fallbacktest&sz=1920x1080&url=[http://roku.com&unviewed_position_start=1&output=vast&impl=s&env=vp&gdfp_req=1&ad_rule=0&description_url=http%3A%2F%2Fapps.roku.com&vad_type=linear&sdkv=roku&min_ad_duration=0&max_ad_duration=60000&rdid=ROKU_ADS_TRACKING_ID&is_lat=ROKU_ADS_LIMIT_TRACKING&idtype=rida&correlator=ROKU_ADS_TIMESTAMP&scor=ROKU_ADS_TIMESTAMP&pod=POD_NUM&ppos=POD_POSITION&cust_params=genre%3DROKU_ADS_CONTENT_GENRE%26ua%3DROKU_ADS_USER_AGENT%26ai%3DROKU_ADS_APP_ID]http://roku.com&unviewed_position_start=1&output=vast&impl=s&env=vp&gdfp_req=1&ad_rule=0&description_url=http%3A%2F%2Fapps.roku.com&vad_type=linear&sdkv=roku&min_ad_duration=0&max_ad_duration=60000&rdid=ROKU_ADS_TRACKING_ID&is_lat=ROKU_ADS_LIMIT_TRACKING&idtype=rida&correlator=ROKU_ADS_TIMESTAMP&scor=ROKU_ADS_TIMESTAMP&pod=POD_NUM&ppos=POD_POSITION&cust_params=genre%3DROKU_ADS_CONTENT_GENRE%26ua%3DROKU_ADS_USER_AGENT%26ai%3DROKU_ADS_APP_ID")
adPods = raf.getAds()
shouldPlayContent = raf.showAds(adPods)
'END ADDING FOR PRE-ROLL
if shouldPlayContent
m.videoPlayer.visible = true
m.videoPlayer.setFocus(true)
m.videoPlayer.control = "play"
m.videoPlayer.observeField("state", "OnVideoPlayerStateChange")
end if
end if
End Sub
When I run this I get an error:
Roku_Ads Framework version 1.8
BRIGHTSCRIPT: ERROR: roAppInfo: class PLUGIN|MARKUP on thread RENDER: roku_ads_lib:/Roku_Ads.brs(527)
'Dot' Operator attempted with invalid BrightScript Component or interface reference. (runtime error &hec) in roku_ads_lib:/Roku_Ads.brs(528)
528: ??
Backtrace:
#4 Function roku_ads_util_getappid(key_ As String) As String
file/line: roku_ads_lib:/Roku_Ads.brs(528)
#3 Function roku_ads_checkallowedfeature(keytype_ As String, util_ As Object) As Boolean
file/line: roku_ads_lib:/Roku_Ads.brs(1287)
#2 Function roku_ads_constructor() As Object
file/line: roku_ads_lib:/Roku_Ads.brs(264)
#1 Function roku_ads() As Object
file/line: roku_ads_lib:/Roku_Ads.brs(32)
#0 Function onitemselected() As Void
file/line: pkg:/components/screens/DetailsScreen/DetailsScreen.brs(75)
What am I doing wrong here? Can you not play an ad when a method is called from a onChange="onItemSelected"
in the component.xml?
Update: Eugene's answer below is correct, Here is how I solved the problem:
Read about scene graph threads, events and handling application events. Once that is done read this post on passing data between the Render thread and main thread. You will need to understand scene graph data scoping.
Essentially you observe the itemSelected
field in components/screens/DetailsScreen/DetailsScreen.xml
:
m.DetailsScreen = scene.findNode("DetailsScreen")
m.DetailsScreen.observeField("itemSelected", m.port)
Then in your main threads event loop you handle the roSGNodeEvent
:
while true
msg = wait(0, m.port)
msgType = type(msg)
? ">>>Main Thread Msg: ";msgType
if msgType = "roSGScreenEvent"
if msg.isScreenClosed() then return
else if msgType = "roSGNodeEvent"
fieldName = msg.getField()
fieldData = msg.getData()
? "> node: "; msg.getNode()
? "> field name: "; fieldName
? "> data: "; fieldData
if (fieldName = "itemSelected" and fieldData = 0) 'User pressed play
'wait for 0.5 second before proceeding to RAF
sleep(500)
PlayAd()
endif
end if
end while
PlayAd()
sets m.DetailsScreen.videoPlayerVisible = true
IF there was no ad or if ad finished playing. This causes onVideoVisibleChange
to be invoked in components/screens/DetailsScreen/DetailsScreen.brs
You can't use RAF in Render thread. You have to send event to the Main thread and and show ads there. You can find samples of RAF integration in Scene Graph here. More info on threads in Scene Graph can be found here.