BasicPlayer.java :  » Music » yoyoplayer » com » hadeslee » yoyoplayer » player » Java Open Source

Java Open Source » Music » yoyoplayer 
yoyoplayer » com » hadeslee » yoyoplayer » player » BasicPlayer.java
/*
 * BasicPlayer.
 *
 * JavaZOOM : jlgui@javazoom.net
 *            http://www.javazoom.net
 *
 *-----------------------------------------------------------------------
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library General Public License as published
 *   by the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   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 Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *----------------------------------------------------------------------
 */
package com.hadeslee.yoyoplayer.player;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Control;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
import javazoom.spi.PropertiesContainer;
import org.tritonus.share.sampled.TAudioFormat;
import org.tritonus.share.sampled.file.TAudioFileFormat;
import static com.hadeslee.yoyoplayer.player.BasicPlayerEvent.*;

/**
 * BasicPlayer is a threaded simple player class based on JavaSound API.
 * It has been successfully tested under J2SE 1.3.x, 1.4.x and 1.5.x.
 */
@SuppressWarnings("unchecked")
public class BasicPlayer implements BasicController, Runnable {

    public static int EXTERNAL_BUFFER_SIZE = 4000 * 4;
    public static int SKIP_INACCURACY_SIZE = 512;
    protected Thread m_thread = null;
    protected Object m_dataSource;
    protected AudioInputStream m_encodedaudioInputStream;
    protected int encodedLength = -1;
    protected AudioInputStream m_audioInputStream;
    protected AudioFileFormat m_audioFileFormat;
    protected SourceDataLine m_line;
    protected FloatControl m_gainControl;
    protected FloatControl m_panControl;
    protected String m_mixerName = null;
    private int m_lineCurrentBufferSize = -1;
    private int lineBufferSize = -1;
    private long threadSleep = -1;
    private static Logger log = Logger.getLogger(BasicPlayer.class.getName());
    /**
     * These variables are used to distinguish stopped, paused, playing states.
     * We need them to control Thread.
     */
//    public static final int UNKNOWN = -1;
//    public static final int PLAYING = 0;
//    public static final int PAUSED = 1;
//    public static final int STOPPED = 2;
//    public static final int OPENED = 3;
//    public static final int SEEKING = 4;
    private int m_status = UNKNOWN;
    private Map empty_map = new HashMap();
    private BasicPlayerEventLauncher laucher;//

    /**
     * Constructs a Basic Player.
     */
    public BasicPlayer() {
        m_dataSource = null;
        laucher = new BasicPlayerEventLauncher();
        laucher.start();
        reset();
    }

    protected void reset() {
        m_status = UNKNOWN;
        if (m_audioInputStream != null) {
            synchronized (m_audioInputStream) {
                closeStream();
            }
        }
        m_audioInputStream = null;
        m_audioFileFormat = null;
        m_encodedaudioInputStream = null;
        encodedLength = -1;
        if (m_line != null) {
            m_line.stop();
            m_line.close();
            m_line = null;
        }
        m_gainControl = null;
        m_panControl = null;
    }

    /**
     * Add listener to be notified.
     * @param bpl
     */
    public void addBasicPlayerListener(BasicPlayerListener bpl) {
        laucher.addBasicPlayerListener(bpl);
    }

    /**
     * Return registered listeners.
     * @return
     */
    public Collection getListeners() {
        return laucher.getBasicPlayerListeners();
    }

    /**
     * Remove registered listener.
     * @param bpl
     */
    public void removeBasicPlayerListener(BasicPlayerListener bpl) {
        laucher.removeBasicPlayerListener(bpl);
    }

    /**
     * Set SourceDataLine buffer size. It affects audio latency.
     * (the delay between line.write(data) and real sound).
     * Minimum value should be over 10000 bytes.
     * @param size -1 means maximum buffer size available.
     */
    public void setLineBufferSize(int size) {
        lineBufferSize = size;
    }

    /**
     * Return SourceDataLine buffer size.
     * @return -1 maximum buffer size.
     */
    public int getLineBufferSize() {
        return lineBufferSize;
    }

    /**
     * Return SourceDataLine current buffer size.
     * @return
     */
    public int getLineCurrentBufferSize() {
        return m_lineCurrentBufferSize;
    }

