📄 basicplayer.java
字号:
*/ public long getDuration() { chkClosed(false); return doGetDuration(); } /** * The actual worker method to retrieve the duration. * * @return A <CODE>long</CODE> object representing the duration or * TIME_UNKNWON. */ abstract protected long doGetDuration(); /** * 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) { chkClosed(false); 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) { chkClosed(false); listeners.removeElement(playerListener); } /** * Deliver the events to the player listeners. * * @param evt the evt type * @param evtData the data associated with this event. * */ public void sendEvent(String evt, Object evtData) { // There's always one listener for EOM -- itself. if (listeners.size() == 0 && evt != PlayerListener.END_OF_MEDIA) return; // Deliver the event to the listeners. synchronized (evtLock) { if (evtQ == null) evtQ = new EvtQ(this); evtQ.sendEvent(evt, evtData); } } /** * the worker method to deliver EOM event */ synchronized void doLoop() { // If a loop count is set, we'll loop back to the beginning. if ((loopCount > 1) || (loopCount == -1)) { try { if (setMediaTime(0) == 0) { if (loopCount > 1) loopCount--; start(); } else loopCount = 1; } catch (MediaException ex) { loopCount = 1; } } else if (loopCountSet > 1) loopCount = loopCountSet; loopAfterEOM = false; } /** * Obtain the collection of <code>Control</code>s * from this player. * @return the collection of <code>Control</code> objects. */ public Control[] getControls() { chkClosed(true); return new Control[] { this }; } /** * 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 the class name of the <code>Control</code>. * @return <code>Control</code> for the class or interface * name. */ public Control getControl(String type) { chkClosed(true); // Prepend the package name if the type given does not // have the package prefix. if (type.indexOf('.') < 0) return doGetControl("javax.microedition.media.control." + type); return doGetControl(type); } /** * The worker method to actually obtain the control. * * @param type the class name of the <code>Control</code>. * @return <code>Control</code> for the class or interface * name. */ abstract protected Control doGetControl(String type); /** * =============================== * For global PlayerID management * =============================== */ /** * Obtain a BasicPlayer instance based on the global id. * * @param pid the given global id. * @return the instance of BasicPlayer associated with given global id * */ public static BasicPlayer get(int pid) { return (BasicPlayer)(mplayers.get(new Integer(pid))); } /** * ========================== * Methods for VolumeControl. * ========================== */ /** * volume level */ private int level = -1; /** * mute state */ private boolean mute; /** * The worker method to actually obtain the control. * * @param vol the volume level to be set. * @return the actual level has been set. */ protected abstract int doSetLevel(int vol); /** * set player mute. * * @param mute the flag to mute the player or not * */ public void setMute(boolean mute) { if (mute && !this.mute) { doSetLevel(0); this.mute = true; sendEvent(PlayerListener.VOLUME_CHANGED, this); } else if (!mute && this.mute) { this.level = doSetLevel(level); this.mute = false; sendEvent(PlayerListener.VOLUME_CHANGED, this); } } /** * Check if this player is muted. * * @return The mute state. */ public boolean isMuted() { return mute; } /** * Set the volume using a linear point scale 0 to 100. * @param ll The new volume specified in the level scale. * @return The level that was actually set. */ public int setLevel(int ll) { int newl; if (ll < 0) { ll = 0; } else if (ll > 100) { ll = 100; } if (!mute) { newl = doSetLevel(ll); if (newl != level) { level = newl; sendEvent(PlayerListener.VOLUME_CHANGED, this); } } return level; } /** * Get the current volume set for this * player. * * @return The volume in the level scale (0-100). */ public int getLevel() { return level; } /** * ================ * Input functions. * ================ */ /** * the source input stream of this player */ protected InputStream stream; /** * the current position in source stream */ long location; /** * Set the locator of this player. * * @param locator the locator to be set. * @param con the flag if to make the connection * */ public void setLocator(String locator, boolean con) throws IOException, MediaException { this.locator = locator; if (con) openConnection(); } /** * Set the input stream of this player. * * @param stream the input stream to be set. * */ public void setStrm(InputStream stream) { this.stream = stream; } /** * establish the connection with the source. * */ private void openConnection() throws IOException, MediaException { try { HttpConnection httpCon = (HttpConnection)Connector.open(locator); int rescode = httpCon.getResponseCode(); // both 4XX and 5XX are error codes if (rescode >= 400) { httpCon.close(); throw new IOException("bad url"); } else { stream = httpCon.openInputStream(); String ctype = httpCon.getType(); boolean supportedCT = false; if (locator.endsWith(".wav")) { supportedCT = true; } else if (ctype != null && ctype.toLowerCase().equals("audio/x-wav")) { supportedCT = true; } httpCon.close(); if (!supportedCT) { stream.close(); stream = null; throw new MediaException("unsupported media type"); } } } catch (IOException ioex) { throw ioex; } catch (MediaException mex) { throw mex; } catch (Exception ex) { new IOException(ex.getMessage() + " failed to connect"); } location = 0; } /** * Read a data buffer from source stream. * * @param buffer the byte array to hold the read data * @param offset the offset of byte array. * @param length the maximum bytes to be read * @return the actual number of bytes have been read */ protected int readStrm(byte buffer[], int offset, int length) throws IOException { int len = stream.read(buffer, offset, length); if (len > 0) location += len; return len; } /** * In source stream, seek to a particular position * * @param where the position intended to seek to. * @return the actual position seeked to. * @exception an error occurs during the seeking */ protected long seekStrm(long where) throws IOException, MediaException { if (stream == null) return location; long skipped, oldLocation = location; if (where < oldLocation) { // seek backward reopenStrm(); location = 0; skipped = stream.skip(where); } else { skipped = stream.skip((where - oldLocation)); } if (skipped > 0) location += skipped; return location; } /** * This is a skip fully method * * @param numBytes the number of bytes intended to skip. * @return the actual number of bytes has been skipped. * @exception if an error occurs or skipped bytes is less * then the intended numBytes. */ protected long skipStrm(int numBytes) throws IOException { long skipped = stream.skip(numBytes); if (skipped > 0) location += skipped; if (skipped < numBytes) throw new IOException("skipped over eom"); return (skipped); } /** * Re-open the source stream. * * @exception if an error occurs. */ private void reopenStrm() throws IOException, MediaException { try { stream.reset(); return; } catch (IOException ex) { if (locator == null) throw ex; } try { stream.close(); stream = null; } catch (IOException e) {} openConnection(); } /** * Get the current position of the source stream * * @return the current position. */ protected long getStrmLoc() { return location; }}/** * The thread that's responsible for delivering Player events. * This class lives for only 5 secs. If no event comes in * 5 secs, it will exit. */class EvtQ extends Thread { /** * the player instance */ private BasicPlayer p; /** * event type array */ private String[] evtQ; /** * event data array */ private Object[] evtDataQ; /** * head and tail pointer of the event queue */ private int head, tail; /** * the default size of the event queue */ private static final int size = 12; /** * The constructor * * @param p the instance of BasicPlayer intending to post event to * this event queue. */ EvtQ(BasicPlayer p) { this.p = p; evtQ = new String[size]; evtDataQ = new Object[size]; start(); } /** * Put an event in the event queue and wake up the thread to * deliver it. If the event queue is filled, block. * * @param evt the evt type * @param evtData the event data */ synchronized void sendEvent(String evt, Object evtData) { // Wait if the event queue is full. // This potentially will block the Player's main thread. while ((head + 1) % size == tail) { try { wait(); } catch (Exception e) { } } evtQ[head] = evt; evtDataQ[head] = evtData; if (++head == size) head = 0; notify(); } /** * the run method for interface Runnable */ public void run() { String evt = ""; Object evtData = null; boolean evtToGo = false; for (;;) { synchronized (this) { // If the queue is empty, we'll wait for at most // 5 secs. if (head == tail) { try { wait(5000); } catch (Exception e) { } } if (head != tail) { evt = evtQ[tail]; evtData = evtDataQ[tail]; // For garbage collection. evtDataQ[tail] = null; evtToGo = true; if (++tail == size) tail = 0; notify(); } else evtToGo = false; } // synchronized this if (evtToGo) { if (evt == PlayerListener.END_OF_MEDIA) { synchronized (p) { p.EOM = true; p.loopAfterEOM = false; if (p.state > Player.PREFETCHED) { p.state = Player.PREFETCHED; if (p.loopCount > 1 || p.loopCount == -1) { p.loopAfterEOM = true; } } } } synchronized (p.listeners) { PlayerListener l; for (int i = 0; i < p.listeners.size(); i++) { try { l = (PlayerListener)p.listeners.elementAt(i); l.playerUpdate(p, evt, evtData); } catch (Exception e) { System.err.println("Error in playerUpdate: " + e); } } } if (p.loopAfterEOM) p.doLoop(); } if (!evtToGo || evt == PlayerListener.CLOSED) { // If there's no event waking up after 5 secs, // we'll kill the thread. synchronized (p.evtLock) { p.evtQ = null; break; } } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -