From: rossb Date: Thu, 11 Aug 2011 12:16:47 +0000 (+0000) Subject: Fixed pa_win_wmme.c latency calculations to result in non-decreasing actual latency... X-Git-Tag: pa_stable_v19_20111121_r1788~49 X-Git-Url: https://andrewgundersen.net/repos?a=commitdiff_plain;h=903263d777b456a338256b555fa72f9b871fde32;p=portaudio Fixed pa_win_wmme.c latency calculations to result in non-decreasing actual latency for increasing suggested latency. --- diff --git a/src/hostapi/wmme/pa_win_wmme.c b/src/hostapi/wmme/pa_win_wmme.c index f22fbcb..e806150 100644 --- a/src/hostapi/wmme/pa_win_wmme.c +++ b/src/hostapi/wmme/pa_win_wmme.c @@ -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( *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. - */ - - unsigned long maxCoalescedBufferSizeFrames = (absoluteMaximumBufferSizeFrames < preferredMaximumBufferSizeFrames) /* min of our limits */ - ? absoluteMaximumBufferSizeFrames - : preferredMaximumBufferSizeFrames; + /* + 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). + + 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 */