2

我看到ClipJava 中的实例有一些奇怪的行为。

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

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

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无论如何它们都是)


可能与此错误有关。

4

1 回答 1

1

DataLine.start对和DataLine.stop的调用已经在内部的混音器上同步DataLineAbstractDataLine

我强烈怀疑在调用堆栈的某个地方(在implStart()/你得到implStop()的任何DataLine化身之下,很可能在本机nStart/内部nstop至少进行了一次异步调用,从而导致你观察到竞争条件。

synchronized如果不更深入地了解所调用的本机实现,您将无法使用或任何其他 Java 构造来解决此类问题。

一个可行的、直接的解决方法可能是关闭旧剪辑并打开一个新实例,而不是倒带旧剪辑。不是最佳的,但在进行更深入的调查之前,它可能会起到作用。

为了能够进行上述更深入的调查,您必须知道您在哪个平台上,以及确认您ClipMixer实例的实际(实现)类名。

更新

同时,请使用自省来设置com.sun.media.sound.Printer.trace = true(或提供您自己的实现com.sun.media.sound.PrinterCLASSPATH

本质上DirectClip.open()生成一个线程,该线程以非线程安全的方式访问多个volatile 变量(特别感兴趣的是),这可能会导致主播放循环挂起。doIO

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

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

于 2010-06-29T20:27:26.320 回答