*
*/
-/* This should be called with the relevant info when initializing a stream for
- callback. */
+/**
+ * This should be called with the relevant info when initializing a stream for callback.
+ *
+ * @param ringBufferSizeInFrames must be a power of 2
+ */
PaError initializeBlioRingBuffers(
PaMacBlio *blio,
PaSampleFormat inputSampleFormat,
PaSampleFormat outputSampleFormat,
- size_t framesPerBuffer,
- long ringBufferSize,
+ long ringBufferSizeInFrames,
int inChan,
int outChan )
{
/* zeroify things */
bzero( blio, sizeof( PaMacBlio ) );
/* this is redundant, but the buffers are used to check
- if the bufffers have been initialized, so we do it explicitly. */
+ if the buffers have been initialized, so we do it explicitly. */
blio->inputRingBuffer.buffer = NULL;
blio->outputRingBuffer.buffer = NULL;
/* initialize simple data */
- blio->ringBufferFrames = ringBufferSize;
+ blio->ringBufferFrames = ringBufferSizeInFrames;
blio->inputSampleFormat = inputSampleFormat;
blio->inputSampleSizeActual = computeSampleSizeFromFormat(inputSampleFormat);
- blio->inputSampleSizePow2 = computeSampleSizeFromFormatPow2(inputSampleFormat);
+ blio->inputSampleSizePow2 = computeSampleSizeFromFormatPow2(inputSampleFormat); // FIXME: WHY?
blio->outputSampleFormat = outputSampleFormat;
blio->outputSampleSizeActual = computeSampleSizeFromFormat(outputSampleFormat);
blio->outputSampleSizePow2 = computeSampleSizeFromFormatPow2(outputSampleFormat);
- blio->framesPerBuffer = framesPerBuffer;
blio->inChan = inChan;
blio->outChan = outChan;
blio->statusFlags = 0;
result = UNIX_ERR( pthread_cond_init( &(blio->outputCond), NULL ) );
#endif
if( inChan ) {
- data = calloc( ringBufferSize, blio->inputSampleSizePow2*inChan );
+ data = calloc( ringBufferSizeInFrames, blio->inputSampleSizePow2 * inChan );
if( !data )
{
result = paInsufficientMemory;
err = PaUtil_InitializeRingBuffer(
&blio->inputRingBuffer,
- 1, ringBufferSize*blio->inputSampleSizePow2*inChan,
+ blio->inputSampleSizePow2 * inChan,
+ ringBufferSizeInFrames,
data );
assert( !err );
}
if( outChan ) {
- data = calloc( ringBufferSize, blio->outputSampleSizePow2*outChan );
+ data = calloc( ringBufferSizeInFrames, blio->outputSampleSizePow2 * outChan );
if( !data )
{
result = paInsufficientMemory;
err = PaUtil_InitializeRingBuffer(
&blio->outputRingBuffer,
- 1, ringBufferSize*blio->outputSampleSizePow2*outChan,
+ blio->outputSampleSizePow2 * outChan,
+ ringBufferSizeInFrames,
data );
assert( !err );
}
#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 );
+ PaUtil_FlushRingBuffer( &blio->outputRingBuffer );
+ /* Fill the buffer with zeros. */
+ bzero( blio->outputRingBuffer.buffer,
+ blio->outputRingBuffer.bufferSize * blio->outputRingBuffer.elementSizeBytes );
+ PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->ringBufferFrames );
/* Update isOutputFull. */
#ifdef PA_MAC__BLIO_MUTEX
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 );
+ blio->inputRingBuffer.bufferSize * blio->inputRingBuffer.elementSizeBytes );
/* Update isInputEmpty. */
#ifdef PA_MAC__BLIO_MUTEX
result = blioSetIsInputEmpty( blio, true );
void *userData )
{
PaMacBlio *blio = (PaMacBlio*)userData;
- long avail;
- long toRead;
- long toWrite;
- long read;
- long written;
+ 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 ) {
- avail = PaUtil_GetRingBufferWriteAvailable( &blio->inputRingBuffer );
+ framesAvailable = PaUtil_GetRingBufferWriteAvailable( &blio->inputRingBuffer );
/* check for underflow */
- if( avail < frameCount * blio->inputSampleSizeActual * blio->inChan )
+ if( framesAvailable < frameCount )
{
- OSAtomicOr32( paInputOverflow, &blio->statusFlags );
+ OSAtomicOr32( paInputOverflow, &blio->statusFlags );
+ framesToTransfer = framesAvailable;
+ }
+ else
+ {
+ framesToTransfer = (ring_buffer_size_t)frameCount;
}
- toRead = MIN( avail, frameCount * blio->inputSampleSizeActual * blio->inChan );
- /* copy the data */
+ /* Copy the data from the audio input to the application ring buffer. */
/*printf( "reading %d\n", toRead );*/
- read = PaUtil_WriteRingBuffer( &blio->inputRingBuffer, input, toRead );
- assert( toRead == read );
+ framesTransferred = PaUtil_WriteRingBuffer( &blio->inputRingBuffer, input, framesToTransfer );
+ assert( framesToTransfer == framesTransferred );
#ifdef PA_MAC__BLIO_MUTEX
/* Priority inversion. See notes below. */
blioSetIsInputEmpty( blio, false );
/* --- Handle Output Buffer --- */
if( blio->outChan ) {
- avail = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer );
+ framesAvailable = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer );
/* check for underflow */
- if( avail < frameCount * blio->outputSampleSizeActual * blio->outChan )
- OSAtomicOr32( paOutputUnderflow, &blio->statusFlags );
+ if( framesAvailable < frameCount )
+ {
+ /* zero out the end of the output buffer that we do not have data for */
+ framesToTransfer = framesAvailable;
- toWrite = MIN( avail, frameCount * blio->outputSampleSizeActual * blio->outChan );
+ 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;
+ }
- if( toWrite != frameCount * blio->outputSampleSizeActual * blio->outChan )
- bzero( ((char *)output)+toWrite,
- frameCount * blio->outputSampleSizeActual * blio->outChan - toWrite );
/* copy the data */
/*printf( "writing %d\n", toWrite );*/
- written = PaUtil_ReadRingBuffer( &blio->outputRingBuffer, output, toWrite );
- assert( toWrite == written );
+ 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
PaError ReadStream( PaStream* stream,
void *buffer,
- unsigned long frames )
+ unsigned long framesRequested )
{
PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
char *cbuf = (char *) buffer;
PaError ret = paNoError;
VVDBUG(("ReadStream()\n"));
- while( frames > 0 ) {
- long avail;
- long toRead;
+ while( framesRequested > 0 ) {
+ ring_buffer_size_t framesAvailable;
+ ring_buffer_size_t framesToTransfer;
+ ring_buffer_size_t framesTransferred;
do {
- avail = PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer );
+ framesAvailable = 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 );
+ framesAvailable, blio->inputRingBuffer.bufferSize );
*/
- if( avail == 0 ) {
+ if( framesAvailable == 0 ) {
#ifdef PA_MAC_BLIO_MUTEX
/**block when empty*/
ret = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) );
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 ) {
+ } while( framesAvailable == 0 );
+ framesToTransfer = MIN( framesAvailable, framesRequested );
+ PaUtil_ReadRingBuffer( &blio->inputRingBuffer, (void *)cbuf, framesToTransfer );
+ cbuf += framesToTransfer * blio->inputSampleSizeActual * blio->inChan;
+ framesRequested -= framesToTransfer;
+
+ 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 );
/* 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;
}
/* 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: */
PaError WriteStream( PaStream* stream,
const void *buffer,
- unsigned long frames )
+ unsigned long framesRequested )
{
PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
char *cbuf = (char *) buffer;
PaError ret = paNoError;
VVDBUG(("WriteStream()\n"));
- while( frames > 0 ) {
- long avail = 0;
- long toWrite;
+ while( framesRequested > 0 ) {
+ ring_buffer_size_t framesAvailable;
+ ring_buffer_size_t framesToTransfer;
+ ring_buffer_size_t framesTransferred;
+
do {
- avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
+ framesAvailable = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
/*
printf( "Write Buffer is %%%g full: %ld of %ld.\n",
100 - 100 * (float)avail / (float) blio->outputRingBuffer.bufferSize,
- avail, blio->outputRingBuffer.bufferSize );
+ framesAvailable, blio->outputRingBuffer.bufferSize );
*/
- if( avail == 0 ) {
+ if( framesAvailable == 0 ) {
#ifdef PA_MAC_BLIO_MUTEX
/*block while full*/
ret = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) );
Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
#endif
}
- } while( avail == 0 );
+ } while( framesAvailable == 0 );
- toWrite = MIN( avail, frames * blio->outputSampleSizeActual * blio->outChan );
- toWrite -= toWrite % blio->outputSampleSizeActual * blio->outChan ;
- PaUtil_WriteRingBuffer( &blio->outputRingBuffer, (void *)cbuf, toWrite );
- cbuf += toWrite;
- frames -= toWrite / ( blio->outputSampleSizeActual * blio->outChan );
+ framesToTransfer = MIN( framesAvailable, framesRequested );
+ PaUtil_WriteRingBuffer( &blio->outputRingBuffer, (void *)cbuf, framesToTransfer );
+ cbuf += framesToTransfer * blio->outputSampleSizeActual * blio->outChan;
+ framesRequested -= framesToTransfer;
#ifdef PA_MAC_BLIO_MUTEX
- if( toWrite == avail ) {
+ if( framesToTransfer == framesAvailable ) {
/* we just filled up the buffer, so we need to mark it as filled. */
ret = blioSetIsOutputFull( blio, true );
if( ret )
so check for that, too, to avoid a race condition. */
if( PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ) ) {
blioSetIsOutputFull( blio, false );
+ /* FIXME remove or review this code, does not fix race, ret not set! */
if( ret )
return ret;
}
/* Report either paNoError or paOutputUnderflowed. */
/* 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 & paOutputUnderflow;
/* report underflow only once: */
void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio )
{
if( blio->outputRingBuffer.buffer ) {
- long avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
- while( avail != blio->outputRingBuffer.bufferSize ) {
- if( avail == 0 )
+ /* FIXME loop until PaUtil_GetRingBufferReadAvailable==0 */
+ ring_buffer_size_t framesAvailable = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
+ while( framesAvailable != blio->outputRingBuffer.bufferSize ) {
+ if( framesAvailable == 0 )
Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
- avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
+ framesAvailable = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
}
}
}
PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
VVDBUG(("GetStreamReadAvailable()\n"));
- return PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer )
- / ( blio->inputSampleSizeActual * blio->inChan );
+ return PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer );
}
PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
VVDBUG(("GetStreamWriteAvailable()\n"));
- return PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer )
- / ( blio->outputSampleSizeActual * blio->outChan );
+ return PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
}