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
|
* 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 );
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue