Startup Splash Screens

Starting with the forthcoming 4.3 software release, we will support (and strongly encourage) splash screens for Roku Channels. These splash screens are shown immediately when you channel launches, before any code is executed, so the user gets immediate feedback.

To add the splash screen, add three new lines into your manifest file:

splash_screen_hd=pkg:/images/<hd splash screen image>
splash_screen_sd=pkg:/images/<sd splash screen image>
splash_color=#rrggbb

The images you specify will be centered in the screen over the background color specified by splash_color. An easy way to get going is to simply use your current homescreen icons, so these lines might look like this:

splash_screen_hd=pkg:/images/mm_icon_focus_hd.png
splash_screen_sd=pkg:/images/mm_icon_focus_sd.png
splash_color=#062365

A couple of considerations for creating and using splash screen images:

  • images must be in your channel package, they can’t be remotely hosted.
  • consider using fairly small images to keep your package size down. Larger packages may not fit on some user’s Roku players if they have a large number of channels installed, and if your package is over 750kb, it may be limited to Roku 2 units only.

While this requires version 4.3 or later, earlier software releases will ignore these new items in the manifest and function correctly, though without the splash screen.

Let us know if you have any questions

Posted in Uncategorized | 10 Comments

International Channel Stores

This week, we began shipping Roku 2 XS and Roku LT units in the UK and Republic of Ireland. To support this international launch, we’ve created separate Channel Stores for each region. What was before the only Channel Store is now shown as the US Channel Store on our developer site. We’ve also added UK, Ireland and Rest of World (RoW) Channel Stores. Users will be assigned to the appropriate channel store based on their location at the time of account setup. Developers must to opt-in to each region in which they want their channels available. All channels that were available original Channel Store have been automatically placed in the US Channel Store, so there is nothing you need to do if you want your channel to continue to appear only in the United States. If you wish your channels to be available in additional regions, you’ll need to log into your developer account and submit a new version of the channel that adds the additional regions (Instructions below).

There are some important considerations for making your channel available in the international Channel Stores:

  • Do you have rights to your content for distribution in that region? Many licenses restrict the geographies and delivery methods for the content.
  • Do you have an addressable audience in the region? You will have to pay for delivery of this content, even if it’s not your ideal audience.
  • Are you able to monetize your content in the region?
  • Is your channel geographically aware? Roku doesn’t do any geographic IP filtering except for directing users to the appropriate channel store. If you need to filter your content based on geography, this functionality will need to be added to your channel.
  • Do you have appropriate and sufficient delivery capabilities in the region? Depending on usage, you may need in-region CDNs or datacenters to serve these international users.

While we want the widest selection of content available in each region, we urge developers and publishers to consider carefully the impact to their business when deciding to submit their channels for additional regions. It should be noted that Roku reserves the right to choose which channels it publishes in which regions and may not publish a channel in each region the developer chooses.

How to Make Your Channel Available in other Regions
If your channel is an existing channel, you’ll need to log into your developer account, create a new version (by clicking “Edit Channel”), add your channel package (it can be the same package currently published), then click edit to choose the appropriate channel stores from the drop-down list. Submit the channel update to start the publication process. For categories in the new regions, please choose the most appropriate ones. We will be reviewing and revising channel categorization before launch.

If your channel is a new channel, you’ll pick the Channel Store(s) at the time of channel creation.

Let us know if you have any questions.

Posted in Uncategorized | 2 Comments

Back in the saddle

Apologies for the dearth of recent posts. As you may have heard, we have been pretty busy recently. We will be working on that. To recap recent Roku happenings:

  • We ended 2011 with more than 400 channels published in the Channel Store. This is up from 135 at the beginning of 2011.
  • We announced the forthcoming Streaming Stick just prior to CES. This product, due in the second half of this year, takes all the functionality of the Roku2 and places it in a package the size of a pack of chewing gum. The Streaming Stick will be compatible with all TV’s that implement the new MHL port, which is being added to a number of TV models this year . Our first announced partner is Best Buy’s Insignia brand. The Streaming Stick will automatically turn an MHL-enabled TV into a “Smart TV’”, and the in the future a user can upgrade their TV again just by buying a new Streaming Stick. From a developer standpoint, there should not be anything specific you will need to do to make your channel Streaming Stick compatible; if it runs on Roku2, it should run on the Streaming Stick. For more information, please see our press release.
  • We announced, and are now shipping in  the UK and Ireland. More on that in the next post.
