Reputation: 1029
Within a Java swing application, the following snippet is supposed to play a siren. It starts OK but stops prematurely, not always at the same time (i.e. sometimes it stops almost immediately and sometimes after a longer delay, but usually it does not finish playing the whole sound file). What could be causing this?
I've done my best to create a minimal example that still has the problem:
package monster;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.io.File;
import javafx.embed.swing.JFXPanel;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example_2 extends JPanel {
protected static final long serialVersionUID = 1L;
public Example_2() {
setPreferredSize(new Dimension(100,100));
setBackground(Color.white);
createPanel();
}
public static void main(String[] args) {
Example_2 e = new Example_2();
JFrame f = new JFrame();
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
f.add(e, BorderLayout.CENTER);
f.pack();
f.setVisible(true);
f.repaint();
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
new Thread(
new Runnable() {
public void run() {
try {
File f = new File("sound/siren_short.wav");
String url = "file:///"+f.getAbsolutePath().replaceAll("\\\\","/").replaceAll(" ", "%20");
MediaPlayer mp = new MediaPlayer(new Media(url));
mp.play();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
public static JFXPanel createPanel() {
return new JFXPanel();
}
}
Upvotes: 0
Views: 145
Reputation: 7910
In the current example code "Example2" posted, it looks to me like the main() executes and exits. Yes, the call to MediaPlayer launches a background thread, but I'm guessing when the main() ends, this terminates the MediaPlayer thread as well (perhaps because it only has daemon status). I haven't used the MediaPlayer yet, myself, so I don't know if this behavior can result or not.
Here is a simple test for you: add the following line.
Thread.sleep(5000); // pauses 5 seconds
or something similar to the end of the main(), after the repaint() call. The number is milliseconds: use a number that is longer than the length of your sound. Does the sound now play to completion? You'll probably have to put the new line of code in a try...catch block.
Check out the api for Thread() when you get a chance. When you get to the page, I'd recommend doing a search on "daemon". There are methods for testing or setting daemon status, plus a terse explanation of what the status means. There is a chance that if you set your runnable to not be a daemon, the program (as shown) will play once and then hang with no way to terminate it except killing it via Eclipse (if it was run in Eclipse) or via an OS task manager.
I haven't delved much into debugging threads in Eclipse--am afraid I can't offer any suggestions there.
Andrew Thompson made a good suggestion, to make use of Clip. This has the benefit of keeping us in "familiar" territory. I've used Clip frequently, but not JavaFX libraries. If you had used Clip, the line of code I'm suggesting (Thread.sleep) would definitely have been needed to allow the sound to play to completion.
Here is a theory: the code which loads and executes the play() command is non-daemon. However, the background processes which deliver the sound data to the line are daemon. If that were the case, then the behavior I describe (termination after the main thread is done) would be consistent.
Upvotes: 1