All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dstadler.audio.player.MP3SPIPlayer Maven / Gradle / Ivy

package org.dstadler.audio.player;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.IOException;
import java.io.InputStream;

/**
 * AudioPlayer implementation which uses the Java Audio System for playback
 * together with the MP3 SPI for transcoding the MP3 audio data to PCM.
 */
public class MP3SPIPlayer implements AudioPlayer {
    private final InputStream stream;
    private AudioInputStream ain;

    private SourceDataLine line = null;
    // We haven't started the line yet.
    boolean started = false;

    public MP3SPIPlayer(InputStream stream) throws IOException {
        this.stream = stream;

        try {
            ain = AudioSystem.getAudioInputStream(stream);
        } catch (UnsupportedAudioFileException e) {
            throw new IOException(e);
        }
    }

    @Override
    public void setOptions(String options) {
        // no options supported here
    }

    @Override
    public void play() throws IOException {
        // Get an audio input stream from the URL
        try {
            ain = AudioUtils.convertToSupportedAudio(ain);

            // Get information about the format of the stream
            AudioFormat format = ain.getFormat( );
            DataLine.Info info = new DataLine.Info(SourceDataLine.class,format);

            // If not done before, open the line through which we'll play the streaming audio
            if(line == null) {
                line = (SourceDataLine) AudioSystem.getLine(info);
                line.open(format);
            }

            // Allocate a buffer for reading from the input stream and writing
            // to the line.  Make it large enough to hold 4k audio frames.
            // Note that the SourceDataLine also has its own internal buffer.
            int framesize = format.getFrameSize( );
            byte[  ] buffer = new byte[4 * 1024 * framesize]; // the buffer
            int numbytes = 0;                               // how many bytes

            for(;;) {  // We'll exit the loop when we reach the end of stream
                // First, read some bytes from the input stream.
                int bytesread = ain.read(buffer, numbytes,buffer.length-numbytes);

                if (bytesread == -1) {
                    break;
                }

                numbytes += bytesread;

                // Now that we've got some audio data to write to the line,
                // start the line, so it will play that data as we write it.
                if (!started) {
                    line.start( );
                    started = true;
                }

                // We must write bytes to the line in an integer multiple of
                // the framesize.  So figure out how many bytes we'll write.
                int bytestowrite = (numbytes/framesize)*framesize;

                // bail out if the player was closed
                if(ain == null) {
                    break;
                }

                // Now write the bytes. The line will buffer them and play
                // them. This call will block until all bytes are written.
                line.write(buffer, 0, bytestowrite);

                // If we didn't have an integer multiple of the frame size,
                // then copy the remaining bytes to the start of the buffer.
                int remaining = numbytes - bytestowrite;
                if (remaining > 0)
                    System.arraycopy(buffer,bytestowrite,buffer,0,remaining);
                numbytes = remaining;
            }

            // Now block until all buffered sound finishes playing.
            line.drain( );
        } catch (LineUnavailableException e) {
            throw new IOException(e);
        }

    }

    @Override
    public void close() throws IOException {
        if(line != null) {
            line.close();
            line = null;
        }

        if(ain != null) {
            ain.close();
            ain = null;
        }

        if(stream != null) {
            stream.close();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy