Javas Audio的问题剪辑频繁播放哔声

我想播放短蜂鸣声(WAV文件)成功和GUI触发动作的错误。

我遇到了javax.sound.sampled.Clip ,它似乎有效。 这是我使用的基本代码:

clip.stop(); clip.setFramePosition(0); clip.start(); 

在按钮单击触发数据库操作后执行此操作。 在成功和错误时,播放两个不同的预加载剪辑。

但是在生产机器(运行Kubuntu 10.4的旧PC)一段时间后(大约400多次执行或2-4小时),剪辑拒绝播放。 停止方法需要大约3秒才能终止,并且后续启动操作不会播放任何声音。 以下每次调用代码都会失败,而不会抛出exception或任何其他反馈。 解决这个问题的唯一方法是重新启动整个应用程序。

我的问题是:有没有解决方法? 还有其他人有同样的问题吗? 或者是否有另一个框架可用于播放至少两种不同的声音(Toolkit.beep()只能播放一种声音)。

不要害怕只是重新创建对象,开销很低。 不要重置剪辑,只需创建新剪辑即可。 您可以缓存文件,这将是一个有用的优化。 重复使用剪辑对象不是。

或者您可以尝试替代实现[不受限制]

这是谷歌“java play wav files”的最佳结果:

http://www.anyexample.com/programming/java/java_play_wav_sound_file.xml

它简化了一次调用:

 new AePlayWave("test.wav").start(); 

只需将此类添加到您的代码库:

 import java.io.File; import java.io.IOException; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine; import javax.sound.sampled.FloatControl; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine; import javax.sound.sampled.UnsupportedAudioFileException; public class AePlayWave extends Thread { private String filename; private Position curPosition; private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb enum Position { LEFT, RIGHT, NORMAL }; public AePlayWave(String wavfile) { filename = wavfile; curPosition = Position.NORMAL; } public AePlayWave(String wavfile, Position p) { filename = wavfile; curPosition = p; } public void run() { File soundFile = new File(filename); if (!soundFile.exists()) { System.err.println("Wave file not found: " + filename); return; } AudioInputStream audioInputStream = null; try { audioInputStream = AudioSystem.getAudioInputStream(soundFile); } catch (UnsupportedAudioFileException e1) { e1.printStackTrace(); return; } catch (IOException e1) { e1.printStackTrace(); return; } AudioFormat format = audioInputStream.getFormat(); SourceDataLine auline = null; DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); try { auline = (SourceDataLine) AudioSystem.getLine(info); auline.open(format); } catch (LineUnavailableException e) { e.printStackTrace(); return; } catch (Exception e) { e.printStackTrace(); return; } if (auline.isControlSupported(FloatControl.Type.PAN)) { FloatControl pan = (FloatControl) auline .getControl(FloatControl.Type.PAN); if (curPosition == Position.RIGHT) pan.setValue(1.0f); else if (curPosition == Position.LEFT) pan.setValue(-1.0f); } auline.start(); int nBytesRead = 0; byte[] abData = new byte[EXTERNAL_BUFFER_SIZE]; try { while (nBytesRead != -1) { nBytesRead = audioInputStream.read(abData, 0, abData.length); if (nBytesRead >= 0) auline.write(abData, 0, nBytesRead); } } catch (IOException e) { e.printStackTrace(); return; } finally { auline.drain(); auline.close(); } } } 

所以我如何解决它:

我基本上遵循了Charles Goodwin的提示,但我更改了AePlayWave类以实现runnable并将其与线程池一起使用(以避免一直开始新线程的开销)。 此外,我使用URL而不是文件来使用打包的JAR文件中的资源。 设置完成(选择文件)或设置更改后,将创建AePlayWave对象。 我希望应用程序播放的每个声音都有一个实例。 事件的侦听器方法然后触发池为该事件声音运行特定的AePlayWave实例。 其余基本相同。

只有两个不方便的问题:

1.)在弱机器上,并不总是播放WAV的结尾。 当声音很短(如100毫秒的哔哔声)时,这可能导致根本没有声音播放! 这就是为什么我在每个声音的结尾添加500毫秒的静音我想玩。 这是一种解决方法,但它有助于现在它似乎是最好和最稳定的方法。

2.)如果播放了多个声音(因为重复非常快),声音会重叠,并且您会听到音调和音量的变化。 这在我的情况下是可以的,但可能会令其他用途烦人。

它已经在生产系统上运行。 如果向我报告任何错误,我将编辑此post以使您及时了解最新信息。

现在这里是(基本上减少)源代码:

 import java.io.IOException; import java.net.URL; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine; import javax.sound.sampled.UnsupportedAudioFileException; public class AudibleListener implements SomeListener { private Runnable successRunner; private Runnable failRunner; ExecutorService pool = Executors.newCachedThreadPool(); /** * Call this after initialization and after every change in your config at runtime. */ public void reloadSettings() { // put your configuration here this.successRunner = new WavePlayer(this.getClass().getResource("success.wav")); this.failRunner = new WavePlayer(this.getClass().getResource("fail.wav")); } /** * Call this to savely shutdown the thread pool. */ public void shutdown() { this.pool.shutdown(); } /** * Listener method called on success. */ public void eventSuccess() { this.pool.execute(this.successRunner); } /** * Listener method called on fail. */ public void eventFailed() { this.pool.execute(this.failRunner); } private class WavePlayer implements Runnable { private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb private URL soundFile; public WavePlayer(URL soundFile) { this.soundFile = soundFile; } @Override public void run() { try { // check if the URL is still accessible! this.soundFile.openConnection().connect(); this.soundFile.openStream().close(); } catch (Exception e) { return; } AudioInputStream audioInputStream = null; try { audioInputStream = AudioSystem .getAudioInputStream(this.soundFile); } catch (UnsupportedAudioFileException e) { return; } catch (IOException e) { return; } AudioFormat format = audioInputStream.getFormat(); SourceDataLine auline = null; DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); try { auline = (SourceDataLine) AudioSystem.getLine(info); auline.open(format); } catch (LineUnavailableException e) { return; } catch (Exception e) { return; } auline.start(); int nBytesRead = 0; byte[] abData = new byte[this.EXTERNAL_BUFFER_SIZE]; try { while (nBytesRead != -1) { nBytesRead = audioInputStream .read(abData, 0, abData.length); if (nBytesRead >= 0) { auline.write(abData, 0, nBytesRead); } } } catch (IOException e) { return; } finally { auline.drain(); auline.close(); } } } } 

欢呼和感谢到目前为止所有的帮助!

P.

更新:

现在运行了72小时,没有任何错误! 看起来我们做到了!