Can someone please help me understand why this code below doesn\'t work?
I start the clip by calling method start()
. This method creates a new thread for th
clip.loop
is a non-blocking call. That is, once you call it (and it does what it does), it will return, this means your thread will exit and, unless there is another non-daemon thread running, the JVM will exit.
I had thought you might be able to use Clip#drain
to cause it to block until the clip had completed, but technically, the clip won't complete...in the normal sense.
Instead, I set up my own loop...
public void start() {
Runnable r = new Runnable() {
public void run() {
while (true) {
clip.setFramePosition(0);
clip.start();
clip.drain();
}
}
};
thread = new Thread(r);
thread.start();
}
Now, this could be an issue, because the Thread
is a non-daemon thread and will never end...Instead of while (true) {
you should setup some kind volitle
flag which you set to false
and help terminate the loop...
For example...
import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
public class Audio {
private Clip clip;
private Thread thread;
private volatile boolean keepPlaying = true;
public static void main(String[] args) {
Audio audio = new Audio("Kalimba.wav");
audio.start();
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
}
audio.stop();
}
public Audio(String audioFile) {
AudioInputStream audioStream = null;
URL audioURL = this.getClass().getClassLoader().getResource(audioFile);
// Obtain audio input stream from the audio file and load the information
// into main memory using the URL path retrieved from above.
try {
audioStream = AudioSystem.getAudioInputStream(audioURL);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
try {
// Retrieve the object of class Clip from the Data Line.
this.clip = AudioSystem.getClip();
// Load the audio input stream into memory for future play-back.
this.clip.open(audioStream);
} catch (LineUnavailableException e) {
e.printStackTrace();
System.exit(1);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
public void stop() {
if (thread != null) {
keepPlaying = false;
clip.stop();
thread.interrupt();
}
}
public void start() {
Runnable r = new Runnable() {
public void run() {
while (keepPlaying) {
clip.setFramePosition(0);
clip.start();
clip.drain();
}
}
};
thread = new Thread(r);
thread.start();
}
}
Updated
There a few things wrong with the above example (IMHO), which can be fixed with a simple object monitor.
So, instead of a volatile
flag and a while
loop, we can use the Clip#loop
functionality and simply use Object#wait
and Object#notify
instead, for example
import java.io.IOException;
import java.net.URL;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
public class Audio {
private Clip clip;
private Thread thread;
private final Object loopLock = new Object();
public static void main(String[] args) {
Audio audio = new Audio("Music.wav");
audio.start();
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
}
audio.stop();
}
public Audio(String audioFile) {
AudioInputStream audioStream = null;
URL audioURL = this.getClass().getClassLoader().getResource(audioFile);
// Obtain audio input stream from the audio file and load the information
// into main memory using the URL path retrieved from above.
try {
audioStream = AudioSystem.getAudioInputStream(audioURL);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
try {
// Retrieve the object of class Clip from the Data Line.
this.clip = AudioSystem.getClip();
// Load the audio input stream into memory for future play-back.
this.clip.open(audioStream);
} catch (LineUnavailableException e) {
e.printStackTrace();
System.exit(1);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
public void stop() {
synchronized (loopLock) {
loopLock.notifyAll();
}
}
public void start() {
Runnable r = new Runnable() {
public void run() {
clip.setFramePosition(0);
clip.loop(Clip.LOOP_CONTINUOUSLY);
synchronized (loopLock) {
try {
loopLock.wait();
} catch (InterruptedException ex) {
}
}
clip.stop();
}
};
thread = new Thread(r);
thread.start();
}
}