0

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?

Espen Herseth Halvorsen
  • 6,175
  • 7
  • 36
  • 38

4 Answers4

4

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.

Jake
  • 8,167
  • 1
  • 19
  • 19
  • Threads don't need to be referenced to be protected from garbage collection. They are the top-level things doing that hold the references. Something has to be at the root of the reference tree: if not all threads, what else could it be? The main thread? Many server programs exit the main thread early on in their execution. – Adrian Pronk Sep 13 '09 at 01:11
  • What I should have said is *active* threads. Threads which have finished executing (returned from run()) are eligible for gc. (Although maybe only after they have been "join()'d") – Adrian Pronk Sep 13 '09 at 01:13
  • @AdrianPronk Useful for me, did you ever find a non duct-tape solution? – Tim the Enchanter Aug 03 '14 at 17:14
1

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.

bohdan_trotsenko
  • 5,167
  • 3
  • 43
  • 70
0

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;    
}
fredcrs
  • 3,558
  • 7
  • 33
  • 55
0

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.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263