2

My game plays back sound via the usual method:

sdl.open();
sdl.start();
sdl.write(data, 0, data.length);
sdl.drain();
sdl.stop();
sdl.close();

And the user may cancel the playback (asynchronously):

sdl.stop();

This cancellation works nicely under Windows, but for one user running OSX 10.5.8 with Java 6 the program hangs. Threaddump shows the playback thread is inside drain(): com.sun.media.sound.MixerSourceLine.nDrain. If the user doesn't interrupt the sound, it completes nicely and the application continues.

My questions are:

  • Is this an OSX Java bug?
  • Should I use sdl.close() instead of stop?
  • Any suggestions or experience on a workaround?

Edit: I found this bug report with similar effects, but the page says it is fixed.

akarnokd
  • 69,132
  • 14
  • 157
  • 192
  • This [example](http://stackoverflow.com/questions/2064066/does-java-have-built-in-libraries-for-audio-synthesis/2065693#2065693) completes normally on Mac OSX 10.5.8, Java 6. – trashgod Oct 18 '11 at 06:43
  • @trashgod That example does not get closed asynchronously. I mentioned in the question that when not interrupted, the sound plays fine. – akarnokd Oct 18 '11 at 06:57
  • Do you get the same behavior using [BigClip](http://stackoverflow.com/questions/5667454/playing-audio-file-in-java-application/5668510#5668510)? – Andrew Thompson Oct 18 '11 at 07:49
  • @AndrewThompson I can't really experiment, because the issue came through an error report from an OSX user without any programming experience (and I'm developing on a Windows machine). It took a hour to explain how to get the threaddump done on his system. Looking at your code it uses smaller blocks for the audio and it may get stopped before the drain() gets called. My code puts the entire audio into the sound buffer and ends up calling drain() fairly quickly after then. – akarnokd Oct 18 '11 at 09:00
  • @Andrew: I've elaborated below, but I welcome your critical insight. – trashgod Oct 18 '11 at 15:08

1 Answers1

1

For reference, this example using close() exits normally under either Java 5 or 6.

Invoking stop(), rather than close(), on the EDT hangs both Java 5 and 6 unless the line has already been closed normally on the initial thread. This appears to be the expected result of drain() blocking, as a stopped line can't drain.

import java.awt.EventQueue;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.swing.JOptionPane;

/**
 * @see https://stackoverflow.com/questions/7803310
 * @see https://stackoverflow.com/questions/2065693
 */
public class Tone {

    public static void main(String[] args) throws LineUnavailableException {
        final AudioFormat af =
            new AudioFormat(Note.SAMPLE_RATE, 8, 1, true, true);
        final SourceDataLine line = AudioSystem.getSourceDataLine(af);
        EventQueue.invokeLater(new Runnable() {

            public void run() {
                JOptionPane.showMessageDialog(null, "Halt");
                //line.stop(); // stops and hangs on drain
                line.close();
            }
        });
        line.open(af, Note.SAMPLE_RATE);
        line.start();
        for (Note n : Note.values()) {
            play(line, n, 500);
            play(line, Note.REST, 10);
        }
        line.drain();
        line.close();
    }

    private static void play(SourceDataLine line, Note note, int ms) {
        ms = Math.min(ms, Note.SECONDS * 1000);
        int length = Note.SAMPLE_RATE * ms / 1000;
        int count = line.write(note.data(), 0, length);
    }
}

Requires Note.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Thanks for the explanation. It seems the Windows JRE does not conform the spec. I'll ask the user to try the game with these modifications. – akarnokd Oct 19 '11 at 12:54