fixes for hardware samplerate changes
This commit is contained in:
parent
21a768824d
commit
8901efea70
3 changed files with 47 additions and 67 deletions
|
|
@ -84,6 +84,7 @@ TESTS = \
|
||||||
bin/patest_sine_channelmaps \
|
bin/patest_sine_channelmaps \
|
||||||
bin/patest_sine_formats \
|
bin/patest_sine_formats \
|
||||||
bin/patest_sine_time \
|
bin/patest_sine_time \
|
||||||
|
bin/patest_sine_srate \
|
||||||
bin/patest_start_stop \
|
bin/patest_start_stop \
|
||||||
bin/patest_stop \
|
bin/patest_stop \
|
||||||
bin/patest_stop_playout \
|
bin/patest_stop_playout \
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@
|
||||||
#include <libkern/OSAtomic.h>
|
#include <libkern/OSAtomic.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
PaError PaMacCore_SetUnixError( int err, int line )
|
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
|
* Durring testing of core audio, I found that serious crashes could occur
|
||||||
* if properties such as sample rate were changed multiple times in rapid
|
* 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
|
* succession. The function below could be used to with a condition variable.
|
||||||
* are acknowledged before another is requested. That seems to help a lot.
|
* 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(
|
OSStatus propertyProc(
|
||||||
|
|
@ -316,9 +322,7 @@ OSStatus propertyProc(
|
||||||
AudioDevicePropertyID inPropertyID,
|
AudioDevicePropertyID inPropertyID,
|
||||||
void* inClientData )
|
void* inClientData )
|
||||||
{
|
{
|
||||||
MutexAndBool *mab = (MutexAndBool *) inClientData;
|
// this is where we would set the condition variable
|
||||||
mab->once = TRUE;
|
|
||||||
pthread_mutex_unlock( &(mab->mutex) );
|
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -337,8 +341,6 @@ PaError AudioDeviceSetPropertyNowAndWaitForChange(
|
||||||
void *outPropertyData )
|
void *outPropertyData )
|
||||||
{
|
{
|
||||||
OSStatus macErr;
|
OSStatus macErr;
|
||||||
int unixErr;
|
|
||||||
MutexAndBool mab;
|
|
||||||
UInt32 outPropertyDataSize = inPropertyDataSize;
|
UInt32 outPropertyDataSize = inPropertyDataSize;
|
||||||
|
|
||||||
/* First, see if it already has that value. If so, return. */
|
/* First, see if it already has that value. If so, return. */
|
||||||
|
|
@ -346,74 +348,63 @@ PaError AudioDeviceSetPropertyNowAndWaitForChange(
|
||||||
isInput, inPropertyID,
|
isInput, inPropertyID,
|
||||||
&outPropertyDataSize, outPropertyData );
|
&outPropertyDataSize, outPropertyData );
|
||||||
if( macErr )
|
if( macErr )
|
||||||
goto failMac2;
|
goto failMac;
|
||||||
if( inPropertyDataSize!=outPropertyDataSize )
|
if( inPropertyDataSize!=outPropertyDataSize )
|
||||||
return paInternalError;
|
return paInternalError;
|
||||||
if( 0==memcmp( outPropertyData, inPropertyData, outPropertyDataSize ) )
|
if( 0==memcmp( outPropertyData, inPropertyData, outPropertyDataSize ) )
|
||||||
return paNoError;
|
return paNoError;
|
||||||
|
|
||||||
/* setup and lock mutex */
|
/* Ideally, we'd use a condition variable to determine changes.
|
||||||
mab.once = FALSE;
|
we could set that up here. */
|
||||||
unixErr = pthread_mutex_init( &mab.mutex, NULL );
|
|
||||||
if( unixErr )
|
/* If we were using a cond variable, we'd add a property listener here.
|
||||||
goto failUnix2;
|
No more notes on that, but don't forget to remove the listener as well! */
|
||||||
unixErr = pthread_mutex_lock( &mab.mutex );
|
//macErr = AudioDeviceAddPropertyListener( inDevice, inChannel, isInput,
|
||||||
if( unixErr )
|
// inPropertyID, propertyProc,
|
||||||
goto failUnix;
|
// NULL );
|
||||||
|
//if( macErr )
|
||||||
|
// /* we couldn't add a listener. */
|
||||||
|
// goto failMac;
|
||||||
|
|
||||||
/* add property listener */
|
|
||||||
macErr = AudioDeviceAddPropertyListener( inDevice, inChannel, isInput,
|
|
||||||
inPropertyID, propertyProc,
|
|
||||||
&mab );
|
|
||||||
if( macErr )
|
|
||||||
goto failMac;
|
|
||||||
/* set property */
|
/* set property */
|
||||||
macErr = AudioDeviceSetProperty( inDevice, NULL, inChannel,
|
macErr = AudioDeviceSetProperty( inDevice, NULL, inChannel,
|
||||||
isInput, inPropertyID,
|
isInput, inPropertyID,
|
||||||
inPropertyDataSize, inPropertyData );
|
inPropertyDataSize, inPropertyData );
|
||||||
if( macErr ) {
|
if( macErr )
|
||||||
/* we couldn't set the property, so we'll just unlock the mutex
|
goto failMac;
|
||||||
and move on. */
|
|
||||||
pthread_mutex_unlock( &mab.mutex );
|
/* 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." ) );
|
||||||
|
|
||||||
|
|
||||||
/* wait for property to change */
|
///* now read the property back out */
|
||||||
unixErr = pthread_mutex_lock( &mab.mutex );
|
|
||||||
if( unixErr )
|
|
||||||
goto failUnix;
|
|
||||||
|
|
||||||
/* now read the property back out */
|
|
||||||
macErr = AudioDeviceGetProperty( inDevice, inChannel,
|
macErr = AudioDeviceGetProperty( inDevice, inChannel,
|
||||||
isInput, inPropertyID,
|
isInput, inPropertyID,
|
||||||
&outPropertyDataSize, outPropertyData );
|
&outPropertyDataSize, outPropertyData );
|
||||||
if( macErr )
|
if( macErr )
|
||||||
goto failMac;
|
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;
|
return paUnanticipatedHostError;
|
||||||
|
|
||||||
failMac:
|
failMac:
|
||||||
pthread_mutex_destroy( &mab.mutex );
|
|
||||||
AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput,
|
|
||||||
inPropertyID, propertyProc );
|
|
||||||
failMac2:
|
|
||||||
return ERR( macErr );
|
return ERR( macErr );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -143,18 +143,6 @@ long computeRingBufferSize( const PaStreamParameters *inputParameters,
|
||||||
long outputFramesPerBuffer,
|
long outputFramesPerBuffer,
|
||||||
double sampleRate );
|
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(
|
OSStatus propertyProc(
|
||||||
AudioDeviceID inDevice,
|
AudioDeviceID inDevice,
|
||||||
UInt32 inChannel,
|
UInt32 inChannel,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue