Thursday, December 20, 2007

Introduction to Digital TV Applications Programming









Articles Index | Java TV Articles Index | Wireless Initiative


TV As television viewers become more sophisticated, the demands for more interactive technology will increase. To meet this demand, Sun is releasing the Java TV API. Java TV applications enhance the broadcast and viewing experience by providing such features as programming information and announcements, selectable applications such as the ability to play along with a game show, broadcast data such as a stock ticker banner running across the screen, or media control such as an interactive program-related survey.

Television viewers with Java-enabled digital television receivers will be able to receive and interact with Java TV applications while watching network programming. The tool for interacting with Java TV applications is the viewer's television remote.

The newly released Java TV reference implementation implements of the Java TV specification that includes the Java TV and Java Media Framework (JMF) APIs. It requires a PersonalJava virtual machine and class libraries to run. The source base is currently available to licensed digital receiver manufacturers (Java TV licensees) so Java-enabled digital receivers should be available to consumers soon. Developers working for licensed companies that specialize in creating digital TV content will use the Java TV API to write digital television applications that either reside on or are downloaded to Java-enabled digital TV receivers.

The Java TV API will be available to the public at a later date through Sun's Community Source Licensing program. At that time, developers who work for television networks can use the Java TV API to write digital television applications that accompany network program broadcasts. While there are a wide variety of digital television receivers with varying capabilities, the Java TV API lets developers access their common features and scales across different receiver implementations.

This article introduces the Java TV API and presents short examples to show the structure of a Java TV application. However, unless you have access to a Java TV compliant environment, you cannot run and test the examples.

Xlets

Another name for Java TV applications is Xlets. Like applets, Xlets are controlled by the software that runs them. In the case of an applet, the underlying software is a browser or the appletviewer tool. In the case of an Xlet, the underlying software is the digital television receiver or set-top box that supports the Java TV platform.

There is no main method and Xlets always implement the Xlet interface. Like applets, Xlets have a life cycle, and the life cycle method signatures are defined by the Xlet interface.

Life Cycle

The Xlet interface provides life cycle methods to signal the following Xlet state changes:

  • Create
  • Initialize
  • Start
  • Pause
  • Destroy

All Java TV implementations have an application manager that calls the life cycle methods to move one or more Xlets through their various application states. For example, the viewer might be playing a game along with a game show and decide to check program listings. If the program listings and game are both Xlets, the software in the receiver is signaled that an Xlet is present when the viewer selects the program listings. At this point, the application manager pauses the game Xlet, and the receiver downloads the program listings Xlet into the receiver. The application manager loads and starts the program listing Xlet. If the viewer goes back to the game, the application manager pauses the program listing Xlet and starts the game Xlet.

The Xlet interface provides no implementations for its life cycle methods. The developer provides application-specific implementations for those methods by defining what happens at each point in the Xlet life cycle. For example, the initXlet method for the game Xlet might create the user interface components.

An Xlet can initiate some state changes itself and inform the application manager of those state changes by invoking methods on the XletContext interface. An XletContext object is passed to an Xlet when the Xlet is initialized to give the Xlet a way to retrieve properties and signal internal state changes.

Packages

The Java TV API reference implementation requires the PersonalJava Application Environment, Version 3.1, which provides core Java capabilities including the Abstract Window Toolkit (AWT) for building user interfaces. Some core Java packages are included in the PersonalJava platform without change from Java 2 Standard Edition, while others have been subsetted by removing functionality not appropriate for consumer products.

The Java TV API consists of classes and interfaces grouped into the following packages. These packages contain classes and interfaces to process the video, audio, and data sent to the digital receiver through the broadcast stream sent by the television networks. The digital receiver gets video, audio, and data from the broadcast stream and processes it through a broadcast media and data pipeline.

  • javax.tv.carousel provides access to remote file and directory data contained in the broadcast.
  • javax.tv.graphics enables simple compositing (imposing one image over another to create one image) and provides a container for building a user interfaced with AWT components.
  • javax.tv.locator provides access to data and resources addressable within a television receiver. Locators can reference broadcast file systems, portions of service information, sources of audio and visual content, and interactive applications.
  • javax.tv.media defines extensions to the Java Media Framework (JMF) to manage the broadcast media pipeline which contains real-time audio and visual content.
  • javax.tv.media.protocol provides access to generic streaming data in the television broadcast.
  • javax.tv.net provides access to Internet Protocol (IP) datagrams transmitted in the broadcast stream.
  • javax.tv.service provides access to the service information (SI) database and basic SI APIs common to its subpackages.
    • javax.tv.service.guide supports electronic program guides with schedules, events, and ratings.
    • javax.tv.service.navigation supports hierarchical service and service information navigation.
    • javax.tv.service.selection supports service selection menus.
    • javax.tv.service.transport lets you query the broadcast delivery mechanisms.

  • javax.tv.util supports the creation and management of timer events.
  • javax.tv.xlet provides life cycle and property management methods.

