~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* 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
 * 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