We expect 2012 to be a busy year and look forward to seeing what developers continue to submit to the channel store.
Posted in Uncategorized | 1 Comment

Welcome Joel Braverman

I wanted to take a minute to welcome the newest member of the Roku Developer Program, Joel Braverman.  Joel will be working with developers to help get channels published, provide useful feedback and guidance for best practices and improve our sample code.

Over the past year or so, Joel has been a prolific Roku developer, publishing a number of channels including Abacus.fm, Musiclouds, and ScreenShades.  You’ll also see Joel active on our forums, lending a hand.

 

Welcome Joel.

Posted in Uncategorized | 8 Comments

Using Launch Parameters

Launch parameters are chunks of information that can be sent to your channel by devices using the Roku External Control Protocol (ECP). ECP is a RESTful API that allows other network connected devices to control a Roku. ECP is documented in the Roku SDK.

When a device using ECP launches a channel, it can also send a collection of parameters to that channel. This ability presents endless possibilities to channel developers. In this article, we’ll explore some of the simplest applications of this mechanism.

Hello World!
Launch parameters are passed to your Main() function as a parameter whose value is a roAssociativeArray. The simplest thing we can do with a launch parameter is display its value directly to the user, so let’s write a very simple channel that does exactly that. First, we need to check for the existence of a launch parameter named message. If that parameter exists, we’ll display it to the user.

sub Main(launchParameters)
  ' setup a poster screen and assign it a message port
  port = CreateObject("roMessagePort")
  screen = CreateObject("roPosterScreen")
  screen.SetMessagePort(port)
  screen.Show()
  
  ' set the default message
  message = "No message received"
  ' check to see if a message was passed in
  if launchParameters.message <> invalid
    message = launchParameters.message
  end if
  
  ' display the message
  screen.ShowMessage(message)
  
  while true
    ' wait for an event from our poster screen
    msg = Wait(0, port)
    
    if type(msg) = "roPosterScreenEvent"
      if msg.isScreenClosed()
        exit while
      end if
    end if
  end while
  
  screen.Close()
end sub

If you side-load this channel and launch it from the Roku home screen using the standard remote control, you will see “No message received” displayed on the poster screen. In order to make use of our launch parameter, we need to launch the channel using ECP. You can do this from your PC using curl and replacing the x’s below with the local IP address of your Roku. Note that the command must be sent as an HTTP POST request and the launch parameters must be sent as URL parameters. It’s also important that the parameter values be properly encoded, otherwise the ECP call will fail and the channel will not launch.

curl -d "" "http://xxx.xxx.xxx.xxx:8060/launch/dev?message=Hello%20World%21"

If this command succeeds, your side-loaded channel will launch and “Hello World!” will be displayed on your poster screen. Try it with some other values for the message parameter.

Play a Video
Displaying a message is a simple way of demonstrating how launch parameters work, but it isn’t especially useful. Suppose we wanted to pass the URL of a piece of content into a channel and have the channel play that content. The first thing we would need is a simple channel that could accept a launch parameter whose value was a URL and use that URL to build a content-meta-data structure that could then be fed into a roVideoScreen. That might look something like this.

sub Main(launchParameters)
  ' don't do anything unless we got a url
  if launchParameters.url <> invalid
    ' setup a poster screen and assign it a message port
    port = CreateObject("roMessagePort")
    screen = CreateObject("roVideoScreen")
    screen.SetMessagePort(port)

    ' build a content-meta-data using the passed in URL   
    screen.SetContent({
      stream: { url: launchParameters.url }
    })

    ' play the video
    screen.Show()
    
    while true
      ' wait for an event from our video screen
      msg = Wait(0, port)
      
      if type(msg) = "roVideoScreenEvent"
        if msg.isScreenClosed()
          exit while
        end if
      end if
    end while
    
    screen.Close()
  end if