    /**
     * Set thread sleep time.
     * Default is -1 (no sleep time).
     * @param time in milliseconds.
     */
    public void setSleepTime(long time) {
        threadSleep = time;
    }

    /**
     * Return thread sleep time in milliseconds.
     * @return -1 means no sleep time.
     */
    public long getSleepTime() {
        return threadSleep;
    }

    /**
     * Returns BasicPlayer status.
     * @return status
     */
    public int getStatus() {
        return m_status;
    }

    /**
     * Open file to play.
     */
    public void open(File file) throws BasicPlayerException {
        log.info("open(" + file + ")");
        if (file != null) {
            m_dataSource = file;
            initAudioInputStream();
        }
    }

    /**
     * Open URL to play.
     */
    public void open(URL url) throws BasicPlayerException {
        log.info("open(" + url + ")");
        if (url != null) {
            m_dataSource = url;
            initAudioInputStream();
        }
    }

    /**
     * Open inputstream to play.
     */
    public void open(InputStream inputStream) throws BasicPlayerException {
        log.info("open(" + inputStream + ")");
        if (inputStream != null) {
            m_dataSource = inputStream;
            initAudioInputStream();
        }
    }

    /**
     * Inits AudioInputStream and AudioFileFormat from the data source.
     * @throws BasicPlayerException
     */
    protected void initAudioInputStream() throws BasicPlayerException {
        try {
            reset();
            notifyEvent(BasicPlayerEvent.OPENING, getEncodedStreamPosition(), -1, m_dataSource);
            if (m_dataSource instanceof URL) {
                initAudioInputStream((URL) m_dataSource);
            } else if (m_dataSource instanceof File) {
                initAudioInputStream((File) m_dataSource);
            } else if (m_dataSource instanceof InputStream) {
                initAudioInputStream((InputStream) m_dataSource);
            }
            createLine();
            // Notify listeners with AudioFileFormat properties.
            Map properties = null;
            if (m_audioFileFormat instanceof TAudioFileFormat) {
                // Tritonus SPI compliant audio file format.
                properties = ((TAudioFileFormat) m_audioFileFormat).properties();
                // Clone the Map because it is not mutable.
                properties = deepCopy(properties);
            } else {
                properties = new HashMap();
            }
            // Add JavaSound properties.
            if (m_audioFileFormat.getByteLength() > 0) {
                properties.put("audio.length.bytes", new Integer(m_audioFileFormat.getByteLength()));
            }
            if (m_audioFileFormat.getFrameLength() > 0) {
                properties.put("audio.length.frames", new Integer(m_audioFileFormat.getFrameLength()));
            }
            if (m_audioFileFormat.getType() != null) {
                properties.put("audio.type", (m_audioFileFormat.getType().toString()));
            }
            // Audio format.
            AudioFormat audioFormat = m_audioFileFormat.getFormat();
            if (audioFormat.getFrameRate() > 0) {
                properties.put("audio.framerate.fps", new Float(audioFormat.getFrameRate()));
            }
            if (audioFormat.getFrameSize() > 0) {
                properties.put("audio.framesize.bytes", new Integer(audioFormat.getFrameSize()));
            }
            if (audioFormat.getSampleRate() > 0) {
                properties.put("audio.samplerate.hz", new Float(audioFormat.getSampleRate()));
            }
            if (audioFormat.getSampleSizeInBits() > 0) {
                properties.put("audio.samplesize.bits", new Integer(audioFormat.getSampleSizeInBits()));
            }
            if (audioFormat.getChannels() > 0) {
                properties.put("audio.channels", new Integer(audioFormat.getChannels()));
            }
            if (audioFormat instanceof TAudioFormat) {
                // Tritonus SPI compliant audio format.
                Map addproperties = ((TAudioFormat) audioFormat).properties();
                properties.putAll(addproperties);
            }
            // Add SourceDataLine
            properties.put("basicplayer.sourcedataline", m_line);
            Iterator<BasicPlayerListener> it = laucher.getBasicPlayerListeners().iterator();
            while (it.hasNext()) {
                BasicPlayerListener bpl = it.next();
                bpl.opened(m_dataSource, properties);
            }
            m_status = OPENED;
            notifyEvent(BasicPlayerEvent.OPENED, getEncodedStreamPosition(), -1, null);
        } catch (LineUnavailableException e) {
            throw new BasicPlayerException(e);
        } catch (UnsupportedAudioFileException e) {
            throw new BasicPlayerException(e);
        } catch (IOException e) {
            throw new BasicPlayerException(e);
        }
    }

