我如何等待java声音片段完成播放?

我使用以下代码使用java声音API播放声音文件。

Clip clip = AudioSystem.getClip(); AudioInputStream inputStream = AudioSystem.getAudioInputStream(stream); clip.open(inputStream); clip.start(); 

方法调用Clip.start()方法立即返回,系统在后台线程中播放声音文件。 我希望我的方法暂停,直到播放完成。

有没有好办法呢?

编辑:对于对我的最终解决方案感兴趣的每个人,根据Uri的答案,我使用下面的代码:

 private final BlockingQueue queue = new ArrayBlockingQueue(1); public void playSoundStream(InputStream stream) { Clip clip = AudioSystem.getClip(); AudioInputStream inputStream = AudioSystem.getAudioInputStream(stream); clip.open(inputStream); clip.start(); LineListener listener = new LineListener() { public void update(LineEvent event) { if (event.getType() != Type.STOP) { return; } try { queue.take(); } catch (InterruptedException e) { //ignore this } } }; clip.addLineListener(listener ); } 

声音片段是类型或线条,因此支持线条侦听器。

如果你使用addLineListener,你应该在播放开始和停止时获得事件; 如果你不在循环中,你应该在剪辑结束时停止。 但是,与任何事件一样,在实际播放结束和停止之前可能存在延迟。

使方法等待有点棘手。 您可以忙着等待它(不是一个好主意)或使用其他同步机制。 我认为有一种模式(不确定)等待一个长期操作来抛出一个完成事件,但这是一个普遍的问题,你可能想要单独发布到SO。

你可以改为使用这段代码:

假设你的clip1正在播放,你想要在之后播放一个clip2,你可以:

 clip1.start(); while(clip1.getMicrosecondLength() != clip1.getMicrosecondPosition()) { } clip2.loop(some int here); 

并且,为了使这项工作不延迟你的主要任务(我说这是因为while循环使得工作等待clip1完成,无论下一步工作是什么……)你可以在你的位置创建一个新的线程希望它发生,只需将代码放在run()方法中……好运!

在Java 8中我更喜欢这种方式:

 CountDownLatch syncLatch = new CountDownLatch(1); try (AudioInputStream stream = AudioSystem.getAudioInputStream(inStream)) { Clip clip = AudioSystem.getClip(); // Listener which allow method return once sound is completed clip.addLineListener(e -> { if (e.getType() == LineEvent.Type.STOP) { syncLatch.countDown(); } }); clip.open(stream); clip.start(); } syncLatch.await(); 

从JDK8开始, Clip的监听器就像是一种错误(即,它可能会发生两次为单个音频再现( .start() )触发Type.STOP。

因此我会使用类似的东西:

 Clip[] myBunchOfClipsToPlaySequentially=new Clip[A_BUNCH]; // // [load actual clips...] // [...] // for(Clip c: myBunchOfClipsToPlaySequentially) while(c.getFramePosition() 

另外,你可以看看JFX8提供的新的AudioClip类(有一些漂亮的方法可以摆弄)

我使用了wait / notify来实现它。 仅供参考。

  final Clip clip = AudioSystem.getClip(mixerInfo); clip.addLineListener(new LineListener(){ @Override public void update(LineEvent e) { if (e.getType()==LineEvent.Type.STOP){ synchronized(clip){ clip.notifyAll(); } System.err.println("STOP!"); } } }); clip.open(as); clip.start(); while (true){ synchronized(clip){ clip.wait(); } if (!clip.isRunning()){ break; } } clip.drain(); clip.stop(); clip.close();