📄 basicplayer.java
字号:
/* * @(#)BasicPlayer.java 1.69 02/09/11 @(#) * * Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved. * PROPRIETARY/CONFIDENTIAL * Use is subject to license terms. */package com.sun.mmedia;import java.io.*;import java.util.Vector;import javax.microedition.io.*;import javax.microedition.media.*;import java.util.Hashtable;import javax.microedition.media.control.*;/** * BasicPlayer provides basic implementation for the Player methods. * Many of the methods call do<method> to do the actual work that can * be overridden by subclasses. */public abstract class BasicPlayer implements Player, VolumeControl { /** * global player id */ private static int pcount = -1; /** * hastable to map playerID to instances */ private static Hashtable mplayers = new Hashtable(4); /** * lock object */ private static Object idLock = new Object(); /** * the locator of this player */ private String locator; /** * the state of this player */ int state = UNREALIZED; /** * the loopCount of this player */ int loopCountSet = 1, loopCount; /** * the flag to indicate whether the Player is currently paused at EOM. * If true, the Player will seek back to the beginning when * restarted. */ boolean EOM = false; /** * the flag to indicate looping after EOM. */ boolean loopAfterEOM = false; /** * this player's playerlisteners */ Vector listeners = new Vector(2); /** * Asynchronous event mechanism. */ EvtQ evtQ = null; /** * event queue lock obj */ Object evtLock = new Object(); /** * player ID of this player */ protected int pID = 0; /** * the default constructor */ public BasicPlayer() { synchronized (idLock) { pcount = (pcount+1) % 32767; pID = pcount; } mplayers.put(new Integer(pID), this); } /** * Check to see if the Player is closed. If the * unrealized boolean flag is true, check also to * see if the Player is UNREALIZED. * * @param unrealized the flag whether to check the unrealized state. */ protected void chkClosed(boolean unrealized) { if (state == CLOSED || (unrealized && state == UNREALIZED)) { throw new IllegalStateException("The Player is " + (state == CLOSED ? "closed" : "unrealized")); } } /** * 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, * 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) throws IllegalArgumentException, IllegalStateException { chkClosed(false); if (state == STARTED) throw new IllegalStateException("setLoopCount"); if (count == 0 || count < -1) throw new IllegalArgumentException("setLoopCount"); loopCountSet = count; loopCount = count; } /** * 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 synchronized void realize() throws MediaException { chkClosed(false); if (state >= REALIZED) return; doRealize(); state = REALIZED; } /** * The worker method to realize the player. * */ abstract protected void doRealize() throws MediaException; /** * 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 synchronized void prefetch() throws MediaException { chkClosed(false); if (state >= PREFETCHED) return; if (state < REALIZED) realize(); doPrefetch(); state = PREFETCHED; } /** * the worker method to prefetch the player */ abstract protected void doPrefetch() throws MediaException; /** * Starts the <code>Player</code> as soon as possible. * If the <code>Player</code> was previously stopped * by calling <code>stop</code>, * 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 synchronized void start() throws MediaException { chkClosed(false); if (state >= STARTED) return; if (state < REALIZED) realize(); if (state < PREFETCHED) prefetch(); // If it's at the EOM, it will automatically // loop back to the beginning. if (EOM) setMediaTime(0); if (!doStart()) throw new MediaException("start"); state = STARTED; sendEvent(PlayerListener.STARTED, new Long(getMediaTime())); } /** * The worker method to actually start the player * * @return Whether the player is successfully started */ abstract protected boolean doStart(); /** * 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. */ public synchronized void stop() { chkClosed(false); loopAfterEOM = false; if (state < STARTED) return; doStop(); state = PREFETCHED; sendEvent(PlayerListener.STOPPED, new Long(getMediaTime())); } /** * the worker method to stop the player */ abstract protected void doStop(); /** * 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 synchronized void deallocate() { chkClosed(false); loopAfterEOM = false; if (state < PREFETCHED) return; if (state == STARTED) stop(); doDeallocate(); state = REALIZED; } /** * the worker method to deallocate the player */ abstract protected void doDeallocate(); /** * 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 synchronized void close() { if (state == CLOSED) return; deallocate(); doClose(); state = CLOSED; try { if (stream != null) stream.close(); } catch (IOException e) { } sendEvent(PlayerListener.CLOSED, null); mplayers.remove(new Integer(pID)); } /** * the worker method to close the player */ abstract protected void doClose(); /** * 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 synchronized long setMediaTime(long now) throws MediaException { chkClosed(true); if (now < 0) now = 0; long theDur = getDuration(); if ((theDur != TIME_UNKNOWN) && (now > theDur)) now = theDur; long rtn = doSetMediaTime(now); EOM = false; return rtn; } /** * The worker method to actually set player's media time. * * @param now The new media time in microseconds. * @return The actual media time set in microseconds. * @exception MediaException Thrown if an error occurs * while setting the media time. */ abstract protected long doSetMediaTime(long now) throws MediaException; /** * Gets this <code>Player</code>'s current <i>media time</i>. * If the <i>media time</i> cannot be determined, * <code>getMediaTime</code> returns <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() { chkClosed(false); return doGetMediaTime(); } /** * The actual worker method to gets this player's * current <i>media time</i> in microseconds. * * @return The current <i>media time</i> in microseconds. */ abstract protected long doGetMediaTime(); /** * 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() { /** * A race condition can occur between * the return of this method and the execution of * a state changing method. */ return state; } /** * 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -