/*
* @(#)Player.java 1.7 02/08/21
*
* Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved.
*/
package javax.media;
import java.awt.Component;
import javax.media.protocol.DataSource;
import java.io.IOException;
/**
* <code>Player</code> is a <code>MediaHandler</code> for rendering
* and controlling time based media data.
* <code>Player</code> extends the <code>Controller</code> interface.
* <code>Player</code> provides methods for
* obtaining AWT components, media processing controls, and a way to
* manage other <code>Controllers</code>.
*
* <h2>How a Player Differs from a Controller</h2>
*
* <code>Player</code> relaxes some restrictions that a
* <code>Controller</code> imposes
* on what methods can be called on a <i>Started</i>
* <code>Controller</code>.
* It also provides a way to manage groups of <CODE>Controllers</CODE>.
*
* <h3>Methods Restricted to <i>Stopped</i> Players</h3>
*
* The following methods cannot be invoked on a <i>Started</i>
* <CODE>Player</CODE>. If they are, <code>ClockStartedError</code>
* is thrown.
* <ul>
* <li> <code>setTimeBase</code>
* <li> <code>syncStart</code>
* <li> <code>deallocate</code>
* <li> <code>addController</code>
* <li> <code>removeController</code>
* </ul>
* <p>
*
* <h3>Methods Allowed on <i>Started</i> Players</h3>
* Unlike a <code>Controller</code>, the following methods are <i>legal</i> on
* a <code>Player</code> in the <i>Started</i> state:
* <ul>
* <li> <code>setMediaTime</code>
* <li> <code>setRate</code>
* </ul>
* Invoking these methods on a <i>Started</i> <code>Player</code> might
* initiate significant and time-consuming processing, depending
* on the location and type of media being processed.
*
* These methods might also cause the state of the <code>Player</code> to
* change.
* If this happens, the appropriate <code>TransitionEvents</code> are posted
* by the <code>Player</code> when its state changes.
* <p>
*
* For example, a <code>Player</code> might have to enter
* the <i>Prefetching</i> state to process a <code>setMediaTime</code>
* invocation.
* In this case, the <code>Player</code> posts a <code>RestartingEvent</code>,
* a <code>PrefetchCompleteEvent</code>, and a <code>StartEvent</code> as
* it moves from the <i>Started</i> state to <i>Prefetching</i>, back to
* <i>Prefetched</i>, and finally back to the <i>Started</i> state.
*
* <h3>Methods that are Illegal on <i>Unrealized</i> Players</h3>
*
* As with <code>Controller</code>, it is illegal to call the following methods
* on an <i>Unrealized</i> <code>Player</code>:
* <ul>
* <li> <code>getTimeBase</code>
* <li> <code>setTimeBase</code>
* <li> <code>setMediaTime</code>
* <li> <code>setRate</code>
* <li> <code>setStopTime</code>
* <li> <code>getStartLatency</code>
* </ul>
* <p>
* It is also illegal to call the following <code>Player</code> methods on an
* <i>Unrealized</i> <code>Player</code>:
* <ul>
* <li> <code>getVisualComponent</code>
* <li> <code>getControlPanelComponent</code>
* <li> <code>getGainControl</code>
* <li> <code>addController</code>
* <li> <code>removeController</code>
* </ul>
* <p>
*
* The <code>Player</code> throws a <code>NotRealizedError</code>
* if any of these methods are called while the <code>Player</code>
* is in the <i>Unrealized</i> state.
*
* <h3>Start Method </h3>
*
* As a convenience, <code>Player</code> provides a <code>start</code>
* method that can be invoked before a <code>Player</code>
* is <i>Prefetched</i>.
* This method attempts to transition the <code>Player</code> to
* the <i>Started</i> state from whatever state it's currently in.
* For example, if the <code>Player</code> is <i>Unrealized</i>,
* <code>start</code> implicitly calls <code>realize</code>,
* <code>prefetch</code>, and <code>Clock.syncStart</code>.
* The appropriate <code>TransitionEvents</code> are posted as
* the <code>Player</code> moves through each state on its way
* to <i>Started</i>.
*
* <h3>RestartingEvent</h3>
*
* If <code>setMediaTime</code> or <code>setRate</code> cause a perceptible
* delay in the presentation of the media, the <code>Player</code> posts a
* <code>RestartingEvent</code> and transitions to the <i>Prefetching</i>
* state.
* The previous state and target state of a <code>RestartingEvent</code>
* is always <i>Started</i>. <code>RestartingEvent</code> is a subclass
* of <code>StopEvent</code>.
*
* <h3>DurationUpdateEvent</h3>
*
* Because a <code>Player</code> cannot always know the duration of the media
* it is playing, the <code>Duration</code> interface defines that
* <code>getDuration</code> returns <code>Duration.DURATION_UNKNOWN</code>
* until the duration can be determined.
* A <code>DurationUpdateEvent</code> is generated when the <code>Player</code>
* can determine its duration or the if its duration
* changes, which can happen at any time. When the end of the media
* is reached, the duration should be known.
*
* <h2>Managing other Controllers</h2>
*
* In some situations, an application might want to use a single
* <code>Player</code> to
* control other <code>Players</code> or <code>Controllers</code>.
* A single controlling <code>Player</code> can be used to
* invoke <code>start</code>, <code>stop</code>, <code>setMediaTime</code>,
* and other methods on the entire group. The controlling
* <code>Player</code> manages all of the state transitions and event posting.
* <p>
* It is also possible to construct a simple <code>Controller</code>
* to update animations, report on media time-line progress, or
* provide other timing-related functions. Such <code>Controllers</code> can
* operate in sync with a controlling <code>Player</code>.
*
* <h3>Adding a Controller</h3>
*
* To have a <CODE>Player</CODE> assume control over a <code>Controller</code>,
* use the <code>addController</code> method.
* A <code>Controller</code> can not be added to a <i>Started</i>
* <code>Player</code>. If <code>addController</code> is called on
* a <i>Started</i> <code>Player</code>,
* a <code>ClockStartedError</code> is thrown.
* An <i>Unrealized</i>  or <code>Started</code>;<code>Controller</code>
* cannot be added to a
* <code>Player</code>; a <code>NotRealizedError</code> is thrown if the
* <code>Controller</code> is <i>Unrealized</i>;
* a <code>ClockStartedError</code> is thrown if the <code>Controller</code>
* is <i>Started</i>.
* <p>
*
* Once a <code>Controller</code> has been added, the <code>Player</code>:
* <ul>
* <li>Invokes <code>setTimeBase</code> on the <code>Controller</code> with the
* <code>Player's</code> <code>TimeBase</code>.
*
* If this fails, <code>addController</code> throws
* an <code>IncompatibleTimeBaseException</code>.
*
* <li>Synchronizes the <code>Controller</code> with the <code>Player</code>
* using <code>setMediaTime</code>, <code>setStopTime</code>,
* and <code>setRate</code>.
*
* <li>Takes the added <code>Controller's</code> latency into account when
* computing the <code>Player's</code> start latency.
* When <code>getStartLatency</code> is called,
* the <code>Player</code> returns the greater of:
* its latency before the <code>Controller</code> was added and
* the latency of the added <code>Controller</code>.
*
* <li>Takes the added <code>Controller's</code> duration into account when
* computing the <code>Player's</code>
* duration. When <code>getDuration</code> is called,
* the <code>Player</code> returns the greater of:
* its duration before the <code>Controller</code> was added and
* the duration of the added <code>Controller</code>.
* If either of these values is DURATION_UNKNOWN,
* <CODE>getDuration</CODE> returns DURATION_UNKNOWN.
* If either of these values is DURATION_UNBOUNDED <CODE>getDuration</CODE>
* returns DURATION_UNBOUNDED.
*
* <li> Adds itself as a <code>ControllerListener</code> for the
* added <code>Controller</code> so that it can
* manage the events that the <code>Controller</code> generates.
* (See the <a href="#events">Events</a> section below for more information.)
*
* <li>Invokes control methods on the added <code>Controller</code>
* in response to methods invoked on the <code>Player</code>. The
* methods that affect
* managed <code>Controllers</code> are discussed below.
*
* </ul>
*
* Once a <code>Controller</code> has been added to a <code>Player</code>,
* methods should only be called on the <code>Controller</code> through the
* managing <code>Player</code>.
* It is not defined how the <code>Controller</code> or <code>Player</code>
* will behave if methods are called directly on an added
* <code>Controller</code>.
* You cannot place a controlling <CODE>Player</CODE> under the control of a
* <CODE>Player</CODE> that it is managing; the resulting behavior is
* undefined.
* <p>
*
* When a <code>Controller</code> is added to a
* <code>Player</code>, the <code>Player</code>
* does not transition the added <code>Controller</code> to
* new state, nor does the <code>Player</code> transition itself
* forward.
* The <code>Player</code> either transitions back to the
* <i>realized</i> state if the added <code>Controller</code>
* is <i>realized</i> or <i>prefetching</i> or it stays
* in the <i>prefetched</i> state if the both the <code>Player</code>
* and the added <code>Controller</code> are in the <i>prefetched</i>
* state. If the <code>Player</code> makes a state transition
* as a result of adding a <code>Controller</code> the <code>Player</code>
* posts a <code>TransitionEvent</code>.
*
* <h3>Removing a Controller</h3>
*
* To stop a <code>Player</code> from managing another
* <code>Controller</code>, call <code>removeController</code>.
* The managing <code>Player</code> must be <i>Stopped</i> before
* <code>removeController</code> can be called.
* A <code>ClockStartedError</code> is thrown if <code>removeController</code>
* is called on a <i>Started</i> <code>Player</code>.
* <p>
*
* When a <code>Controller</code> is removed from a <code>Player's</code>
* control, the <code>Player</code>:
* <ul>
* <li> Resets the <code>Controller's</code> <code>TimeBase</code>
* to its default.
* <li> Recalculates its duration and posts a
* <code>DurationUpdateEvent</code> if the <code>Player's</code> duration
* is different without the <CODE>Controller</CODE> added.
* <li> Recalculates its start latency.
* </ul>
*
* <h3>Setting the Media Time and Rate of a Managing Player</h3>
*
* When you call <code>setMediaTime</code> on a <code>Player</code> that's
* managing other <code>Controllers</code>,
* its actions differ depending on whether or not the <code>Player</code>
* is <I>Started</I>.
* If the <code>Player</code> is not <i>Started</i>, it simply
* invokes <code>setMediaTime</code> on all of the
* <code>Controllers</code> it's managing.
* <p>
*
* If the <code>Player</code> is <i>Started</i>,
* it posts a <code>RestartingEvent</code> and
* performs the following tasks for each managed <code>Controller</code>:
*
* <ul>
* <li>Invokes <code>stop</code> on the <code>Controller</code>.
* <li>Invokes <code>setMediaTime</code> on the <code>Controller</code>.
* <li>Invokes <code>prefetch</code> on the <code>Controller</code>.
* <li>Waits for a <code>PrefetchCompleteEvent</code> from
* the <code>Controller</code>.
* <li>Invokes <code>syncStart</code> on the <code>Controller</code>
* </ul>
*
* <p>
*
* The same is true when <code>setRate</code> is called on a
* managing <code>Player</code>.
* The <code>Player</code> attempts to set the specified rate
* on all managed <code>Controllers</code>, stopping and restarting
* the <code>Controllers</code> if necessary.
* If some of the <code>Controllers</code> do not support the requested rate,
* the <code>Player</code> returns the rate that was actually set.
* All <code>Controllers</code> are guaranteed to have been successfully
* set to the rate returned.
*
* <h3>Starting a Managing Player</h3>
* When you call <code>start</code> on a managing <code>Player</code>,
* all of the <code>Controllers</code> managed by
* the <code>Player</code> are transitioned to
* the <i>Prefetched</i> state. When the <code>Controllers</code>
* are <i>Prefetched</i>,
* the managing <code>Player</code> calls <code>syncStart</code>
* with a time consistent with the latencies of each of the managed
* <code>Controllers</code>.
*
*
* <h3>Calling realize, prefetch, stop, or deallocate on a Managing Player</h3>
*
* When you call <code>realize</code>, <code>prefetch</code>,
* <code>stop</code>, or <code>deallocate</code> on a managing
* <code>Player</code>,
* the <code>Player</code> calls that method on all of the
* <code>Controllers</code> that it is managing.
* The <code>Player</code> moves from one state to the
* next when all of its <code>Controllers</code> have reached that state.
* For example, a <code>Player</code> in the <i>Prefetching</i>
* state does not transition into the <i>Prefetched</i>
* state until all of its managed <code>Controllers</code>
* are <i>Prefetched</i>.
* The <code>Player</code> posts <code>TransitionEvents</code> normally
* as it changes state.
* <p>
*
* <h3>Calling syncStart or setStopTime on a Managing Player</h3>
* When you call <code>syncStart</code> or <code>setStopTime</code> on a
* managing <code>Player</code>, the <code>Player</code>
* calls that method on all of the <code>Controllers</code> that it
* is managing. (The <code>Player</code>
* must be in the correct state or an error is thrown.
* For example, the <code>Player</code> must be <I>Prefetched</I>
* before you can call <code>syncStart</code>.)
*
* <h3>Setting the Time Base of a Managing Player</h3>
* When <code>setTimeBase</code> is called on a managing <code>Player</code>,
* the <code>Player</code> calls <code>setTimeBase</code> on all of
* the <code>Controllers</code> it's managing.
* If <code>setTimeBase</code> fails on any of the <code>Controllers</code>,
* an <code>IncompatibleTimeBaseException</code> is thrown
* and the <code>TimeBase</code> last used
* is restored for all of the <code>Controllers</code>.
*
* <h3>Getting the Duration of a Managing Player</h3>
* Calling <code>getDuration</code> on a managing <code>Player</code>
* returns the maximum duration of all of the added
* <code>Controllers</code> and the managing <code>Player</code>.
* If the <CODE>Player</CODE> or any <CODE>Controller</CODE>
* has not resolved its duration, <code>getDuration</code>
* returns <code>Duration.DURATION_UNKNOWN</code>.
*
* <h3> Closing a Managing Player</h3>
* When <code>close</code> is called on a managing <code>Player</code>
* all managed <code>Controllers</code> are closed as well.
*
* <a name="events"><h3>Events</h3></a>
* Most events posted by a managed <code>Controller</code> are filtered
* by the managing <code>Player</code>. Certain events are sent directly
* from the <code>Controller</code> through the <code>Player</code> and to the
* listeners registered with the <code>Player</code>.
* <p>
*
* To handle the events that a managed <code>Controller</code> can generate,
* the <code>Player</code> registers a listener with the
* <code>Controller</code> when it is added.
* Other listeners that are registered with the <code>Controller</code>
* must be careful not to invoke methods on the <code>Controller</code>
* while it is being managed by the <code>Player</code>.
* Calling a control method on a managed <code>Controller</code> directly
* will produce unpredictable results.
* <p>
*
* When a <CODE>Controller</CODE> is removed from the <code>Player's</code>
* list of managed <code>Controllers</code>,
* the <code>Player</code> removes itself from the <code>Controller's</code>
* listener list.
*
* <h4>Transition Events</h4>
* A managing <code>Player</code> posts <code>TransitionEvents</code> normally
* as it moves between states, but
* the managed <code>Controllers</code> affect when the <code>Player</code>
* changes state.
* In general,
* a <code>Player</code> does not post a transition event until all of its
* managed <code>Controllers</code> have posted the event.
*
* <h4>Status Change Events</h4>
* The managing <code>Player</code> collects the
* <code>RateChangeEvents</code>, <code>StopTimeChangeEvents</code>,
* and <code>MediaTimeSetEvents</code> posted by its
* managed <code>Controllers</code> and posts a single event for the group.
*
* <h4>DurationUpdateEvent</h4>
* A <code>Player</code> posts a <code>DurationUpdateEvent</code> when
* it determines its duration or its duration changes.
* A managing <code>Player's</code> duration might change if a managed
* <code>Controller</code> updates or discovers its duration.
* In general, if a managed <code>Controller</code>
* posts a <code>DurationUpdateEvent</code> and the new duration
* changes the managing <code>Player's</code> duration,
* the <code>Player</code> posts a <code>DurationUpdateEvent</code>
*
* <h4>CachingControlEvent</h4>
* A managing <CODE>Player</CODE> reposts <CODE>CachingControlEvents</CODE>
* received from a <CODE>Players</CODE> that it manages, but otherwise
* ignores the events.
*
* <h4>ControllerErrorEvents</h4>
* A managing <CODE>Player</CODE> immediately reposts
* any <CODE>ControllerErrorEvent</CODE> received from a
* <CODE>Controller</CODE> that it is managing.
* After a <CODE>ControllerErrorEvent</CODE> has been
* received from a managed <CODE>Controller</CODE>, a
* managing <CODE>Player</CODE> no longer invokes any methods
* on the managed <CODE>Controller</CODE>; the
* managed <CODE>Controller</CODE> is ignored from that point on.
*
* @see Manager
* @see GainControl
* @see Clock
* @see TransitionEvent
* @see RestartingEvent
* @see DurationUpdateEvent
* @see java.awt.Component
*
* @version 1.7, 02/08/21
*/
public interface Player extends MediaHandler, Controller {
/**
* Gets the display <code>Component</code> for this <code>Player</code>.
* The display <code>Component</code> is where visual media
* is rendered.
* If this <code>Player</code> has no visual component,
* <code>getVisualComponent</code> returns <CODE>null</CODE>.
* For example, <code>getVisualComponent</code> might return
* <CODE>null</CODE> if the <code>Player</code> only plays audio.
*
*
* @return The media display <code>Component</code> for this
* <code>Player</code>.
*/
public Component getVisualComponent();
/**
* Gets the object for controlling this <code>Player's</code>
* audio gain.
* If this player does not have a
* <code>GainControl</code>, <code>getGainControl</code> returns
* <CODE>null</CODE>.
* For example, <code>getGainControl</code> might return
* <CODE>null</CODE> if the <code>Player</code> does not play audio data.
*
* @return The <code>GainControl</code> object for this
* <code>Player</code>.
*/
public GainControl getGainControl();
/**
* Gets the <code>Component</code> that provides the default user
* interface for controlling this <code>Player</code>.
* If this <code>Player</code> has no default control panel,
* <code>getControlPanelComponent</code> returns <CODE>null</CODE>.
*
* @return The default control panel GUI for this <code>Player</code>.
*/
public Component getControlPanelComponent();
/**
* Starts the <code>Player</code> as soon as possible.
* The <CODE>start</CODE> method attempts to transition the
* <code>Player</code> to the <i>Started</i> state.
* If the <CODE>Player</CODE> has not been <i>Realized</i> or
* <i>Prefetched</i>, <code>start</code> automatically performs
* those actions. The appropriate events
* are posted as the <code>Player</code> moves through each state.
*/
public void start();
/**
* Tells the <CODE>Player</CODE> to assume control of another <code>Controller</code>.
*
* @param newController The <code>Controller</code> to be managed.
*
* @exception IncompatibleTimeBaseException Thrown if the added
* <code>Controller</code> cannot take this
* <code>Player's</code> <CODE>TimeBase</CODE>.
*/
public void addController(Controller newController)
throws IncompatibleTimeBaseException;
/**
* Tells the <CODE>Player</CODE> to stop controlling a <code>Controller</code>.
*
* @param oldController The <code>Controller</code> to stop managing.
*/
public void removeController(Controller oldController);
}
|