Sun Java Solaris Communities My SDN Account Join SDN
 
1.0 Programmers Guide

1.0 Overview

 
TOC  Prev  Next  
The transitions between states are controlled with five methods:

  • realize

  • prefetch

  • start

  • deallocate

  • stop

  • close

By controlling when these methods are called, you can manage the state of a Player. For example, you might want to minimize start-latency by preparing the Player to start before you actually start it.

You can implement the ControllerListener interface to manage these control methods in response to changes in the Player's state. Listening for a Player's state transitions is also important in other cases. For example, you cannot get a Player's components until the Player has been Realized. By listening for a RealizeCompleteEvent you can get the components as soon as the Player is Realized.

5.1 Preparing a Player to Start

Most media Players cannot be started instantly. Before the Player can start, certain hardware and software conditions must be met. For example, if the Player has never been started, it might be necessary to allocate buffers in memory to store the media data. Or, if the media data resides on a network device, the Player might have to establish a network connection before it can download the data. Even if the Player has been started before, the buffers might contain data that is not valid for the current media position.

5.1.1 Realizing and Prefetching the Player

JMF breaks the process of preparing a Player to start into two phases, Realizing and Prefetching. Realizing and Prefetching a Player before you start it minimizes the time it takes the Player to begin presenting media when start is called and helps create a highly-responsive interactive experience for the user. Implementing the ControllerListener interface allows you to control when these operations occur.

You call realize to move the Player into the Realizing state and begin the realization process. You call prefetch to move the Player into the Prefetching state and initiate the prefetching process. The realize and prefetch methods are asynchronous and return immediately. When the Player completes the requested operation, it posts a RealizeCompleteEvent or PrefetchCompleteEvent. "Player States" on page 6 describes the operations that a Player performs in each of these states.

A Player in the Prefetched state is prepared to start and its start-up latency cannot be further reduced. However, setting the media time through setMediaTime might return the Player to the Realized state, increasing its start-up latency.

Keep in mind that a Prefetched Player ties up system resources. Because some resources, such as sound cards, might only be usable by one program at a time, this might prevent other Players from starting.

5.1.2 Blocking until a Player is Realized

Many of the methods that can be called on a Player require that the Player be in the Realized state. One way to guarantee that a Player is Realized when you call these methods is to implement a method that calls realize and blocks until the Player posts a RealizeCompleteEvent.

Note: Be aware that blocking on realize can produce unsatisfactory results. For example, if an applet blocks while a Player is realizing, Applet.start and Applet.stop will not be able to interrupt the process.

To block until a Player is Realized, you could implement a method called blockingRealize that calls realize on your Player and returns when the Player posts a RealizeCompleteEvent and your controllerUpdate method is called. This requires that you implement the ControllerListener interface and register as a listener with the Player. If you register as a listener with multiple Players, your controllerUpdate method needs to determine which Player posted the RealizeCompleteEvent.1


boolean realized = false; public synchronized void blockingRealize() { myPlayer.realize(); while (!realized) { try { wait(); } catch (java.lang.InterruptedException e) { status.setText("Interrupted while waiting on realize...exiting."); System.exit(1); } } } public synchronized void controllerUpdate (ControllerEvent event) { if (event instanceof RealizeCompleteEvent) { realized = true; notify(); } else if (event instanceof EndOfMediaEvent) { eomReached = true; } }

5.1.3 Determining a Player's Start-up Latency

To determine how much time is required to start a Player, you can call getStartLatency . For Players that have a variable start latency, the return value of getStartLatency represents the maximum possible start latency. For some media types, getStartLatency might return LATENCY_UNKNOWN.

The start-up latency reported by getStartLatency might differ depending on the Player's current state. For example, after a prefetch operation, the value returned by getStartLatency is typically smaller. A Controller that can be added to a Player will return a useful value once it is Prefetched. (For more information about added Controllers, see "Using a Player to Manage and Synchronize other Controllers" on page 29.)

5.2 Starting and Stopping a Player

Calling start moves a Player into the Started state. As soon as start is called, methods that are only legal for stopped Players cannot be called until the Player has been stopped.

If start is called and the Player has not been prefetched, start performs the realize and prefetch operations as needed to move the Player into the Prefetched state. The Player posts transition events as it moves through each state.

When stop is called on a Player, the Player is considered to be stopped immediately; stop is synchronous. However, a Player can also stop asynchronously when:

  • The end of the media stream is reached.

  • The stop time previously set with setStopTime is reached.

  • The Player is data starved.

When a Player stops, it posts a StopEvent. To determine why the Player stopped, you must listen for the specific stop events: DeallocateEvent, EndOfMediaEvent , RestartingEvent, StopAtTimeEvent, StopByRequestEvent, and DataStarvedEvent.

5.3 Releasing Player Resources

The deallocate method tells a Player to release any exclusive resources and minimize its use of non-exclusive resources. Although buffering and memory management requirements for Players are not specified, most Java Media Players allocate buffers that are large by the standards of Java objects. A well-implemented Player releases as much internal memory as possible when deallocate is called.

The deallocate method can only be called on a Stopped Player. To avoid ClockStartedErrors, you should call stop before you call deallocate. Calling deallocate on a Player in the Prefetching or Prefetched state returns it to the Realized state. If deallocate is called while the Player is realizing, the Player posts a DeallocateEvent and returns to the Unrealized state. (Once a Player has been realized, it can never return to the Unrealized state.)

You generally call deallocate when the Player is not being used. For example, an applet should call deallocate as part of its stop method. By calling deallocate , the program can maintain references to the Player, while freeing other resources for use by the system as a whole. (JMF does not prevent a Realized Player that has formerly been Prefetched or Started from maintaining information that would allow it to be started up more quickly in the future.)

When you are finished with a Player (or other Controller) and are not going to use it anymore, you should call close. The close method indicates that the Controller will no longer be used and can shut itself down. Calling close releases all of the resources that the Controller was using and causes the it to cease all activity. When a Controller is closed, it posts a ControllerClosedEvent. A closed Controller cannot be reopened and invoking methods on a closed Controller might generate errors.

5.4 Implementing the ControllerListener Interface

ControllerListener is an asynchronous interface for handling events generated by Controller objects. Using the ControllerListener interface enables you to manage the timing of potentially time-consuming Player operations such as prefetching.

To implement the ControllerListener interface, you need to:

  1. Implement the ControllerListener interface in a class.
  2. Register that class as a listener by calling addControllerListener on the Controller that you want to receive events from.
When a Controller posts an event, it calls controllerUpdate on each registered listener. Typically, controllerUpdate is implemented as a series of if-else statements of the form:


if(event instanceof EventType){ ... } else if(event instanceof OtherEventType){ ... }

This filters out the events that you are not interested in. If you have registered as a listener with multiple Controllers, you also need to determine which Controller posted the event. ControllerEvents come "stamped" with a reference to their source that you can access by calling getSource.

"Appendix D: ControllerAdapter" on page 73 provides the source for an implementation of ControllerListener that can be easily extended to respond to particular Events.

When you receive events from a Controller, you might need to do some additional processing to ensure that the Controller is in the proper state before calling a control method. For example, before calling any of the methods that are restricted to Stopped Players, you should check the Player's target state by calling getTargetState. If start has been called, the Player is considered to be in the Started state, though it might be posting transition events as it prepares the Player to present media.

Some types of ControllerEvents are stamped with additional state information. For example, the StartEvent and StopEvent classes each define a method that allows you to retrieve the media time at which the event occurred.

1 This example code is used with the permission of Bill Day and JavaWorld magazine. The blockingRealize example code was first published by Bill Day in "Java Media Framework Player API: Multimedia Comes to Java" in JavaWorld magazine, an online publication of Web Publishing Inc., April 1997. Please see http://www.javaworld.com/javaworld/jw-04-1997/jw- 04-jmf.html for the complete article, example code listing, and demonstration applets.

TOC  Prev  Next