skip to Main Content

I have a JavaFX Tetris game that uses the MediaPlayer class to play music and sound effects. Specifically, in my SoundPlayer class that handles all audio, I load in the game’s .wav files when game is started, and iterate each file, creating a Media object for each one, and then a MediaPlayer object for each Media object. The MediaPlayers, one for each sound, are stored in an array for future playback using the class’s playSound method that accepts an integer argument that indicates the index of the MediaPlayer that corresponds to the desired sound effect. It works perfectly on windows and mac, but on my laptop that runs popOS, while it technically works, it has the following issues:

  • when the game launches, some sounds will play correctly, but after a few times of playing, the playback volume will become so quiet that you can barely hear it, even though the actual volume attribute of the MediaPlayer does not change

  • some sounds do not play the entire sound, only playing part of it.

The background music and most sounds work correctly, but for some, these issues occur.
Here is my code for playing a sound when triggered by the game:

public void playSound(int index)
{
     MediaPlayer mediaPlayer = mediaPlayerList[index];
     mediaPlayer.stop();
     mediaPlayer.seek(Duration.ZERO);
     mediaPlayer.play();
}

This works perfectly on my other computers, but I only have this issue on my popOS laptop.
Does anyone know if this is a Linux issue with the way Java.sound works, or if perhaps it is an issue with my laptop hardware? I have tried configuring the java.sound.config file to no avail and am at a loss.

As stated above, I have tried looking up fixes for java.sound config file and nothing I have found seems to work, so I am starting to think it might be an issue with my laptop, but I thought I would ask to see if anyone is aware of anything I may have missed. I am a CS student currently and this is my first attempt at a project using Java for audio playback, so I am fairly ignorant on how it works at a low level. Any help would be greatly appreciated if anyone is aware of any fixes or potential causes for this. Also, my audio driver is up to date and all other audio playback i have tried on this laptop works fine.

Initially, I was using the Java Sound API’s Clip class to playback sound effects, and the audio playback worked correctly with Clips, but my issue with Clips was that when sounds were rapidly triggered by user input, as is frequently the case in my game, I found that audio skipped somewhat frequently likely due to my limited knowledge of multi-threading, so I decided to try out JavaFX’s MediaPlayer instead, which is far more responsive and optimized, and as I said, works perfectly on my Windows machine and mac…..it is only having this issue on my Linux laptop. If it is any help, I am using openjdk-17….I don’t know if this is an issue specifically with open-jdk vs oracle jdk, or something of that nature.

2

Answers


  1. The open-source AudioCue library (obtainable via Maven) is basically a Clip that has been written to support multi-threading. It should work for you, and is free to use.

    There are multiple good points in the comments (which are supposed to be for asking questions and clarifications of the original post, afaik) that seem to me could well be listed as "answers. My answer here will duplicate some of those points.

    For short cues, prefer a class which is just loaded one time only and can played back multiple times directly from memory: Clip, AudioClip, to classes which require reading from files or other forms of streaming: SourceDataLine, MediaPlayer.

    The nice thing about AudioClip is that it does support concurrent playback, unlike Clip or the streaming playback methods. So, you can take the same AudioClip and play it multiple times without first calling a stop method and repositioning its playback position. Each iteration should play through to the end.

    There was a time when some Linux operating systems would only allow a single sound source to play at a given moment, but that was quite a while ago. IDK if that might be the issue for the particular OS configuration you are testing. If it is, going back to the AudioCue library I mentioned at the start, it has a class, AudioMixer, for funneling all the sound cues into a single output line which would be a workaround for that situation.

    Login or Signup to reply.
  2. I moved my and Slaw’s notes from comments to an answer. They might not solve the actual issue, instead, they are guides to troubleshooting some issues with JavaFX Media playback.

    Use AudioClip for short audio playback

    javafx.scene.media.AudioClip is typically more appropriate for short sound effects.

    See further explanation in Phil’s answer and also the description from the AudioClip javadoc:

    An AudioClip represents a segment of audio that can be played with minimal latency. Clips are loaded similarly to Media objects but have different behavior, for example, a Media cannot play itself. AudioClips are also usable immediately. Playback behavior is fire and forget: once one of the play methods is called the only operable control is stop(). An AudioClip may also be played multiple times simultaneously.

    To accomplish the same task using Media one would have to create a new MediaPlayer object for each sound played in parallel. Media objects are however better suited for long-playing sounds. This is primarily because AudioClip stores in memory the raw, uncompressed audio data for the entire sound, which can be quite large for long audio clips. A MediaPlayer will only have enough decompressed audio data pre-rolled in memory to play for a short amount of time so it is much more memory efficient for long clips, especially if they are compressed.

    As noted in comments:

    I ended up using AudioClips instead of MediaPlayers as it seems they are designed more for creating and object once and then using that same instance for repeated playback rather than creating and disposing of MediaPlayers. Everything is working great now.

    Implement error handling for MediaPlayers

    I am not getting any errors

    There is error handling code in the media package javadoc. Try it and see if it reports anything.

    Most media errors are not reported if handled by default, it can just silently fail. If you want to report and handle them thoroughly, then you need to implement the full and extensive media exception logic from the media player package documentation.

    Of course, even then there may still be no actual error reported if the issue is actually in your code or the system does not accurately detect and provide feedback for a problem.

    Check your code logic for correctness

    not playing back the full sound (the audio cuts out)

    Your code stops the player. then starts playing from the start. Depending on timing of calls, cutting off existing sounds before they complete playing would be expected.

    Disregard java.sound APIs and documentation if you don’t use them

    java.sound isn’t related to JavaFX media, configuring it won’t help you with the playing sounds using the JavaFX MediaPlayer or AudioClip APIs.

    Unlike a lot of things in JavaFX where the framework is mostly single-threaded, when you look at the MediaPlayer doc, it notes that:

    Consider asynchronous operation

    The operation of a MediaPlayer is inherently asynchronous.

    Usually, you don’t need to worry much about this, but it could be causing issues in your case on your platform. Methods like seek won’t work if the player is in an UNKNOWN state.

    Consider creating new MediaPlayers rather than reusing them

    Rather than reusing MediaPlayers, you could create a new one each time you use one if they are getting into a broken state on your platform after repeated use as you describe. But I guess avoid that if possible as it may take time and resources to ready the players each time a new one is created.

    As noted by the asker:

    As for creating a new MediaPlayer each time a sound needs to be played, I tried that, but due I found that it caused lag when there is rapid user input.

    Ensure you have the correct native platform dependencies installed

    JavaFX media uses GStreamer Lite for playback (the media module ships with the native gstreamer library, you don’t need to install it). It may have some dependencies on other components in the OS. For instance JavaFX 21 requires GTK 3. But I don’t know what those dependencies may be and what you would do if the unknown dependencies aren’t met 🙂

    Perhaps try installing a packaged JDK that includes JavaFX for your Linux platform (like Liberica Full JDK) from a native package type for the platform (like an RPM or DEB). If it is properly packaged, the package manager would ensure any native dependencies are installed at the right versions on the platform. I don’t know if this would make any difference for you, but may be something to consider.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search