end sub

Once you side-load this channel, you can launch it using ECP the same way we did our first channel, but this time you would need to send it a parameter called url whose value is the URL to a compatible mp4 video. You could do that with a command similar to this. Again, notice that the launch parameter must be properly URL encoded for the command to succeed.

curl -d "" "http://xxx.xxx.xxx.xxx:8060/launch/dev?url=http%3A%2F%2Fvideo.ted.com%2Ftalks%2Fpodcast%2FDavidBrooks_2011.mp4"

If the command succeeds, your side-loaded channel will launch and begin playing the video referenced by the URL.

Using this simple channel as a starting point, you could add support for additional video and audio content by adding a second launch parameter to specify the type of content that the URL refers to. Or, instead of a single video, you could pass in the URL of an MRSS feed and display all the content contained in that feed.

And if you’re working with a content provider’s API, you can use launch parameters to pass in search terms or content identifiers, or other data that can be used in conjunction with that particular API to get the user to compelling content quickly.

Posted in Uncategorized | 2 Comments

Logging Into an Online Account

In a previous post, we learned how to associate a channel with an online service using rendezvous style linking. In this post, we’ll associate a channel with an online service by logging in directly with a username and password. Any time you send sensitive information over the internet, it’s important to make sure that information is secure. Be sure you take the necessary precautions to protect your users’ data.

We’re going to ask the user to enter two chunks of information, a username and a password. We will be using the roKeyboardScreen component for both of these tasks, so the first thing we need is a reusable function that presents a roKeyboardScreen and returns whatever string the user types into it.

function ShowKeyboardScreen(prompt = "", secure = false)
  result = ""

  ' create a roKeyboardScreen and assign a message port to it
  port = CreateObject("roMessagePort")
  screen = CreateObject("roKeyboardScreen")
  screen.SetMessagePort(port)

  ' display a short string telling the user what they need to enter
  screen.SetDisplayText(prompt)

  ' add some buttons
  screen.AddButton(1, "Okay")
  screen.AddButton(2, "Cancel")

  ' if secure is true, the typed text will be obscured on the screen
  ' this is useful when the user is entering a password
  screen.SetSecureText(secure)

  ' display our keyboard screen
  screen.Show()

  while true
    ' wait for an event from the screen
    msg = wait(0, port)

    if type(msg) = "roKeyboardScreenEvent" then
      if msg.isScreenClosed() then
        exit while
      else if msg.isButtonPressed()
        if msg.GetIndex() = 1
          ' the user pressed the Okay button
          ' close the screen and return the text they entered
          result = screen.GetText()
          exit while
        else if msg.GetIndex() = 2
          ' the user pressed the Cancel button
          ' close the screen and return an empty string
          result = ""
          exit while
        end if
      end if
    end if
  end while

  screen.Close()
  return result
end function

Now we can use our keyboard screen to solicit information from the user. Notice that the second call to ShowKeyboardScreen() has two arguments. Passing a true value as the second argument will cause the text to be obscured on the screen as the user is typing their password.

username = ShowKeyboardScreen("Enter your username")
if username <> ""
  ' only prompt the user for a password if they entered a username
  password = ShowKeyboardScreen("Enter your username", true)
end if

Once you have the user’s credentials, it is safe to store them in the device registry because all data stored in the registry is encrypted, Access to registry data is tied to the developer key used to package your channel, so make sure future updates to your channel are packaged with the same key. Otherwise your channel will lose access to any data stored in the registry and your users will have to go through the login process again. It is also important to protect the key and its associated password appropriately.

Now you can use the credentials to make an API call to your cloud service and authenticate the channel to the user’s account. Because we’re sending sensitive data, we’ll use SSL to encrypt the data when making the transfer. For purposes of this example, we’ll assume that the API will return a chunk of XML containing a token that should be used when making subsequent API calls.

if username <> "" and password <> ""
  ' the user entered both a username and a password
  ' store them in the registry for logging in during future sessions
  sec = CreateObject("roRegistrySection", "mySection")
  sec.Write("username", username)
  sec.Write("password", password)
  sec.Flush()

  ' and now let's try logging in
  xfer = CreateObject("roURLTransfer")
  ' setup the transfer for SSL
  xfer.SetCertificatesFile("common:/certs/ca-bundle.crt")
  xfer.InitClientCertificates()
  xfer.SetURL("https://api.example.com/login?username=" + xfer.Escape(username) + "&password=" + xfer.Escape(password))
  response = xfer.GetToString()

  ' parse the response and extract the apiToken
  xml = CreateObject("roXMLElement")
  if xml.Parse(response)
    apiToken = xml.token.GetText()
  end if
end if

Once the channel is associated with the user’s account, you can give them a personalized experience within your channel.

Posted in sdk | 5 Comments

Linking a Channel to an Online Account

There are several different ways of associating a channel with an online account. In this tutorial, we will explore rendezvous style registration where a channel presents a code to the user and asks them to go to a computer and enter that code into a web site to complete the registration process. This linking method is documented in the Device Registration and Linking document in the Roku SDK.

Rendezvous style registration has the benefit of not requiring the user to type information directly into the channel using an on-screen keyboard. The downside is that the user may have to move to a different room to access the website and enter the code. In a future tutorial, we will look at the method where the user directly enters their username and password into the channel.

The first step in a rendezvous style registration is for the channel to request a linking code from your API. When your API receives that request, it should generate a new linking code and store it along with an expiration timestamp that is some reasonable amount of time in the future. Linking codes should be unique enough that no other device will be assigned the same code before the code has expired.

In the simplest case, the API can respond with the newly generated linking code and a timestamp indicating when the code expires. The API response to this request might look like this:

<apiResponse>
  <linkingCode expires="1310598793">ABC123</linkingCode>
</apiResponse>

To make the API request in BrighScript and extract the linking code, your channel would have a function similar to this one:

function GetLinkingCode()
  result = invalid

  xfer = CreateObject("roURLTransfer")
  xfer.SetURL("http://api.example.com/getLinkingCode")
  response = xfer.GetToString()
  xml = CreateObject("roXMLElement")
  if xml.Parse(response)
    result = {
      code: xml.linkingCode.GetText()
      expires: StrToI(xml.linkingCode@expires)
    }
  end if

  return result
end function

When the user validates their linking code, the API should generate a unique token for the device and store that token along with its association to the user’s account. This token will be stored by the channel in the Roku’s registry and used to identify the device to the API during future sessions.

While the registration screen is visible, the channel should periodically poll the API to find out whether the user has validated their linking code and to retrieve the associated token. A successful API response to this request might look like this:

<apiResponse>
  <status>success</status>
  <deviceToken>3F2504E0-4F89-11D3-9A0C-0305E82C3301</deviceToken>
</apiResponse>

The API may also respond to the polling request with a failure status if the user has not yet validated the linking code or the linking code has expired or some other error occurs. That response might look like this:

<apiResponse>
  <status>failure</status>
</apiResponse>

To make this API request in BrightScript and process the result, your channel might implement a function similar to the following. This function will poll the API to check whether the linking code has been validated. If the code has been validated, it saves the associated token in the registry for future use. The function returns a boolean value indicating whether the linking code has been validated.

function ValidateLinkingCode(linkingCode)
  result = false

  xfer = CreateObject("roURLTransfer")
  xfer.SetURL("http://api.example.com/validateLinkingCode?code=" + linkingCode)
  response = xfer.GetToString()
  xml = CreateObject("roXMLElement")
  if xml.Parse(response)
    if UCase(xml.status.GetText()) = "SUCCESS"
      sec = CreateObject("roRegistrySection", "mySection")      
      sec.Write("deviceToken", xml.deviceToken.GetText())
      sec.Flush()

      result = true
    end if
  end if

  return result
