Simplified version of what I'm actually doing (triggering a buzzer sound when a timer expires), but this demonstrates my design well enough.
Once playback is started, Swing never needs to touch the audio clip again. I have been able to confirm that this code does play back the sound and does not block the event dispatch thread, but I want to make sure there isn't some other thread safety concern that I am unknowingly violating. Thanks!
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.LineEvent;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class TriggeringSoundTest extends JFrame
{
private static final long serialVersionUID = -4573437469199690850L;
private boolean soundPlaying = false;
public TriggeringSoundTest()
{
JButton button = new JButton("Play Sound");
button.addActionListener(e -> new Thread(() -> playBuzzer()).start());
getContentPane().add(button);
}
private void playBuzzer()
{
URL url = getClass().getResource("resources/buzzer.wav");
try (AudioInputStream stream = AudioSystem.getAudioInputStream(url);
Clip clip = AudioSystem.getClip())
{
clip.open(stream);
clip.addLineListener(e -> {
if (e.getType() == LineEvent.Type.STOP)
soundPlaying = false;
});
soundPlaying = true;
clip.start();
while (soundPlaying)
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException exp)
{
// TODO Auto-generated catch block
exp.printStackTrace();
}
}
}
catch (UnsupportedAudioFileException exp)
{
// TODO Auto-generated catch block
exp.printStackTrace();
}
catch (IOException exp)
{
// TODO Auto-generated catch block
exp.printStackTrace();
}
catch (LineUnavailableException exp)
{
// TODO Auto-generated catch block
exp.printStackTrace();
}
}
private static void createAndShowGUI()
{
JFrame frame = new TriggeringSoundTest();
frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(() -> createAndShowGUI());
}
}