~noskcaj/ubuntu/saucy/sflphone/merge-1.2.3-2

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject/third_party/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.c

  • Committer: Jackson Doak
  • Date: 2013-07-10 21:04:46 UTC
  • mfrom: (20.1.3 sid)
  • Revision ID: noskcaj@ubuntu.com-20130710210446-y8f587vza807icr9
Properly merged from upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
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
 
 * 
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
 
 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