Reputation: 773
I am trying to run 4 MP3 tracks at the same time in different threads. I am using the JLayer1.0 MP3 library to play the MP3s. Given that I cannot control when the threads will start, I am using a CountDownLatch to at least get them to run at the same time. However, every time I run the program, the tracks will play, but will consistently start at different times causing them to be off timing.
Here's my program:
public class MP3 {
private String filename;
private Player player;
private final CountDownLatch runlatch;
// constructor that takes the name of an MP3 file
public MP3(String filename, CountDownLatch runlatch) {
this.filename = filename;
this.runlatch = runlatch;
}
// play the MP3 file to the sound card
public void play() {
try {
FileInputStream fis = new FileInputStream(filename);
BufferedInputStream bis = new BufferedInputStream(fis);
System.out.println(filename);
player = new Player(bis);
}
catch (Exception e) {
System.out.println("Problem playing file " + filename);
System.out.println(e);
}
// run in new thread to play in background
Thread track = new Thread() {
public void run() {
try {
try {
runlatch.countDown();
runlatch.await();
player.play();
} catch (InterruptedException e) {
System.out.println(e);
}
}
catch (Exception e) { System.out.println(e); }
}
};
track.start();
}
// test client
public static void main(String[] args) throws InterruptedException {
CountDownLatch runlatch = new CountDownLatch(4);
String filename1 = args[0];
String filename2 = args[1];
String filename3 = args[2];
String filename4 = args[3];
MP3 track1 = new MP3(filename1, runlatch);
MP3 track2 = new MP3(filename2, runlatch);
MP3 track3 = new MP3(filename3, runlatch);
MP3 track4 = new MP3(filename4, runlatch);
track1.play();
track2.play();
track3.play();
track4.play();
}
}
I know that I cannot control how each thread executes the code after the latch is opened by the final thread. It seems that I would have to get into the JLayer1.0 implementation to have more control of when the MP3s will start to play.
Is there any simple way to get the MP3 tracks to stay in timing throughout their duration? I know a multiple track player has already been implemented in java, but it seems to be more complex then what I want.
Upvotes: 2
Views: 1470
Reputation:
Reading the API for CountdownLatch makes me wonder if you can use it the way you are trying to use it.
"A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes."
The run method in the CountdownLatch example looks like this:
public void run() {
try {
startSignal.await();
doWork();
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
It waits for the start signal, but doesn't do the countDown until after it's work method completes. It seems like you are mis-using the CountdowLatch and that it's real purpose is to make sure that all threads are finished before the main thread can complete.
So here's my suggestion: Start up each thread like you are doing, but instead of using CountdownLatch, have each thread loop on a static boolean until the value changes to false. That way, you get all the threads started up, then you can set your ThreadLocal to false and they should all call play(). Note that this is probably not production-quality code and that you really should have each thread listen for an event, but give it a try.
The overall issue could be that the OS scheduling of threads is what is to blame and that is what JPlayer 1.0 developers figured out a solution for, but if the hardware and OS are cooperating, it should be do-able to get play() to happen at the same time for each thread plus or minus a couple of milliseconds.
Last edit: The more I look at CountdownLatch, the more I think you can use it to synchronize the threads starting. You don't want the countdown in each thread, you just want:
startSignal.await();
play();
Upvotes: 1