From 110043f84225aa12750d299152addd295184619c Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Wed, 18 May 2016 21:41:01 -0700 Subject: [PATCH 1/4] Fix assert when reading or writing with non-power of 2 channels. --- examples/paex_read_write_wire.c | 30 +--- src/hostapi/coreaudio/pa_mac_core.c | 26 +-- src/hostapi/coreaudio/pa_mac_core_blocking.c | 173 ++++++++++--------- src/hostapi/coreaudio/pa_mac_core_blocking.h | 9 +- 4 files changed, 120 insertions(+), 118 deletions(-) diff --git a/examples/paex_read_write_wire.c b/examples/paex_read_write_wire.c index 2f13426..586dd17 100644 --- a/examples/paex_read_write_wire.c +++ b/examples/paex_read_write_wire.c @@ -33,13 +33,13 @@ */ /* - * The text above constitutes the entire PortAudio license; however, + * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the * license above. */ @@ -51,7 +51,7 @@ /* #define SAMPLE_RATE (17932) // Test failure to open with this value. */ #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (1024) -#define NUM_CHANNELS (2) +#define NUM_CHANNELS (6) #define NUM_SECONDS (15) /* #define DITHER_FLAG (paDitherOff) */ #define DITHER_FLAG (0) /**/ @@ -109,8 +109,8 @@ int main(void) char *sampleBlock; int i; int numBytes; - - + + printf("patest_read_write_wire.c\n"); fflush(stdout); numBytes = FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ; @@ -170,24 +170,6 @@ int main(void) err = Pa_StopStream( stream ); if( err != paNoError ) goto error; - CLEAR( sampleBlock ); -/* - err = Pa_StartStream( stream ); - if( err != paNoError ) goto error; - printf("Wire on. Interrupt to stop.\n"); fflush(stdout); - - while( 1 ) - { - err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER ); - if( err ) goto xrun; - err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER ); - if( err ) goto xrun; - } - err = Pa_StopStream( stream ); - if( err != paNoError ) goto error; - - Pa_CloseStream( stream ); -*/ free( sampleBlock ); Pa_Terminate(); diff --git a/src/hostapi/coreaudio/pa_mac_core.c b/src/hostapi/coreaudio/pa_mac_core.c index 0aede34..4b7b43c 100644 --- a/src/hostapi/coreaudio/pa_mac_core.c +++ b/src/hostapi/coreaudio/pa_mac_core.c @@ -1921,14 +1921,13 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, /* * If input and output devs are different or we are doing SR conversion, - * we also need a - * ring buffer to store inpt data while waiting for output - * data. + * we also need a ring buffer to store input data while waiting for + * output data. */ if( (stream->outputUnit && (stream->inputUnit != stream->outputUnit)) || stream->inputSRConverter ) { - /* May want the ringSize ot initial position in + /* May want the ringSize or initial position in ring buffer to depend somewhat on sample rate change */ void *data; @@ -1951,7 +1950,15 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, } /* now we can initialize the ring buffer */ - PaUtil_InitializeRingBuffer( &stream->inputRingBuffer, szfl*inputParameters->channelCount, ringSize, data ) ; + result = PaUtil_InitializeRingBuffer( &stream->inputRingBuffer, szfl*inputParameters->channelCount, ringSize, data ); + if( result != 0 ) + { + /* The only reason this should fail is if ringSize is not a power of 2, which we do not anticipate happening. */ + result = paUnanticipatedHostError; + free(data); + goto error; + } + /* advance the read point a little, so we are reading from the middle of the buffer */ if( stream->outputUnit ) @@ -1973,12 +1980,11 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, stream->outputFramesPerBuffer, sampleRate ); result = initializeBlioRingBuffers( &stream->blio, - inputParameters?inputParameters->sampleFormat:0 , - outputParameters?outputParameters->sampleFormat:0 , - MAX(stream->inputFramesPerBuffer,stream->outputFramesPerBuffer), + inputParameters ? inputParameters->sampleFormat : 0, + outputParameters ? outputParameters->sampleFormat : 0, ringSize, - inputParameters?inputChannelCount:0 , - outputParameters?outputChannelCount:0 ) ; + inputParameters ? inputChannelCount : 0, + outputParameters ? outputChannelCount : 0 ) ; if( result != paNoError ) goto error; diff --git a/src/hostapi/coreaudio/pa_mac_core_blocking.c b/src/hostapi/coreaudio/pa_mac_core_blocking.c index e366aa3..485c373 100644 --- a/src/hostapi/coreaudio/pa_mac_core_blocking.c +++ b/src/hostapi/coreaudio/pa_mac_core_blocking.c @@ -108,14 +108,16 @@ static size_t computeSampleSizeFromFormatPow2( PaSampleFormat format ) * */ -/* 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 ) { @@ -126,20 +128,19 @@ PaError initializeBlioRingBuffers( /* 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; @@ -163,7 +164,7 @@ PaError initializeBlioRingBuffers( 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; @@ -172,12 +173,13 @@ PaError initializeBlioRingBuffers( 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; @@ -186,7 +188,8 @@ PaError initializeBlioRingBuffers( err = PaUtil_InitializeRingBuffer( &blio->outputRingBuffer, - 1, ringBufferSize*blio->outputSampleSizePow2*outChan, + blio->outputSampleSizePow2 * outChan, + ringBufferSizeInFrames, data ); assert( !err ); } @@ -266,12 +269,11 @@ PaError resetBlioRingBuffers( PaMacBlio *blio ) #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 @@ -280,16 +282,14 @@ PaError resetBlioRingBuffers( PaMacBlio *blio ) 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 ); @@ -344,30 +344,32 @@ int BlioCallback( const void *input, void *output, unsigned long frameCount, 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 ); @@ -377,21 +379,31 @@ int BlioCallback( const void *input, void *output, unsigned long frameCount, /* --- 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 @@ -406,24 +418,25 @@ int BlioCallback( const void *input, void *output, unsigned long frameCount, 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 ) ); @@ -441,14 +454,13 @@ PaError ReadStream( PaStream* stream, 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 ); + } while( framesAvailable == 0 ); + framesToTransfer = MIN( framesAvailable, framesRequested ); + PaUtil_ReadRingBuffer( &blio->inputRingBuffer, (void *)cbuf, framesToTransfer ); + cbuf += framesToTransfer * blio->inputSampleSizeActual * blio->inChan; + framesRequested -= framesToTransfer; - if( toRead == avail ) { + 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 ); @@ -457,8 +469,10 @@ PaError ReadStream( PaStream* stream, /* 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; } @@ -468,6 +482,7 @@ PaError ReadStream( PaStream* stream, /* 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: */ @@ -482,25 +497,27 @@ PaError ReadStream( PaStream* stream, 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 ) ); @@ -518,16 +535,15 @@ PaError WriteStream( PaStream* stream, 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 ) @@ -536,6 +552,7 @@ PaError WriteStream( PaStream* stream, 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; } @@ -545,6 +562,7 @@ PaError WriteStream( PaStream* stream, /* 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: */ @@ -562,11 +580,12 @@ PaError WriteStream( PaStream* stream, 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 ); } } } @@ -577,8 +596,7 @@ signed long GetStreamReadAvailable( PaStream* stream ) PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; VVDBUG(("GetStreamReadAvailable()\n")); - return PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ) - / ( blio->inputSampleSizeActual * blio->inChan ); + return PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ); } @@ -587,7 +605,6 @@ signed long GetStreamWriteAvailable( PaStream* stream ) PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; VVDBUG(("GetStreamWriteAvailable()\n")); - return PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ) - / ( blio->outputSampleSizeActual * blio->outChan ); + return PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); } diff --git a/src/hostapi/coreaudio/pa_mac_core_blocking.h b/src/hostapi/coreaudio/pa_mac_core_blocking.h index a6f0ad5..c669e0b 100644 --- a/src/hostapi/coreaudio/pa_mac_core_blocking.h +++ b/src/hostapi/coreaudio/pa_mac_core_blocking.h @@ -64,7 +64,7 @@ #include "pa_mac_core_utilities.h" /* - * Number of miliseconds to busy wait whil waiting for data in blocking calls. + * Number of milliseconds to busy wait while waiting for data in blocking calls. */ #define PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL (5) /* @@ -79,7 +79,7 @@ typedef struct { PaUtilRingBuffer inputRingBuffer; PaUtilRingBuffer outputRingBuffer; - size_t ringBufferFrames; + ring_buffer_size_t ringBufferFrames; PaSampleFormat inputSampleFormat; size_t inputSampleSizeActual; size_t inputSampleSizePow2; @@ -87,8 +87,6 @@ typedef struct { size_t outputSampleSizeActual; size_t outputSampleSizePow2; - size_t framesPerBuffer; - int inChan; int outChan; @@ -117,8 +115,7 @@ PaError initializeBlioRingBuffers( PaMacBlio *blio, PaSampleFormat inputSampleFormat, PaSampleFormat outputSampleFormat, - size_t framesPerBuffer, - long ringBufferSize, + long ringBufferSizeInFrames, int inChan, int outChan ); PaError destroyBlioRingBuffers( PaMacBlio *blio ); From 315309f60e8f77531a4e2d14d52b3fc46ee8196f Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Sat, 21 May 2016 17:25:18 -0700 Subject: [PATCH 2/4] Mac: test adjustable number of channels. --- examples/paex_read_write_wire.c | 111 ++++++++++--------- qa/paqa_devs.c | 10 +- src/hostapi/coreaudio/pa_mac_core_blocking.c | 13 +-- test/patest_maxsines.c | 12 +- test/patest_multi_sine.c | 2 +- 5 files changed, 74 insertions(+), 74 deletions(-) diff --git a/examples/paex_read_write_wire.c b/examples/paex_read_write_wire.c index 586dd17..2bb41d1 100644 --- a/examples/paex_read_write_wire.c +++ b/examples/paex_read_write_wire.c @@ -49,56 +49,40 @@ #include "portaudio.h" /* #define SAMPLE_RATE (17932) // Test failure to open with this value. */ -#define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (1024) -#define NUM_CHANNELS (6) -#define NUM_SECONDS (15) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (512) +#define NUM_SECONDS (10) /* #define DITHER_FLAG (paDitherOff) */ -#define DITHER_FLAG (0) /**/ - -/* @todo Underflow and overflow is disabled until we fix priming of blocking write. */ -#define CHECK_OVERFLOW (0) -#define CHECK_UNDERFLOW (0) - +#define DITHER_FLAG (0) /* Select sample format. */ -#if 0 +#if 1 #define PA_SAMPLE_TYPE paFloat32 #define SAMPLE_SIZE (4) #define SAMPLE_SILENCE (0.0f) -#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) #define PRINTF_S_FORMAT "%.8f" #elif 0 #define PA_SAMPLE_TYPE paInt16 #define SAMPLE_SIZE (2) #define SAMPLE_SILENCE (0) -#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) #define PRINTF_S_FORMAT "%d" -#elif 1 +#elif 0 #define PA_SAMPLE_TYPE paInt24 #define SAMPLE_SIZE (3) #define SAMPLE_SILENCE (0) -#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) #define PRINTF_S_FORMAT "%d" #elif 0 #define PA_SAMPLE_TYPE paInt8 #define SAMPLE_SIZE (1) #define SAMPLE_SILENCE (0) -#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) #define PRINTF_S_FORMAT "%d" #else #define PA_SAMPLE_TYPE paUInt8 #define SAMPLE_SIZE (1) #define SAMPLE_SILENCE (128) -#define CLEAR( a ) { \ - int i; \ - for( i=0; idefaultLowInputLatency ); - printf( "Input HL: %g s\n", Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ); - inputParameters.channelCount = NUM_CHANNELS; - inputParameters.sampleFormat = PA_SAMPLE_TYPE; - inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ; - inputParameters.hostApiSpecificStreamInfo = NULL; + inputInfo = Pa_GetDeviceInfo( inputParameters.device ); + printf( " Name: %s\n", inputInfo->name ); + printf( " LL: %g s\n", inputInfo->defaultLowInputLatency ); + printf( " HL: %g s\n", inputInfo->defaultHighInputLatency ); outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ printf( "Output device # %d.\n", outputParameters.device ); - printf( "Output LL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency ); - printf( "Output HL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency ); - outputParameters.channelCount = NUM_CHANNELS; + outputInfo = Pa_GetDeviceInfo( outputParameters.device ); + printf( " Name: %s\n", outputInfo->name ); + printf( " LL: %g s\n", outputInfo->defaultLowOutputLatency ); + printf( " HL: %g s\n", outputInfo->defaultHighOutputLatency ); + + int numChannels = inputInfo->maxInputChannels < outputInfo->maxOutputChannels + ? inputInfo->maxInputChannels : outputInfo->maxOutputChannels; + printf( "Num channels = %d.\n", numChannels ); + + inputParameters.channelCount = numChannels; + inputParameters.sampleFormat = PA_SAMPLE_TYPE; + inputParameters.suggestedLatency = inputInfo->defaultHighInputLatency ; + inputParameters.hostApiSpecificStreamInfo = NULL; + + outputParameters.channelCount = numChannels; outputParameters.sampleFormat = PA_SAMPLE_TYPE; - outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; + outputParameters.suggestedLatency = outputInfo->defaultHighOutputLatency; outputParameters.hostApiSpecificStreamInfo = NULL; /* -- setup -- */ - err = Pa_OpenStream( + err = Pa_OpenStream( &stream, &inputParameters, &outputParameters, @@ -154,21 +142,33 @@ int main(void) paClipOff, /* we won't output out of range samples so don't bother clipping them */ NULL, /* no callback, use blocking API */ NULL ); /* no callback, so no callback userData */ - if( err != paNoError ) goto error; + if( err != paNoError ) goto error2; + + numBytes = FRAMES_PER_BUFFER * numChannels * SAMPLE_SIZE ; + sampleBlock = (char *) malloc( numBytes ); + if( sampleBlock == NULL ) + { + printf("Could not allocate record array.\n"); + goto error1; + } + memset( sampleBlock, SAMPLE_SILENCE, numBytes ); err = Pa_StartStream( stream ); - if( err != paNoError ) goto error; + if( err != paNoError ) goto error1; printf("Wire on. Will run %d seconds.\n", NUM_SECONDS); fflush(stdout); for( i=0; i<(NUM_SECONDS*SAMPLE_RATE)/FRAMES_PER_BUFFER; ++i ) { - err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER ); - if( err && CHECK_UNDERFLOW ) goto xrun; - err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER ); - if( err && CHECK_OVERFLOW ) goto xrun; + // You may get underruns or overruns if the output is not primed by PortAudio. + err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER ); + if( err ) goto xrun; + err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER ); + if( err ) goto xrun; } + printf("Wire off.\n"); fflush(stdout); + err = Pa_StopStream( stream ); - if( err != paNoError ) goto error; + if( err != paNoError ) goto error1; free( sampleBlock ); @@ -176,6 +176,7 @@ int main(void) return 0; xrun: + printf("err = %d\n", err); fflush(stdout); if( stream ) { Pa_AbortStream( stream ); Pa_CloseStream( stream ); @@ -187,13 +188,13 @@ xrun: if( err & paOutputUnderflow ) fprintf( stderr, "Output Underflow.\n" ); return -2; - -error: +error1: + free( sampleBlock ); +error2: if( stream ) { Pa_AbortStream( stream ); Pa_CloseStream( stream ); } - free( sampleBlock ); Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); diff --git a/qa/paqa_devs.c b/qa/paqa_devs.c index 721b07f..5bfdaab 100644 --- a/qa/paqa_devs.c +++ b/qa/paqa_devs.c @@ -231,7 +231,7 @@ static void TestDevices( int mode ) 88200.0, 96000.0, -1.0 }; /* Negative terminated list. */ int numDevices = Pa_GetDeviceCount(); - for( id=0; id MAX_TEST_CHANNELS ) maxChannels = MAX_TEST_CHANNELS; - for( jc=1; jc<=maxChannels; jc++ ) + for( jc=4; jc<=maxChannels; jc++ ) { printf("\n========================================================================\n"); printf(" Device = %s\n", pdi->name ); printf("========================================================================\n"); /* Try each standard sample rate. */ - for( i=0; standardSampleRates[i] > 0; i++ ) + for( i=9; standardSampleRates[i] > 0; i++ ) { TestFormats( mode, (PaDeviceIndex)id, standardSampleRates[i], jc ); } @@ -258,8 +258,8 @@ static void TestFormats( int mode, PaDeviceIndex deviceID, double sampleRate, int numChannels ) { TestAdvance( mode, deviceID, sampleRate, numChannels, paFloat32 ); - TestAdvance( mode, deviceID, sampleRate, numChannels, paInt16 ); - TestAdvance( mode, deviceID, sampleRate, numChannels, paInt32 ); +// TestAdvance( mode, deviceID, sampleRate, numChannels, paInt16 ); +// TestAdvance( mode, deviceID, sampleRate, numChannels, paInt32 ); /* TestAdvance( mode, deviceID, sampleRate, numChannels, paInt24 ); */ } diff --git a/src/hostapi/coreaudio/pa_mac_core_blocking.c b/src/hostapi/coreaudio/pa_mac_core_blocking.c index 485c373..92c3251 100644 --- a/src/hostapi/coreaudio/pa_mac_core_blocking.c +++ b/src/hostapi/coreaudio/pa_mac_core_blocking.c @@ -456,9 +456,9 @@ PaError ReadStream( PaStream* stream, } } while( framesAvailable == 0 ); framesToTransfer = MIN( framesAvailable, framesRequested ); - PaUtil_ReadRingBuffer( &blio->inputRingBuffer, (void *)cbuf, framesToTransfer ); - cbuf += framesToTransfer * blio->inputSampleSizeActual * blio->inChan; - framesRequested -= framesToTransfer; + framesTransferred = PaUtil_ReadRingBuffer( &blio->inputRingBuffer, (void *)cbuf, framesToTransfer ); + cbuf += framesTransferred * blio->inputSampleSizeActual * blio->inChan; + framesRequested -= framesTransferred; if( framesToTransfer == framesAvailable ) { #ifdef PA_MAC_BLIO_MUTEX @@ -509,7 +509,6 @@ PaError WriteStream( PaStream* stream, ring_buffer_size_t framesToTransfer; ring_buffer_size_t framesTransferred; - do { framesAvailable = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); /* @@ -538,9 +537,9 @@ PaError WriteStream( PaStream* stream, } while( framesAvailable == 0 ); framesToTransfer = MIN( framesAvailable, framesRequested ); - PaUtil_WriteRingBuffer( &blio->outputRingBuffer, (void *)cbuf, framesToTransfer ); - cbuf += framesToTransfer * blio->outputSampleSizeActual * blio->outChan; - framesRequested -= framesToTransfer; + framesTransferred = PaUtil_WriteRingBuffer( &blio->outputRingBuffer, (void *)cbuf, framesToTransfer ); + cbuf += framesTransferred * blio->outputSampleSizeActual * blio->outChan; + framesRequested -= framesTransferred; #ifdef PA_MAC_BLIO_MUTEX if( framesToTransfer == framesAvailable ) { diff --git a/test/patest_maxsines.c b/test/patest_maxsines.c index 1dd9556..49db8d2 100644 --- a/test/patest_maxsines.c +++ b/test/patest_maxsines.c @@ -46,8 +46,8 @@ #include #include "portaudio.h" -#define MAX_SINES (500) -#define MAX_USAGE (0.8) +#define MAX_SINES (2000) +#define MAX_USAGE (0.5) #define SAMPLE_RATE (44100) #define FREQ_TO_PHASE_INC(freq) (freq/(float)SAMPLE_RATE) @@ -60,7 +60,7 @@ #endif #define TWOPI (M_PI * 2.0) -#define TABLE_SIZE (512) +#define TABLE_SIZE (1024) typedef struct paTestData { @@ -70,7 +70,7 @@ typedef struct paTestData } paTestData; -/* Convert phase between and 1.0 to sine value +/* Convert phase between 0.0 and 1.0 to sine value * using linear interpolation. */ float LookupSine( paTestData *data, float phase ); @@ -187,14 +187,14 @@ int main(void) /* Play an increasing number of sine waves until we hit MAX_USAGE */ do { - data.numSines++; + data.numSines += 10; Pa_Sleep(200); load = Pa_GetStreamCpuLoad(stream); printf("numSines = %d, CPU load = %f\n", data.numSines, load ); fflush(stdout); } while((load < MAX_USAGE) && (data.numSines < MAX_SINES)); - Pa_Sleep(2000); /* Stay for 2 seconds around 80% CPU. */ + Pa_Sleep(2000); /* Stay for 2 seconds at max CPU. */ err = Pa_StopStream( stream ); if( err != paNoError ) diff --git a/test/patest_multi_sine.c b/test/patest_multi_sine.c index 5e149f6..2b11bfc 100644 --- a/test/patest_multi_sine.c +++ b/test/patest_multi_sine.c @@ -47,7 +47,7 @@ #include "portaudio.h" #define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (256) +#define FRAMES_PER_BUFFER (128) #define FREQ_INCR (300.0 / SAMPLE_RATE) #define MAX_CHANNELS (64) From 36a6c92caac08319443254d13a10b89616777039 Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Sat, 21 May 2016 17:30:21 -0700 Subject: [PATCH 3/4] Revert paqa_devs --- qa/paqa_devs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qa/paqa_devs.c b/qa/paqa_devs.c index 5bfdaab..edf3071 100644 --- a/qa/paqa_devs.c +++ b/qa/paqa_devs.c @@ -231,7 +231,7 @@ static void TestDevices( int mode ) 88200.0, 96000.0, -1.0 }; /* Negative terminated list. */ int numDevices = Pa_GetDeviceCount(); - for( id=3; id MAX_TEST_CHANNELS ) maxChannels = MAX_TEST_CHANNELS; - for( jc=4; jc<=maxChannels; jc++ ) + for( jc=1; jc<=maxChannels; jc++ ) { printf("\n========================================================================\n"); printf(" Device = %s\n", pdi->name ); printf("========================================================================\n"); /* Try each standard sample rate. */ - for( i=9; standardSampleRates[i] > 0; i++ ) + for( i=0; standardSampleRates[i] > 0; i++ ) { TestFormats( mode, (PaDeviceIndex)id, standardSampleRates[i], jc ); } From e89441f968ca36bdf487454122fef9bbb2c72a36 Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Sat, 21 May 2016 17:31:53 -0700 Subject: [PATCH 4/4] Restore paqa_devs --- qa/paqa_devs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qa/paqa_devs.c b/qa/paqa_devs.c index edf3071..721b07f 100644 --- a/qa/paqa_devs.c +++ b/qa/paqa_devs.c @@ -258,8 +258,8 @@ static void TestFormats( int mode, PaDeviceIndex deviceID, double sampleRate, int numChannels ) { TestAdvance( mode, deviceID, sampleRate, numChannels, paFloat32 ); -// TestAdvance( mode, deviceID, sampleRate, numChannels, paInt16 ); -// TestAdvance( mode, deviceID, sampleRate, numChannels, paInt32 ); + TestAdvance( mode, deviceID, sampleRate, numChannels, paInt16 ); + TestAdvance( mode, deviceID, sampleRate, numChannels, paInt32 ); /* TestAdvance( mode, deviceID, sampleRate, numChannels, paInt24 ); */ }