Fix ring buffer handling in pa_mac_core.c that caused many spurious paInputOverflow flags.

Fixed size bug when input underflow detected. Code was confused between bytes and elements.
Zero out the beginning of a recording when detecting pops to prevent start of audio from looking like a pop in qa loopback test.
This commit is contained in:
philburk 2012-06-25 01:12:29 +00:00
commit b4a22b91ff
4 changed files with 55 additions and 42 deletions

View file

@ -515,6 +515,12 @@ void PaQa_FadeInRecording( PaQaRecording *recording, int startFrame, int count )
assert( startFrame >= 0 );
assert( count > 0 );
/* Zero out initial part of the recording. */
for( is=0; is<startFrame; is++ )
{
recording->buffer[ is ] = 0.0f;
}
/* Fade in where signal begins. */
for( is=0; is<count; is++ )
{
double c = cos( phase );

View file

@ -989,8 +989,8 @@ static int PaQa_AnalyzeLoopbackConnection( UserOptions *userOptions, PaDeviceInd
int framesPerBuffers[] = { 0, 16, 32, 40, 64, 100, 128, 256, 512, 1024 };
int numBufferSizes = (sizeof(framesPerBuffers)/sizeof(int));
PaSampleFormat sampleFormats[] = { paUInt8, paInt8, paInt16, paInt32 };
const char *sampleFormatNames[] = { "paUInt8", "paInt8", "paInt16", "paInt32" };
PaSampleFormat sampleFormats[] = { paFloat32, paUInt8, paInt8, paInt16, paInt32 };
const char *sampleFormatNames[] = { "paFloat32", "paUInt8", "paInt8", "paInt16", "paInt32" };
int numSampleFormats = (sizeof(sampleFormats)/sizeof(PaSampleFormat));
printf( "=============== Analysing Loopback %d to %d =====================\n", outputDevice, inputDevice );

View file

@ -1774,25 +1774,16 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
do is initialize everything so that if we fail, we know what hasn't
been touched.
*/
bzero( stream, sizeof( PaMacCoreStream ) );
stream->inputAudioBufferList.mBuffers[0].mData = NULL;
stream->inputRingBuffer.buffer = NULL;
bzero( &stream->blio, sizeof( PaMacBlio ) );
/*
/*
stream->blio.inputRingBuffer.buffer = NULL;
stream->blio.outputRingBuffer.buffer = NULL;
stream->blio.inputSampleFormat = inputParameters?inputParameters->sampleFormat:0;
stream->blio.inputSampleSize = computeSampleSizeFromFormat(stream->blio.inputSampleFormat);
stream->blio.outputSampleFormat=outputParameters?outputParameters->sampleFormat:0;
stream->blio.outputSampleSize = computeSampleSizeFromFormat(stream->blio.outputSampleFormat);
*/
stream->inputSRConverter = NULL;
stream->inputUnit = NULL;
stream->outputUnit = NULL;
stream->inputFramesPerBuffer = 0;
stream->outputFramesPerBuffer = 0;
stream->bufferProcessorIsInitialized = FALSE;
stream->timingInformationMutexIsInitialized = 0;
*/
/* assert( streamCallback ) ; */ /* only callback mode is implemented */
if( streamCallback )
@ -2251,6 +2242,7 @@ static OSStatus AudioIOProc( void *inRefCon,
*/
OSStatus err = 0;
unsigned long frames;
long bytesPerFrame = sizeof( float ) * ioData->mBuffers[0].mNumberChannels;
/* -- start processing -- */
PaUtil_BeginBufferProcessing( &(stream->bufferProcessor),
@ -2261,8 +2253,8 @@ static OSStatus AudioIOProc( void *inRefCon,
/* -- compute frames. do some checks -- */
assert( ioData->mNumberBuffers == 1 );
assert( ioData->mBuffers[0].mNumberChannels == stream->userOutChan );
frames = ioData->mBuffers[0].mDataByteSize;
frames /= sizeof( float ) * ioData->mBuffers[0].mNumberChannels;
frames = ioData->mBuffers[0].mDataByteSize / bytesPerFrame;
/* -- copy and process input data -- */
err= AudioUnitRender(stream->inputUnit,
ioActionFlags,
@ -2301,6 +2293,7 @@ static OSStatus AudioIOProc( void *inRefCon,
* is required on input, that is done here as well.
*/
unsigned long frames;
long bytesPerFrame = sizeof( float ) * ioData->mBuffers[0].mNumberChannels;
/* Sometimes, when stopping a duplex stream we get erroneous
xrun flags, so if this is our last run, clear the flags. */
@ -2322,8 +2315,7 @@ static OSStatus AudioIOProc( void *inRefCon,
/* -- Copy and process output data -- */
assert( ioData->mNumberBuffers == 1 );
frames = ioData->mBuffers[0].mDataByteSize;
frames /= sizeof( float ) * ioData->mBuffers[0].mNumberChannels;
frames = ioData->mBuffers[0].mDataByteSize / bytesPerFrame;
assert( ioData->mBuffers[0].mNumberChannels == stream->userOutChan );
PaUtil_SetOutputFrameCount( &(stream->bufferProcessor), frames );
PaUtil_SetInterleavedOutputChannels( &(stream->bufferProcessor),
@ -2337,6 +2329,8 @@ static OSStatus AudioIOProc( void *inRefCon,
/* Here, we read the data out of the ring buffer, through the
audio converter. */
int inChan = stream->inputAudioBufferList.mBuffers[0].mNumberChannels;
long bytesPerFrame = flsz * inChan;
if( stream->inputSRConverter )
{
OSStatus err;
@ -2353,8 +2347,13 @@ static OSStatus AudioIOProc( void *inRefCon,
{ /*the ring buffer callback underflowed */
err = 0;
bzero( ((char *)data) + size, sizeof(data)-size );
/* The ring buffer can underflow normally when the stream is stopping.
* So only report an error if the stream is active. */
if( stream->state == ACTIVE )
{
stream->xrunFlags |= paInputUnderflow;
}
}
ERR( err );
assert( !err );
@ -2374,7 +2373,7 @@ static OSStatus AudioIOProc( void *inRefCon,
AudioConverter would otherwise handle for us. */
void *data1, *data2;
ring_buffer_size_t size1, size2;
PaUtil_GetRingBufferReadRegions( &stream->inputRingBuffer,
ring_buffer_size_t framesReadable = PaUtil_GetRingBufferReadRegions( &stream->inputRingBuffer,
frames,
&data1, &size1,
&data2, &size2 );
@ -2389,14 +2388,21 @@ static OSStatus AudioIOProc( void *inRefCon,
PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
&callbackResult );
PaUtil_AdvanceRingBufferReadIndex(&stream->inputRingBuffer, size1 );
} else if( size1 + size2 < frames ) {
} else if( framesReadable < frames ) {
long sizeBytes1 = size1 * bytesPerFrame;
long sizeBytes2 = size2 * bytesPerFrame;
/*we underflowed. take what data we can, zero the rest.*/
unsigned char data[frames*inChan*flsz];
if( size1 )
memcpy( data, data1, size1 );
if( size2 )
memcpy( data+size1, data2, size2 );
bzero( data+size1+size2, frames*flsz*inChan - size1 - size2 );
unsigned char data[ frames * bytesPerFrame ];
if( size1 > 0 )
{
memcpy( data, data1, sizeBytes1 );
}
if( size2 > 0 )
{
memcpy( data+sizeBytes1, data2, sizeBytes2 );
}
bzero( data+sizeBytes1+sizeBytes2, (frames*bytesPerFrame) - sizeBytes1 - sizeBytes2 );
PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames );
PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor),
@ -2407,7 +2413,7 @@ static OSStatus AudioIOProc( void *inRefCon,
PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
&callbackResult );
PaUtil_AdvanceRingBufferReadIndex( &stream->inputRingBuffer,
size1+size2 );
framesReadable );
/* flag underflow */
stream->xrunFlags |= paInputUnderflow;
} else {
@ -2425,7 +2431,7 @@ static OSStatus AudioIOProc( void *inRefCon,
framesProcessed =
PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
&callbackResult );
PaUtil_AdvanceRingBufferReadIndex(&stream->inputRingBuffer, size1+size2 );
PaUtil_AdvanceRingBufferReadIndex(&stream->inputRingBuffer, framesReadable );
}
}
} else {
@ -2463,14 +2469,14 @@ static OSStatus AudioIOProc( void *inRefCon,
{
/* If this is duplex or we use a converter, put the data
into the ring buffer. */
long bytesIn, bytesOut;
bytesIn = sizeof( float ) * inNumberFrames * chan;
bytesOut = PaUtil_WriteRingBuffer( &stream->inputRingBuffer,
ring_buffer_size_t framesWritten = PaUtil_WriteRingBuffer( &stream->inputRingBuffer,
stream->inputAudioBufferList.mBuffers[0].mData,
inNumberFrames );
if( bytesIn != bytesOut )
if( framesWritten != inNumberFrames )
{
stream->xrunFlags |= paInputOverflow ;
}
}
else
{
/* for simplex input w/o SR conversion,

View file

@ -359,8 +359,9 @@ int BlioCallback( const void *input, void *output, unsigned long frameCount,
/* check for underflow */
if( avail < frameCount * blio->inputSampleSizeActual * blio->inChan )
{
OSAtomicOr32( paInputOverflow, &blio->statusFlags );
}
toRead = MIN( avail, frameCount * blio->inputSampleSizeActual * blio->inChan );
/* copy the data */