Java声音 - LineUnavailableException:

5

我正在使用以下代码加载一个剪辑(javax.sound.sampled.Clip)

def createClip(file:String):Clip = {
    val clip = AudioSystem.getClip()
    clip.open(AudioSystem.getAudioInputStream(new File(s"sounds/$file.wav")))
    clip
}

这段代码是用Scala编写的,但我想熟悉Java而不熟悉Scala的人也会发现它基本相同,就像使用Java一样。

我的目标是使播放声音变得轻松无阻,就像这样。

createClip("example_WAV_File").start()

由于我将创建一个新的剪辑,每次调用音频文件时,我认为关于倒带剪辑等方面不应该有任何问题。然而,在实际的应用程序(游戏)中,我使用了这个库来处理由拳击等操作产生的声音。现在问题来了,当我多次进行拳击时,有时会出现以下错误:
“Exception in thread "Thread-58" javax.sound.sampled.LineUnavailableException: line with format PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, little-endian not supported.”
我曾经遇到过类似的错误,但那是关于位编码超过16位的问题。由于我的文件具有16位编码,我不知道这可能是什么原因...
如上所述,只有在播放几个剪辑时才会出现此错误。我想,这可能是一个内存问题。我天真地以为,垃圾收集器会为我完成所有工作,因为当离开其范围时,剪辑将失去任何引用。
我的初始解决方案是,保留对我要播放的任何声音的引用,并仅在另一个实例需要已播放的声音时重置它。这个解决方案永远不会失败,但无法真正播放同一段剪辑两次。这就是为什么我转而在需要时多次加载剪辑。
我想,我可能应该在剪辑上使用close()方法。
val clip = createClip("example_WAV_file")
clip.start()
clip.close()

这实际上解决了我的问题,增强了我的猜测,即它可能与内存有关,但现在剪辑在开始后立即停止。

我真的需要为每个剪辑创建一个线程,等待clip.getMicrosecondLength()的时间来关闭它吗?听起来相当糟糕。

唯一的选择是->我实际上非常错误地使用了声音API,尽管我认为我只是按照一些教程所示的方式使用它。那么我的特定错误在哪里?或者能够同时播放同一剪辑的解决方案是什么?


你解决了这个问题吗? - Nelson
我不这么认为,抱歉。我只是查看了我的旧项目。每个剪辑我都只创建了一次,并在播放时设置了它的帧位置。 正如我在帖子中提到的,我已经相当确定这是一个内存问题,所以有可能,如果在加载文件时将其声明为只读,它可能会起作用。这样,加载相同数据的两个单独的剪辑就可以共存了。 - Julian
请忽略我当时关于线程的说法:D - Julian
1个回答

0

当你使用open()打开一个Clip时,你基本上分配了一个本地音频线,即一种有限的资源。这意味着,当你完成后,必须将其关闭。通过LineListener是一种简单的方法来实现这一点。

例如:

Clip clip = createClip("some.wav");
clip.addLineListener(event -> {
    if (LineEvent.Type.STOP.equals(event.getType()) {
        event.getLine().close();
    }
});
clip.start();

这样可以确保每当一行停止时(当剪辑播放完成时会发生这种情况),该行也会关闭并释放已使用的本地资源。

请注意,这意味着您不能简单地再次播放同一剪辑,而必须创建/打开一个新剪辑。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接