    /**
     * Inits Audio ressources from file.
     */
    protected void initAudioInputStream(File file) throws UnsupportedAudioFileException, IOException {
        m_audioInputStream = AudioSystem.getAudioInputStream(file);
        m_audioFileFormat = AudioSystem.getAudioFileFormat(file);
    }

    /**
     * Inits Audio ressources from URL.
     */
    protected void initAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException {
        m_audioInputStream = AudioSystem.getAudioInputStream(url);
        m_audioFileFormat = AudioSystem.getAudioFileFormat(url);
    }

    /**
     * Inits Audio ressources from InputStream.
     */
    protected void initAudioInputStream(InputStream inputStream) throws UnsupportedAudioFileException, IOException {
        m_audioInputStream = AudioSystem.getAudioInputStream(inputStream);
        m_audioFileFormat = AudioSystem.getAudioFileFormat(inputStream);
    }

    /**
     * Inits Audio ressources from AudioSystem.<br>
     */
    protected void initLine() throws LineUnavailableException {
        log.info("initLine()");
        if (m_line == null) {
            createLine();
        }
        if (!m_line.isOpen()) {
            openLine();
        } else {
            AudioFormat lineAudioFormat = m_line.getFormat();
            AudioFormat audioInputStreamFormat = m_audioInputStream == null ? null : m_audioInputStream.getFormat();
            if (!lineAudioFormat.equals(audioInputStreamFormat)) {
                m_line.close();
                openLine();
            }
        }
    }

    /**
     * Inits a DateLine.<br>
     *
     * We check if the line supports Gain and Pan controls.
     *
     * From the AudioInputStream, i.e. from the sound file, we
     * fetch information about the format of the audio data. These
     * information include the sampling frequency, the number of
     * channels and the size of the samples. There information
     * are needed to ask JavaSound for a suitable output line
     * for this audio file.
     * Furthermore, we have to give JavaSound a hint about how
     * big the internal buffer for the line should be. Here,
     * we say AudioSystem.NOT_SPECIFIED, signaling that we don't
     * care about the exact size. JavaSound will use some default
     * value for the buffer size.
     */
    protected void createLine() throws LineUnavailableException {
        log.info("Create Line");
        if (m_line == null) {
            AudioFormat sourceFormat = m_audioInputStream.getFormat();
            log.info("Create Line : Source format : " + sourceFormat.toString());
            int nSampleSizeInBits = sourceFormat.getSampleSizeInBits();
            if (nSampleSizeInBits <= 0) {
                nSampleSizeInBits = 16;
            }
            if ((sourceFormat.getEncoding() == AudioFormat.Encoding.ULAW) || (sourceFormat.getEncoding() == AudioFormat.Encoding.ALAW)) {
                nSampleSizeInBits = 16;
            }
            if (nSampleSizeInBits != 8) {
                nSampleSizeInBits = 16;
            }
            AudioFormat targetFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, sourceFormat.getSampleRate(), nSampleSizeInBits, sourceFormat.getChannels(), sourceFormat.getChannels() * (nSampleSizeInBits / 8), sourceFormat.getSampleRate(), false);
            log.info("Create Line : Target format: " + targetFormat);
            // Keep a reference on encoded stream to progress notification.
            m_encodedaudioInputStream = m_audioInputStream;
            try {
                // Get total length in bytes of the encoded stream.
                encodedLength = m_encodedaudioInputStream.available();
            } catch (IOException e) {
                log.log(Level.SEVERE, "Cannot get m_encodedaudioInputStream.available()", e);
            }
            // Create decoded stream.
            m_audioInputStream = AudioSystem.getAudioInputStream(targetFormat, m_audioInputStream);
            AudioFormat audioFormat = m_audioInputStream.getFormat();
            DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat, -1);
            Mixer mixer = getMixer(m_mixerName);
            if (mixer != null) {
                log.info("Mixer : " + mixer.getMixerInfo().toString());
                m_line = (SourceDataLine) mixer.getLine(info);
            } else {
                m_line = (SourceDataLine) AudioSystem.getLine(info);
                m_mixerName = null;
            }
            log.info("Line : " + m_line.toString());
            log.info("Line Info : " + m_line.getLineInfo().toString());
            log.info("Line AudioFormat: " + m_line.getFormat().toString());
        }
    }

    /**
     * Opens the line.
     */
    protected void openLine() throws LineUnavailableException {
        if (m_line != null) {
            AudioFormat audioFormat = m_audioInputStream.getFormat();
            int buffersize = lineBufferSize;
            if (buffersize <= 0) {
                buffersize = m_line.getBufferSize();
            }
            m_lineCurrentBufferSize = buffersize;
            m_line.open(audioFormat, buffersize);
            log.info("Open Line : BufferSize=" + buffersize);
            /*-- Display supported controls --*/
            Control[] c = m_line.getControls();
            for (int p = 0; p < c.length; p++) {
                log.info("Controls : " + c[p].toString());
            }
            /*-- Is Gain Control supported ? --*/
            if (m_line.isControlSupported(FloatControl.Type.MASTER_GAIN)) {
                m_gainControl = (FloatControl) m_line.getControl(FloatControl.Type.MASTER_GAIN);
                log.info("Master Gain Control : [" + m_gainControl.getMinimum() + "," + m_gainControl.getMaximum() + "] " + m_gainControl.getPrecision());
            }
            /*-- Is Pan control supported ? --*/
            if (m_line.isControlSupported(FloatControl.Type.PAN)) {
                m_panControl = (FloatControl) m_line.getControl(FloatControl.Type.PAN);
                log.info("Pan Control : [" + m_panControl.getMinimum() + "," + m_panControl.getMaximum() + "] " + m_panControl.getPrecision());
            }
        }
    }

    /**
     * Stops the playback.<br>
     *
     * Player Status = STOPPED.<br>
     * Thread should free Audio ressources.
     */
    protected void stopPlayback() {
        if ((m_status == PLAYING) || (m_status == PAUSED)) {
            if (m_line != null) {
                m_line.flush();
                m_line.stop();
            }
            m_status = STOPPED;
            synchronized (m_audioInputStream) {
                m_audioInputStream.notifyAll();
            }
            notifyEvent(BasicPlayerEvent.STOPPED, getEncodedStreamPosition(), -1, null);
            synchronized (m_audioInputStream) {
                closeStream();
            }
            log.info("stopPlayback() completed");
        }
    }

    /**
     * Pauses the playback.<br>
     *
     * Player Status = PAUSED.
     */
    protected void pausePlayback() {
        if (m_line != null) {
            if (m_status == PLAYING) {
//                m_line.flush();
                m_line.stop();
                m_status = PAUSED;
                log.info("pausePlayback() completed");
                notifyEvent(BasicPlayerEvent.PAUSED, getEncodedStreamPosition(), -1, null);
            }
        }
    }

    /**
     * Resumes the playback.<br>
     *
     * Player Status = PLAYING.
     */
    protected void resumePlayback() {
        if (m_line != null) {
            if (m_status == PAUSED) {
                m_line.start();
                m_status = PLAYING;
                synchronized (m_audioInputStream) {
                    m_audioInputStream.notifyAll();
                }
                log.info("resumePlayback() completed");
                notifyEvent(BasicPlayerEvent.RESUMED, getEncodedStreamPosition(), -1, null);
            }
        }
    }

    /**
     * Starts playback.
     */
    protected void startPlayback() throws BasicPlayerException {
        if (m_status == STOPPED) {
            initAudioInputStream();
        }
        if (m_status == OPENED) {
            log.info("startPlayback called");
            if (!(m_thread == null || !m_thread.isAlive())) {
                log.warning("WARNING: old thread still running!!");
                int cnt = 0;
                while (m_status != OPENED) {
                    try {
                        if (m_thread != null) {
                            log.info("Waiting ... " + cnt);
                            cnt++;
                            Thread.sleep(1000);
                            if (cnt > 2) {
                                m_thread.interrupt();
                            }
                        }
                    } catch (InterruptedException e) {
                        throw new BasicPlayerException(BasicPlayerException.WAITERROR, e);
                    }
                }
            }
            // Open SourceDataLine.
            try {
                initLine();
            } catch (LineUnavailableException e) {
                throw new BasicPlayerException(BasicPlayerException.CANNOTINITLINE, e);
            }
            log.info("Creating new thread");
            m_thread = new Thread(this, "BasicPlayer");
            m_thread.start();
            if (m_line != null) {
                m_line.start();
                m_status = PLAYING;
                synchronized (m_audioInputStream) {
                    m_audioInputStream.notifyAll();
                }
                notifyEvent(BasicPlayerEvent.PLAYING, getEncodedStreamPosition(), -1, null);
            }
        }
    }

    /**
     * Main loop.
     *
     * Player Status == STOPPED || SEEKING => End of Thread + Freeing Audio Ressources.<br>
     * Player Status == PLAYING => Audio stream data sent to Audio line.<br>
     * Player Status == PAUSED => Waiting for another status.
     */
    public void run() {
        log.info("Thread Running");
        int nBytesRead = 1;
        byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
        int readIndex = 0;//
        int writeIndex = 0;//
        // Lock stream while playing.
        synchronized (m_audioInputStream) {
            boolean buffering = false;
            // Main play/pause loop.
            while ((nBytesRead != -1) && (m_status != STOPPED) && (m_status != SEEKING) && (m_status != UNKNOWN)) {
                if (m_status == PLAYING) {
                    // Play.
                    try {
                        nBytesRead = m_audioInputStream.read(abData, 0, abData.length);
                        if (nBytesRead >= 0) {
                            byte[] pcm = new byte[nBytesRead];
                            System.arraycopy(abData, 0, pcm, 0, nBytesRead);
                            if (m_line.available() >= m_line.getBufferSize()) {
//                                buffering = true;
                                log.fine(" : " + m_line.available() + "/" + m_line.getBufferSize());
                            }
//                            if(m_line.available()==0){
//                                buffering=false;
//                            }
                            if (buffering == false) {
                                int nBytesWritten = m_line.write(abData, 0, nBytesRead);
                                // Compute position in bytes in encoded stream.
                                int nEncodedBytes = getEncodedStreamPosition();
                                // Notify listeners
                                Iterator<BasicPlayerListener> it = laucher.getBasicPlayerListeners().iterator();
                                while (it.hasNext()) {
                                    BasicPlayerListener bpl = it.next();
                                    if (m_audioInputStream instanceof PropertiesContainer) {
                                        // Pass audio parameters such as instant bitrate, ...
                                        Map properties = ((PropertiesContainer) m_audioInputStream).properties();
                                        bpl.progress(nEncodedBytes, m_line.getMicrosecondPosition(), pcm, properties);
                                    } else {
                                        bpl.progress(nEncodedBytes, m_line.getMicrosecondPosition(), pcm, empty_map);
                                    }
                                }
                            }

                        }
                    } catch (IOException e) {
                        log.log(Level.SEVERE, "Thread cannot run()", e);
                        m_status = STOPPED;
                        notifyEvent(BasicPlayerEvent.STOPPED, getEncodedStreamPosition(), -1, null);
                    }
                    // Nice CPU usage.
                    if (threadSleep > 0) {
                        try {
                            Thread.sleep(threadSleep);
                        } catch (InterruptedException e) {
                            log.log(Level.SEVERE, "Thread cannot sleep(" + threadSleep + ")", e);
                        }
                    }
                } else {
                    synchronized (m_audioInputStream) {
                        try {
                            log.log(Level.INFO, ",.....");
                            m_audioInputStream.wait();
                            log.log(Level.INFO, ",.......");
                        } catch (InterruptedException ex) {
                            Logger.getLogger(BasicPlayer.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                // Pause
//                    try {
//                        Thread.sleep(500);
//                    } catch (InterruptedException e) {
//                        log.log(Level.SEVERE, "Thread cannot sleep(500)", e);
//                    }
                }
            }
            // Free audio resources.
            if (m_line != null) {
                m_line.drain();
                m_line.stop();
                m_line.close();
                m_line = null;
            }
            // Notification of "End Of Media"
            if (nBytesRead == -1) {
                notifyEvent(BasicPlayerEvent.EOM, getEncodedStreamPosition(), -1, null);
            }
            // Close stream.
            closeStream();
        }
        m_status = STOPPED;
        notifyEvent(BasicPlayerEvent.STOPPED, getEncodedStreamPosition(), -1, null);
        log.info("Thread completed");
    }

    /**
     * Skip bytes in the File inputstream.
     * It will skip N frames matching to bytes, so it will never skip given bytes length exactly.
     * @param bytes
     * @return value>0 for File and value=0 for URL and InputStream
     * @throws BasicPlayerException
     */
    protected long skipBytes(long bytes) throws BasicPlayerException {
        long totalSkipped = 0;
        if (m_dataSource instanceof File) {
            log.fine("Bytes to skip : " + bytes);
            int previousStatus = m_status;
            m_status = SEEKING;
            long skipped = 0;
            try {
                synchronized (m_audioInputStream) {
                    notifyEvent(BasicPlayerEvent.SEEKING, getEncodedStreamPosition(), -1, null);
                    initAudioInputStream();
                    if (m_audioInputStream != null) {
                        // Loop until bytes are really skipped.
                        while (totalSkipped < (bytes - SKIP_INACCURACY_SIZE)) {
                            skipped = m_audioInputStream.skip(bytes - totalSkipped);
                            if (skipped == 0) {
                                break;
                            }
                            totalSkipped = totalSkipped + skipped;
                            log.fine("Skipped : " + totalSkipped + "/" + bytes);
                            if (totalSkipped == -1) {
                                throw new BasicPlayerException(BasicPlayerException.SKIPNOTSUPPORTED);
                            }
                        }
                    }
                }
                notifyEvent(BasicPlayerEvent.SEEKED, getEncodedStreamPosition(), -1, null);
                m_status = OPENED;
                if (previousStatus == PLAYING) {
                    startPlayback();
                } else if (previousStatus == PAUSED) {
                    startPlayback();
                    pausePlayback();
                }
            } catch (IOException e) {
                throw new BasicPlayerException(e);
            }
        }
        return totalSkipped;
    }

    /**
     * Notify listeners about a BasicPlayerEvent.
     * @param code event code.
     * @param position in the stream when the event occurs.
     */
    protected void notifyEvent(int code, int position, double value, Object description) {
        BasicPlayerEvent event = new BasicPlayerEvent(this, code, position, value, description);
        laucher.put(event);
    }

    protected int getEncodedStreamPosition() {
        int nEncodedBytes = -1;
        if (m_dataSource instanceof File) {
            try {
                if (m_encodedaudioInputStream != null) {
                    nEncodedBytes = encodedLength - m_encodedaudioInputStream.available();
                }
            } catch (IOException e) {
                //log.debug("Cannot get m_encodedaudioInputStream.available()",e);
            }
        }
        return nEncodedBytes;
    }

    protected void closeStream() {
        // Close stream.
        try {
            if (m_audioInputStream != null) {
                m_audioInputStream.close();
                log.info("Stream closed");
            }
        } catch (IOException e) {
            log.log(Level.SEVERE, "Cannot close stream", e);
        }
    }

    /**
     * Returns true if Gain control is supported.
     */
    public boolean hasGainControl() {
        if (m_gainControl == null) {
            // Try to get Gain control again (to support J2SE 1.5)
            if ((m_line != null) && (m_line.isControlSupported(FloatControl.Type.MASTER_GAIN))) {
                m_gainControl = (FloatControl) m_line.getControl(FloatControl.Type.MASTER_GAIN);
            }
        }
        return m_gainControl != null;
    }

    /**
     * Returns Gain value.
     */
    public float getGainValue() {
        if (hasGainControl()) {
            return m_gainControl.getValue();
        } else {
            return 0.0F;
        }
    }

    /**
     * Gets max Gain value.
     */
    public float getMaximumGain() {
        if (hasGainControl()) {
            return m_gainControl.getMaximum();
        } else {
            return 0.0F;
        }
    }

    /**
     * Gets min Gain value.
     */
    public float getMinimumGain() {
        if (hasGainControl()) {
            return m_gainControl.getMinimum();
        } else {
            return 0.0F;
        }
    }

    /**
     * Returns true if Pan control is supported.
     */
    public boolean hasPanControl() {
        if (m_panControl == null) {
            // Try to get Pan control again (to support J2SE 1.5)
            if ((m_line != null) && (m_line.isControlSupported(FloatControl.Type.PAN))) {
                m_panControl = (FloatControl) m_line.getControl(FloatControl.Type.PAN);
            }
        }
        return m_panControl != null;
    }

    /**
     * Returns Pan precision.
     */
    public float getPrecision() {
        if (hasPanControl()) {
            return m_panControl.getPrecision();
        } else {
            return 0.0F;
        }
    }

    /**
     * Returns Pan value.
     */
    public float getPan() {
        if (hasPanControl()) {
            return m_panControl.getValue();
        } else {
            return 0.0F;
        }
    }

    /**
     * Deep copy of a Map.
     * @param src
     * @return
     */
    protected Map deepCopy(Map src) {
        HashMap map = new HashMap();
        if (src != null) {
            Iterator it = src.keySet().iterator();
            while (it.hasNext()) {
                Object key = it.next();
                Object value = src.get(key);
                map.put(key, value);
            }
        }
        return map;
    }

    /**
     * @see javazoom.jlgui.basicplayer.BasicController#seek(long)
     */
    public long seek(long bytes) throws BasicPlayerException {
        return skipBytes(bytes);
    }

    /**
     * @see javazoom.jlgui.basicplayer.BasicController#play()
     */
    public void play() throws BasicPlayerException {
        startPlayback();
    }

    /**
     * @see javazoom.jlgui.basicplayer.BasicController#stop()
     */
    public void stop() throws BasicPlayerException {
        stopPlayback();
    }

    /**
     * @see javazoom.jlgui.basicplayer.BasicController#pause()
     */
    public void pause() throws BasicPlayerException {
        pausePlayback();
    }

    /**
     * @see javazoom.jlgui.basicplayer.BasicController#resume()
     */
    public void resume() throws BasicPlayerException {
        resumePlayback();
    }

    /**
     * Sets Pan value.
     * Line should be opened before calling this method.
     * Linear scale : -1.0 <--> +1.0
     */
    public void setPan(double fPan) throws BasicPlayerException {
        if (hasPanControl()) {
            log.fine("Pan : " + fPan);
            m_panControl.setValue((float) fPan);
            notifyEvent(BasicPlayerEvent.PAN, getEncodedStreamPosition(), fPan, null);
        } else {
            throw new BasicPlayerException(BasicPlayerException.PANCONTROLNOTSUPPORTED);
        }
    }

    /**
     * Sets Gain value.
     * Line should be opened before calling this method.
     * Linear scale 0.0  <-->  1.0
     * Threshold Coef. : 1/2 to avoid saturation.
     */
    public void setGain(double fGain) throws BasicPlayerException {
        if (hasGainControl()) {
            double minGainDB = getMinimumGain();
            double ampGainDB = ((10.0f / 20.0f) * getMaximumGain()) - getMinimumGain();
            double cste = Math.log(10.0) / 20;
            double valueDB = minGainDB + (1 / cste) * Math.log(1 + (Math.exp(cste * ampGainDB) - 1) * fGain);
            log.finest("Gain : " + valueDB);
            m_gainControl.setValue((float) valueDB);
            notifyEvent(BasicPlayerEvent.GAIN, getEncodedStreamPosition(), fGain, null);
        } else {
            throw new BasicPlayerException(BasicPlayerException.GAINCONTROLNOTSUPPORTED);
        }
    }

    public List getMixers() {
        ArrayList mixers = new ArrayList();
        Mixer.Info[] mInfos = AudioSystem.getMixerInfo();
        if (mInfos != null) {
            for (int i = 0; i < mInfos.length; i++) {
                Line.Info lineInfo = new Line.Info(SourceDataLine.class);
                Mixer mixer = AudioSystem.getMixer(mInfos[i]);
                if (mixer.isLineSupported(lineInfo)) {
                    mixers.add(mInfos[i].getName());
                }
            }
        }
        return mixers;
    }

    public Mixer getMixer(String name) {
        Mixer mixer = null;
        if (name != null) {
            Mixer.Info[] mInfos = AudioSystem.getMixerInfo();
            if (mInfos != null) {
                for (int i = 0; i < mInfos.length; i++) {
                    if (mInfos[i].getName().equals(name)) {
                        mixer = AudioSystem.getMixer(mInfos[i]);
                        break;
                    }
                }
            }
        }
        return mixer;
    }

    public String getMixerName() {
        return m_mixerName;
    }

    public void setMixerName(String name) {
        m_mixerName = name;
    }

    public long getMicrosecondPosition() {
        if (m_line != null) {
            return m_line.getMicrosecondPosition();
        } else {
            return -1;
        }
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.