音频剪辑卡住了

时间:2010-06-21 02:30:00

标签: java javasound

我在Java中看到了Clip个实例的一些奇怪行为。

我正在处理的类的目的是保持包含相同声音样本的Clip个实例的数量(由URI索引。)当应用程序请求播放剪辑时已经有三个或更多来自同一来源的剪辑已经播放,执行以下步骤:

  • 按照PANframePosition的加权总和对当前播放的片段进行排序。
  • 选择具有最高值的剪辑作为要停止并重新启动的剪辑。
  • 重新开始剪辑(以下方法):

void restart(Clip clip, float gain, float pan) {
    clip.stop();
    clip.flush();
    pan = Math.max(-1f, Math.min(pan, 1f));
    ((FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN))
                        .setValue(gain);
    ((FloatControl) clip.getControl(FloatControl.Type.PAN))
                        .setValue(pan);
    clip.setFramePosition(0);
    clip.start();
}

如果快速连续多次调用此方法(例如1ms内20次),则会出现奇怪的行为:

  • 剪辑播放
  • 该片段会触发START个事件,表示已开始播放
  • 剪辑永远不会触发STOP事件。
  • stopstart的后续调用无效(但不会抛出异常。)
  • getFramePosition始终返回0,即使剪辑可听到(最后一次)。

知道可能导致这种情况的原因吗?

我不认为这是一个线程问题(至少在我的代码中没有。)只有一个线程调用我的类的公共方法(并且它们都是synchronized无论如何)


可能与this bug有关。

1 个答案:

答案 0 :(得分:1)

AbstractDataLineDataLine.start的调音台上,DataLine.stopDataLine的来电已经已经同步

我强烈怀疑有一些调用堆栈(在implStart() / implStop()之下,你所拥有的DataLine化身,很可能在本地nStart / {{1 }})至少进行一次异步调用,从而导致您观察到的竞争条件。

使用nstop或任何其他Java构造来解决此类问题是不可能的,而不必更深入地了解所调用的本机实现。

可行的,即时解决方法可能关闭旧剪辑并打开新实例而不是倒回旧实例。不是最佳的,但在进行更深入的调查之前,它可能会成功。

为了能够执行上述更深入的调查,您必须知道自己所处的平台,以及对synchronized和{{1}的实际(实现)类名的确认实例。

<强>更新

同时,请使用内省设置Clip(或在Mixer中提供您自己的com.sun.media.sound.Printer实施。)

基本上DirectClip.open() spawns一个thread以非线程安全的方式访问多个volatile variables(特别感兴趣的是com.sun.media.sound.Printer.trace = true),这可能会导致主回放循环挂。

您可以通过在明显挂起时强制thread dump并检查回放线程状态/堆栈跟踪来确认(或确认)此(与CLASSPATH跟踪一起使用)(或使用调试器。)

如果doIO等访问结果而不是成为问题,那么继续挖掘本机实现仍然是要做的事情;如果Printer等访问 再次成为问题,那么就没有简单的解决方法(您可以尝试使用内省来抓取doIO并定期发出信号因为doIO而导致它失速 - 再次确认。)