why this code doesn't play the sound file
Asked Answered
D

3

3

The code

import javax.sound.sampled.*;
import java.io.*;

public class Tester {
static Thread th;


public static void main(String[] args) {
    startNewThread();   
   while( th.isAlive() == true) {
       System.out.println("sound thread is working");
   }
}

public static void startNewThread() {
   Runnable r = new Runnable() {
       public void run() {
           startPlaying();
       }
   };
   th =new Thread(r);
   th.start();
} 
public static void startPlaying() {
   try {            
        AudioInputStream ais = AudioSystem.getAudioInputStream(new File("d:/UnderTest/wavtester.wav"));
        Clip clip = AudioSystem.getClip();
        clip.open(ais);
        clip.loop(-1); // keep playing the sound                  
   } catch(Exception exc) {
       System.out.println(exc);
     }       
 }
}

This code does give the output sound thread working , but does not play anything. In this code i have started a separate thread for playing sound and the program should not terminate till the sound thread has finished it's job .But the program terminates after printing series of sound thread working.

What is the reason for this ( for the program terminating and the sound not playing) ?

Dialectics answered 29/7, 2011 at 8:55 Comment(6)
I did mean edit your other question. But the same comments I made there, apply here. What do the last two single line comments in the linked source mean to you?Elstan
@ Andrew Thompson It means the program will terminate only after the daemon thread , generated by clip has finished. But i don't know the reason why it finishes after 3-4 seconds of playing.Dialectics
@ Andrew Thompson JOptionPane appears for a while and disappears on it's own. I had posted this question before but didn't get any meaningful answer #6595421Dialectics
"JOptionPane appears for a while and disappears on it's own." The only thing I can think of that would explain that is "Your Java installation is broken".Elstan
@ Andrew Thompson what do you mean by is brokenDialectics
@ Andrew Thompson Is this the best way to play a wav / any sound file ? The code i have posted as an answerDialectics
B
6

The problem is that Clip already launches a background daemon thread to play the wave file.

So, the execution flow of your code is as follows:

  • the main thread launches a secondary (useless) thread
  • the secondary thread launches a daemon thread (which will play the sound)
  • in the mean time, the main thread keeps printing something while the secondary thread is alive
  • When the secondary thread finishes launching the playback thread, it will end, so the secondary thread will not be in the active state anymore
  • the main thread will notice that the secondary thread is not active and will end as well
  • Since the playback thread is a daemon thread, the JVM will exit (because the only threads left are daemon threads)

The final result is precisely what you see: some text get printed by the main thread while the secondary thread is launching the playback thread, and when the playback thread would start playing, boom, the JVM finishes. Sometimes you might even be able to listen some "clicking" from the headphones (as the sound starts to play) before the JVM exits.

The easiest fix is to make the secondary thread (ie, a non-daemon thread) sleep while the sound is playing.

...
  clip.open(ais);
  clip.loop(-1);
  Thread.sleep(amountToSleep);
...

One important thing to notice: about 1 year ago, when I worked with that java API, I noticed that the method getMicrosecondLength() is buggy. I was coding both in Windows and Linux, and in one platform I'd get the correct value, but in the other, the very same method would return the length in milliseconds!

I found that the most reliable way to get the real length of the sound is to use the getFrameLength() method, and calculate the length from that.

I couldn't locate the code I wrote back then in this notebook. I will check later in another PC, and if I find it I will post a complete example (that works reliably on both Windows with Sun JVM and Linux with either OpenJDK or Sun).

Boreal answered 29/7, 2011 at 10:28 Comment(2)
I get a frame length of 504845 How can i know the track length from it ?Dialectics
This is what I don't remember exactly... I'd have to check my code to be sure. But you can try something like clip.getFormat().getFrameRate(), which should give you the amount of frames in each second (usually this value would be something between 8000 and 44100). Then you divide the number of frames (getFrameLength()) by the frame rate and get the length of the clip in seconds.Boreal
D
0
import javax.sound.sampled.*;
import java.io.*;
import javax.swing.*;

public class Tester {
static Thread th;


public static void main(String[] args) throws Exception {
     Clip clip = AudioSystem.getClip();
     AudioInputStream ais = AudioSystem.getAudioInputStream(new File("d:/UnderTest/wavtester.wav"));
     clip.open(ais);
     clip.loop(0);
     // Calculate totalFrames
     long totalFrames = (long)(clip.getFrameLength() * clip.getFormat().getFrameRate());
     Thread.sleep( ( totalFrames* 1000 )); // pause the thread till the sound plays

     System.out.println(clip.getFrameLength());
     System.out.println(clip.getFormat().getFrameRate());           
 }
}
Dialectics answered 29/7, 2011 at 11:11 Comment(1)
I'd remove the try {} catch {} block and leave only Thread.sleep(...), since it is not necessary in such a simple code (you've even declared the main method as throws Exception), and in production code this is far from the correct way to deal with InterruptedException.Boreal
H
0
while(clip.isRunning()){} 

is better

Hepler answered 30/9, 2011 at 0:25 Comment(1)
what if i have stopped/paused the line via clip.stop() and the main thread finishes it's work. It will return true and i will be thrown out of the program . I don't think this check suits the condition.Dialectics

© 2022 - 2024 — McMap. All rights reserved.