Improve calculation of default latencies on Mac CoreAudio.
Allow very low buffer sizes if suggestedLatency is low. Set actual latencies in StreamInfo.
This commit is contained in:
parent
ddc1a3ce11
commit
e3387a98a7
3 changed files with 266 additions and 111 deletions
|
|
@ -76,9 +76,11 @@
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/* This is a reasonable size for a small buffer based on experience. */
|
||||||
|
#define PA_MAC_SMALL_BUFFER_SIZE (64)
|
||||||
|
|
||||||
/* prototypes for functions declared in this file */
|
/* prototypes for functions declared in this file */
|
||||||
|
|
||||||
PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
|
PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -397,6 +399,132 @@ static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi)
|
||||||
return paNoError;
|
return paNoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* =================================================================================================== */
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @brief Clip the desired size against the allowed IO buffer size range for the device.
|
||||||
|
*/
|
||||||
|
static PaError ClipToDeviceBufferSize( AudioDeviceID macCoreDeviceId,
|
||||||
|
int isInput, UInt32 desiredSize, UInt32 *allowedSize )
|
||||||
|
{
|
||||||
|
UInt32 resultSize = desiredSize;
|
||||||
|
AudioValueRange audioRange;
|
||||||
|
UInt32 propSize = sizeof( audioRange );
|
||||||
|
PaError err = WARNING(AudioDeviceGetProperty( macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &audioRange ) );
|
||||||
|
//printf("kAudioDevicePropertyBufferFrameSizeRange: err = %d, propSize = %d, minimum = %g\n", err, propSize, audioRange.mMinimum);
|
||||||
|
//printf("kAudioDevicePropertyBufferFrameSizeRange: err = %d, propSize = %d, meximum = %g\n", err, propSize, audioRange.mMaximum );
|
||||||
|
resultSize = MAX( resultSize, audioRange.mMinimum );
|
||||||
|
resultSize = MIN( resultSize, audioRange.mMaximum );
|
||||||
|
*allowedSize = resultSize;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =================================================================================================== */
|
||||||
|
#if 0
|
||||||
|
void DumpDeviceProperties( AudioDeviceID macCoreDeviceId,
|
||||||
|
int isInput )
|
||||||
|
{
|
||||||
|
UInt32 propSize;
|
||||||
|
UInt32 deviceLatency;
|
||||||
|
UInt32 streamLatency;
|
||||||
|
UInt32 bufferFrames;
|
||||||
|
UInt32 safetyOffset;
|
||||||
|
|
||||||
|
printf(" ---- latency query : macCoreDeviceId = %d, isInput %d ----\n", macCoreDeviceId, isInput );
|
||||||
|
|
||||||
|
propSize = sizeof(UInt32);
|
||||||
|
PaError err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioStreamPropertyLatency, &propSize, &streamLatency));
|
||||||
|
printf("kAudioStreamPropertyLatency: err = %d, propSize = %d, value = %d\n", err, propSize, streamLatency );
|
||||||
|
|
||||||
|
propSize = sizeof(UInt32);
|
||||||
|
err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propSize, &bufferFrames));
|
||||||
|
printf("kAudioDevicePropertyBufferFrameSize: err = %d, propSize = %d, value = %d\n", err, propSize, bufferFrames );
|
||||||
|
|
||||||
|
propSize = sizeof(UInt32);
|
||||||
|
err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertySafetyOffset, &propSize, &safetyOffset));
|
||||||
|
printf("kAudioDevicePropertySafetyOffset: err = %d, propSize = %d, value = %d\n", err, propSize, safetyOffset );
|
||||||
|
|
||||||
|
propSize = sizeof(UInt32);
|
||||||
|
err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &deviceLatency));
|
||||||
|
printf("kAudioDevicePropertyLatency: err = %d, propSize = %d, value = %d\n", err, propSize, deviceLatency );
|
||||||
|
|
||||||
|
AudioValueRange audioRange;
|
||||||
|
propSize = sizeof( audioRange );
|
||||||
|
err = WARNING(AudioDeviceGetProperty( macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &audioRange ) );
|
||||||
|
printf("kAudioDevicePropertyBufferFrameSizeRange: err = %d, propSize = %d, minimum = %g\n", err, propSize, audioRange.mMinimum);
|
||||||
|
printf("kAudioDevicePropertyBufferFrameSizeRange: err = %d, propSize = %d, maximum = %g\n", err, propSize, audioRange.mMaximum );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* =================================================================================================== */
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* Calculate the fixed latency from the system and the device.
|
||||||
|
* Sum of kAudioStreamPropertyLatency +
|
||||||
|
* kAudioDevicePropertySafetyOffset +
|
||||||
|
* kAudioDevicePropertyLatency
|
||||||
|
*
|
||||||
|
* Some useful info from Jeff Moore on latency.
|
||||||
|
* http://osdir.com/ml/coreaudio-api/2010-01/msg00046.html
|
||||||
|
* http://osdir.com/ml/coreaudio-api/2009-07/msg00140.html
|
||||||
|
*/
|
||||||
|
static PaError CalculateFixedDeviceLatency( AudioDeviceID macCoreDeviceId, int isInput, UInt32 *fixedLatencyPtr )
|
||||||
|
{
|
||||||
|
UInt32 propSize;
|
||||||
|
UInt32 deviceLatency;
|
||||||
|
UInt32 streamLatency;
|
||||||
|
UInt32 safetyOffset;
|
||||||
|
|
||||||
|
propSize = sizeof(UInt32);
|
||||||
|
PaError err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioStreamPropertyLatency, &propSize, &streamLatency));
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
|
||||||
|
propSize = sizeof(UInt32);
|
||||||
|
err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertySafetyOffset, &propSize, &safetyOffset));
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
|
||||||
|
propSize = sizeof(UInt32);
|
||||||
|
err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &deviceLatency));
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
|
||||||
|
*fixedLatencyPtr = deviceLatency + streamLatency + safetyOffset;
|
||||||
|
return err;
|
||||||
|
error:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =================================================================================================== */
|
||||||
|
static PaError CalculateDefaultDeviceLatencies( AudioDeviceID macCoreDeviceId,
|
||||||
|
int isInput, UInt32 *lowLatencyFramesPtr,
|
||||||
|
UInt32 *highLatencyFramesPtr )
|
||||||
|
{
|
||||||
|
UInt32 propSize;
|
||||||
|
UInt32 bufferFrames = 0;
|
||||||
|
UInt32 fixedLatency = 0;
|
||||||
|
UInt32 clippedMinBufferSize = 0;
|
||||||
|
|
||||||
|
PaError err = CalculateFixedDeviceLatency( macCoreDeviceId, isInput, &fixedLatency );
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
|
||||||
|
// For low latency use a small fixed size buffer clipped to the device range.
|
||||||
|
err = ClipToDeviceBufferSize( macCoreDeviceId, isInput, PA_MAC_SMALL_BUFFER_SIZE, &clippedMinBufferSize );
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
|
||||||
|
// For high latency use the default device buffer size.
|
||||||
|
propSize = sizeof(UInt32);
|
||||||
|
err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propSize, &bufferFrames));
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
|
||||||
|
*lowLatencyFramesPtr = fixedLatency + clippedMinBufferSize;
|
||||||
|
*highLatencyFramesPtr = fixedLatency + bufferFrames;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
error:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =================================================================================================== */
|
||||||
|
|
||||||
static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi,
|
static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi,
|
||||||
PaDeviceInfo *deviceInfo,
|
PaDeviceInfo *deviceInfo,
|
||||||
AudioDeviceID macCoreDeviceId,
|
AudioDeviceID macCoreDeviceId,
|
||||||
|
|
@ -407,8 +535,7 @@ static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi,
|
||||||
UInt32 i;
|
UInt32 i;
|
||||||
int numChannels = 0;
|
int numChannels = 0;
|
||||||
AudioBufferList *buflist = NULL;
|
AudioBufferList *buflist = NULL;
|
||||||
UInt32 frameLatency;
|
|
||||||
|
|
||||||
VVDBUG(("GetChannelInfo()\n"));
|
VVDBUG(("GetChannelInfo()\n"));
|
||||||
|
|
||||||
/* Get the number of channels from the stream configuration.
|
/* Get the number of channels from the stream configuration.
|
||||||
|
|
@ -433,39 +560,33 @@ static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi,
|
||||||
else
|
else
|
||||||
deviceInfo->maxOutputChannels = numChannels;
|
deviceInfo->maxOutputChannels = numChannels;
|
||||||
|
|
||||||
if (numChannels > 0) /* do not try to retrieve the latency if there is no channels. */
|
if (numChannels > 0) /* do not try to retrieve the latency if there are no channels. */
|
||||||
{
|
{
|
||||||
/* Get the latency. Don't fail if we can't get this. */
|
/* Get the latency. Don't fail if we can't get this. */
|
||||||
/* default to something reasonable */
|
/* default to something reasonable */
|
||||||
deviceInfo->defaultLowInputLatency = .01;
|
deviceInfo->defaultLowInputLatency = .01;
|
||||||
deviceInfo->defaultHighInputLatency = .10;
|
deviceInfo->defaultHighInputLatency = .10;
|
||||||
deviceInfo->defaultLowOutputLatency = .01;
|
deviceInfo->defaultLowOutputLatency = .01;
|
||||||
deviceInfo->defaultHighOutputLatency = .10;
|
deviceInfo->defaultHighOutputLatency = .10;
|
||||||
propSize = sizeof(UInt32);
|
UInt32 lowLatencyFrames = 0;
|
||||||
err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &frameLatency));
|
UInt32 highLatencyFrames = 0;
|
||||||
if (!err)
|
err = CalculateDefaultDeviceLatencies( macCoreDeviceId, isInput, &lowLatencyFrames, &highLatencyFrames );
|
||||||
{
|
if( err == 0 )
|
||||||
/** FEEDBACK:
|
{
|
||||||
* This code was arrived at by trial and error, and some extentive, but not exhaustive
|
|
||||||
* testing. Sebastien Beaulieu <seb@plogue.com> has suggested using
|
double lowLatencySeconds = lowLatencyFrames / deviceInfo->defaultSampleRate;
|
||||||
* kAudioDevicePropertyLatency + kAudioDevicePropertySafetyOffset + buffer size instead.
|
double highLatencySeconds = highLatencyFrames / deviceInfo->defaultSampleRate;
|
||||||
* At the time this code was written, many users were reporting dropouts with audio
|
if (isInput)
|
||||||
* programs that probably used this formula. This was probably
|
{
|
||||||
* around 10.4.4, and the problem is probably fixed now. So perhaps
|
deviceInfo->defaultLowInputLatency = lowLatencySeconds;
|
||||||
* his formula should be reviewed and used.
|
deviceInfo->defaultHighInputLatency = highLatencySeconds;
|
||||||
* */
|
}
|
||||||
double secondLatency = frameLatency / deviceInfo->defaultSampleRate;
|
else
|
||||||
if (isInput)
|
{
|
||||||
{
|
deviceInfo->defaultLowOutputLatency = lowLatencySeconds;
|
||||||
deviceInfo->defaultLowInputLatency = 3 * secondLatency;
|
deviceInfo->defaultHighOutputLatency = highLatencySeconds;
|
||||||
deviceInfo->defaultHighInputLatency = 3 * 10 * secondLatency;
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
deviceInfo->defaultLowOutputLatency = 3 * secondLatency;
|
|
||||||
deviceInfo->defaultHighOutputLatency = 3 * 10 * secondLatency;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
PaUtil_FreeMemory( buflist );
|
PaUtil_FreeMemory( buflist );
|
||||||
return paNoError;
|
return paNoError;
|
||||||
|
|
@ -474,6 +595,7 @@ static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* =================================================================================================== */
|
||||||
static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi,
|
static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi,
|
||||||
PaDeviceInfo *deviceInfo,
|
PaDeviceInfo *deviceInfo,
|
||||||
AudioDeviceID macCoreDeviceId,
|
AudioDeviceID macCoreDeviceId,
|
||||||
|
|
@ -1315,6 +1437,56 @@ static PaError OpenAndSetupOneAudioUnit(
|
||||||
return paResult;
|
return paResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* =================================================================================================== */
|
||||||
|
|
||||||
|
UInt32 CalculateOptimalBufferSize( PaMacAUHAL *auhalHostApi,
|
||||||
|
const PaStreamParameters *inputParameters,
|
||||||
|
const PaStreamParameters *outputParameters,
|
||||||
|
UInt32 fixedInputLatency,
|
||||||
|
UInt32 fixedOutputLatency,
|
||||||
|
double sampleRate )
|
||||||
|
{
|
||||||
|
UInt32 requested = 0;
|
||||||
|
// Use maximum of suggested input and output latencies.
|
||||||
|
if( inputParameters )
|
||||||
|
{
|
||||||
|
UInt32 suggestedLatencyFrames = inputParameters->suggestedLatency * sampleRate;
|
||||||
|
// Calculate a buffer size assuming we are double buffered.
|
||||||
|
SInt32 variableLatencyFrames = suggestedLatencyFrames - fixedInputLatency;
|
||||||
|
// Prevent negative latency.
|
||||||
|
variableLatencyFrames = MAX( variableLatencyFrames, 0 );
|
||||||
|
requested = MAX( requested, (UInt32) variableLatencyFrames );
|
||||||
|
}
|
||||||
|
if( outputParameters )
|
||||||
|
{
|
||||||
|
UInt32 suggestedLatencyFrames = outputParameters->suggestedLatency * sampleRate;
|
||||||
|
SInt32 variableLatencyFrames = suggestedLatencyFrames - fixedOutputLatency;
|
||||||
|
variableLatencyFrames = MAX( variableLatencyFrames, 0 );
|
||||||
|
requested = MAX( requested, (UInt32) variableLatencyFrames );
|
||||||
|
}
|
||||||
|
|
||||||
|
VDBUG( ("Block Size unspecified. Based on Latency, the user wants a Block Size near: %ld.\n",
|
||||||
|
requested ) );
|
||||||
|
|
||||||
|
// Clip to the capabilities of the device.
|
||||||
|
if( inputParameters )
|
||||||
|
{
|
||||||
|
ClipToDeviceBufferSize( auhalHostApi->devIds[inputParameters->device],
|
||||||
|
true, // In the old code isInput was false!
|
||||||
|
requested, &requested );
|
||||||
|
}
|
||||||
|
if( outputParameters )
|
||||||
|
{
|
||||||
|
ClipToDeviceBufferSize( auhalHostApi->devIds[outputParameters->device],
|
||||||
|
false, requested, &requested );
|
||||||
|
}
|
||||||
|
VDBUG(("After querying hardware, setting block size to %ld.\n", requested));
|
||||||
|
|
||||||
|
error:
|
||||||
|
return requested;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =================================================================================================== */
|
||||||
/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
|
/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
|
||||||
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
PaStream** s,
|
PaStream** s,
|
||||||
|
|
@ -1332,6 +1504,12 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
int inputChannelCount, outputChannelCount;
|
int inputChannelCount, outputChannelCount;
|
||||||
PaSampleFormat inputSampleFormat, outputSampleFormat;
|
PaSampleFormat inputSampleFormat, outputSampleFormat;
|
||||||
PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
|
PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
|
||||||
|
UInt32 fixedInputLatency = 0;
|
||||||
|
UInt32 fixedOutputLatency = 0;
|
||||||
|
// Accumulate contributions to latency in these variables.
|
||||||
|
UInt32 inputLatencyFrames = 0;
|
||||||
|
UInt32 outputLatencyFrames = 0;
|
||||||
|
|
||||||
VVDBUG(("OpenStream(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld SR=%g, FPB=%ld\n",
|
VVDBUG(("OpenStream(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld SR=%g, FPB=%ld\n",
|
||||||
inputParameters ? inputParameters->channelCount : -1,
|
inputParameters ? inputParameters->channelCount : -1,
|
||||||
inputParameters ? inputParameters->sampleFormat : -1,
|
inputParameters ? inputParameters->sampleFormat : -1,
|
||||||
|
|
@ -1454,71 +1632,28 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
|
|
||||||
PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
|
PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
|
||||||
|
|
||||||
/* -- handle paFramesPerBufferUnspecified -- */
|
|
||||||
if( framesPerBuffer == paFramesPerBufferUnspecified ) {
|
if( inputParameters )
|
||||||
long requested = 64;
|
{
|
||||||
if( inputParameters )
|
CalculateFixedDeviceLatency( auhalHostApi->devIds[inputParameters->device], true, &fixedInputLatency );
|
||||||
requested = MAX( requested, inputParameters->suggestedLatency * sampleRate / 2 );
|
inputLatencyFrames += fixedInputLatency;
|
||||||
if( outputParameters )
|
|
||||||
requested = MAX( requested, outputParameters->suggestedLatency *sampleRate / 2 );
|
|
||||||
VDBUG( ("Block Size unspecified. Based on Latency, the user wants a Block Size near: %ld.\n",
|
|
||||||
requested ) );
|
|
||||||
if( requested <= 64 ) {
|
|
||||||
/*requested a realtively low latency. make sure this is in range of devices */
|
|
||||||
/*try to get the device's min natural buffer size and use that (but no smaller than 64).*/
|
|
||||||
AudioValueRange audioRange;
|
|
||||||
UInt32 size = sizeof( audioRange );
|
|
||||||
if( inputParameters ) {
|
|
||||||
WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[inputParameters->device],
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
kAudioDevicePropertyBufferFrameSizeRange,
|
|
||||||
&size, &audioRange ) );
|
|
||||||
if( result )
|
|
||||||
requested = MAX( requested, audioRange.mMinimum );
|
|
||||||
}
|
|
||||||
size = sizeof( audioRange );
|
|
||||||
if( outputParameters ) {
|
|
||||||
WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[outputParameters->device],
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
kAudioDevicePropertyBufferFrameSizeRange,
|
|
||||||
&size, &audioRange ) );
|
|
||||||
if( result )
|
|
||||||
requested = MAX( requested, audioRange.mMinimum );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* requested a realtively high latency. make sure this is in range of devices */
|
|
||||||
/*try to get the device's max natural buffer size and use that (but no larger than 1024).*/
|
|
||||||
AudioValueRange audioRange;
|
|
||||||
UInt32 size = sizeof( audioRange );
|
|
||||||
requested = MIN( requested, 1024 );
|
|
||||||
if( inputParameters ) {
|
|
||||||
WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[inputParameters->device],
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
kAudioDevicePropertyBufferFrameSizeRange,
|
|
||||||
&size, &audioRange ) );
|
|
||||||
if( result )
|
|
||||||
requested = MIN( requested, audioRange.mMaximum );
|
|
||||||
}
|
|
||||||
size = sizeof( audioRange );
|
|
||||||
if( outputParameters ) {
|
|
||||||
WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[outputParameters->device],
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
kAudioDevicePropertyBufferFrameSizeRange,
|
|
||||||
&size, &audioRange ) );
|
|
||||||
if( result )
|
|
||||||
requested = MIN( requested, audioRange.mMaximum );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* -- double check ranges -- */
|
|
||||||
if( requested > 1024 ) requested = 1024;
|
|
||||||
if( requested < 64 ) requested = 64;
|
|
||||||
VDBUG(("After querying hardware, setting block size to %ld.\n", requested));
|
|
||||||
framesPerBuffer = requested;
|
|
||||||
}
|
}
|
||||||
|
if( outputParameters )
|
||||||
|
{
|
||||||
|
CalculateFixedDeviceLatency( auhalHostApi->devIds[outputParameters->device], false, &fixedOutputLatency );
|
||||||
|
outputLatencyFrames += fixedOutputLatency;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if( framesPerBuffer == paFramesPerBufferUnspecified )
|
||||||
|
{
|
||||||
|
framesPerBuffer = CalculateOptimalBufferSize( auhalHostApi, inputParameters, outputParameters,
|
||||||
|
fixedInputLatency, fixedOutputLatency,
|
||||||
|
sampleRate );
|
||||||
|
}
|
||||||
|
|
||||||
|
inputLatencyFrames += framesPerBuffer;
|
||||||
|
outputLatencyFrames += framesPerBuffer;
|
||||||
|
|
||||||
/* -- Now we actually open and setup streams. -- */
|
/* -- Now we actually open and setup streams. -- */
|
||||||
if( inputParameters && outputParameters && outputParameters->device == inputParameters->device )
|
if( inputParameters && outputParameters && outputParameters->device == inputParameters->device )
|
||||||
|
|
@ -1605,7 +1740,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
* ring buffer to store inpt data while waiting for output
|
* ring buffer to store inpt data while waiting for output
|
||||||
* data.
|
* data.
|
||||||
*/
|
*/
|
||||||
if( (stream->outputUnit && stream->inputUnit != stream->outputUnit)
|
if( (stream->outputUnit && (stream->inputUnit != stream->outputUnit))
|
||||||
|| stream->inputSRConverter )
|
|| stream->inputSRConverter )
|
||||||
{
|
{
|
||||||
/* May want the ringSize ot initial position in
|
/* May want the ringSize ot initial position in
|
||||||
|
|
@ -1636,6 +1771,9 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
middle of the buffer */
|
middle of the buffer */
|
||||||
if( stream->outputUnit )
|
if( stream->outputUnit )
|
||||||
PaUtil_AdvanceRingBufferWriteIndex( &stream->inputRingBuffer, ringSize / RING_BUFFER_ADVANCE_DENOMINATOR );
|
PaUtil_AdvanceRingBufferWriteIndex( &stream->inputRingBuffer, ringSize / RING_BUFFER_ADVANCE_DENOMINATOR );
|
||||||
|
|
||||||
|
// Just adds to input latency between input device and PA full duplex callback.
|
||||||
|
inputLatencyFrames += ringSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1658,6 +1796,10 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
outputParameters?outputChannelCount:0 ) ;
|
outputParameters?outputChannelCount:0 ) ;
|
||||||
if( result != paNoError )
|
if( result != paNoError )
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
inputLatencyFrames += ringSize;
|
||||||
|
outputLatencyFrames += ringSize;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- initialize Buffer Processor -- */
|
/* -- initialize Buffer Processor -- */
|
||||||
|
|
@ -1686,16 +1828,28 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
}
|
}
|
||||||
stream->bufferProcessorIsInitialized = TRUE;
|
stream->bufferProcessorIsInitialized = TRUE;
|
||||||
|
|
||||||
/*
|
// Calculate actual latency from the sum of individual latencies.
|
||||||
IMPLEMENT ME: initialise the following fields with estimated or actual
|
if( inputParameters )
|
||||||
values.
|
{
|
||||||
I think this is okay the way it is br 12/1/05
|
inputLatencyFrames += PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor);
|
||||||
maybe need to change input latency estimate if IO devs differ
|
stream->streamRepresentation.streamInfo.inputLatency = inputLatencyFrames / sampleRate;
|
||||||
*/
|
}
|
||||||
stream->streamRepresentation.streamInfo.inputLatency =
|
else
|
||||||
PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor)/sampleRate;
|
{
|
||||||
stream->streamRepresentation.streamInfo.outputLatency =
|
stream->streamRepresentation.streamInfo.inputLatency = 0.0;
|
||||||
PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor)/sampleRate;
|
}
|
||||||
|
|
||||||
|
if( outputParameters )
|
||||||
|
{
|
||||||
|
|
||||||
|
outputLatencyFrames += PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor);
|
||||||
|
stream->streamRepresentation.streamInfo.outputLatency = outputLatencyFrames / sampleRate;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stream->streamRepresentation.streamInfo.outputLatency = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
|
stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
|
||||||
|
|
||||||
stream->sampleRate = sampleRate;
|
stream->sampleRate = sampleRate;
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ static void PrintSupportedStandardSampleRates(
|
||||||
else
|
else
|
||||||
printf( "\n" );
|
printf( "\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
int main(void);
|
int main(void);
|
||||||
int main(void)
|
int main(void)
|
||||||
|
|
@ -161,10 +162,10 @@ int main(void)
|
||||||
printf( "Max inputs = %d", deviceInfo->maxInputChannels );
|
printf( "Max inputs = %d", deviceInfo->maxInputChannels );
|
||||||
printf( ", Max outputs = %d\n", deviceInfo->maxOutputChannels );
|
printf( ", Max outputs = %d\n", deviceInfo->maxOutputChannels );
|
||||||
|
|
||||||
printf( "Default low input latency = %8.3f\n", deviceInfo->defaultLowInputLatency );
|
printf( "Default low input latency = %8.4f\n", deviceInfo->defaultLowInputLatency );
|
||||||
printf( "Default low output latency = %8.3f\n", deviceInfo->defaultLowOutputLatency );
|
printf( "Default low output latency = %8.4f\n", deviceInfo->defaultLowOutputLatency );
|
||||||
printf( "Default high input latency = %8.3f\n", deviceInfo->defaultHighInputLatency );
|
printf( "Default high input latency = %8.4f\n", deviceInfo->defaultHighInputLatency );
|
||||||
printf( "Default high output latency = %8.3f\n", deviceInfo->defaultHighOutputLatency );
|
printf( "Default high output latency = %8.4f\n", deviceInfo->defaultHighOutputLatency );
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#if PA_USE_ASIO
|
#if PA_USE_ASIO
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ static int QaCallback( const void *inputBuffer, void *outputBuffer,
|
||||||
PaQaData *data = (PaQaData *) userData;
|
PaQaData *data = (PaQaData *) userData;
|
||||||
(void) inputBuffer;
|
(void) inputBuffer;
|
||||||
|
|
||||||
/* Play simle sawtooth wave. */
|
/* Play simple sawtooth wave. */
|
||||||
if( data->mode == MODE_OUTPUT )
|
if( data->mode == MODE_OUTPUT )
|
||||||
{
|
{
|
||||||
phase = data->sawPhase;
|
phase = data->sawPhase;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue