/*
 * this is the BlioCallback function. It expects to recieve a PaMacBlio Object
 * pointer as userData.
 *
 */
int BlioCallback( const void *input, void *output, unsigned long frameCount,
	const PaStreamCallbackTimeInfo* timeInfo,
        PaStreamCallbackFlags statusFlags,
        void *userData )
{
   PaMacBlio *blio = (PaMacBlio*)userData;
   long avail;
   long toRead;
   long toWrite;

   /* set flags returned by OS: */
   OSAtomicOr32( statusFlags, &blio->statusFlags ) ;

   /* --- Handle Input Buffer --- */
   if( blio->inChan ) {
      avail = RingBuffer_GetWriteAvailable( &blio->inputRingBuffer );

      /* check for underflow */
      if( avail < frameCount * blio->inputSampleSize * blio->inChan )
         OSAtomicOr32( paInputOverflow, &blio->statusFlags );

      toRead = MIN( avail, frameCount * blio->inputSampleSize * blio->inChan );

      /* copy the data */
      /*printf( "reading %d\n", toRead );*/
      assert( toRead == RingBuffer_Write( &blio->inputRingBuffer, input, toRead ) );
#ifdef PA_MAC__BLIO_MUTEX
      /* Priority inversion. See notes below. */
      blioSetIsInputEmpty( blio, false );
#endif
   }


   /* --- Handle Output Buffer --- */
   if( blio->outChan ) {
      avail = RingBuffer_GetReadAvailable( &blio->outputRingBuffer );

      /* check for underflow */
      if( avail < frameCount * blio->outputSampleSize * blio->outChan )
         OSAtomicOr32( paOutputUnderflow, &blio->statusFlags );

      toWrite = MIN( avail, frameCount * blio->outputSampleSize * blio->outChan );

      if( toWrite != frameCount * blio->outputSampleSize * blio->outChan )
         bzero( ((char *)output)+toWrite,
                frameCount * blio->outputSampleSize * blio->outChan - toWrite );
      /* copy the data */
      /*printf( "writing %d\n", toWrite );*/
      assert( toWrite == RingBuffer_Read( &blio->outputRingBuffer, output, toWrite ) );
#ifdef PA_MAC__BLIO_MUTEX
      /* We have a priority inversion here. However, we will only have to
         wait if this was true and is now false, which means we've got
         some room in the buffer.
         Hopefully problems will be minimized. */
      blioSetIsOutputFull( blio, false );
#endif
   }

   return paContinue;
}
/* This should be called after stopping or aborting the stream, so that on next
   start, the buffers will be ready. */
PaError resetBlioRingBuffers( PaMacBlio *blio )
{
#ifdef PA_MAC__BLIO_MUTEX
   int result;
#endif
   blio->statusFlags = 0;
   if( blio->outputRingBuffer.buffer ) {
      PaUtil_FlushRingBuffer( &blio->outputRingBuffer );
      bzero( blio->outputRingBuffer.buffer,
             blio->outputRingBuffer.bufferSize );
      /* Advance buffer */
      PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->ringBufferFrames*blio->outputSampleSizeActual*blio->outChan );
      //PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->outputRingBuffer.bufferSize );

      /* Update isOutputFull. */
#ifdef PA_MAC__BLIO_MUTEX
      result = blioSetIsOutputFull( blio, toAdvance == blio->outputRingBuffer.bufferSize );
      if( result )
         goto error;
#endif
/*
      printf( "------%d\n" ,  blio->framesPerBuffer );
      printf( "------%d\n" ,  blio->outChan );
      printf( "------%d\n" ,  blio->outputSampleSize );
      printf( "------%d\n" ,  blio->framesPerBuffer*blio->outChan*blio->outputSampleSize );
*/
   }
   if( blio->inputRingBuffer.buffer ) {
      PaUtil_FlushRingBuffer( &blio->inputRingBuffer );
      bzero( blio->inputRingBuffer.buffer,
             blio->inputRingBuffer.bufferSize );
      /* Update isInputEmpty. */
#ifdef PA_MAC__BLIO_MUTEX
      result = blioSetIsInputEmpty( blio, true );
      if( result )
         goto error;
#endif
   }
   return paNoError;
#ifdef PA_MAC__BLIO_MUTEX
 error:
   return result;
#endif
}
PaError ReadStream( PaStream* stream,
                           void *buffer,
                           unsigned long frames )
{
    PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
    char *cbuf = (char *) buffer;
    PaError ret = paNoError;
    VVDBUG(("ReadStream()\n"));

    while( frames > 0 ) {
       long avail;
       long toRead;
       do {
          avail = PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer );
/*
          printf( "Read Buffer is %%%g full: %ld of %ld.\n",
                  100 * (float)avail / (float) blio->inputRingBuffer.bufferSize,
                  avail, blio->inputRingBuffer.bufferSize );
*/
          if( avail == 0 ) {
#ifdef PA_MAC_BLIO_MUTEX
             /**block when empty*/
             ret = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) );
             if( ret )
                return ret;
             while( blio->isInputEmpty ) {
                ret = UNIX_ERR( pthread_cond_wait( &blio->inputCond, &blio->inputMutex ) );
                if( ret )
                   return ret;
             }
             ret = UNIX_ERR( pthread_mutex_unlock( &blio->inputMutex ) );
             if( ret )
                return ret;
#else
             Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
#endif
          }
       } while( avail == 0 );
       toRead = MIN( avail, frames * blio->inputSampleSizeActual * blio->inChan );
       toRead -= toRead % blio->inputSampleSizeActual * blio->inChan ;
       PaUtil_ReadRingBuffer( &blio->inputRingBuffer, (void *)cbuf, toRead );
       cbuf += toRead;
       frames -= toRead / ( blio->inputSampleSizeActual * blio->inChan );

       if( toRead == avail ) {
#ifdef PA_MAC_BLIO_MUTEX
          /* we just emptied the buffer, so we need to mark it as empty. */
          ret = blioSetIsInputEmpty( blio, true );
          if( ret )
             return ret;
          /* of course, in the meantime, the callback may have put some sats
             in, so
             so check for that, too, to avoid a race condition. */
          if( PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ) ) {
             blioSetIsInputEmpty( blio, false );
             if( ret )
                return ret;
          }
#endif
       }
    }

    /*   Report either paNoError or paInputOverflowed. */
    /*   may also want to report other errors, but this is non-standard. */
    ret = blio->statusFlags & paInputOverflow;

    /* report underflow only once: */
    if( ret ) {
       OSAtomicAnd32( (uint32_t)(~paInputOverflow), &blio->statusFlags );
       ret = paInputOverflowed;
    }

    return ret;
}
Beispiel #4
0
PaError ReadStream( PaStream* stream,
                           void *buffer,
                           unsigned long framesRequested )
{
    PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
    char *cbuf = (char *) buffer;
    PaError ret = paNoError;
    VVDBUG(("ReadStream()\n"));

    while( framesRequested > 0 ) {
       ring_buffer_size_t framesAvailable;
       ring_buffer_size_t framesToTransfer;
       ring_buffer_size_t framesTransferred;
       do {
          framesAvailable = PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer );
/*
          printf( "Read Buffer is %%%g full: %ld of %ld.\n",
                  100 * (float)avail / (float) blio->inputRingBuffer.bufferSize,
                  framesAvailable, blio->inputRingBuffer.bufferSize );
*/
          if( framesAvailable == 0 ) {
#ifdef PA_MAC_BLIO_MUTEX
             /**block when empty*/
             ret = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) );
             if( ret )
                return ret;
             while( blio->isInputEmpty ) {
                ret = UNIX_ERR( pthread_cond_wait( &blio->inputCond, &blio->inputMutex ) );
                if( ret )
                   return ret;
             }
             ret = UNIX_ERR( pthread_mutex_unlock( &blio->inputMutex ) );
             if( ret )
                return ret;
#else
             Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
#endif
          }
       } while( framesAvailable == 0 );
       framesToTransfer = (ring_buffer_size_t) MIN( framesAvailable, framesRequested );
       framesTransferred = PaUtil_ReadRingBuffer( &blio->inputRingBuffer, (void *)cbuf, framesToTransfer );
       cbuf += framesTransferred * blio->inputSampleSizeActual * blio->inChan;
       framesRequested -= framesTransferred;

       if( framesToTransfer == framesAvailable ) {
#ifdef PA_MAC_BLIO_MUTEX
          /* we just emptied the buffer, so we need to mark it as empty. */
          ret = blioSetIsInputEmpty( blio, true );
          if( ret )
             return ret;
          /* of course, in the meantime, the callback may have put some sats
             in, so
             so check for that, too, to avoid a race condition. */
          /* FIXME - this does not seem to fix any race condition. */
          if( PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ) ) {
             blioSetIsInputEmpty( blio, false );
             /* FIXME - why check? ret has not been set? */
             if( ret )
                return ret;
          }
#endif
       }
    }

    /*   Report either paNoError or paInputOverflowed. */
    /*   may also want to report other errors, but this is non-standard. */
    /* FIXME should not clobber ret, use if(blio->statusFlags & paInputOverflow) */
    ret = blio->statusFlags & paInputOverflow;

    /* report underflow only once: */
    if( ret ) {
       OSAtomicAnd32( (uint32_t)(~paInputOverflow), &blio->statusFlags );
       ret = paInputOverflowed;
    }

    return ret;
}
Beispiel #5
0
/*
 * this is the BlioCallback function. It expects to recieve a PaMacBlio Object
 * pointer as userData.
 *
 */
int BlioCallback( const void *input, void *output, unsigned long frameCount,
	const PaStreamCallbackTimeInfo* timeInfo,
        PaStreamCallbackFlags statusFlags,
        void *userData )
{
   PaMacBlio *blio = (PaMacBlio*)userData;
   ring_buffer_size_t framesAvailable;
   ring_buffer_size_t framesToTransfer;
   ring_buffer_size_t framesTransferred;

   /* set flags returned by OS: */
   OSAtomicOr32( statusFlags, &blio->statusFlags ) ;

   /* --- Handle Input Buffer --- */
   if( blio->inChan ) {
      framesAvailable = PaUtil_GetRingBufferWriteAvailable( &blio->inputRingBuffer );

      /* check for underflow */
      if( framesAvailable < frameCount )
      {
          OSAtomicOr32( paInputOverflow, &blio->statusFlags );
          framesToTransfer = framesAvailable;
      }
      else
      {
          framesToTransfer = (ring_buffer_size_t)frameCount;
      }

      /* Copy the data from the audio input to the application ring buffer. */
      /*printf( "reading %d\n", toRead );*/
      framesTransferred = PaUtil_WriteRingBuffer( &blio->inputRingBuffer, input, framesToTransfer );
      assert( framesToTransfer == framesTransferred );
#ifdef PA_MAC__BLIO_MUTEX
      /* Priority inversion. See notes below. */
      blioSetIsInputEmpty( blio, false );
#endif
   }


   /* --- Handle Output Buffer --- */
   if( blio->outChan ) {
      framesAvailable = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer );

      /* check for underflow */
      if( framesAvailable < frameCount )
      {
          /* zero out the end of the output buffer that we do not have data for */
          framesToTransfer = framesAvailable;

          size_t bytesPerFrame = blio->outputSampleSizeActual * blio->outChan;
          size_t offsetInBytes = framesToTransfer * bytesPerFrame;
          size_t countInBytes = (frameCount - framesToTransfer) * bytesPerFrame;
          bzero( ((char *)output) + offsetInBytes, countInBytes );

          OSAtomicOr32( paOutputUnderflow, &blio->statusFlags );
          framesToTransfer = framesAvailable;
      }
      else
      {
          framesToTransfer = (ring_buffer_size_t)frameCount;
      }

      /* copy the data */
      /*printf( "writing %d\n", toWrite );*/
      framesTransferred = PaUtil_ReadRingBuffer( &blio->outputRingBuffer, output, framesToTransfer );
      assert( framesToTransfer == framesTransferred );
#ifdef PA_MAC__BLIO_MUTEX
      /* We have a priority inversion here. However, we will only have to
         wait if this was true and is now false, which means we've got
         some room in the buffer.
         Hopefully problems will be minimized. */
      blioSetIsOutputFull( blio, false );
#endif
   }

   return paContinue;
}