当我从.jar运行时,为什么Java Sound的行为会有所不同?

时间:2012-09-03 17:35:05

标签: java multithreading javasound

下面的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.sleepSystem.nanoTime进行定时确认线程正在休眠的时间与预期一致。

  • 由于要播放的声音文件已预先加载到内存中,我认为从.jar中提取声音资源的行为不会导致问题。

  • 我尝试使用内存池大小选项-Xms2m-Xmx64m(单独)从jar内部和外部运行程序,但行为没有变化。

我在Ubuntu 11.04上运行OpenJDK Java 6。知道发生了什么事吗?

2 个答案:

答案 0 :(得分:4)

我不知道这是否与问题直接相关,但每次播放该剪辑时实例化一个新剪辑有点自我挫败。 Clip的要点是能够在不必先加载它的情况下启动它。正如您当前设置的那样,您的剪辑在完全加载之前甚至不会开始播放。 (当包含实例化步骤时,SourceDataLines开始比Clips更快地播放,因为它们不会在开始之前等待加载所有数据。)

因此,作为解决此问题的第一步,我建议在播放调用之前实例化各种剪辑。我相信如果你这样做,并且剪辑开始在它自己的线程中,它可以被允许运行它的过程而不需要弄乱Thread.sleep。您只需在下次启动之前将剪辑重新定位回其起始帧。 (可以在比赛开始前的比赛中完成。

一旦您对Clip的使用变得更加传统,可能更容易弄清楚是否还有其他事情发生。

我也不清楚为什么源.wav文件作为中间步骤被加载到字节数组中。不妨将它们直接加载到剪辑中。考虑到PCM数据的优势,它们将以相同的方式占用相同数量的空间,并且在你打电话时准备就绪。

禁用错误消息也会弄巧成拙。 Java可能试图给你一个非常好的诊断,也许不是在这个特定的睡眠呼叫(我知道,我知道),但如果你经常这样做,谁知道。 :)

答案 1 :(得分:3)

可能加载byte[]是问题所在。