Auto Play menu in the Roku Script

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.

  • Joel

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

  • Joel

“CorporateTV” wrote:
The video will play in side mode, but the application will not even load when I package and upload it to ROKU. Any idea on what I’m doing wrong?
You’ve declared the variable as “msg”, but you’re trying to access it as “message”. Change your “message.isrequestfailed()” and “message.isfullresult()” to “msg.isrequestfailed()” and “msg.isfullresult()”.

My fault, error in the example code I posted.

  • Joel

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.

  • Joel