import java.io.*;
import javax.sound.sampled.*;

/**
    Klasa SimpleSoundPlayer obsługuje otwieranie pliku dwiękowego
    z systemu plików i jego póniejsze otwieranie.
*/
public class SimpleSoundPlayer  {

    public static void main(String[] args) {
        // Ładowanie dwięku.
        SimpleSoundPlayer sound =
            new SimpleSoundPlayer("../sounds/voice.wav");

        // Tworzenie strumienia dwiękowego.
        InputStream stream =
            new ByteArrayInputStream(sound.getSamples());

        // Odtwarzanie dwięku.
        sound.play(stream);

        // Koniec.
        System.exit(0);
    }

    private AudioFormat format;
    private byte[] samples;

    /**
        Otwieranie dwięku z pliku.
    */
    public SimpleSoundPlayer(String filename) {
        try {
            // Otwieranie strumienia wejcia dwiękowego.
            AudioInputStream stream =
                AudioSystem.getAudioInputStream(
                new File(filename));

            format = stream.getFormat();

            // Pobieranie próbek dwiękowych.
            samples = getSamples(stream);
        }
        catch (UnsupportedAudioFileException ex) {
            ex.printStackTrace();
        }
        catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
        Pobieranie próbek dwięku jako tablicy bajtów.
    */
    public byte[] getSamples() {
        return samples;
    }

    /**
        Pobranie próbek z AudioInputStream w postaci tablicy bajtów.
    */
    private byte[] getSamples(AudioInputStream audioStream) {
        // Pobranie liczby bajtów do odczytania.
        int length = (int)(audioStream.getFrameLength() *
            format.getFrameSize());

        // Odczytanie całego strumienia.
        byte[] samples = new byte[length];
        DataInputStream is = new DataInputStream(audioStream);
        try {
            is.readFully(samples);
        }
        catch (IOException ex) {
            ex.printStackTrace();
        }

        // Zwrócenie próbek.
        return samples;
    }

    /**
        Odtwarzanie strumienia. Metoda ta jest blokowana (nie wraca), 
        dopóki nie zostanie zakończenie odtwarzanie dwięku.
    */
    public void play(InputStream source) {

        // Wykorzystujemy krótki - długoci 100 ms (1/10 sekundy) - bufor 
        // do zmiany strumienia dwięku w czasie rzeczywistym
        int bufferSize = format.getFrameSize() *
            Math.round(format.getSampleRate() / 10);
        byte[] buffer = new byte[bufferSize];

        // Tworzenie obiektu Line do odtwarzania dwięku.
        SourceDataLine line;
        try {
            DataLine.Info info =
                new DataLine.Info(SourceDataLine.class, format);
            line = (SourceDataLine)AudioSystem.getLine(info);
            line.open(format, bufferSize);
        }
        catch (LineUnavailableException ex) {
            ex.printStackTrace();
            return;
        }

        // Uruchomienie odtwarzania.
        line.start();

        // Kopiowanie danych do obiektu Line.
        try {
            int numBytesRead = 0;
            while (numBytesRead != -1) {
                numBytesRead =
                    source.read(buffer, 0, buffer.length);
                if (numBytesRead != -1) {
                   line.write(buffer, 0, numBytesRead);
                }
            }
        }
        catch (IOException ex) {
            ex.printStackTrace();
        }

        // Oczekiwanie na zakończenie odtwarzania i zamknięcie obiektu Line.
        line.drain();
        line.close();

    }
}
