[RESOLVED] Audio source 1 second delay on stop

In an app, when using a MemoryAudioSource (as a source for an AudioTransportSource), when you issue a stop() call to stop playback of the audio, there is a 1-second delay before any other actions can be taken on that audio. The reason is this code in stop():

    if (playing)
    {
        playing = false;

        int n = 500;
        while (--n >= 0 && ! stopped)
            Thread::sleep (2);

        sendChangeMessage();
    }

The flag “stopped” only gets set in the getNextAudioBlock() function. But with a non-buffered audio source, that function no longer gets called after calling stop(). So that flag never gets set, and it takes a full second for the loop to exit and the app to become responsive again. Since we have three such sources, the three-second delay causes the BBOD to appear (on Mac), and is unacceptable.

We fixed our app by using a BufferingAudioSource instead. Using that class, we do get a getNextAudioBlock call which resets the stopped flag, and so our app remains responsive. But (using Juce 7.0.5, at least), it appears the the non-buffered version has a bug here.

[EDIT] changing to BufferingAudioSource did not solve the problem at all. I had commented out that loop in my testing.

Oh, and because that “playing” flag gets set, when we query if the transport is still playing, it says that is is NOT playing, and our controls reset as if the transport has stopped. Maybe the query for that should check if stopped is true, not playing?

Ok, this is bizzare. Now I’m getting the same delays using the BufferingAudioSource (which apparently is set up here to use the MemoryAudioSource as its source). I tested on both Mac and PC yesterday, and it worked flawlessly. But now it’s having the exact same issues! There is a 1-second delay for each of the three audio sources when I call stop() on the AudioTransportSource that uses those sources.

I see why I got that result. I had commented out that loop that causes the 1 second delay. (D’OH!)

So, in reality, the buffered version and the memory version both have this problem. They hang for 1 second when calling stop().

How can I resolve this? Is there another step I need to take before or after calling stop() that will force that “stopped” flag to be set to true? It’s private (not even protected), and there is no setter for it, so it’s not accessible except via getNextAudioBuffer().

I think a clue lies in the fact that we have another AudioSource-derived class that contains our three MemoryAudioSource objects (so that we can run them all in parallel and switch between them while the transport is running). In that class’ getNextAudioBlock(), we check if all three MemoryAudioSource objects are playing or not, which prevents calling getNextAudioBlock() for the three sources. (And at this point in time playing is false, even though stopped is still false.) That is why we aren’t getting that callback. I may just be able to remove that check from our code, since getNextAudioBlock should not be called if it’s not needed by the calling thread.

That fixed it. We were skipping calling getNextAudioBlock on our three contained sources, because isPlaying() was false. But stopped (which we cannot check) was still false. So I re-arranged the code so that our container source’s getNextAudioBlock() always calls getNextAudioBlock on all three of our contained sources, but then just doesn’t use that data to write to anyplace. Whew!