如何用JavaFX播放mp3片段?

时间:2013-12-07 12:51:57

标签: javafx-2

我想开发一个以特定方式播放mp3文件的Java程序。我使用startTime和endTime在此文件中标记了许多片段。该程序应该播放第一个片段,然后睡5秒钟。然后播放第二个片段并再次睡眠。等等。我使用JavaFX类MediaPlayer。程序原型如下:

import javafx.application.Application;
import javafx.stage.Stage;
import java.io.FileNotFoundException;
import java.io.IOException;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.util.Duration;
import java.util.concurrent.TimeUnit;

public class JavaFXMediaPlayer02 extends Application {
    @Override
    public void start(Stage stage) throws FileNotFoundException,IOException,InterruptedException {
        Media media = new Media("file:///D:/1016_00.mp3");
        MediaPlayer mediaPlayer = new MediaPlayer(media);
//Set and play the first fragment of mp3-file
        mediaPlayer.setStartTime(Duration.millis(1219.0));
        mediaPlayer.setStopTime(Duration.millis(2728.0));
        mediaPlayer.play();
        System.out.println("1st fragment played!");
        TimeUnit.SECONDS.sleep(5);
//Set and play the second fragment
        mediaPlayer.setStartTime(Duration.millis(3947.0));
        mediaPlayer.setStopTime(Duration.millis(6629.0));
        mediaPlayer.play();
        System.out.println("2nd fragment played!");
        TimeUnit.SECONDS.sleep(5);
//Set and play the second fragment
        mediaPlayer.setStartTime(Duration.millis(7453.0));
        mediaPlayer.setStopTime(Duration.millis(10704.0));
        mediaPlayer.play();
        System.out.println("3rd fragment played!");
    }
    public static void main(String[] args) {
        launch(args);
    }
}

但我只听到第三个片段。怎么了?为什么我没有听到第一个和第二个片段?如何纠正我的程序? JavaFX不适合我的任务吗?

1 个答案:

答案 0 :(得分:2)

这里的问题在于TimeUnit.SECONDS.sleep(5);调用。此方法将当前线程设置为睡眠。在您的情况下,此线程是JavaFX应用程序线程。这导致整个应用程序“冻结”(如果你添加了一些GUI元素会更加明显),因此mediaPlayer.play();命令被执行,但由于睡眠功能而立即被“冻结”。在`TimeUnit.SECONDS.sleep(5);来电之后,您为MediaPlayer设置新的开始和结束时间,然后再次执行play(),以便在新的开始时间开始播放。这就是为什么只播放你的最后一个片段。

现在解决方案: 您永远不应该在JavaFX App Thread上调用Thread.sleep()或类似的方法。但在你的情况下,你必须在播放片段之间等待一段时间。第一种方法是在新线程上调用Thread.sleep()TimeUnit.SECONDS.sleep(5);并在JFX App Thread上调用Mediaplayer方法。但这不能正常工作,因为您尚未设置调用线程的“顺序”。有多种方法可以执行此操作(通过SemaphoresLocks and ConditionsJavaFX Concurrency等等...)

我尝试通过快速编程来解决您的问题,但我遇到了mediaPlayer.setStopTime(Duration.millis());的问题。它似乎不适用于我的计算机,因此文件始终播放到最后。我添加了一个停止按钮来模拟自动停止。 以下类设置新的起点和终点并播放片段。如果媒体播放器停止,它将调用LittleMediaScheduler类上的下一个片段。

public class LittleMediaHelper implements Runnable {

public double startTime;
public double endTime;
public MediaPlayer player;
public int id;
public LittleMediaScheduler scheduler;

public LittleMediaHelper(double startTime, double endTime,
        MediaPlayer player, int id) {
    this.startTime = startTime;
    this.endTime = endTime;
    this.player = player;
    this.id = id;
}

public LittleMediaScheduler getScheduler() {
    return scheduler;
}

public void setScheduler(LittleMediaScheduler scheduler) {
    this.scheduler = scheduler;
}

@Override
public void run() {

    Platform.runLater(new Runnable() {

        @Override
        public void run() {

            player.setStartTime(Duration.millis(startTime));
            player.setStopTime(Duration.millis(endTime));

            System.out.println(player.getStartTime());
            System.out.println(player.getStopTime());
            player.play();
            player.setOnStopped(new Runnable() {

                @Override
                public void run() {

                    int idtmp = id + 1;
                    System.out.println("NEXT " + idtmp);

                    scheduler.call(idtmp);

                }
            });

        }
    });

}

}

这个类负责在新线程上睡眠一定数量,并在成功睡眠后调用下一个LittleMediaHelper课程播放功能。

public class LittleMediaScheduler {
private ArrayList<LittleMediaHelper> hArrL;
private int SLEEPTIME = 2000;

public LittleMediaScheduler(LittleMediaHelper... helpers) {
    this.hArrL = new ArrayList<>();
    for (LittleMediaHelper h : helpers) {
        h.setScheduler(this);
        System.out.println(h.startTime);
        this.hArrL.add(h);
    }

    System.out.println(hArrL.size());

}

public void init() {
    Thread t = new Thread(this.hArrL.get(0));
    t.start();
}

public void call(final int id) {
    Thread t = new Thread(new Task<String>() {

        @Override
        protected String call() throws Exception {
            Thread.sleep(SLEEPTIME);
            return null;
        }

        @Override
        protected void succeeded() {
            super.succeeded();
            System.out.println("Next playing...");
            if (id > LittleMediaScheduler.this.hArrL.size() - 1) {
                return;
            }
            LittleMediaHelper next = LittleMediaScheduler.this.hArrL
                    .get(id);
            Thread nextT = new Thread(next);
            nextT.start();
        }
    });
    t.start();
}

}

带有停止按钮的主类。没有mediaPlayer.pause(),虽然设置了新的起始端点,但播放器会以某种方式重复两次。不知道这是不是一个bug。

public class JavaFXMediaPlayer02 extends Application {
@Override
public void start(Stage stage) throws FileNotFoundException, IOException,
        InterruptedException {
    Media media = new Media("file:///C:/test.mp3");
    final MediaPlayer mediaPlayer = new MediaPlayer(media);

    LittleMediaHelper phase1 = new LittleMediaHelper(0, 1000, mediaPlayer,
            0);
    LittleMediaHelper phase2 = new LittleMediaHelper(50000, 55000,
            mediaPlayer, 1);
    LittleMediaHelper phase3 = new LittleMediaHelper(200000, 200500,
            mediaPlayer, 2);
    LittleMediaScheduler scheduler = new LittleMediaScheduler(phase1,
            phase2, phase3);

    scheduler.init();

    Group g = new Group();
    Button b = new Button("STOP");
    b.setOnAction(new EventHandler<ActionEvent>() {

        @Override
        public void handle(ActionEvent arg0) {
            mediaPlayer.pause();
            mediaPlayer.stop();
        }
    });

    g.getChildren().add(b);
    Scene sc = new Scene(g);
    stage.setScene(sc);
    stage.show();

}

public static void main(String[] args) {
    launch(args);
}
}