I have a highschool capstone where I must create a music player which plays music. However, whenever I connect my bluetooth headphones(airpods or musicozy) and then disconnect them, the MediaPlayer halts and an error is produced. I've searched on the internet for an answer but am unable to find one. If someone could help me that would be great! I'm using Javafx 17.0.2 and JDK 11.
Here's a mini reproducible example below.
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$7(MediaPlayer.java:2566)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(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$3(WinApplication.java:184)
at java.base/java.lang.Thread.run(Thread.java:834)
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
The problem with your recovery is that you are seeking too soon. The docs for seek state that it does nothing while the media player is stopped, but you aren't waiting for the state to change after calling play().
Try this:
mediaPlayer.setOnError( () -> {
mediaPlayer = new MediaPlayer(media);
System.out.println(durationBackup.toMillis());
mediaPlayer.setOnPlaying(() ->{
mediaPlayer.seek(durationBackup);
mediaPlayer.setOnPlaying(null);
});
mediaPlayer.play();
});