On Oct 7, 2011, at 9:24 AM, [email protected] wrote:

> o #28039 IAudioClock_GetPosition must ignore underruns (MacOS) 
> Here I've no idea how to solve this.  My initial query remained unanswered:
> http://lists.apple.com/archives/coreaudio-api//2011/Sep/msg00024.html
> Ken?  Andrew's yesterday patch (using GetCurrentPadding) is an interim
> work-around.  GetPosition (speaker) is unrelated to padding which is
> solely about buffering.

It is expected that the queue's time keeps incrementing even when no buffers 
are enqueued.  For example, see 
<https://developer.apple.com/library/ios/#qa/qa1718/_index.html>.

Here's one possible solution:

Enqueue the buffers with AudioQueueEnqueueBufferWithParameters() to get back 
the actual start time (in the queue's time frame) at which each buffer is 
scheduled to start.  Then, compare AudioQueueGetCurrentTime() with the 
scheduled start time of the enqueued buffer(s) to see how far into which buffer 
the queue has played.

The code will have to track the position (in the desired sense) separately from 
the queue time.  There will be a scalar value containing the sum of the lengths 
of all buffers known to have been completely played.  There will also be a list 
of time ranges for those buffers which have been queued but are not known to 
have been completely played yet.  For each buffer, the time range consists of 
its scheduled start time and its length.

At certain points -- ca_out_buffer_cb() and GetPosition() -- 
AudioQueueGetCurrentTime() will be called.  The buffer list will be scanned.  
All the buffers whose end time (i.e. start time + length) is less than the 
queue time will be removed from the list, with their lengths added into the 
sum.  That's all that's necessary for ca_out_buffer_cb() and is only done in 
that function to make sure the buffer list doesn't keep growing if 
GetPosition() is rarely or never called.  For GetPosition(), the queue time 
will be compared to the first buffer that remains in the list, if any.  If 
there are no buffers or the queue time is before the start time of the first 
buffer, then GetPosition() returns the sum.  Otherwise, it will return the sum 
plus the queue time minus the buffer start time.

AudioClient_Reset() will clear the buffer list (and the sum?).


There's another approach that came to mind, but I don't think it's feasible: 
only run the queue when there are actually buffers to play.  Don't start the 
queue until a buffer has been enqueued and stop it when there are no more 
ready.  Basically, during the callback when the queue is requesting another 
buffer, if there's nothing to enqueue, call AudioQueueStop(..., FALSE).  You 
may also need to use AudioQueueAddPropertyListener() to observe 
kAudioQueueProperty_IsRunning to learn when it has actually stopped, since the 
queue's time will reset to 0 at that point.  During each period of the queue 
running, its time will reflect actual queued samples being played.


Timeline discontinuities occur when the sample rate changes, the output device 
is switched, the DSP has to be reset, or that sort of thing, I believe.  They 
don't have anything to do with underruns of the kind you're considering.

Regards,
Ken



Reply via email to