2009-02-17 8 views
6

J'utilise le code suivant pour lire un fichier son en utilisant l'API de son java.Comment puis-je attendre la fin d'un clip audio java?

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

L'appel de méthode à la méthode Clip.start() retourne immédiatement, et le système lectures du fichier audio dans un fil de fond. Je veux que ma méthode fasse une pause jusqu'à ce que la lecture soit terminée.

Y at-il une bonne façon de le faire?

EDIT: Pour tout le monde intéressé par ma solution finale, basée sur la réponse d'Uri, j'ai utilisé le code ci-dessous:

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

Répondre

4

Un clip audio est un type ou ligne et supporte donc les auditeurs ligne.

Si vous utilisez addLineListener, vous devriez recevoir des événements lorsque la lecture commence et s'arrête; Si vous n'êtes pas dans une boucle, vous devriez vous arrêter lorsque le clip se termine. Cependant, comme pour tous les événements, il peut y avoir un décalage avant la fin de la lecture et l'arrêt.

Faire attendre la méthode est un peu plus délicat. Vous pouvez soit être occupé, soit attendre (ce n'est pas une bonne idée) ou utiliser d'autres mécanismes de synchronisation. Je pense qu'il existe un modèle (pas sûr) d'attendre une longue opération pour lancer un événement d'achèvement, mais c'est une question générale que vous voudrez peut-être publier séparément à SO.

6

vous pouvez simplement mettre ce code à la place:

supposer que votre clip1 joue et que vous voulez un clip2 à jouer juste après cela, vous pouvez:

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

et, pour faire ce travail sans retarder votre tâche principale (je dis cela parce que la boucle while fait que le travail attend que clip1 se termine, peu importe le travail suivant ...) vous pouvez créer un nouveau thread au point où vous voulez qu'il se produise, et juste mettre le code dans sa méthode run() ... GOOD LUCK!

+0

Cela a fonctionné comme un charme pour une simple application du texte à la parole que je travaillais. – progyammer

+0

Je doute que celui-ci soit une technique gourmande en ressources. – sancho21

0

Au JDK8, auditeur de Clip est une sorte de poussette (il peut arriver qu'il déclenche le Type.STOP deux fois pour une seule reproduction de l'audio (.start()).

Je voudrais donc utiliser quelque chose comme :

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. 

En outre, vous pouvez jeter un oeil à la nouvelle classe AudioClip que JFX8 fournit (a quelques méthodes astucieuses pour jouer avec)

0

J'ai utilisé une attente/notification pour mettre en œuvre ce juste fo. r votre référence.

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

Je préfère cette façon en 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(); 
Questions connexes