AudioTransportSource smacking me around the face and neck


#1

I’m just coming to grips with what seems to be the current audio scheme, and although I probably have a way to go, I thinking I’m hitting something that probably is a bug.

My AudioTransportSource uses a ResamplingAudioSource and then a BufferingAudioSource and it’s getting stuck in a loop, at the end here:

[code]void BufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate_)
{
source->prepareToPlay (samplesPerBlockExpected, sampleRate_);

sampleRate = sampleRate_;

buffer.setSize (2, jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer));
buffer.clear();

bufferValidStart = 0;
bufferValidEnd = 0;

SharedBufferingAudioSourceThread::getInstance()->addSource (this);

while (bufferValidEnd - bufferValidStart < jmin (((int) sampleRate_) / 4,
                                                 buffer.getNumSamples() / 2))
{
    SharedBufferingAudioSourceThread::getInstance()->notify();
    Thread::sleep (5);
}

}[/code]

Since this class took a lock on my movie structures, that’s game over for me. I guess the other thread is meant to change something to release it, but it never does.

On a side note, not sure what I’m missing. I have the AudioDeviceManager, which has an AudioSourcePlayer as a source. When needed, I change the source of the AudioSourcePlayer, along with the sample rate and telling it to use a buffer.

The source is an AudioTransportSource, and in turn it has a PositionableAudioSource subclass that tries to access the actual samples, from a movie file, sample by sample.

What I hear is something, but about 10 seconds late, at a weird speed, and quite garbled. Next I’ll probably start injecting tets samples, but am I doing something weird? Did I miss a step? There seem to be a lot of classes, but little configuration. The only heavily overriding I did was the PositionableAudioSource that actually does the work.

Bruce

[/code]


#2

So, sure enough, when I don’t pass in a read-ahead or sample rate, I get something with glitches - about what I’d expect, since I paid no attention to buffering, hoping for the read-ahead to do that.

I have have read-ahead only, the first audio samples get looped again and again.

If I do no read-ahead but sample rate, I get a Stylophone, played in the traditional 10 year old’s Xmas present style.

Is this fixable? Should I deconstruct the classes and try to use a rate converter and buffer on their own? That’s getting a bit unwieldy, especially since I haven’t even started to add splitters and mixers.

Bruce

EDIT: So first off, I wasn’t getting that the buffer I receive has to be cleared - I was just using addFrom, thinking it would replace the samples. Once I cleared the buffer, I get slightly better results. Now I just have the 3 to 4 second lag and the glitching - even with a 1 second buffer. More to explore, obviously. Jules, please do look at my first note - that prep can get stuck.


#3

I’m a bit confused by this, as I use those classes all the time and they seem rock-solid to me.

But I guess the startup code could get stuck if the thread failed for some reason to read the data correctly. It sounds like you’re having issues where the thread’s failing to read what’s necessary - maybe there’s some non-threadsafe code in part of your upstream audio path?


#4

I think it may have been a deadlock? Possibly one of my tasks was holding a lock that’s stopping one of the audio tasks finishing it’s setup.

So, between that, and using copyFrom not addFrom, I seem to be mostly working. Is the buffered read ahead going to be enough to let me relax on the time spent in my getnextblock method? There’s a possibility of a lock in there (a readwritelock) but I was hoping to have your buffering cover it.

I’m hearing some really unpleasant skips right now, with a half second buffer (samplerate * 0.5).

Also - is there no ‘play speed’ for transport sources? Should I use setPosition to shuttle them, or is that bad?

On a side note, apart from mass confusion, it really only took one nasty late night to get audio partly up and running, so thanks for that!

Bruce


#5

Yes, as the read-ahead all happens in big chunks on a background thread, you can be quite relaxed about how you write your read method. But not too relaxed! If you’re getting glitches, then it could be that you need a bigger buffer, or you’re locking somewhere and interfering with the play thread.


#6

That’s the impression I’m getting. I was letting the thread access my movie directly, but that involves it locking, especially since this is an extra thread. What I did have was:

getABlock
lockmovie
readfrommovie
checkbuffersize (accesses movie too)
unlockmovie
copy buffer to block

But now I’m considering:

movie thread
do video stuff
pull related audio into buffer
put somewhere safe

getABlock
read from safe place/s

But now of course I need to manage things a bit more, especially the differing buffer sizes. I’m thinking of using juce buffers, but I will have to manage samples straddling each other. There isn’t a ring buffer of something nice like that I should use is there? Isn’t that the standard audio thread structure?

Bruce


#7

I have an AudioSink class that uses a circular buffer which is drained by a thread writing to a file. I use it for audio capture. It’s probably more conservative than it needs to be with respect to the locks and buffer sizes, but I’ve never had any problems with it. Also it doesn’t chew up CPU time. If you want I could send it to you.

Or maybe there’s a place to post code samples?


#8

Yes please, I would like to see it. I’ve got to the point where with or without the added Juce buffering, I get occasional skips, so I’m pretty sure I need to add my own buffer so I can get the samples out on the same thread that does the video, thus dropping the locking required.

I was going to mimic some of the Juce buffering class, but I’d love to see an alternative.

I’ll private message you with my email address, or else - if it’s short enough you can probably post it in the useful code forum.

Bruce