Example Xlets

Xlets are typically small programs that perform simple functions such as electronic programming guides (EPGs), interactive games, enhanced content, managing the broadcast media pipeline, or managing the broadcast data signal.

This section presents two example Xlets. The first example displays a selectable list of services (channels); the second example retrieves and rotates through a list of programs and services presenting each service at the command line for 10 seconds. When run on a digital receiver, the second example Xlet presents the programs and services in the broadcast receiver where they can be retrieved by another Xlet and displayed in a user interface.

Display List of Selectable Services

The SvcDispXlet class displays a list of selectable services. The user can select a service and display details related to the selected service.

The SvcDispXlet implements the Xlet interface. In the initXlet method, the root container of the user interface is retrieved and the user interface created. Additionally, an instance of the SIManager class is acquired. This object is used to access the SI information that will be displayed by the Xlet.

The Xlet implements the ActionListener interface so it can listen for action events generated by the user interface components. In this example, the Xlet listens for action events generated by the list of programs and services and by a Refresh button. The Refresh button updates the service list by adding new programs and services and removing old ones.

  • The Xlet is made an action listener for action events generated by the list when the user selects a program or service.
  • The Xlet is made an action listener for action events generated by the Refresh button when the viewer uses the remote to select it.

The underlying Java platform calls the Xlet's actionPerformed method when action events are generated by user interface components for which the Xlet has been made an action listener. The actionPerformed method checks which component generated the event and passes it to the UpdateList method where the appropriate action is taken based on whether the list or button generated the event.

The SIManager object created with the call to SIManager.createInstance() is the entry point into the SI database.

The SIManager is used in the updateList method to create and manage the programs and services list.

The Xlet defines a Retriever class, which implements the SIRequestor interface. This interface is implemented by application classes to receive the results of asynchronous SI retrieval requests. The updateList method calls the getPrograms method in the Retriever class to retrieve the updated programs and services list.

import javax.tv.xlet.*;
import javax.tv.graphics.*;
import javax.tv.service.*;
import javax.tv.service.guide.*;
import javax.tv.service.navigation.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Date;
import java.text.DateFormat;

