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

Annotation of /trunk/3rdparty/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 273 - (hide annotations) (download)
Fri Nov 12 01:10:22 2010 UTC (9 years, 3 months ago) by william
File MIME type: text/plain
File size: 19333 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 william 31 /*
2     * Implementation of the PortAudio API for Apple AUHAL
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 william 273 *
19 william 31 *
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 william 273 * The text above constitutes the entire PortAudio license; however,
45 william 31 * 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 william 273 * they can be incorporated into the canonical version. It is also
50     * requested that these non-binding requests be included along with the
51 william 31 * license above.
52     */
53    
54     /**
55     @file
56     @ingroup hostapi_src
57    
58     This file contains the implementation
59     required for blocking I/O. It is separated from pa_mac_core.c simply to ease
60     development.
61     */
62    
63     #include "pa_mac_core_blocking.h"
64     #include "pa_mac_core_internal.h"
65     #include <assert.h>
66     #ifdef MOSX_USE_NON_ATOMIC_FLAG_BITS
67     # define OSAtomicOr32( a, b ) ( (*(b)) |= (a) )
68     # define OSAtomicAnd32( a, b ) ( (*(b)) &= (a) )
69     #else
70     # include <libkern/OSAtomic.h>
71     #endif
72    
73     /*
74     * This fnuction determines the size of a particular sample format.
75     * if the format is not recognized, this returns zero.
76     */
77     static size_t computeSampleSizeFromFormat( PaSampleFormat format )
78     {
79     switch( format ) {
80     case paFloat32: return 4;
81     case paInt32: return 4;
82     case paInt24: return 3;
83     case paInt16: return 2;
84     case paInt8: case paUInt8: return 1;
85     default: return 0;
86     }
87     }
88     /*
89     * Same as computeSampleSizeFromFormat, except that if
90     * the size is not a power of two, it returns the next power of two up
91     */
92     static size_t computeSampleSizeFromFormatPow2( PaSampleFormat format )
93     {
94     switch( format ) {
95     case paFloat32: return 4;
96     case paInt32: return 4;
97     case paInt24: return 4;
98     case paInt16: return 2;
99     case paInt8: case paUInt8: return 1;
100     default: return 0;
101     }
102     }
103    
104    
105    
106     /*
107     * Functions for initializing, resetting, and destroying BLIO structures.
108     *
109     */
110    
111     /* This should be called with the relevant info when initializing a stream for
112     callback. */
113     PaError initializeBlioRingBuffers(
114     PaMacBlio *blio,
115     PaSampleFormat inputSampleFormat,
116     PaSampleFormat outputSampleFormat,
117     size_t framesPerBuffer,
118     long ringBufferSize,
119     int inChan,
120     int outChan )
121     {
122     void *data;
123     int result;
124     OSStatus err;
125    
126     /* zeroify things */
127     bzero( blio, sizeof( PaMacBlio ) );
128     /* this is redundant, but the buffers are used to check
129     if the bufffers have been initialized, so we do it explicitly. */
130     blio->inputRingBuffer.buffer = NULL;
131     blio->outputRingBuffer.buffer = NULL;
132    
133     /* initialize simple data */
134     blio->ringBufferFrames = ringBufferSize;
135     blio->inputSampleFormat = inputSampleFormat;
136     blio->inputSampleSizeActual = computeSampleSizeFromFormat(inputSampleFormat);
137     blio->inputSampleSizePow2 = computeSampleSizeFromFormatPow2(inputSampleFormat);
138     blio->outputSampleFormat = outputSampleFormat;
139     blio->outputSampleSizeActual = computeSampleSizeFromFormat(outputSampleFormat);
140     blio->outputSampleSizePow2 = computeSampleSizeFromFormatPow2(outputSampleFormat);
141    
142     blio->framesPerBuffer = framesPerBuffer;
143     blio->inChan = inChan;
144     blio->outChan = outChan;
145     blio->statusFlags = 0;
146     blio->errors = paNoError;
147     #ifdef PA_MAC_BLIO_MUTEX
148     blio->isInputEmpty = false;
149     blio->isOutputFull = false;
150     #endif
151    
152     /* setup ring buffers */
153     #ifdef PA_MAC_BLIO_MUTEX
154     result = PaMacCore_SetUnixError( pthread_mutex_init(&(blio->inputMutex),NULL), 0 );
155     if( result )
156     goto error;
157     result = UNIX_ERR( pthread_cond_init( &(blio->inputCond), NULL ) );
158     if( result )
159     goto error;
160     result = UNIX_ERR( pthread_mutex_init(&(blio->outputMutex),NULL) );
161     if( result )
162     goto error;
163     result = UNIX_ERR( pthread_cond_init( &(blio->outputCond), NULL ) );
164     #endif
165     if( inChan ) {
166     data = calloc( ringBufferSize, blio->inputSampleSizePow2*inChan );
167     if( !data )
168     {
169     result = paInsufficientMemory;
170     goto error;
171     }
172    
173     err = PaUtil_InitializeRingBuffer(
174     &blio->inputRingBuffer,
175     1, ringBufferSize*blio->inputSampleSizePow2*inChan,
176     data );
177     assert( !err );
178     }
179     if( outChan ) {
180     data = calloc( ringBufferSize, blio->outputSampleSizePow2*outChan );
181     if( !data )
182     {
183     result = paInsufficientMemory;
184     goto error;
185     }
186    
187     err = PaUtil_InitializeRingBuffer(
188     &blio->outputRingBuffer,
189     1, ringBufferSize*blio->outputSampleSizePow2*outChan,
190     data );
191     assert( !err );
192     }
193    
194     result = resetBlioRingBuffers( blio );
195     if( result )
196     goto error;
197    
198     return 0;
199    
200     error:
201     destroyBlioRingBuffers( blio );
202     return result;
203     }
204    
205     #ifdef PA_MAC_BLIO_MUTEX
206     PaError blioSetIsInputEmpty( PaMacBlio *blio, bool isEmpty )
207     {
208     PaError result = paNoError;
209     if( isEmpty == blio->isInputEmpty )
210     goto done;
211    
212     /* we need to update the value. Here's what we do:
213     * - Lock the mutex, so noone else can write.
214     * - update the value.
215     * - unlock.
216     * - broadcast to all listeners.
217     */
218     result = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) );
219     if( result )
220     goto done;
221     blio->isInputEmpty = isEmpty;
222     result = UNIX_ERR( pthread_mutex_unlock( &blio->inputMutex ) );
223     if( result )
224     goto done;
225     result = UNIX_ERR( pthread_cond_broadcast( &blio->inputCond ) );
226     if( result )
227     goto done;
228    
229     done:
230     return result;
231     }
232     PaError blioSetIsOutputFull( PaMacBlio *blio, bool isFull )
233     {
234     PaError result = paNoError;
235     if( isFull == blio->isOutputFull )
236     goto done;
237    
238     /* we need to update the value. Here's what we do:
239     * - Lock the mutex, so noone else can write.
240     * - update the value.
241     * - unlock.
242     * - broadcast to all listeners.
243     */
244     result = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) );
245     if( result )
246     goto done;
247     blio->isOutputFull = isFull;
248     result = UNIX_ERR( pthread_mutex_unlock( &blio->outputMutex ) );
249     if( result )
250     goto done;
251     result = UNIX_ERR( pthread_cond_broadcast( &blio->outputCond ) );
252     if( result )
253     goto done;
254    
255     done:
256     return result;
257     }
258     #endif
259    
260     /* This should be called after stopping or aborting the stream, so that on next
261     start, the buffers will be ready. */
262     PaError resetBlioRingBuffers( PaMacBlio *blio )
263     {
264     #ifdef PA_MAC__BLIO_MUTEX
265     int result;
266     #endif
267     blio->statusFlags = 0;
268     if( blio->outputRingBuffer.buffer ) {
269     PaUtil_FlushRingBuffer( &blio->outputRingBuffer );
270     bzero( blio->outputRingBuffer.buffer,
271     blio->outputRingBuffer.bufferSize );
272     /* Advance buffer */
273     PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->ringBufferFrames*blio->outputSampleSizeActual*blio->outChan );
274     //PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->outputRingBuffer.bufferSize );
275    
276     /* Update isOutputFull. */
277     #ifdef PA_MAC__BLIO_MUTEX
278     result = blioSetIsOutputFull( blio, toAdvance == blio->outputRingBuffer.bufferSize );
279     if( result )
280     goto error;
281     #endif
282     /*
283     printf( "------%d\n" , blio->framesPerBuffer );
284     printf( "------%d\n" , blio->outChan );
285     printf( "------%d\n" , blio->outputSampleSize );
286     printf( "------%d\n" , blio->framesPerBuffer*blio->outChan*blio->outputSampleSize );
287     */
288     }
289     if( blio->inputRingBuffer.buffer ) {
290     PaUtil_FlushRingBuffer( &blio->inputRingBuffer );
291     bzero( blio->inputRingBuffer.buffer,
292     blio->inputRingBuffer.bufferSize );
293     /* Update isInputEmpty. */
294     #ifdef PA_MAC__BLIO_MUTEX
295     result = blioSetIsInputEmpty( blio, true );
296     if( result )
297     goto error;
298     #endif
299     }
300     return paNoError;
301     #ifdef PA_MAC__BLIO_MUTEX
302     error:
303     return result;
304     #endif
305     }
306    
307     /*This should be called when you are done with the blio. It can safely be called
308     multiple times if there are no exceptions. */
309     PaError destroyBlioRingBuffers( PaMacBlio *blio )
310     {
311     PaError result = paNoError;
312     if( blio->inputRingBuffer.buffer ) {
313     free( blio->inputRingBuffer.buffer );
314     #ifdef PA_MAC__BLIO_MUTEX
315     result = UNIX_ERR( pthread_mutex_destroy( & blio->inputMutex ) );
316     if( result ) return result;
317     result = UNIX_ERR( pthread_cond_destroy( & blio->inputCond ) );
318     if( result ) return result;
319     #endif
320     }
321     blio->inputRingBuffer.buffer = NULL;
322     if( blio->outputRingBuffer.buffer ) {
323     free( blio->outputRingBuffer.buffer );
324     #ifdef PA_MAC__BLIO_MUTEX
325     result = UNIX_ERR( pthread_mutex_destroy( & blio->outputMutex ) );
326     if( result ) return result;
327     result = UNIX_ERR( pthread_cond_destroy( & blio->outputCond ) );
328     if( result ) return result;
329     #endif
330     }
331     blio->outputRingBuffer.buffer = NULL;
332    
333     return result;
334     }
335    
336     /*
337     * this is the BlioCallback function. It expects to recieve a PaMacBlio Object
338     * pointer as userData.
339     *
340     */
341     int BlioCallback( const void *input, void *output, unsigned long frameCount,
342     const PaStreamCallbackTimeInfo* timeInfo,
343     PaStreamCallbackFlags statusFlags,
344     void *userData )
345     {
346     PaMacBlio *blio = (PaMacBlio*)userData;
347     long avail;
348     long toRead;
349     long toWrite;
350     long read;
351     long written;
352    
353     /* set flags returned by OS: */
354     OSAtomicOr32( statusFlags, &blio->statusFlags ) ;
355    
356     /* --- Handle Input Buffer --- */
357     if( blio->inChan ) {
358     avail = PaUtil_GetRingBufferWriteAvailable( &blio->inputRingBuffer );
359    
360     /* check for underflow */
361     if( avail < frameCount * blio->inputSampleSizeActual * blio->inChan )
362     OSAtomicOr32( paInputOverflow, &blio->statusFlags );
363    
364     toRead = MIN( avail, frameCount * blio->inputSampleSizeActual * blio->inChan );
365    
366     /* copy the data */
367     /*printf( "reading %d\n", toRead );*/
368     read = PaUtil_WriteRingBuffer( &blio->inputRingBuffer, input, toRead );
369     assert( toRead == read );
370     #ifdef PA_MAC__BLIO_MUTEX
371     /* Priority inversion. See notes below. */
372     blioSetIsInputEmpty( blio, false );
373     #endif
374     }
375    
376    
377     /* --- Handle Output Buffer --- */
378     if( blio->outChan ) {
379     avail = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer );
380    
381     /* check for underflow */
382     if( avail < frameCount * blio->outputSampleSizeActual * blio->outChan )
383     OSAtomicOr32( paOutputUnderflow, &blio->statusFlags );
384    
385     toWrite = MIN( avail, frameCount * blio->outputSampleSizeActual * blio->outChan );
386    
387     if( toWrite != frameCount * blio->outputSampleSizeActual * blio->outChan )
388     bzero( ((char *)output)+toWrite,
389     frameCount * blio->outputSampleSizeActual * blio->outChan - toWrite );
390     /* copy the data */
391     /*printf( "writing %d\n", toWrite );*/
392     written = PaUtil_ReadRingBuffer( &blio->outputRingBuffer, output, toWrite );
393     assert( toWrite == written );
394     #ifdef PA_MAC__BLIO_MUTEX
395     /* We have a priority inversion here. However, we will only have to
396     wait if this was true and is now false, which means we've got
397     some room in the buffer.
398     Hopefully problems will be minimized. */
399     blioSetIsOutputFull( blio, false );
400     #endif
401     }
402    
403     return paContinue;
404     }
405    
406     PaError ReadStream( PaStream* stream,
407     void *buffer,
408     unsigned long frames )
409     {
410     PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
411     char *cbuf = (char *) buffer;
412     PaError ret = paNoError;
413     VVDBUG(("ReadStream()\n"));
414    
415     while( frames > 0 ) {
416     long avail;
417     long toRead;
418     do {
419     avail = PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer );
420     /*
421     printf( "Read Buffer is %%%g full: %ld of %ld.\n",
422     100 * (float)avail / (float) blio->inputRingBuffer.bufferSize,
423     avail, blio->inputRingBuffer.bufferSize );
424     */
425     if( avail == 0 ) {
426     #ifdef PA_MAC_BLIO_MUTEX
427     /**block when empty*/
428     ret = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) );
429     if( ret )
430     return ret;
431     while( blio->isInputEmpty ) {
432     ret = UNIX_ERR( pthread_cond_wait( &blio->inputCond, &blio->inputMutex ) );
433     if( ret )
434     return ret;
435     }
436     ret = UNIX_ERR( pthread_mutex_unlock( &blio->inputMutex ) );
437     if( ret )
438     return ret;
439     #else
440     Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
441     #endif
442     }
443     } while( avail == 0 );
444     toRead = MIN( avail, frames * blio->inputSampleSizeActual * blio->inChan );
445     toRead -= toRead % blio->inputSampleSizeActual * blio->inChan ;
446     PaUtil_ReadRingBuffer( &blio->inputRingBuffer, (void *)cbuf, toRead );
447     cbuf += toRead;
448     frames -= toRead / ( blio->inputSampleSizeActual * blio->inChan );
449    
450     if( toRead == avail ) {
451     #ifdef PA_MAC_BLIO_MUTEX
452     /* we just emptied the buffer, so we need to mark it as empty. */
453     ret = blioSetIsInputEmpty( blio, true );
454     if( ret )
455     return ret;
456     /* of course, in the meantime, the callback may have put some sats
457     in, so
458     so check for that, too, to avoid a race condition. */
459     if( PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ) ) {
460     blioSetIsInputEmpty( blio, false );
461     if( ret )
462     return ret;
463     }
464     #endif
465     }
466     }
467    
468     /* Report either paNoError or paInputOverflowed. */
469     /* may also want to report other errors, but this is non-standard. */
470     ret = blio->statusFlags & paInputOverflow;
471    
472     /* report underflow only once: */
473     if( ret ) {
474     OSAtomicAnd32( (uint32_t)(~paInputOverflow), &blio->statusFlags );
475     ret = paInputOverflowed;
476     }
477    
478     return ret;
479     }
480    
481    
482     PaError WriteStream( PaStream* stream,
483     const void *buffer,
484     unsigned long frames )
485     {
486     PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
487     char *cbuf = (char *) buffer;
488     PaError ret = paNoError;
489     VVDBUG(("WriteStream()\n"));
490    
491     while( frames > 0 ) {
492     long avail = 0;
493     long toWrite;
494    
495     do {
496     avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
497     /*
498     printf( "Write Buffer is %%%g full: %ld of %ld.\n",
499     100 - 100 * (float)avail / (float) blio->outputRingBuffer.bufferSize,
500     avail, blio->outputRingBuffer.bufferSize );
501     */
502     if( avail == 0 ) {
503     #ifdef PA_MAC_BLIO_MUTEX
504     /*block while full*/
505     ret = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) );
506     if( ret )
507     return ret;
508     while( blio->isOutputFull ) {
509     ret = UNIX_ERR( pthread_cond_wait( &blio->outputCond, &blio->outputMutex ) );
510     if( ret )
511     return ret;
512     }
513     ret = UNIX_ERR( pthread_mutex_unlock( &blio->outputMutex ) );
514     if( ret )
515     return ret;
516     #else
517     Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
518     #endif
519     }
520     } while( avail == 0 );
521    
522     toWrite = MIN( avail, frames * blio->outputSampleSizeActual * blio->outChan );
523     toWrite -= toWrite % blio->outputSampleSizeActual * blio->outChan ;
524     PaUtil_WriteRingBuffer( &blio->outputRingBuffer, (void *)cbuf, toWrite );
525     cbuf += toWrite;
526     frames -= toWrite / ( blio->outputSampleSizeActual * blio->outChan );
527    
528     #ifdef PA_MAC_BLIO_MUTEX
529     if( toWrite == avail ) {
530     /* we just filled up the buffer, so we need to mark it as filled. */
531     ret = blioSetIsOutputFull( blio, true );
532     if( ret )
533     return ret;
534     /* of course, in the meantime, we may have emptied the buffer, so
535     so check for that, too, to avoid a race condition. */
536     if( PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ) ) {
537     blioSetIsOutputFull( blio, false );
538     if( ret )
539     return ret;
540     }
541     }
542     #endif
543     }
544    
545     /* Report either paNoError or paOutputUnderflowed. */
546     /* may also want to report other errors, but this is non-standard. */
547     ret = blio->statusFlags & paOutputUnderflow;
548    
549     /* report underflow only once: */
550     if( ret ) {
551     OSAtomicAnd32( (uint32_t)(~paOutputUnderflow), &blio->statusFlags );
552     ret = paOutputUnderflowed;
553     }
554    
555     return ret;
556     }
557    
558     /*
559     *
560     */
561     void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio )
562     {
563     if( blio->outputRingBuffer.buffer ) {
564     long avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
565     while( avail != blio->outputRingBuffer.bufferSize ) {
566     if( avail == 0 )
567     Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
568     avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
569     }
570     }
571     }
572    
573    
574     signed long GetStreamReadAvailable( PaStream* stream )
575     {
576     PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
577     VVDBUG(("GetStreamReadAvailable()\n"));
578    
579     return PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer )
580     / ( blio->inputSampleSizeActual * blio->inChan );
581     }
582    
583    
584     signed long GetStreamWriteAvailable( PaStream* stream )
585     {
586     PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
587     VVDBUG(("GetStreamWriteAvailable()\n"));
588    
589     return PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer )
590     / ( blio->outputSampleSizeActual * blio->outChan );
591     }
592    

  ViewVC Help
Powered by ViewVC 1.1.22