From: bjornroche Date: Mon, 30 Nov 2009 21:07:43 +0000 (+0000) Subject: fixes for hardware samplerate changes X-Git-Tag: pa_stable_v19_20110326_r1647~206 X-Git-Url: https://andrewgundersen.net/repos?a=commitdiff_plain;h=8901efea707fafe67170d6f9529e8922362526da;p=portaudio fixes for hardware samplerate changes --- diff --git a/Makefile.in b/Makefile.in index dca537d..0ca2d01 100644 --- a/Makefile.in +++ b/Makefile.in @@ -84,6 +84,7 @@ TESTS = \ bin/patest_sine_channelmaps \ bin/patest_sine_formats \ bin/patest_sine_time \ + bin/patest_sine_srate \ bin/patest_start_stop \ bin/patest_stop \ bin/patest_stop_playout \ diff --git a/src/hostapi/coreaudio/pa_mac_core_utilities.c b/src/hostapi/coreaudio/pa_mac_core_utilities.c index 5bc592e..86c341c 100644 --- a/src/hostapi/coreaudio/pa_mac_core_utilities.c +++ b/src/hostapi/coreaudio/pa_mac_core_utilities.c @@ -61,6 +61,7 @@ #include #include #include +#include PaError PaMacCore_SetUnixError( int err, int line ) { @@ -305,8 +306,13 @@ long computeRingBufferSize( const PaStreamParameters *inputParameters, /* * Durring testing of core audio, I found that serious crashes could occur * if properties such as sample rate were changed multiple times in rapid - * succession. The function below has some fancy logic to make sure that changes - * are acknowledged before another is requested. That seems to help a lot. + * succession. The function below could be used to with a condition variable. + * to prevent propertychanges from happening until the last property + * change is acknowledged. Instead, I implemented a busy-wait, which is simpler + * to implement b/c in second round of testing (nov '09) property changes occured + * quickly and so there was no real way to test the condition variable implementation. + * therefore, this function is not used, but it is aluded to in commented code below, + * since it represents a theoretically better implementation. */ OSStatus propertyProc( @@ -316,9 +322,7 @@ OSStatus propertyProc( AudioDevicePropertyID inPropertyID, void* inClientData ) { - MutexAndBool *mab = (MutexAndBool *) inClientData; - mab->once = TRUE; - pthread_mutex_unlock( &(mab->mutex) ); + // this is where we would set the condition variable return noErr; } @@ -337,8 +341,6 @@ PaError AudioDeviceSetPropertyNowAndWaitForChange( void *outPropertyData ) { OSStatus macErr; - int unixErr; - MutexAndBool mab; UInt32 outPropertyDataSize = inPropertyDataSize; /* First, see if it already has that value. If so, return. */ @@ -346,74 +348,63 @@ PaError AudioDeviceSetPropertyNowAndWaitForChange( isInput, inPropertyID, &outPropertyDataSize, outPropertyData ); if( macErr ) - goto failMac2; + goto failMac; if( inPropertyDataSize!=outPropertyDataSize ) return paInternalError; if( 0==memcmp( outPropertyData, inPropertyData, outPropertyDataSize ) ) return paNoError; - /* setup and lock mutex */ - mab.once = FALSE; - unixErr = pthread_mutex_init( &mab.mutex, NULL ); - if( unixErr ) - goto failUnix2; - unixErr = pthread_mutex_lock( &mab.mutex ); - if( unixErr ) - goto failUnix; - - /* add property listener */ - macErr = AudioDeviceAddPropertyListener( inDevice, inChannel, isInput, - inPropertyID, propertyProc, - &mab ); - if( macErr ) - goto failMac; + /* Ideally, we'd use a condition variable to determine changes. + we could set that up here. */ + + /* If we were using a cond variable, we'd add a property listener here. + No more notes on that, but don't forget to remove the listener as well! */ + //macErr = AudioDeviceAddPropertyListener( inDevice, inChannel, isInput, + // inPropertyID, propertyProc, + // NULL ); + //if( macErr ) + // /* we couldn't add a listener. */ + // goto failMac; + /* set property */ macErr = AudioDeviceSetProperty( inDevice, NULL, inChannel, isInput, inPropertyID, inPropertyDataSize, inPropertyData ); - if( macErr ) { - /* we couldn't set the property, so we'll just unlock the mutex - and move on. */ - pthread_mutex_unlock( &mab.mutex ); - } + if( macErr ) + goto failMac; - /* wait for property to change */ - unixErr = pthread_mutex_lock( &mab.mutex ); - if( unixErr ) - goto failUnix; + /* busy-wait up to 30 seconds for the property to change */ + /* busy-wait is justified here only because the correct alternative (condition variable) + was hard to test, since most of the waiting ended up being for setting rather than + getting in OS X 10.5. This was not the case in earlier OS versions. */ + struct timeval tv1, tv2; + gettimeofday( &tv1, NULL ); + memcpy( &tv2, &tv1, sizeof( struct timeval ) ); + while( tv2.tv_sec - tv1.tv_sec < 30 ) { + macErr = AudioDeviceGetProperty( inDevice, inChannel, + isInput, inPropertyID, + &outPropertyDataSize, outPropertyData ); + if( macErr ) + goto failMac; + if( 0==memcmp( outPropertyData, inPropertyData, outPropertyDataSize ) ) { + return paNoError; + } + Pa_Sleep( 100 ); + gettimeofday( &tv2, NULL ); + } + DBUG( ("Timeout waiting for device setting." ) ); + - /* now read the property back out */ + ///* now read the property back out */ macErr = AudioDeviceGetProperty( inDevice, inChannel, isInput, inPropertyID, &outPropertyDataSize, outPropertyData ); if( macErr ) goto failMac; - /* cleanup */ - AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, - inPropertyID, propertyProc ); - unixErr = pthread_mutex_unlock( &mab.mutex ); - if( unixErr ) - goto failUnix2; - unixErr = pthread_mutex_destroy( &mab.mutex ); - if( unixErr ) - goto failUnix2; - - return paNoError; - - failUnix: - pthread_mutex_destroy( &mab.mutex ); - AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, - inPropertyID, propertyProc ); - failUnix2: - DBUG( ("Error #%d while setting a device property: %s\n", unixErr, strerror( unixErr ) ) ); return paUnanticipatedHostError; failMac: - pthread_mutex_destroy( &mab.mutex ); - AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, - inPropertyID, propertyProc ); - failMac2: return ERR( macErr ); } diff --git a/src/hostapi/coreaudio/pa_mac_core_utilities.h b/src/hostapi/coreaudio/pa_mac_core_utilities.h index 899826d..7c4afe5 100644 --- a/src/hostapi/coreaudio/pa_mac_core_utilities.h +++ b/src/hostapi/coreaudio/pa_mac_core_utilities.h @@ -143,18 +143,6 @@ long computeRingBufferSize( const PaStreamParameters *inputParameters, long outputFramesPerBuffer, double sampleRate ); -/* - * Durring testing of core audio, I found that serious crashes could occur - * if properties such as sample rate were changed multiple times in rapid - * succession. The function below has some fancy logic to make sure that changes - * are acknowledged before another is requested. That seems to help a lot. - */ - -typedef struct { - bool once; /* I didn't end up using this. bdr */ - pthread_mutex_t mutex; -} MutexAndBool ; - OSStatus propertyProc( AudioDeviceID inDevice, UInt32 inChannel,