Ignore:
Timestamp:
Oct 13, 2006 5:57:42 PM (18 years ago)
Author:
bennylp
Message:

Updated PortAudio? to latest version for Mac

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/portaudio/pa_mac_core.c

    r341 r770  
    11/* 
    2  * $Id$ 
    3  * pa_mac_core.c 
    4  * Implementation of PortAudio for Mac OS X CoreAudio        
    5  *                                                                                          
     2 * Implementation of the PortAudio API for Apple AUHAL 
     3 * 
    64 * PortAudio Portable Real-Time Audio Library 
    75 * Latest Version at: http://www.portaudio.com 
    86 * 
    9  * Authors: Ross Bencina and Phil Burk 
    10  * Copyright (c) 1999-2000 Ross Bencina and Phil Burk 
     7 * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. 
     8 * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) 
     9 * 
     10 * Dominic's code was based on code by Phil Burk, Darren Gibbs, 
     11 * Gord Peters, Stephane Letz, and Greg Pfiel. 
     12 * 
     13 * The following people also deserve acknowledgements: 
     14 * 
     15 * Olivier Tristan for feedback and testing 
     16 * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O 
     17 * interface. 
     18 *  
     19 * 
     20 * Based on the Open Source API proposed by Ross Bencina 
     21 * Copyright (c) 1999-2002 Ross Bencina, Phil Burk 
    1122 * 
    1223 * Permission is hereby granted, free of charge, to any person obtaining 
     
    2132 * included in all copies or substantial portions of the Software. 
    2233 * 
    23  * Any person wishing to distribute modifications to the Software is 
    24  * requested to send the modifications to the original developer so that 
    25  * they can be incorporated into the canonical version. 
    26  * 
    2734 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
    2835 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
     
    3239 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
    3340 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
     41 */ 
     42 
     43/* 
     44 * The text above constitutes the entire PortAudio license; however,  
     45 * the PortAudio community also makes the following non-binding requests: 
    3446 * 
     47 * Any person wishing to distribute modifications to the Software is 
     48 * requested to send the modifications to the original developer so that 
     49 * they can be incorporated into the canonical version. It is also  
     50 * requested that these non-binding requests be included along with the  
     51 * license above. 
    3552 */ 
    3653 
    37 #include <CoreAudio/CoreAudio.h> 
    38 #include <AudioToolbox/AudioToolbox.h> 
    39 #include <stdio.h> 
    40 #include <stdlib.h> 
    41 #include <math.h> 
    42 #include <assert.h> 
    43  
    44 #include "portaudio.h" 
    45 #include "pa_trace.h" 
    46 #include "pa_util.h" 
    47 #include "pa_allocation.h" 
    48 #include "pa_hostapi.h" 
    49 #include "pa_stream.h" 
    50 #include "pa_cpuload.h" 
    51 #include "pa_process.h" 
    52  
    53 // =====  constants  ===== 
    54  
    55 // =====  structs  ===== 
    56 #pragma mark structs 
    57  
    58 // PaMacCoreHostApiRepresentation - host api datastructure specific to this implementation 
    59 typedef struct PaMacCore_HAR 
     54/** 
     55 @file pa_mac_core 
     56 @ingroup hostapi_src 
     57 @author Bjorn Roche 
     58 @brief AUHAL implementation of PortAudio 
     59*/ 
     60 
     61/* FIXME: not all error conditions call PaUtil_SetLastHostErrorInfo() 
     62 * PaMacCore_SetError() will do this. 
     63 */ 
     64 
     65#include "pa_mac_core_internal.h" 
     66 
     67#include <string.h> /* strlen(), memcmp() etc. */ 
     68 
     69#include "pa_mac_core.h" 
     70#include "pa_mac_core_utilities.h" 
     71#include "pa_mac_core_blocking.h" 
     72 
     73 
     74 
     75/* prototypes for functions declared in this file */ 
     76 
     77#ifdef __cplusplus 
     78extern "C" 
    6079{ 
    61     PaUtilHostApiRepresentation inheritedHostApiRep; 
    62     PaUtilStreamInterface callbackStreamInterface; 
    63     PaUtilStreamInterface blockingStreamInterface; 
    64      
    65     PaUtilAllocationGroup *allocations; 
    66     AudioDeviceID *macCoreDeviceIds; 
     80#endif /* __cplusplus */ 
     81 
     82PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); 
     83 
     84#ifdef __cplusplus 
    6785} 
    68 PaMacCoreHostApiRepresentation; 
    69  
    70 typedef struct PaMacCore_DI 
     86#endif /* __cplusplus */ 
     87 
     88#define RING_BUFFER_ADVANCE_DENOMINATOR (4) 
     89 
     90static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); 
     91static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, 
     92                                  const PaStreamParameters *inputParameters, 
     93                                  const PaStreamParameters *outputParameters, 
     94                                  double sampleRate ); 
     95static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, 
     96                           PaStream** s, 
     97                           const PaStreamParameters *inputParameters, 
     98                           const PaStreamParameters *outputParameters, 
     99                           double sampleRate, 
     100                           unsigned long framesPerBuffer, 
     101                           PaStreamFlags streamFlags, 
     102                           PaStreamCallback *streamCallback, 
     103                           void *userData ); 
     104static PaError CloseStream( PaStream* stream ); 
     105static PaError StartStream( PaStream *stream ); 
     106static PaError StopStream( PaStream *stream ); 
     107static PaError AbortStream( PaStream *stream ); 
     108static PaError IsStreamStopped( PaStream *s ); 
     109static PaError IsStreamActive( PaStream *stream ); 
     110static PaTime GetStreamTime( PaStream *stream ); 
     111static void setStreamStartTime( PaStream *stream ); 
     112static OSStatus AudioIOProc( void *inRefCon, 
     113                               AudioUnitRenderActionFlags *ioActionFlags, 
     114                               const AudioTimeStamp *inTimeStamp, 
     115                               UInt32 inBusNumber, 
     116                               UInt32 inNumberFrames, 
     117                               AudioBufferList *ioData ); 
     118static double GetStreamCpuLoad( PaStream* stream ); 
     119 
     120static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi, 
     121                               PaDeviceInfo *deviceInfo, 
     122                               AudioDeviceID macCoreDeviceId, 
     123                               int isInput); 
     124 
     125static PaError OpenAndSetupOneAudioUnit( 
     126                                   const PaStreamParameters *inStreamParams, 
     127                                   const PaStreamParameters *outStreamParams, 
     128                                   const unsigned long requestedFramesPerBuffer, 
     129                                   unsigned long *actualInputFramesPerBuffer, 
     130                                   unsigned long *actualOutputFramesPerBuffer, 
     131                                   const PaMacAUHAL *auhalHostApi, 
     132                                   AudioUnit *audioUnit, 
     133                                   AudioConverterRef *srConverter, 
     134                                   AudioDeviceID *audioDevice, 
     135                                   const double sampleRate, 
     136                                   void *refCon ); 
     137 
     138/* for setting errors. */ 
     139#define PA_AUHAL_SET_LAST_HOST_ERROR( errorCode, errorText ) \ 
     140    PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText ) 
     141 
     142 
     143/*currently, this is only used in initialization, but it might be modified 
     144  to be used when the list of devices changes.*/ 
     145static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi) 
    71146{ 
    72     PaDeviceInfo inheritedDeviceInfo; 
     147    UInt32 size; 
     148    UInt32 propsize; 
     149    VVDBUG(("gatherDeviceInfo()\n")); 
     150    /* -- free any previous allocations -- */ 
     151    if( auhalHostApi->devIds ) 
     152        PaUtil_GroupFreeMemory(auhalHostApi->allocations, auhalHostApi->devIds); 
     153    auhalHostApi->devIds = NULL; 
     154 
     155    /* -- figure out how many devices there are -- */ 
     156    AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices, 
     157                                  &propsize, 
     158                                  NULL ); 
     159    auhalHostApi->devCount = propsize / sizeof( AudioDeviceID ); 
     160 
     161    VDBUG( ( "Found %ld device(s).\n", auhalHostApi->devCount ) ); 
     162 
     163    /* -- copy the device IDs -- */ 
     164    auhalHostApi->devIds = (AudioDeviceID *)PaUtil_GroupAllocateMemory( 
     165                             auhalHostApi->allocations, 
     166                             propsize ); 
     167    if( !auhalHostApi->devIds ) 
     168        return paInsufficientMemory; 
     169    AudioHardwareGetProperty( kAudioHardwarePropertyDevices, 
     170                                  &propsize, 
     171                                  auhalHostApi->devIds ); 
     172#ifdef MAC_CORE_VERBOSE_DEBUG 
     173    { 
     174       int i; 
     175       for( i=0; i<auhalHostApi->devCount; ++i ) 
     176          printf( "Device %d\t: %ld\n", i, auhalHostApi->devIds[i] ); 
     177    } 
     178#endif 
     179 
     180    size = sizeof(AudioDeviceID); 
     181    auhalHostApi->defaultIn  = kAudioDeviceUnknown; 
     182    auhalHostApi->defaultOut = kAudioDeviceUnknown; 
     183 
     184    /* determine the default device. */ 
     185    /* I am not sure how these calls to AudioHardwareGetProperty() 
     186       could fail, but in case they do, we use the first available 
     187       device as the default. */ 
     188    if( 0 != AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, 
     189                     &size, 
     190                     &auhalHostApi->defaultIn) ) { 
     191       int i; 
     192       auhalHostApi->defaultIn  = kAudioDeviceUnknown; 
     193       VDBUG(("Failed to get default input device from OS.")); 
     194       VDBUG((" I will substitute the first available input Device.")); 
     195       for( i=0; i<auhalHostApi->devCount; ++i ) { 
     196          PaDeviceInfo devInfo; 
     197          if( 0 != GetChannelInfo( auhalHostApi, &devInfo, 
     198                                   auhalHostApi->devIds[i], TRUE ) ) 
     199             if( devInfo.maxInputChannels ) { 
     200                auhalHostApi->defaultIn = auhalHostApi->devIds[i]; 
     201                break; 
     202             } 
     203       } 
     204    }    
     205    if( 0 != AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, 
     206                     &size, 
     207                     &auhalHostApi->defaultOut) ) { 
     208       int i; 
     209       auhalHostApi->defaultIn  = kAudioDeviceUnknown; 
     210       VDBUG(("Failed to get default output device from OS.")); 
     211       VDBUG((" I will substitute the first available output Device.")); 
     212       for( i=0; i<auhalHostApi->devCount; ++i ) { 
     213          PaDeviceInfo devInfo; 
     214          if( 0 != GetChannelInfo( auhalHostApi, &devInfo, 
     215                                   auhalHostApi->devIds[i], FALSE ) ) 
     216             if( devInfo.maxOutputChannels ) { 
     217                auhalHostApi->defaultOut = auhalHostApi->devIds[i]; 
     218                break; 
     219             } 
     220       } 
     221    }    
     222 
     223    VDBUG( ( "Default in : %ld\n", auhalHostApi->defaultIn  ) ); 
     224    VDBUG( ( "Default out: %ld\n", auhalHostApi->defaultOut ) ); 
     225 
     226    return paNoError; 
    73227} 
    74 PaMacCoreDeviceInfo; 
    75  
    76 // PaMacCoreStream - a stream data structure specifically for this implementation 
    77 typedef struct PaMacCore_S 
    78 { 
    79     PaUtilStreamRepresentation streamRepresentation; 
    80     PaUtilCpuLoadMeasurer cpuLoadMeasurer; 
    81     PaUtilBufferProcessor bufferProcessor; 
    82      
    83     int primeStreamUsingCallback; 
    84      
    85     AudioDeviceID inputDevice; 
    86     AudioDeviceID outputDevice; 
    87      
    88     // Processing thread management -------------- 
    89 //    HANDLE abortEvent; 
    90 //    HANDLE processingThread; 
    91 //    DWORD processingThreadId; 
    92      
    93     char throttleProcessingThreadOnOverload; // 0 -> don't throtte, non-0 -> throttle 
    94     int processingThreadPriority; 
    95     int highThreadPriority; 
    96     int throttledThreadPriority; 
    97     unsigned long throttledSleepMsecs; 
    98      
    99     int isStopped; 
    100     volatile int isActive; 
    101     volatile int stopProcessing; // stop thread once existing buffers have been returned 
    102     volatile int abortProcessing; // stop thread immediately 
    103      
    104 //    DWORD allBuffersDurationMs; // used to calculate timeouts 
    105 } 
    106 PaMacCoreStream; 
    107  
    108 // Data needed by the CoreAudio callback functions 
    109 typedef struct PaMacCore_CD 
    110 { 
    111     PaMacCoreStream *stream; 
    112     PaStreamCallback *callback; 
    113     void *userData; 
    114     PaUtilConverter *inputConverter; 
    115     PaUtilConverter *outputConverter; 
    116     void *inputBuffer; 
    117     void *outputBuffer; 
    118     int inputChannelCount; 
    119     int outputChannelCount; 
    120     PaSampleFormat inputSampleFormat; 
    121     PaSampleFormat outputSampleFormat; 
    122     PaUtilTriangularDitherGenerator *ditherGenerator; 
    123 } 
    124 PaMacClientData; 
    125  
    126 // =====  CoreAudio-PortAudio bridge functions ===== 
    127 #pragma mark CoreAudio-PortAudio bridge functions 
    128  
    129 // Maps CoreAudio OSStatus codes to PortAudio PaError codes 
    130 static PaError conv_err(OSStatus error) 
    131 { 
    132     PaError result; 
    133      
    134     switch (error) { 
    135         case kAudioHardwareNoError: 
    136             result = paNoError; break; 
    137         case kAudioHardwareNotRunningError: 
    138             result = paInternalError; break; 
    139         case kAudioHardwareUnspecifiedError: 
    140             result = paInternalError; break; 
    141         case kAudioHardwareUnknownPropertyError: 
    142             result = paInternalError; break; 
    143         case kAudioHardwareBadPropertySizeError: 
    144             result = paInternalError; break; 
    145         case kAudioHardwareIllegalOperationError: 
    146             result = paInternalError; break; 
    147         case kAudioHardwareBadDeviceError: 
    148             result = paInvalidDevice; break; 
    149         case kAudioHardwareBadStreamError: 
    150             result = paBadStreamPtr; break; 
    151 //        case kAudioHardwareUnsupportedOperationError: 
    152 //            result = paInternalError; break; 
    153         case kAudioDeviceUnsupportedFormatError: 
    154             result = paSampleFormatNotSupported; break; 
    155         case kAudioDevicePermissionsError: 
    156             result = paDeviceUnavailable; break; 
    157         default: 
    158             result = paInternalError; 
    159     } 
    160      
    161     return result; 
    162 } 
    163  
    164 static AudioStreamBasicDescription *InitializeStreamDescription(const PaStreamParameters *parameters, double sampleRate) 
    165 { 
    166     struct AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(sizeof(AudioStreamBasicDescription)); 
    167     streamDescription->mSampleRate = sampleRate; 
    168     streamDescription->mFormatID = kAudioFormatLinearPCM; 
    169     streamDescription->mFormatFlags = 0; 
    170     streamDescription->mFramesPerPacket = 1; 
    171      
    172     if (parameters->sampleFormat & paNonInterleaved) { 
    173         streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsNonInterleaved; 
    174         streamDescription->mChannelsPerFrame = 1; 
    175         streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat); 
    176         streamDescription->mBytesPerPacket = Pa_GetSampleSize(parameters->sampleFormat); 
    177     } 
    178     else { 
    179         streamDescription->mChannelsPerFrame = parameters->channelCount; 
    180     } 
    181      
    182     streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat) * streamDescription->mChannelsPerFrame; 
    183     streamDescription->mBytesPerPacket = streamDescription->mBytesPerFrame * streamDescription->mFramesPerPacket; 
    184      
    185     if (parameters->sampleFormat & paFloat32) { 
    186         streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsFloat; 
    187         streamDescription->mBitsPerChannel = 32; 
    188     } 
    189     else if (parameters->sampleFormat & paInt32) { 
    190         streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; 
    191         streamDescription->mBitsPerChannel = 32; 
    192     } 
    193     else if (parameters->sampleFormat & paInt24) { 
    194         streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; 
    195         streamDescription->mBitsPerChannel = 24; 
    196     } 
    197     else if (parameters->sampleFormat & paInt16) { 
    198         streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; 
    199         streamDescription->mBitsPerChannel = 16; 
    200     } 
    201     else if (parameters->sampleFormat & paInt8) { 
    202         streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; 
    203         streamDescription->mBitsPerChannel = 8; 
    204     }     
    205     else if (parameters->sampleFormat & paInt32) { 
    206         streamDescription->mBitsPerChannel = 8; 
    207     } 
    208      
    209     return streamDescription; 
    210 } 
    211  
    212 static PaStreamCallbackTimeInfo *InitializeTimeInfo(const AudioTimeStamp* now, const AudioTimeStamp* inputTime, const AudioTimeStamp* outputTime) 
    213 { 
    214     PaStreamCallbackTimeInfo *timeInfo = PaUtil_AllocateMemory(sizeof(PaStreamCallbackTimeInfo)); 
    215      
    216     timeInfo->inputBufferAdcTime = inputTime->mSampleTime; 
    217     timeInfo->currentTime = now->mSampleTime; 
    218     timeInfo->outputBufferDacTime = outputTime->mSampleTime; 
    219      
    220     return timeInfo; 
    221 } 
    222  
    223 // =====  support functions  ===== 
    224 #pragma mark support functions 
    225  
    226 static void CleanUp(PaMacCoreHostApiRepresentation *macCoreHostApi) 
    227 { 
    228     if( macCoreHostApi->allocations ) 
    229     { 
    230         PaUtil_FreeAllAllocations( macCoreHostApi->allocations ); 
    231         PaUtil_DestroyAllocationGroup( macCoreHostApi->allocations ); 
    232     } 
    233      
    234     PaUtil_FreeMemory( macCoreHostApi );     
    235 } 
    236  
    237 static PaError GetChannelInfo(PaDeviceInfo *deviceInfo, AudioDeviceID macCoreDeviceId, int isInput) 
     228 
     229static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi, 
     230                               PaDeviceInfo *deviceInfo, 
     231                               AudioDeviceID macCoreDeviceId, 
     232                               int isInput) 
    238233{ 
    239234    UInt32 propSize; 
     
    241236    UInt32 i; 
    242237    int numChannels = 0; 
    243     AudioBufferList *buflist; 
    244  
    245     err = conv_err(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, NULL)); 
     238    AudioBufferList *buflist = NULL; 
     239    UInt32 frameLatency; 
     240 
     241    VVDBUG(("GetChannelInfo()\n")); 
     242 
     243    /* Get the number of channels from the stream configuration. 
     244       Fail if we can't get this. */ 
     245 
     246    err = ERR(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, NULL)); 
     247    if (err) 
     248        return err; 
     249 
    246250    buflist = PaUtil_AllocateMemory(propSize); 
    247     err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, buflist)); 
    248     if (!err) { 
    249         for (i = 0; i < buflist->mNumberBuffers; ++i) { 
    250             numChannels += buflist->mBuffers[i].mNumberChannels; 
     251    if( !buflist ) 
     252       return paInsufficientMemory; 
     253    err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, buflist)); 
     254    if (err) 
     255        goto error; 
     256 
     257    for (i = 0; i < buflist->mNumberBuffers; ++i) 
     258        numChannels += buflist->mBuffers[i].mNumberChannels; 
     259 
     260    if (isInput) 
     261        deviceInfo->maxInputChannels = numChannels; 
     262    else 
     263        deviceInfo->maxOutputChannels = numChannels; 
     264       
     265    if (numChannels > 0) /* do not try to retrieve the latency if there is no channels. */ 
     266    { 
     267       /* Get the latency.  Don't fail if we can't get this. */ 
     268       /* default to something reasonable */ 
     269       deviceInfo->defaultLowInputLatency = .01; 
     270       deviceInfo->defaultHighInputLatency = .10; 
     271       deviceInfo->defaultLowOutputLatency = .01; 
     272       deviceInfo->defaultHighOutputLatency = .10; 
     273       propSize = sizeof(UInt32); 
     274       err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &frameLatency)); 
     275       if (!err) 
     276       { 
     277          /** FEEDBACK: 
     278           * This code was arrived at by trial and error, and some extentive, but not exhaustive 
     279           * testing. Sebastien Beaulieu <seb@plogue.com> has suggested using 
     280           * kAudioDevicePropertyLatency + kAudioDevicePropertySafetyOffset + buffer size instead. 
     281           * At the time this code was written, many users were reporting dropouts with audio 
     282           * programs that probably used this formula. This was probably 
     283           * around 10.4.4, and the problem is probably fixed now. So perhaps 
     284           * his formula should be reviewed and used. 
     285           * */ 
     286          double secondLatency = frameLatency / deviceInfo->defaultSampleRate; 
     287          if (isInput) 
     288          { 
     289             deviceInfo->defaultLowInputLatency = 3 * secondLatency; 
     290             deviceInfo->defaultHighInputLatency = 3 * 10 * secondLatency; 
     291          } 
     292          else 
     293          { 
     294             deviceInfo->defaultLowOutputLatency = 3 * secondLatency; 
     295             deviceInfo->defaultHighOutputLatency = 3 * 10 * secondLatency; 
     296          } 
     297       } 
     298    } 
     299    PaUtil_FreeMemory( buflist ); 
     300    return paNoError; 
     301 error: 
     302    PaUtil_FreeMemory( buflist ); 
     303    return err; 
     304} 
     305 
     306static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi, 
     307                                     PaDeviceInfo *deviceInfo, 
     308                                     AudioDeviceID macCoreDeviceId, 
     309                                     PaHostApiIndex hostApiIndex ) 
     310{ 
     311    Float64 sampleRate; 
     312    char *name; 
     313    PaError err = paNoError; 
     314    UInt32 propSize; 
     315 
     316    VVDBUG(("InitializeDeviceInfo(): macCoreDeviceId=%ld\n", macCoreDeviceId)); 
     317 
     318    memset(deviceInfo, 0, sizeof(deviceInfo)); 
     319 
     320    deviceInfo->structVersion = 2; 
     321    deviceInfo->hostApi = hostApiIndex; 
     322 
     323    /* Get the device name.  Fail if we can't get it. */ 
     324    err = ERR(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL)); 
     325    if (err) 
     326        return err; 
     327 
     328    name = PaUtil_GroupAllocateMemory(auhalHostApi->allocations,propSize); 
     329    if ( !name ) 
     330        return paInsufficientMemory; 
     331    err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, name)); 
     332    if (err) 
     333        return err; 
     334    deviceInfo->name = name; 
     335 
     336    /* Try to get the default sample rate.  Don't fail if we can't get this. */ 
     337    propSize = sizeof(Float64); 
     338    err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &sampleRate)); 
     339    if (err) 
     340        deviceInfo->defaultSampleRate = 0.0; 
     341    else 
     342        deviceInfo->defaultSampleRate = sampleRate; 
     343 
     344    /* Get the maximum number of input and output channels.  Fail if we can't get this. */ 
     345 
     346    err = GetChannelInfo(auhalHostApi, deviceInfo, macCoreDeviceId, 1); 
     347    if (err) 
     348        return err; 
     349 
     350    err = GetChannelInfo(auhalHostApi, deviceInfo, macCoreDeviceId, 0); 
     351    if (err) 
     352        return err; 
     353 
     354    return paNoError; 
     355} 
     356 
     357PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) 
     358{ 
     359    PaError result = paNoError; 
     360    int i; 
     361    PaMacAUHAL *auhalHostApi; 
     362    PaDeviceInfo *deviceInfoArray; 
     363 
     364    VVDBUG(("PaMacCore_Initialize(): hostApiIndex=%d\n", hostApiIndex)); 
     365 
     366    auhalHostApi = (PaMacAUHAL*)PaUtil_AllocateMemory( sizeof(PaMacAUHAL) ); 
     367    if( !auhalHostApi ) 
     368    { 
     369        result = paInsufficientMemory; 
     370        goto error; 
     371    } 
     372 
     373    auhalHostApi->allocations = PaUtil_CreateAllocationGroup(); 
     374    if( !auhalHostApi->allocations ) 
     375    { 
     376        result = paInsufficientMemory; 
     377        goto error; 
     378    } 
     379 
     380    auhalHostApi->devIds = NULL; 
     381    auhalHostApi->devCount = 0; 
     382 
     383    /* get the info we need about the devices */ 
     384    result = gatherDeviceInfo( auhalHostApi ); 
     385    if( result != paNoError ) 
     386       goto error; 
     387 
     388    *hostApi = &auhalHostApi->inheritedHostApiRep; 
     389    (*hostApi)->info.structVersion = 1; 
     390    (*hostApi)->info.type = paCoreAudio; 
     391    (*hostApi)->info.name = "Core Audio"; 
     392 
     393    (*hostApi)->info.defaultInputDevice = paNoDevice; 
     394    (*hostApi)->info.defaultOutputDevice = paNoDevice; 
     395 
     396    (*hostApi)->info.deviceCount = 0;   
     397 
     398    if( auhalHostApi->devCount > 0 ) 
     399    { 
     400        (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( 
     401                auhalHostApi->allocations, sizeof(PaDeviceInfo*) * auhalHostApi->devCount); 
     402        if( !(*hostApi)->deviceInfos ) 
     403        { 
     404            result = paInsufficientMemory; 
     405            goto error; 
    251406        } 
    252                  
    253                 if (isInput) 
    254                         deviceInfo->maxInputChannels = numChannels; 
    255                 else 
    256                         deviceInfo->maxOutputChannels = numChannels; 
    257                  
    258         int frameLatency; 
    259         propSize = sizeof(UInt32); 
    260         err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &frameLatency)); 
    261         if (!err) { 
    262             double secondLatency = frameLatency / deviceInfo->defaultSampleRate; 
    263             if (isInput) { 
    264                 deviceInfo->defaultLowInputLatency = secondLatency; 
    265                 deviceInfo->defaultHighInputLatency = secondLatency; 
     407 
     408        /* allocate all device info structs in a contiguous block */ 
     409        deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( 
     410                auhalHostApi->allocations, sizeof(PaDeviceInfo) * auhalHostApi->devCount ); 
     411        if( !deviceInfoArray ) 
     412        { 
     413            result = paInsufficientMemory; 
     414            goto error; 
     415        } 
     416 
     417        for( i=0; i < auhalHostApi->devCount; ++i ) 
     418        { 
     419            int err; 
     420            err = InitializeDeviceInfo( auhalHostApi, &deviceInfoArray[i], 
     421                                      auhalHostApi->devIds[i], 
     422                                      hostApiIndex ); 
     423            if (err == paNoError) 
     424            { /* copy some info and set the defaults */ 
     425                (*hostApi)->deviceInfos[(*hostApi)->info.deviceCount] = &deviceInfoArray[i]; 
     426                if (auhalHostApi->devIds[i] == auhalHostApi->defaultIn) 
     427                    (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; 
     428                if (auhalHostApi->devIds[i] == auhalHostApi->defaultOut) 
     429                    (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; 
     430                (*hostApi)->info.deviceCount++; 
    266431            } 
    267             else { 
    268                 deviceInfo->defaultLowOutputLatency = secondLatency; 
    269                 deviceInfo->defaultHighOutputLatency = secondLatency; 
     432            else 
     433            { /* there was an error. we need to shift the devices down, so we ignore this one */ 
     434                int j; 
     435                auhalHostApi->devCount--; 
     436                for( j=i; j<auhalHostApi->devCount; ++j ) 
     437                   auhalHostApi->devIds[j] = auhalHostApi->devIds[j+1]; 
     438                i--; 
    270439            } 
    271440        } 
    272441    } 
    273     PaUtil_FreeMemory(buflist); 
    274      
    275     return err; 
    276 } 
    277  
    278 static PaError InitializeDeviceInfo(PaMacCoreDeviceInfo *macCoreDeviceInfo,  AudioDeviceID macCoreDeviceId, PaHostApiIndex hostApiIndex ) 
    279 { 
    280     PaDeviceInfo *deviceInfo = &macCoreDeviceInfo->inheritedDeviceInfo; 
    281     deviceInfo->structVersion = 2; 
    282     deviceInfo->hostApi = hostApiIndex; 
    283      
    284     PaError err = paNoError; 
    285     UInt32 propSize; 
    286  
    287     err = conv_err(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL)); 
    288     // FIXME: this allocation should be part of the allocations group 
    289     char *name = PaUtil_AllocateMemory(propSize); 
    290     err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, name)); 
    291     if (!err) { 
    292         deviceInfo->name = name; 
    293     } 
    294      
    295     Float64 sampleRate; 
    296     propSize = sizeof(Float64); 
    297     err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &sampleRate)); 
    298     if (!err) { 
    299         deviceInfo->defaultSampleRate = sampleRate; 
    300     } 
    301  
    302  
    303     // Get channel info 
    304     err = GetChannelInfo(deviceInfo, macCoreDeviceId, 1); 
    305     err = GetChannelInfo(deviceInfo, macCoreDeviceId, 0); 
    306  
    307     return err; 
    308 } 
    309  
    310 static PaError InitializeDeviceInfos( PaMacCoreHostApiRepresentation *macCoreHostApi, PaHostApiIndex hostApiIndex ) 
    311 { 
    312     PaError result = paNoError; 
    313     PaUtilHostApiRepresentation *hostApi; 
    314     PaMacCoreDeviceInfo *deviceInfoArray; 
    315  
    316     // initialise device counts and default devices under the assumption that there are no devices. These values are incremented below if and when devices are successfully initialized. 
    317     hostApi = &macCoreHostApi->inheritedHostApiRep; 
    318     hostApi->info.deviceCount = 0; 
    319     hostApi->info.defaultInputDevice = paNoDevice; 
    320     hostApi->info.defaultOutputDevice = paNoDevice; 
    321      
    322     UInt32 propsize; 
    323     AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propsize, NULL); 
    324     int numDevices = propsize / sizeof(AudioDeviceID); 
    325     hostApi->info.deviceCount = numDevices; 
    326     if (numDevices > 0) { 
    327         hostApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( 
    328                                             macCoreHostApi->allocations, sizeof(PaDeviceInfo*) * numDevices ); 
    329         if( !hostApi->deviceInfos ) 
     442 
     443    (*hostApi)->Terminate = Terminate; 
     444    (*hostApi)->OpenStream = OpenStream; 
     445    (*hostApi)->IsFormatSupported = IsFormatSupported; 
     446 
     447    PaUtil_InitializeStreamInterface( &auhalHostApi->callbackStreamInterface, 
     448                                      CloseStream, StartStream, 
     449                                      StopStream, AbortStream, IsStreamStopped, 
     450                                      IsStreamActive, 
     451                                      GetStreamTime, GetStreamCpuLoad, 
     452                                      PaUtil_DummyRead, PaUtil_DummyWrite, 
     453                                      PaUtil_DummyGetReadAvailable, 
     454                                      PaUtil_DummyGetWriteAvailable ); 
     455 
     456    PaUtil_InitializeStreamInterface( &auhalHostApi->blockingStreamInterface, 
     457                                      CloseStream, StartStream, 
     458                                      StopStream, AbortStream, IsStreamStopped, 
     459                                      IsStreamActive, 
     460                                      GetStreamTime, PaUtil_DummyGetCpuLoad, 
     461                                      ReadStream, WriteStream, 
     462                                      GetStreamReadAvailable, 
     463                                      GetStreamWriteAvailable ); 
     464 
     465    return result; 
     466 
     467error: 
     468    if( auhalHostApi ) 
     469    { 
     470        if( auhalHostApi->allocations ) 
    330471        { 
    331             return paInsufficientMemory; 
     472            PaUtil_FreeAllAllocations( auhalHostApi->allocations ); 
     473            PaUtil_DestroyAllocationGroup( auhalHostApi->allocations ); 
    332474        } 
    333  
    334         // allocate all device info structs in a contiguous block 
    335         deviceInfoArray = (PaMacCoreDeviceInfo*)PaUtil_GroupAllocateMemory( 
    336                                 macCoreHostApi->allocations, sizeof(PaMacCoreDeviceInfo) * numDevices ); 
    337         if( !deviceInfoArray ) 
    338         { 
    339             return paInsufficientMemory; 
    340         } 
    341          
    342         macCoreHostApi->macCoreDeviceIds = PaUtil_GroupAllocateMemory(macCoreHostApi->allocations, propsize); 
    343         AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propsize, macCoreHostApi->macCoreDeviceIds); 
    344  
    345         AudioDeviceID defaultInputDevice, defaultOutputDevice; 
    346         propsize = sizeof(AudioDeviceID); 
    347         AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propsize, &defaultInputDevice); 
    348         AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propsize, &defaultOutputDevice); 
    349          
    350         UInt32 i; 
    351         for (i = 0; i < numDevices; ++i) { 
    352             if (macCoreHostApi->macCoreDeviceIds[i] == defaultInputDevice) { 
    353                 hostApi->info.defaultInputDevice = i; 
    354             } 
    355             if (macCoreHostApi->macCoreDeviceIds[i] == defaultOutputDevice) { 
    356                 hostApi->info.defaultOutputDevice = i; 
    357             } 
    358             InitializeDeviceInfo(&deviceInfoArray[i], macCoreHostApi->macCoreDeviceIds[i], hostApiIndex); 
    359             hostApi->deviceInfos[i] = &(deviceInfoArray[i].inheritedDeviceInfo);       
    360         } 
    361     } 
    362  
     475                 
     476        PaUtil_FreeMemory( auhalHostApi ); 
     477    } 
    363478    return result; 
    364479} 
    365480 
    366 static OSStatus CheckFormat(AudioDeviceID macCoreDeviceId, const PaStreamParameters *parameters, double sampleRate, int isInput) 
    367 { 
    368     UInt32 propSize = sizeof(AudioStreamBasicDescription); 
    369     AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(propSize); 
    370  
    371     streamDescription->mSampleRate = sampleRate; 
    372     streamDescription->mFormatID = 0; 
    373     streamDescription->mFormatFlags = 0; 
    374     streamDescription->mBytesPerPacket = 0; 
    375     streamDescription->mFramesPerPacket = 0; 
    376     streamDescription->mBytesPerFrame = 0; 
    377     streamDescription->mChannelsPerFrame = 0; 
    378     streamDescription->mBitsPerChannel = 0; 
    379     streamDescription->mReserved = 0; 
    380  
    381     OSStatus result = AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamFormatSupported, &propSize, streamDescription); 
    382     PaUtil_FreeMemory(streamDescription); 
    383     return result; 
    384 } 
    385  
    386 static OSStatus CopyInputData(PaMacClientData* destination, const AudioBufferList *source, unsigned long frameCount) 
    387 { 
    388     int frameSpacing, channelSpacing; 
    389     if (destination->inputSampleFormat & paNonInterleaved) { 
    390         frameSpacing = 1; 
    391         channelSpacing = destination->inputChannelCount; 
    392     } 
    393     else { 
    394         frameSpacing = destination->inputChannelCount; 
    395         channelSpacing = 1; 
    396     } 
    397      
    398     AudioBuffer const *inputBuffer = &source->mBuffers[0]; 
    399     void *coreAudioBuffer = inputBuffer->mData; 
    400     void *portAudioBuffer = destination->inputBuffer; 
    401     UInt32 i, streamNumber, streamChannel; 
    402     for (i = streamNumber = streamChannel = 0; i < destination->inputChannelCount; ++i, ++streamChannel) { 
    403         if (streamChannel >= inputBuffer->mNumberChannels) { 
    404             ++streamNumber; 
    405             inputBuffer = &source->mBuffers[streamNumber]; 
    406             coreAudioBuffer = inputBuffer->mData; 
    407             streamChannel = 0; 
    408         } 
    409         destination->inputConverter(portAudioBuffer, frameSpacing, coreAudioBuffer, inputBuffer->mNumberChannels, frameCount, destination->ditherGenerator); 
    410         coreAudioBuffer += sizeof(Float32); 
    411         portAudioBuffer += Pa_GetSampleSize(destination->inputSampleFormat) * channelSpacing; 
    412     } 
    413     return 0; 
    414 } 
    415  
    416 static OSStatus CopyOutputData(AudioBufferList* destination, PaMacClientData *source, unsigned long frameCount) 
    417 { 
    418     int frameSpacing, channelSpacing; 
    419     if (source->outputSampleFormat & paNonInterleaved) { 
    420         frameSpacing = 1; 
    421         channelSpacing = source->outputChannelCount; 
    422     } 
    423     else { 
    424         frameSpacing = source->outputChannelCount; 
    425         channelSpacing = 1; 
    426     } 
    427      
    428     AudioBuffer *outputBuffer = &destination->mBuffers[0]; 
    429     void *coreAudioBuffer = outputBuffer->mData; 
    430     void *portAudioBuffer = source->outputBuffer; 
    431     UInt32 i, streamNumber, streamChannel; 
    432     for (i = streamNumber = streamChannel = 0; i < source->outputChannelCount; ++i, ++streamChannel) { 
    433         if (streamChannel >= outputBuffer->mNumberChannels) { 
    434             ++streamNumber; 
    435             outputBuffer = &destination->mBuffers[streamNumber]; 
    436             coreAudioBuffer = outputBuffer->mData; 
    437             streamChannel = 0; 
    438         } 
    439         source->outputConverter(coreAudioBuffer, outputBuffer->mNumberChannels, portAudioBuffer, frameSpacing, frameCount, NULL); 
    440         coreAudioBuffer += sizeof(Float32); 
    441         portAudioBuffer += Pa_GetSampleSize(source->outputSampleFormat) * channelSpacing; 
    442     }     
    443     return 0; 
    444 } 
    445  
    446 static OSStatus AudioIOProc( AudioDeviceID inDevice, 
    447                       const AudioTimeStamp* inNow, 
    448                       const AudioBufferList* inInputData, 
    449                       const AudioTimeStamp* inInputTime, 
    450                       AudioBufferList* outOutputData,  
    451                       const AudioTimeStamp* inOutputTime, 
    452                       void* inClientData) 
    453 { 
    454     PaMacClientData *clientData = (PaMacClientData *)inClientData; 
    455     PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime); 
    456      
    457     PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer ); 
    458      
    459     AudioBuffer *outputBuffer = &outOutputData->mBuffers[0]; 
    460     unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32)); 
    461  
    462     if (clientData->inputBuffer) { 
    463         CopyInputData(clientData, inInputData, frameCount); 
    464     } 
    465     PaStreamCallbackResult result = clientData->callback(clientData->inputBuffer, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData); 
    466     if (clientData->outputBuffer) { 
    467         CopyOutputData(outOutputData, clientData, frameCount); 
    468     } 
    469  
    470     PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount ); 
    471      
    472     if (result == paComplete || result == paAbort) { 
    473         Pa_StopStream(clientData->stream); 
    474     } 
    475     return 0; 
    476 } 
    477  
    478 // This is not for input-only streams, this is for streams where the input device is different from the output device 
    479 // TODO: This needs to store the output data in a buffer, to be written to the device the next time AudioOutputProc is called 
    480 static OSStatus AudioInputProc( AudioDeviceID inDevice, 
    481                          const AudioTimeStamp* inNow, 
    482                          const AudioBufferList* inInputData, 
    483                          const AudioTimeStamp* inInputTime, 
    484                          AudioBufferList* outOutputData,  
    485                          const AudioTimeStamp* inOutputTime, 
    486                          void* inClientData) 
    487 { 
    488     PaMacClientData *clientData = (PaMacClientData *)inClientData; 
    489     PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime); 
    490  
    491     PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer ); 
    492  
    493     AudioBuffer const *inputBuffer = &inInputData->mBuffers[0]; 
    494     unsigned long frameCount = inputBuffer->mDataByteSize / (inputBuffer->mNumberChannels * sizeof(Float32)); 
    495  
    496     CopyInputData(clientData, inInputData, frameCount); 
    497     clientData->callback(clientData->inputBuffer, NULL, frameCount, timeInfo, paNoFlag, clientData->userData); 
    498      
    499     PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount ); 
    500     return 0; 
    501 } 
    502  
    503 // This is not for output-only streams, this is for streams where the input device is different from the output device 
    504 static OSStatus AudioOutputProc( AudioDeviceID inDevice, 
    505                           const AudioTimeStamp* inNow, 
    506                           const AudioBufferList* inInputData, 
    507                           const AudioTimeStamp* inInputTime, 
    508                           AudioBufferList* outOutputData,  
    509                           const AudioTimeStamp* inOutputTime, 
    510                           void* inClientData) 
    511 { 
    512     PaMacClientData *clientData = (PaMacClientData *)inClientData; 
    513     PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime); 
    514  
    515     PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer ); 
    516  
    517     AudioBuffer *outputBuffer = &outOutputData->mBuffers[0]; 
    518     unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32)); 
    519  
    520     clientData->callback(NULL, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData); 
    521  
    522     CopyOutputData(outOutputData, clientData, frameCount); 
    523  
    524     PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount ); 
    525     return 0; 
    526 } 
    527  
    528 static PaError SetSampleRate(AudioDeviceID device, double sampleRate, int isInput) 
    529 { 
    530     PaError result = paNoError; 
    531      
    532     double actualSampleRate; 
    533     UInt32 propSize = sizeof(double); 
    534     result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyNominalSampleRate, propSize, &sampleRate)); 
    535      
    536     result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyNominalSampleRate, &propSize, &actualSampleRate)); 
    537      
    538     if (result == paNoError && actualSampleRate != sampleRate) { 
    539         result = paInvalidSampleRate; 
    540     } 
    541      
    542     return result;     
    543 } 
    544  
    545 static PaError SetFramesPerBuffer(AudioDeviceID device, unsigned long framesPerBuffer, int isInput) 
    546 { 
    547     PaError result = paNoError; 
    548     UInt32 preferredFramesPerBuffer = framesPerBuffer; 
    549     //    while (preferredFramesPerBuffer > UINT32_MAX) { 
    550     //        preferredFramesPerBuffer /= 2; 
    551     //    } 
    552      
    553     UInt32 actualFramesPerBuffer; 
    554     UInt32 propSize = sizeof(UInt32); 
    555     result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyBufferFrameSize, propSize, &preferredFramesPerBuffer)); 
    556      
    557     result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propSize, &actualFramesPerBuffer)); 
    558      
    559     if (result != paNoError) { 
    560         // do nothing 
    561     } 
    562     else if (actualFramesPerBuffer > framesPerBuffer) { 
    563         result = paBufferTooSmall; 
    564     } 
    565     else if (actualFramesPerBuffer < framesPerBuffer) { 
    566         result = paBufferTooBig; 
    567     } 
    568      
    569     return result;     
    570 } 
    571      
    572 static PaError SetUpUnidirectionalStream(AudioDeviceID device, double sampleRate, unsigned long framesPerBuffer, int isInput) 
    573 { 
    574     PaError err = paNoError; 
    575     err = SetSampleRate(device, sampleRate, isInput); 
    576     if( err == paNoError ) 
    577         err = SetFramesPerBuffer(device, framesPerBuffer, isInput); 
    578     return err; 
    579 } 
    580  
    581 // =====  PortAudio functions  ===== 
    582 #pragma mark PortAudio functions 
    583  
    584 #ifdef __cplusplus 
    585 extern "C" 
    586 { 
    587 #endif // __cplusplus 
    588      
    589     PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); 
    590      
    591 #ifdef __cplusplus 
    592 } 
    593 #endif // __cplusplus 
    594481 
    595482static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) 
    596483{ 
    597     PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi; 
    598      
    599     CleanUp(macCoreHostApi); 
     484    PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi; 
     485 
     486    VVDBUG(("Terminate()\n")); 
     487 
     488    /* 
     489        IMPLEMENT ME: 
     490            - clean up any resources not handled by the allocation group 
     491        TODO: Double check that everything is handled by alloc group 
     492    */ 
     493 
     494    if( auhalHostApi->allocations ) 
     495    { 
     496        PaUtil_FreeAllAllocations( auhalHostApi->allocations ); 
     497        PaUtil_DestroyAllocationGroup( auhalHostApi->allocations ); 
     498    } 
     499 
     500    PaUtil_FreeMemory( auhalHostApi ); 
    600501} 
     502 
    601503 
    602504static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, 
     
    605507                                  double sampleRate ) 
    606508{ 
    607     PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi; 
    608     PaDeviceInfo *deviceInfo; 
    609      
    610     PaError result = paNoError; 
    611     if (inputParameters) { 
    612         deviceInfo = macCoreHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device]; 
    613         if (inputParameters->channelCount > deviceInfo->maxInputChannels) 
    614             result = paInvalidChannelCount; 
    615         else if (CheckFormat(macCoreHostApi->macCoreDeviceIds[inputParameters->device], inputParameters, sampleRate, 1) != kAudioHardwareNoError) { 
    616             result = paInvalidSampleRate; 
    617         } 
    618     } 
    619     if (outputParameters && result == paNoError) { 
    620         deviceInfo = macCoreHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device]; 
    621         if (outputParameters->channelCount > deviceInfo->maxOutputChannels) 
    622             result = paInvalidChannelCount; 
    623         else if (CheckFormat(macCoreHostApi->macCoreDeviceIds[outputParameters->device], outputParameters, sampleRate, 0) != kAudioHardwareNoError) { 
    624             result = paInvalidSampleRate; 
    625         } 
    626     } 
    627  
    628     return result; 
     509    int inputChannelCount, outputChannelCount; 
     510    PaSampleFormat inputSampleFormat, outputSampleFormat; 
     511 
     512    VVDBUG(("IsFormatSupported(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld sampleRate=%g\n", 
     513                inputParameters  ? inputParameters->channelCount  : -1, 
     514                inputParameters  ? inputParameters->sampleFormat  : -1, 
     515                outputParameters ? outputParameters->channelCount : -1, 
     516                outputParameters ? outputParameters->sampleFormat : -1, 
     517                (float) sampleRate )); 
     518  
     519    /** These first checks are standard PA checks. We do some fancier checks 
     520        later. */ 
     521    if( inputParameters ) 
     522    { 
     523        inputChannelCount = inputParameters->channelCount; 
     524        inputSampleFormat = inputParameters->sampleFormat; 
     525 
     526        /* all standard sample formats are supported by the buffer adapter, 
     527            this implementation doesn't support any custom sample formats */ 
     528        if( inputSampleFormat & paCustomFormat ) 
     529            return paSampleFormatNotSupported; 
     530             
     531        /* unless alternate device specification is supported, reject the use of 
     532            paUseHostApiSpecificDeviceSpecification */ 
     533 
     534        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) 
     535            return paInvalidDevice; 
     536 
     537        /* check that input device can support inputChannelCount */ 
     538        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) 
     539            return paInvalidChannelCount; 
     540    } 
     541    else 
     542    { 
     543        inputChannelCount = 0; 
     544    } 
     545 
     546    if( outputParameters ) 
     547    { 
     548        outputChannelCount = outputParameters->channelCount; 
     549        outputSampleFormat = outputParameters->sampleFormat; 
     550 
     551        /* all standard sample formats are supported by the buffer adapter, 
     552            this implementation doesn't support any custom sample formats */ 
     553        if( outputSampleFormat & paCustomFormat ) 
     554            return paSampleFormatNotSupported; 
     555             
     556        /* unless alternate device specification is supported, reject the use of 
     557            paUseHostApiSpecificDeviceSpecification */ 
     558 
     559        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) 
     560            return paInvalidDevice; 
     561 
     562        /* check that output device can support outputChannelCount */ 
     563        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) 
     564            return paInvalidChannelCount; 
     565 
     566    } 
     567    else 
     568    { 
     569        outputChannelCount = 0; 
     570    } 
     571  
     572    /* FEEDBACK */ 
     573    /*        I think the only way to check a given format SR combo is     */ 
     574    /*        to try opening it. This could be disruptive, is that Okay?   */ 
     575    /*        The alternative is to just read off available sample rates,  */ 
     576    /*        but this will not work %100 of the time (eg, a device that   */ 
     577    /*        supports N output at one rate but only N/2 at a higher rate.)*/ 
     578 
     579    /* The following code opens the device with the requested parameters to 
     580       see if it works. */ 
     581    { 
     582       PaError err; 
     583       PaStream *s; 
     584       err = OpenStream( hostApi, &s, inputParameters, outputParameters, 
     585                           sampleRate, 1024, 0, (PaStreamCallback *)1, NULL ); 
     586       if( err != paNoError && err != paInvalidSampleRate ) 
     587          DBUG( ( "OpenStream @ %g returned: %d: %s\n", 
     588                  (float) sampleRate, err, Pa_GetErrorText( err ) ) ); 
     589       if( err )  
     590          return err; 
     591       err = CloseStream( s ); 
     592       if( err ) { 
     593          /* FEEDBACK: is this more serious? should we assert? */ 
     594          DBUG( ( "WARNING: could not close Stream. %d: %s\n", 
     595                  err, Pa_GetErrorText( err ) ) ); 
     596       } 
     597    } 
     598 
     599    return paFormatIsSupported; 
    629600} 
    630601 
     602static PaError OpenAndSetupOneAudioUnit( 
     603                                   const PaStreamParameters *inStreamParams, 
     604                                   const PaStreamParameters *outStreamParams, 
     605                                   const unsigned long requestedFramesPerBuffer, 
     606                                   unsigned long *actualInputFramesPerBuffer, 
     607                                   unsigned long *actualOutputFramesPerBuffer, 
     608                                   const PaMacAUHAL *auhalHostApi, 
     609                                   AudioUnit *audioUnit, 
     610                                   AudioConverterRef *srConverter, 
     611                                   AudioDeviceID *audioDevice, 
     612                                   const double sampleRate, 
     613                                   void *refCon ) 
     614{ 
     615    ComponentDescription desc; 
     616    Component comp; 
     617    /*An Apple TN suggests using CAStreamBasicDescription, but that is C++*/ 
     618    AudioStreamBasicDescription desiredFormat; 
     619    OSErr result = noErr; 
     620    PaError paResult = paNoError; 
     621    int line = 0; 
     622    UInt32 callbackKey; 
     623    AURenderCallbackStruct rcbs; 
     624    unsigned long macInputStreamFlags  = paMacCorePlayNice; 
     625    unsigned long macOutputStreamFlags = paMacCorePlayNice; 
     626 
     627    VVDBUG(("OpenAndSetupOneAudioUnit(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld, requestedFramesPerBuffer=%ld\n", 
     628                inStreamParams  ? inStreamParams->channelCount  : -1, 
     629                inStreamParams  ? inStreamParams->sampleFormat  : -1, 
     630                outStreamParams ? outStreamParams->channelCount : -1, 
     631                outStreamParams ? outStreamParams->sampleFormat : -1, 
     632                requestedFramesPerBuffer )); 
     633 
     634    /* -- handle the degenerate case  -- */ 
     635    if( !inStreamParams && !outStreamParams ) { 
     636       *audioUnit = NULL; 
     637       *audioDevice = kAudioDeviceUnknown; 
     638       return paNoError; 
     639    } 
     640 
     641    /* -- get the user's api specific info, if they set any -- */ 
     642    if( inStreamParams && inStreamParams->hostApiSpecificStreamInfo ) 
     643       macInputStreamFlags= 
     644            ((paMacCoreStreamInfo*)inStreamParams->hostApiSpecificStreamInfo) 
     645                  ->flags; 
     646    if( outStreamParams && outStreamParams->hostApiSpecificStreamInfo ) 
     647       macOutputStreamFlags= 
     648            ((paMacCoreStreamInfo*)outStreamParams->hostApiSpecificStreamInfo) 
     649                  ->flags; 
     650    /* Override user's flags here, if desired for testing. */ 
     651 
     652    /* 
     653     * The HAL AU is a Mac OS style "component". 
     654     * the first few steps deal with that. 
     655     * Later steps work on a combination of Mac OS 
     656     * components and the slightly lower level 
     657     * HAL. 
     658     */ 
     659 
     660    /* -- describe the output type AudioUnit -- */ 
     661    /*  Note: for the default AudioUnit, we could use the 
     662     *  componentSubType value kAudioUnitSubType_DefaultOutput; 
     663     *  but I don't think that's relevant here. 
     664     */ 
     665    desc.componentType         = kAudioUnitType_Output; 
     666    desc.componentSubType      = kAudioUnitSubType_HALOutput; 
     667    desc.componentManufacturer = kAudioUnitManufacturer_Apple; 
     668    desc.componentFlags        = 0; 
     669    desc.componentFlagsMask    = 0; 
     670    /* -- find the component -- */ 
     671    comp = FindNextComponent( NULL, &desc ); 
     672    if( !comp ) 
     673    { 
     674       DBUG( ( "AUHAL component not found." ) ); 
     675       *audioUnit = NULL; 
     676       *audioDevice = kAudioDeviceUnknown; 
     677       return paUnanticipatedHostError; 
     678    } 
     679    /* -- open it -- */ 
     680    result = OpenAComponent( comp, audioUnit ); 
     681    if( result ) 
     682    { 
     683       DBUG( ( "Failed to open AUHAL component." ) ); 
     684       *audioUnit = NULL; 
     685       *audioDevice = kAudioDeviceUnknown; 
     686       return ERR( result ); 
     687    } 
     688    /* -- prepare a little error handling logic / hackery -- */ 
     689#define ERR_WRAP(mac_err) do { result = mac_err ; line = __LINE__ ; if ( result != noErr ) goto error ; } while(0) 
     690 
     691    /* -- if there is input, we have to explicitly enable input -- */ 
     692    if( inStreamParams ) 
     693    { 
     694       UInt32 enableIO; 
     695       enableIO = 1; 
     696       ERR_WRAP( AudioUnitSetProperty( *audioUnit, 
     697                 kAudioOutputUnitProperty_EnableIO, 
     698                 kAudioUnitScope_Input, 
     699                 INPUT_ELEMENT, 
     700                 &enableIO, 
     701                 sizeof(enableIO) ) ); 
     702    } 
     703    /* -- if there is no output, we must explicitly disable output -- */ 
     704    if( !outStreamParams ) 
     705    { 
     706       UInt32 enableIO; 
     707       enableIO = 0; 
     708       ERR_WRAP( AudioUnitSetProperty( *audioUnit, 
     709                 kAudioOutputUnitProperty_EnableIO, 
     710                 kAudioUnitScope_Output, 
     711                 OUTPUT_ELEMENT, 
     712                 &enableIO, 
     713                 sizeof(enableIO) ) ); 
     714    } 
     715    /* -- set the devices -- */ 
     716    /* make sure input and output are the same device if we are doing input and 
     717       output. */ 
     718    if( inStreamParams && outStreamParams ) 
     719       assert( outStreamParams->device == inStreamParams->device ); 
     720    if( inStreamParams ) 
     721    { 
     722       *audioDevice = auhalHostApi->devIds[inStreamParams->device] ; 
     723       ERR_WRAP( AudioUnitSetProperty( *audioUnit, 
     724                    kAudioOutputUnitProperty_CurrentDevice, 
     725                    kAudioUnitScope_Global, 
     726                    INPUT_ELEMENT, 
     727                    audioDevice, 
     728                    sizeof(AudioDeviceID) ) ); 
     729    } 
     730    if( outStreamParams ) 
     731    { 
     732       *audioDevice = auhalHostApi->devIds[outStreamParams->device] ; 
     733       ERR_WRAP( AudioUnitSetProperty( *audioUnit, 
     734                    kAudioOutputUnitProperty_CurrentDevice, 
     735                    kAudioUnitScope_Global, 
     736                    OUTPUT_ELEMENT, 
     737                    audioDevice, 
     738                    sizeof(AudioDeviceID) ) ); 
     739    } 
     740 
     741    /* -- set format -- */ 
     742    bzero( &desiredFormat, sizeof(desiredFormat) ); 
     743    desiredFormat.mFormatID         = kAudioFormatLinearPCM ; 
     744    desiredFormat.mFormatFlags      = kAudioFormatFlagsNativeFloatPacked; 
     745    desiredFormat.mFramesPerPacket  = 1; 
     746    desiredFormat.mBitsPerChannel   = sizeof( float ) * 8; 
     747 
     748    result = 0; 
     749    /*  set device format first, but only touch the device if the user asked */ 
     750    if( inStreamParams ) { 
     751       /*The callback never calls back if we don't set the FPB */ 
     752       /*This seems wierd, because I would think setting anything on the device 
     753         would be disruptive.*/ 
     754       paResult = setBestFramesPerBuffer( *audioDevice, FALSE, 
     755                                          requestedFramesPerBuffer, 
     756                                          actualInputFramesPerBuffer ); 
     757       if( paResult ) goto error; 
     758       if( macInputStreamFlags & paMacCore_ChangeDeviceParameters ) { 
     759          bool requireExact; 
     760          requireExact=macInputStreamFlags&paMacCore_FailIfConversionRequired; 
     761          paResult = setBestSampleRateForDevice( *audioDevice, FALSE, 
     762                                                 requireExact, sampleRate ); 
     763          if( paResult ) goto error; 
     764       } 
     765       if( actualInputFramesPerBuffer && actualOutputFramesPerBuffer ) 
     766          *actualOutputFramesPerBuffer = *actualInputFramesPerBuffer ; 
     767    } 
     768    if( outStreamParams && !inStreamParams ) { 
     769       /*The callback never calls back if we don't set the FPB */ 
     770       /*This seems wierd, because I would think setting anything on the device 
     771         would be disruptive.*/ 
     772       paResult = setBestFramesPerBuffer( *audioDevice, TRUE, 
     773                                          requestedFramesPerBuffer, 
     774                                          actualOutputFramesPerBuffer ); 
     775       if( paResult ) goto error; 
     776       if( macOutputStreamFlags & paMacCore_ChangeDeviceParameters ) { 
     777          bool requireExact; 
     778          requireExact=macOutputStreamFlags&paMacCore_FailIfConversionRequired; 
     779          paResult = setBestSampleRateForDevice( *audioDevice, TRUE, 
     780                                                 requireExact, sampleRate ); 
     781          if( paResult ) goto error; 
     782       } 
     783    } 
     784 
     785    /* -- set the quality of the output converter -- */ 
     786    if( outStreamParams ) { 
     787       UInt32 value = kAudioConverterQuality_Max; 
     788       switch( macOutputStreamFlags & 0x0700 ) { 
     789       case 0x0100: /*paMacCore_ConversionQualityMin:*/ 
     790          value=kRenderQuality_Min; 
     791          break; 
     792       case 0x0200: /*paMacCore_ConversionQualityLow:*/ 
     793          value=kRenderQuality_Low; 
     794          break; 
     795       case 0x0300: /*paMacCore_ConversionQualityMedium:*/ 
     796          value=kRenderQuality_Medium; 
     797          break; 
     798       case 0x0400: /*paMacCore_ConversionQualityHigh:*/ 
     799          value=kRenderQuality_High; 
     800          break; 
     801       } 
     802       ERR_WRAP( AudioUnitSetProperty( *audioUnit, 
     803                    kAudioUnitProperty_RenderQuality, 
     804                    kAudioUnitScope_Global, 
     805                    OUTPUT_ELEMENT, 
     806                    &value, 
     807                    sizeof(value) ) ); 
     808    } 
     809    /* now set the format on the Audio Units. */ 
     810    if( outStreamParams ) 
     811    { 
     812       desiredFormat.mSampleRate    =sampleRate; 
     813       desiredFormat.mBytesPerPacket=sizeof(float)*outStreamParams->channelCount; 
     814       desiredFormat.mBytesPerFrame =sizeof(float)*outStreamParams->channelCount; 
     815       desiredFormat.mChannelsPerFrame = outStreamParams->channelCount; 
     816       ERR_WRAP( AudioUnitSetProperty( *audioUnit, 
     817                            kAudioUnitProperty_StreamFormat, 
     818                            kAudioUnitScope_Input, 
     819                            OUTPUT_ELEMENT, 
     820                            &desiredFormat, 
     821                            sizeof(AudioStreamBasicDescription) ) ); 
     822    } 
     823    if( inStreamParams ) 
     824    { 
     825       AudioStreamBasicDescription sourceFormat; 
     826       UInt32 size = sizeof( AudioStreamBasicDescription ); 
     827 
     828       /* keep the sample rate of the device, or we confuse AUHAL */ 
     829       ERR_WRAP( AudioUnitGetProperty( *audioUnit, 
     830                            kAudioUnitProperty_StreamFormat, 
     831                            kAudioUnitScope_Input, 
     832                            INPUT_ELEMENT, 
     833                            &sourceFormat, 
     834                            &size ) ); 
     835       desiredFormat.mSampleRate = sourceFormat.mSampleRate; 
     836       desiredFormat.mBytesPerPacket=sizeof(float)*inStreamParams->channelCount; 
     837       desiredFormat.mBytesPerFrame =sizeof(float)*inStreamParams->channelCount; 
     838       desiredFormat.mChannelsPerFrame = inStreamParams->channelCount; 
     839       ERR_WRAP( AudioUnitSetProperty( *audioUnit, 
     840                            kAudioUnitProperty_StreamFormat, 
     841                            kAudioUnitScope_Output, 
     842                            INPUT_ELEMENT, 
     843                            &desiredFormat, 
     844                            sizeof(AudioStreamBasicDescription) ) ); 
     845    } 
     846    /* set the maximumFramesPerSlice */ 
     847    /* not doing this causes real problems 
     848       (eg. the callback might not be called). The idea of setting both this 
     849       and the frames per buffer on the device is that we'll be most likely 
     850       to actually get the frame size we requested in the callback with the 
     851       minimum latency. */ 
     852    if( outStreamParams ) { 
     853       UInt32 size = sizeof( *actualOutputFramesPerBuffer ); 
     854       ERR_WRAP( AudioUnitSetProperty( *audioUnit, 
     855                            kAudioUnitProperty_MaximumFramesPerSlice, 
     856                            kAudioUnitScope_Input, 
     857                            OUTPUT_ELEMENT, 
     858                            actualOutputFramesPerBuffer, 
     859                            sizeof(unsigned long) ) ); 
     860       ERR_WRAP( AudioUnitGetProperty( *audioUnit, 
     861                            kAudioUnitProperty_MaximumFramesPerSlice, 
     862                            kAudioUnitScope_Global, 
     863                            OUTPUT_ELEMENT, 
     864                            actualOutputFramesPerBuffer, 
     865                            &size ) ); 
     866    } 
     867    if( inStreamParams ) { 
     868       /*UInt32 size = sizeof( *actualInputFramesPerBuffer );*/ 
     869       ERR_WRAP( AudioUnitSetProperty( *audioUnit, 
     870                            kAudioUnitProperty_MaximumFramesPerSlice, 
     871                            kAudioUnitScope_Output, 
     872                            INPUT_ELEMENT, 
     873                            actualInputFramesPerBuffer, 
     874                            sizeof(unsigned long) ) ); 
     875/* Don't know why this causes problems 
     876       ERR_WRAP( AudioUnitGetProperty( *audioUnit, 
     877                            kAudioUnitProperty_MaximumFramesPerSlice, 
     878                            kAudioUnitScope_Global, //Output, 
     879                            INPUT_ELEMENT, 
     880                            actualInputFramesPerBuffer, 
     881                            &size ) ); 
     882*/ 
     883    } 
     884 
     885    /* -- if we have input, we may need to setup an SR converter -- */ 
     886    /* even if we got the sample rate we asked for, we need to do 
     887       the conversion in case another program changes the underlying SR. */ 
     888    /* FIXME: I think we need to monitor stream and change the converter if the incoming format changes. */ 
     889    if( inStreamParams ) { 
     890       AudioStreamBasicDescription desiredFormat; 
     891       AudioStreamBasicDescription sourceFormat; 
     892       UInt32 sourceSize = sizeof( sourceFormat ); 
     893       bzero( &desiredFormat, sizeof(desiredFormat) ); 
     894       desiredFormat.mSampleRate       = sampleRate; 
     895       desiredFormat.mFormatID         = kAudioFormatLinearPCM ; 
     896       desiredFormat.mFormatFlags      = kAudioFormatFlagsNativeFloatPacked; 
     897       desiredFormat.mFramesPerPacket  = 1; 
     898       desiredFormat.mBitsPerChannel   = sizeof( float ) * 8; 
     899       desiredFormat.mBytesPerPacket=sizeof(float)*inStreamParams->channelCount; 
     900       desiredFormat.mBytesPerFrame =sizeof(float)*inStreamParams->channelCount; 
     901       desiredFormat.mChannelsPerFrame = inStreamParams->channelCount; 
     902 
     903       /* get the source format */ 
     904       ERR_WRAP( AudioUnitGetProperty( 
     905                         *audioUnit, 
     906                         kAudioUnitProperty_StreamFormat, 
     907                         kAudioUnitScope_Output, 
     908                         INPUT_ELEMENT, 
     909                         &sourceFormat, 
     910                         &sourceSize ) ); 
     911 
     912       if( desiredFormat.mSampleRate != sourceFormat.mSampleRate ) 
     913       { 
     914          UInt32 value = kAudioConverterQuality_Max; 
     915          switch( macInputStreamFlags & 0x0700 ) { 
     916          case 0x0100: /*paMacCore_ConversionQualityMin:*/ 
     917             value=kAudioConverterQuality_Min; 
     918             break; 
     919          case 0x0200: /*paMacCore_ConversionQualityLow:*/ 
     920             value=kAudioConverterQuality_Low; 
     921             break; 
     922          case 0x0300: /*paMacCore_ConversionQualityMedium:*/ 
     923             value=kAudioConverterQuality_Medium; 
     924             break; 
     925          case 0x0400: /*paMacCore_ConversionQualityHigh:*/ 
     926             value=kAudioConverterQuality_High; 
     927             break; 
     928          } 
     929          VDBUG(( "Creating sample rate converter for input" 
     930                  " to convert from %g to %g\n", 
     931                  (float)sourceFormat.mSampleRate, 
     932                  (float)desiredFormat.mSampleRate ) ); 
     933          /* create our converter */ 
     934          ERR_WRAP( AudioConverterNew(  
     935                             &sourceFormat, 
     936                             &desiredFormat, 
     937                             srConverter ) ); 
     938          /* Set quality */ 
     939          ERR_WRAP( AudioConverterSetProperty( 
     940                             *srConverter, 
     941                             kAudioConverterSampleRateConverterQuality, 
     942                             sizeof( value ), 
     943                             &value ) ); 
     944       } 
     945    } 
     946    /* -- set IOProc (callback) -- */ 
     947    callbackKey = outStreamParams ? kAudioUnitProperty_SetRenderCallback 
     948                                  : kAudioOutputUnitProperty_SetInputCallback ; 
     949    rcbs.inputProc = AudioIOProc; 
     950    rcbs.inputProcRefCon = refCon; 
     951    ERR_WRAP( AudioUnitSetProperty( 
     952                               *audioUnit, 
     953                               callbackKey, 
     954                               kAudioUnitScope_Output, 
     955                               outStreamParams ? OUTPUT_ELEMENT : INPUT_ELEMENT, 
     956                               &rcbs, 
     957                               sizeof(rcbs)) ); 
     958 
     959    if( inStreamParams && outStreamParams && *srConverter ) 
     960           ERR_WRAP( AudioUnitSetProperty( 
     961                               *audioUnit, 
     962                               kAudioOutputUnitProperty_SetInputCallback, 
     963                               kAudioUnitScope_Output, 
     964                               INPUT_ELEMENT, 
     965                               &rcbs, 
     966                               sizeof(rcbs)) ); 
     967 
     968    /*IMPLEMENTME: may need to worry about channel mapping.*/ 
     969 
     970    /* initialize the audio unit */ 
     971    ERR_WRAP( AudioUnitInitialize(*audioUnit) ); 
     972 
     973    if( inStreamParams && outStreamParams ) 
     974       VDBUG( ("Opened device %ld for input and output.\n", *audioDevice ) ); 
     975    else if( inStreamParams ) 
     976       VDBUG( ("Opened device %ld for input.\n", *audioDevice ) ); 
     977    else if( outStreamParams ) 
     978       VDBUG( ("Opened device %ld for output.\n", *audioDevice ) ); 
     979    return paNoError; 
     980#undef ERR_WRAP 
     981 
     982    error: 
     983       CloseComponent( *audioUnit ); 
     984       *audioUnit = NULL; 
     985       if( result ) 
     986          return PaMacCore_SetError( result, line, 1 ); 
     987       return paResult; 
     988} 
     989 
     990/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ 
    631991static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, 
    632992                           PaStream** s, 
     
    639999                           void *userData ) 
    6401000{ 
    641     PaError err = paNoError; 
    642     PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)hostApi; 
    643     PaMacCoreStream *stream = PaUtil_AllocateMemory(sizeof(PaMacCoreStream)); 
    644     stream->isActive = 0; 
    645     stream->isStopped = 1; 
    646     stream->inputDevice = kAudioDeviceUnknown; 
    647     stream->outputDevice = kAudioDeviceUnknown; 
    648      
    649     PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, 
    650                                            ( (streamCallback) 
    651                                              ? &macCoreHostApi->callbackStreamInterface 
    652                                              : &macCoreHostApi->blockingStreamInterface ), 
    653                                            streamCallback, userData ); 
     1001    PaError result = paNoError; 
     1002    PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi; 
     1003    PaMacCoreStream *stream = 0; 
     1004    int inputChannelCount, outputChannelCount; 
     1005    PaSampleFormat inputSampleFormat, outputSampleFormat; 
     1006    PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; 
     1007    VVDBUG(("OpenStream(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld SR=%g, FPB=%ld\n", 
     1008                inputParameters  ? inputParameters->channelCount  : -1, 
     1009                inputParameters  ? inputParameters->sampleFormat  : -1, 
     1010                outputParameters ? outputParameters->channelCount : -1, 
     1011                outputParameters ? outputParameters->sampleFormat : -1, 
     1012                (float) sampleRate, 
     1013                framesPerBuffer )); 
     1014    VDBUG( ("Opening Stream.\n") ); 
     1015 
     1016    /*These first few bits of code are from paSkeleton with few modifications.*/ 
     1017    if( inputParameters ) 
     1018    { 
     1019        inputChannelCount = inputParameters->channelCount; 
     1020        inputSampleFormat = inputParameters->sampleFormat; 
     1021 
     1022        /* unless alternate device specification is supported, reject the use of 
     1023            paUseHostApiSpecificDeviceSpecification */ 
     1024 
     1025        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) 
     1026            return paInvalidDevice; 
     1027 
     1028        /* check that input device can support inputChannelCount */ 
     1029        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) 
     1030            return paInvalidChannelCount; 
     1031 
     1032        /* Host supports interleaved float32 */ 
     1033        hostInputSampleFormat = paFloat32; 
     1034    } 
     1035    else 
     1036    { 
     1037        inputChannelCount = 0; 
     1038        inputSampleFormat = hostInputSampleFormat = paFloat32; /* Surpress 'uninitialised var' warnings. */ 
     1039    } 
     1040 
     1041    if( outputParameters ) 
     1042    { 
     1043        outputChannelCount = outputParameters->channelCount; 
     1044        outputSampleFormat = outputParameters->sampleFormat; 
     1045         
     1046        /* unless alternate device specification is supported, reject the use of 
     1047            paUseHostApiSpecificDeviceSpecification */ 
     1048 
     1049        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) 
     1050            return paInvalidDevice; 
     1051 
     1052        /* check that output device can support inputChannelCount */ 
     1053        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) 
     1054            return paInvalidChannelCount; 
     1055 
     1056        /* Host supports interleaved float32 */ 
     1057        hostOutputSampleFormat = paFloat32; 
     1058    } 
     1059    else 
     1060    { 
     1061        outputChannelCount = 0; 
     1062        outputSampleFormat = hostOutputSampleFormat = paFloat32; /* Surpress 'uninitialized var' warnings. */ 
     1063    } 
     1064 
     1065    /* validate platform specific flags */ 
     1066    if( (streamFlags & paPlatformSpecificFlags) != 0 ) 
     1067        return paInvalidFlag; /* unexpected platform specific flag */ 
     1068 
     1069    stream = (PaMacCoreStream*)PaUtil_AllocateMemory( sizeof(PaMacCoreStream) ); 
     1070    if( !stream ) 
     1071    { 
     1072        result = paInsufficientMemory; 
     1073        goto error; 
     1074    } 
     1075 
     1076    /* If we fail after this point, we my be left in a bad state, with 
     1077       some data structures setup and others not. So, first thing we 
     1078       do is initialize everything so that if we fail, we know what hasn't 
     1079       been touched. 
     1080     */ 
     1081 
     1082    stream->inputAudioBufferList.mBuffers[0].mData = NULL; 
     1083    stream->inputRingBuffer.buffer = NULL; 
     1084    bzero( &stream->blio, sizeof( PaMacBlio ) ); 
     1085/* 
     1086    stream->blio.inputRingBuffer.buffer = NULL; 
     1087    stream->blio.outputRingBuffer.buffer = NULL; 
     1088    stream->blio.inputSampleFormat = inputParameters?inputParameters->sampleFormat:0; 
     1089    stream->blio.inputSampleSize = computeSampleSizeFromFormat(stream->blio.inputSampleFormat); 
     1090    stream->blio.outputSampleFormat=outputParameters?outputParameters->sampleFormat:0; 
     1091    stream->blio.outputSampleSize = computeSampleSizeFromFormat(stream->blio.outputSampleFormat); 
     1092*/ 
     1093    stream->inputSRConverter = NULL; 
     1094    stream->inputUnit = NULL; 
     1095    stream->outputUnit = NULL; 
     1096    stream->inputFramesPerBuffer = 0; 
     1097    stream->outputFramesPerBuffer = 0; 
     1098    stream->bufferProcessorIsInitialized = FALSE; 
     1099 
     1100    /* assert( streamCallback ) ; */ /* only callback mode is implemented */ 
     1101    if( streamCallback ) 
     1102    { 
     1103        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, 
     1104                                        &auhalHostApi->callbackStreamInterface, 
     1105                                        streamCallback, userData ); 
     1106    } 
     1107    else 
     1108    { 
     1109        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, 
     1110                                        &auhalHostApi->blockingStreamInterface, 
     1111                                        BlioCallback, &stream->blio ); 
     1112    } 
     1113 
    6541114    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); 
    655      
     1115 
     1116    /* -- handle paFramesPerBufferUnspecified -- */ 
     1117    if( framesPerBuffer == paFramesPerBufferUnspecified ) { 
     1118       long requested = 64; 
     1119       if( inputParameters ) 
     1120          requested = MAX( requested, inputParameters->suggestedLatency * sampleRate / 2 ); 
     1121       if( outputParameters ) 
     1122          requested = MAX( requested, outputParameters->suggestedLatency *sampleRate / 2 ); 
     1123       VDBUG( ("Block Size unspecified. Based on Latency, the user wants a Block Size near: %ld.\n", 
     1124              requested ) ); 
     1125       if( requested <= 64 ) { 
     1126          /*requested a realtively low latency. make sure this is in range of devices */ 
     1127          /*try to get the device's min natural buffer size and use that (but no smaller than 64).*/ 
     1128          AudioValueRange audioRange; 
     1129          size_t size = sizeof( audioRange ); 
     1130          if( inputParameters ) { 
     1131             WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[inputParameters->device], 
     1132                                          0, 
     1133                                          false, 
     1134                                          kAudioDevicePropertyBufferFrameSizeRange, 
     1135                                          &size, &audioRange ) ); 
     1136             if( result ) 
     1137                requested = MAX( requested, audioRange.mMinimum ); 
     1138          } 
     1139          if( outputParameters ) { 
     1140             WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[outputParameters->device], 
     1141                                          0, 
     1142                                          false, 
     1143                                          kAudioDevicePropertyBufferFrameSizeRange, 
     1144                                          &size, &audioRange ) ); 
     1145             if( result ) 
     1146                requested = MAX( requested, audioRange.mMinimum ); 
     1147          } 
     1148       } else { 
     1149          /* requested a realtively high latency. make sure this is in range of devices */ 
     1150          /*try to get the device's max natural buffer size and use that (but no larger than 1024).*/ 
     1151          AudioValueRange audioRange; 
     1152          size_t size = sizeof( audioRange ); 
     1153          requested = MIN( requested, 1024 ); 
     1154          if( inputParameters ) { 
     1155             WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[inputParameters->device], 
     1156                                          0, 
     1157                                          false, 
     1158                                          kAudioDevicePropertyBufferFrameSizeRange, 
     1159                                          &size, &audioRange ) ); 
     1160             if( result ) 
     1161                requested = MIN( requested, audioRange.mMaximum ); 
     1162          } 
     1163          if( outputParameters ) { 
     1164             WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[outputParameters->device], 
     1165                                          0, 
     1166                                          false, 
     1167                                          kAudioDevicePropertyBufferFrameSizeRange, 
     1168                                          &size, &audioRange ) ); 
     1169             if( result ) 
     1170                requested = MIN( requested, audioRange.mMaximum ); 
     1171          } 
     1172       } 
     1173       /* -- double check ranges -- */ 
     1174       if( requested > 1024 ) requested = 1024; 
     1175       if( requested < 64 ) requested = 64; 
     1176       VDBUG(("After querying hardware, setting block size to %ld.\n", requested)); 
     1177       framesPerBuffer = requested; 
     1178    } 
     1179 
     1180    /* -- Now we actually open and setup streams. -- */ 
     1181    if( inputParameters && outputParameters && outputParameters->device == inputParameters->device ) 
     1182    { /* full duplex. One device. */ 
     1183       result = OpenAndSetupOneAudioUnit( inputParameters, 
     1184                                          outputParameters, 
     1185                                          framesPerBuffer, 
     1186                                          &(stream->inputFramesPerBuffer), 
     1187                                          &(stream->outputFramesPerBuffer), 
     1188                                          auhalHostApi, 
     1189                                          &(stream->inputUnit), 
     1190                                          &(stream->inputSRConverter), 
     1191                                          &(stream->inputDevice), 
     1192                                          sampleRate, 
     1193                                          stream ); 
     1194       stream->outputUnit = stream->inputUnit; 
     1195       stream->outputDevice = stream->inputDevice; 
     1196       if( result != paNoError ) 
     1197           goto error; 
     1198    } 
     1199    else 
     1200    { /* full duplex, different devices OR simplex */ 
     1201       result = OpenAndSetupOneAudioUnit( NULL, 
     1202                                          outputParameters, 
     1203                                          framesPerBuffer, 
     1204                                          NULL, 
     1205                                          &(stream->outputFramesPerBuffer), 
     1206                                          auhalHostApi, 
     1207                                          &(stream->outputUnit), 
     1208                                          NULL, 
     1209                                          &(stream->outputDevice), 
     1210                                          sampleRate, 
     1211                                          stream ); 
     1212       if( result != paNoError ) 
     1213           goto error; 
     1214       result = OpenAndSetupOneAudioUnit( inputParameters, 
     1215                                          NULL, 
     1216                                          framesPerBuffer, 
     1217                                          &(stream->inputFramesPerBuffer), 
     1218                                          NULL, 
     1219                                          auhalHostApi, 
     1220                                          &(stream->inputUnit), 
     1221                                          &(stream->inputSRConverter), 
     1222                                          &(stream->inputDevice), 
     1223                                          sampleRate, 
     1224                                          stream ); 
     1225       if( result != paNoError ) 
     1226           goto error; 
     1227    } 
     1228 
     1229    if( stream->inputUnit ) { 
     1230       const size_t szfl = sizeof(float); 
     1231       /* setup the AudioBufferList used for input */ 
     1232       bzero( &stream->inputAudioBufferList, sizeof( AudioBufferList ) ); 
     1233       stream->inputAudioBufferList.mNumberBuffers = 1; 
     1234       stream->inputAudioBufferList.mBuffers[0].mNumberChannels 
     1235                 = inputChannelCount; 
     1236       stream->inputAudioBufferList.mBuffers[0].mDataByteSize 
     1237                 = stream->inputFramesPerBuffer*inputChannelCount*szfl; 
     1238       stream->inputAudioBufferList.mBuffers[0].mData 
     1239                 = (float *) calloc( 
     1240                               stream->inputFramesPerBuffer*inputChannelCount, 
     1241                               szfl ); 
     1242       if( !stream->inputAudioBufferList.mBuffers[0].mData ) 
     1243       { 
     1244          result = paInsufficientMemory; 
     1245          goto error; 
     1246       } 
     1247         
     1248       /* 
     1249        * If input and output devs are different or we are doing SR conversion, 
     1250        * we also need a 
     1251        * ring buffer to store inpt data while waiting for output 
     1252        * data. 
     1253        */ 
     1254       if( (stream->outputUnit && stream->inputUnit != stream->outputUnit) 
     1255           || stream->inputSRConverter ) 
     1256       { 
     1257          /* May want the ringSize ot initial position in 
     1258             ring buffer to depend somewhat on sample rate change */ 
     1259 
     1260          void *data; 
     1261          long ringSize; 
     1262 
     1263          ringSize = computeRingBufferSize( inputParameters, 
     1264                                            outputParameters, 
     1265                                            stream->inputFramesPerBuffer, 
     1266                                            stream->outputFramesPerBuffer, 
     1267                                            sampleRate ); 
     1268          /*ringSize <<= 4; *//*16x bigger, for testing */ 
     1269 
     1270 
     1271          /*now, we need to allocate memory for the ring buffer*/ 
     1272          data = calloc( ringSize, szfl ); 
     1273          if( !data ) 
     1274          { 
     1275             result = paInsufficientMemory; 
     1276             goto error; 
     1277          } 
     1278 
     1279          /* now we can initialize the ring buffer */ 
     1280          assert( 0 == 
     1281            RingBuffer_Init( &stream->inputRingBuffer, 
     1282                             ringSize*szfl, data ) ); 
     1283          /* advance the read point a little, so we are reading from the 
     1284             middle of the buffer */ 
     1285          if( stream->outputUnit ) 
     1286             RingBuffer_AdvanceWriteIndex( &stream->inputRingBuffer, ringSize*szfl / RING_BUFFER_ADVANCE_DENOMINATOR ); 
     1287       } 
     1288    } 
     1289 
     1290    /* -- initialize Blio Buffer Processors -- */ 
     1291    if( !streamCallback ) 
     1292    { 
     1293       long ringSize; 
     1294 
     1295       ringSize = computeRingBufferSize( inputParameters, 
     1296                                         outputParameters, 
     1297                                         stream->inputFramesPerBuffer, 
     1298                                         stream->outputFramesPerBuffer, 
     1299                                         sampleRate ); 
     1300       result = initializeBlioRingBuffers( &stream->blio, 
     1301              inputParameters?inputParameters->sampleFormat:0 , 
     1302              outputParameters?outputParameters->sampleFormat:0 , 
     1303              MAX(stream->inputFramesPerBuffer,stream->outputFramesPerBuffer), 
     1304              ringSize, 
     1305              inputParameters?inputChannelCount:0 , 
     1306              outputParameters?outputChannelCount:0 ) ; 
     1307       if( result != paNoError ) 
     1308          goto error; 
     1309    } 
     1310 
     1311    /* -- initialize Buffer Processor -- */ 
     1312    { 
     1313       unsigned long maxHostFrames = stream->inputFramesPerBuffer; 
     1314       if( stream->outputFramesPerBuffer > maxHostFrames ) 
     1315          maxHostFrames = stream->outputFramesPerBuffer; 
     1316       result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, 
     1317                 inputChannelCount, inputSampleFormat, 
     1318                 hostInputSampleFormat, 
     1319                 outputChannelCount, outputSampleFormat, 
     1320                 hostOutputSampleFormat, 
     1321                 sampleRate, 
     1322                 streamFlags, 
     1323                 framesPerBuffer, 
     1324                 /* If sample rate conversion takes place, the buffer size 
     1325                    will not be known. */ 
     1326                 maxHostFrames, 
     1327                 stream->inputSRConverter 
     1328                              ? paUtilUnknownHostBufferSize 
     1329                              : paUtilBoundedHostBufferSize, 
     1330                 streamCallback ? streamCallback : BlioCallback, 
     1331                 streamCallback ? userData : &stream->blio ); 
     1332       if( result != paNoError ) 
     1333           goto error; 
     1334    } 
     1335    stream->bufferProcessorIsInitialized = TRUE; 
     1336 
     1337    /* 
     1338        IMPLEMENT ME: initialise the following fields with estimated or actual 
     1339        values. 
     1340        I think this is okay the way it is br 12/1/05 
     1341        maybe need to change input latency estimate if IO devs differ 
     1342    */ 
     1343    stream->streamRepresentation.streamInfo.inputLatency = 
     1344            PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)/sampleRate; 
     1345    stream->streamRepresentation.streamInfo.outputLatency = 
     1346            PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)/sampleRate; 
     1347    stream->streamRepresentation.streamInfo.sampleRate = sampleRate; 
     1348 
     1349    stream->sampleRate  = sampleRate; 
     1350    stream->outDeviceSampleRate = 0; 
     1351    if( stream->outputUnit ) { 
     1352       Float64 rate; 
     1353       UInt32 size = sizeof( rate ); 
     1354       result = ERR( AudioDeviceGetProperty( stream->outputDevice, 
     1355                                    0, 
     1356                                    FALSE, 
     1357                                    kAudioDevicePropertyNominalSampleRate, 
     1358                                    &size, &rate ) ); 
     1359       if( result ) 
     1360          goto error; 
     1361       stream->outDeviceSampleRate = rate; 
     1362    } 
     1363    stream->inDeviceSampleRate = 0; 
     1364    if( stream->inputUnit ) { 
     1365       Float64 rate; 
     1366       UInt32 size = sizeof( rate ); 
     1367       result = ERR( AudioDeviceGetProperty( stream->inputDevice, 
     1368                                    0, 
     1369                                    TRUE, 
     1370                                    kAudioDevicePropertyNominalSampleRate, 
     1371                                    &size, &rate ) ); 
     1372       if( result ) 
     1373          goto error; 
     1374       stream->inDeviceSampleRate = rate; 
     1375    } 
     1376    stream->userInChan  = inputChannelCount; 
     1377    stream->userOutChan = outputChannelCount; 
     1378 
     1379    stream->isTimeSet   = FALSE; 
     1380    stream->state = STOPPED; 
     1381    stream->xrunFlags = 0; 
     1382 
    6561383    *s = (PaStream*)stream; 
    657     PaMacClientData *clientData = PaUtil_AllocateMemory(sizeof(PaMacClientData)); 
    658     clientData->stream = stream; 
    659     clientData->callback = streamCallback; 
    660     clientData->userData = userData; 
    661     clientData->inputBuffer = 0; 
    662     clientData->outputBuffer = 0; 
    663     clientData->ditherGenerator = PaUtil_AllocateMemory(sizeof(PaUtilTriangularDitherGenerator)); 
    664     PaUtil_InitializeTriangularDitherState(clientData->ditherGenerator); 
    665      
    666     if (inputParameters != NULL) { 
    667         stream->inputDevice = macCoreHostApi->macCoreDeviceIds[inputParameters->device]; 
    668         clientData->inputConverter = PaUtil_SelectConverter(paFloat32, inputParameters->sampleFormat, streamFlags); 
    669         clientData->inputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(inputParameters->sampleFormat) * framesPerBuffer * inputParameters->channelCount); 
    670         clientData->inputChannelCount = inputParameters->channelCount; 
    671         clientData->inputSampleFormat = inputParameters->sampleFormat; 
    672         err = SetUpUnidirectionalStream(stream->inputDevice, sampleRate, framesPerBuffer, 1); 
    673     } 
    674      
    675     if (err == paNoError && outputParameters != NULL) { 
    676         stream->outputDevice = macCoreHostApi->macCoreDeviceIds[outputParameters->device]; 
    677         clientData->outputConverter = PaUtil_SelectConverter(outputParameters->sampleFormat, paFloat32, streamFlags); 
    678         clientData->outputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(outputParameters->sampleFormat) * framesPerBuffer * outputParameters->channelCount); 
    679         clientData->outputChannelCount = outputParameters->channelCount; 
    680         clientData->outputSampleFormat = outputParameters->sampleFormat; 
    681         err = SetUpUnidirectionalStream(stream->outputDevice, sampleRate, framesPerBuffer, 0); 
    682     } 
    683  
    684     if (inputParameters == NULL || outputParameters == NULL || stream->inputDevice == stream->outputDevice) { 
    685         AudioDeviceID device = (inputParameters == NULL) ? stream->outputDevice : stream->inputDevice; 
    686  
    687         AudioDeviceAddIOProc(device, AudioIOProc, clientData); 
    688     } 
    689     else { 
    690         // using different devices for input and output 
    691         AudioDeviceAddIOProc(stream->inputDevice, AudioInputProc, clientData); 
    692         AudioDeviceAddIOProc(stream->outputDevice, AudioOutputProc, clientData); 
    693     } 
    694      
    695     return err; 
     1384 
     1385    return result; 
     1386 
     1387error: 
     1388    CloseStream( stream ); 
     1389    return result; 
    6961390} 
    6971391 
    698 // Note: When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted. 
     1392PaTime GetStreamTime( PaStream *s ) 
     1393{ 
     1394   /* FIXME: I am not at all sure this timing info stuff is right. 
     1395             patest_sine_time reports negative latencies, which is wierd.*/ 
     1396    PaMacCoreStream *stream = (PaMacCoreStream*)s; 
     1397    AudioTimeStamp timeStamp; 
     1398 
     1399    VVDBUG(("GetStreamTime()\n")); 
     1400 
     1401    if ( !stream->isTimeSet ) 
     1402        return (PaTime)0; 
     1403 
     1404    if ( stream->outputDevice ) { 
     1405        AudioDeviceGetCurrentTime( stream->outputDevice, &timeStamp); 
     1406        return (PaTime)(timeStamp.mSampleTime - stream->startTime.mSampleTime)/stream->outDeviceSampleRate; 
     1407    } else if ( stream->inputDevice ) { 
     1408        AudioDeviceGetCurrentTime( stream->inputDevice, &timeStamp); 
     1409    return (PaTime)(timeStamp.mSampleTime - stream->startTime.mSampleTime)/stream->inDeviceSampleRate; 
     1410    } else { 
     1411        return (PaTime)0; 
     1412    } 
     1413} 
     1414 
     1415static void setStreamStartTime( PaStream *stream ) 
     1416{ 
     1417   /* FIXME: I am not at all sure this timing info stuff is right. 
     1418             patest_sine_time reports negative latencies, which is wierd.*/ 
     1419   PaMacCoreStream *s = (PaMacCoreStream *) stream; 
     1420   VVDBUG(("setStreamStartTime()\n")); 
     1421   if( s->outputDevice ) 
     1422      AudioDeviceGetCurrentTime( s->outputDevice, &s->startTime); 
     1423   else if( s->inputDevice ) 
     1424      AudioDeviceGetCurrentTime( s->inputDevice, &s->startTime); 
     1425   else 
     1426      bzero( &s->startTime, sizeof( s->startTime ) ); 
     1427 
     1428   //FIXME: we need a memory barier here 
     1429 
     1430   s->isTimeSet = TRUE; 
     1431} 
     1432 
     1433 
     1434static PaTime TimeStampToSecs(PaMacCoreStream *stream, const AudioTimeStamp* timeStamp) 
     1435{ 
     1436    VVDBUG(("TimeStampToSecs()\n")); 
     1437    //printf( "ATS: %lu, %g, %g\n", timeStamp->mFlags, timeStamp->mSampleTime, timeStamp->mRateScalar ); 
     1438    if (timeStamp->mFlags & kAudioTimeStampSampleTimeValid) 
     1439        return (timeStamp->mSampleTime / stream->sampleRate); 
     1440    else 
     1441        return 0; 
     1442} 
     1443 
     1444#define RING_BUFFER_EMPTY (1000) 
     1445 
     1446static OSStatus ringBufferIOProc( AudioConverterRef inAudioConverter,  
     1447                             UInt32*ioDataSize,  
     1448                             void** outData,  
     1449                             void*inUserData ) 
     1450{ 
     1451   void *dummyData; 
     1452   long dummySize; 
     1453   RingBuffer *rb = (RingBuffer *) inUserData; 
     1454 
     1455   VVDBUG(("ringBufferIOProc()\n")); 
     1456 
     1457   assert( sizeof( UInt32 ) == sizeof( long ) ); 
     1458   if( RingBuffer_GetReadAvailable( rb ) == 0 ) { 
     1459      *outData = NULL; 
     1460      *ioDataSize = 0; 
     1461      return RING_BUFFER_EMPTY; 
     1462   } 
     1463   RingBuffer_GetReadRegions( rb, *ioDataSize, 
     1464                              outData, (long *)ioDataSize,  
     1465                              &dummyData, &dummySize ); 
     1466       
     1467   assert( *ioDataSize ); 
     1468   RingBuffer_AdvanceReadIndex( rb, *ioDataSize ); 
     1469 
     1470   return noErr; 
     1471} 
     1472 
     1473/* 
     1474 * Called by the AudioUnit API to process audio from the sound card. 
     1475 * This is where the magic happens. 
     1476 */ 
     1477/* FEEDBACK: there is a lot of redundant code here because of how all the cases differ. This makes it hard to maintain, so if there are suggestinos for cleaning it up, I'm all ears. */ 
     1478static OSStatus AudioIOProc( void *inRefCon, 
     1479                               AudioUnitRenderActionFlags *ioActionFlags, 
     1480                               const AudioTimeStamp *inTimeStamp, 
     1481                               UInt32 inBusNumber, 
     1482                               UInt32 inNumberFrames, 
     1483                               AudioBufferList *ioData ) 
     1484{ 
     1485   unsigned long framesProcessed     = 0; 
     1486   PaStreamCallbackTimeInfo timeInfo = {0,0,0}; 
     1487   PaMacCoreStream *stream           = (PaMacCoreStream*)inRefCon; 
     1488   const bool isRender               = inBusNumber == OUTPUT_ELEMENT; 
     1489   int callbackResult                = paContinue ; 
     1490 
     1491   VVDBUG(("AudioIOProc()\n")); 
     1492 
     1493   PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); 
     1494 
     1495   /* -----------------------------------------------------------------*\ 
     1496      This output may be useful for debugging, 
     1497      But printing durring the callback is a bad enough idea that 
     1498      this is not enabled by enableing the usual debugging calls. 
     1499   \* -----------------------------------------------------------------*/ 
     1500   /* 
     1501   static int renderCount = 0; 
     1502   static int inputCount = 0; 
     1503   printf( "-------------------  starting reder/input\n" ); 
     1504   if( isRender ) 
     1505      printf("Render callback (%d):\t", ++renderCount); 
     1506   else 
     1507      printf("Input callback  (%d):\t", ++inputCount); 
     1508   printf( "Call totals: %d (input), %d (render)\n", inputCount, renderCount ); 
     1509 
     1510   printf( "--- inBusNumber: %lu\n", inBusNumber ); 
     1511   printf( "--- inNumberFrames: %lu\n", inNumberFrames ); 
     1512   printf( "--- %x ioData\n", (unsigned) ioData ); 
     1513   if( ioData ) 
     1514   { 
     1515      int i=0; 
     1516      printf( "--- ioData.mNumBuffers %lu: \n", ioData->mNumberBuffers ); 
     1517      for( i=0; i<ioData->mNumberBuffers; ++i ) 
     1518         printf( "--- ioData buffer %d size: %lu.\n", i, ioData->mBuffers[i].mDataByteSize ); 
     1519   } 
     1520      ----------------------------------------------------------------- */ 
     1521 
     1522   if( !stream->isTimeSet ) 
     1523      setStreamStartTime( stream ); 
     1524 
     1525   if( isRender ) { 
     1526      AudioTimeStamp currentTime; 
     1527      timeInfo.outputBufferDacTime = TimeStampToSecs(stream, inTimeStamp); 
     1528      AudioDeviceGetCurrentTime(stream->outputDevice, &currentTime); 
     1529      timeInfo.currentTime = TimeStampToSecs(stream, &currentTime); 
     1530   } 
     1531   if( isRender && stream->inputUnit == stream->outputUnit ) 
     1532      timeInfo.inputBufferAdcTime = TimeStampToSecs(stream, inTimeStamp); 
     1533   if( !isRender ) { 
     1534      AudioTimeStamp currentTime; 
     1535      timeInfo.inputBufferAdcTime = TimeStampToSecs(stream, inTimeStamp); 
     1536      AudioDeviceGetCurrentTime(stream->inputDevice, &currentTime); 
     1537      timeInfo.currentTime = TimeStampToSecs(stream, &currentTime); 
     1538   } 
     1539 
     1540   //printf( "---%g, %g, %g\n", timeInfo.inputBufferAdcTime, timeInfo.currentTime, timeInfo.outputBufferDacTime ); 
     1541 
     1542   if( isRender && stream->inputUnit == stream->outputUnit 
     1543                && !stream->inputSRConverter ) 
     1544   { 
     1545      /* --------- Full Duplex, One Device, no SR Conversion ------- 
     1546       * 
     1547       * This is the lowest latency case, and also the simplest. 
     1548       * Input data and output data are available at the same time. 
     1549       * we do not use the input SR converter or the input ring buffer. 
     1550       * 
     1551       */ 
     1552      OSErr err = 0; 
     1553      unsigned long frames; 
     1554 
     1555      /* -- start processing -- */ 
     1556      PaUtil_BeginBufferProcessing( &(stream->bufferProcessor), 
     1557                                    &timeInfo, 
     1558                                    stream->xrunFlags ); 
     1559      stream->xrunFlags = 0; 
     1560 
     1561      /* -- compute frames. do some checks -- */ 
     1562      assert( ioData->mNumberBuffers == 1 ); 
     1563      assert( ioData->mBuffers[0].mNumberChannels == stream->userOutChan ); 
     1564      frames = ioData->mBuffers[0].mDataByteSize; 
     1565      frames /= sizeof( float ) * ioData->mBuffers[0].mNumberChannels; 
     1566      /* -- copy and process input data -- */ 
     1567      err= AudioUnitRender(stream->inputUnit, 
     1568                    ioActionFlags, 
     1569                    inTimeStamp, 
     1570                    INPUT_ELEMENT, 
     1571                    inNumberFrames, 
     1572                    &stream->inputAudioBufferList ); 
     1573      /* FEEDBACK: I'm not sure what to do when this call fails */ 
     1574      assert( !err ); 
     1575 
     1576      PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames ); 
     1577      PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), 
     1578                          0, 
     1579                          stream->inputAudioBufferList.mBuffers[0].mData, 
     1580                          stream->inputAudioBufferList.mBuffers[0].mNumberChannels); 
     1581      /* -- Copy and process output data -- */ 
     1582      PaUtil_SetOutputFrameCount( &(stream->bufferProcessor), frames ); 
     1583      PaUtil_SetInterleavedOutputChannels( &(stream->bufferProcessor), 
     1584                                        0, 
     1585                                        ioData->mBuffers[0].mData, 
     1586                                        ioData->mBuffers[0].mNumberChannels); 
     1587      /* -- complete processing -- */ 
     1588      framesProcessed = 
     1589                 PaUtil_EndBufferProcessing( &(stream->bufferProcessor), 
     1590                                             &callbackResult ); 
     1591   } 
     1592   else if( isRender ) 
     1593   { 
     1594      /* -------- Output Side of Full Duplex (Separate Devices or SR Conversion) 
     1595       *       -- OR Simplex Output 
     1596       * 
     1597       * This case handles output data as in the full duplex case, 
     1598       * and, if there is input data, reads it off the ring buffer  
     1599       * and into the PA buffer processor. If sample rate conversion 
     1600       * is required on input, that is done here as well. 
     1601       */ 
     1602      unsigned long frames; 
     1603 
     1604      /* Sometimes, when stopping a duplex stream we get erroneous 
     1605         xrun flags, so if this is our last run, clear the flags. */ 
     1606      int xrunFlags = stream->xrunFlags; 
     1607/* 
     1608      if( xrunFlags & paInputUnderflow ) 
     1609         printf( "input underflow.\n" ); 
     1610      if( xrunFlags & paInputOverflow ) 
     1611         printf( "input overflow.\n" ); 
     1612*/ 
     1613      if( stream->state == STOPPING || stream->state == CALLBACK_STOPPED ) 
     1614         xrunFlags = 0; 
     1615 
     1616      /* -- start processing -- */ 
     1617      PaUtil_BeginBufferProcessing( &(stream->bufferProcessor), 
     1618                                    &timeInfo, 
     1619                                    xrunFlags ); 
     1620      stream->xrunFlags = 0; /* FEEDBACK: we only send flags to Buf Proc once */ 
     1621 
     1622      /* -- Copy and process output data -- */ 
     1623      assert( ioData->mNumberBuffers == 1 ); 
     1624      frames = ioData->mBuffers[0].mDataByteSize; 
     1625      frames /= sizeof( float ) * ioData->mBuffers[0].mNumberChannels; 
     1626      assert( ioData->mBuffers[0].mNumberChannels == stream->userOutChan ); 
     1627      PaUtil_SetOutputFrameCount( &(stream->bufferProcessor), frames ); 
     1628      PaUtil_SetInterleavedOutputChannels( &(stream->bufferProcessor), 
     1629                                     0, 
     1630                                     ioData->mBuffers[0].mData, 
     1631                                     ioData->mBuffers[0].mNumberChannels); 
     1632 
     1633      /* -- copy and process input data, and complete processing -- */ 
     1634      if( stream->inputUnit ) { 
     1635         const int flsz = sizeof( float ); 
     1636         /* Here, we read the data out of the ring buffer, through the 
     1637            audio converter. */ 
     1638         int inChan = stream->inputAudioBufferList.mBuffers[0].mNumberChannels; 
     1639         if( stream->inputSRConverter ) 
     1640         { 
     1641               OSStatus err; 
     1642               UInt32 size; 
     1643               float data[ inChan * frames ]; 
     1644               size = sizeof( data ); 
     1645               err = AudioConverterFillBuffer(  
     1646                             stream->inputSRConverter, 
     1647                             ringBufferIOProc, 
     1648                             &stream->inputRingBuffer, 
     1649                             &size, 
     1650                             (void *)&data ); 
     1651               if( err == RING_BUFFER_EMPTY ) 
     1652               { /*the ring buffer callback underflowed */ 
     1653                  err = 0; 
     1654                  bzero( ((char *)data) + size, sizeof(data)-size ); 
     1655                  stream->xrunFlags |= paInputUnderflow; 
     1656               } 
     1657               ERR( err ); 
     1658               assert( !err ); 
     1659                
     1660               PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames ); 
     1661               PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), 
     1662                                   0, 
     1663                                   data, 
     1664                                   inChan ); 
     1665               framesProcessed = 
     1666                    PaUtil_EndBufferProcessing( &(stream->bufferProcessor), 
     1667                                                &callbackResult ); 
     1668         } 
     1669         else 
     1670         { 
     1671            /* Without the AudioConverter is actually a bit more complex 
     1672               because we have to do a little buffer processing that the 
     1673               AudioConverter would otherwise handle for us. */ 
     1674            void *data1, *data2; 
     1675            long size1, size2; 
     1676            RingBuffer_GetReadRegions( &stream->inputRingBuffer, 
     1677                                       inChan*frames*flsz, 
     1678                                       &data1, &size1, 
     1679                                       &data2, &size2 ); 
     1680            if( size1 / ( flsz * inChan ) == frames ) { 
     1681               /* simplest case: all in first buffer */ 
     1682               PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames ); 
     1683               PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), 
     1684                                   0, 
     1685                                   data1, 
     1686                                   inChan ); 
     1687               framesProcessed = 
     1688                    PaUtil_EndBufferProcessing( &(stream->bufferProcessor), 
     1689                                                &callbackResult ); 
     1690               RingBuffer_AdvanceReadIndex(&stream->inputRingBuffer, size1 ); 
     1691            } else if( ( size1 + size2 ) / ( flsz * inChan ) < frames ) { 
     1692               /*we underflowed. take what data we can, zero the rest.*/ 
     1693               float data[frames*inChan]; 
     1694               if( size1 ) 
     1695                  memcpy( data, data1, size1 ); 
     1696               if( size2 ) 
     1697                  memcpy( data+size1, data2, size2 ); 
     1698               bzero( data+size1+size2, frames*flsz*inChan - size1 - size2 ); 
     1699 
     1700               PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames ); 
     1701               PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), 
     1702                                   0, 
     1703                                   data, 
     1704                                   inChan ); 
     1705               framesProcessed = 
     1706                    PaUtil_EndBufferProcessing( &(stream->bufferProcessor), 
     1707                                                &callbackResult ); 
     1708               RingBuffer_AdvanceReadIndex( &stream->inputRingBuffer, 
     1709                                            size1+size2 ); 
     1710               /* flag underflow */ 
     1711               stream->xrunFlags |= paInputUnderflow; 
     1712            } else { 
     1713               /*we got all the data, but split between buffers*/ 
     1714               PaUtil_SetInputFrameCount( &(stream->bufferProcessor), 
     1715                                          size1 / ( flsz * inChan ) ); 
     1716               PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), 
     1717                                   0, 
     1718                                   data1, 
     1719                                   inChan ); 
     1720               PaUtil_Set2ndInputFrameCount( &(stream->bufferProcessor), 
     1721                                             size2 / ( flsz * inChan ) ); 
     1722               PaUtil_Set2ndInterleavedInputChannels( &(stream->bufferProcessor), 
     1723                                   0, 
     1724                                   data2, 
     1725                                   inChan ); 
     1726               framesProcessed = 
     1727                    PaUtil_EndBufferProcessing( &(stream->bufferProcessor), 
     1728                                                &callbackResult ); 
     1729               RingBuffer_AdvanceReadIndex(&stream->inputRingBuffer, size1+size2 ); 
     1730            } 
     1731         } 
     1732      } else { 
     1733         framesProcessed = 
     1734                 PaUtil_EndBufferProcessing( &(stream->bufferProcessor), 
     1735                                             &callbackResult ); 
     1736      } 
     1737 
     1738   } 
     1739   else 
     1740   { 
     1741      /* ------------------ Input 
     1742       * 
     1743       * First, we read off the audio data and put it in the ring buffer. 
     1744       * if this is an input-only stream, we need to process it more, 
     1745       * otherwise, we let the output case deal with it. 
     1746       */ 
     1747      OSErr err = 0; 
     1748      int chan = stream->inputAudioBufferList.mBuffers[0].mNumberChannels ; 
     1749      /* FIXME: looping here may not actually be necessary, but it was something I tried in testing. */ 
     1750      do { 
     1751         err= AudioUnitRender(stream->inputUnit, 
     1752                 ioActionFlags, 
     1753                 inTimeStamp, 
     1754                 INPUT_ELEMENT, 
     1755                 inNumberFrames, 
     1756                 &stream->inputAudioBufferList ); 
     1757         if( err == -10874 ) 
     1758            inNumberFrames /= 2; 
     1759      } while( err == -10874 && inNumberFrames > 1 ); 
     1760      /* FEEDBACK: I'm not sure what to do when this call fails */ 
     1761      ERR( err ); 
     1762      assert( !err ); 
     1763      if( stream->inputSRConverter || stream->outputUnit ) 
     1764      { 
     1765         /* If this is duplex or we use a converter, put the data 
     1766            into the ring buffer. */ 
     1767         long bytesIn, bytesOut; 
     1768         bytesIn = sizeof( float ) * inNumberFrames * chan; 
     1769         bytesOut = RingBuffer_Write( &stream->inputRingBuffer, 
     1770                                stream->inputAudioBufferList.mBuffers[0].mData, 
     1771                                bytesIn ); 
     1772         if( bytesIn != bytesOut ) 
     1773            stream->xrunFlags |= paInputOverflow ; 
     1774      } 
     1775      else 
     1776      { 
     1777         /* for simplex input w/o SR conversion, 
     1778            just pop the data into the buffer processor.*/ 
     1779         PaUtil_BeginBufferProcessing( &(stream->bufferProcessor), 
     1780                              &timeInfo, 
     1781                              stream->xrunFlags ); 
     1782         stream->xrunFlags = 0; 
     1783 
     1784         PaUtil_SetInputFrameCount( &(stream->bufferProcessor), inNumberFrames); 
     1785         PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), 
     1786                             0, 
     1787                             stream->inputAudioBufferList.mBuffers[0].mData, 
     1788                             chan ); 
     1789         framesProcessed = 
     1790              PaUtil_EndBufferProcessing( &(stream->bufferProcessor), 
     1791                                          &callbackResult ); 
     1792      } 
     1793      if( !stream->outputUnit && stream->inputSRConverter ) 
     1794      { 
     1795         /* ------------------ Simplex Input w/ SR Conversion 
     1796          * 
     1797          * if this is a simplex input stream, we need to read off the buffer, 
     1798          * do our sample rate conversion and pass the results to the buffer 
     1799          * processor. 
     1800          * The logic here is complicated somewhat by the fact that we don't 
     1801          * know how much data is available, so we loop on reasonably sized 
     1802          * chunks, and let the BufferProcessor deal with the rest. 
     1803          * 
     1804          */ 
     1805         /*This might be too big or small depending on SR conversion*/ 
     1806         float data[ chan * inNumberFrames ]; 
     1807         OSStatus err; 
     1808         do 
     1809         { /*Run the buffer processor until we are out of data*/ 
     1810            UInt32 size; 
     1811            long f; 
     1812 
     1813            size = sizeof( data ); 
     1814            err = AudioConverterFillBuffer(  
     1815                          stream->inputSRConverter, 
     1816                          ringBufferIOProc, 
     1817                          &stream->inputRingBuffer, 
     1818                          &size, 
     1819                          (void *)data ); 
     1820            if( err != RING_BUFFER_EMPTY ) 
     1821               ERR( err ); 
     1822            assert( err == 0 || err == RING_BUFFER_EMPTY ); 
     1823 
     1824            f = size / ( chan * sizeof(float) ); 
     1825            PaUtil_SetInputFrameCount( &(stream->bufferProcessor), f ); 
     1826            if( f ) 
     1827            { 
     1828               PaUtil_BeginBufferProcessing( &(stream->bufferProcessor), 
     1829                                             &timeInfo, 
     1830                                             stream->xrunFlags ); 
     1831               stream->xrunFlags = 0; 
     1832 
     1833               PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), 
     1834                                0, 
     1835                                data, 
     1836                                chan ); 
     1837               framesProcessed = 
     1838                    PaUtil_EndBufferProcessing( &(stream->bufferProcessor), 
     1839                                                &callbackResult ); 
     1840            } 
     1841         } while( callbackResult == paContinue && !err ); 
     1842      } 
     1843   } 
     1844 
     1845   switch( callbackResult ) 
     1846   { 
     1847   case paContinue: break; 
     1848   case paComplete: 
     1849   case paAbort: 
     1850      stream->isTimeSet = FALSE; 
     1851      stream->state = CALLBACK_STOPPED ; 
     1852      if( stream->outputUnit ) 
     1853         AudioOutputUnitStop(stream->outputUnit); 
     1854      if( stream->inputUnit ) 
     1855         AudioOutputUnitStop(stream->inputUnit); 
     1856      break; 
     1857   } 
     1858 
     1859   PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); 
     1860   return noErr; 
     1861} 
     1862 
     1863 
     1864/* 
     1865    When CloseStream() is called, the multi-api layer ensures that 
     1866    the stream has already been stopped or aborted. 
     1867*/ 
    6991868static PaError CloseStream( PaStream* s ) 
    7001869{ 
    701     PaError err = paNoError; 
     1870    /* This may be called from a failed OpenStream. 
     1871       Therefore, each piece of info is treated seperately. */ 
     1872    PaError result = paNoError; 
    7021873    PaMacCoreStream *stream = (PaMacCoreStream*)s; 
    7031874 
    704     PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer ); 
    705  
    706     if (stream->inputDevice != kAudioDeviceUnknown) { 
    707         if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) { 
    708             err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioIOProc)); 
    709         } 
    710         else { 
    711             err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioInputProc)); 
    712             err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioOutputProc)); 
    713         } 
    714     } 
    715     else { 
    716         err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioIOProc)); 
    717     } 
    718      
    719     return err; 
     1875    VVDBUG(("CloseStream()\n")); 
     1876    VDBUG( ( "Closing stream.\n" ) ); 
     1877 
     1878    if( stream ) { 
     1879       if( stream->outputUnit && stream->outputUnit != stream->inputUnit ) { 
     1880          AudioUnitUninitialize( stream->outputUnit ); 
     1881          CloseComponent( stream->outputUnit ); 
     1882       } 
     1883       stream->outputUnit = NULL; 
     1884       if( stream->inputUnit ) 
     1885       { 
     1886          AudioUnitUninitialize( stream->inputUnit ); 
     1887          CloseComponent( stream->inputUnit ); 
     1888          stream->inputUnit = NULL; 
     1889       } 
     1890       if( stream->inputRingBuffer.buffer ) 
     1891          free( (void *) stream->inputRingBuffer.buffer ); 
     1892       stream->inputRingBuffer.buffer = NULL; 
     1893       /*TODO: is there more that needs to be done on error 
     1894               from AudioConverterDispose?*/ 
     1895       if( stream->inputSRConverter ) 
     1896          ERR( AudioConverterDispose( stream->inputSRConverter ) ); 
     1897       stream->inputSRConverter = NULL; 
     1898       if( stream->inputAudioBufferList.mBuffers[0].mData ) 
     1899          free( stream->inputAudioBufferList.mBuffers[0].mData ); 
     1900       stream->inputAudioBufferList.mBuffers[0].mData = NULL; 
     1901 
     1902       result = destroyBlioRingBuffers( &stream->blio ); 
     1903       if( result ) 
     1904          return result; 
     1905       if( stream->bufferProcessorIsInitialized ) 
     1906          PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); 
     1907       PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); 
     1908       PaUtil_FreeMemory( stream ); 
     1909    } 
     1910 
     1911    return result; 
    7201912} 
    7211913 
     
    7231915static PaError StartStream( PaStream *s ) 
    7241916{ 
    725     PaError err = paNoError; 
    7261917    PaMacCoreStream *stream = (PaMacCoreStream*)s; 
    727  
    728     if (stream->inputDevice != kAudioDeviceUnknown) { 
    729         if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) { 
    730             err = conv_err(AudioDeviceStart(stream->inputDevice, AudioIOProc)); 
    731         } 
    732         else { 
    733             err = conv_err(AudioDeviceStart(stream->inputDevice, AudioInputProc)); 
    734             err = conv_err(AudioDeviceStart(stream->outputDevice, AudioOutputProc)); 
    735         } 
    736     } 
    737     else { 
    738         err = conv_err(AudioDeviceStart(stream->outputDevice, AudioIOProc)); 
    739     } 
    740      
    741     stream->isActive = 1; 
    742     stream->isStopped = 0; 
    743     return err; 
     1918    OSErr result = noErr; 
     1919    VVDBUG(("StartStream()\n")); 
     1920    VDBUG( ( "Starting stream.\n" ) ); 
     1921 
     1922#define ERR_WRAP(mac_err) do { result = mac_err ; if ( result != noErr ) return ERR(result) ; } while(0) 
     1923 
     1924    /*FIXME: maybe want to do this on close/abort for faster start? */ 
     1925    PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); 
     1926    if(  stream->inputSRConverter ) 
     1927       ERR_WRAP( AudioConverterReset( stream->inputSRConverter ) ); 
     1928 
     1929    /* -- start -- */ 
     1930    stream->state = ACTIVE; 
     1931    if( stream->inputUnit ) { 
     1932       ERR_WRAP( AudioOutputUnitStart(stream->inputUnit) ); 
     1933    } 
     1934    if( stream->outputUnit && stream->outputUnit != stream->inputUnit ) { 
     1935       ERR_WRAP( AudioOutputUnitStart(stream->outputUnit) ); 
     1936    } 
     1937 
     1938    //setStreamStartTime( stream ); 
     1939    //stream->isTimeSet = TRUE; 
     1940 
     1941    return paNoError; 
     1942#undef ERR_WRAP 
     1943} 
     1944 
     1945 
     1946static PaError StopStream( PaStream *s ) 
     1947{ 
     1948    PaMacCoreStream *stream = (PaMacCoreStream*)s; 
     1949    OSErr result = noErr; 
     1950    PaError paErr; 
     1951    VVDBUG(("StopStream()\n")); 
     1952 
     1953    VDBUG( ("Waiting for BLIO.\n") ); 
     1954    waitUntilBlioWriteBufferIsFlushed( &stream->blio ); 
     1955    VDBUG( ( "Stopping stream.\n" ) ); 
     1956 
     1957    stream->isTimeSet = FALSE; 
     1958    stream->state = STOPPING; 
     1959 
     1960#define ERR_WRAP(mac_err) do { result = mac_err ; if ( result != noErr ) return ERR(result) ; } while(0) 
     1961    /* -- stop and reset -- */ 
     1962    if( stream->inputUnit == stream->outputUnit && stream->inputUnit ) 
     1963    { 
     1964       ERR_WRAP( AudioOutputUnitStop(stream->inputUnit) ); 
     1965       ERR_WRAP( AudioUnitReset(stream->inputUnit, kAudioUnitScope_Global, 1) ); 
     1966       ERR_WRAP( AudioUnitReset(stream->inputUnit, kAudioUnitScope_Global, 0) ); 
     1967    } 
     1968    else 
     1969    { 
     1970       if( stream->inputUnit ) 
     1971       { 
     1972          ERR_WRAP(AudioOutputUnitStop(stream->inputUnit) ); 
     1973          ERR_WRAP(AudioUnitReset(stream->inputUnit,kAudioUnitScope_Global,1)); 
     1974       } 
     1975       if( stream->outputUnit ) 
     1976       { 
     1977          ERR_WRAP(AudioOutputUnitStop(stream->outputUnit)); 
     1978          ERR_WRAP(AudioUnitReset(stream->outputUnit,kAudioUnitScope_Global,0)); 
     1979       } 
     1980    } 
     1981    if( stream->inputRingBuffer.buffer ) { 
     1982       RingBuffer_Flush( &stream->inputRingBuffer ); 
     1983       bzero( (void *)stream->inputRingBuffer.buffer, 
     1984              stream->inputRingBuffer.bufferSize ); 
     1985       /* advance the write point a little, so we are reading from the 
     1986          middle of the buffer. We'll need extra at the end because 
     1987          testing has shown that this helps. */ 
     1988       if( stream->outputUnit ) 
     1989          RingBuffer_AdvanceWriteIndex( &stream->inputRingBuffer, 
     1990                                    stream->inputRingBuffer.bufferSize 
     1991                                           / RING_BUFFER_ADVANCE_DENOMINATOR ); 
     1992    } 
     1993 
     1994    stream->xrunFlags = 0; 
     1995    stream->state = STOPPED; 
     1996 
     1997    paErr = resetBlioRingBuffers( &stream->blio ); 
     1998    if( paErr ) 
     1999       return paErr; 
     2000 
     2001/* 
     2002    //stream->isTimeSet = FALSE; 
     2003*/ 
     2004 
     2005    VDBUG( ( "Stream Stopped.\n" ) ); 
     2006    return paNoError; 
     2007#undef ERR_WRAP 
    7442008} 
    7452009 
    7462010static PaError AbortStream( PaStream *s ) 
    7472011{ 
    748     PaError err = paNoError; 
    749     PaMacCoreStream *stream = (PaMacCoreStream*)s; 
    750      
    751     if (stream->inputDevice != kAudioDeviceUnknown) { 
    752         if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) { 
    753             err = conv_err(AudioDeviceStop(stream->inputDevice, AudioIOProc)); 
    754         } 
    755         else { 
    756             err = conv_err(AudioDeviceStop(stream->inputDevice, AudioInputProc)); 
    757             err = conv_err(AudioDeviceStop(stream->outputDevice, AudioOutputProc)); 
    758         } 
    759     } 
    760     else { 
    761         err = conv_err(AudioDeviceStop(stream->outputDevice, AudioIOProc)); 
    762     } 
    763      
    764     stream->isActive = 0; 
    765     stream->isStopped = 1; 
    766     return err; 
    767 }     
    768  
    769 static PaError StopStream( PaStream *s ) 
    770 { 
    771     // TODO: this should be nicer than abort 
    772     return AbortStream(s); 
     2012    VVDBUG(("AbortStream()->StopStream()\n")); 
     2013    VDBUG( ( "Aborting stream.\n" ) ); 
     2014    /* We have nothing faster than StopStream. */ 
     2015    return StopStream(s); 
    7732016} 
     2017 
    7742018 
    7752019static PaError IsStreamStopped( PaStream *s ) 
    7762020{ 
    7772021    PaMacCoreStream *stream = (PaMacCoreStream*)s; 
    778      
    779     return stream->isStopped; 
     2022    VVDBUG(("IsStreamStopped()\n")); 
     2023 
     2024    return stream->state == STOPPED ? 1 : 0; 
    7802025} 
    7812026 
     
    7842029{ 
    7852030    PaMacCoreStream *stream = (PaMacCoreStream*)s; 
    786  
    787     return stream->isActive; 
    788 } 
    789  
    790  
    791 static PaTime GetStreamTime( PaStream *s ) 
    792 { 
    793     OSStatus err; 
    794     PaTime result; 
    795     PaMacCoreStream *stream = (PaMacCoreStream*)s; 
    796  
    797     AudioTimeStamp *timeStamp = PaUtil_AllocateMemory(sizeof(AudioTimeStamp)); 
    798     if (stream->inputDevice != kAudioDeviceUnknown) { 
    799         err = AudioDeviceGetCurrentTime(stream->inputDevice, timeStamp); 
    800     } 
    801     else { 
    802         err = AudioDeviceGetCurrentTime(stream->outputDevice, timeStamp); 
    803     } 
    804      
    805     result = err ? 0 : timeStamp->mSampleTime; 
    806     PaUtil_FreeMemory(timeStamp); 
    807  
    808     return result; 
     2031    VVDBUG(("IsStreamActive()\n")); 
     2032    return ( stream->state == ACTIVE || stream->state == STOPPING ); 
    8092033} 
    8102034 
     
    8132037{ 
    8142038    PaMacCoreStream *stream = (PaMacCoreStream*)s; 
    815      
     2039    VVDBUG(("GetStreamCpuLoad()\n")); 
     2040 
    8162041    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); 
    8172042} 
    818  
    819  
    820 // As separate stream interfaces are used for blocking and callback streams, the following functions can be guaranteed to only be called for blocking streams. 
    821  
    822 static PaError ReadStream( PaStream* s, 
    823                            void *buffer, 
    824                            unsigned long frames ) 
    825 { 
    826     return paInternalError; 
    827 } 
    828  
    829  
    830 static PaError WriteStream( PaStream* s, 
    831                             const void *buffer, 
    832                             unsigned long frames ) 
    833 { 
    834     return paInternalError; 
    835 } 
    836  
    837  
    838 static signed long GetStreamReadAvailable( PaStream* s ) 
    839 { 
    840     return paInternalError; 
    841 } 
    842  
    843  
    844 static signed long GetStreamWriteAvailable( PaStream* s ) 
    845 { 
    846     return paInternalError; 
    847 } 
    848  
    849 // HostAPI-specific initialization function 
    850 PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) 
    851 { 
    852     PaError result = paNoError; 
    853     PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaMacCoreHostApiRepresentation) ); 
    854     if( !macCoreHostApi ) 
    855     { 
    856         result = paInsufficientMemory; 
    857         goto error; 
    858     } 
    859      
    860     macCoreHostApi->allocations = PaUtil_CreateAllocationGroup(); 
    861     if( !macCoreHostApi->allocations ) 
    862     { 
    863         result = paInsufficientMemory; 
    864         goto error; 
    865     } 
    866      
    867     *hostApi = &macCoreHostApi->inheritedHostApiRep; 
    868     (*hostApi)->info.structVersion = 1; 
    869     (*hostApi)->info.type = paCoreAudio; 
    870     (*hostApi)->info.name = "CoreAudio"; 
    871  
    872     result = InitializeDeviceInfos(macCoreHostApi, hostApiIndex); 
    873     if (result != paNoError) { 
    874         goto error; 
    875     } 
    876      
    877     // Set up the proper callbacks to this HostApi's functions 
    878     (*hostApi)->Terminate = Terminate; 
    879     (*hostApi)->OpenStream = OpenStream; 
    880     (*hostApi)->IsFormatSupported = IsFormatSupported; 
    881      
    882     PaUtil_InitializeStreamInterface( &macCoreHostApi->callbackStreamInterface, CloseStream, StartStream, 
    883                                       StopStream, AbortStream, IsStreamStopped, IsStreamActive, 
    884                                       GetStreamTime, GetStreamCpuLoad, 
    885                                       PaUtil_DummyRead, PaUtil_DummyWrite, 
    886                                       PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); 
    887      
    888     PaUtil_InitializeStreamInterface( &macCoreHostApi->blockingStreamInterface, CloseStream, StartStream, 
    889                                       StopStream, AbortStream, IsStreamStopped, IsStreamActive, 
    890                                       GetStreamTime, PaUtil_DummyGetCpuLoad, 
    891                                       ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); 
    892      
    893     return result; 
    894      
    895 error: 
    896         if( macCoreHostApi ) { 
    897             CleanUp(macCoreHostApi); 
    898         } 
    899      
    900     return result; 
    901 } 
Note: See TracChangeset for help on using the changeset viewer.