/[pcsx2_0.9.7]/trunk/3rdparty/portaudio/src/hostapi/coreaudio/pa_mac_core_utilities.c
ViewVC logotype

Contents of /trunk/3rdparty/portaudio/src/hostapi/coreaudio/pa_mac_core_utilities.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 273 - (show annotations) (download)
Fri Nov 12 01:10:22 2010 UTC (9 years, 2 months ago) by william
File MIME type: text/plain
File size: 26406 byte(s)
Auto Commited Import of: pcsx2-0.9.7-DEBUG (upstream: v0.9.7.4013 local: v0.9.7.197-latest) in ./trunk
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 }
733

  ViewVC Help
Powered by ViewVC 1.1.22