⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wavplayer.java

📁 用于移动设备上的java虚拟机源代码
💻 JAVA
字号:
/* * @(#)WavPlayer.java	1.51 02/11/05 @(#) * * Copyright (c) 1996-2002 Sun Microsystems, Inc.  All rights reserved. * PROPRIETARY/CONFIDENTIAL * Use is subject to license terms. */package com.sun.mmedia;import javax.microedition.media.*;import javax.microedition.media.control.*;import com.sun.mmedia.BasicPlayer;import java.io.IOException;/** * This class implements the wav (audio/x-wav) audio player. */public class WavPlayer extends BasicPlayer implements Runnable {    /**     * the duration of this player     */    private long duration = TIME_UNKNOWN;    /**      * Audio format parameters: sampleRate, channel number, sample size     */    private int sampleRate, channels, sampleSizeInBits;    /**     * byte rate and alignment     */    private int bytesPerSecond, blockAlign;    /**     * Last time when the player is stopped, how many samples have been     * played and the media time at that point      */    private long lastPos, origin;    /**     * waveout lock obj      */    private Object waveLock = new Object();    /**     * play thread obj     */    private Thread playThread;    /**     * a status flag indicating whether this player is started      */    private boolean started;    /**     * a status flag indicating whether this player has been deallocated      */    private boolean interrupted;    /**     * a play lock obj      */    private Object playLock = new Object();    /**     * In source stream, the start position of pcm data     */    private long startpt;    /**     * where the pcm data ends in source stream      */    private long endpt = Long.MAX_VALUE;    /**     * the pointer to native wave out data structure.      */    private int peer;    /**     * The buffer length to read from source stream every time.     */    private int bufLen;    /**     * the data buffer read from source stream      */    private byte[] buffer;        /**     * a pause lock obj      */    private Object pauseLock = new Object();    /**     * a flag indicating if this player could be paused      */    private boolean canPause = true;    /**      * Open the audio device in a particular format.     *      * @param sampleRate the sampleRate of the intended format     * @param bits how many bits per sample of the intended format     * @param channels mono or stereo     * @return the pointer to the wave out data structure, if succeeded.     *         non-positive number if failed.     */    private native int nOpen(int sampleRate, int bits, int channels);         /**     * Pass a data buffer to native code.     *     * @param peer the pointer to the native wave out data structure.     * @param data the data buffer to be written to native wave out     * @param offset the offset in data buffer.     * @param len how many bytes of data to be written.     * @return the acutal number of bytes has been written.     */    private native int nWrite(int peer, byte[] data, int offset, int len);    /**     * Utility functions for wave out     *     * @param peer the pointer to the native wave out data structure.     * @param code functionality code     * @param param parameters for a particular functionality.     * @return status.     */    private native int nCommon(int peer, int code, int param);        /**     * Return the content type.     *     * @return the wav content type.     */    public String getContentType() {	chkClosed(true);	return "audio/x-wav";    }    /**     * Parse the input, realize the player     */    protected void doRealize() throws MediaException {	try {	    readHeader();	    startpt = getStrmLoc();	} catch (IOException e) {	    throw new MediaException(e.getMessage());	}    }            /**     * Get the duration of the media represented by this object.     * The value returned is the media's duration     * when played at the default rate.     * If the duration can't be determined (for example, the media object is     * presenting live * video)  <CODE>getDuration</CODE> returns      * <CODE>TIME_UNKNWON</CODE>.     *     * @return A <CODE>long</CODE> object representing the duration or      * TIME_UNKNWON.     */    public long doGetDuration() {	return duration;    }            /**     * Parse the Wave audio file header.     *     */    protected void readHeader() throws IOException {	if (readInt() != 0x46464952) // RIFF	    throw new IOException("malformed wave data");		readInt();		if (readInt() != 0x45564157) // WAVE	    throw new IOException("malformed wave data");		// Only the required chunks 'fmt ' and 'data' are supported.	// There are no restrictions upon the order of the chunks within 	// a WAVE file, with the exception that the Format chunk must precede	// the Data chunk.		// Skip all chunks until you reach the 'fmt ' chunk	while (readInt() != 0x20746D66) { // FMT	    int size = readInt();	    skipStrm(size);	}		// Handle Format chunk 'fmt ', formatSize	int fmtsize = readInt();	if (fmtsize < 16)	    throw new IOException("bad fmt chunk");	fmtsize -= 16;		int encoding = readShort();	if (encoding != 0x0001) // WF_PCM	    throw new IOException("only supports PCM");	channels = readShort();	sampleRate = readInt();	bytesPerSecond = readInt();	blockAlign = readShort();	sampleSizeInBits = readShort();	// bytesPerSecond and blockAlign might not accurate in the file	// need to calculate 	bytesPerSecond = sampleRate * channels * sampleSizeInBits / 8;	blockAlign = channels * sampleSizeInBits / 8;	// skip the rest of the format chunk	if (fmtsize > 0)	    skipStrm(fmtsize);	// Skip all chunks until you reach the 'data' chunk	while (readInt() != 0x61746164) { // DATA	    int size = readInt();	    skipStrm(size);	}		// Handle Format chunk 'data'	long dataSize = readInt();	endpt = getStrmLoc() + dataSize;	if ((channels * sampleSizeInBits / 8) == blockAlign) {	    duration = (dataSize*1000000L)/bytesPerSecond;	} else {	    duration = TIME_UNKNOWN;	}	return;    }    /**     * Get the resources ready.     */    protected void doPrefetch() throws MediaException {	// Open the audio device.	synchronized (waveLock) {	    if (peer == 0) {		peer = nOpen(sampleRate, sampleSizeInBits, channels);		if (peer <= 0) {		    throw new MediaException("can't open audio device");		}		bufLen = nCommon(peer, 9, 0);		buffer = new byte[bufLen];		if (getLevel() == -1)		    setLevel(nCommon(peer, 8, 0));	    }	}	if (isMuted()) {	    nCommon(peer, 7, 0);	} else {	    nCommon(peer, 7, getLevel());	}    }    /**     * Start the playback.     * @return the status if the player has been successfully started.     */    protected boolean doStart() {	if (started)	    return true;	started = true;	// Start the playback loop.	synchronized (playLock) {	    if (playThread == null) {		playThread = new Thread(this);		playThread.start();	    } else		playLock.notifyAll();	}	    	nCommon(peer, 2, 0); // RESUME	return true;    }    /**     * Stop the playback loop.     */    protected void doStop() {	if (!started)	    return;		started = false;	synchronized (pauseLock) {	    while (!canPause)		try {		    pauseLock.wait();		} catch (Exception ex) {		}	    nCommon(peer, 1, 0); // PAUSE	    pauseLock.notifyAll();	}    }    /**     * Deallocate the exclusing resource.     */    protected void doDeallocate() {	// Interrupt the playback loop.	// If the playThread had not been started, we'll need	// to explicitly close the device.	if (state == PREFETCHED && playThread == null) {	    nCommon(peer, 5, 0); // CLOSE	    return;	}	synchronized (playLock) {	    interrupted = true;	    // Wake up the run loop if it was stopped.	    playLock.notifyAll();	    // Wait for the playback loop to completely stop before 	    // returning.  There's a maximum wait limit set here in 	    // case anything goes wrong.	    if (playThread != null) {		try {		    playLock.wait(5000);		} catch (Exception e) {}	    }	}    }    /**     * Close the player.     */    protected void doClose() {	// Deallocate would have been called before this.	// So all the resources should have been released.    }    /**     * 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.     */    protected long doSetMediaTime(long now) throws MediaException {	long ret = now;	try {	    long pp = (bytesPerSecond * now / 1000000L / blockAlign) *		blockAlign + startpt;	    if (getState() == STARTED)		doStop();	    nCommon(peer, 3, 0); // FLUSH	    lastPos = nCommon(peer, 6, 0); // SAMPLES_PLAYED	    ret = seekStrm(pp);	    ret = (ret-startpt) * 1000000L / bytesPerSecond;	    origin = ret;	    if (getState() == STARTED)		doStart();	} catch (Exception e) {	    throw new MediaException(e.getMessage());	}	return ret;    }    /**     * Gets this player's current <i>media time</i>     * in microseconds.     *      * @return The current <i>media time</i> in microseconds.     */    public long doGetMediaTime() {	long pos = 0;	long mtime;	synchronized (waveLock) {	    if (sampleRate == 0)		return 0;	    pos = nCommon(peer, 6, 0); /* SAMPLES_PLAYED */	}	// Media time is in micro-seconds	mtime = ((pos - lastPos) * 1000000L) / sampleRate + origin;	return (mtime < 0 ? 0 : mtime);    }    /**     * 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.     */    protected Control doGetControl(String type) {	if ((getState() >= REALIZED) && 	    type.equals("javax.microedition.media.control.VolumeControl")) {	    return this;	}	return null;    }        /**     * error string      */    private String errMsg = null;        /**     * Read the data from the source and write them to the waveout in native.     * @return the status.     */    private boolean doProcess() {	int len = 0, wlen = 0;		try {	    len = readBytes(buffer, 0, bufLen);	} catch (IOException ioe) {	    errMsg = ioe.getMessage();	    return false;	}	if (len < 1) {	    synchronized (pauseLock) {		canPause = false;		try {		    while (nCommon(peer, 4, 0) != 1) // DRAIN			pauseLock.wait(20);		} catch (Exception ex) {}		canPause = true;		pauseLock.notifyAll();	    }	    Thread.yield();	    started = false;	    sendEvent(PlayerListener.END_OF_MEDIA, new Long(getMediaTime()));	    return true;	}	synchronized (pauseLock) {	    canPause = false;	    while ((wlen = nWrite(peer, buffer, 0, len)) == 0) {		try {		    pauseLock.wait(16);		} catch (Exception ex) {}	    }	    canPause = true;	    pauseLock.notifyAll();	}	if (wlen == -1) 	    return false;		return true;    }        /**     * Main process loop driving the media flow.     */    public void run() {	boolean statusOK = true;	while (true) {	    while (!interrupted && started && statusOK) {		statusOK = doProcess();		Thread.yield();	    }	    synchronized (playLock) {		if (interrupted || !statusOK)		    break;		try {		    playLock.wait();		} catch (Exception ex) {}	    }	} // end of while (true)	// Close the audio device, exit safely out of the process loop.	nCommon(peer, 3, 0); // FLUSH	synchronized (waveLock) {	    nCommon(peer, 5, 0); // CLOSE	    peer = 0;	    interrupted = started = false;	}	lastPos = 0;	synchronized (playLock) {	    playThread = null;	    // Notify the blocking deallocate that we are done with	    // the process loop.	    playLock.notifyAll();	}	if (!statusOK) {	    if (stream != null) {		try {		    stream.close();		} catch (IOException ex) {}	    }	    sendEvent(PlayerListener.ERROR, errMsg);	}    }    /**     * ====================================     * Read calls to read from SourceStream     * ====================================     */    /**     * Read bytes from source stream.     * @param array the byte array to hold the data     * @param offset the offset in the byte array     * @param num the number of bytes to be read     * @return the actual number of bytes has been read     */    private int readBytes(byte[] array, int offset, int num) throws     IOException {	if (num == 0) {	    return 0;	}	long cpos = getStrmLoc();	long available = endpt - cpos;	if (available <= 0) {	    return -1;	}		if (num > available) {	    num = (int) available;	}	int rem = num;	int read = 0;	while (rem > 0) {	    try {		read = readStrm(array, offset, rem);	    } catch (IOException e) {		return -1;	    }	    if (read == -1) {	// End of stream		if (rem == num) {		    return -1;		} else {		    return num - rem;		}	    }	    rem -= read;	    offset += read;	}	return num;    }    /**     * temporary buffer     */    private byte [] intArray = new byte[4];    /**     * Read an integer from source stream     * @return the integer read.     * @throws IOExeption if there is an error     */    private int readInt() throws IOException {	if (readBytes(intArray, 0, 4) < 4)	    throw new IOException("malformed wave data");	return ((intArray[3] & 0xFF) << 24) |	    ((intArray[2] & 0xFF) << 16) |	    ((intArray[1] & 0xFF) << 8) |	    (intArray[0] & 0xFF);    }    /**     * Read a short from source stream     * @return the short read     * @throws IOException if there is an error     */    private short readShort() throws IOException {	if (readBytes(intArray, 0, 2) < 2)	    throw new IOException("malformed wave data");	return (short) (((intArray[1] & 0xFF) << 8) |		(intArray[0] & 0xFF));    }    /**     * ==========================     * Methods for VolumeControl.     * ==========================     */    /**     * The worker method to actually obtain the control.     *     * @param vol the volume level to be set.       * @return the actual level has been set.     */    protected int doSetLevel(int vol) {	// 0 <= vol <= 100	synchronized (waveLock) {	    if (peer > 0) {		nCommon(peer, 7, vol); // SETVOL	    }	}	return vol;    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -