开发者

Audio clip getting stuck

I am seeing some strange behaviour with Clip instances in Java.

The purpose of the class I am working on is to 开发者_C百科keep count of the number of Clip instances containing the same sound sample (indexed by URI.) When the application requests to play a clip and there are already three or more clips from the same source already playing, the following steps are performed:

  • Sort the currently-playing clips by a weighted sum of PAN and framePosition.
  • Select the clip with the highest value as the one to be stopped and re-started.
  • Re-start the clip (the following method):

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();
}

Strange behaviour occurs if this method is called many times in quick succession (e.g. 20 times within 1ms):

  • The clip plays
  • The clip fires a START event to signal that it has started playing
  • The clip never fires a STOP event.
  • Subsequent calls to stop and start have no effect (but do not throw exceptions.)
  • getFramePosition always returns 0, even when the clip is audible (for the last time.)

Any idea what could be causing this?

I don't think it's a threading issue (at least not in my code.) Only one thread is calling the public methods of my class (and they are all synchronized anyway)


Might be related to this bug.


The calls to DataLine.start and DataLine.stop are already synchronized on the DataLine's mixer inside AbstractDataLine.

I strongly suspect that somewehere down the call stack (below implStart()/implStop() of whatever DataLine incarnation you got, very likely inside the native nStart/nstop) at least one asynchronous call is made, thus resulting in the race condition you observe.

It would be impossible for you to work around this kind of problem using synchronized or any other Java construct without more intimate knowledge of the native implementation that is called.

A viable, immediate workaround could be to close the old clip and open a new instance instead of rewinding the old one. Not optimal, but it may well do the trick pending a deeper investigation.

In order to be able to perform the aforementioned deeper investigation, one would have to know what platform you are on, as well as a confirmation of the actual (implementation) class names of your Clip and Mixer instances.

UPDATE

In parallel, please use introspection to set com.sun.media.sound.Printer.trace = true (or provide your own implementation of com.sun.media.sound.Printer in the CLASSPATH.)

Essentially DirectClip.open() spawns a thread which accesses several volatile variables (of particular interest being doIO) in a non-threadsafe manner, which could potentially result in the main playback loop hanging.

You can confirm (or infirm) this (in conjunction with the Printer traces) by forcing a thread dump at the time of the apparent hang, and inspecting the playback thread state/stack trace (or use a debugger.)

If doIO etc. access turns out not to be the problem then continuing to dig at the native implementations is still the thing to do; if doIO etc. access does turn out to be the problem then again, there is no easy fix (you can try to use introspection to grab DirectClip.thread and signal it periodically in case it stalls because of doIO -- again, to be confirmed.)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