[Portaudio] Missing port audio callbacks

Stefan Hajnoczi stefanha at gmail.com
Fri Aug 18 05:59:18 EDT 2017

On Fri, Aug 18, 2017 at 7:31 AM, Matti Sillanpää
<maash.1.bridge at gmail.com> wrote:
> Hi Phil.
> pa_devs lists both cards. I attached the dump.
> I modified the paex_record to blocking read:
> ***********************************************************************************
>    err = Pa_OpenStream(
>               &stream,
>               &inputParameters,
>               NULL,                  /* &outputParameters, */
>               SAMPLE_RATE,
>               FRAMES_PER_BUFFER,
>               paClipOff,      /* we won't output out of range samples so
> don't bother clipping the\
> m */
>               NULL,//recordCallback,
>               NULL );
>     if( err != paNoError ) goto done;
>     err = Pa_StartStream( stream );
>     if( err != paNoError ) goto done;
>     printf("\n=== Now recording!! Please speak into the microphone. ===\n");
> fflush(stdout);
>     Pa_ReadStream(stream, (void*)data.recordedSamples, FRAMES_PER_BUFFER);
>     for (i=0; i < 20; i++) {
>       printf("data: %x\n", data.recordedSamples[i]);
>     }
> **********************************************************************************
> The Pa_StartStream doesn't return. I attached strace dump from this also.

It looks like Pa_StartStream() *does* return to me.  The strace
contains the "Now recording!!" message so the program must have gotten
to Pa_ReadStream().

I'm not familiar with the ALSA ioctl interface, but my interpretation
of the strace log is that a capture error like an overrun occurs.  The
program then tries to resume capture by reinitializing the device.

The strace log ends after a few rounds of this pattern.  Perhaps
poll() was hanging (the sound driver in the kernel was no longer
producing events) or you interrupted the strace - it's not clear from
the strace log.

Here is the PortAudio source code from
src/hostapi/alsa/pa_linux_alsa.c:ReadStream() that corresponds to the
repeated pattern in the strace log:

    while( frames > 0 )
        int xrun = 0;
        PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
        framesGot = PA_MIN( framesAvail, frames );

        PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
        if( framesGot > 0 )
            framesGot = PaUtil_CopyInput( &stream->bufferProcessor,
&userBuffer, framesGot );
            PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
            frames -= framesGot;

Here is a theory:

1. We see an infinite loop so the while( frames > 0 ) loop must never terminate.
2. In order for the loop to continue frames can never reach 0 and none
of the PA_ENSURE() calls produce an error.
3. PaAlsaStream_WaitForFrames() can create this situation when an xrun
occurs and ALSA reset succeeds:

    if( xrun )
        /* Recover from the xrun state */
        PA_ENSURE( PaAlsaStream_HandleXrun( self ) );
        *framesAvail = 0;

When an xrun occurs framesAvail = 0 and there is no error as long as
PaAlsaStream_HandleXrun() succeeds.  The loop will try again, having
made no progress.  The ALSA API always hits an xrun on this device and
PortAudio keeps retrying forever.

This seems to be the infinite loop you are hitting.

Phil: Does this make sense?  Should PortAudio keep a consecutive xrun
counter and bail out if the device keeps producing xruns without
making progress?


More information about the Portaudio mailing list