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

时间:2009-02-17 17:36:07

标签: java javasound

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

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

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

有没有好办法呢?

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

private final BlockingQueue<URL> queue = new ArrayBlockingQueue<URL>(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 );
}

6 个答案:

答案 0 :(得分:5)

您可以改为使用此代码:

假设你的clip1正在播放,你想要在那之后立即播放clip2,你可以:

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

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

答案 1 :(得分:4)

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

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

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

答案 2 :(得分:3)

我更喜欢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();

答案 3 :(得分:0)

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

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

Clip[] myBunchOfClipsToPlaySequentially=new Clip[A_BUNCH];
//
// [load actual clips...]
// [...]
//
for(Clip c: myBunchOfClipsToPlaySequentially)
    while(c.getFramePosition()<c.getFrameLength())
        Thread.yield(); // Note that if we simply put a NO-OP instead (like a
                        // semicolon or a {}), we make our CPU
                        // cry). Thread.yield() allows for almost 0% CPU consumption.

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

答案 4 :(得分:0)

我使用了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();

答案 5 :(得分:0)

不确定我是否可以代表其他人发言,这个帖子很旧了。但是我使用剪辑库来播放我的 .wav 文件,然后在声音文件运行的时间内让线程休眠:

Clip clip = AudioSystem.getClip();
clip.open(audioInputStream);
clip.start();
System.out.println("Clip Started");
Thread.sleep(162000); //Length of time in milliseconds
System.out.println("Clip finished");

对我来说就像一个魅力,我正在监控我的处理器,整个程序最多使用了 4%!