package sound; import javax.sound.sampled.*; import java.io.*; /** * The class Playback extends from Thread * and allows for playback of a simple sound. The thread doesn't die until * the sound is finished playing, however it is not blocking either. It * will simply play the sound in the "background." * * Copyright Georgia Institute of Technology 2004 * @author unknown undergrad * @author Barb Ericson ericson@cc.gatech.edu */ public class Playback extends Thread { ///////////////// fields //////////////////////////////////// /** * Constant that is the default buffer size. * @see Sound#Sound() * @see Playback#run() */ private static final int BUFFER_SIZE = 16384; /** * The source data line for the sound */ private SourceDataLine line; /** * flag that says is the sound currently being played */ private boolean playing = false; /** * The sound being played */ private SimpleSound sound; ////////////////// Constructors ////////////////////////////////////// /** * Constructor that takes the simple sound to be played * @param sound the simple sound to play */ public Playback(SimpleSound sound) { this.sound = sound; } /** * Stop the playback */ private void shutDown(String message, Exception e) { if (message != null) { System.err.println(message); e.printStackTrace(); } playing = false; } /** * Stops this thread by breaking the while loop in the run method. * Used, for example, by the "stop" button in the SoundExplorer class. */ public void stopPlaying() { playing = false; } /** * Method to return true if this playback thread is playing and * false otherwise * @return true if playing else false */ public boolean getPlaying() { return playing; } /** * Starts this thread. Gets an AudioInputStream, and writes is out * to a SourceDataLine. If a SoundExplorer exists, upon creation of * the SourceDataLine, the soundExplorer is added as the LineListener. * When the thread finishes the run method, it removes itself from the * list of threads currently playing this sound. * @throws JavaSoundException if there were problems playing the sound. */ public void run() { AudioFileFormat audioFileFormat = sound.getAudioFileFormat(); SoundExplorer soundExplorer = sound.getSoundExplorer(); //get something to play AudioInputStream audioInputStream = sound.makeAIS(); if(audioInputStream == null) { shutDown("There is no input stream to play", null); return; } //reset stream to the begining try { audioInputStream.reset(); } catch(Exception e) { shutDown("Problems resetting the stream\n", e); return; } /* define the required attributes for the line make sure a compatible line is supported */ DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFileFormat.getFormat()); if(!AudioSystem.isLineSupported(info)) { shutDown("Line matching " + info + "not supported.", null); return; } //get and open the source data line for playback try { line = (SourceDataLine) AudioSystem.getLine(info); if(sound.getSoundExplorer() != null) line.addLineListener(soundExplorer); line.open(audioFileFormat.getFormat(), BUFFER_SIZE); } catch(LineUnavailableException e) { shutDown("Unable to open the line: ", e); return; } //play back the captured data int frameSizeInBytes = audioFileFormat.getFormat().getFrameSize(); int bufferLengthInBytes = line.getBufferSize(); int bufferLengthInFrames = bufferLengthInBytes / frameSizeInBytes; byte[] data = new byte[bufferLengthInBytes]; int numBytesRead = 0; //start the source data line and begin playing line.start(); playing = true; // the loop that actually writes the data out while(playing) { try { if((numBytesRead = audioInputStream.read(data)) == -1) { break;//end of audioInputStream } int numBytesRemaining = numBytesRead; while(numBytesRemaining > 0) { numBytesRemaining -= line.write(data, 0, numBytesRemaining); }//while } catch(Exception e) { shutDown("Error during playback: ", e); break; }//catch }//while /* we reached the end of the stream or an error occurred. if we were playing, then let the data play out, else, skip to stopping and closing the line. */ if(playing) line.drain(); line.stop(); line.close(); line = null; shutDown(null, null); if(sound.getDEBUG()) System.out.println("exiting run method"); /* this thread is about to die. remove itself from the collection of threads playing this sound */ sound.removePlayback(this); }//run() }//end class Playback