Roku SDK Documentation : Implementing transport controls

Table of Contents


Transport controls enable your channel to handle voice commands from the Roku voice remote, Roku mobile app, or a virtual assistant such as Amazon Alexa or Google Assistant. With transport controls, your channel can respond to voice commands such as "fast forward", "rewind", "pause", "resume", "start over", "replay", and so on. This makes it easy for your customers to control the playback of your content with the convenience of voice commands, which enhances the overall user experience of your channel. 

After September 30, 2019, implementing transport controls is required for channels that have streamed more than an average of 10 million hours over the last three months.

Handling transport commands

To handle voice commands in your channel, your application needs to use the roInput object to listen for transport events and process them. To do this, follow these steps:

  1. Create an roInput object, and set the roMessagePort for receiving events.

    input = CreateObject("roInput")
    port = CreateObject("roMessagePort")
    input.SetMessagePort(port)
  2. Register the roInput component for transport events by calling its EnableTransportEvents() function. This tells the firmware that your channel can handle transport events sent to the roInput object. Once this is set, your channel will receive roInput events for every transport command on this roInput object.

    input.EnableTransportEvents()
  3. Use a message loop to listen for the transport events. In the message loop, do the following:

    1. Use the roInputEvent.GetInfo() method to check for transport commands sent to your channel. This method returns an AssociativeArray with the following fields: typeid, command. You can use the type key to verify that the event received is a transport event, and the command key to identify the specific transport event ("play", "pause", "stop", "forward", "next", "rewind", "replay", "seek", and "startover"). 

      For the "seek" command, the AssociativeArray will contain two additional fields: direction and duration. The direction field indicates whether the seek command is for skipping "forward" or "backward"; the duration field specifies how many seconds to skip forward or backward. 

      Seek functionality can also be implemented via trickplay using the Video.seek field. In this case, the channel must implement the Roku Advertising Framework (or not include ads). The seek transport control attribute must also be enabled in the Roku channel manifest (supports_etc_seek=1).

    2. Call the roInput.EventResponse() method to indicate that you have handled the transport command. This method takes an AssociativeArray with two fields: id and status. The id field specifies the transport ID event; the status specifies whether the event was handled, handled with an error, or unhandled.  This method should be called immediately after a transport event is received. If your application does not handle a transport event within 5 seconds, the Roku firmware will consider the event to be unhandled and then handle it.

    3. Optionally, for better modularization, you can pass the captured transport command to a function for handing.

    while m.playing
     
    msg = wait(0, port)
    if (type(msg) = "roInputEvent") then
        info = msg.GetInfo()
        if (info.type <> invalid and info.type = "transport") then
            eventStatus = "unhandled"
            videoPlayerScreen = m.top.getScene().findNode("VideoPlayerScreen")
            if (videoPlayerScreen <> invalid) then
                eventStatus = videoPlayerScreen.callFunc("handleTransport", info)
            end if
            input.EventResponse({id : info.id, status: eventStatus})
        end if
    end if
  4. Add business logic for handling each transport command. In this example, a function is used to receive the transport command and implement the required behavior. 

    function handleTransport(evt)
    	cmd = evt.command
    	ret = "success"
    	if cmd = "play"
    		'handle "play" command
    	else if cmd = "pause"
    		'handle "play" command
    	else if cmd = "stop"
    		'handle "pause" command
    	else if cmd = "forward"
    		'handle "forward" command
    	else if cmd = "rewind"
    		'handle "rewind" command
    	else if cmd = "replay"
    		'handle "replay" command
    	else if cmd = "seek"
    		duration = evt.duration.ToInt()
    		seekPosition = m.videoplayer.position
    		if (evt.direction = "backward") then
    			seekPosition = m.videoplayer.position - duration
    		else
        		seekPosition = m.videoplayer.position + duration
    	endif
    	if (seekPosition > m.videoplayer.duration) then
    		ret = "success.seek-end"
    		m.seekPosition = m.videoplayer.duration - 30
    	else if (seekPosition < 0) then
    		ret = "success.seek-start"
    		m.seekPosition = 0
    	else
        	m.seekPosition = seekPosition
    	endif
    	m.seekPosition = seekPosition
    	playVideoFrom()
    	else
        	ret = "unhandled"
    	endif
    return ret
    endfunction

    If your channel supports the "seek" or "next" command, you must add an attribute for the command to the Roku channel manifest:

    supports_etc_seek=1
    supports_etc_next=1

Using ECP commands for testing transport controls

You can test transport controls in a channel by sending External Control Protocol (ECP) commands via cURL to your Roku deviceSpecifically, send an HTTP POST request to port 8060 on your Roku device using the following syntax: 

http://<roku-device-ip-address>:8060/input/<channelId>?id=<longInteger>type="transport"&command=<commandValue>
Parameter
Description
Example
inputUse the input command for passing transport events. 
channelId

Enter one of the following:

  • dev. Sideloaded channel.
  • <id>. Public or non-certified channels. To find your channel ID, use the preview page on the Developer Dashboard.

To get a list of all the installed channels and their channel IDs on your Roku device, you can enter http://<roku-device-ip-address>:8060/query/apps in a web browser. An XML file with all the channel (app) IDs on the device is generated.

dev
idAssign a unique ID (as a LongInteger) to the transport event.5
typeEnter "transport" to specify that you are sending a transport event."transport"
command

Enter the type of transport event: "play", "pause", "stop", "forward", "next", "rewind", "replay", "seek", and "startover".

If you are sending a "seek" command, you must also pass two additional fields: direction and seconds.

"forward"
directionFor the "seek" command only. Enter "forward" or "backward"."backward"
durationFor the "seek" command only. Enter how many seconds to skip forward or backward. "10"

The following examples show how to send ECP commands via cURL HTTP POST requests. The examples are based on a side-loaded channel handling forward and seek commands. 

 

curl -d '' 'http://192.168.1.114:8060/input/dev?id=5&type=transport&command=forward'
curl -d '' 'http://192.168.1.114:8060/input/dev?id=8&type=transport&command=seek&direction=backward&duration=10'

 

Transport command reference

The following table summarizes the different transport commands, how they may be invoked, and their expected behavior: 

Transport CommandVoice Command ExamplesResult
transport.play"play"
"play media"
"resume" (if paused)
Media is played.
transport.pause"pause"
"stop"
Media is paused.
transport.replay

"replay"
"instant replay"
"go back a bit"

Media rewind 10 to 25 seconds (actual rewind time depends on your application's implementation of Roku instant replay feature).
transport.startover

"start over"
"go to beginning"

Media starts from the beginning
transport.rewind"rewind"
"start rewinding"
"can you rewind?"
Media rewinds until another command is received and processed. Additional rewind commands speed up the rewinding, if possible.
transport.forward

"fast forward"
"forward"
"start forwarding"
"can you forward?"
"can you fast forward?"

Media fast forwards until another command is received and processed. Additional fast forward commands speed up the rewinding, if possible.

transport.seek

Forwards
"Forward 10 minutes"
"Fast forward half an hour"
"Skip 30 seconds"
"Go forward 1 minute"

Media skips forwards by the specified time.

Backwards
"Rewind 10 minutes"
"Go back 30 minutes"
"Go backward 15 seconds"
Media skips backward by the specified time.
transport.next"next"The next video clip is played.