end function

With these two functions, you are ready to build your channel’s rendezvous linking experience. This chunk of BrightScript will get a linking code from the API, display it on a roCodeRegistrationScreen, and then start polling the API waiting for the linking code to be validated. Once the code has been validated, the screen will close.

sub ShowLinkScreen()
  dt = CreateObject("roDateTime")

  ' create a roCodeRegistrationScreen and assign it a roMessagePort
  port = CreateObject("roMessagePort")
  screen = CreateObject("roCodeRegistrationScreen")
  screen.SetMessagePort(port)

  ' add some header text
  screen.AddHeaderText("Link Your Account")
  ' add some buttons
  screen.AddButton(1, "Get new code")
  screen.AddButton(2, "Back")
  ' Add a short narrative explaining what this screen is
  screen.AddParagraph("Before you can use this channel, you must link the channel to your account.")
  ' Focal text should give specific instructions to the user
  screen.AddFocalText("Go to http://www.example.com/roku, log into your account, and enter the following code.", "spacing-normal")

  ' display a retrieving message until we get a linking code
  screen.SetRegistrationCode("Retrieving...")
  screen.Show()

  ' get a new code
  linkingCode = GetLinkingCode()
  if linkingCode <> invalid
    screen.SetRegistrationCode(linkingCode.code)
  else
    screen.SetRegistrationCode("Failed to get code...")
  end if
 
  screen.Show()

  while true
    ' we want to poll the API every 15 seconds for validation,
    ' so set a 15000 millisecond timeout on the Wait()
    msg = Wait(15000, screen.GetMessagePort())
   
    if msg = invalid
      ' poll the API for validation
      if ValidateLinkingCode(linkingCode.code)
        ' if validation succeeded, close the screen
        exit while
      end if

      dt.Mark()
      if dt.AsSeconds() > linkingCode.expires
        ' the code expired. display a message, then get a new one
        d = CreateObject("roMessageDialog")
        dPort = CreateObject("roMessagePort")
        d.SetMessagePort(dPort)
        d.SetTitle("Code Expired")
        d.SetText("This code has expired. Press OK to get a new one")
        d.AddButton(1, "OK")
        d.Show()

        Wait(0, dPort)
        d.Close()
        screen.SetRegistrationCode("Retrieving...")
        screen.Show()

        linkingCode = GetLinkingCode()
        if linkingCode <> invalid
          screen.SetRegistrationCode(linkingCode.code)
        else
          screen.SetRegistrationCode("Failed to get code...")
        end if
        screen.Show()
      end if
    else if type(msg) = "roCodeRegistrationScreenEvent"
      if msg.isScreenClosed()
        exit while
      else if msg.isButtonPressed()
        if msg.GetIndex() = 1
          ' the user wants a new code
          code = GetLinkingCode()
          linkingCode = GetLinkingCode()
          if linkingCode <> invalid
            screen.SetRegistrationCode(linkingCode.code)
          else
            screen.SetRegistrationCode("Failed to get code...")
          end if
          screen.Show()
        else if msg.GetIndex() = 2
          ' the user wants to close the screen
          exit while
        end if
      end if
    end if
  end while
 
  screen.Close()
end sub

Once the channel is successfully linked with your API, the device token will be stored in the Roku’s registry. By including the device token in subsequent API requests, your API will be able to associate the channel with the user’s account and provide the channel with appropriate data.

Posted in sdk | 8 Comments

Adding Preroll Video to Your Channel

In this tutorial, we are going to develop a chunk of BrightScript code that can be used to display preroll ads in a Roku channel. To do this, we will use roVideoScreen, roVideoPlayer, and roImageCanvas, all of which are documented in the Component Reference document in the Roku SDK

The goal of adding preroll video to a channel can be broken down into two tasks. First, we need to play two pieces of video content back to back as a single video experience. Second, we need to disable trick-play during the first of those two pieces of content so the user is not able to skip the preroll and jump directly to the main content. The main content should have a traditional trick-play experience consistent with most other channels.

