Java声音 - LineUnavailableException:

Jul*_*ian 5 java scala javasound

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

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

它是用Scala编写的,但我想任何不熟悉scala的人都会看到java基本相同,就像java一样.

我的尝试是让它毫不费力地播放这样的声音

createClip("example_WAV_File").start()
Run Code Online (Sandbox Code Playgroud)

因为我将创建一个新的 Clip,每次我调用一个声音文件,我认为关于倒回剪辑等应该没有任何问题.但是在实际应用程序(游戏)中,我使用这个库来处理声音Punch和所有这些东西的结果.现在是这样的事情,当(例如)冲压几次时,有些时候我会得到

线程"Thread-58"中的异常javax.sound.sampled.LineUnavailableException:行格式为PCM_SIGNED 44100.0 Hz,16位,立体声,4字节/帧,不支持little-endian.

我曾遇到类似的错误,但这是关于比特编码超过16位.由于我的文件有16位编码,我不知道这可能是什么...

如上所述,只有在播放几个剪辑时才会出现错误.我想,这可能表明存在内存问题.我天真地想,垃圾收集器会为我做所有工作,因为剪辑在离开其范围时会失去任何参考.

我最初的解决方案是,保持对我要播放的任何声音的引用,并且只在另一个实例需要已经播放的声音时才回放它.这个解决方案永远不会破坏,但它真的不能两次播放相同的剪辑.这就是为什么我在需要时切换到多次加载剪辑的原因.

我想,我可能应该在剪辑上使用close()方法.

val clip = createClip("example_WAV_file")
clip.start()
clip.close()
Run Code Online (Sandbox Code Playgroud)

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

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

只剩下选项 - >我使用声音API确实非常错误,即使我想,我正在使用它只是一些教程给我看的方式.那我的特殊错误在哪里?或者,能够同时播放相同剪辑两次的解决方案是什么?

hen*_*rik 0

当您open()a时Clip,您基本上分配了本机音频线路,即有限的资源。这意味着,完成后必须将其关闭。一个简单的方法是通过LineListener

例如:

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

这确保了每当一行停止时(当剪辑完成播放时发生),该行也会关闭并释放所使用的本机资源。

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