下面的play
方法来自一个类,该类在实例化时将.wav文件读入名为data
的字节数组中,并将声音格式存储在名为AudioFormat
的对象中format
。
我有一个程序从play
调用java.util.Timer
。当我进入包含所有相关.class文件的文件夹并使用命令java MainClass
运行程序时,一切都按预期工作。但是,当我将所有.class文件放在可执行文件.jar中并使用命令java -jar MyProgram.jar
运行程序时,使用play
方法播放的声音会在50到150毫秒之后被切断。< / p>
public void play() throws LineUnavailableException {
final Clip clip = (Clip)AudioSystem.getLine(new DataLine.Info(Clip.class, format));
clip.open(format, data, 0, data.length);
new Thread() {
public void run() {
clip.start();
try {
Thread.sleep(300); // all sounds are less than 300 ms long
} catch (InterruptedException ex) { /* i know, i know... */ }
clip.close();
}
}.start();
}
一些评论:
我尝试将play
方法的睡眠时间增加到1000毫秒,行为没有变化。
使用Thread.sleep
对System.nanoTime
进行定时确认线程正在休眠的时间与预期一致。
由于要播放的声音文件已预先加载到内存中,我认为从.jar中提取声音资源的行为不会导致问题。
我尝试使用内存池大小选项-Xms2m
和-Xmx64m
(单独)从jar内部和外部运行程序,但行为没有变化。
我在Ubuntu 11.04上运行OpenJDK Java 6。知道发生了什么事吗?
答案 0 :(得分:4)
我不知道这是否与问题直接相关,但每次播放该剪辑时实例化一个新剪辑有点自我挫败。 Clip的要点是能够在不必先加载它的情况下启动它。正如您当前设置的那样,您的剪辑在完全加载之前甚至不会开始播放。 (当包含实例化步骤时,SourceDataLines开始比Clips更快地播放,因为它们不会在开始之前等待加载所有数据。)
因此,作为解决此问题的第一步,我建议在播放调用之前实例化各种剪辑。我相信如果你这样做,并且剪辑开始在它自己的线程中,它可以被允许运行它的过程而不需要弄乱Thread.sleep。您只需在下次启动之前将剪辑重新定位回其起始帧。 (可以在比赛开始前的比赛中完成。
一旦您对Clip的使用变得更加传统,可能更容易弄清楚是否还有其他事情发生。
我也不清楚为什么源.wav文件作为中间步骤被加载到字节数组中。不妨将它们直接加载到剪辑中。考虑到PCM数据的优势,它们将以相同的方式占用相同数量的空间,并且在你打电话时准备就绪。
禁用错误消息也会弄巧成拙。 Java可能试图给你一个非常好的诊断,也许不是在这个特定的睡眠呼叫(我知道,我知道),但如果你经常这样做,谁知道。 :)
答案 1 :(得分:3)
可能加载byte[]
是问题所在。