如何等待 Java 声音剪辑完成播放?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/557903/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 12:51:12  来源:igfitidea点击:

how can I wait for a java sound clip to finish playing back?

javajavasound

提问by Panagiotis Korros

I am using the following code to play a sound file using the java sound API.

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

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

The method call to the Clip.start() method returns immediately, and the system playbacks the sound file in a background thread. I want my method to pause until the playback has completed.

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

Is there any nice way to do it?

有什么好的方法可以做到吗?

EDIT: For everyone interested in my final solution, based on the answer from Uri, I used the code below:

编辑:对于每个对我的最终解决方案感兴趣的人,根据 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 );
}

采纳答案by Uri

A sound clip is a type or Line and therefore supports Line listeners.

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

If you use addLineListener, you should get events when play starts and stops; if you're not in a loop, you should get a stop when the clip ends. However, as with any events, there might be a lag before the actual end of playback and the stopping.

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

Making the method wait is slightly trickier. You can either busy-wait on it (not a good idea) or use other synchronization mechanisms. I think there is a pattern (not sure about it) for waiting on a long operation to throw a completion event, but that's a general question you may want to post separately to SO.

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

回答by sancho21

I prefer this way in Java 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();

回答by Arash Tarafar

you can just put this code instead:

你可以把这个代码改为:

assume your clip1 is playing and you want a clip2 to be played right after that, you can:

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

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

and, to make this work without delaying your main task (I say this because the while loop makes the work wait for clip1 to finish, no matter what the next work is...) you can make a new thread in the point where you want it to happen, and just put the code in its run() method... GOOD LUCK!

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

回答by Unai Vivi

As of JDK8, Clip's listener is kind of buggy (i.e. it can happen that it fires the Type.STOP twice for a single reproduction of the audio (.start()).

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

I would therefore use something like:

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

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.

In addition, you could take a look to the new AudioClipclass that JFX8 provides (has some nifty methods to fiddle with)

此外,您可以查看JFX8 提供的新AudioClip类(有一些漂亮的方法可以使用)

回答by googol4u

I have used a wait/notify to implement this. Just for your reference.

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

        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();