每当您断开蓝牙耳机时,Javafx MediaPlayer 都会出错

Javafx MediaPlayer runs into error whenever you disconnect bluetooth headphones

我有一个高中顶点,我必须在其中创建一个播放音乐的音乐播放器。但是,每当我连接蓝牙耳机(airpods 或 musicozy)然后断开它们时,MediaPlayer 就会停止并产生错误。我在互联网上搜索了答案,但找不到。如果有人可以帮助我,那就太好了!我正在使用 Javafx 17.0.2 和 JDK 11.

下面是一个可重现的迷你示例。

JavaFxMediaPlayer

package apprunner;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.stage.Stage;

public class JavaFxMediaPlayer extends Application {

    public static void main(String[] args) throws MalformedURLException, IOException {
        launch(args);

    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setTitle("My");
        Button button = new Button("Play Song");
        Scene scene = new Scene(button, 200, 100);
        stage.setScene(scene);
        stage.show();
        File file = new File("C:\Users\John Doe\OneDrive\Desktop\YourLieInAprilTest\Mp3Test.mp3");
        String path = file.toURI().toASCIIString();
        Media media = new Media(path);
        MediaPlayer mediaPlayer = new MediaPlayer(media);
        button.setOnAction(new EventHandler() {
            @Override
            public void handle(Event arg0) {
                mediaPlayer.stop();
                mediaPlayer.play();
            }
        });
        Runnable printStackTrace = new Runnable() {
            public void run() {
                mediaPlayer.getError().getMessage();
                mediaPlayer.getError().printStackTrace();
            }
        };
        mediaPlayer.setOnError(printStackTrace);

    }
}

模块信息

module MotisHarmony {
    requires javafx.swt;
    requires javafx.base;
    requires javafx.controls;
    requires javafx.fxml;
    requires javafx.graphics;
    requires javafx.media;
    requires javafx.swing;
    requires javafx.web;
    exports mediaplayerjavafx;
    opens mediaplayerjavafx to javafx.graphics;
}

产生错误

MediaException: PLAYBACK_HALTED : IDirectSoundBuffer_GetStatus The operation completed successfully.
, IDirectSoundBuffer_GetCurrentPosition: The operation completed successfully.
, dwStatus: 0
    at javafx.media/javafx.scene.media.MediaException.haltException(MediaException.java:150)
    at javafx.media/javafx.scene.media.MediaPlayer$_PlayerStateListener.lambda$onHalt(MediaPlayer.java:2566)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater(PlatformImpl.java:457)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater(PlatformImpl.java:456)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop(WinApplication.java:184)
    at java.base/java.lang.Thread.run(Thread.java:834)

新的 JavaFxMediaPlayer 修复尝试(搜索不工作)

package apprunner;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.stage.Stage;
import javafx.util.Duration;

public class AppRunner extends Application {

    public Duration durationBackup = null;

    MediaPlayer mediaPlayer;

    public static void main(String[] args) throws MalformedURLException, IOException {
        launch(args);

    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setTitle("My");
        Button button = new Button("Play Song");
        Scene scene = new Scene(button, 200, 100);
        stage.setScene(scene);
        stage.show();
        File file = new File("C:\Users\John Doe\OneDrive\Desktop\YourLieInAprilTest\Mp3Test.mp3");
        String path = file.toURI().toASCIIString();
        Media media = new Media(path);
        mediaPlayer = new MediaPlayer(media);
        button.setOnAction(new EventHandler() {
            @Override
            public void handle(Event arg0) {
                mediaPlayer.stop();
                mediaPlayer.play();
            }
        });
        mediaPlayer.currentTimeProperty().addListener(new InvalidationListener() {
            public void invalidated(Observable ov) {
                //Here we keep a backup of the current duration of the song just incase the mediaPlayer crashes, which it does everytime you disconnect a bluetooth headset for some reason
                durationBackup = mediaPlayer.getCurrentTime();
            }
        });
        //Here I try to create a new MediaPlayer and go to the last position we were at before the mediaPlayer halted
        Runnable attemptToResetMediaPlayer = new Runnable() {
            public void run() {
                mediaPlayer = new MediaPlayer(media);
                mediaPlayer.play();
                System.out.println(durationBackup.toMillis());
                mediaPlayer.seek(durationBackup);
            }
        };
        mediaPlayer.setOnError(attemptToResetMediaPlayer);
    }
}

如何重现错误

额外信息

Link to the Mp3 file I used to test. https://drive.google.com/file/d/1CvAafbMviQ7nvKyojnem9GK73LJsD6MJ/view?usp=sharing

I am using JDK 11 and Javafx 17.0.2

System Type: 64-bit operating system, x64-based processor

Processor: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz 2.81 GHz

Windows Edition: Windows 10 Home

你恢复的问题是你求的太早了。 seek 的文档声明它在媒体播放器停止时不执行任何操作,但您不会在调用 play() 后等待状态更改。

试试这个:

    mediaPlayer.setOnError( () -> {
            mediaPlayer = new MediaPlayer(media);
            System.out.println(durationBackup.toMillis());
            mediaPlayer.setOnPlaying(() ->{
                mediaPlayer.seek(durationBackup);
                mediaPlayer.setOnPlaying(null);
            });
            mediaPlayer.play();
    });