~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/third_party/portaudio/src/hostapi/coreaudio/pa_mac_core_utilities.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Helper and utility functions for pa_mac_core.c (Apple AUHAL implementation)
3
 
 *
4
 
 * PortAudio Portable Real-Time Audio Library
5
 
 * Latest Version at: http://www.portaudio.com
6
 
 *
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
22
 
 *
23
 
 * Permission is hereby granted, free of charge, to any person obtaining
24
 
 * a copy of this software and associated documentation files
25
 
 * (the "Software"), to deal in the Software without restriction,
26
 
 * including without limitation the rights to use, copy, modify, merge,
27
 
 * publish, distribute, sublicense, and/or sell copies of the Software,
28
 
 * and to permit persons to whom the Software is furnished to do so,
29
 
 * subject to the following conditions:
30
 
 *
31
 
 * The above copyright notice and this permission notice shall be
32
 
 * included in all copies or substantial portions of the Software.
33
 
 *
34
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
35
 
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
36
 
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
37
 
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
38
 
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
39
 
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
40
 
 * 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:
46
 
 *
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.
52
 
 */
53
 
 
54
 
/**
55
 
 @file
56
 
 @ingroup hostapi_src
57
 
*/
58
 
 
59
 
#include "pa_mac_core_utilities.h"
60
 
#include "pa_mac_core_internal.h"
61
 
#include <libkern/OSAtomic.h>
62
 
#include <strings.h>
63
 
#include <pthread.h>
64
 
#include <sys/time.h>
65
 
 
66
 
PaError PaMacCore_SetUnixError( int err, int line )
67
 
{
68
 
   PaError ret;
69
 
   const char *errorText;
70
 
 
71
 
   if( err == 0 )
72
 
   {
73
 
      return paNoError;
74
 
   }
75
 
 
76
 
   ret = paNoError;
77
 
   errorText = strerror( err );
78
 
 
79
 
   /** Map Unix error to PaError. Pretty much the only one that maps
80
 
       is ENOMEM. */
81
 
   if( err == ENOMEM )
82
 
      ret = paInsufficientMemory;
83
 
   else
84
 
      ret = paInternalError;
85
 
 
86
 
   DBUG(("%d on line %d: msg='%s'\n", err, line, errorText));
87
 
   PaUtil_SetLastHostErrorInfo( paCoreAudio, err, errorText );
88
 
 
89
 
   return ret;
90
 
}
91
 
 
92
 
/*
93
 
 * Translates MacOS generated errors into PaErrors
94
 
 */
95
 
PaError PaMacCore_SetError(OSStatus error, int line, int isError)
96
 
{
97
 
    /*FIXME: still need to handle possible ComponentResult values.*/
98
 
    /*       unfortunately, they don't seem to be documented anywhere.*/
99
 
    PaError result;
100
 
    const char *errorType;
101
 
    const char *errorText;
102
 
 
103
 
    switch (error) {
104
 
    case kAudioHardwareNoError:
105
 
        return paNoError;
106
 
    case kAudioHardwareNotRunningError:
107
 
        errorText = "Audio Hardware Not Running";
108
 
        result = paInternalError; break;
109
 
    case kAudioHardwareUnspecifiedError:
110
 
        errorText = "Unspecified Audio Hardware Error";
111
 
        result = paInternalError; break;
112
 
    case kAudioHardwareUnknownPropertyError:
113
 
        errorText = "Audio Hardware: Unknown Property";
114
 
        result = paInternalError; break;
115
 
    case kAudioHardwareBadPropertySizeError:
116
 
        errorText = "Audio Hardware: Bad Property Size";
117
 
        result = paInternalError; break;
118
 
    case kAudioHardwareIllegalOperationError:
119
 
        errorText = "Audio Hardware: Illegal Operation";
120
 
        result = paInternalError; break;
121
 
    case kAudioHardwareBadDeviceError:
122
 
        errorText = "Audio Hardware: Bad Device";
123
 
        result = paInvalidDevice; break;
124
 
    case kAudioHardwareBadStreamError:
125
 
        errorText = "Audio Hardware: BadStream";
126
 
        result = paBadStreamPtr; break;
127
 
    case kAudioHardwareUnsupportedOperationError:
128
 
        errorText = "Audio Hardware: Unsupported Operation";
129
 
        result = paInternalError; break;
130
 
    case kAudioDeviceUnsupportedFormatError:
131
 
        errorText = "Audio Device: Unsupported Format";
132
 
        result = paSampleFormatNotSupported; break;
133
 
    case kAudioDevicePermissionsError:
134
 
        errorText = "Audio Device: Permissions Error";
135
 
        result = paDeviceUnavailable; break;
136
 
    /* Audio Unit Errors: http://developer.apple.com/documentation/MusicAudio/Reference/CoreAudio/audio_units/chapter_5_section_3.html */
137
 
    case kAudioUnitErr_InvalidProperty:
138
 
        errorText = "Audio Unit: Invalid Property";
139
 
        result = paInternalError; break;
140
 
    case kAudioUnitErr_InvalidParameter:
141
 
        errorText = "Audio Unit: Invalid Parameter";
142
 
        result = paInternalError; break;
143
 
    case kAudioUnitErr_NoConnection:
144
 
        errorText = "Audio Unit: No Connection";
145
 
        result = paInternalError; break;
146
 
    case kAudioUnitErr_FailedInitialization:
147
 
        errorText = "Audio Unit: Initialization Failed";
148
 
        result = paInternalError; break;
149
 
    case kAudioUnitErr_TooManyFramesToProcess:
150
 
        errorText = "Audio Unit: Too Many Frames";
151
 
        result = paInternalError; break;
152
 
    case kAudioUnitErr_IllegalInstrument:
153
 
        errorText = "Audio Unit: Illegal Instrument";
154
 
        result = paInternalError; break;
155
 
    case kAudioUnitErr_InstrumentTypeNotFound:
156
 
        errorText = "Audio Unit: Instrument Type Not Found";
157
 
        result = paInternalError; break;
158
 
    case kAudioUnitErr_InvalidFile:
159
 
        errorText = "Audio Unit: Invalid File";
160
 
        result = paInternalError; break;
161
 
    case kAudioUnitErr_UnknownFileType:
162
 
        errorText = "Audio Unit: Unknown File Type";
163
 
        result = paInternalError; break;
164
 
    case kAudioUnitErr_FileNotSpecified:
165
 
        errorText = "Audio Unit: File Not Specified";
166
 
        result = paInternalError; break;
167
 
    case kAudioUnitErr_FormatNotSupported:
168
 
        errorText = "Audio Unit: Format Not Supported";
169
 
        result = paInternalError; break;
170
 
    case kAudioUnitErr_Uninitialized:
171
 
        errorText = "Audio Unit: Unitialized";
172
 
        result = paInternalError; break;
173
 
    case kAudioUnitErr_InvalidScope:
174
 
        errorText = "Audio Unit: Invalid Scope";
175
 
        result = paInternalError; break;
176
 
    case kAudioUnitErr_PropertyNotWritable:
177
 
        errorText = "Audio Unit: PropertyNotWritable";
178
 
        result = paInternalError; break;
179
 
    case kAudioUnitErr_InvalidPropertyValue:
180
 
        errorText = "Audio Unit: Invalid Property Value";
181
 
        result = paInternalError; break;
182
 
    case kAudioUnitErr_PropertyNotInUse:
183
 
        errorText = "Audio Unit: Property Not In Use";
184
 
        result = paInternalError; break;
185
 
    case kAudioUnitErr_Initialized:
186
 
        errorText = "Audio Unit: Initialized";
187
 
        result = paInternalError; break;
188
 
    case kAudioUnitErr_InvalidOfflineRender:
189
 
        errorText = "Audio Unit: Invalid Offline Render";
190
 
        result = paInternalError; break;
191
 
    case kAudioUnitErr_Unauthorized:
192
 
        errorText = "Audio Unit: Unauthorized";
193
 
        result = paInternalError; break;
194
 
    case kAudioUnitErr_CannotDoInCurrentContext:
195
 
        errorText = "Audio Unit: cannot do in current context";
196
 
        result = paInternalError; break;
197
 
    default:
198
 
        errorText = "Unknown Error";
199
 
        result = paInternalError;
200
 
    }
201
 
 
202
 
    if (isError)
203
 
        errorType = "Error";
204
 
    else
205
 
        errorType = "Warning";
206
 
 
207
 
    char str[20];
208
 
    // see if it appears to be a 4-char-code
209
 
    *(UInt32 *)(str + 1) = CFSwapInt32HostToBig(error);
210
 
    if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4]))
211
 
    {
212
 
        str[0] = str[5] = '\'';
213
 
        str[6] = '\0';
214
 
    } else {
215
 
        // no, format it as an integer
216
 
        sprintf(str, "%d", (int)error);
217
 
    }
218
 
 
219
 
    DBUG(("%s on line %d: err='%s', msg=%s\n", errorType, line, str, errorText));
220
 
 
221
 
    PaUtil_SetLastHostErrorInfo( paCoreAudio, error, errorText );
222
 
 
223
 
    return result;
224
 
}
225
 
 
226
 
/*
227
 
 * This function computes an appropriate ring buffer size given
228
 
 * a requested latency (in seconds), sample rate and framesPerBuffer.
229
 
 *
230
 
 * The returned ringBufferSize is computed using the following
231
 
 * constraints:
232
 
 *   - it must be at least 4.
233
 
 *   - it must be at least 3x framesPerBuffer.
234
 
 *   - it must be at least 2x the suggestedLatency.
235
 
 *   - it must be a power of 2.
236
 
 * This function attempts to compute the minimum such size.
237
 
 *
238
 
 * FEEDBACK: too liberal/conservative/another way?
239
 
 */
240
 
long computeRingBufferSize( const PaStreamParameters *inputParameters,
241
 
                                   const PaStreamParameters *outputParameters,
242
 
                                   long inputFramesPerBuffer,
243
 
                                   long outputFramesPerBuffer,
244
 
                                   double sampleRate )
245
 
{
246
 
   long ringSize;
247
 
   int index;
248
 
   int i;
249
 
   double latencyTimesChannelCount ;
250
 
   long framesPerBufferTimesChannelCount ;
251
 
 
252
 
   VVDBUG(( "computeRingBufferSize()\n" ));
253
 
 
254
 
   assert( inputParameters || outputParameters );
255
 
 
256
 
   if( outputParameters && inputParameters )
257
 
   {
258
 
      latencyTimesChannelCount = MAX(
259
 
           inputParameters->suggestedLatency * inputParameters->channelCount,
260
 
           outputParameters->suggestedLatency * outputParameters->channelCount );
261
 
      framesPerBufferTimesChannelCount = MAX(
262
 
           inputFramesPerBuffer * inputParameters->channelCount,
263
 
           outputFramesPerBuffer * outputParameters->channelCount );
264
 
   }
265
 
   else if( outputParameters )
266
 
   {
267
 
      latencyTimesChannelCount
268
 
                = outputParameters->suggestedLatency * outputParameters->channelCount;
269
 
      framesPerBufferTimesChannelCount
270
 
                = outputFramesPerBuffer * outputParameters->channelCount;
271
 
   }
272
 
   else /* we have inputParameters  */
273
 
   {
274
 
      latencyTimesChannelCount
275
 
                = inputParameters->suggestedLatency * inputParameters->channelCount;
276
 
      framesPerBufferTimesChannelCount
277
 
                = inputFramesPerBuffer * inputParameters->channelCount;
278
 
   }
279
 
 
280
 
   ringSize = (long) ( latencyTimesChannelCount * sampleRate * 2 + .5);
281
 
   VDBUG( ( "suggested latency * channelCount: %d\n", (int) (latencyTimesChannelCount*sampleRate) ) );
282
 
   if( ringSize < framesPerBufferTimesChannelCount * 3 )
283
 
      ringSize = framesPerBufferTimesChannelCount * 3 ;
284
 
   VDBUG(("framesPerBuffer*channelCount:%d\n",(int)framesPerBufferTimesChannelCount));
285
 
   VDBUG(("Ringbuffer size (1): %d\n", (int)ringSize ));
286
 
 
287
 
   /* make sure it's at least 4 */
288
 
   ringSize = MAX( ringSize, 4 );
289
 
 
290
 
   /* round up to the next power of 2 */
291
 
   index = -1;
292
 
   for( i=0; i<sizeof(long)*8; ++i )
293
 
      if( ringSize >> i & 0x01 )
294
 
         index = i;
295
 
   assert( index > 0 );
296
 
   if( ringSize <= ( 0x01 << index ) )
297
 
      ringSize = 0x01 << index ;
298
 
   else
299
 
      ringSize = 0x01 << ( index + 1 );
300
 
 
301
 
   VDBUG(( "Final Ringbuffer size (2): %d\n", (int)ringSize ));
302
 
   return ringSize;
303
 
}
304
 
 
305
 
 
306
 
/*
307
 
 * Durring testing of core audio, I found that serious crashes could occur
308
 
 * if properties such as sample rate were changed multiple times in rapid
309
 
 * succession. The function below could be used to with a condition variable.
310
 
 * to prevent propertychanges from happening until the last property
311
 
 * change is acknowledged. Instead, I implemented a busy-wait, which is simpler
312
 
 * to implement b/c in second round of testing (nov '09) property changes occured
313
 
 * quickly and so there was no real way to test the condition variable implementation.
314
 
 * therefore, this function is not used, but it is aluded to in commented code below,
315
 
 * since it represents a theoretically better implementation.
316
 
 */
317
 
 
318
 
OSStatus propertyProc(
319
 
    AudioDeviceID inDevice,
320
 
    UInt32 inChannel,
321
 
    Boolean isInput,
322
 
    AudioDevicePropertyID inPropertyID,
323
 
    void* inClientData )
324
 
{
325
 
   // this is where we would set the condition variable
326
 
   return noErr;
327
 
}
328
 
 
329
 
/* sets the value of the given property and waits for the change to
330
 
   be acknowledged, and returns the final value, which is not guaranteed
331
 
   by this function to be the same as the desired value. Obviously, this
332
 
   function can only be used for data whose input and output are the
333
 
   same size and format, and their size and format are known in advance.
334
 
   whether or not the call succeeds, if the data is successfully read,
335
 
   it is returned in outPropertyData. If it is not read successfully,
336
 
   outPropertyData is zeroed, which may or may not be useful in
337
 
   determining if the property was read. */
338
 
PaError AudioDeviceSetPropertyNowAndWaitForChange(
339
 
    AudioDeviceID inDevice,
340
 
    UInt32 inChannel,
341
 
    Boolean isInput,
342
 
    AudioDevicePropertyID inPropertyID,
343
 
    UInt32 inPropertyDataSize,
344
 
    const void *inPropertyData,
345
 
    void *outPropertyData )
346
 
{
347
 
   OSStatus macErr;
348
 
   UInt32 outPropertyDataSize = inPropertyDataSize;
349
 
 
350
 
   /* First, see if it already has that value. If so, return. */
351
 
   macErr = AudioDeviceGetProperty( inDevice, inChannel,
352
 
                                 isInput, inPropertyID,
353
 
                                 &outPropertyDataSize, outPropertyData );
354
 
   if( macErr ) {
355
 
      memset( outPropertyData, 0, inPropertyDataSize );
356
 
      goto failMac;
357
 
   }
358
 
   if( inPropertyDataSize!=outPropertyDataSize )
359
 
      return paInternalError;
360
 
   if( 0==memcmp( outPropertyData, inPropertyData, outPropertyDataSize ) )
361
 
      return paNoError;
362
 
 
363
 
   /* Ideally, we'd use a condition variable to determine changes.
364
 
      we could set that up here. */
365
 
 
366
 
   /* If we were using a cond variable, we'd do something useful here,
367
 
      but for now, this is just to make 10.6 happy. */
368
 
   macErr = AudioDeviceAddPropertyListener( inDevice, inChannel, isInput,
369
 
                                   inPropertyID, propertyProc,
370
 
                                   NULL );
371
 
   if( macErr )
372
 
      /* we couldn't add a listener. */
373
 
      goto failMac;
374
 
 
375
 
   /* set property */
376
 
   macErr  = AudioDeviceSetProperty( inDevice, NULL, inChannel,
377
 
                                 isInput, inPropertyID,
378
 
                                 inPropertyDataSize, inPropertyData );
379
 
   if( macErr )
380
 
      goto failMac;
381
 
 
382
 
   /* busy-wait up to 30 seconds for the property to change */
383
 
   /* busy-wait is justified here only because the correct alternative (condition variable)
384
 
      was hard to test, since most of the waiting ended up being for setting rather than
385
 
      getting in OS X 10.5. This was not the case in earlier OS versions. */
386
 
   struct timeval tv1, tv2;
387
 
   gettimeofday( &tv1, NULL );
388
 
   memcpy( &tv2, &tv1, sizeof( struct timeval ) );
389
 
   while( tv2.tv_sec - tv1.tv_sec < 30 ) {
390
 
      /* now read the property back out */
391
 
      macErr = AudioDeviceGetProperty( inDevice, inChannel,
392
 
                                    isInput, inPropertyID,
393
 
                                    &outPropertyDataSize, outPropertyData );
394
 
      if( macErr ) {
395
 
         memset( outPropertyData, 0, inPropertyDataSize );
396
 
         goto failMac;
397
 
      }
398
 
      /* and compare... */
399
 
      if( 0==memcmp( outPropertyData, inPropertyData, outPropertyDataSize ) ) {
400
 
         AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc );
401
 
         return paNoError;
402
 
      }
403
 
      /* No match yet, so let's sleep and try again. */
404
 
      Pa_Sleep( 100 );
405
 
      gettimeofday( &tv2, NULL );
406
 
   }
407
 
   DBUG( ("Timeout waiting for device setting.\n" ) );
408
 
 
409
 
   AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc );
410
 
   return paNoError;
411
 
 
412
 
 failMac:
413
 
   AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc );
414
 
   return ERR( macErr );
415
 
}
416
 
 
417
 
/*
418
 
 * Sets the sample rate the HAL device.
419
 
 * if requireExact: set the sample rate or fail.
420
 
 *
421
 
 * otherwise      : set the exact sample rate.
422
 
 *             If that fails, check for available sample rates, and choose one
423
 
 *             higher than the requested rate. If there isn't a higher one,
424
 
 *             just use the highest available.
425
 
 */
426
 
PaError setBestSampleRateForDevice( const AudioDeviceID device,
427
 
                                    const bool isOutput,
428
 
                                    const bool requireExact,
429
 
                                    const Float64 desiredSrate )
430
 
{
431
 
   const bool isInput = isOutput ? 0 : 1;
432
 
   Float64 srate;
433
 
   UInt32 propsize = sizeof( Float64 );
434
 
   OSErr err;
435
 
   AudioValueRange *ranges;
436
 
   int i=0;
437
 
   Float64 max  = -1; /*the maximum rate available*/
438
 
   Float64 best = -1; /*the lowest sample rate still greater than desired rate*/
439
 
   VDBUG(("Setting sample rate for device %ld to %g.\n",device,(float)desiredSrate));
440
 
 
441
 
   /* -- try setting the sample rate -- */
442
 
   srate = 0;
443
 
   err = AudioDeviceSetPropertyNowAndWaitForChange(
444
 
                                 device, 0, isInput,
445
 
                                 kAudioDevicePropertyNominalSampleRate,
446
 
                                 propsize, &desiredSrate, &srate );
447
 
 
448
 
   /* -- if the rate agrees, and was changed, we are done -- */
449
 
   if( srate != 0 && srate == desiredSrate )
450
 
      return paNoError;
451
 
   /* -- if the rate agrees, and we got no errors, we are done -- */
452
 
   if( !err && srate == desiredSrate )
453
 
      return paNoError;
454
 
   /* -- we've failed if the rates disagree and we are setting input -- */
455
 
   if( requireExact )
456
 
      return paInvalidSampleRate;
457
 
 
458
 
   /* -- generate a list of available sample rates -- */
459
 
   err = AudioDeviceGetPropertyInfo( device, 0, isInput,
460
 
                                kAudioDevicePropertyAvailableNominalSampleRates,
461
 
                                &propsize, NULL );
462
 
   if( err )
463
 
      return ERR( err );
464
 
   ranges = (AudioValueRange *)calloc( 1, propsize );
465
 
   if( !ranges )
466
 
      return paInsufficientMemory;
467
 
   err = AudioDeviceGetProperty( device, 0, isInput,
468
 
                                kAudioDevicePropertyAvailableNominalSampleRates,
469
 
                                &propsize, ranges );
470
 
   if( err )
471
 
   {
472
 
      free( ranges );
473
 
      return ERR( err );
474
 
   }
475
 
   VDBUG(("Requested sample rate of %g was not available.\n", (float)desiredSrate));
476
 
   VDBUG(("%lu Available Sample Rates are:\n",propsize/sizeof(AudioValueRange)));
477
 
#ifdef MAC_CORE_VERBOSE_DEBUG
478
 
   for( i=0; i<propsize/sizeof(AudioValueRange); ++i )
479
 
      VDBUG( ("\t%g-%g\n",
480
 
              (float) ranges[i].mMinimum,
481
 
              (float) ranges[i].mMaximum ) );
482
 
#endif
483
 
   VDBUG(("-----\n"));
484
 
 
485
 
   /* -- now pick the best available sample rate -- */
486
 
   for( i=0; i<propsize/sizeof(AudioValueRange); ++i )
487
 
   {
488
 
      if( ranges[i].mMaximum > max ) max = ranges[i].mMaximum;
489
 
      if( ranges[i].mMinimum > desiredSrate ) {
490
 
         if( best < 0 )
491
 
            best = ranges[i].mMinimum;
492
 
         else if( ranges[i].mMinimum < best )
493
 
            best = ranges[i].mMinimum;
494
 
      }
495
 
   }
496
 
   if( best < 0 )
497
 
      best = max;
498
 
   VDBUG( ("Maximum Rate %g. best is %g.\n", max, best ) );
499
 
   free( ranges );
500
 
 
501
 
   /* -- set the sample rate -- */
502
 
   propsize = sizeof( best );
503
 
   srate = 0;
504
 
   err = AudioDeviceSetPropertyNowAndWaitForChange(
505
 
                                 device, 0, isInput,
506
 
                                 kAudioDevicePropertyNominalSampleRate,
507
 
                                 propsize, &best, &srate );
508
 
 
509
 
   /* -- if the set rate matches, we are done -- */
510
 
   if( srate != 0 && srate == best )
511
 
      return paNoError;
512
 
 
513
 
   if( err )
514
 
      return ERR( err );
515
 
 
516
 
   /* -- otherwise, something wierd happened: we didn't set the rate, and we got no errors. Just bail. */
517
 
   return paInternalError;
518
 
}
519
 
 
520
 
 
521
 
/*
522
 
   Attempts to set the requestedFramesPerBuffer. If it can't set the exact
523
 
   value, it settles for something smaller if available. If nothing smaller
524
 
   is available, it uses the smallest available size.
525
 
   actualFramesPerBuffer will be set to the actual value on successful return.
526
 
   OK to pass NULL to actualFramesPerBuffer.
527
 
   The logic is very simmilar too setBestSampleRate only failure here is
528
 
   not usually catastrophic.
529
 
*/
530
 
PaError setBestFramesPerBuffer( const AudioDeviceID device,
531
 
                                const bool isOutput,
532
 
                                UInt32 requestedFramesPerBuffer,
533
 
                                UInt32 *actualFramesPerBuffer )
534
 
{
535
 
   UInt32 afpb;
536
 
   const bool isInput = !isOutput;
537
 
   UInt32 propsize = sizeof(UInt32);
538
 
   OSErr err;
539
 
   Float64 min  = -1; /*the min blocksize*/
540
 
   Float64 best = -1; /*the best blocksize*/
541
 
   int i=0;
542
 
   AudioValueRange *ranges;
543
 
 
544
 
   if( actualFramesPerBuffer == NULL )
545
 
      actualFramesPerBuffer = &afpb;
546
 
 
547
 
 
548
 
   /* -- try and set exact FPB -- */
549
 
   err = AudioDeviceSetProperty( device, NULL, 0, isInput,
550
 
                                 kAudioDevicePropertyBufferFrameSize,
551
 
                                 propsize, &requestedFramesPerBuffer);
552
 
   err = AudioDeviceGetProperty( device, 0, isInput,
553
 
                           kAudioDevicePropertyBufferFrameSize,
554
 
                           &propsize, actualFramesPerBuffer);
555
 
   if( err )
556
 
      return ERR( err );
557
 
   if( *actualFramesPerBuffer == requestedFramesPerBuffer )
558
 
      return paNoError; /* we are done */
559
 
 
560
 
   /* -- fetch available block sizes -- */
561
 
   err = AudioDeviceGetPropertyInfo( device, 0, isInput,
562
 
                           kAudioDevicePropertyBufferSizeRange,
563
 
                           &propsize, NULL );
564
 
   if( err )
565
 
      return ERR( err );
566
 
   ranges = (AudioValueRange *)calloc( 1, propsize );
567
 
   if( !ranges )
568
 
      return paInsufficientMemory;
569
 
   err = AudioDeviceGetProperty( device, 0, isInput,
570
 
                                kAudioDevicePropertyBufferSizeRange,
571
 
                                &propsize, ranges );
572
 
   if( err )
573
 
   {
574
 
      free( ranges );
575
 
      return ERR( err );
576
 
   }
577
 
   VDBUG(("Requested block size of %lu was not available.\n",
578
 
          requestedFramesPerBuffer ));
579
 
   VDBUG(("%lu Available block sizes are:\n",propsize/sizeof(AudioValueRange)));
580
 
#ifdef MAC_CORE_VERBOSE_DEBUG
581
 
   for( i=0; i<propsize/sizeof(AudioValueRange); ++i )
582
 
      VDBUG( ("\t%g-%g\n",
583
 
              (float) ranges[i].mMinimum,
584
 
              (float) ranges[i].mMaximum ) );
585
 
#endif
586
 
   VDBUG(("-----\n"));
587
 
 
588
 
   /* --- now pick the best available framesPerBuffer -- */
589
 
   for( i=0; i<propsize/sizeof(AudioValueRange); ++i )
590
 
   {
591
 
      if( min == -1 || ranges[i].mMinimum < min ) min = ranges[i].mMinimum;
592
 
      if( ranges[i].mMaximum < requestedFramesPerBuffer ) {
593
 
         if( best < 0 )
594
 
            best = ranges[i].mMaximum;
595
 
         else if( ranges[i].mMaximum > best )
596
 
            best = ranges[i].mMaximum;
597
 
      }
598
 
   }
599
 
   if( best == -1 )
600
 
      best = min;
601
 
   VDBUG( ("Minimum FPB  %g. best is %g.\n", min, best ) );
602
 
   free( ranges );
603
 
 
604
 
   /* --- set the buffer size (ignore errors) -- */
605
 
   requestedFramesPerBuffer = (UInt32) best ;
606
 
   propsize = sizeof( UInt32 );
607
 
   err = AudioDeviceSetProperty( device, NULL, 0, isInput,
608
 
                                 kAudioDevicePropertyBufferSize,
609
 
                                 propsize, &requestedFramesPerBuffer );
610
 
   /* --- read the property to check that it was set -- */
611
 
   err = AudioDeviceGetProperty( device, 0, isInput,
612
 
                                 kAudioDevicePropertyBufferSize,
613
 
                                 &propsize, actualFramesPerBuffer );
614
 
 
615
 
   if( err )
616
 
      return ERR( err );
617
 
 
618
 
   return paNoError;
619
 
}
620
 
 
621
 
/**********************
622
 
 *
623
 
 * XRun stuff
624
 
 *
625
 
 **********************/
626
 
 
627
 
struct PaMacXRunListNode_s {
628
 
   PaMacCoreStream *stream;
629
 
   struct PaMacXRunListNode_s *next;
630
 
} ;
631
 
 
632
 
typedef struct PaMacXRunListNode_s PaMacXRunListNode;
633
 
 
634
 
/** Always empty, so that it can always be the one returned by
635
 
    addToXRunListenerList. note that it's not a pointer. */
636
 
static PaMacXRunListNode firstXRunListNode;
637
 
static int xRunListSize;
638
 
static pthread_mutex_t xrunMutex;
639
 
 
640
 
OSStatus xrunCallback(
641
 
    AudioDeviceID inDevice,
642
 
    UInt32 inChannel,
643
 
    Boolean isInput,
644
 
    AudioDevicePropertyID inPropertyID,
645
 
    void* inClientData)
646
 
{
647
 
   PaMacXRunListNode *node = (PaMacXRunListNode *) inClientData;
648
 
 
649
 
   int ret = pthread_mutex_trylock( &xrunMutex ) ;
650
 
 
651
 
   if( ret == 0 ) {
652
 
 
653
 
      node = node->next ; //skip the first node
654
 
 
655
 
      for( ; node; node=node->next ) {
656
 
         PaMacCoreStream *stream = node->stream;
657
 
 
658
 
         if( stream->state != ACTIVE )
659
 
            continue; //if the stream isn't active, we don't care if the device is dropping
660
 
 
661
 
         if( isInput ) {
662
 
            if( stream->inputDevice == inDevice )
663
 
               OSAtomicOr32( paInputOverflow, (uint32_t *)&(stream->xrunFlags) );
664
 
         } else {
665
 
            if( stream->outputDevice == inDevice )
666
 
               OSAtomicOr32( paOutputUnderflow, (uint32_t *)&(stream->xrunFlags) );
667
 
         }
668
 
      }
669
 
 
670
 
      pthread_mutex_unlock( &xrunMutex );
671
 
   }
672
 
 
673
 
   return 0;
674
 
}
675
 
 
676
 
int initializeXRunListenerList()
677
 
{
678
 
   xRunListSize = 0;
679
 
   bzero( (void *) &firstXRunListNode, sizeof(firstXRunListNode) );
680
 
   return pthread_mutex_init( &xrunMutex, NULL );
681
 
}
682
 
int destroyXRunListenerList()
683
 
{
684
 
   PaMacXRunListNode *node;
685
 
   node = firstXRunListNode.next;
686
 
   while( node ) {
687
 
      PaMacXRunListNode *tmp = node;
688
 
      node = node->next;
689
 
      free( tmp );
690
 
   }
691
 
   xRunListSize = 0;
692
 
   return pthread_mutex_destroy( &xrunMutex );
693
 
}
694
 
 
695
 
void *addToXRunListenerList( void *stream )
696
 
{
697
 
   pthread_mutex_lock( &xrunMutex );
698
 
   PaMacXRunListNode *newNode;
699
 
   // setup new node:
700
 
   newNode = (PaMacXRunListNode *) malloc( sizeof( PaMacXRunListNode ) );
701
 
   newNode->stream = (PaMacCoreStream *) stream;
702
 
   newNode->next = firstXRunListNode.next;
703
 
   // insert:
704
 
   firstXRunListNode.next = newNode;
705
 
   pthread_mutex_unlock( &xrunMutex );
706
 
 
707
 
   return &firstXRunListNode;
708
 
}
709
 
 
710
 
int removeFromXRunListenerList( void *stream )
711
 
{
712
 
   pthread_mutex_lock( &xrunMutex );
713
 
   PaMacXRunListNode *node, *prev;
714
 
   prev = &firstXRunListNode;
715
 
   node = firstXRunListNode.next;
716
 
   while( node ) {
717
 
      if( node->stream == stream ) {
718
 
         //found it:
719
 
         --xRunListSize;
720
 
         prev->next = node->next;
721
 
         free( node );
722
 
         pthread_mutex_unlock( &xrunMutex );
723
 
         return xRunListSize;
724
 
      }
725
 
      prev = prev->next;
726
 
      node = node->next;
727
 
   }
728
 
 
729
 
   pthread_mutex_unlock( &xrunMutex );
730
 
   // failure
731
 
   return xRunListSize;
732
 
}