To explain the context of yesterday's question/bug-report about AudioQueueGetCurrentTime: once again, I'm struggling with how to deal with buffer under-runs in playback AudioQueues.
I'm streaming audio from a socket, so depending on network conditions I might fall behind in my duty of shoveling frames into the queue. If I ignore the problem, the effect is pretty bad: each buffer's playback time is scheduled right after the previous one, even if the previous one had already finished playing a while ago, so the new buffer might not get played at all! If the stream falls enough behind, the result is permanent silence as the queue discards each incoming buffer without playing it.
The solution is to detect when an under-run occurs, and set the inTimeStamp of the next buffer to force it to be played Right Now. That will move up the scheduling of all following buffers so they play normally again.*
The problems I have are:
(1) How do I tell when an under-run occurs? I can't figure out any way. The time-stamp feature of the API doesn't help with this at all; it reports a discontinuity if I interrupt audio by plugging/unplugging headphones, but not if the queue runs out of samples and stops playing. Yesterday I was attempting to compare the expected sample time (the total number of samples I've queued since start) against the value of AudioQueueGetCurrentTime, which would work if that call did the right thing, but it doesn't.
(2) After an under-run, what value do I pass in for the inTimeStamp when scheduling the buffer, to indicate "Right Now"? Again, I thought the value of AudioQueueGetCurrentTime would work for this, but it doesn't, because it drifts apart from the actual sample count and it resets to zero when the audio hardware reconfigures.
This is driving me batty. In principle AudioQueues are a nice, friendly high-level API for playing audio, but the reality is that I've spent a great deal of time and frustration trying to get something working that ought to be easy. The documentation is much better than in the past, but still explains only the very basics, and relies way too much on big blobs of boilerplate sample code with no explanations of the real principles underneath. (It's been more than 3 months and I'm still discovering unexpected things about the actual behavior of the queues' buffering!)
By this point I'm wondering if it would have been faster for me to have just rolled up my sleeves and used AudioUnits.
—Jens
* Yes, technically the audio will no longer be in sync with when it should be playing; but this is Internet radio playback, not Logic Pro, and the user just wants to hear some dang music instead of silence, even if it's two seconds late. |