We are a Roku programmer and are having a problem with occasional packet loss of data on our data upload of our Roku content. This problem lies directly with our ISP and we have been working for weeks to correct this problem. A new fiber is being installed with a 60 day completion time but for now we have plenty of bandwidth up, but an occasional millisecond spike or dip in our data upload of the HLS encode, and the Roku boxes receiving the signal send the channel back to the menu.
Our purpose for the Roku channel is a private channel and direct monitored by the end-users to our channel only. It is for more of a corporate project. The problem is that we and the end user facilities never turn it off, and if we have this network spike on our end, it causes our end users to have to send someone to hit the PLAY button every time this happens because the channel menu comes up. Sometimes at very inopportune moments during the playback.
Is there a way in the script for the channel to tell the Roku signal to “Select” or “Play” the signal automatically in specific time intervals? Say every 30 seconds or 1 minute or something? This would essentially keep the signal going to the Roku boxes without our corporate end users having to send someone to their closed-circuit head-end of the facilities that have the boxes to simply press “play” on the remote whenever there was a signal drop on the upload causing the box to go to menu.
I would think just like when building a DVD, we can script in to auto-play or repeat intervals, that maybe we could do the same with our bright script for our channel? Just not sure if it is possible or how to go about attempting a test.
I have heard there is a way to force the Roku to read from the DVR if it senses signal loss then back to the live steam once it senses it back up. This may be the simpler option?
Any suggestions?
Does your channel get an isRequestFailed() or isPartialResult() event when the HLS steam is interrupted? If so, you might be able to code the channel so that it automatically restarts the stream. I’ve been able to do that with my audio player channel so that any interrupted audio streams are automatically restarted without the user having to select ‘Play’ again. I would think it would be similar for video streams.
You could pretty easily have a check in the function that calls your video player function like:
returnvalue=-5
while returnvalue=-5
returnvalue=playvideo(video)
end while
so if the video playback fails for any reason other than end of content or user canceling playbak, your video playback function will just start playback again.
you would need to return a value to indicate failure like the -5 above and a different value to indicate intentional end of play.
-RokuJoel
I tried the solution you presented but it did not work. I’m sure do to a mistake on my end.
Below is the code for my video player function, I put the code inside that function, was that right? Am I missing something?
Function displayVideo(args As Dynamic)
print "Displaying video: "
p = CreateObject("roMessagePort")
video = CreateObject("roVideoScreen")
video.setMessagePort(p)
bitrates = [0] ' 0 = no dots, adaptive bitrate
'bitrates = [348] ' <500 Kbps = 1 dot
'bitrates = [664] ' <800 Kbps = 2 dots
'bitrates = [996] ' <1.1Mbps = 3 dots
bitrates = [1500] ' >=1.1Mbps = 4 dots
'bitrates = [0]
'Stream Info
urls = ["http://kitiosdevices-i.akamaihd.net/hls/live/202237/FFE_Roku/iOS/playlist.m3u8"] ' Link of stream, for us, must be an .m3u8
qualities = ["SD"] ' Values for this are "SD" & "HD"
streamformat = "hls" ' Type of stream, we are using HLS.
title = "Family Friendly Entertainment" ' Text shown while stream is loading.
srt = "file://pkg:/source/ffe.srt" ' This .srt is not needed for our channel; however, it must not be deleted or commented out because it is reference below
if type(args) = "roAssociativeArray"
if type(args.url) = "roString" and args.url <> "" then
urls[0] = args.url
end if
if type(args.StreamFormat) = "roString" and args.StreamFormat <> "" then
StreamFormat = args.StreamFormat
end if
if type(args.title) = "roString" and args.title <> "" then
title = args.title
else
title = ""
end if
if type(args.srt) = "roString" and args.srt <> "" then
srt = args.StreamFormat
else
srt = ""
end if
end if
videoclip = CreateObject("roAssociativeArray")
videoclip.StreamBitrates = bitrates
videoclip.StreamUrls = urls
videoclip.StreamQualities = qualities
videoclip.StreamFormat = StreamFormat
videoclip.Title = title
print "srt = ";srt
if srt <> invalid and srt <> "" then
videoclip.SubtitleUrl = srt
end if
video.SetContent(videoclip)
video.show()
lastSavedPos = 0
statusInterval = 10 'position must change by more than this number of seconds before saving
'Code to make channel auto restart
returnvalue=-5
while returnvalue=-5
returnvalue=playvideo(video)
end while
while true
msg = wait(0, video.GetMessagePort())
if type(msg) = "roVideoScreenEvent"
if msg.isScreenClosed() then 'ScreenClosed event
print "Closing video screen"
exit while
else if msg.isPlaybackPosition() then
nowpos = msg.GetIndex()
if nowpos > 10000
end if
if nowpos > 0
if abs(nowpos - lastSavedPos) > statusInterval
lastSavedPos = nowpos
end if
end if
else if msg.isRequestFailed()
print "play failed: "; msg.GetMessage()
else
print "Unknown event: "; msg.GetType(); " msg: "; msg.GetMessage()
endif
end if
end while
End Function
No, I meant the function that calls your videoplayer function is where you would put that code.
In the videoplayer you would just change
else if message.isrequestfailed()
return -5
else if message.isfullresult()
return -1
end if
down near the bottom of the function.
so undo what you did, then modify your video function as above. Assuming you are using simplevideoplayer, which it looks like you are, then you would modify function show springboard screen as follows:
from
else if msg.isButtonPressed()
print "Button pressed: "; msg.GetIndex(); " " msg.GetData()
if msg.GetIndex() = 1
displayVideo("")
else if msg.GetIndex() = 2
return true
endif
else
to:
else if msg.isButtonPressed()
print "Button pressed: "; msg.GetIndex(); " " msg.GetData()
if msg.GetIndex() = 1
returnvalue=-5
while returnvalue=-5
returnvalue=displayVideo("")
end while
else if msg.GetIndex() = 2
return true
endif
else
-Joel
I updated my code with the snippets that you provided, see below.
Another problem I’m having now is that when i upload the code to the ROKU box and view in “Side Developer Mode,” the stream will play. But when I package, and upload it to ROKU and preview it, it will show the loading screen for a couple seconds before returning me back to the ROKU home screen.
Any Idea what could be causing that. After all, this is the same code that was running before and worked.
Thanks for you help!
'*************************************************************
'** showSpringboardScreen()
'*************************************************************
Function showSpringboardScreen(item as object) As Boolean
port = CreateObject("roMessagePort")
screen = CreateObject("roSpringboardScreen")
print "showSpringboardScreen"
screen.SetMessagePort(port)
screen.AllowUpdates(false)
if item <> invalid and type(item) = "roAssociativeArray"
screen.SetContent(item)
endif
screen.SetDescriptionStyle("generic") 'audio, movie, video, generic
' generic+episode=4x3,
screen.ClearButtons()
screen.AddButton(1,"Play Live Stream")
screen.AddButton(2,"Go Back")
screen.SetStaticRatingEnabled(false)
screen.AllowUpdates(true)
screen.Show()
downKey=3
selectKey=6
while true
msg = wait(0, screen.GetMessagePort())
if type(msg) = "roSpringboardScreenEvent"
if msg.isScreenClosed()
print "Screen closed"
exit while
else if msg.isButtonPressed()
print "Button pressed: "; msg.GetIndex(); " " msg.GetData()
if msg.GetIndex() = 1
returnvalue=-5
while returnvalue=-5
returnvalue=displayVideo("")
end while
else if msg.GetIndex() = 2
return true
endif
else
print "Unknown event: "; msg.GetType(); " msg: "; msg.GetMessage()
endif
else
print "wrong type.... type=";msg.GetType(); " msg: "; msg.GetMessage()
endif
end while
return true
End Function
'*************************************************************
'** displayVideo()
'*************************************************************
Function displayVideo(args As Dynamic)
print "Displaying video: "
p = CreateObject("roMessagePort")
video = CreateObject("roVideoScreen")
video.setMessagePort(p)
bitrates = [0] ' 0 = no dots, adaptive bitrate
'bitrates = [348] ' <500 Kbps = 1 dot
'bitrates = [664] ' <800 Kbps = 2 dots
'bitrates = [996] ' <1.1Mbps = 3 dots
bitrates = [1500] ' >=1.1Mbps = 4 dots
'bitrates = [0]
'Swap the commented values below to play different video clips...
' Family Friendly Entertainment Stream Info
urls = ["http://kitiosdevices-i.akamaihd.net/hls/live/202237/FFE_Roku/iOS/playlist.m3u8"]
qualities = ["SD"]
streamformat = "hls"
title = "Family Friendly Entertainment"
srt = "file://pkg:/source/craigventer.srt"
if type(args) = "roAssociativeArray"
if type(args.url) = "roString" and args.url <> "" then
urls[0] = args.url
end if
if type(args.StreamFormat) = "roString" and args.StreamFormat <> "" then
StreamFormat = args.StreamFormat
end if
if type(args.title) = "roString" and args.title <> "" then
title = args.title
else
title = ""
end if
if type(args.srt) = "roString" and args.srt <> "" then
srt = args.StreamFormat
else
srt = ""
end if
end if
videoclip = CreateObject("roAssociativeArray")
videoclip.StreamBitrates = bitrates
videoclip.StreamUrls = urls
videoclip.StreamQualities = qualities
videoclip.StreamFormat = StreamFormat
videoclip.Title = title
print "srt = ";srt
if srt <> invalid and srt <> "" then
videoclip.SubtitleUrl = srt
end if
video.SetContent(videoclip)
video.show()
lastSavedPos = 0
statusInterval = 10 'position must change by more than this number of seconds before saving
while true
msg = wait(0, video.GetMessagePort())
if type(msg) = "roVideoScreenEvent"
if msg.isScreenClosed() then 'ScreenClosed event
print "Closing video screen"
exit while
else if msg.isPlaybackPosition() then
nowpos = msg.GetIndex()
if nowpos > 10000
end if
if nowpos > 0
if abs(nowpos - lastSavedPos) > statusInterval
lastSavedPos = nowpos
end if
end if
else if message.isrequestfailed()
return -5
else if message.isfullresult()
return -1
end if
end if
end while
End Function
When you side-load and the stream plays, does your brightscript stop running and bring you back to the debugger prompt, even though the video is playing?
In public or private channel, if the code stops running, the channel exits instead of becoming unresponsive to clicks.
Joel
When you side-load and the stream plays, does your brightscript stop running and bring you back to the debugger prompt, even though the video is playing?
It does not bring me back to any debugger that I am aware of. How would I know?
When developing and testing a channel, you should be connected to your Roku player via telnet connection on port 8085. Best bet on a pc is to download Putty and use it (select the telnet setting) to connect to your device. There is also a pure telnet version called PuttyTel if you don’t want to be bothered with other “swiss army knife” functions.
You can also install window’s built-in telnet but it is not as easy to use as Putty.
On a mac, just load Terminal and type:
telnet 8085
For example, if your device is on 192.168.1.54 then you would type:
telnet 192.168.1.54 8085
and hit the enter key.
My fault, error in the example code I posted.
Joel,
I think I found the problem that I was having. The variable in the code from the development kit used “msg” the variable in the code that you supplied was “message.”
After changing this, everything appears to be working. I’m testing the script now to see if the script will auto restart the stream.
One question though. Is there a certain amount of time that this script that you wrote will no longer work, like say the time it takes for a piece of hardware needing to be restarted versus a simple spike/dropout in bandwidth? Or will this script keep retrying until it gets connected?
Joel,
Saw where you posted the fix. I didn’t see that until I had discovered that problem as well.
Thanks for responding though!
“CorporateTV” wrote:
One question though. Is there a certain amount of time that this script that you wrote will no longer work, like say the time it takes for a piece of hardware needing to be restarted versus a simple spike/dropout in bandwidth? Or will this script keep retrying until it gets connected?
Theoretically, it should fail and retry over and over, however, there may be some conditions under which it might stall and stay stalled forever, so you might want to work out a timer of some kind to close the screen with a -5 (or whatever you choose for your “fail” code) after a certain amount of time during which no position notification updates have happened or the Start of Play event fails to trigger.
I would also recommend using a range of various bitrate encodes for the video, from low to high, so that if the bandwidth fluctuates, your channel still plays.