From: rossb Date: Tue, 27 Dec 2011 08:58:59 +0000 (+0000) Subject: fixed regression in r1718 (PA/coreaudio) where PA callback timestamps would be offset... X-Git-Tag: pa_stable_v19_20140130_r1919~94 X-Git-Url: https://andrewgundersen.net/repos?a=commitdiff_plain;h=c1390f8c18469b3f9188bd4b3a6cd05f2406571e;p=portaudio 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. --- diff --git a/src/hostapi/coreaudio/pa_mac_core.c b/src/hostapi/coreaudio/pa_mac_core.c index b182dac..55ce9f0 100644 --- a/src/hostapi/coreaudio/pa_mac_core.c +++ b/src/hostapi/coreaudio/pa_mac_core.c @@ -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; diff --git a/src/hostapi/coreaudio/pa_mac_core_internal.h b/src/hostapi/coreaudio/pa_mac_core_internal.h index 462240b..14e3d07 100644 --- a/src/hostapi/coreaudio/pa_mac_core_internal.h +++ b/src/hostapi/coreaudio/pa_mac_core_internal.h @@ -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;