First, let’s define the two pieces of content by building a content-meta-data structure for each of them. A content-meta-data is just a roAssociativeArray with some specific attributes used to represent a given piece of content. The only thing we need to know about the preroll video is the format it’s in and the URL to the asset, so its content-meta-data will be a lot more sparse than the main content’s. In most projects this would be done by making an API call to your cloud service and parsing the result, but for demonstration purposes, we’ll just hardcode it:

preroll = {
    streamFormat: "mp4"
    stream: {
      url:  "http://www.archive.org/download/kelloggs_variety_pak/kelloggs_variety_pak_512kb.mp4"
    }
  }

content ={
    title:        "TEDTalks : David Brooks: The social animal"
    sdPosterURL:  "http://images.ted.com/images/ted/78e8d94d1d2a81cd182e0626dc8e96a43c88d760_132x99.jpg"
    hdPosterURL:  "http://images.ted.com/images/ted/78e8d94d1d2a81cd182e0626dc8e96a43c88d760_132x99.jpg"
    description:  "Tapping into the findings of his latest book, NYTimes columnist David Brooks unpacks new insights into human nature from the cognitive sciences -- insights with massive implications for economics and politics as well as our own self-knowledge. In a talk full of humor, he shows how you can't hope to understand humans as separate individuals making choices based on their conscious awareness."
    contentType:  "episode"
    streamFormat: "mp4"
    stream: {
      url:  "http://video.ted.com/talks/podcast/DavidBrooks_2011.mp4"
    }
  }

Now we need to play these two pieces of content back to back. Here is a very simple subroutine that uses roVideoScreen to play a video. If you have been experimenting with the sample code in the Roku SDK, you have probably seen subroutines similar to this.

sub ShowVideoScreen(video)
  port = CreateObject("roMessagePort")
  screen = CreateObject("roVideoScreen")
  screen.SetMessagePort(port)
  screen.SetContent(video)

  screen.Show()

  while true
    msg = wait(0, port)

    if type(msg) = "roVideoScreenEvent"
      if msg.isScreenClosed()
        exit while
      end if
    end if
  end while

  screen.Close()
end sub

Given this subroutine, you might be tempted to do something like this:

ShowVideoScreen(preroll)
ShowVideoScreen(content)

That will work. The preroll video will play and then the content video will play, but there are a few problems.

  • Trick play will not be disabled during the preroll
  • There may be a moment between the time when the preroll stops playing and when the content starts playing that the previous UI screen becomes visible for a fraction of a second
  • If the user exits playback during the preroll, the main content will begin playing immediately. The desired behavior would be for the video experience to end and the previous UI screen to become visible

To prevent the underlying UI from flickering into view between videos, we can simply display a blank roImageCanvas before playing the videos. During that moment after the first video ends and before the second video starts, the previous screen will still become visible for a moment, but it will be a blank screen, which makes for a more seamless transition between videos and a more pleasant experience for your users.

The other two problems can be solved by using the roVideoPlayer component to play the preroll content. roVideoPlayer is a much more manual video playback mechanism than roVideoScreen. By default, it has no trick play modes and no buffer screen. These features must be added manually in BrightScript. The lack of trick play is exactly what we want, but we will have to draw our own buffer screen and handle any up or back remote key presses manually. We will do all this by building a new function for playing preroll content. This function should not only play a piece of content with trick play disabled, it should also return a value that indicates whether or not the user terminated playback by pressing up or back. We will use this return value to decide whether we should play the main content or return the user to the previous UI screen.

