Forum Discussion

Transparent's avatar
10 years ago

roUniversalControlEvent - Pause/Play functions

Hi, I'm trying to implement the ability to Play and Pause my video when sent by ECP. I got the following code from customvideoplayer.

**How can I implement my video app to allow it to Play/Pause upon receiving a command through ECP (Posting /Keypress/Play) - When I try to it says code 13/code 113 in the debugger
I've code below that I'm trying to play with to get it to work but I'm not sure if I'm heading with the right approach.

Screenshot: Send video url and it plays fine
http://imgur.com/a/PcQ0v

Screenshot: Command I'm sending to try to Pause the video
http://imgur.com/a/DyPBB

Screenshot: What I'm getting back from debugger when I try to send Pause/Unpause(play) command
http://imgur.com/a/z00IC

msg = wait(0, m.port)
if msg <> invalid
'If this is a startup progress status message, record progress
'and update the UI accordingly:
if msg.isStatusMessage() and msg.GetMessage() = "startup progress"
m.paused = false
progress% = msg.GetIndex() / 10
if m.progress <> progress%
m.progress = progress%
end if

'Playback progress (in seconds):
else if msg.isPlaybackPosition()
m.position = msg.GetIndex()

else if msg.isRemoteKeyPressed()
index = msg.GetIndex()
print "Remote button pressed: " + index.tostr()

if index = 4 or index = 8 '<LEFT> or <REV>
m.position = m.position - 60
m.player.Seek(m.position * 1000)
else if index = 5 or index = 9 '<RIGHT> or <FWD>
m.position = m.position + 60
m.player.Seek(m.position * 1000)
else if index = 13 '<PAUSE/PLAY>
if m.player.paused m.player.Resume() else m.player.Pause()
end if

else if msg.isPaused()
this.paused = true


else if msg.isResumed()
this.paused = false


end if
'Output events for debug
print msg.GetType(); ","; msg.GetIndex(); ": "; msg.GetMessage()
if msg.GetInfo() <> invalid print msg.GetInfo();
end if
end while



Or is this the right way to do it -
  'event = port.GetMessage()
' if (event <> invalid)
' if (type(event) = "roUniversalControlEvent")
' code = event.GetInt()
' print "code: " + stri(code)
' if code = 13
'if player.paused player.Resume() else player.Pause()
' end if

' else if msg.isPaused()
' this.paused = true

' else if msg.isResumed()
' this.paused = false

' endif
' endif

