finnw
finnw

Reputation: 48659

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 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:

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):

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.

Upvotes: 2

Views: 1073

Answers (1)

vladr
vladr

Reputation: 66721

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.)

Upvotes: 1

Related Questions