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:
Create an roInput object, and set the roMessagePort for receiving events.
input = CreateObject("roInput") port = CreateObject("roMessagePort") input.SetMessagePort(port)
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()
Use a message loop to listen for the transport events. In the message loop, do the following:
Use the roInputEvent.GetInfo() method to check for transport commands sent to your channel. This method returns an AssociativeArray with the following fields: type, id, 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).
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.
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
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 device. Specifically, 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 |
---|---|---|
input | Use the input command for passing transport events. | |
channelId | Enter one of the following:
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 |
id | Assign a unique ID (as a LongInteger) to the transport event. | 5 |
type | Enter "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" |
direction | For the "seek" command only. Enter "forward" or "backward". | "backward" |
duration | For 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 Command | Voice Command Examples | Result |
---|---|---|
transport.play | "play" "play media" "resume" (if paused) | Media is played. |
transport.pause | "pause" "stop" | Media is paused. |
transport.replay | "replay" | Media rewind 10 to 25 seconds (actual rewind time depends on your application's implementation of Roku instant replay feature). |
transport.startover | "start over" | 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" | Media fast forwards until another command is received and processed. Additional fast forward commands speed up the rewinding, if possible. |
transport.seek | Forwards | 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. |