20 Replies

  • "renojim" wrote:
    You appear to have multiple variables referring to whether or not the video is paused:
    m.paused
    m.player.paused
    this.paused

    You really need to clean this up. I doubt there's any reason to have anything other than a variable just called paused.

    -JT


    Hi Jim,
    That code is actually from CustomVideoPlayer, supplied by Roku https://sourceforge.net/projects/rokusdkexamples/files/
  • "Transparent" wrote:
    "renojim" wrote:
    You appear to have multiple variables referring to whether or not the video is paused:
    m.paused
    m.player.paused
    this.paused

    You really need to clean this up. I doubt there's any reason to have anything other than a variable just called paused.

    -JT


    Hi Jim,
    That code is actually from CustomVideoPlayer, supplied by Roku https://sourceforge.net/projects/rokusdkexamples/files/

    The Custom Video Player SDK example you linked to works just fine (if you use a working stream url). So if your code doesn't handle play/pause, you must have changed something that introduced the error. I suggest you look at what you've changed, perhaps even go back to the original code, substitute your own Stream url, make sure the StreamFormat is correct, e.g. "ism", and it should work.

    I also noticed that the code you posted is not the same code as that in the Custom Video Player example. For instance, there's no use of m.player.paused in the SDK example.
  • The Custom Video Player SDK example you linked to works just fine (if you use a working stream url). So if your code doesn't handle play/pause, you must have changed something that introduced the error. I suggest you look at what you've changed, perhaps even go back to the original code, substitute your own Stream url, make sure the StreamFormat is correct, e.g. "ism", and it should work.

    I also noticed that the code you posted is not the same code as that in the Custom Video Player example. For instance, there's no use of m.player.paused in the SDK example.



    I can't even run CustomVideoPlayer as an error pops up on the line 'Sub Setup() As Object', I prob have to add something, so I havn't really seen it in action.

    The pause works in that? Did you Pause it through the terminal like the command i've above, if not, can you please and tell me if it works? I don't want to have the stream url used inside the program, I want to be able to send it to the channel remotely, I guess the issue I have it trying to integrate the Pausing/Playing code in CVP into my own app

    Sorry Yeah you're right (sorry Jim), m.player.paused is not in the custom video player but m.paused is, I guess I was just playing around with it trying to get it to work.
  • Here's what I did:

    1. Download customvideoplayer.zip from: https://sourceforge.net/projects/rokusdkexamples/files/customvideoplayer.zip/download
    2. Un-zip customvideoplayer.zip into a new folder, customvideoplayer
    3. Remove the read-only attribute recursively from the new folder, its subfolders, and files (at least on Windows, not sure about other systems, the SDK examples are unzipped by default into a read-only folder, which must be changed in order to edit the contents)
    4. Edit customvideoplayer/source/main.brs
    5. Change the SetContentList statement in Sub Setup() to:
        this.player.SetContentList([{
    REM Stream: { url: "http://ec2-184-72-239-149.compute-1.amazonaws.com:1935/demos/smil:bigbuckbunnyiphone.smil/playlist.m3u8" }
    Stream: { url: "http://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/Manifest" }
    REM StreamFormat: "hls"
    StreamFormat: "ism"
    REM SwitchingStrategy: "full-adaptation"
    }])

    6. Zip and deploy the channel to my Roku
    7. Play/pause successfully using both the Roku remote and the following curl command:
    curl -d '' http://192.168.0.6:8060/keypress/Play

    8. As an added bonus, modified the code to specify the url using ECP
    9. Launched and played the video successfully using the following curl command:
    curl -d '' http://192.168.0.6:8060/launch/dev?url=http%3A%2F%2Fplayready.directtaps.net%2Fsmoothstreaming%2FSSWSS720H264%2FSuperSpeedway_720.ism%2FManifest


    Here's the final version of the code.

    ' ********************************************************************
    ' ********************************************************************
    ' ** Roku Custom Video Player Channel (BrightScript)
    ' **
    ' ** May 2010
    ' ** Copyright (c) 2010 Roku Inc. All Rights Reserved.
    ' ********************************************************************
    ' ********************************************************************

    Sub RunUserInterface(params As Object)
    Print "Launch url: "; params.url
    o = Setup(params.url)
    o.setup()
    o.paint()
    o.eventloop()
    End Sub

    Sub Setup(launchUrl As String) As Object
    this = {
    port: CreateObject("roMessagePort")
    progress: 0 'buffering progress
    position: 0 'playback position (in seconds)
    paused: false 'is the video currently paused?
    fonts: CreateObject("roFontRegistry") 'global font registry
    canvas: CreateObject("roImageCanvas") 'user interface
    player: CreateObject("roVideoPlayer")
    setup: SetupFramedCanvas
    paint: PaintFramedCanvas
    eventloop: EventLoop
    }

    'Static help text:
    this.help = "Press the right or left arrow buttons on the remote control "
    this.help = this.help + "to seek forward or back through the video at "
    this.help = this.help + "approximately one minute intervals. Press down "
    this.help = this.help + "to toggle fullscreen. To exit the sample, press "
    this.help = this.help + "the remote control Home key."

    'Register available fonts:
    this.fonts.Register("pkg:/fonts/caps.otf")
    this.textcolor = "#406040"

    'Setup image canvas:
    this.canvas.SetMessagePort(this.port)
    this.canvas.SetLayer(0, { Color: "#000000" })
    this.canvas.Show()

    'Resolution-specific settings:
    mode = CreateObject("roDeviceInfo").GetDisplayMode()
    if mode = "720p"
    this.layout = {
    full: this.canvas.GetCanvasRect()
    top: { x: 0, y: 0, w:1280, h: 130 }
    left: { x: 249, y: 177, w: 391, h: 291 }
    right: { x: 700, y: 177, w: 350, h: 291 }
    bottom: { x: 249, y: 500, w: 780, h: 300 }
    }
    this.background = "pkg:/images/back-hd.jpg"
    this.headerfont = this.fonts.get("lmroman10 caps", 50, 50, false)
    else
    this.layout = {
    full: this.canvas.GetCanvasRect()
    top: { x: 0, y: 0, w: 720, h: 80 }
    left: { x: 100, y: 100, w: 280, h: 210 }
    right: { x: 400, y: 100, w: 220, h: 210 }
    bottom: { x: 100, y: 340, w: 520, h: 140 }
    }
    this.background = "pkg:/images/back-sd.jpg"
    this.headerfont = this.fonts.get("lmroman10 caps", 30, 50, false)
    end if

    this.player.SetMessagePort(this.port)
    this.player.SetLoop(true)
    this.player.SetPositionNotificationPeriod(1)
    this.player.SetDestinationRect(this.layout.left)
    this.player.SetContentList([{
    REM Stream: { url: "http://ec2-184-72-239-149.compute-1.amazonaws.com:1935/demos/smil:bigbuckbunnyiphone.smil/playlist.m3u8" }
    REM Stream: { url: "http://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/Manifest" }
    Stream: { url: launchUrl }
    REM StreamFormat: "hls"
    StreamFormat: "ism"
    REM SwitchingStrategy: "full-adaptation"
    }])
    this.player.Play()

    return this
    End Sub

    Sub EventLoop()
    while true
    msg = wait(0, m.port)
    if msg <> invalid
    'If this is a startup progress status message, record progress
    'and update the UI accordingly:
    if msg.isStatusMessage() and msg.GetMessage() = "startup progress"
    m.paused = false
    progress% = msg.GetIndex() / 10
    if m.progress <> progress%
    m.progress = progress%
    m.paint()
    end if

    'Playback progress (in seconds):
    else if msg.isPlaybackPosition()
    m.position = msg.GetIndex()
    m.paint()

    else if msg.isRemoteKeyPressed()
    index = msg.GetIndex()
    print "Remote button pressed: " + index.tostr()
    if index = 3 '<DOWN> (toggle fullscreen)
    if m.paint = PaintFullscreenCanvas
    m.setup = SetupFramedCanvas
    m.paint = PaintFramedCanvas
    rect = m.layout.left
    else
    m.setup = SetupFullscreenCanvas
    m.paint = PaintFullscreenCanvas
    rect = { x:0, y:0, w:0, h:0 } 'fullscreen
    m.player.SetDestinationRect(0, 0, 0, 0) 'fullscreen
    end if
    m.setup()
    m.player.SetDestinationRect(rect)
    else if index = 4 or index = 8 '<LEFT> or <REV>
    m.position = m.position - 60
    m.player.Seek(m.position * 1000)
    else if index = 5 or index = 9 '<RIGHT> or <FWD>
    m.position = m.position + 60
    m.player.Seek(m.position * 1000)
    else if index = 13 '<PAUSE/PLAY>
    if m.paused m.player.Resume() else m.player.Pause()
    end if

    else if msg.isPaused()
    m.paused = true
    m.paint()

    else if msg.isResumed()
    m.paused = false
    m.paint()

    end if
    'Output events for debug
    print msg.GetType(); ","; msg.GetIndex(); ": "; msg.GetMessage()
    if msg.GetInfo() <> invalid print msg.GetInfo();
    end if
    end while
    End Sub

    Sub SetupFullscreenCanvas()
    m.canvas.AllowUpdates(false)
    m.paint()
    m.canvas.AllowUpdates(true)
    End Sub

    Sub PaintFullscreenCanvas()
    list = []

    if m.progress < 100
    color = "#000000" 'opaque black
    list.Push({
    Text: "Loading..." + m.progress.tostr() + "%"
    TextAttrs: { font: "huge" }
    TargetRect: m.layout.full
    })
    else if m.paused
    color = "#80000000" 'semi-transparent black
    list.Push({
    Text: "Paused"
    TextAttrs: { font: "huge" }
    TargetRect: m.layout.full
    })
    else
    color = "#00000000" 'fully transparent
    end if

    m.canvas.SetLayer(0, { Color: color, CompositionMode: "Source" })
    m.canvas.SetLayer(1, list)
    End Sub

    Sub SetupFramedCanvas()
    m.canvas.AllowUpdates(false)
    m.canvas.Clear()
    m.canvas.SetLayer(0, [
    { 'Background:
    Url: m.background
    CompositionMode: "Source"
    },
    { 'The title:
    Text: "Custom Video Player"
    TargetRect: m.layout.top
    TextAttrs: { valign: "bottom", font: m.headerfont, color: m.textcolor }
    },
    { 'Help text:
    Text: m.help
    TargetRect: m.layout.right
    TextAttrs: { halign: "left", valign: "top", color: m.textcolor }
    }
    ])
    m.paint()
    m.canvas.AllowUpdates(true)
    End Sub

    Sub PaintFramedCanvas()
    list = []
    if m.progress < 100 'Video is currently buffering
    list.Push({
    Color: "#80000000"
    TargetRect: m.layout.left
    })
    list.Push({
    Text: "Loading..." + m.progress.tostr() + "%"
    TargetRect: m.layout.left
    })
    else 'Video is currently playing
    if m.paused
    list.Push({
    Color: "#80000000"
    TargetRect: m.layout.left
    CompositionMode: "Source"
    })
    list.Push({
    Text: "Paused"
    TargetRect: m.layout.left
    })
    else 'not paused
    list.Push({
    Color: "#00000000"
    TargetRect: m.layout.left
    CompositionMode: "Source"
    })
    end if
    list.Push({
    Text: "Current position: " + m.position.tostr() + " seconds"
    TargetRect: m.layout.bottom
    TextAttrs: { halign: "left", valign: "top", color: m.textcolor }
    })
    end if
    m.canvas.SetLayer(1, list)
    End Sub


    That should get you started.
  • Wow belltown, thanks a lot! That helps so much! Really do appreciate the time you put into modifying that
    I've one question though, that error I had earlier at
    Sub Setup(launchUrl As String) As Object
    still pops up, is that an issue? As I can still upload the channel and it runs fine, seems odd - should it be ignored?


    Syntax error: unexpected token "As", expected one of <INTID>, <FLOATID>, <DOUBLEID>, <STRINGID>, <INTLITERAL>, <HEXLITERAL>, <FLOATLITERAL>, <DOUBLELITERAL>, <STRINGLITERAL>, "True", "False", "Invalid", "(", "Type", "Rnd", "GetGlobalAA", "Box", "Run", "Eval", "GetLastCompileError", "GetLastRuntimeError", "Sleep", "Wait", "CreateObject", "GetInterface", "UpTime", "RebootSystem", "ListDir", "ReadAsciiFile", "WriteAsciiFile", "CopyFile", "MatchFiles", "DeleteFile", "DeleteDirectory", "CreateDirectory", "FormatDrive", "strtoi", "Ucase", "LCase", "Asc", "Chr", "Instr", "Left", "Len", "Mid", "Right", "Str", "Stri", "String", "Stringi", "Val", "Tr", "Abs", "Atn", "Cos", "Csng", "Cdbl", "Exp", "Fix", "Int", "Log", "Sgn", "Sin", "Sqr", "Tan", <ID>, "Component", "Interface", "Event", "Exit", "Print", "?", "Goto", "Return", "Stop", <NEWLINE>, or ":"
  • Interesting. I don't get an error on my Roku for that code, nor for the Roku SDK customvideoplayer example code, and I've never seen that particular error message before. I'm surprised the code still runs with a syntax error like that. Maybe it's something new. Just curious what Roku model number and OS version are you running?

    What I think it's saying though is that a "Sub" cannot have a non-void return type, so change:
    Sub Setup(launchUrl As String) As Object
    to:
    Function Setup(launchUrl As String) As Object
    and change the corresponding:
    End Sub
    statement to:
    End Function
  • Model: 3500X - Roku Stick
    Version: 7.2.0 Build 4100 - 09

    Yeap, no more errors exist now and the channel runs fine, thanks!

    Edit: Was only trying to do Pause/Play but you also gave me ffw and rwd...loving it
  • "Transparent" wrote:
    Model: 3500X - Roku Stick
    Version: 7.2.0 Build 4100 - 09

    Yeap, no more errors exist now and the channel runs fine, thanks!

    Curious. I have a Model 3100X with version 7.2.0 • build 4100-02, and I didn't get the error message when specifying a non-void return value on a Sub declaration. I wonder if Roku changed something in the -03 .. -09 builds.

    Unless.. That was an error you saw in the Roku Debugger on port 8085 right, rather than somewhere else (like Eclipse?)
  • Would be nice if sub can be used in lieu of function because of less typing!

    Now maybe it's important for function to nag if there is no `return` statement (i am ambivalent if it should or not). But there is no good design justification for sub complaining if there is non-void return (besides nit-picking 🙂 - i said "good" reason!). Quick check... no, `function` does non ensure there is `return` (probably futile to try that compile-time), so `sub` may as well be turned to synonym of `function`.
  • "belltown" wrote:
    "Transparent" wrote:
    Model: 3500X - Roku Stick
    Version: 7.2.0 Build 4100 - 09

    Yeap, no more errors exist now and the channel runs fine, thanks!

    Curious. I have a Model 3100X with version 7.2.0 • build 4100-02, and I didn't get the error message when specifying a non-void return value on a Sub declaration. I wonder if Roku changed something in the -03 .. -09 builds.

    Unless.. That was an error you saw in the Roku Debugger on port 8085 right, rather than somewhere else (like Eclipse?)


    I saw the error on Eclipse - version 3.8.1, it says my brightscript plugin is version: BrightScript Core 1.0.0.201407311702. It might be an older one as I think I remember people talking about the new brightscript plugin crashing eclipse so I didnt update anything, atleast I think I remember seeing that