From: Richard Cartwright Date: Thu, 9 Nov 2017 21:32:10 +0000 (+0000) Subject: Update darwin build to use newer core audio frameworks. X-Git-Url: https://andrewgundersen.net/repos?a=commitdiff_plain;h=refs%2Fheads%2Fticket_218;p=portaudio Update darwin build to use newer core audio frameworks. Replaced references to core services audio component with equivalent function calls in the AudioUnit/AudioComponent.h API. --- diff --git a/src/hostapi/coreaudio/pa_mac_core.c b/src/hostapi/coreaudio/pa_mac_core.c index 257e9de..fff53ba 100644 --- a/src/hostapi/coreaudio/pa_mac_core.c +++ b/src/hostapi/coreaudio/pa_mac_core.c @@ -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; imaxInputChannels = 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, kAudioDevicePropertyBufferFrameSize, AudioDevicePropertyGenericListenerProc ); - AudioDeviceRemovePropertyListener( deviceID, 0, isInput, kAudioDevicePropertySafetyOffset, + 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 ); diff --git a/src/hostapi/coreaudio/pa_mac_core_internal.h b/src/hostapi/coreaudio/pa_mac_core_internal.h index 14e3d07..ebb2b9e 100644 --- a/src/hostapi/coreaudio/pa_mac_core_internal.h +++ b/src/hostapi/coreaudio/pa_mac_core_internal.h @@ -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 +#include #include #include #include @@ -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;