function ShowPreRoll(video)
  ' a true result indicates that playback finished without user intervention
  ' a false result indicates that the user pressed UP or BACK to terminate playback
  result = true
  canvas = CreateObject("roImageCanvas")
  player = CreateObject("roVideoPlayer")
  port = CreateObject("roMessagePort")

  canvas.SetMessagePort(port)
  ' build a very simple buffer screen for our preroll video
  canvas.SetLayer(0, { text: "Your program will begin after this message" })
  canvas.Show()

  ' be sure to use the same message port for both the canvas and the player
  ' so we can receive events from both
  player.SetMessagePort(port)
  player.SetDestinationRect(canvas.GetCanvasRect())
  player.AddContent(video)

  player.Play()

  ' start our event loop
  while true
    ' wait for an event
    msg = wait(0, canvas.GetMessagePort())

    if type(msg) = "roVideoPlayerEvent"
      if msg.isFullResult()
        ' the video played to the end without user intervention
        exit while
      else if isRequestFailed()
        ' something went wrong with playback, but the user did not intervene
        exit while
      else if msg.isStatusMessage()
        if msg.GetMessage() = "start of play"
          ' once the video starts, clear out the canvas so it doesn't cover the video
          canvas.SetLayer(0, { color: "#00000000", CompositionMode: "Source" })
          canvas.Show()
        end if
      end if
    else if type(msg) = "roImageCanvasEvent"
      if msg.isRemoteKeyPressed()
        index = msg.GetIndex()
        if index = 0 or index = 2
          ' the user pressed UP or BACK to terminate playback
          result = false
          exit while
        end if
      end if
    end if
  end while

  player.Stop()
  canvas.Close()

  return result
end function

Now we have all the pieces necessary to build our video experience. Here’s how it all comes together:

' create and display a blank roImageCanvas to prevent the
' underlying UI from flickering between videos
canvas = CreateObject("roImageCanvas")
canvas.SetLayer(0, "#000000")
canvas.Show()

' play the preroll video with trick play disabled
if ShowPreroll(preroll)
  ' only play the main content if the preroll completed without user intervention
  ShowVideoScreen(content)
end if

' close the blank canvas and return the user to the previous UI screen
canvas.Close()
Posted in Uncategorized | 8 Comments

Games! On Roku!

We’re excited to announce that Angry Birds will be coming to Roku later this summer.  We believe that the TV will become a huge market for casual gaming and as Anthony Wood, Roku’s founder and CEO said, “just as we were the first to enable Netflix to stream instantly to the TV, we intend to be the catalyst for transforming the way people play casual games on the biggest screen in the home.”

While we can’t yet share all the details of our upcoming products and future SDK releases, we are ready to discuss how you can get started with casual gaming on Roku today.

The upcoming release of the 3.0 software will add significantly to the capabilities of the Roku player’s support for game development  by incorporating BrightScript’s new 2D graphics functionality.  The 2D graphics functionality provides advanced animation and compositing with optimum performance on Roku hardware.  While it was designed primarily for games, it can also be used to create new and unique interfaces and video channels.  While games like Angry Birds will require additional SDK features, games written with the 3.0 SDK will work on all current hardware as well as future products.

The 3.0 SDK is just the first step in our efforts to bring casual gaming to Roku.  If you would like to discuss building games or other applications for current or future Roku product please email us at partners@roku.com.

-Patrick

 

Posted in Uncategorized | 4 Comments

Hello World!

One of the goals of this blog is to help developers who are new to BrightScript grasp the syntax and concepts of the language. To that end, today we present the most iconic of beginner programming projects, Hello World! We are actually going to write Hello World! three different ways and, in doing so, introduce you to three BrightScript components you can use in your own channels.

All BrightScript components are documented in the Component Reference document found in the Roku SDK. The SDK can be downloaded from our developer site. Developers new to the Roku platform will also want to read the Developer Guide and the Channel Packaging and Publishing documents. These documents explain how to put your Roku into development mode and how to side-load your channel for testing.

Variation 1 – roPosterScreen
At some point while using Roku, you’ve probably seen a blank screen that says “retreiving…” in the center. More often than not, when you see that message, you are looking at a roPosterScreen. An empty roPosterScreen will display that message by default, but you can change the text of that message programatically. Our first Hello World! uses roPosterScreen’s ShowMessage() function to change the message text on an empty roPosterScreen. Here’s how it’s done:

sub Main()
  ' create our screen
  screen = CreateObject("roPosterScreen") 

  ' setup a message port so we can receive event information
  port = CreateObject("roMessagePort")
  screen.SetMessagePort(port)

  ' change the screen's message text
  screen.ShowMessage("Hello World!")
  screen.Show()

  ' start our event loop
  while true
    msg = Wait(0, port) ' wait for an event

    if type(msg) = "roPosterScreenEvent"
      ' we got a poster screen event
      if msg.isScreenClosed()
        ' the user closed the screen
        exit while
      end if
    end if
  end while

  screen.Close()
  ' any time all screens in a channel are closed, the channel will exit
end sub

Variation 2 – roOneLineDialog
roOneLineDialog is an SDK component that displays a dialog with a single line of text and an optional busy animation. Typically, you would use roOneLineDialog to inform the user that your channel is busy performing some task and they should wait for that task to complete before continuing. Here’s Hello World! complete with busy animation:

sub Main()
  ' create and display a roPosterScreen as a backdrop
  screen = CreateObject("roPosterScreen")
  port = CreateObject("roMessagePort")
  screen.SetMessagePort(port)
  screen.Show()

  ' create our roOneLineDialog
  dialog = CreateObject("roOneLineDialog")

  ' set the text of the dialog
  dialog.SetTitle("Hello World!")
  dialog.ShowBusyAnimation()

  ' display the dialog
  dialog.Show()
  ' pretend we're doing something important
  Sleep(10000)
  ' close the dialog
  dialog.Close()

  ' event loop for our roPosterScreen
  while true
    msg = wait(0, port) ' wait for an event

    ' make sure the message we got is of the type we are expecting
    if type(msg) = "roPosterScreenEvent"
      if msg.isScreenClosed()
        ' the user closed the screen, exit the while loop
        exit while
      end if
    end if
  end while

  screen.Close()
  ' anytime all screens within a channel are closed, the channel will exit
end sub

Variation 3 – roMessageDialog
roMessageDialog displays a message to the user and can also solicit feedback from them via a collection of buttons. Our final Hello World! will use a roMessageDialog with two buttons to solicit input from the user and then use a roPosterScreen and its ShowMessage() function to confirm to the user that we received that input:

sub Main()
  ' create and display a roPosterScreen as a backdrop
  screen = CreateObject("roPosterScreen")
  port = CreateObject("roMessagePort")
  screen.SetMessagePort(port)
  screen.Show()

  ' create our roMessageDialog
  dialog = CreateObject("roMessageDialog")
  ' give the dialog the same message port as the poster screen so we can get events from both
  dialog.SetMessagePort(port)

  ' set the text of the dialog
  dialog.SetTitle("Hello World!")
  ' add some buttons
  ' assign them different indexes so we can tell them apart
  ' when we handle their respective isButtonPressed() events
  dialog.AddButton(1, "Hello!")
  dialog.AddButton(2, "Goodbye!")
  dialog.SetMenuTopLeft(true)

  ' display the dialog
  dialog.Show()

  ' event loop
  while true
    msg = wait(0, port) ' wait for an event

    ' make sure the message we got is of the type we are expecting
    if type(msg) = "roMessageDialogEvent"
      if msg.isButtonPressed()
        ' the user pressed a button on the roMessageDialog
        ' the index of the button assigned in the AddButton() function
        ' will correspond to the value returned by the event's GetIndex() function
        buttonIndex = msg.GetIndex()

        if buttonIndex = 1
          ' the user pressed the "Hello!" button
          screen.ShowMessage("You pressed Hello!")
        else
          ' the user pressed the "Goodbye!" button
          screen.ShowMessage("You pressed Goodbye!")
        end if
        dialog.Close()
      end if
    else if type(msg) = "roPosterScreenEvent"
      if msg.isScreenClosed()
        ' the user closed the screen, exit the while loop
        exit while
      end if
    end if
  end while

  screen.Close()
  ' anytime all screens within a channel are closed, the channel will exit
end sub

There you have it. Three different implementations of Hello World! using three different SDK components that you can use in your own channels.

Posted in sdk | 5 Comments