在不同线程中播放多个 MP3 曲目
我试图在不同的线程中同时运行 4 个 MP3 曲目。我正在使用 JLayer1.0 MP3 库 来播放 MP3。鉴于我无法控制线程何时启动,我使用 CountDownLatch 至少让它们同时运行。然而,每次我运行该程序时,曲目都会播放,但会始终在不同的时间开始,导致它们不定时。
这是我的程序:
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();
}
}
我知道我无法控制最终线程打开锁存器后每个线程如何执行代码。看来我必须进入 JLayer1.0 实现才能更好地控制 MP3 何时开始播放。
有没有什么简单的方法可以让 MP3 曲目在整个播放过程中保持同步?我知道多轨播放器已经在java中实现了,但似乎比我想要的更复杂。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
阅读 CountdownLatch 的 API 让我想知道您是否可以按照您尝试使用它的方式使用它。
“一种同步辅助工具,允许一个或多个线程等待,直到其他线程中执行的一组操作完成。”
CountdownLatch 示例中的 run 方法如下所示:
它等待开始信号,但直到其工作方法完成后才执行 countDown。看来您误用了 CountdowLatch,它的真正目的是确保所有线程在主线程完成之前完成。
所以我的建议是:像您正在做的那样启动每个线程,但不要使用 CountdownLatch,而是让每个线程在静态布尔值上循环,直到值更改为 false。这样,您就可以启动所有线程,然后您可以将 ThreadLocal 设置为 false,并且它们都应该调用 play()。请注意,这可能不是生产质量的代码,您确实应该让每个线程侦听一个事件,但请尝试一下。
总体问题可能是操作系统的线程调度才是罪魁祸首,这就是 JPlayer 1.0 开发人员找到的解决方案,但如果硬件和操作系统合作,应该可以让 play()每个线程同时发生加上或减去几毫秒。
最后编辑:我对 CountdownLatch 的了解越多,我就越认为您可以使用它来同步线程的启动。您不需要每个线程中的倒计时,您只需要:
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:
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: