Fixed pa_win_wmme.c latency calculations to result in non-decreasing actual latency for increasing suggested latency.
This commit is contained in:
parent
d15c703f8f
commit
903263d777
1 changed files with 46 additions and 42 deletions
|
|
@ -1341,13 +1341,9 @@ static unsigned long ComputeHostBufferCountForFixedBufferSizeFrames(
|
|||
/* Calculate the number of buffers of length hostFramesPerBuffer
|
||||
that fit in suggestedLatencyFrames, rounding up to the next integer.
|
||||
|
||||
The exact formula for round-up is:
|
||||
((suggestedLatencyFrames + (hostFramesPerBuffer - 1)) / hostFramesPerBuffer)
|
||||
However we subtract 2 instead of 1 below to account for rounding errors.
|
||||
This ensures we don't erroneously overallocate an extra buffer due to a one-sample rounding error.
|
||||
The value (hostBufferSizeFrames - 1) below is to ensure the buffer count is rounded up.
|
||||
*/
|
||||
|
||||
unsigned long resultBufferCount = ((suggestedLatencyFrames + (hostBufferSizeFrames - 2)) / hostBufferSizeFrames);
|
||||
unsigned long resultBufferCount = ((suggestedLatencyFrames + (hostBufferSizeFrames - 1)) / hostBufferSizeFrames);
|
||||
|
||||
/* We always need one extra buffer for processing while the rest are queued/playing.
|
||||
i.e. latency is framesPerBuffer * (bufferCount - 1)
|
||||
|
|
@ -1370,61 +1366,69 @@ static PaError SelectHostBufferSizeFramesAndHostBufferCount(
|
|||
unsigned long *hostBufferSizeFrames,
|
||||
unsigned long *hostBufferCount )
|
||||
{
|
||||
unsigned long effectiveUserFramesPerBuffer;
|
||||
unsigned long numberOfUserBuffersPerHostBuffer;
|
||||
|
||||
|
||||
if( userFramesPerBuffer == paFramesPerBufferUnspecified ){
|
||||
|
||||
*hostBufferSizeFrames = PA_MME_HOST_BUFFER_GRANULARITY_FRAMES_WHEN_UNSPECIFIED_;
|
||||
effectiveUserFramesPerBuffer = PA_MME_HOST_BUFFER_GRANULARITY_FRAMES_WHEN_UNSPECIFIED_;
|
||||
|
||||
}else{
|
||||
|
||||
*hostBufferSizeFrames = userFramesPerBuffer;
|
||||
effectiveUserFramesPerBuffer = userFramesPerBuffer;
|
||||
|
||||
if( *hostBufferSizeFrames > absoluteMaximumBufferSizeFrames ){
|
||||
/* user has requested a user buffer that's larger than what we can handle */
|
||||
if( effectiveUserFramesPerBuffer > absoluteMaximumBufferSizeFrames ){
|
||||
/* user has requested a user buffer that's larger than absoluteMaximumBufferSizeFrames */
|
||||
|
||||
/* @todo FIXME right now we allow the user to request an oversize host buffer,
|
||||
/* @todo FIXME/REVIEW right now we allow the user to request an oversize host buffer,
|
||||
even though elsewhere in the code there are suggestions that oversize buffers
|
||||
can cause crashes with some drivers. */
|
||||
can cause crashes with some drivers. see http://www.portaudio.com/trac/ticket/189
|
||||
*/
|
||||
/* return paBufferTooBig; */
|
||||
}
|
||||
}
|
||||
|
||||
/* compute a host buffer count based on suggestedLatencyFrames and our granularity */
|
||||
|
||||
*hostBufferSizeFrames = effectiveUserFramesPerBuffer;
|
||||
|
||||
*hostBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames(
|
||||
suggestedLatencyFrames, *hostBufferSizeFrames, minimumBufferCount );
|
||||
|
||||
/* consider coalescing multiple user buffers into each host buffer */
|
||||
/*
|
||||
If there are too many host buffers we would like to coalesce
|
||||
them by packing an integer number of user buffers into each host buffer.
|
||||
We try to coalesce such that hostBufferCount will lie between
|
||||
PA_MME_TARGET_HOST_BUFFER_COUNT_ and (PA_MME_TARGET_HOST_BUFFER_COUNT_*2)-1.
|
||||
We limit coalescing to avoid exceeding either absoluteMaximumBufferSizeFrames and
|
||||
preferredMaximumBufferSizeFrames.
|
||||
|
||||
if( *hostBufferCount >= PA_MME_TARGET_HOST_BUFFER_COUNT_ * 2 ){
|
||||
|
||||
/* If there are too many host buffers we would like to coalesce
|
||||
them by packing an integer number of user buffers into each host buffer.
|
||||
We try to coalesce such that hostBufferCount will lie between
|
||||
PA_MME_TARGET_HOST_BUFFER_COUNT_ and (PA_MME_TARGET_HOST_BUFFER_COUNT_*2)-1.
|
||||
We limit coalescing to avoid exceeding either absoluteMaximumBufferSizeFrames and
|
||||
preferredMaximumBufferSizeFrames.
|
||||
*/
|
||||
First, compute a coalescing factor: the number of user buffers per host buffer.
|
||||
The goal is to achieve PA_MME_TARGET_HOST_BUFFER_COUNT_ total buffer count.
|
||||
Since our latency is computed based on (*hostBufferCount - 1) we compute a
|
||||
coalescing factor based on (*hostBufferCount - 1) and (PA_MME_TARGET_HOST_BUFFER_COUNT_-1).
|
||||
|
||||
unsigned long maxCoalescedBufferSizeFrames = (absoluteMaximumBufferSizeFrames < preferredMaximumBufferSizeFrames) /* min of our limits */
|
||||
? absoluteMaximumBufferSizeFrames
|
||||
: preferredMaximumBufferSizeFrames;
|
||||
The + (PA_MME_TARGET_HOST_BUFFER_COUNT_-2) term below is intended to round up.
|
||||
*/
|
||||
numberOfUserBuffersPerHostBuffer = ((*hostBufferCount - 1) + (PA_MME_TARGET_HOST_BUFFER_COUNT_-2)) / (PA_MME_TARGET_HOST_BUFFER_COUNT_ - 1);
|
||||
|
||||
if( numberOfUserBuffersPerHostBuffer > 1 )
|
||||
{
|
||||
unsigned long maxCoalescedBufferSizeFrames = (absoluteMaximumBufferSizeFrames < preferredMaximumBufferSizeFrames) /* minimum of our limits */
|
||||
? absoluteMaximumBufferSizeFrames
|
||||
: preferredMaximumBufferSizeFrames;
|
||||
|
||||
unsigned long maxUserBuffersPerHostBuffer = maxCoalescedBufferSizeFrames / *hostBufferSizeFrames; /* don't coalesce more than this */
|
||||
unsigned long maxUserBuffersPerHostBuffer = maxCoalescedBufferSizeFrames / effectiveUserFramesPerBuffer; /* don't coalesce more than this */
|
||||
|
||||
/* we truncate here to compute a conservative value of numUserBuffersPerHostBuffer
|
||||
then we recompute hostBufferCount after coalescing.
|
||||
*/
|
||||
unsigned long numUserBuffersPerHostBuffer = *hostBufferCount / PA_MME_TARGET_HOST_BUFFER_COUNT_;
|
||||
if( numUserBuffersPerHostBuffer > maxUserBuffersPerHostBuffer )
|
||||
numUserBuffersPerHostBuffer = maxUserBuffersPerHostBuffer;
|
||||
if( numberOfUserBuffersPerHostBuffer > maxUserBuffersPerHostBuffer )
|
||||
numberOfUserBuffersPerHostBuffer = maxUserBuffersPerHostBuffer;
|
||||
|
||||
if( numUserBuffersPerHostBuffer > 1 ){
|
||||
*hostBufferSizeFrames *= numUserBuffersPerHostBuffer;
|
||||
*hostBufferSizeFrames = effectiveUserFramesPerBuffer * numberOfUserBuffersPerHostBuffer;
|
||||
|
||||
/* recompute hostBufferCount to approximate suggestedLatencyFrames now that hostBufferSizeFrames is larger */
|
||||
*hostBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames(
|
||||
suggestedLatencyFrames, *hostBufferSizeFrames, minimumBufferCount );
|
||||
}
|
||||
/* recompute hostBufferCount to approximate suggestedLatencyFrames now that hostBufferSizeFrames is larger */
|
||||
*hostBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames(
|
||||
suggestedLatencyFrames, *hostBufferSizeFrames, minimumBufferCount );
|
||||
}
|
||||
|
||||
return paNoError;
|
||||
|
|
@ -1515,7 +1519,7 @@ static PaError CalculateBufferSettings(
|
|||
: PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_;
|
||||
|
||||
result = SelectHostBufferSizeFramesAndHostBufferCount(
|
||||
(unsigned long)(suggestedInputLatency * sampleRate),
|
||||
(unsigned long)(suggestedInputLatency * sampleRate), /* (truncate) */
|
||||
userFramesPerBuffer,
|
||||
minimumBufferCount,
|
||||
(unsigned long)(PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate), /* in frames. preferred maximum */
|
||||
|
|
@ -1610,7 +1614,7 @@ static PaError CalculateBufferSettings(
|
|||
/* compute the output buffer size and count */
|
||||
|
||||
result = SelectHostBufferSizeFramesAndHostBufferCount(
|
||||
(unsigned long)(suggestedOutputLatency * sampleRate),
|
||||
(unsigned long)(suggestedOutputLatency * sampleRate), /* (truncate) */
|
||||
userFramesPerBuffer,
|
||||
PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_,
|
||||
(unsigned long)(PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate), /* in frames. preferred maximum */
|
||||
|
|
|
|||
Loading…
Reference in a new issue