pa_win_wmme.c fixed bug in stream info inputLatency see ticket #178. improved interpretation of suggestedLatency based on recent discussions. see tickets #98 #99 #181

This commit is contained in:
rossb 2011-07-28 12:03:09 +00:00
commit e07e139e0d

View file

@ -154,21 +154,21 @@
#define PA_MME_USE_HIGH_DEFAULT_LATENCY_ (0) /* For debugging glitches. */
#if PA_MME_USE_HIGH_DEFAULT_LATENCY_
#define PA_MME_WIN_9X_DEFAULT_LATENCY_ (0.4)
#define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ (4)
#define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ (4)
#define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_ (4)
#define PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_ (16)
#define PA_MME_MAX_HOST_BUFFER_SECS_ (0.3) /* Do not exceed unless user buffer exceeds */
#define PA_MME_MAX_HOST_BUFFER_BYTES_ (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */
#define PA_MME_WIN_9X_DEFAULT_LATENCY_ (0.4)
#define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ (4)
#define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ (4)
#define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_ (4)
#define PA_MME_HOST_BUFFER_GRANULARITY_FRAMES_WHEN_UNSPECIFIED_ (16)
#define PA_MME_MAX_HOST_BUFFER_SECS_ (0.3) /* Do not exceed unless user buffer exceeds */
#define PA_MME_MAX_HOST_BUFFER_BYTES_ (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */
#else
#define PA_MME_WIN_9X_DEFAULT_LATENCY_ (0.2)
#define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ (2)
#define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ (3)
#define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_ (2)
#define PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_ (16)
#define PA_MME_MAX_HOST_BUFFER_SECS_ (0.1) /* Do not exceed unless user buffer exceeds */
#define PA_MME_MAX_HOST_BUFFER_BYTES_ (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */
#define PA_MME_WIN_9X_DEFAULT_LATENCY_ (0.2)
#define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ (2)
#define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ (3) /* always use at least 3 input buffers for full duplex */
#define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_ (2)
#define PA_MME_HOST_BUFFER_GRANULARITY_FRAMES_WHEN_UNSPECIFIED_ (16)
#define PA_MME_MAX_HOST_BUFFER_SECS_ (0.1) /* Do not exceed unless user buffer exceeds */
#define PA_MME_MAX_HOST_BUFFER_BYTES_ (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */
#endif
/* Use higher latency for NT because it is even worse at real-time
@ -177,6 +177,13 @@
#define PA_MME_WIN_NT_DEFAULT_LATENCY_ (PA_MME_WIN_9X_DEFAULT_LATENCY_ * 2)
#define PA_MME_WIN_WDM_DEFAULT_LATENCY_ (PA_MME_WIN_9X_DEFAULT_LATENCY_)
/* When client suggestedLatency could result in many host buffers, we aim to have around 8,
based off Windows documentation that suggests that the kmixer uses 8 buffers. This choice
is somewhat arbitrary here, since we havn't observed significant stability degredation
with using either more, or less buffers.
*/
#define PA_MME_TARGET_HOST_BUFFER_COUNT_ 8
#define PA_MME_MIN_TIMEOUT_MSEC_ (1000)
@ -791,7 +798,9 @@ static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMme
MMRESULT mmresult;
WAVEOUTCAPS woc;
PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo;
#ifdef PAWIN_USE_WDMKS_DEVICE_INFO
int wdmksDeviceOutputChannelCountIsKnown;
#endif
*success = 0;
@ -1324,126 +1333,135 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
}
static void SelectBufferSizeAndCount( unsigned long baseBufferSize,
unsigned long requestedLatency,
unsigned long baseBufferCount, unsigned long minimumBufferCount,
unsigned long maximumBufferSize, unsigned long *hostBufferSize,
unsigned long *hostBufferCount )
static unsigned long ComputeHostBufferCountForFixedBufferSizeFrames(
unsigned long suggestedLatencyFrames,
unsigned long hostBufferSizeFrames,
unsigned long minimumBufferCount )
{
unsigned long sizeMultiplier, bufferCount, latency;
unsigned long nextLatency, nextBufferSize;
int baseBufferSizeIsPowerOfTwo;
sizeMultiplier = 1;
bufferCount = baseBufferCount;
/* Calculate the number of buffers of length hostFramesPerBuffer
that fit in suggestedLatencyFrames, rounding up to the next integer.
/* count-1 below because latency is always determined by one less
than the total number of buffers.
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.
*/
latency = (baseBufferSize * sizeMultiplier) * (bufferCount-1);
if( latency > requestedLatency )
{
unsigned long resultBufferCount = ((suggestedLatencyFrames + (hostBufferSizeFrames - 2)) / hostBufferSizeFrames);
/* reduce number of buffers without falling below suggested latency */
/* We always need one extra buffer for processing while the rest are queued/playing.
i.e. latency is framesPerBuffer * (bufferCount - 1)
*/
resultBufferCount += 1;
nextLatency = (baseBufferSize * sizeMultiplier) * (bufferCount-2);
while( bufferCount > minimumBufferCount && nextLatency >= requestedLatency )
{
--bufferCount;
nextLatency = (baseBufferSize * sizeMultiplier) * (bufferCount-2);
}
if( resultBufferCount < minimumBufferCount ) /* clamp to minimum buffer count */
resultBufferCount = minimumBufferCount;
}else if( latency < requestedLatency ){
baseBufferSizeIsPowerOfTwo = (! (baseBufferSize & (baseBufferSize - 1)));
if( baseBufferSizeIsPowerOfTwo ){
/* double size of buffers without exceeding requestedLatency */
nextBufferSize = (baseBufferSize * (sizeMultiplier*2));
nextLatency = nextBufferSize * (bufferCount-1);
while( nextBufferSize <= maximumBufferSize
&& nextLatency < requestedLatency )
{
sizeMultiplier *= 2;
nextBufferSize = (baseBufferSize * (sizeMultiplier*2));
nextLatency = nextBufferSize * (bufferCount-1);
}
}else{
/* increase size of buffers upto first excess of requestedLatency */
nextBufferSize = (baseBufferSize * (sizeMultiplier+1));
nextLatency = nextBufferSize * (bufferCount-1);
while( nextBufferSize <= maximumBufferSize
&& nextLatency < requestedLatency )
{
++sizeMultiplier;
nextBufferSize = (baseBufferSize * (sizeMultiplier+1));
nextLatency = nextBufferSize * (bufferCount-1);
}
if( nextLatency < requestedLatency )
++sizeMultiplier;
}
/* increase number of buffers until requestedLatency is reached */
latency = (baseBufferSize * sizeMultiplier) * (bufferCount-1);
while( latency < requestedLatency )
{
++bufferCount;
latency = (baseBufferSize * sizeMultiplier) * (bufferCount-1);
}
}
*hostBufferSize = baseBufferSize * sizeMultiplier;
*hostBufferCount = bufferCount;
return resultBufferCount;
}
static void ReselectBufferCount( unsigned long bufferSize,
unsigned long requestedLatency,
unsigned long baseBufferCount, unsigned long minimumBufferCount,
unsigned long *hostBufferCount )
static PaError SelectHostBufferSizeFramesAndHostBufferCount(
unsigned long suggestedLatencyFrames,
unsigned long userFramesPerBuffer,
unsigned long minimumBufferCount,
unsigned long preferredMaximumBufferSizeFrames, /* try not to exceed this. for example, don't exceed when coalescing buffers */
unsigned long absoluteMaximumBufferSizeFrames, /* never exceed this, a hard limit */
unsigned long *hostBufferSizeFrames,
unsigned long *hostBufferCount )
{
unsigned long bufferCount, latency;
unsigned long nextLatency;
if( userFramesPerBuffer == paFramesPerBufferUnspecified ){
bufferCount = baseBufferCount;
*hostBufferSizeFrames = PA_MME_HOST_BUFFER_GRANULARITY_FRAMES_WHEN_UNSPECIFIED_;
/* count-1 below because latency is always determined by one less
than the total number of buffers.
*/
latency = bufferSize * (bufferCount-1);
}else{
if( latency > requestedLatency )
{
/* reduce number of buffers without falling below suggested latency */
*hostBufferSizeFrames = userFramesPerBuffer;
nextLatency = bufferSize * (bufferCount-2);
while( bufferCount > minimumBufferCount && nextLatency >= requestedLatency )
{
--bufferCount;
nextLatency = bufferSize * (bufferCount-2);
if( *hostBufferSizeFrames > absoluteMaximumBufferSizeFrames ){
/* user has requested a user buffer that's larger than what we can handle */
/* @todo FIXME 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. */
/* return paBufferTooBig; */
}
}
/* compute a host buffer count based on suggestedLatencyFrames and our granularity */
}else if( latency < requestedLatency ){
*hostBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames(
suggestedLatencyFrames, *hostBufferSizeFrames, minimumBufferCount );
/* increase number of buffers until requestedLatency is reached */
/* consider coalescing multiple user buffers into each host buffer */
latency = bufferSize * (bufferCount-1);
while( latency < requestedLatency )
{
++bufferCount;
latency = bufferSize * (bufferCount-1);
}
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;
unsigned long maxUserBuffersPerHostBuffer = maxCoalescedBufferSizeFrames / *hostBufferSizeFrames; /* 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( numUserBuffersPerHostBuffer > 1 ){
*hostBufferSizeFrames *= numUserBuffersPerHostBuffer;
/* recompute hostBufferCount to approximate suggestedLatencyFrames now that hostBufferSizeFrames is larger */
*hostBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames(
suggestedLatencyFrames, *hostBufferSizeFrames, minimumBufferCount );
}
}
*hostBufferCount = bufferCount;
return paNoError;
}
static PaError CalculateMaxHostSampleFrameSizeBytes(
int channelCount,
PaSampleFormat hostSampleFormat,
const PaWinMmeStreamInfo *streamInfo,
int *hostSampleFrameSizeBytes )
{
unsigned int i;
/* PA WMME streams may aggregate multiple WMME devices. When the stream addresses
more than one device in a single direction, maxDeviceChannelCount is the maximum
number of channels used by a single device.
*/
int maxDeviceChannelCount = channelCount;
int hostSampleSizeBytes = Pa_GetSampleSize( hostSampleFormat );
if( hostSampleSizeBytes < 0 )
{
return hostSampleSizeBytes; /* the value of hostSampleSize here is an error code, not a sample size */
}
if( streamInfo && ( streamInfo->flags & paWinMmeUseMultipleDevices ) )
{
maxDeviceChannelCount = streamInfo->devices[0].channelCount;
for( i=1; i< streamInfo->deviceCount; ++i )
{
if( streamInfo->devices[i].channelCount > maxDeviceChannelCount )
maxDeviceChannelCount = streamInfo->devices[i].channelCount;
}
}
*hostSampleFrameSizeBytes = hostSampleSizeBytes * maxDeviceChannelCount;
return paNoError;
}
@ -1456,48 +1474,26 @@ static PaError CalculateBufferSettings(
unsigned long *hostFramesPerInputBuffer, unsigned long *hostInputBufferCount,
unsigned long *hostFramesPerOutputBuffer, unsigned long *hostOutputBufferCount,
int inputChannelCount, PaSampleFormat hostInputSampleFormat,
PaTime suggestedInputLatency, PaWinMmeStreamInfo *inputStreamInfo,
PaTime suggestedInputLatency, const PaWinMmeStreamInfo *inputStreamInfo,
int outputChannelCount, PaSampleFormat hostOutputSampleFormat,
PaTime suggestedOutputLatency, PaWinMmeStreamInfo *outputStreamInfo,
PaTime suggestedOutputLatency, const PaWinMmeStreamInfo *outputStreamInfo,
double sampleRate, unsigned long userFramesPerBuffer )
{
PaError result = paNoError;
int effectiveInputChannelCount, effectiveOutputChannelCount;
int hostInputFrameSize = 0;
unsigned int i;
if( inputChannelCount > 0 )
if( inputChannelCount > 0 ) /* stream has input */
{
int hostInputSampleSize = Pa_GetSampleSize( hostInputSampleFormat );
if( hostInputSampleSize < 0 )
{
result = hostInputSampleSize; /* this is an error code */
int hostInputFrameSizeBytes;
result = CalculateMaxHostSampleFrameSizeBytes(
inputChannelCount, hostInputSampleFormat, inputStreamInfo, &hostInputFrameSizeBytes );
if( result != paNoError )
goto error;
}
if( inputStreamInfo
&& ( inputStreamInfo->flags & paWinMmeUseMultipleDevices ) )
{
/* set effectiveInputChannelCount to the largest number of
channels on any one device.
*/
effectiveInputChannelCount = 0;
for( i=0; i< inputStreamInfo->deviceCount; ++i )
{
if( inputStreamInfo->devices[i].channelCount > effectiveInputChannelCount )
effectiveInputChannelCount = inputStreamInfo->devices[i].channelCount;
}
}
else
{
effectiveInputChannelCount = inputChannelCount;
}
hostInputFrameSize = hostInputSampleSize * effectiveInputChannelCount;
if( inputStreamInfo
&& ( inputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )
{
/* input - using low level latency parameters if provided */
if( inputStreamInfo->bufferCount <= 0
|| inputStreamInfo->framesPerBuffer <= 0 )
{
@ -1510,28 +1506,25 @@ static PaError CalculateBufferSettings(
}
else
{
unsigned long hostBufferSizeBytes, hostBufferCount;
/* input - not using low level latency parameters, so compute
hostFramesPerInputBuffer and hostInputBufferCount
based on userFramesPerBuffer and suggestedInputLatency. */
unsigned long minimumBufferCount = (outputChannelCount > 0)
? PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_
: PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_;
unsigned long maximumBufferSize = (long) ((PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate) * hostInputFrameSize);
if( maximumBufferSize > PA_MME_MAX_HOST_BUFFER_BYTES_ )
maximumBufferSize = PA_MME_MAX_HOST_BUFFER_BYTES_;
/* compute the following in bytes, then convert back to frames */
SelectBufferSizeAndCount(
((userFramesPerBuffer == paFramesPerBufferUnspecified)
? PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_
: userFramesPerBuffer ) * hostInputFrameSize, /* baseBufferSize */
((unsigned long)(suggestedInputLatency * sampleRate)) * hostInputFrameSize, /* suggestedLatency */
4, /* baseBufferCount */
minimumBufferCount, maximumBufferSize,
&hostBufferSizeBytes, &hostBufferCount );
*hostFramesPerInputBuffer = hostBufferSizeBytes / hostInputFrameSize;
*hostInputBufferCount = hostBufferCount;
result = SelectHostBufferSizeFramesAndHostBufferCount(
(unsigned long)(suggestedInputLatency * sampleRate),
userFramesPerBuffer,
minimumBufferCount,
(unsigned long)(PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate), /* in frames. preferred maximum */
(PA_MME_MAX_HOST_BUFFER_BYTES_ / hostInputFrameSizeBytes), /* in frames. a hard limit. note truncation due to
division is intentional here to limit max bytes */
hostFramesPerInputBuffer,
hostInputBufferCount );
if( result != paNoError )
goto error;
}
}
else
@ -1540,11 +1533,13 @@ static PaError CalculateBufferSettings(
*hostInputBufferCount = 0;
}
if( outputChannelCount > 0 )
if( outputChannelCount > 0 ) /* stream has output */
{
if( outputStreamInfo
&& ( outputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )
{
/* output - using low level latency parameters */
if( outputStreamInfo->bufferCount <= 0
|| outputStreamInfo->framesPerBuffer <= 0 )
{
@ -1555,16 +1550,17 @@ static PaError CalculateBufferSettings(
*hostFramesPerOutputBuffer = outputStreamInfo->framesPerBuffer;
*hostOutputBufferCount = outputStreamInfo->bufferCount;
if( inputChannelCount > 0 ) /* full duplex */
{
/* harmonize hostFramesPerInputBuffer and hostFramesPerOutputBuffer */
if( *hostFramesPerInputBuffer != *hostFramesPerOutputBuffer )
{
if( inputStreamInfo
&& ( inputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )
{
/* a custom StreamInfo was used for specifying both input
and output buffer sizes, the larger buffer size
and output buffer sizes. We require that the larger buffer size
must be a multiple of the smaller buffer size */
if( *hostFramesPerInputBuffer < *hostFramesPerOutputBuffer )
@ -1588,111 +1584,72 @@ static PaError CalculateBufferSettings(
else
{
/* a custom StreamInfo was not used for specifying the input buffer size,
so use the output buffer size, and approximately the same latency. */
so use the output buffer size, and approximately the suggested input latency. */
*hostFramesPerInputBuffer = *hostFramesPerOutputBuffer;
*hostInputBufferCount = (((unsigned long)(suggestedInputLatency * sampleRate)) / *hostFramesPerInputBuffer) + 1;
if( *hostInputBufferCount < PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ )
*hostInputBufferCount = PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_;
*hostInputBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames(
(unsigned long)(suggestedInputLatency * sampleRate),
*hostFramesPerInputBuffer,
PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ );
}
}
}
}
else
{
unsigned long hostBufferSizeBytes, hostBufferCount;
unsigned long minimumBufferCount = PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_;
unsigned long maximumBufferSize;
int hostOutputFrameSize;
int hostOutputSampleSize;
/* output - no low level latency parameters, so compute hostFramesPerOutputBuffer and hostOutputBufferCount
based on userFramesPerBuffer and suggestedOutputLatency. */
hostOutputSampleSize = Pa_GetSampleSize( hostOutputSampleFormat );
if( hostOutputSampleSize < 0 )
{
result = hostOutputSampleSize;
int hostOutputFrameSizeBytes;
result = CalculateMaxHostSampleFrameSizeBytes(
outputChannelCount, hostOutputSampleFormat, outputStreamInfo, &hostOutputFrameSizeBytes );
if( result != paNoError )
goto error;
}
if( outputStreamInfo
&& ( outputStreamInfo->flags & paWinMmeUseMultipleDevices ) )
/* compute the output buffer size and count */
result = SelectHostBufferSizeFramesAndHostBufferCount(
(unsigned long)(suggestedOutputLatency * sampleRate),
userFramesPerBuffer,
PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_,
(unsigned long)(PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate), /* in frames. preferred maximum */
(PA_MME_MAX_HOST_BUFFER_BYTES_ / hostOutputFrameSizeBytes), /* in frames. a hard limit. note truncation due to
division is intentional here to limit max bytes */
hostFramesPerOutputBuffer,
hostOutputBufferCount );
if( result != paNoError )
goto error;
if( inputChannelCount > 0 ) /* full duplex */
{
/* set effectiveOutputChannelCount to the largest number of
channels on any one device.
*/
effectiveOutputChannelCount = 0;
for( i=0; i< outputStreamInfo->deviceCount; ++i )
{
if( outputStreamInfo->devices[i].channelCount > effectiveOutputChannelCount )
effectiveOutputChannelCount = outputStreamInfo->devices[i].channelCount;
}
}
else
{
effectiveOutputChannelCount = outputChannelCount;
}
/* harmonize hostFramesPerInputBuffer and hostFramesPerOutputBuffer */
hostOutputFrameSize = hostOutputSampleSize * effectiveOutputChannelCount;
maximumBufferSize = (long) ((PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate) * hostOutputFrameSize);
if( maximumBufferSize > PA_MME_MAX_HOST_BUFFER_BYTES_ )
maximumBufferSize = PA_MME_MAX_HOST_BUFFER_BYTES_;
/* compute the following in bytes, then convert back to frames */
SelectBufferSizeAndCount(
((userFramesPerBuffer == paFramesPerBufferUnspecified)
? PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_
: userFramesPerBuffer ) * hostOutputFrameSize, /* baseBufferSize */
((unsigned long)(suggestedOutputLatency * sampleRate)) * hostOutputFrameSize, /* suggestedLatency */
4, /* baseBufferCount */
minimumBufferCount,
maximumBufferSize,
&hostBufferSizeBytes, &hostBufferCount );
*hostFramesPerOutputBuffer = hostBufferSizeBytes / hostOutputFrameSize;
*hostOutputBufferCount = hostBufferCount;
if( inputChannelCount > 0 )
{
/* ensure that both input and output buffer sizes are the same.
if they don't match at this stage, choose the smallest one
and use that for input and output
and use that for input and output and recompute the corresponding
buffer count accordingly.
*/
if( *hostFramesPerOutputBuffer != *hostFramesPerInputBuffer )
{
if( hostFramesPerInputBuffer < hostFramesPerOutputBuffer )
{
unsigned long framesPerHostBuffer = *hostFramesPerInputBuffer;
minimumBufferCount = PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_;
ReselectBufferCount(
framesPerHostBuffer * hostOutputFrameSize, /* bufferSize */
((unsigned long)(suggestedOutputLatency * sampleRate)) * hostOutputFrameSize, /* suggestedLatency */
4, /* baseBufferCount */
minimumBufferCount,
&hostBufferCount );
*hostFramesPerOutputBuffer = *hostFramesPerInputBuffer;
*hostFramesPerOutputBuffer = framesPerHostBuffer;
*hostOutputBufferCount = hostBufferCount;
*hostOutputBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames(
(unsigned long)(suggestedOutputLatency * sampleRate),
*hostOutputBufferCount,
PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ );
}
else
{
unsigned long framesPerHostBuffer = *hostFramesPerOutputBuffer;
minimumBufferCount = PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_;
ReselectBufferCount(
framesPerHostBuffer * hostInputFrameSize, /* bufferSize */
((unsigned long)(suggestedInputLatency * sampleRate)) * hostInputFrameSize, /* suggestedLatency */
4, /* baseBufferCount */
minimumBufferCount,
&hostBufferCount );
*hostFramesPerInputBuffer = *hostFramesPerOutputBuffer;
*hostFramesPerInputBuffer = framesPerHostBuffer;
*hostInputBufferCount = hostBufferCount;
*hostInputBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames(
(unsigned long)(suggestedInputLatency * sampleRate),
*hostFramesPerInputBuffer,
PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ );
}
}
}
@ -2476,12 +2433,13 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
bufferProcessorIsInitialized = 1;
/* stream info input latency is the minimum buffering latency (unlike suggested and default which are *maximums*) */
stream->streamRepresentation.streamInfo.inputLatency =
(double)(PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor)
+(framesPerHostInputBuffer * (hostInputBufferCount-1))) / sampleRate;
+ framesPerHostInputBuffer) / sampleRate;
stream->streamRepresentation.streamInfo.outputLatency =
(double)(PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor)
+(framesPerHostOutputBuffer * (hostOutputBufferCount-1))) / sampleRate;
+ (framesPerHostOutputBuffer * (hostOutputBufferCount-1))) / sampleRate;
stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
stream->primeStreamUsingCallback = ( (streamFlags&paPrimeOutputBuffersUsingStreamCallback) && streamCallback ) ? 1 : 0;