【问题标题】:SourceDataLine.drain() hangs on OSXSourceDataLine.drain() 在 OSX 上挂起
【发布时间】:2011-12-09 20:08:09
【问题描述】:

我的游戏通过常规方法播放声音:

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

并且用户可以取消播放(异步):

sdl.stop();

此取消在 Windows 下运行良好,但对于运行 OSX 10.5.8 和 Java 6 的用户,程序会挂起。 Threaddump 显示播放线程在 drain() 内部:com.sun.media.sound.MixerSourceLine.nDrain。如果用户没有打断声音,它会很好地完成并且应用程序会继续。

我的问题是:

  • 这是 OSX Java 错误吗?
  • 我应该使用 sdl.close() 而不是 stop 吗?
  • 有任何解决方法的建议或经验吗?

编辑:我发现this 有类似效果的错误报告,但页面上说它已修复。

【问题讨论】:

  • example 在 Mac OSX 10.5.8、Java 6 上正常完成。
  • @trashgod 该示例不会异步关闭。我在问题中提到,当不被打断时,声音播放正常。
  • 你使用BigClip得到同样的行为吗?
  • @AndrewThompson 我无法真正进行实验,因为问题来自没有任何编程经验的 OSX 用户的错误报告(我正在 Windows 机器上开发)。花了一个小时来解释如何在他的系统上完成线程转储。查看您的代码,它使用较小的音频块,并且可能在调用 drain() 之前停止。我的代码将整个音频放入声音缓冲区,然后很快就调用了 drain()。
  • @Andrew:我在下面进行了详细说明,但我欢迎您的批判性见解。

标签: java macos javasound


【解决方案1】:

作为参考,这个使用close()的例子在Java 5或6下正常退出。

在 EDT 上调用 stop() 而不是 close() 会挂起 Java 5 和 6,除非 line 已经在初始线程上正常关闭。这似乎是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);
    }
}

需要Note

【讨论】:

  • 感谢您的解释。 Windows JRE 似乎不符合规范。我会要求用户尝试这些修改的游戏。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-17
  • 2011-09-15
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
  • 1970-01-01
  • 2014-05-11
相关资源
最近更新 更多