fixed regression in r1718 (PA/coreaudio) where PA callback timestamps would be offset by massive latency (frames interpreted as seconds) if the initial query for actual device sample rate failed. This checkin reinstates the use of nominal sample rate as default for latency calculations when actual sample rate query fails.
This commit is contained in:
parent
56f148f7b8
commit
c1390f8c18
2 changed files with 40 additions and 47 deletions
|
|
@ -990,18 +990,19 @@ static void UpdateTimeStampOffsets( PaMacCoreStream *stream )
|
|||
}
|
||||
|
||||
/* ================================================================================= */
|
||||
/* Query sample rate property. */
|
||||
static OSStatus UpdateSampleRateFromDeviceProperty( PaMacCoreStream *stream, AudioDeviceID deviceID, Boolean isInput )
|
||||
|
||||
/* can be used to update from nominal or actual sample rate */
|
||||
static OSStatus UpdateSampleRateFromDeviceProperty( PaMacCoreStream *stream, AudioDeviceID deviceID, Boolean isInput, AudioDevicePropertyID sampleRatePropertyID )
|
||||
{
|
||||
PaMacCoreDeviceProperties * deviceProperties = isInput ? &stream->inputProperties : &stream->outputProperties;
|
||||
/* FIXME: not sure if this should be the sample rate of the output device or the output unit */
|
||||
Float64 actualSampleRate = deviceProperties->sampleRate;
|
||||
|
||||
Float64 sampleRate = 0.0;
|
||||
UInt32 propSize = sizeof(Float64);
|
||||
OSStatus osErr = AudioDeviceGetProperty( deviceID, 0, isInput, kAudioDevicePropertyActualSampleRate, &propSize, &actualSampleRate);
|
||||
if( (osErr == noErr) && (actualSampleRate > 1000.0) ) // avoid divide by zero if there's an error
|
||||
OSStatus osErr = AudioDeviceGetProperty( deviceID, 0, isInput, sampleRatePropertyID, &propSize, &sampleRate);
|
||||
if( (osErr == noErr) && (sampleRate > 1000.0) ) /* avoid divide by zero if there's an error */
|
||||
{
|
||||
deviceProperties->sampleRate = actualSampleRate;
|
||||
deviceProperties->samplePeriod = 1.0 / actualSampleRate;
|
||||
deviceProperties->sampleRate = sampleRate;
|
||||
deviceProperties->samplePeriod = 1.0 / sampleRate;
|
||||
}
|
||||
return osErr;
|
||||
}
|
||||
|
|
@ -1013,7 +1014,7 @@ static OSStatus AudioDevicePropertyActualSampleRateListenerProc( AudioDeviceID i
|
|||
// Make sure the callback is operating on a stream that is still valid!
|
||||
assert( stream->streamRepresentation.magic == PA_STREAM_MAGIC );
|
||||
|
||||
OSStatus osErr = UpdateSampleRateFromDeviceProperty( stream, inDevice, isInput );
|
||||
OSStatus osErr = UpdateSampleRateFromDeviceProperty( stream, inDevice, isInput, kAudioDevicePropertyActualSampleRate );
|
||||
if( osErr == noErr )
|
||||
{
|
||||
UpdateTimeStampOffsets( stream );
|
||||
|
|
@ -1077,9 +1078,6 @@ static OSStatus SetupDevicePropertyListeners( PaMacCoreStream *stream, AudioDevi
|
|||
OSStatus osErr = noErr;
|
||||
PaMacCoreDeviceProperties *deviceProperties = isInput ? &stream->inputProperties : &stream->outputProperties;
|
||||
|
||||
// Start with the current values for the device properties.
|
||||
UpdateSampleRateFromDeviceProperty( stream, deviceID, isInput );
|
||||
|
||||
if( (osErr = QueryUInt32DeviceProperty( deviceID, isInput,
|
||||
kAudioDevicePropertyLatency, &deviceProperties->deviceLatency )) != noErr ) return osErr;
|
||||
if( (osErr = QueryUInt32DeviceProperty( deviceID, isInput,
|
||||
|
|
@ -1993,53 +1991,48 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||
|
||||
stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
|
||||
|
||||
stream->sampleRate = sampleRate;
|
||||
stream->outDeviceSampleRate = 0;
|
||||
if( stream->outputUnit ) {
|
||||
Float64 rate;
|
||||
UInt32 size = sizeof( rate );
|
||||
result = ERR( AudioDeviceGetProperty( stream->outputDevice,
|
||||
0,
|
||||
FALSE,
|
||||
kAudioDevicePropertyNominalSampleRate,
|
||||
&size, &rate ) );
|
||||
if( result )
|
||||
goto error;
|
||||
stream->outDeviceSampleRate = rate;
|
||||
}
|
||||
stream->inDeviceSampleRate = 0;
|
||||
if( stream->inputUnit ) {
|
||||
Float64 rate;
|
||||
UInt32 size = sizeof( rate );
|
||||
result = ERR( AudioDeviceGetProperty( stream->inputDevice,
|
||||
0,
|
||||
TRUE,
|
||||
kAudioDevicePropertyNominalSampleRate,
|
||||
&size, &rate ) );
|
||||
if( result )
|
||||
goto error;
|
||||
stream->inDeviceSampleRate = rate;
|
||||
}
|
||||
stream->sampleRate = sampleRate;
|
||||
|
||||
stream->userInChan = inputChannelCount;
|
||||
stream->userOutChan = outputChannelCount;
|
||||
|
||||
// Setup property listeners for timestamp and latency calculations.
|
||||
pthread_mutex_init( &stream->timingInformationMutex, NULL );
|
||||
stream->timingInformationMutexIsInitialized = 1;
|
||||
InitializeDeviceProperties( &stream->inputProperties );
|
||||
InitializeDeviceProperties( &stream->outputProperties );
|
||||
InitializeDeviceProperties( &stream->inputProperties ); // zeros the struct. doesn't actually init it to useful values
|
||||
InitializeDeviceProperties( &stream->outputProperties ); // zeros the struct. doesn't actually init it to useful values
|
||||
if( stream->outputUnit )
|
||||
{
|
||||
Boolean isInput = FALSE;
|
||||
|
||||
// Start with the current values for the device properties.
|
||||
// Init with nominal sample rate. Use actual sample rate where available
|
||||
|
||||
result = ERR( UpdateSampleRateFromDeviceProperty(
|
||||
stream, stream->outputDevice, isInput, kAudioDevicePropertyNominalSampleRate ) );
|
||||
if( result )
|
||||
goto error; /* fail if we can't even get a nominal device sample rate */
|
||||
|
||||
UpdateSampleRateFromDeviceProperty( stream, stream->outputDevice, isInput, kAudioDevicePropertyActualSampleRate );
|
||||
|
||||
SetupDevicePropertyListeners( stream, stream->outputDevice, isInput );
|
||||
}
|
||||
if( stream->inputUnit )
|
||||
{
|
||||
Boolean isInput = TRUE;
|
||||
|
||||
// as above
|
||||
result = ERR( UpdateSampleRateFromDeviceProperty(
|
||||
stream, stream->inputDevice, isInput, kAudioDevicePropertyNominalSampleRate ) );
|
||||
if( result )
|
||||
goto error;
|
||||
|
||||
UpdateSampleRateFromDeviceProperty( stream, stream->inputDevice, isInput, kAudioDevicePropertyActualSampleRate );
|
||||
|
||||
SetupDevicePropertyListeners( stream, stream->inputDevice, isInput );
|
||||
}
|
||||
UpdateTimeStampOffsets( stream );
|
||||
// Setup copies to be used by audio callback.
|
||||
// Setup timestamp copies to be used by audio callback.
|
||||
stream->timestampOffsetCombined_ioProcCopy = stream->timestampOffsetCombined;
|
||||
stream->timestampOffsetInputDevice_ioProcCopy = stream->timestampOffsetInputDevice;
|
||||
stream->timestampOffsetOutputDevice_ioProcCopy = stream->timestampOffsetOutputDevice;
|
||||
|
|
|
|||
|
|
@ -120,7 +120,11 @@ typedef struct PaMacCoreDeviceProperties
|
|||
UInt32 bufferFrameSize;
|
||||
// UInt32 streamLatency; // Seems to be the same as deviceLatency!?
|
||||
UInt32 deviceLatency;
|
||||
/* Current device sample rate. May change! */
|
||||
/* Current device sample rate. May change!
|
||||
These are initialized to the nominal device sample rate,
|
||||
and updated with the actual sample rate, when/where available.
|
||||
Note that these are the *device* sample rates, prior to any required
|
||||
SR conversion. */
|
||||
Float64 sampleRate;
|
||||
Float64 samplePeriod; // reciprocal
|
||||
}
|
||||
|
|
@ -166,10 +170,6 @@ typedef struct PaMacCoreStream
|
|||
ACTIVE = 3 /* The stream is active and running. */
|
||||
} state;
|
||||
double sampleRate;
|
||||
//these may be different from the stream sample rate due to SR conversion:
|
||||
double outDeviceSampleRate;
|
||||
double inDeviceSampleRate;
|
||||
|
||||
PaMacCoreDeviceProperties inputProperties;
|
||||
PaMacCoreDeviceProperties outputProperties;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue