Programming Paradigms When Using JMF

JMF based applets and applications tend to require particular programming approaches that other general calculation programs don't usually possess. This section addresses those approaches.

The JMF deals with time-based media. That requires not only a sophisticated model of time, but also support for the idiosyncratic and asynchronous behavior of a range of hardware devices and networks. Different capture devices might take considerably different times to become ready, network streams might drop out, and file systems might become full through saving large media files. All these eventualities and many, many more should be dealt with robustly and appropriately by a well-written JMF program.

Event Driven

Event-driven programming lies at the heart of most JMF programs. Graphical user interfaces programmed in the AWT or Swing set must wait and respond to user actions (for example, a button press) that occur asynchronously (that is, the program has no knowledge of when they'll occur). Also, a JMF program that is playing or processing must wait and respond to the various timing events and actions arising from a player or processor.

Those of you who aren't familiar with the concepts and practice of event-driven programming should consider acquiring such practice before delving too deeply into the JMF API. Such knowledge is necessary because of the central role of events in controlling the API.

The later section within this chapter dealing with time and the next chapter cover the major listener interfaces and events of the API. However, it is extremely typical to see lines like those found in Listing 7.1 in a JMF program.

Listing 7.1 Skeleton Example of the Type of Event Driven Programming Used in Conjunction with the JMF
public class MyJMFProgram implements ControllerListener {
:
:
  player.addControllerListener(this);
:
:
public synchronized void controllerUpdate(ControllerEvent e) {
:
}
}

Such a class is listening to, and will be sent events from, the player object.

Threading

The devices responsible for controlling and transporting time-based media (for example, networks, renderers, and capture devices) are asynchronous. As in many applications, when this is combined with the control of multiple streams, channels, tracks, or sources and destinations of media, it is necessary to delegate control of individual items to separate threads so that the whole program won't suffer a bottleneck or be brought to an unresponsive halt by a single recalcitrant subtask.

Java provides strong and fundamental support for threads through the Thread class and Runnable interface. User classes that are to run as threads can either extend Thread or implement Runnable. Because of Java's single inheritance, it is often better for a class to implement Runnable (which only consists of the single run() method) than the subclass Thread.

An application employing threads tends to consist of a main, controller program that creates the threads for the individual tasks and both monitors and communicates with them as necessary. The classes that are to act as the threads must possess a run() method. This is started when the thread is started, and the thread is alive only while the method hasn't returned.

A threaded program usually possesses code similar to that found in Listing 7.2.

Listing 7.2 Typical Structure of Code Starting Up a New Thread
// Need to create a thread to handle a sub-task. First create
// a new instance of the class that will do the work. Then
// pass that object to the Thread constructor. Finally, start
// up the thread.

MyThreadedController controlObj = new MyThreadedController(...);
Thread theThread = new Thread(controlObj);
theThread.start();

Exceptions

Exceptions in Java represent unusual, abnormal, and unexpected results that halt the normal flow of program execution. For JMF programs, exceptions are a very real possibility that a well-written and robust program must be capable of dealing with or at least exiting gracefully and with the maximum amount of information for the user. Examples of such exceptions within the context of a JMF program include the inability to create a player or processor for the media object specified, a number of time related exceptions (for example, trying to invoke a method on a processor that isn't yet in a state to support that action), as well as IO exceptions (for example, attempting to open a file that doesn't exist).

Hence, it is common to find a number of try {...} catch { ...} blocks in a program, whereby the code that could potentially throw an exception is enclosed in the try block; whereas the one or more catch blocks contain code for dealing with the exceptions that might arise. If you are unfamiliar with exceptions and the mechanism for handling them, refer to a general Java textbook or reference. A typical example of this type of processing is found in Listing 7.3.

Listing 7.3 Typical Usage of try{ }, catch{ } Blocks to Deal with Thrown Exceptions
try {
  Player player = Manager.createPlayer(locator);
}
catch (NoPlayerException e) {
  System.err.println("Unable to create a player for..." + e);
}

URLs and Networks

One of the important features of Java is the integration of network support into the heart of the language. That theme of integrating networking support extends to the JMF, where for instance it is not only possible to play a file across the network, but also it is relatively simple. One central class of the API is the MediaLocator, which specifies the location of a media object and is closely related to Java Platform's URL class.

Integration of networking features into the JMF extends into support for RTP (Real-time Transport Protocol), the communication protocol employed to stream media across networks. That topic is covered in Chapter 9.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset