/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import javax.microedition.media.protocol.SourceStream;
import javax.microedition.media.protocol.DataSource;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import com.sun.j2me.app.AppPackage;
import com.sun.j2me.app.AppIsolate;
import com.sun.j2me.log.Logging;
import com.sun.j2me.log.LogChannels;
import com.sun.mmedia.PlayerStateSubscriber;
import java.io.IOException;
public class PlayerImpl implements Player {
public PlayerStateSubscriber state_subscriber = null;
protected BasicPlayer playerInst = null;
public BasicPlayer getPlayerInst(){ return playerInst; };
protected DataSource source;
protected SourceStream stream;
private boolean isClosed = false;
private String mediaFormat = null;
private boolean handledByDevice = false;
private boolean handledByJava = false;
private int hNative; // handle of native API library
private int loopCount = 0; /* if set in unrealized state */
private Vector listeners = new Vector(2);
/**
* hastable to map playerID to instances
*/
private static Hashtable mplayers = new Hashtable(4);
/**
* table of player states
*/
private static Hashtable pstates = new Hashtable();
/**
* table of media times
*/
private static Hashtable mtimes = new Hashtable();
/**
* VM paused?
*/
private static boolean vmPaused = false;
/**
* global player id
*/
private static int pcount = -1;
/**
* player ID of this player
*/
protected int pID = 0;
/**
* lock object
*/
private static Object idLock = new Object();
// Init native library
protected native int nInit(int appId, int pID, String URI);
// Terminate native library
protected native int nTerm(int handle);
// Get Media Format
protected native String nGetMediaFormat(int handle);
// Need media Download in Java side?
protected native boolean nIsHandledByDevice(int handle);
// Realize native player
protected native boolean nRealize(int handle, String mime);
private static String PL_ERR_SH = "Cannot create a Player: ";
/**
* Constructor
*/
private PlayerImpl() {};
public PlayerImpl(DataSource source) throws MediaException, IOException {
// Get current application ID to support MVM
int appId = AppIsolate.getIsolateId();
synchronized (idLock) {
pcount = (pcount + 1) % 32767;
pID = pcount;
}
String locator = source.getLocator();
hNative = nInit(appId, pID, locator);
if (0 == hNative) {
throw new MediaException("Unable to create native player");
} else if (-1 == hNative) {
throw new IOException("Unable to create native player");
}
mediaFormat = nGetMediaFormat(hNative);
if( mediaFormat.equals( BasicPlayer.MEDIA_FORMAT_UNSUPPORTED ) ) {
/* verify if handled by Java */
mediaFormat = Configuration.getConfiguration().ext2Format(source.getLocator());
if( mediaFormat == null || mediaFormat.equals( BasicPlayer.MEDIA_FORMAT_UNSUPPORTED ) ) {
nTerm(hNative);
throw new MediaException("Unsupported Media Format:" + mediaFormat + " for " + source.getLocator());
} else {
handledByJava = true;
}
}
if (locator != null && mediaFormat.equals(BasicPlayer.MEDIA_FORMAT_UNKNOWN)) {
if (locator.equals(Manager.TONE_DEVICE_LOCATOR)) {
mediaFormat = BasicPlayer.MEDIA_FORMAT_DEVICE_TONE;
handledByDevice = true;
} else if (locator.equals(Manager.MIDI_DEVICE_LOCATOR)) {
mediaFormat = BasicPlayer.MEDIA_FORMAT_DEVICE_MIDI;
handledByDevice = true;
}
} else if (locator != null && locator.startsWith(Configuration.CAPTURE_LOCATOR)) {
if (locator.startsWith(Configuration.AUDIO_CAPTURE_LOCATOR)) {
mediaFormat = BasicPlayer.MEDIA_FORMAT_CAPTURE_AUDIO;
} else if (locator.startsWith(Configuration.VIDEO_CAPTURE_LOCATOR)) {
mediaFormat = BasicPlayer.MEDIA_FORMAT_CAPTURE_VIDEO;
} else if (locator.startsWith(Configuration.RADIO_CAPTURE_LOCATOR)) {
mediaFormat = BasicPlayer.MEDIA_FORMAT_CAPTURE_RADIO;
}
handledByDevice = true;
}
if (!handledByJava && !handledByDevice) {
handledByDevice = nIsHandledByDevice(hNative);
}
this.source = source;
if (!handledByDevice) {
source.connect();
SourceStream[] streams = source.getStreams();
if (null == streams) {
throw new MediaException("DataSource.getStreams() returned null");
} else if (0 == streams.length) {
throw new MediaException("DataSource.getStreams() returned an empty array");
} else if (null == streams[0]) {
throw new MediaException("DataSource.getStreams()[0] is null");
} else {
if (streams.length > 1 && Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI,
"*** DataSource.getStreams() returned " + streams.length +
" streams, only first one will be used!");
}
stream = streams[0];
}
}
// Set event listener
new MMEventListener();
}
/**
* Constructs portions of the <code>Player</code> without
* acquiring the scarce and exclusive resources.
* This may include examining media data and may
* take some time to complete.
* <p>
* When <code>realize</code> completes successfully,
* the <code>Player</code> is in the
* <i>REALIZED</i> state.
* <p>
* If <code>realize</code> is called when the <code>Player</code> is in
* the <i>REALIZED</i>, <i>PREFETCHTED</i> or <i>STARTED</i> state,
* the request will be ignored.
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @exception MediaException Thrown if the <code>Player</code> cannot
* be realized.
* @exception SecurityException Thrown if the caller does not
* have security permission to realize the <code>Player</code>.
*
*/
public void realize() throws MediaException {
if (playerInst != null) {
if (isClosed) {
throw new IllegalStateException();
}
return;
}
String type = source.getContentType();
if (type == null && stream != null && stream.getContentDescriptor() != null) {
type = stream.getContentDescriptor().getContentType();
}
/* try to realize native player */
if (!nRealize(hNative, type)) {
throw new MediaException("Can not realize");
}
MediaDownload mediaDownload = null;
if (!handledByDevice && !handledByJava) {
mediaFormat = nGetMediaFormat(hNative);
if (mediaFormat.equals(BasicPlayer.MEDIA_FORMAT_UNSUPPORTED)) {
String format;
/* verify if handled by Java */
if (type != null &&
(format = Configuration.getConfiguration().mime2Format(type)) != null &&
!format.equals(BasicPlayer.MEDIA_FORMAT_UNKNOWN) &&
!format.equals(BasicPlayer.MEDIA_FORMAT_UNSUPPORTED)) {
mediaFormat = format;
handledByJava = true;
} else {
throw new MediaException("Unsupported media format");
}
}
/* predownload media data to recognize media format and/or
specific media parameters (e.g. duration) */
if (!mediaFormat.equals(BasicPlayer.MEDIA_FORMAT_TONE)) {
mediaDownload = new MediaDownload(hNative, stream);
try {
mediaDownload.fgDownload();
} catch(IOException ex1) {
ex1.printStackTrace();
throw new MediaException("Can not start download Thread: " + ex1);
}catch(Exception ex) {
ex.printStackTrace();
throw new MediaException( "Can not start download Thread: " + ex );
}
}
}
if (mediaFormat.equals(BasicPlayer.MEDIA_FORMAT_UNKNOWN)) {
/* ask media format if unknown */
mediaFormat = nGetMediaFormat(hNative);
if (mediaFormat.equals(BasicPlayer.MEDIA_FORMAT_UNKNOWN)) {
throw new MediaException("Unknown Media Format");
}
if (mediaFormat.equals(BasicPlayer.MEDIA_FORMAT_UNSUPPORTED)) {
throw new MediaException("Unsupported Media Format");
}
}
/* create Implementation Player */
playerInst = getPlayerFromType(mediaFormat);
playerInst.notificationSource = this;
playerInst.hNative = hNative;
playerInst.mediaFormat = mediaFormat;
playerInst.handledByDevice = handledByDevice;
playerInst.pID = pID;
playerInst.mediaDownload = mediaDownload;
playerInst.setSource(source);
if (loopCount != 0) {
playerInst.setLoopCount(loopCount);
}
if (listeners.size() > 0) {
for(int i=0; i<listeners.size(); i++)
playerInst.addPlayerListener((PlayerListener)listeners.elementAt(i));
listeners.removeAllElements();
}
mplayers.put(new Integer(pID), playerInst);
playerInst.realize();
if (null != state_subscriber) {
state_subscriber.PlayerRealized(this);
}
}
/**
* Gets the playerFromType attribute of the Manager class
*
* @param type Description of the Parameter
* @return The playerFromType value
* @exception IOException Description of the Exception
* @exception MediaException Description of the Exception
*/
private BasicPlayer getPlayerFromType(String type) throws MediaException {
String className = null;
if ("GIF".equals(type)) {
className = "com.sun.mmedia.GIFPlayer";
} else if (BasicPlayer.MEDIA_FORMAT_CAPTURE_VIDEO.equals(type)) {
className = "com.sun.mmedia.DirectCamera";
} else if (DirectPlayer.nIsToneControlSupported(hNative)) {
className = "com.sun.mmedia.DirectTone";
} else if (DirectPlayer.nIsMIDIControlSupported(hNative)) {
className = "com.sun.mmedia.DirectMIDI";
} else {
className = "com.sun.mmedia.DirectPlayer";
}
if ((type == null) || className == null) {
throw new MediaException(PL_ERR_SH + "MediaFormat " + type + " is not supported");
}
BasicPlayer p = null;
try {
// ... try and instantiate the handler ...
Class handlerClass = Class.forName(className);
p = (BasicPlayer) handlerClass.newInstance();
} catch (Exception e) {
throw new MediaException(PL_ERR_SH + e.getMessage());
}
return p;
}
/**
* Acquires the scarce and exclusive resources
* and processes as much data as necessary
* to reduce the start latency.
* <p>
* When <code>prefetch</code> completes successfully,
* the <code>Player</code> is in
* the <i>PREFETCHED</i> state.
* <p>
* If <code>prefetch</code> is called when the <code>Player</code>
* is in the <i>UNREALIZED</i> state,
* it will implicitly call <code>realize</code>.
* <p>
* If <code>prefetch</code> is called when the <code>Player</code>
* is already in the <i>PREFETCHED</i> state, the <code>Player</code>
* may still process data necessary to reduce the start
* latency. This is to guarantee that start latency can
* be maintained at a minimum.
* <p>
* If <code>prefetch</code> is called when the <code>Player</code>
* is in the <i>STARTED</i> state,
* the request will be ignored.
* <p>
* If the <code>Player</code> cannot obtain all
* of the resources it needs, it throws a <code>MediaException</code>.
* When that happens, the <code>Player</code> will not be able to
* start. However, <code>prefetch</code> may be called again when
* the needed resource is later released perhaps by another
* <code>Player</code> or application.
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @exception MediaException Thrown if the <code>Player</code> cannot
* be prefetched.
* @exception SecurityException Thrown if the caller does not
* have security permission to prefetch the <code>Player</code>.
*
*/
public void prefetch() throws MediaException {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst == null) {
realize();
}
if (playerInst != null) {
playerInst.chkClosed(false);
if (vmPaused) {
return;
}
playerInst.prefetch();
if (null != state_subscriber) {
state_subscriber.PlayerPrefetched(this);
}
}
};
/**
* Starts the <code>Player</code> as soon as possible.
* If the <code>Player</code> was previously stopped
* by calling <code>stop</code> or reaching a preset
* stop time, it will resume playback
* from where it was previously stopped. If the
* <code>Player</code> has reached the end of media,
* calling <code>start</code> will automatically
* start the playback from the start of the media.
* <p>
* When <code>start</code> returns successfully,
* the <code>Player</code> must have been started and
* a <code>STARTED</code> event will
* be delivered to the registered <code>PlayerListener</code>s.
* However, the <code>Player</code> is not guaranteed to be in
* the <i>STARTED</i> state. The <code>Player</code> may have
* already stopped (in the <i>PREFETCHED</i> state) because
* the media has 0 or a very short duration.
* <p>
* If <code>start</code> is called when the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>REALIZED</i> state,
* it will implicitly call <code>prefetch</code>.
* <p>
* If <code>start</code> is called when the <code>Player</code>
* is in the <i>STARTED</i> state,
* the request will be ignored.
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @exception MediaException Thrown if the <code>Player</code> cannot
* be started.
* @exception SecurityException Thrown if the caller does not
* have security permission to start the <code>Player</code>.
*/
public void start() throws MediaException {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst == null) {
realize();
}
if ( getState() == REALIZED )
{
prefetch();
}
if (playerInst != null) {
playerInst.chkClosed(false);
if (vmPaused) {
return;
}
playerInst.start();
}
};
/**
* Stops the <code>Player</code>. It will pause the playback at
* the current media time.
* <p>
* When <code>stop</code> returns, the <code>Player</code> is in the
* <i>PREFETCHED</i> state.
* A <code>STOPPED</code> event will be delivered to the registered
* <code>PlayerListener</code>s.
* <p>
* If <code>stop</code> is called on
* a stopped <code>Player</code>, the request is ignored.
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @exception MediaException Thrown if the <code>Player</code>
* cannot be stopped.
*/
public void stop() throws MediaException {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst != null) {
playerInst.stop();
}
}
/**
* Release the scarce or exclusive
* resources like the audio device acquired by the <code>Player</code>.
* <p>
* When <code>deallocate</code> returns, the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>REALIZED</i> state.
* <p>
* If the <code>Player</code> is blocked at
* the <code>realize</code> call while realizing, calling
* <code>deallocate</code> unblocks the <code>realize</code> call and
* returns the <code>Player</code> to the <i>UNREALIZED</i> state.
* Otherwise, calling <code>deallocate</code> returns the
* <code>Player</code> to the <i>REALIZED</i> state.
* <p>
* If <code>deallocate</code> is called when the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>REALIZED</i>
* state, the request is ignored.
* <p>
* If the <code>Player</code> is <code>STARTED</code>
* when <code>deallocate</code> is called, <code>deallocate</code>
* will implicitly call <code>stop</code> on the <code>Player</code>.
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
*/
public void deallocate() {
if (playerInst != null) {
playerInst.deallocate();
if( null != state_subscriber &&
( getState() == PREFETCHED || getState() == STARTED ) ) {
state_subscriber.PlayerDeallocated(this);
}
} else {
// Player in the UNREALIZED or CLOSED state
if (isClosed) {
throw new IllegalStateException();
}
}
};
/**
* Close the <code>Player</code> and release its resources.
* <p>
* When the method returns, the <code>Player</code> is in the
* <i>CLOSED</i> state and can no longer be used.
* A <code>CLOSED</code> event will be delivered to the registered
* <code>PlayerListener</code>s.
* <p>
* If <code>close</code> is called on a closed <code>Player</code>
* the request is ignored.
*/
public void close() {
if (playerInst != null) {
playerInst.close();
mplayers.remove(new Integer(pID));
} else {
if (!isClosed) {
/* close source of unrealized player */
if (source != null) {
source.disconnect();
source = null;
}
/* close native part of unrealized player */
if(hNative != 0) {
nTerm(hNative);
}
}
}
isClosed = true;
}
/**
* Sets the <code>TimeBase</code> for this <code>Player</code>.
* <p>
* A <code>Player</code> has a default <code>TimeBase</code> that
* is determined by the implementation.
* To reset a <code>Player</code> to its default
* <code>TimeBase</code>, call <code>setTimeBase(null)</code>.
*
* @param master The new <CODE>TimeBase</CODE> or
* <CODE>null</CODE> to reset the <code>Player</code>
* to its default <code>TimeBase</code>.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>UNREALIZED</i>, <i>STARTED</i> or <i>CLOSED</i> state.
* @exception MediaException Thrown if
* the specified <code>TimeBase</code> cannot be set on the
* <code>Player</code>.
* @see #getTimeBase
*/
public void setTimeBase(TimeBase master) throws MediaException {
if (playerInst != null) {
playerInst.setTimeBase(master);
} else {
// Player in the UNREALIZED or CLOSED state
throw new IllegalStateException();
}
};
/**
* Gets the <code>TimeBase</code> that this <code>Player</code> is using.
* @return The <code>TimeBase</code> that this <code>Player</code> is using.
* @see #setTimeBase
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>CLOSED</i> state.
*/
public TimeBase getTimeBase() {
if (playerInst != null) {
return playerInst.getTimeBase();
}
// Player in the UNREALIZED or CLOSED state
throw new IllegalStateException();
};
/**
* Sets the <code>Player</code>'s <i>media time</i>.
* <p>
* For some media types, setting the media time may not be very
* accurate. The returned value will indicate the
* actual media time set.
* <p>
* Setting the media time to negative values will effectively
* set the media time to zero. Setting the media time to
* beyond the duration of the media will set the time to
* the end of media.
* <p>
* There are some media types that cannot support the setting
* of media time. Calling <code>setMediaTime</code> will throw
* a <code>MediaException</code> in those cases.
*
* @param now The new media time in microseconds.
* @return The actual media time set in microseconds.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>CLOSED</i> state.
* @exception MediaException Thrown if the media time
* cannot be set.
* @see #getMediaTime
*/
public long setMediaTime(long now) throws MediaException {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst != null) {
return playerInst.setMediaTime(now);
}
throw new IllegalStateException();
};
/**
* Gets this <code>Player</code>'s current <i>media time</i>.
* <p>
* <code>getMediaTime</code> may return <code>TIME_UNKNOWN</code> to
* indicate that the media time cannot be determined.
* However, once <code>getMediaTime</code> returns a known time
* (time not equals to <code>TIME_UNKNOWN</code>), subsequent calls
* to <code>getMediaTime</code> must not return
* <code>TIME_UNKNOWN</code>.
*
* @return The current <i>media time</i> in microseconds or
* <code>TIME_UNKNOWN</code>.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @see #setMediaTime
*/
public long getMediaTime() {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst != null) {
return playerInst.getMediaTime();
} else {
return Player.TIME_UNKNOWN;
}
};
/**
* Gets the current state of this <code>Player</code>.
* The possible states are: <i>UNREALIZED</i>,
* <i>REALIZED</i>, <i>PREFETCHED</i>, <i>STARTED</i>, <i>CLOSED</i>.
*
* @return The <code>Player</code>'s current state.
*/
public int getState() {
if (playerInst != null) {
return playerInst.getState();
}
return isClosed ? Player.CLOSED : Player.UNREALIZED;
};
/**
* Get the duration of the media.
* The value returned is the media's duration
* when played at the default rate.
* <br>
* If the duration cannot be determined (for example, the
* <code>Player</code> is presenting live
* media) <CODE>getDuration</CODE> returns <CODE>TIME_UNKNOWN</CODE>.
*
* @return The duration in microseconds or <code>TIME_UNKNOWN</code>.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
*/
public long getDuration() {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst != null) {
return playerInst.getDuration();
} else {
return Player.TIME_UNKNOWN;
}
};
/**
* Get the content type of the media that's
* being played back by this <code>Player</code>.
* <p>
* See <a href="Manager.html#content-type">content type</a>
* for the syntax of the content type returned.
*
* @return The content type being played back by this
* <code>Player</code>.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>CLOSED</i> state.
*/
public String getContentType() {
if (playerInst != null) {
return playerInst.getContentType();
}
throw new IllegalStateException();
};
/**
* Set the number of times the <code>Player</code> will loop
* and play the content.
* <p>
* By default, the loop count is one. That is, once started,
* the <code>Player</code> will start playing from the current
* media time to the end of media once.
* <p>
* If the loop count is set to N where N is bigger than one,
* starting the <code>Player</code> will start playing the
* content from the current media time to the end of media.
* It will then loop back to the beginning of the content
* (media time zero) and play till the end of the media.
* The number of times it will loop to the beginning and
* play to the end of media will be N-1.
* <p>
* Setting the loop count to 0 is invalid. An
* <code>IllegalArgumentException</code> will be thrown.
* <p>
* Setting the loop count to -1 will loop and play the content
* indefinitely.
* <p>
* If the <code>Player</code> is stopped before the preset loop
* count is reached either because <code>stop</code> is called or
* a preset stop time (set with the <code>StopTimeControl</code>)
* is reached, calling <code>start</code> again will
* resume the looping playback from where it was stopped until it
* fully reaches the preset loop count.
* <p>
* An <i>END_OF_MEDIA</i> event will be posted
* every time the <code>Player</code> reaches the end of media.
* If the <code>Player</code> loops back to the beginning and
* starts playing again because it has not completed the loop
* count, a <i>STARTED</i> event will be posted.
*
* @param count indicates the number of times the content will be
* played. 1 is the default. 0 is invalid. -1 indicates looping
* indefintely.
* @exception IllegalArgumentException Thrown if the given
* count is invalid.
* @exception IllegalStateException Thrown if the
* <code>Player</code> is in the <i>STARTED</i>
* or <i>CLOSED</i> state.
*/
public void setLoopCount(int count) {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst != null) {
playerInst.setLoopCount(count);
} else {
if (count != 0) {
loopCount = count;
} else {
throw new IllegalArgumentException();
}
}
};
/**
* Add a player listener for this player.
*
* @param playerListener the listener to add.
* If <code>null</code> is used, the request will be ignored.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @see #removePlayerListener
*/
public void addPlayerListener(PlayerListener playerListener) {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst != null) {
playerInst.addPlayerListener(playerListener);
} else {
if (playerListener != null) {
listeners.addElement(playerListener);
}
}
};
/**
* Remove a player listener for this player.
*
* @param playerListener the listener to remove.
* If <code>null</code> is used or the given
* <code>playerListener</code> is not a listener for this
* <code>Player</code>, the request will be ignored.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @see #addPlayerListener
*/
public void removePlayerListener(PlayerListener playerListener) {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst != null) {
playerInst.removePlayerListener(playerListener);
} else {
listeners.removeElement(playerListener);
}
};
/**
* Gets the controls attribute of the BasicPlayer object
*
* @return The controls value
*/
public final Control[] getControls() {
if (playerInst != null) {
return playerInst.getControls();
}
throw new IllegalStateException();
}
/**
* Gets the <code>Control</code> that supports the specified
* class or interface. The full class
* or interface name should be specified.
* <code>Null</code> is returned if the <code>Control</code>
* is not supported.
*
* @param type Description of the Parameter
* @return <code>Control</code> for the class or interface
* name.
*/
public Control getControl(String type) {
if (playerInst != null) {
return playerInst.getControl(type);
}
throw new IllegalStateException();
}
/**
* For global PlayerID management
*
* @param pid Description of the Parameter
* @return Description of the Return Value
*/
public static BasicPlayer get(int pid) {
return (BasicPlayer) (mplayers.get(new Integer(pid)));
}
/**
* Send external volume changed event to all of the player from this VM
*/
public static void sendExternalVolumeChanged(String evt, int volume) {
if (mplayers == null) {
return;
}
/* Send event to player if this player is in realized state (or above) */
for (Enumeration e = mplayers.elements(); e.hasMoreElements();) {
BasicPlayer p = (BasicPlayer) e.nextElement();
int state = p.getState();
if (state >= Player.REALIZED) {
VolumeControl vc = (VolumeControl)p.getControl("VolumeControl");
if (vc != null) {
vc.setLevel(volume);
}
}
}
}
/**
* Pauses and deallocates all media players.
*
* After this call all players are either in realized
* or unrealized state.
*
* Resources are being released during deallocation.
*/
public static void pauseAll() {
vmPaused = true;
if (mplayers == null) {
return;
}
for (Enumeration e = mplayers.elements(); e.hasMoreElements();) {
BasicPlayer p = (BasicPlayer) e.nextElement();
int state = p.getState();
long time = p.getMediaTime();
// save the player's state
pstates.put(p, new Integer(state));
// save the player's media time
mtimes.put(p, new Long(time));
try {
// Stop the player
if (state == Player.STARTED) {
p.stop();
}
} catch(MediaException ex) {
}
}
}
/**
* Resumes all media players' activities.
*
* Players that were in STARTED state when pause
* was called will resume playing at the media time
* they were stopped and deallocated.
*/
public static void resumeAll() {
vmPaused = false;
if (mplayers == null || pstates.size() == 0) {
return;
}
for (Enumeration e = mplayers.elements(); e.hasMoreElements();) {
BasicPlayer p = (BasicPlayer) e.nextElement();
int state = ((Integer) pstates.get(p)).intValue();
long time = ((Long) mtimes.get(p)).longValue();
switch (state) {
/*
case Player.PREFETCHED:
try {
p.prefetch();
p.setMediaTime(time);
} catch (MediaException ex) {
}
break;
*/
case Player.STARTED:
try {
//p.realize();
//p.prefetch();
if (p.getState() != Player.STARTED) {
p.setMediaTime(time);
p.start();
}
} catch (MediaException ex) {
}
break;
}
}
// clear player states and media times
pstates.clear();
mtimes.clear();
}
}