I am playing of a sound-file in Java, and is looking for a simple way to determine when the sound-file has finished playing so I can kill the thread. Is there a simple way to accomplish this?
Why do you want to kill the thread? It will go away on its own once the it terminates.
If you insist, set up a synchronized method you can call to set a "die now" flag; check that flag periodically.
Comments
You play sound either synchronously or asynchronously.
In case you play it synchronously (blocking the calling thread), you know when the sound ends playing — your code gain control then.
In case you play it asynchronously (allowing a different thread to be created), the helper thread will terminate itself right after finishing playing.
P.S.
Please share your observations on memory leaking and reasons underneath the question.
Sorry this is a little late, but I just ran into an issue today that sounds suspiciously familiar to this one. In some game code, Im using javax.sound.sampled.Clip to play various sounds, I found that if I didn't explicitly call line.close() once it was finished, the count of native threads in the profiler would just sky-rocket until I got an OutOfMemory error.
// this just opens a line to play the sample
Clip clip = AudioSystem.getClip();
clip.open( audioFormat, sounddata, 0, sounddata.length);
clip.start();
// at this point, there is a native thread created 'behind the scenes'
// unless I added this, it never goes away:
clip.addLineListener( new LineListener() {
public void update(LineEvent evt) {
if (evt.getType() == LineEvent.Type.STOP) {
evt.getLine().close();
}
}
});
My presumption is that the clip creates a thread to meter out the sample bytes into the line, but the thread hangs around after that in case you want to re-use the clip again. My second presumption is that somewhere something in my code must have a reference to the clip, or vice-versa, but at any rate, the snippet above duct-taped the problem.
Hope this is useful to someone.
I dont use clips, it takes more time to load in memory, depending the size of the file you are reading. I preefer reading the bytes, and use this method I created:
public void play(File file) throws UnsupportedAudioFileException, IOException, LineUnavailableException, InterruptedException
{
AudioInputStream encoded = AudioSystem.getAudioInputStream(file);
AudioFormat encodedFormat = encoded.getFormat();
AudioFormat decodedFormat = this.getDecodedFormat(encodedFormat);
line = AudioSystem.getSourceDataLine(decodedFormat);
currentDecoded = AudioSystem.getAudioInputStream(decodedFormat, encoded);
line.open(decodedFormat);
line.start();
byte[] b = new byte[this.bufferSize];
int i = 0;
synchronized(lock){
while(true)
{
i = currentDecoded.read(b, 0, b.length);
if(i == -1)
break;
line.write(b, 0, i);
if(paused == true)
{
line.stop();
lock.wait();
line.start();
}
}
}
line.drain();
line.stop();
line.close();
currentDecoded.close();
encoded.close();
}
it uses this method:
protected AudioFormat getDecodedFormat(AudioFormat format)
{
AudioFormat decodedFormat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED, // Encoding to use
format.getSampleRate(), // sample rate (same as base format)
16, // sample size in bits (thx to Javazoom)
format.getChannels(), // # of Channels
format.getChannels()*2, // Frame Size
format.getSampleRate(), // Frame Rate
false // Big Endian
);
return decodedFormat;
}