public class SvcDispXlet implements Xlet,
ActionListener {
private Container root_container = null;
private Panel panel = null;
private List slist = null;
private List plist = null;
private Button button = null;
private SIManager si_manager = null;
private Retriever retriever = new Retriever();

// init method
public void initXlet(XletContext ctx){
root_container = TVContainer.getRootContainer(ctx);
panel = new Panel();
panel.setBackground(Color.black);
root_container.setLayout(null);
root_container.setBounds(0,0,400,300);
root_container.add(panel);
panel.setBounds(0, 0,
root_container.getSize().height,
root_container.getSize().width - 50);
panel.setLayout(new GridLayout(2,1));
slist = new List();
slist.setBackground(Color.lightGray);
slist.addActionListener(this);
panel.add(slist);
plist = new List();
plist.setBackground(Color.lightGray);
panel.add(plist);
button = new Button("Refresh");
button.setBackground(Color.darkGray);
button.setForeground(Color.white);
button.addActionListener(this);
root_container.add(button);
button.setBounds(0,
root_container.getSize().width-50,
root_container.getSize().height,
50);
root_container.validate();
root_container.setVisible(true);
si_manager = SIManager.createInstance();
}

// start method
// Do an initial update of the slist
public void startXlet(){
panel.validate();
updateList(slist);
}

// pause
public void pauseXlet(){}

// destroy
public void destroyXlet(boolean unconditional){}

// called when the refresh button is pressed
// or service is selected in the list
public void actionPerformed(ActionEvent evt){
if(evt.getSource() == button){
this.updateList(slist);
plist.removeAll();
} else if (evt.getSource() == slist) {
this.updateList(plist);
}
}

private void updateList(List list){
//Clear out the old list
list.removeAll();
ServiceList collection =
si_manager.filterServices(null);
ServiceIterator si =
collection.createServiceIterator();
si.toEnd();
if(list == slist) {
while(si.hasPrevious()){
slist.addItem(
si.previousService().getName(), 0);
}
} else {
while(si.hasPrevious()){
Service s = si.previousService();
if(slist.getSelectedItem().
equals(s.getName())) {
retriever.getPrograms(s);
break;
}
}
}
}

class Retriever implements SIRequestor {
DateFormat dfmt =
DateFormat.getDateInstance(DateFormat.SHORT);
DateFormat tfmt =
DateFormat.getTimeInstance(DateFormat.SHORT);

void getPrograms(Service s) {
try{
SIManager.createInstance().
retrieveServiceDetails(
s.getLocator(), this);
} catch (Exception e) {
e.printStackTrace();
}
}

public void notifySuccess(
SIRetrievable[] result) {
if(result[0] instanceof ServiceDetails) {
try{
((ServiceDetails)result[0]).
getProgramSchedule().
retrieveFutureProgramEvents(new Date(),
new Date(System.currentTimeMillis()
+ 600000000), this);
catch (SIException e) {}
} else if (result[0] instanceof ProgramEvent) {
for(int i = 0; i < result.length; i++ ) {
ProgramEvent e = (ProgramEvent)result[i];
plist.addItem(e.getName() + " : "
+ dfmt.format(e.getStartTime())
+ " "
+ tfmt.format(e.getStartTime()));
}
}
}
public void notifyFailure(
SIRequestFailureType reason) {}
} //End Retriever class
} //End SvcDispXlet class

Present Rotating List of Programs and Services

The ServiceSelectorXlet Xlet presents a rotating list of selectable services. Each service presents (is printed to the command line) for 10 seconds before rotating to the next service.

This Xlet implements ServiceContextListener so it can listen to action events related to service contexts. A service context represents an environment in which services are presented in a broadcast receiver. The initXlet method creates a ServiceContext object, and the Xlet uses the ServiceContext object to select new services in the broadcast media to be presented to the digital receiver.

The startXlet method checks for a service context object, and creates one if none currently exists. Once a service context object is created either by init or start, the Xlet is made an action listener for action events generated by the service context. When a service context event is generated, the underlying Java platform calls the receiveServiceContextEvent method, which checks which context event occurred and handles the action event accordingly.

The context event can indicate that the presentation changed, terminated, or failed. A change is a success, and the name of the changed service is printed to the command line with a notice that it succeeded. If the presentation terminated or failed, the reason for the termination or failure is retrieved and printed to the command line.

import javax.tv.locator.*;
import javax.tv.service.*;
import javax.tv.service.navigation.*;
import javax.tv.service.selection.*;
import javax.tv.xlet.*;

public class ServiceSelectorXlet
implements Xlet, ServiceContextListener {
ServiceContextFactory scf;
ServiceContext sc;

public void initXlet(XletContext context) {
scf = ServiceContextFactory.getInstance();
try{
sc = scf.getServiceContext(context);
} catch (Exception e) {}
}

public void pauseXlet() {}
public void destroyXlet( boolean unconditional ) {}

public void startXlet() {
//If fail to get a service context at initXlet
if(sc == null) {
try{
//Get all existing service contexts
ServiceContext[] ctxs = scf.getServiceContexts();
if(ctxs.length > 0) {
sc = ctxs[0];
} else {
// none available, try to create one then.
sc = scf.createServiceContext();
}
} catch (Exception e) {
System.out.println(
"Cannot obtain a valid ServiceContext: "
+ e);
return;
}
}

// Add ServiceContextListener
sc.addListener(this);

//Get all available Services from SIManager
ServiceList list = SIManager.createInstance().
filterServices(null);
//Iterate the list to tune
for(int i = 0; i < list.size(); i++ ) {
try{
Service s = list.getService(i);
System.out.println("selecting: "
+ s.getName());
sc.select(s);
Thread.sleep(20000);
} catch (Exception e) {
System.out.println("selection failed: " + e);
}
}

System.out.println("End of startXlet()");
}

//Invoked when selection completes
public void receiveServiceContextEvent(
ServiceContextEvent event) {
//Selection success
if(event instanceof PresentationChangedEvent) {
Service currentService =
event.getServiceContext().getService();
System.out.println("Selection succeeded for: "
+ currentService.getName());
//Selection terminated
} else if (event instanceof
PresentationTerminatedEvent) {
int reason = ((PresentationTerminatedEvent)event).
getReason();
System.out.println(
"Selection terminated with a reason: "
+ reason);
//Selection failed
} else if (event instanceof SelectionFailedEvent) {
int reason = ((
SelectionFailedEvent)event).getReason();
System.out.println(
"Selection failed with a reason: "
+ reason);
}
}
}

More Information

You can find more information on the Java TV platform at the following web sites and forums:

coffeecup

Monica Pawlan is a manager and writer at Sun Microsystems, Inc., who enjoys learning and writing about new Java platform technologies. She also likes to garden, play guitar, and travel.

Have a question about programming? Use Java Online Support.

1 As used on this web site, the terms Java virtual machine or Java VM mean a virtual machine for the Java platform.

No comments: