9

我正在使用以下代码使用 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 );
}
4

6 回答 6

8

我在 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();
于 2017-10-13T07:38:19.873 回答
7

你可以把这段代码改为:

假设您的剪辑 1 正在播放并且您希望在此之后立即播放剪辑 2,您可以:

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

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

于 2013-06-25T15:12:00.163 回答
4

声音剪辑是一种类型或 Line,因此支持 Line 侦听器。

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

让方法等待有点棘手。您可以忙于等待(不是一个好主意)或使用其他同步机制。我认为有一种模式(不确定)等待长时间操作以引发完成事件,但这是您可能希望单独发布给 SO 的一般问题。

于 2009-02-17T17:51:20.770 回答
0

从 JDK8 开始,Clip的侦听器有点问题(即,它可能会触发 Type.STOP 两次以复制音频(.start())。

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

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类(有一些漂亮的方法可以摆弄)

于 2016-10-06T17:28:34.607 回答
0

我已经使用等待/通知来实现这一点。仅供参考。

        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();
于 2017-07-11T16:39:33.917 回答
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%!

于 2021-02-24T13:17:56.890 回答