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