Java Sound crash fixes for Linux. (issue #1)

- Explicitly supply the AudioFormat when creating a Clip.
- Disable Master Gain if unsupported (e.g. in PulseAudio).
- Do not try to play uninitialized sounds (e.g. LineUnavailableException during creation, seems to happen regularly with PulseAudio).

Other changes:
- Errors replaced with debugs in 'getTrackLength()' if audio fields inaccessible.
- Do not log ThreadDeath exceptions (it's a known issue, and only clutters the log file).

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2014-07-08 00:42:50 -04:00
parent a9cc7a3deb
commit 83c475cdc1
3 changed files with 24 additions and 8 deletions

View File

@ -246,7 +246,7 @@ public class MusicController {
/** /**
* Gets the length of the track, in milliseconds. * Gets the length of the track, in milliseconds.
* Returns 0f if no file is loaded or an MP3 is currently being converted. * Returns 0 if no file is loaded or an MP3 is currently being converted.
* @author bdk (http://slick.ninjacave.com/forum/viewtopic.php?t=2699) * @author bdk (http://slick.ninjacave.com/forum/viewtopic.php?t=2699)
*/ */
public static int getTrackLength() { public static int getTrackLength() {
@ -265,7 +265,8 @@ public class MusicController {
length.setAccessible(true); length.setAccessible(true);
duration = (float) (length.get(audio)); duration = (float) (length.get(audio));
} catch (Exception e) { } catch (Exception e) {
Log.error("Could not get track length.", e); Log.debug("Could not get track length.");
return 0;
} }
return (int) (duration * 1000); return (int) (duration * 1000);
} }

View File

@ -103,7 +103,8 @@ public class Opsu extends StateBasedGame {
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override @Override
public void uncaughtException(Thread t, Throwable e) { public void uncaughtException(Thread t, Throwable e) {
Log.error("** Uncaught Exception! **", e); if (!(e instanceof ThreadDeath)) // TODO: see MusicController
Log.error("** Uncaught Exception! **", e);
} }
}); });

View File

@ -23,9 +23,11 @@ import itdelatrisu.opsu.states.Options;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem; import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip; import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl; import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException; import javax.sound.sampled.UnsupportedAudioFileException;
@ -154,7 +156,13 @@ public class SoundController {
try { try {
URL url = ResourceLoader.getResource(ref); URL url = ResourceLoader.getResource(ref);
AudioInputStream audioIn = AudioSystem.getAudioInputStream(url); AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
Clip clip = AudioSystem.getClip();
// GNU/Linux workaround
// Clip clip = AudioSystem.getClip();
AudioFormat format = audioIn.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, format);
Clip clip = (Clip) AudioSystem.getLine(info);
clip.open(audioIn); clip.open(audioIn);
return clip; return clip;
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) { } catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
@ -218,6 +226,9 @@ public class SoundController {
* @param volume the volume [0, 1] * @param volume the volume [0, 1]
*/ */
private static void playClip(Clip clip, float volume) { private static void playClip(Clip clip, float volume) {
if (clip == null) // clip failed to load properly
return;
if (volume > 0f) { if (volume > 0f) {
// stop clip if running // stop clip if running
if (clip.isRunning()) { if (clip.isRunning()) {
@ -225,10 +236,13 @@ public class SoundController {
clip.flush(); clip.flush();
} }
// set volume // PulseAudio does not support Master Gain
FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); if (clip.isControlSupported(FloatControl.Type.MASTER_GAIN)) {
float dB = (float) (Math.log(volume) / Math.log(10.0) * 20.0); // set volume
gainControl.setValue(dB); FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
float dB = (float) (Math.log(volume) / Math.log(10.0) * 20.0);
gainControl.setValue(dB);
}
// play clip // play clip
clip.setFramePosition(0); clip.setFramePosition(0);