Compare commits

...
Sign in to create a new pull request.
Author SHA1 Message Date
Richard Cartwright
68ce920967 Update darwin build to use newer core audio frameworks.
Replaced references to core services audio component with equivalent
function calls in the AudioUnit/AudioComponent.h API.
2017-11-09 21:32:10 +00:00
2 changed files with 171 additions and 170 deletions

View file

@ -15,7 +15,7 @@
* Olivier Tristan for feedback and testing * Olivier Tristan for feedback and testing
* Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O
* interface. * interface.
* *
* *
* Based on the Open Source API proposed by Ross Bencina * Based on the Open Source API proposed by Ross Bencina
* Copyright (c) 1999-2002 Ross Bencina, Phil Burk * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
@ -41,13 +41,13 @@
*/ */
/* /*
* The text above constitutes the entire PortAudio license; however, * The text above constitutes the entire PortAudio license; however,
* the PortAudio community also makes the following non-binding requests: * the PortAudio community also makes the following non-binding requests:
* *
* Any person wishing to distribute modifications to the Software is * Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that * requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. It is also * they can be incorporated into the canonical version. It is also
* requested that these non-binding requests be included along with the * requested that these non-binding requests be included along with the
* license above. * license above.
*/ */
@ -76,10 +76,10 @@
extern "C" extern "C"
{ {
#endif /* __cplusplus */ #endif /* __cplusplus */
/* This is a reasonable size for a small buffer based on experience. */ /* This is a reasonable size for a small buffer based on experience. */
#define PA_MAC_SMALL_BUFFER_SIZE (64) #define PA_MAC_SMALL_BUFFER_SIZE (64)
/* prototypes for functions declared in this file */ /* prototypes for functions declared in this file */
PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
@ -135,7 +135,7 @@ const char *PaMacCore_GetChannelName( int device, int channelIndex, bool input )
PaMacAUHAL *macCoreHostApi = (PaMacAUHAL*)hostApi; PaMacAUHAL *macCoreHostApi = (PaMacAUHAL*)hostApi;
AudioDeviceID hostApiDevice = macCoreHostApi->devIds[device]; AudioDeviceID hostApiDevice = macCoreHostApi->devIds[device];
CFStringRef nameRef; CFStringRef nameRef;
/* First try with CFString */ /* First try with CFString */
UInt32 size = sizeof(nameRef); UInt32 size = sizeof(nameRef);
error = AudioDeviceGetProperty( hostApiDevice, error = AudioDeviceGetProperty( hostApiDevice,
@ -158,23 +158,23 @@ const char *PaMacCore_GetChannelName( int device, int channelIndex, bool input )
{ {
if( !ensureChannelNameSize( size ) ) if( !ensureChannelNameSize( size ) )
return NULL; return NULL;
error = AudioDeviceGetProperty( hostApiDevice, error = AudioDeviceGetProperty( hostApiDevice,
channelIndex + 1, channelIndex + 1,
input, input,
kAudioDevicePropertyChannelName, kAudioDevicePropertyChannelName,
&size, &size,
channelName ); channelName );
if( !error ) if( !error )
return channelName; return channelName;
} }
/* as a last-ditch effort, we use the device name and append the channel number. */ /* as a last-ditch effort, we use the device name and append the channel number. */
nameRef = CFStringCreateWithFormat( NULL, NULL, CFSTR( "%s: %d"), hostApi->deviceInfos[device]->name, channelIndex + 1 ); nameRef = CFStringCreateWithFormat( NULL, NULL, CFSTR( "%s: %d"), hostApi->deviceInfos[device]->name, channelIndex + 1 );
size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameRef), kCFStringEncodingUTF8);; size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameRef), kCFStringEncodingUTF8);;
if( !ensureChannelNameSize( size ) ) if( !ensureChannelNameSize( size ) )
{ {
@ -195,19 +195,19 @@ const char *PaMacCore_GetChannelName( int device, int channelIndex, bool input )
CFStringGetCString( nameRef, channelName, size+1, kCFStringEncodingUTF8 ); CFStringGetCString( nameRef, channelName, size+1, kCFStringEncodingUTF8 );
CFRelease( nameRef ); CFRelease( nameRef );
} }
return channelName; return channelName;
} }
PaError PaMacCore_GetBufferSizeRange( PaDeviceIndex device, PaError PaMacCore_GetBufferSizeRange( PaDeviceIndex device,
long *minBufferSizeFrames, long *maxBufferSizeFrames ) long *minBufferSizeFrames, long *maxBufferSizeFrames )
{ {
PaError result; PaError result;
PaUtilHostApiRepresentation *hostApi; PaUtilHostApiRepresentation *hostApi;
result = PaUtil_GetHostApiRepresentation( &hostApi, paCoreAudio ); result = PaUtil_GetHostApiRepresentation( &hostApi, paCoreAudio );
if( result == paNoError ) if( result == paNoError )
{ {
PaDeviceIndex hostApiDeviceIndex; PaDeviceIndex hostApiDeviceIndex;
@ -218,19 +218,19 @@ PaError PaMacCore_GetBufferSizeRange( PaDeviceIndex device,
AudioDeviceID macCoreDeviceId = macCoreHostApi->devIds[hostApiDeviceIndex]; AudioDeviceID macCoreDeviceId = macCoreHostApi->devIds[hostApiDeviceIndex];
AudioValueRange audioRange; AudioValueRange audioRange;
UInt32 propSize = sizeof( audioRange ); UInt32 propSize = sizeof( audioRange );
// return the size range for the output scope unless we only have inputs // return the size range for the output scope unless we only have inputs
Boolean isInput = 0; Boolean isInput = 0;
if( macCoreHostApi->inheritedHostApiRep.deviceInfos[hostApiDeviceIndex]->maxOutputChannels == 0 ) if( macCoreHostApi->inheritedHostApiRep.deviceInfos[hostApiDeviceIndex]->maxOutputChannels == 0 )
isInput = 1; isInput = 1;
result = WARNING(AudioDeviceGetProperty( macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &audioRange ) ); result = WARNING(AudioDeviceGetProperty( macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &audioRange ) );
*minBufferSizeFrames = audioRange.mMinimum; *minBufferSizeFrames = audioRange.mMinimum;
*maxBufferSizeFrames = audioRange.mMaximum; *maxBufferSizeFrames = audioRange.mMaximum;
} }
} }
return result; return result;
} }
@ -401,7 +401,7 @@ static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi)
break; break;
} }
} }
} }
if( 0 != AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, if( 0 != AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
&size, &size,
&auhalHostApi->defaultOut) ) { &auhalHostApi->defaultOut) ) {
@ -418,7 +418,7 @@ static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi)
break; break;
} }
} }
} }
VDBUG( ( "Default in : %ld\n", auhalHostApi->defaultIn ) ); VDBUG( ( "Default in : %ld\n", auhalHostApi->defaultIn ) );
VDBUG( ( "Default out: %ld\n", auhalHostApi->defaultOut ) ); VDBUG( ( "Default out: %ld\n", auhalHostApi->defaultOut ) );
@ -457,27 +457,27 @@ static void DumpDeviceProperties( AudioDeviceID macCoreDeviceId,
UInt32 bufferFrames; UInt32 bufferFrames;
UInt32 safetyOffset; UInt32 safetyOffset;
AudioStreamID streamIDs[128]; AudioStreamID streamIDs[128];
printf("\n======= latency query : macCoreDeviceId = %d, isInput %d =======\n", (int)macCoreDeviceId, isInput ); printf("\n======= latency query : macCoreDeviceId = %d, isInput %d =======\n", (int)macCoreDeviceId, isInput );
propSize = sizeof(UInt32); propSize = sizeof(UInt32);
err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propSize, &bufferFrames)); err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propSize, &bufferFrames));
printf("kAudioDevicePropertyBufferFrameSize: err = %d, propSize = %d, value = %d\n", err, propSize, bufferFrames ); printf("kAudioDevicePropertyBufferFrameSize: err = %d, propSize = %d, value = %d\n", err, propSize, bufferFrames );
propSize = sizeof(UInt32); propSize = sizeof(UInt32);
err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertySafetyOffset, &propSize, &safetyOffset)); err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertySafetyOffset, &propSize, &safetyOffset));
printf("kAudioDevicePropertySafetyOffset: err = %d, propSize = %d, value = %d\n", err, propSize, safetyOffset ); printf("kAudioDevicePropertySafetyOffset: err = %d, propSize = %d, value = %d\n", err, propSize, safetyOffset );
propSize = sizeof(UInt32); propSize = sizeof(UInt32);
err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &deviceLatency)); err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &deviceLatency));
printf("kAudioDevicePropertyLatency: err = %d, propSize = %d, value = %d\n", err, propSize, deviceLatency ); printf("kAudioDevicePropertyLatency: err = %d, propSize = %d, value = %d\n", err, propSize, deviceLatency );
AudioValueRange audioRange; AudioValueRange audioRange;
propSize = sizeof( audioRange ); propSize = sizeof( audioRange );
err = WARNING(AudioDeviceGetProperty( macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &audioRange ) ); err = WARNING(AudioDeviceGetProperty( macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &audioRange ) );
printf("kAudioDevicePropertyBufferFrameSizeRange: err = %d, propSize = %u, minimum = %g\n", err, propSize, audioRange.mMinimum); printf("kAudioDevicePropertyBufferFrameSizeRange: err = %d, propSize = %u, minimum = %g\n", err, propSize, audioRange.mMinimum);
printf("kAudioDevicePropertyBufferFrameSizeRange: err = %d, propSize = %u, maximum = %g\n", err, propSize, audioRange.mMaximum ); printf("kAudioDevicePropertyBufferFrameSizeRange: err = %d, propSize = %u, maximum = %g\n", err, propSize, audioRange.mMaximum );
/* Get the streams from the device and query their latency. */ /* Get the streams from the device and query their latency. */
propSize = sizeof(streamIDs); propSize = sizeof(streamIDs);
err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreams, &propSize, &streamIDs[0])); err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreams, &propSize, &streamIDs[0]));
@ -485,7 +485,7 @@ static void DumpDeviceProperties( AudioDeviceID macCoreDeviceId,
for( i=0; i<numStreams; i++ ) for( i=0; i<numStreams; i++ )
{ {
printf("Stream #%d = %d---------------------- \n", i, streamIDs[i] ); printf("Stream #%d = %d---------------------- \n", i, streamIDs[i] );
propSize = sizeof(UInt32); propSize = sizeof(UInt32);
err = WARNING(AudioStreamGetProperty(streamIDs[i], 0, kAudioStreamPropertyLatency, &propSize, &streamLatency)); err = WARNING(AudioStreamGetProperty(streamIDs[i], 0, kAudioStreamPropertyLatency, &propSize, &streamLatency));
printf(" kAudioStreamPropertyLatency: err = %d, propSize = %d, value = %d\n", err, propSize, streamLatency ); printf(" kAudioStreamPropertyLatency: err = %d, propSize = %d, value = %d\n", err, propSize, streamLatency );
@ -513,22 +513,22 @@ static PaError CalculateFixedDeviceLatency( AudioDeviceID macCoreDeviceId, int i
UInt32 streamLatency; UInt32 streamLatency;
UInt32 safetyOffset; UInt32 safetyOffset;
AudioStreamID streamIDs[1]; AudioStreamID streamIDs[1];
// To get stream latency we have to get a streamID from the device. // To get stream latency we have to get a streamID from the device.
// We are only going to look at the first stream so only fetch one stream. // We are only going to look at the first stream so only fetch one stream.
propSize = sizeof(streamIDs); propSize = sizeof(streamIDs);
err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreams, &propSize, &streamIDs[0])); err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreams, &propSize, &streamIDs[0]));
if( err != paNoError ) goto error; if( err != paNoError ) goto error;
if( propSize == sizeof(AudioStreamID) ) if( propSize == sizeof(AudioStreamID) )
{ {
propSize = sizeof(UInt32); propSize = sizeof(UInt32);
err = WARNING(AudioStreamGetProperty(streamIDs[0], 0, kAudioStreamPropertyLatency, &propSize, &streamLatency)); err = WARNING(AudioStreamGetProperty(streamIDs[0], 0, kAudioStreamPropertyLatency, &propSize, &streamLatency));
} }
propSize = sizeof(UInt32); propSize = sizeof(UInt32);
err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertySafetyOffset, &propSize, &safetyOffset)); err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertySafetyOffset, &propSize, &safetyOffset));
if( err != paNoError ) goto error; if( err != paNoError ) goto error;
propSize = sizeof(UInt32); propSize = sizeof(UInt32);
err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &deviceLatency)); err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &deviceLatency));
if( err != paNoError ) goto error; if( err != paNoError ) goto error;
@ -548,24 +548,24 @@ static PaError CalculateDefaultDeviceLatencies( AudioDeviceID macCoreDeviceId,
UInt32 bufferFrames = 0; UInt32 bufferFrames = 0;
UInt32 fixedLatency = 0; UInt32 fixedLatency = 0;
UInt32 clippedMinBufferSize = 0; UInt32 clippedMinBufferSize = 0;
//DumpDeviceProperties( macCoreDeviceId, isInput ); //DumpDeviceProperties( macCoreDeviceId, isInput );
PaError err = CalculateFixedDeviceLatency( macCoreDeviceId, isInput, &fixedLatency ); PaError err = CalculateFixedDeviceLatency( macCoreDeviceId, isInput, &fixedLatency );
if( err != paNoError ) goto error; if( err != paNoError ) goto error;
// For low latency use a small fixed size buffer clipped to the device range. // For low latency use a small fixed size buffer clipped to the device range.
err = ClipToDeviceBufferSize( macCoreDeviceId, isInput, PA_MAC_SMALL_BUFFER_SIZE, &clippedMinBufferSize ); err = ClipToDeviceBufferSize( macCoreDeviceId, isInput, PA_MAC_SMALL_BUFFER_SIZE, &clippedMinBufferSize );
if( err != paNoError ) goto error; if( err != paNoError ) goto error;
// For high latency use the default device buffer size. // For high latency use the default device buffer size.
propSize = sizeof(UInt32); propSize = sizeof(UInt32);
err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propSize, &bufferFrames)); err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propSize, &bufferFrames));
if( err != paNoError ) goto error; if( err != paNoError ) goto error;
*lowLatencyFramesPtr = fixedLatency + clippedMinBufferSize; *lowLatencyFramesPtr = fixedLatency + clippedMinBufferSize;
*highLatencyFramesPtr = fixedLatency + bufferFrames; *highLatencyFramesPtr = fixedLatency + bufferFrames;
return err; return err;
error: error:
return err; return err;
@ -583,7 +583,7 @@ static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi,
UInt32 i; UInt32 i;
int numChannels = 0; int numChannels = 0;
AudioBufferList *buflist = NULL; AudioBufferList *buflist = NULL;
VVDBUG(("GetChannelInfo()\n")); VVDBUG(("GetChannelInfo()\n"));
/* Get the number of channels from the stream configuration. /* Get the number of channels from the stream configuration.
@ -607,7 +607,7 @@ static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi,
deviceInfo->maxInputChannels = numChannels; deviceInfo->maxInputChannels = numChannels;
else else
deviceInfo->maxOutputChannels = numChannels; deviceInfo->maxOutputChannels = numChannels;
if (numChannels > 0) /* do not try to retrieve the latency if there are no channels. */ if (numChannels > 0) /* do not try to retrieve the latency if there are no channels. */
{ {
/* Get the latency. Don't fail if we can't get this. */ /* Get the latency. Don't fail if we can't get this. */
@ -615,13 +615,13 @@ static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi,
deviceInfo->defaultLowInputLatency = .01; deviceInfo->defaultLowInputLatency = .01;
deviceInfo->defaultHighInputLatency = .10; deviceInfo->defaultHighInputLatency = .10;
deviceInfo->defaultLowOutputLatency = .01; deviceInfo->defaultLowOutputLatency = .01;
deviceInfo->defaultHighOutputLatency = .10; deviceInfo->defaultHighOutputLatency = .10;
UInt32 lowLatencyFrames = 0; UInt32 lowLatencyFrames = 0;
UInt32 highLatencyFrames = 0; UInt32 highLatencyFrames = 0;
err = CalculateDefaultDeviceLatencies( macCoreDeviceId, isInput, &lowLatencyFrames, &highLatencyFrames ); err = CalculateDefaultDeviceLatencies( macCoreDeviceId, isInput, &lowLatencyFrames, &highLatencyFrames );
if( err == 0 ) if( err == 0 )
{ {
double lowLatencySeconds = lowLatencyFrames / deviceInfo->defaultSampleRate; double lowLatencySeconds = lowLatencyFrames / deviceInfo->defaultSampleRate;
double highLatencySeconds = highLatencyFrames / deviceInfo->defaultSampleRate; double highLatencySeconds = highLatencyFrames / deviceInfo->defaultSampleRate;
if (isInput) if (isInput)
@ -661,7 +661,7 @@ static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi,
deviceInfo->structVersion = 2; deviceInfo->structVersion = 2;
deviceInfo->hostApi = hostApiIndex; deviceInfo->hostApi = hostApiIndex;
/* Get the device name using CFString */ /* Get the device name using CFString */
propSize = sizeof(nameRef); propSize = sizeof(nameRef);
err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceNameCFString, &propSize, &nameRef)); err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceNameCFString, &propSize, &nameRef));
@ -724,12 +724,12 @@ PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIn
int unixErr; int unixErr;
VVDBUG(("PaMacCore_Initialize(): hostApiIndex=%d\n", hostApiIndex)); VVDBUG(("PaMacCore_Initialize(): hostApiIndex=%d\n", hostApiIndex));
SInt32 major; SInt32 major;
SInt32 minor; SInt32 minor;
Gestalt(gestaltSystemVersionMajor, &major); Gestalt(gestaltSystemVersionMajor, &major);
Gestalt(gestaltSystemVersionMinor, &minor); Gestalt(gestaltSystemVersionMinor, &minor);
// Starting with 10.6 systems, the HAL notification thread is created internally // Starting with 10.6 systems, the HAL notification thread is created internally
if (major == 10 && minor >= 6) { if (major == 10 && minor >= 6) {
CFRunLoopRef theRunLoop = NULL; CFRunLoopRef theRunLoop = NULL;
@ -739,7 +739,7 @@ PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIn
goto error; goto error;
} }
} }
unixErr = initializeXRunListenerList(); unixErr = initializeXRunListenerList();
if( 0 != unixErr ) { if( 0 != unixErr ) {
return UNIX_ERR(unixErr); return UNIX_ERR(unixErr);
@ -775,7 +775,7 @@ PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIn
(*hostApi)->info.defaultInputDevice = paNoDevice; (*hostApi)->info.defaultInputDevice = paNoDevice;
(*hostApi)->info.defaultOutputDevice = paNoDevice; (*hostApi)->info.defaultOutputDevice = paNoDevice;
(*hostApi)->info.deviceCount = 0; (*hostApi)->info.deviceCount = 0;
if( auhalHostApi->devCount > 0 ) if( auhalHostApi->devCount > 0 )
{ {
@ -854,7 +854,7 @@ error:
PaUtil_FreeAllAllocations( auhalHostApi->allocations ); PaUtil_FreeAllAllocations( auhalHostApi->allocations );
PaUtil_DestroyAllocationGroup( auhalHostApi->allocations ); PaUtil_DestroyAllocationGroup( auhalHostApi->allocations );
} }
PaUtil_FreeMemory( auhalHostApi ); PaUtil_FreeMemory( auhalHostApi );
} }
return result; return result;
@ -903,7 +903,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
outputParameters ? outputParameters->channelCount : -1, outputParameters ? outputParameters->channelCount : -1,
outputParameters ? outputParameters->sampleFormat : -1, outputParameters ? outputParameters->sampleFormat : -1,
(float) sampleRate )); (float) sampleRate ));
/** These first checks are standard PA checks. We do some fancier checks /** These first checks are standard PA checks. We do some fancier checks
later. */ later. */
if( inputParameters ) if( inputParameters )
@ -915,7 +915,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
this implementation doesn't support any custom sample formats */ this implementation doesn't support any custom sample formats */
if( inputSampleFormat & paCustomFormat ) if( inputSampleFormat & paCustomFormat )
return paSampleFormatNotSupported; return paSampleFormatNotSupported;
/* unless alternate device specification is supported, reject the use of /* unless alternate device specification is supported, reject the use of
paUseHostApiSpecificDeviceSpecification */ paUseHostApiSpecificDeviceSpecification */
@ -940,7 +940,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
this implementation doesn't support any custom sample formats */ this implementation doesn't support any custom sample formats */
if( outputSampleFormat & paCustomFormat ) if( outputSampleFormat & paCustomFormat )
return paSampleFormatNotSupported; return paSampleFormatNotSupported;
/* unless alternate device specification is supported, reject the use of /* unless alternate device specification is supported, reject the use of
paUseHostApiSpecificDeviceSpecification */ paUseHostApiSpecificDeviceSpecification */
@ -956,7 +956,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
{ {
outputChannelCount = 0; outputChannelCount = 0;
} }
/* FEEDBACK */ /* FEEDBACK */
/* I think the only way to check a given format SR combo is */ /* I think the only way to check a given format SR combo is */
/* to try opening it. This could be disruptive, is that Okay? */ /* to try opening it. This could be disruptive, is that Okay? */
@ -974,7 +974,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
if( err != paNoError && err != paInvalidSampleRate ) if( err != paNoError && err != paInvalidSampleRate )
DBUG( ( "OpenStream @ %g returned: %d: %s\n", DBUG( ( "OpenStream @ %g returned: %d: %s\n",
(float) sampleRate, err, Pa_GetErrorText( err ) ) ); (float) sampleRate, err, Pa_GetErrorText( err ) ) );
if( err ) if( err )
return err; return err;
err = CloseStream( s ); err = CloseStream( s );
if( err ) { if( err ) {
@ -1016,18 +1016,18 @@ static void UpdateTimeStampOffsets( PaMacCoreStream *stream )
Float64 inputHardwareLatency = 0.0; Float64 inputHardwareLatency = 0.0;
Float64 outputSoftwareLatency = 0.0; Float64 outputSoftwareLatency = 0.0;
Float64 outputHardwareLatency = 0.0; Float64 outputHardwareLatency = 0.0;
if( stream->inputUnit != NULL ) if( stream->inputUnit != NULL )
{ {
inputSoftwareLatency = CalculateSoftwareLatencyFromProperties( stream, &stream->inputProperties ); inputSoftwareLatency = CalculateSoftwareLatencyFromProperties( stream, &stream->inputProperties );
inputHardwareLatency = CalculateHardwareLatencyFromProperties( stream, &stream->inputProperties ); inputHardwareLatency = CalculateHardwareLatencyFromProperties( stream, &stream->inputProperties );
} }
if( stream->outputUnit != NULL ) if( stream->outputUnit != NULL )
{ {
outputSoftwareLatency = CalculateSoftwareLatencyFromProperties( stream, &stream->outputProperties ); outputSoftwareLatency = CalculateSoftwareLatencyFromProperties( stream, &stream->outputProperties );
outputHardwareLatency = CalculateHardwareLatencyFromProperties( stream, &stream->outputProperties ); outputHardwareLatency = CalculateHardwareLatencyFromProperties( stream, &stream->outputProperties );
} }
/* We only need a mutex around setting these variables as a group. */ /* We only need a mutex around setting these variables as a group. */
pthread_mutex_lock( &stream->timingInformationMutex ); pthread_mutex_lock( &stream->timingInformationMutex );
stream->timestampOffsetCombined = inputSoftwareLatency + outputSoftwareLatency; stream->timestampOffsetCombined = inputSoftwareLatency + outputSoftwareLatency;
@ -1042,7 +1042,7 @@ static void UpdateTimeStampOffsets( PaMacCoreStream *stream )
static OSStatus UpdateSampleRateFromDeviceProperty( PaMacCoreStream *stream, AudioDeviceID deviceID, Boolean isInput, AudioDevicePropertyID sampleRatePropertyID ) static OSStatus UpdateSampleRateFromDeviceProperty( PaMacCoreStream *stream, AudioDeviceID deviceID, Boolean isInput, AudioDevicePropertyID sampleRatePropertyID )
{ {
PaMacCoreDeviceProperties * deviceProperties = isInput ? &stream->inputProperties : &stream->outputProperties; PaMacCoreDeviceProperties * deviceProperties = isInput ? &stream->inputProperties : &stream->outputProperties;
Float64 sampleRate = 0.0; Float64 sampleRate = 0.0;
UInt32 propSize = sizeof(Float64); UInt32 propSize = sizeof(Float64);
OSStatus osErr = AudioDeviceGetProperty( deviceID, 0, isInput, sampleRatePropertyID, &propSize, &sampleRate); OSStatus osErr = AudioDeviceGetProperty( deviceID, 0, isInput, sampleRatePropertyID, &propSize, &sampleRate);
@ -1057,7 +1057,7 @@ static OSStatus UpdateSampleRateFromDeviceProperty( PaMacCoreStream *stream, Aud
static OSStatus AudioDevicePropertyActualSampleRateListenerProc( AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, void *inClientData ) static OSStatus AudioDevicePropertyActualSampleRateListenerProc( AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, void *inClientData )
{ {
PaMacCoreStream *stream = (PaMacCoreStream*)inClientData; PaMacCoreStream *stream = (PaMacCoreStream*)inClientData;
// Make sure the callback is operating on a stream that is still valid! // Make sure the callback is operating on a stream that is still valid!
assert( stream->streamRepresentation.magic == PA_STREAM_MAGIC ); assert( stream->streamRepresentation.magic == PA_STREAM_MAGIC );
@ -1086,10 +1086,10 @@ static OSStatus AudioDevicePropertyGenericListenerProc( AudioDeviceID inDevice,
{ {
OSStatus osErr = noErr; OSStatus osErr = noErr;
PaMacCoreStream *stream = (PaMacCoreStream*)inClientData; PaMacCoreStream *stream = (PaMacCoreStream*)inClientData;
// Make sure the callback is operating on a stream that is still valid! // Make sure the callback is operating on a stream that is still valid!
assert( stream->streamRepresentation.magic == PA_STREAM_MAGIC ); assert( stream->streamRepresentation.magic == PA_STREAM_MAGIC );
PaMacCoreDeviceProperties *deviceProperties = isInput ? &stream->inputProperties : &stream->outputProperties; PaMacCoreDeviceProperties *deviceProperties = isInput ? &stream->inputProperties : &stream->outputProperties;
UInt32 *valuePtr = NULL; UInt32 *valuePtr = NULL;
switch( inPropertyID ) switch( inPropertyID )
@ -1097,14 +1097,14 @@ static OSStatus AudioDevicePropertyGenericListenerProc( AudioDeviceID inDevice,
case kAudioDevicePropertySafetyOffset: case kAudioDevicePropertySafetyOffset:
valuePtr = &deviceProperties->safetyOffset; valuePtr = &deviceProperties->safetyOffset;
break; break;
case kAudioDevicePropertyLatency: case kAudioDevicePropertyLatency:
valuePtr = &deviceProperties->deviceLatency; valuePtr = &deviceProperties->deviceLatency;
break; break;
case kAudioDevicePropertyBufferFrameSize: case kAudioDevicePropertyBufferFrameSize:
valuePtr = &deviceProperties->bufferFrameSize; valuePtr = &deviceProperties->bufferFrameSize;
break; break;
} }
if( valuePtr != NULL ) if( valuePtr != NULL )
{ {
@ -1124,37 +1124,37 @@ static OSStatus SetupDevicePropertyListeners( PaMacCoreStream *stream, AudioDevi
{ {
OSStatus osErr = noErr; OSStatus osErr = noErr;
PaMacCoreDeviceProperties *deviceProperties = isInput ? &stream->inputProperties : &stream->outputProperties; PaMacCoreDeviceProperties *deviceProperties = isInput ? &stream->inputProperties : &stream->outputProperties;
if( (osErr = QueryUInt32DeviceProperty( deviceID, isInput, if( (osErr = QueryUInt32DeviceProperty( deviceID, isInput,
kAudioDevicePropertyLatency, &deviceProperties->deviceLatency )) != noErr ) return osErr; kAudioDevicePropertyLatency, &deviceProperties->deviceLatency )) != noErr ) return osErr;
if( (osErr = QueryUInt32DeviceProperty( deviceID, isInput, if( (osErr = QueryUInt32DeviceProperty( deviceID, isInput,
kAudioDevicePropertyBufferFrameSize, &deviceProperties->bufferFrameSize )) != noErr ) return osErr; kAudioDevicePropertyBufferFrameSize, &deviceProperties->bufferFrameSize )) != noErr ) return osErr;
if( (osErr = QueryUInt32DeviceProperty( deviceID, isInput, if( (osErr = QueryUInt32DeviceProperty( deviceID, isInput,
kAudioDevicePropertySafetyOffset, &deviceProperties->safetyOffset )) != noErr ) return osErr; kAudioDevicePropertySafetyOffset, &deviceProperties->safetyOffset )) != noErr ) return osErr;
AudioDeviceAddPropertyListener( deviceID, 0, isInput, kAudioDevicePropertyActualSampleRate, AudioDeviceAddPropertyListener( deviceID, 0, isInput, kAudioDevicePropertyActualSampleRate,
AudioDevicePropertyActualSampleRateListenerProc, stream ); AudioDevicePropertyActualSampleRateListenerProc, stream );
AudioDeviceAddPropertyListener( deviceID, 0, isInput, kAudioStreamPropertyLatency, AudioDeviceAddPropertyListener( deviceID, 0, isInput, kAudioStreamPropertyLatency,
AudioDevicePropertyGenericListenerProc, stream ); AudioDevicePropertyGenericListenerProc, stream );
AudioDeviceAddPropertyListener( deviceID, 0, isInput, kAudioDevicePropertyBufferFrameSize, AudioDeviceAddPropertyListener( deviceID, 0, isInput, kAudioDevicePropertyBufferFrameSize,
AudioDevicePropertyGenericListenerProc, stream ); AudioDevicePropertyGenericListenerProc, stream );
AudioDeviceAddPropertyListener( deviceID, 0, isInput, kAudioDevicePropertySafetyOffset, AudioDeviceAddPropertyListener( deviceID, 0, isInput, kAudioDevicePropertySafetyOffset,
AudioDevicePropertyGenericListenerProc, stream ); AudioDevicePropertyGenericListenerProc, stream );
return osErr; return osErr;
} }
static void CleanupDevicePropertyListeners( PaMacCoreStream *stream, AudioDeviceID deviceID, Boolean isInput ) static void CleanupDevicePropertyListeners( PaMacCoreStream *stream, AudioDeviceID deviceID, Boolean isInput )
{ {
AudioDeviceRemovePropertyListener( deviceID, 0, isInput, kAudioDevicePropertyActualSampleRate, AudioDeviceRemovePropertyListener( deviceID, 0, isInput, kAudioDevicePropertyActualSampleRate,
AudioDevicePropertyActualSampleRateListenerProc ); AudioDevicePropertyActualSampleRateListenerProc );
AudioDeviceRemovePropertyListener( deviceID, 0, isInput, kAudioDevicePropertyLatency, AudioDeviceRemovePropertyListener( deviceID, 0, isInput, kAudioDevicePropertyLatency,
AudioDevicePropertyGenericListenerProc );
AudioDeviceRemovePropertyListener( deviceID, 0, isInput, kAudioDevicePropertyBufferFrameSize,
AudioDevicePropertyGenericListenerProc ); AudioDevicePropertyGenericListenerProc );
AudioDeviceRemovePropertyListener( deviceID, 0, isInput, kAudioDevicePropertySafetyOffset, AudioDeviceRemovePropertyListener( deviceID, 0, isInput, kAudioDevicePropertyBufferFrameSize,
AudioDevicePropertyGenericListenerProc );
AudioDeviceRemovePropertyListener( deviceID, 0, isInput, kAudioDevicePropertySafetyOffset,
AudioDevicePropertyGenericListenerProc ); AudioDevicePropertyGenericListenerProc );
} }
@ -1173,8 +1173,8 @@ static PaError OpenAndSetupOneAudioUnit(
const double sampleRate, const double sampleRate,
void *refCon ) void *refCon )
{ {
ComponentDescription desc; AudioComponentDescription desc;
Component comp; AudioComponent comp;
/*An Apple TN suggests using CAStreamBasicDescription, but that is C++*/ /*An Apple TN suggests using CAStreamBasicDescription, but that is C++*/
AudioStreamBasicDescription desiredFormat; AudioStreamBasicDescription desiredFormat;
OSStatus result = noErr; OSStatus result = noErr;
@ -1222,7 +1222,7 @@ static PaError OpenAndSetupOneAudioUnit(
outChannelMap = ((PaMacCoreStreamInfo*)outStreamParams->hostApiSpecificStreamInfo) outChannelMap = ((PaMacCoreStreamInfo*)outStreamParams->hostApiSpecificStreamInfo)
->channelMap; ->channelMap;
outChannelMapSize = ((PaMacCoreStreamInfo*)outStreamParams->hostApiSpecificStreamInfo) outChannelMapSize = ((PaMacCoreStreamInfo*)outStreamParams->hostApiSpecificStreamInfo)
->channelMapSize; ->channelMapSize;
} }
/* Override user's flags here, if desired for testing. */ /* Override user's flags here, if desired for testing. */
@ -1245,7 +1245,7 @@ static PaError OpenAndSetupOneAudioUnit(
desc.componentFlags = 0; desc.componentFlags = 0;
desc.componentFlagsMask = 0; desc.componentFlagsMask = 0;
/* -- find the component -- */ /* -- find the component -- */
comp = FindNextComponent( NULL, &desc ); comp = AudioComponentFindNext( NULL, &desc );
if( !comp ) if( !comp )
{ {
DBUG( ( "AUHAL component not found." ) ); DBUG( ( "AUHAL component not found." ) );
@ -1254,7 +1254,7 @@ static PaError OpenAndSetupOneAudioUnit(
return paUnanticipatedHostError; return paUnanticipatedHostError;
} }
/* -- open it -- */ /* -- open it -- */
result = OpenAComponent( comp, audioUnit ); result = AudioComponentInstanceNew( comp, audioUnit );
if( result ) if( result )
{ {
DBUG( ( "Failed to open AUHAL component." ) ); DBUG( ( "Failed to open AUHAL component." ) );
@ -1527,7 +1527,7 @@ static PaError OpenAndSetupOneAudioUnit(
(float)sourceFormat.mSampleRate, (float)sourceFormat.mSampleRate,
(float)desiredFormat.mSampleRate ) ); (float)desiredFormat.mSampleRate ) );
/* create our converter */ /* create our converter */
ERR_WRAP( AudioConverterNew( ERR_WRAP( AudioConverterNew(
&sourceFormat, &sourceFormat,
&desiredFormat, &desiredFormat,
srConverter ) ); srConverter ) );
@ -1607,7 +1607,7 @@ static PaError OpenAndSetupOneAudioUnit(
#undef ERR_WRAP #undef ERR_WRAP
error: error:
CloseComponent( *audioUnit ); AudioComponentInstanceDispose( *audioUnit );
*audioUnit = NULL; *audioUnit = NULL;
if( result ) if( result )
return PaMacCore_SetError( result, line, 1 ); return PaMacCore_SetError( result, line, 1 );
@ -1624,7 +1624,7 @@ static UInt32 CalculateOptimalBufferSize( PaMacAUHAL *auhalHostApi,
double sampleRate, double sampleRate,
UInt32 requestedFramesPerBuffer ) UInt32 requestedFramesPerBuffer )
{ {
UInt32 resultBufferSizeFrames = 0; UInt32 resultBufferSizeFrames = 0;
// Use maximum of suggested input and output latencies. // Use maximum of suggested input and output latencies.
if( inputParameters ) if( inputParameters )
{ {
@ -1632,35 +1632,35 @@ static UInt32 CalculateOptimalBufferSize( PaMacAUHAL *auhalHostApi,
// Calculate a buffer size assuming we are double buffered. // Calculate a buffer size assuming we are double buffered.
SInt32 variableLatencyFrames = suggestedLatencyFrames - fixedInputLatency; SInt32 variableLatencyFrames = suggestedLatencyFrames - fixedInputLatency;
// Prevent negative latency. // Prevent negative latency.
variableLatencyFrames = MAX( variableLatencyFrames, 0 ); variableLatencyFrames = MAX( variableLatencyFrames, 0 );
resultBufferSizeFrames = MAX( resultBufferSizeFrames, (UInt32) variableLatencyFrames ); resultBufferSizeFrames = MAX( resultBufferSizeFrames, (UInt32) variableLatencyFrames );
} }
if( outputParameters ) if( outputParameters )
{ {
UInt32 suggestedLatencyFrames = outputParameters->suggestedLatency * sampleRate; UInt32 suggestedLatencyFrames = outputParameters->suggestedLatency * sampleRate;
SInt32 variableLatencyFrames = suggestedLatencyFrames - fixedOutputLatency; SInt32 variableLatencyFrames = suggestedLatencyFrames - fixedOutputLatency;
variableLatencyFrames = MAX( variableLatencyFrames, 0 ); variableLatencyFrames = MAX( variableLatencyFrames, 0 );
resultBufferSizeFrames = MAX( resultBufferSizeFrames, (UInt32) variableLatencyFrames ); resultBufferSizeFrames = MAX( resultBufferSizeFrames, (UInt32) variableLatencyFrames );
} }
// can't have zero frames. code to round up to next user buffer requires non-zero // can't have zero frames. code to round up to next user buffer requires non-zero
resultBufferSizeFrames = MAX( resultBufferSizeFrames, 1 ); resultBufferSizeFrames = MAX( resultBufferSizeFrames, 1 );
if( requestedFramesPerBuffer != paFramesPerBufferUnspecified ) if( requestedFramesPerBuffer != paFramesPerBufferUnspecified )
{ {
// make host buffer the next highest integer multiple of user frames per buffer // make host buffer the next highest integer multiple of user frames per buffer
UInt32 n = (resultBufferSizeFrames + requestedFramesPerBuffer - 1) / requestedFramesPerBuffer; UInt32 n = (resultBufferSizeFrames + requestedFramesPerBuffer - 1) / requestedFramesPerBuffer;
resultBufferSizeFrames = n * requestedFramesPerBuffer; resultBufferSizeFrames = n * requestedFramesPerBuffer;
// FIXME: really we should be searching for a multiple of requestedFramesPerBuffer // FIXME: really we should be searching for a multiple of requestedFramesPerBuffer
// that is >= suggested latency and also fits within device buffer min/max // that is >= suggested latency and also fits within device buffer min/max
}else{ }else{
VDBUG( ("Block Size unspecified. Based on Latency, the user wants a Block Size near: %ld.\n", VDBUG( ("Block Size unspecified. Based on Latency, the user wants a Block Size near: %ld.\n",
resultBufferSizeFrames ) ); resultBufferSizeFrames ) );
} }
// Clip to the capabilities of the device. // Clip to the capabilities of the device.
if( inputParameters ) if( inputParameters )
{ {
@ -1702,7 +1702,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
UInt32 inputLatencyFrames = 0; UInt32 inputLatencyFrames = 0;
UInt32 outputLatencyFrames = 0; UInt32 outputLatencyFrames = 0;
UInt32 suggestedLatencyFramesPerBuffer = requestedFramesPerBuffer; UInt32 suggestedLatencyFramesPerBuffer = requestedFramesPerBuffer;
VVDBUG(("OpenStream(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld SR=%g, FPB=%ld\n", VVDBUG(("OpenStream(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld SR=%g, FPB=%ld\n",
inputParameters ? inputParameters->channelCount : -1, inputParameters ? inputParameters->channelCount : -1,
inputParameters ? inputParameters->sampleFormat : -1, inputParameters ? inputParameters->sampleFormat : -1,
@ -1711,7 +1711,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
(float) sampleRate, (float) sampleRate,
requestedFramesPerBuffer )); requestedFramesPerBuffer ));
VDBUG( ("Opening Stream.\n") ); VDBUG( ("Opening Stream.\n") );
/* These first few bits of code are from paSkeleton with few modifications. */ /* These first few bits of code are from paSkeleton with few modifications. */
if( inputParameters ) if( inputParameters )
{ {
@ -1723,7 +1723,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
{ {
return paSampleFormatNotSupported; return paSampleFormatNotSupported;
} }
/* unless alternate device specification is supported, reject the use of /* unless alternate device specification is supported, reject the use of
paUseHostApiSpecificDeviceSpecification */ paUseHostApiSpecificDeviceSpecification */
@ -1747,13 +1747,13 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
{ {
outputChannelCount = outputParameters->channelCount; outputChannelCount = outputParameters->channelCount;
outputSampleFormat = outputParameters->sampleFormat; outputSampleFormat = outputParameters->sampleFormat;
/* @todo Blocking read/write on Mac is not yet supported. */ /* @todo Blocking read/write on Mac is not yet supported. */
if( !streamCallback && outputSampleFormat & paNonInterleaved ) if( !streamCallback && outputSampleFormat & paNonInterleaved )
{ {
return paSampleFormatNotSupported; return paSampleFormatNotSupported;
} }
/* unless alternate device specification is supported, reject the use of /* unless alternate device specification is supported, reject the use of
paUseHostApiSpecificDeviceSpecification */ paUseHostApiSpecificDeviceSpecification */
@ -1790,7 +1790,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
been touched. been touched.
*/ */
bzero( stream, sizeof( PaMacCoreStream ) ); bzero( stream, sizeof( PaMacCoreStream ) );
/* /*
stream->blio.inputRingBuffer.buffer = NULL; stream->blio.inputRingBuffer.buffer = NULL;
stream->blio.outputRingBuffer.buffer = NULL; stream->blio.outputRingBuffer.buffer = NULL;
@ -1816,19 +1816,19 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
if( inputParameters ) if( inputParameters )
{ {
CalculateFixedDeviceLatency( auhalHostApi->devIds[inputParameters->device], true, &fixedInputLatency ); CalculateFixedDeviceLatency( auhalHostApi->devIds[inputParameters->device], true, &fixedInputLatency );
inputLatencyFrames += fixedInputLatency; inputLatencyFrames += fixedInputLatency;
} }
if( outputParameters ) if( outputParameters )
{ {
CalculateFixedDeviceLatency( auhalHostApi->devIds[outputParameters->device], false, &fixedOutputLatency ); CalculateFixedDeviceLatency( auhalHostApi->devIds[outputParameters->device], false, &fixedOutputLatency );
outputLatencyFrames += fixedOutputLatency; outputLatencyFrames += fixedOutputLatency;
} }
suggestedLatencyFramesPerBuffer = CalculateOptimalBufferSize( auhalHostApi, inputParameters, outputParameters, suggestedLatencyFramesPerBuffer = CalculateOptimalBufferSize( auhalHostApi, inputParameters, outputParameters,
fixedInputLatency, fixedOutputLatency, fixedInputLatency, fixedOutputLatency,
sampleRate, requestedFramesPerBuffer ); sampleRate, requestedFramesPerBuffer );
@ -1896,10 +1896,10 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
stream->inputFramesPerBuffer = inputFramesPerBuffer; stream->inputFramesPerBuffer = inputFramesPerBuffer;
stream->outputFramesPerBuffer = outputFramesPerBuffer; stream->outputFramesPerBuffer = outputFramesPerBuffer;
} }
inputLatencyFrames += stream->inputFramesPerBuffer; inputLatencyFrames += stream->inputFramesPerBuffer;
outputLatencyFrames += stream->outputFramesPerBuffer; outputLatencyFrames += stream->outputFramesPerBuffer;
if( stream->inputUnit ) { if( stream->inputUnit ) {
const size_t szfl = sizeof(float); const size_t szfl = sizeof(float);
/* setup the AudioBufferList used for input */ /* setup the AudioBufferList used for input */
@ -1918,7 +1918,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
result = paInsufficientMemory; result = paInsufficientMemory;
goto error; goto error;
} }
/* /*
* If input and output devs are different or we are doing SR conversion, * If input and output devs are different or we are doing SR conversion,
* we also need a ring buffer to store input data while waiting for * we also need a ring buffer to store input data while waiting for
@ -1963,7 +1963,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
middle of the buffer */ middle of the buffer */
if( stream->outputUnit ) if( stream->outputUnit )
PaUtil_AdvanceRingBufferWriteIndex( &stream->inputRingBuffer, ringSize / RING_BUFFER_ADVANCE_DENOMINATOR ); PaUtil_AdvanceRingBufferWriteIndex( &stream->inputRingBuffer, ringSize / RING_BUFFER_ADVANCE_DENOMINATOR );
// Just adds to input latency between input device and PA full duplex callback. // Just adds to input latency between input device and PA full duplex callback.
inputLatencyFrames += ringSize; inputLatencyFrames += ringSize;
} }
@ -1987,10 +1987,10 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
outputParameters ? outputChannelCount : 0 ) ; outputParameters ? outputChannelCount : 0 ) ;
if( result != paNoError ) if( result != paNoError )
goto error; goto error;
inputLatencyFrames += ringSize; inputLatencyFrames += ringSize;
outputLatencyFrames += ringSize; outputLatencyFrames += ringSize;
} }
/* -- initialize Buffer Processor -- */ /* -- initialize Buffer Processor -- */
@ -2020,7 +2020,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
stream->bufferProcessorIsInitialized = TRUE; stream->bufferProcessorIsInitialized = TRUE;
// Calculate actual latency from the sum of individual latencies. // Calculate actual latency from the sum of individual latencies.
if( inputParameters ) if( inputParameters )
{ {
inputLatencyFrames += PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor); inputLatencyFrames += PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor);
stream->streamRepresentation.streamInfo.inputLatency = inputLatencyFrames / sampleRate; stream->streamRepresentation.streamInfo.inputLatency = inputLatencyFrames / sampleRate;
@ -2029,8 +2029,8 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
{ {
stream->streamRepresentation.streamInfo.inputLatency = 0.0; stream->streamRepresentation.streamInfo.inputLatency = 0.0;
} }
if( outputParameters ) if( outputParameters )
{ {
outputLatencyFrames += PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor); outputLatencyFrames += PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor);
stream->streamRepresentation.streamInfo.outputLatency = outputLatencyFrames / sampleRate; stream->streamRepresentation.streamInfo.outputLatency = outputLatencyFrames / sampleRate;
@ -2039,11 +2039,11 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
{ {
stream->streamRepresentation.streamInfo.outputLatency = 0.0; stream->streamRepresentation.streamInfo.outputLatency = 0.0;
} }
stream->streamRepresentation.streamInfo.sampleRate = sampleRate; stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
stream->sampleRate = sampleRate; stream->sampleRate = sampleRate;
stream->userInChan = inputChannelCount; stream->userInChan = inputChannelCount;
stream->userOutChan = outputChannelCount; stream->userOutChan = outputChannelCount;
@ -2055,31 +2055,31 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
if( stream->outputUnit ) if( stream->outputUnit )
{ {
Boolean isInput = FALSE; Boolean isInput = FALSE;
// Start with the current values for the device properties. // Start with the current values for the device properties.
// Init with nominal sample rate. Use actual sample rate where available // Init with nominal sample rate. Use actual sample rate where available
result = ERR( UpdateSampleRateFromDeviceProperty( result = ERR( UpdateSampleRateFromDeviceProperty(
stream, stream->outputDevice, isInput, kAudioDevicePropertyNominalSampleRate ) ); stream, stream->outputDevice, isInput, kAudioDevicePropertyNominalSampleRate ) );
if( result ) if( result )
goto error; /* fail if we can't even get a nominal device sample rate */ goto error; /* fail if we can't even get a nominal device sample rate */
UpdateSampleRateFromDeviceProperty( stream, stream->outputDevice, isInput, kAudioDevicePropertyActualSampleRate ); UpdateSampleRateFromDeviceProperty( stream, stream->outputDevice, isInput, kAudioDevicePropertyActualSampleRate );
SetupDevicePropertyListeners( stream, stream->outputDevice, isInput ); SetupDevicePropertyListeners( stream, stream->outputDevice, isInput );
} }
if( stream->inputUnit ) if( stream->inputUnit )
{ {
Boolean isInput = TRUE; Boolean isInput = TRUE;
// as above // as above
result = ERR( UpdateSampleRateFromDeviceProperty( result = ERR( UpdateSampleRateFromDeviceProperty(
stream, stream->inputDevice, isInput, kAudioDevicePropertyNominalSampleRate ) ); stream, stream->inputDevice, isInput, kAudioDevicePropertyNominalSampleRate ) );
if( result ) if( result )
goto error; goto error;
UpdateSampleRateFromDeviceProperty( stream, stream->inputDevice, isInput, kAudioDevicePropertyActualSampleRate ); UpdateSampleRateFromDeviceProperty( stream, stream->inputDevice, isInput, kAudioDevicePropertyActualSampleRate );
SetupDevicePropertyListeners( stream, stream->inputDevice, isInput ); SetupDevicePropertyListeners( stream, stream->inputDevice, isInput );
} }
UpdateTimeStampOffsets( stream ); UpdateTimeStampOffsets( stream );
@ -2105,14 +2105,14 @@ error:
PaTime GetStreamTime( PaStream *s ) PaTime GetStreamTime( PaStream *s )
{ {
return HOST_TIME_TO_PA_TIME( AudioGetCurrentHostTime() ); return HOST_TIME_TO_PA_TIME( AudioGetCurrentHostTime() );
} }
#define RING_BUFFER_EMPTY (1000) #define RING_BUFFER_EMPTY (1000)
static OSStatus ringBufferIOProc( AudioConverterRef inAudioConverter, static OSStatus ringBufferIOProc( AudioConverterRef inAudioConverter,
UInt32*ioDataSize, UInt32*ioDataSize,
void** outData, void** outData,
void*inUserData ) void*inUserData )
{ {
void *dummyData; void *dummyData;
@ -2130,7 +2130,7 @@ static OSStatus ringBufferIOProc( AudioConverterRef inAudioConverter,
assert( ( (*ioDataSize) / rb->elementSizeBytes ) * rb->elementSizeBytes == (*ioDataSize) ) ; assert( ( (*ioDataSize) / rb->elementSizeBytes ) * rb->elementSizeBytes == (*ioDataSize) ) ;
(*ioDataSize) /= rb->elementSizeBytes ; (*ioDataSize) /= rb->elementSizeBytes ;
PaUtil_GetRingBufferReadRegions( rb, *ioDataSize, PaUtil_GetRingBufferReadRegions( rb, *ioDataSize,
outData, (ring_buffer_size_t *)ioDataSize, outData, (ring_buffer_size_t *)ioDataSize,
&dummyData, &dummySize ); &dummyData, &dummySize );
assert( *ioDataSize ); assert( *ioDataSize );
PaUtil_AdvanceRingBufferReadIndex( rb, *ioDataSize ); PaUtil_AdvanceRingBufferReadIndex( rb, *ioDataSize );
@ -2157,11 +2157,11 @@ static OSStatus AudioIOProc( void *inRefCon,
const bool isRender = inBusNumber == OUTPUT_ELEMENT; const bool isRender = inBusNumber == OUTPUT_ELEMENT;
int callbackResult = paContinue ; int callbackResult = paContinue ;
double hostTimeStampInPaTime = HOST_TIME_TO_PA_TIME(inTimeStamp->mHostTime); double hostTimeStampInPaTime = HOST_TIME_TO_PA_TIME(inTimeStamp->mHostTime);
VVDBUG(("AudioIOProc()\n")); VVDBUG(("AudioIOProc()\n"));
PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
/* -----------------------------------------------------------------*\ /* -----------------------------------------------------------------*\
This output may be useful for debugging, This output may be useful for debugging,
But printing durring the callback is a bad enough idea that But printing durring the callback is a bad enough idea that
@ -2190,7 +2190,7 @@ static OSStatus AudioIOProc( void *inRefCon,
----------------------------------------------------------------- */ ----------------------------------------------------------------- */
/* compute PaStreamCallbackTimeInfo */ /* compute PaStreamCallbackTimeInfo */
if( pthread_mutex_trylock( &stream->timingInformationMutex ) == 0 ){ if( pthread_mutex_trylock( &stream->timingInformationMutex ) == 0 ){
/* snapshot the ioproc copy of timing information */ /* snapshot the ioproc copy of timing information */
stream->timestampOffsetCombined_ioProcCopy = stream->timestampOffsetCombined; stream->timestampOffsetCombined_ioProcCopy = stream->timestampOffsetCombined;
@ -2198,24 +2198,24 @@ static OSStatus AudioIOProc( void *inRefCon,
stream->timestampOffsetOutputDevice_ioProcCopy = stream->timestampOffsetOutputDevice; stream->timestampOffsetOutputDevice_ioProcCopy = stream->timestampOffsetOutputDevice;
pthread_mutex_unlock( &stream->timingInformationMutex ); pthread_mutex_unlock( &stream->timingInformationMutex );
} }
/* For timeInfo.currentTime we could calculate current time backwards from the HAL audio /* For timeInfo.currentTime we could calculate current time backwards from the HAL audio
output time to give a more accurate impression of the current timeslice but it doesn't output time to give a more accurate impression of the current timeslice but it doesn't
seem worth it at the moment since other PA host APIs don't do any better. seem worth it at the moment since other PA host APIs don't do any better.
*/ */
timeInfo.currentTime = HOST_TIME_TO_PA_TIME( AudioGetCurrentHostTime() ); timeInfo.currentTime = HOST_TIME_TO_PA_TIME( AudioGetCurrentHostTime() );
/* /*
For an input HAL AU, inTimeStamp is the time the samples are received from the hardware, For an input HAL AU, inTimeStamp is the time the samples are received from the hardware,
for an output HAL AU inTimeStamp is the time the samples are sent to the hardware. for an output HAL AU inTimeStamp is the time the samples are sent to the hardware.
PA expresses timestamps in terms of when the samples enter the ADC or leave the DAC PA expresses timestamps in terms of when the samples enter the ADC or leave the DAC
so we add or subtract kAudioDevicePropertyLatency below. so we add or subtract kAudioDevicePropertyLatency below.
*/ */
/* FIXME: not sure what to do below if the host timestamps aren't valid (kAudioTimeStampHostTimeValid isn't set) /* FIXME: not sure what to do below if the host timestamps aren't valid (kAudioTimeStampHostTimeValid isn't set)
Could ask on CA mailing list if it is possible for it not to be set. If so, could probably grab a now timestamp Could ask on CA mailing list if it is possible for it not to be set. If so, could probably grab a now timestamp
at the top and compute from there (modulo scheduling jitter) or ask on mailing list for other options. */ at the top and compute from there (modulo scheduling jitter) or ask on mailing list for other options. */
if( isRender ) if( isRender )
{ {
if( stream->inputUnit ) /* full duplex */ if( stream->inputUnit ) /* full duplex */
@ -2225,14 +2225,14 @@ static OSStatus AudioIOProc( void *inRefCon,
// Ross and Phil agreed that the following calculation is correct based on an email from Jeff Moore: // Ross and Phil agreed that the following calculation is correct based on an email from Jeff Moore:
// http://osdir.com/ml/coreaudio-api/2009-07/msg00140.html // http://osdir.com/ml/coreaudio-api/2009-07/msg00140.html
// Basically the difference between the Apple output timestamp and the PA timestamp is kAudioDevicePropertyLatency. // Basically the difference between the Apple output timestamp and the PA timestamp is kAudioDevicePropertyLatency.
timeInfo.inputBufferAdcTime = hostTimeStampInPaTime - timeInfo.inputBufferAdcTime = hostTimeStampInPaTime -
(stream->timestampOffsetCombined_ioProcCopy + stream->timestampOffsetInputDevice_ioProcCopy); (stream->timestampOffsetCombined_ioProcCopy + stream->timestampOffsetInputDevice_ioProcCopy);
timeInfo.outputBufferDacTime = hostTimeStampInPaTime + stream->timestampOffsetOutputDevice_ioProcCopy; timeInfo.outputBufferDacTime = hostTimeStampInPaTime + stream->timestampOffsetOutputDevice_ioProcCopy;
} }
else /* full duplex with ring-buffer from a separate input AUHAL ioproc */ else /* full duplex with ring-buffer from a separate input AUHAL ioproc */
{ {
/* FIXME: take the ring buffer latency into account */ /* FIXME: take the ring buffer latency into account */
timeInfo.inputBufferAdcTime = hostTimeStampInPaTime - timeInfo.inputBufferAdcTime = hostTimeStampInPaTime -
(stream->timestampOffsetCombined_ioProcCopy + stream->timestampOffsetInputDevice_ioProcCopy); (stream->timestampOffsetCombined_ioProcCopy + stream->timestampOffsetInputDevice_ioProcCopy);
timeInfo.outputBufferDacTime = hostTimeStampInPaTime + stream->timestampOffsetOutputDevice_ioProcCopy; timeInfo.outputBufferDacTime = hostTimeStampInPaTime + stream->timestampOffsetOutputDevice_ioProcCopy;
} }
@ -2245,10 +2245,10 @@ static OSStatus AudioIOProc( void *inRefCon,
} }
else /* input only */ else /* input only */
{ {
timeInfo.inputBufferAdcTime = hostTimeStampInPaTime - stream->timestampOffsetInputDevice_ioProcCopy; timeInfo.inputBufferAdcTime = hostTimeStampInPaTime - stream->timestampOffsetInputDevice_ioProcCopy;
timeInfo.outputBufferDacTime = 0; timeInfo.outputBufferDacTime = 0;
} }
//printf( "---%g, %g, %g\n", timeInfo.inputBufferAdcTime, timeInfo.currentTime, timeInfo.outputBufferDacTime ); //printf( "---%g, %g, %g\n", timeInfo.inputBufferAdcTime, timeInfo.currentTime, timeInfo.outputBufferDacTime );
if( isRender && stream->inputUnit == stream->outputUnit if( isRender && stream->inputUnit == stream->outputUnit
@ -2310,7 +2310,7 @@ static OSStatus AudioIOProc( void *inRefCon,
* -- OR Simplex Output * -- OR Simplex Output
* *
* This case handles output data as in the full duplex case, * This case handles output data as in the full duplex case,
* and, if there is input data, reads it off the ring buffer * and, if there is input data, reads it off the ring buffer
* and into the PA buffer processor. If sample rate conversion * and into the PA buffer processor. If sample rate conversion
* is required on input, that is done here as well. * is required on input, that is done here as well.
*/ */
@ -2352,14 +2352,14 @@ static OSStatus AudioIOProc( void *inRefCon,
audio converter. */ audio converter. */
int inChan = stream->inputAudioBufferList.mBuffers[0].mNumberChannels; int inChan = stream->inputAudioBufferList.mBuffers[0].mNumberChannels;
long bytesPerFrame = flsz * inChan; long bytesPerFrame = flsz * inChan;
if( stream->inputSRConverter ) if( stream->inputSRConverter )
{ {
OSStatus err; OSStatus err;
UInt32 size; UInt32 size;
float data[ inChan * frames ]; float data[ inChan * frames ];
size = sizeof( data ); size = sizeof( data );
err = AudioConverterFillBuffer( err = AudioConverterFillBuffer(
stream->inputSRConverter, stream->inputSRConverter,
ringBufferIOProc, ringBufferIOProc,
&stream->inputRingBuffer, &stream->inputRingBuffer,
@ -2414,13 +2414,13 @@ static OSStatus AudioIOProc( void *inRefCon,
&callbackResult ); &callbackResult );
PaUtil_AdvanceRingBufferReadIndex(&stream->inputRingBuffer, size1 ); PaUtil_AdvanceRingBufferReadIndex(&stream->inputRingBuffer, size1 );
} else if( framesReadable < frames ) { } else if( framesReadable < frames ) {
long sizeBytes1 = size1 * bytesPerFrame; long sizeBytes1 = size1 * bytesPerFrame;
long sizeBytes2 = size2 * bytesPerFrame; long sizeBytes2 = size2 * bytesPerFrame;
/*we underflowed. take what data we can, zero the rest.*/ /*we underflowed. take what data we can, zero the rest.*/
unsigned char data[ frames * bytesPerFrame ]; unsigned char data[ frames * bytesPerFrame ];
if( size1 > 0 ) if( size1 > 0 )
{ {
memcpy( data, data1, sizeBytes1 ); memcpy( data, data1, sizeBytes1 );
} }
if( size2 > 0 ) if( size2 > 0 )
@ -2544,7 +2544,7 @@ static OSStatus AudioIOProc( void *inRefCon,
long f; long f;
size = sizeof( data ); size = sizeof( data );
err = AudioConverterFillBuffer( err = AudioConverterFillBuffer(
stream->inputSRConverter, stream->inputSRConverter,
ringBufferIOProc, ringBufferIOProc,
&stream->inputRingBuffer, &stream->inputRingBuffer,
@ -2612,19 +2612,19 @@ static PaError CloseStream( PaStream* s )
VDBUG( ( "Closing stream.\n" ) ); VDBUG( ( "Closing stream.\n" ) );
if( stream ) { if( stream ) {
if( stream->outputUnit ) if( stream->outputUnit )
{ {
Boolean isInput = FALSE; Boolean isInput = FALSE;
CleanupDevicePropertyListeners( stream, stream->outputDevice, isInput ); CleanupDevicePropertyListeners( stream, stream->outputDevice, isInput );
} }
if( stream->inputUnit ) if( stream->inputUnit )
{ {
Boolean isInput = TRUE; Boolean isInput = TRUE;
CleanupDevicePropertyListeners( stream, stream->inputDevice, isInput ); CleanupDevicePropertyListeners( stream, stream->inputDevice, isInput );
} }
if( stream->outputUnit ) { if( stream->outputUnit ) {
int count = removeFromXRunListenerList( stream ); int count = removeFromXRunListenerList( stream );
if( count == 0 ) if( count == 0 )
@ -2645,13 +2645,13 @@ static PaError CloseStream( PaStream* s )
} }
if( stream->outputUnit && stream->outputUnit != stream->inputUnit ) { if( stream->outputUnit && stream->outputUnit != stream->inputUnit ) {
AudioUnitUninitialize( stream->outputUnit ); AudioUnitUninitialize( stream->outputUnit );
CloseComponent( stream->outputUnit ); AudioComponentInstanceDispose( stream->outputUnit );
} }
stream->outputUnit = NULL; stream->outputUnit = NULL;
if( stream->inputUnit ) if( stream->inputUnit )
{ {
AudioUnitUninitialize( stream->inputUnit ); AudioUnitUninitialize( stream->inputUnit );
CloseComponent( stream->inputUnit ); AudioComponentInstanceDispose( stream->inputUnit );
stream->inputUnit = NULL; stream->inputUnit = NULL;
} }
if( stream->inputRingBuffer.buffer ) if( stream->inputRingBuffer.buffer )
@ -2671,7 +2671,7 @@ static PaError CloseStream( PaStream* s )
return result; return result;
if( stream->bufferProcessorIsInitialized ) if( stream->bufferProcessorIsInitialized )
PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
if( stream->timingInformationMutexIsInitialized ) if( stream->timingInformationMutexIsInitialized )
pthread_mutex_destroy( &stream->timingInformationMutex ); pthread_mutex_destroy( &stream->timingInformationMutex );
@ -2704,19 +2704,19 @@ static PaError StartStream( PaStream *s )
if( stream->outputUnit && stream->outputUnit != stream->inputUnit ) { if( stream->outputUnit && stream->outputUnit != stream->inputUnit ) {
ERR_WRAP( AudioOutputUnitStart(stream->outputUnit) ); ERR_WRAP( AudioOutputUnitStart(stream->outputUnit) );
} }
return paNoError; return paNoError;
#undef ERR_WRAP #undef ERR_WRAP
} }
// it's not clear from appl's docs that this really waits // it's not clear from appl's docs that this really waits
// until all data is flushed. // until all data is flushed.
static ComponentResult BlockWhileAudioUnitIsRunning( AudioUnit audioUnit, AudioUnitElement element ) static OSStatus BlockWhileAudioUnitIsRunning( AudioUnit audioUnit, AudioUnitElement element )
{ {
Boolean isRunning = 1; Boolean isRunning = 1;
while( isRunning ) { while( isRunning ) {
UInt32 s = sizeof( isRunning ); UInt32 s = sizeof( isRunning );
ComponentResult err = AudioUnitGetProperty( audioUnit, kAudioOutputUnitProperty_IsRunning, kAudioUnitScope_Global, element, &isRunning, &s ); OSStatus err = AudioUnitGetProperty( audioUnit, kAudioOutputUnitProperty_IsRunning, kAudioUnitScope_Global, element, &isRunning, &s );
if( err ) if( err )
return err; return err;
Pa_Sleep( 100 ); Pa_Sleep( 100 );

View file

@ -15,7 +15,7 @@
* Olivier Tristan for feedback and testing * Olivier Tristan for feedback and testing
* Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O
* interface. * interface.
* *
* *
* Based on the Open Source API proposed by Ross Bencina * Based on the Open Source API proposed by Ross Bencina
* Copyright (c) 1999-2002 Ross Bencina, Phil Burk * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
@ -41,13 +41,13 @@
*/ */
/* /*
* The text above constitutes the entire PortAudio license; however, * The text above constitutes the entire PortAudio license; however,
* the PortAudio community also makes the following non-binding requests: * the PortAudio community also makes the following non-binding requests:
* *
* Any person wishing to distribute modifications to the Software is * Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that * requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. It is also * they can be incorporated into the canonical version. It is also
* requested that these non-binding requests be included along with the * requested that these non-binding requests be included along with the
* license above. * license above.
*/ */
@ -62,6 +62,7 @@
#define PA_MAC_CORE_INTERNAL_H__ #define PA_MAC_CORE_INTERNAL_H__
#include <CoreAudio/CoreAudio.h> #include <CoreAudio/CoreAudio.h>
#include <AudioUnit/AudioComponent.h>
#include <CoreServices/CoreServices.h> #include <CoreServices/CoreServices.h>
#include <AudioUnit/AudioUnit.h> #include <AudioUnit/AudioUnit.h>
#include <AudioToolbox/AudioToolbox.h> #include <AudioToolbox/AudioToolbox.h>
@ -120,10 +121,10 @@ typedef struct PaMacCoreDeviceProperties
UInt32 bufferFrameSize; UInt32 bufferFrameSize;
// UInt32 streamLatency; // Seems to be the same as deviceLatency!? // UInt32 streamLatency; // Seems to be the same as deviceLatency!?
UInt32 deviceLatency; UInt32 deviceLatency;
/* Current device sample rate. May change! /* Current device sample rate. May change!
These are initialized to the nominal device sample rate, These are initialized to the nominal device sample rate,
and updated with the actual sample rate, when/where available. and updated with the actual sample rate, when/where available.
Note that these are the *device* sample rates, prior to any required Note that these are the *device* sample rates, prior to any required
SR conversion. */ SR conversion. */
Float64 sampleRate; Float64 sampleRate;
Float64 samplePeriod; // reciprocal Float64 samplePeriod; // reciprocal
@ -172,7 +173,7 @@ typedef struct PaMacCoreStream
double sampleRate; double sampleRate;
PaMacCoreDeviceProperties inputProperties; PaMacCoreDeviceProperties inputProperties;
PaMacCoreDeviceProperties outputProperties; PaMacCoreDeviceProperties outputProperties;
/* data updated by main thread and notifications, protected by timingInformationMutex */ /* data updated by main thread and notifications, protected by timingInformationMutex */
int timingInformationMutexIsInitialized; int timingInformationMutexIsInitialized;
pthread_mutex_t timingInformationMutex; pthread_mutex_t timingInformationMutex;
@ -181,13 +182,13 @@ typedef struct PaMacCoreStream
Float64 timestampOffsetCombined; Float64 timestampOffsetCombined;
Float64 timestampOffsetInputDevice; Float64 timestampOffsetInputDevice;
Float64 timestampOffsetOutputDevice; Float64 timestampOffsetOutputDevice;
/* Offsets in seconds to be applied to Apple timestamps to convert them to PA timestamps. /* Offsets in seconds to be applied to Apple timestamps to convert them to PA timestamps.
* While the io proc is active, the following values are only accessed and manipulated by the ioproc */ * While the io proc is active, the following values are only accessed and manipulated by the ioproc */
Float64 timestampOffsetCombined_ioProcCopy; Float64 timestampOffsetCombined_ioProcCopy;
Float64 timestampOffsetInputDevice_ioProcCopy; Float64 timestampOffsetInputDevice_ioProcCopy;
Float64 timestampOffsetOutputDevice_ioProcCopy; Float64 timestampOffsetOutputDevice_ioProcCopy;
} }
PaMacCoreStream; PaMacCoreStream;