]> Repos - portaudio/commitdiff
fixes for hardware samplerate changes
authorbjornroche <bjornroche@0f58301d-fd10-0410-b4af-bbb618454e57>
Mon, 30 Nov 2009 21:07:43 +0000 (21:07 +0000)
committerbjornroche <bjornroche@0f58301d-fd10-0410-b4af-bbb618454e57>
Mon, 30 Nov 2009 21:07:43 +0000 (21:07 +0000)
Makefile.in
src/hostapi/coreaudio/pa_mac_core_utilities.c
src/hostapi/coreaudio/pa_mac_core_utilities.h

index dca537d54c25deaea29fe346106863329d1c1678..0ca2d01a44bbc0829e60b9b1acb78a16846e8cfc 100644 (file)
@@ -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 \
index 5bc592e86e163c10daa7837daaaba9308bf5868d..86c341c52c43eb32d2cc3e4f693fb91e99437e3b 100644 (file)
@@ -61,6 +61,7 @@
 #include <libkern/OSAtomic.h>
 #include <strings.h>
 #include <pthread.h>
+#include <sys/time.h>
 
 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 );
 }
 
index 899826d596419c0d5355dea7c48b5d52fadbca8b..7c4afe52cacdb6808de37e827807c8144d0b4ebd 100644 (file)
@@ -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,