PortAudio / portaudio

PortAudio is a cross-platform, open-source C language library for real-time audio input and output.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Expression 'paTimedOut' failed in 'src/os/unix/pa_unix_util.c', line: 400

nodemand opened this issue · comments

I'm getting the following errors when executing Pa_StartStream:

Expression 'paTimedOut' failed in 'src/os/unix/pa_unix_util.c', line: 400
Expression 'PaUnixThread_New( &stream->thread, &CallbackThreadFunc, stream, 1., stream->rtSched )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 3025
Expression 'pthread_join( self->thread, &pret )' failed in 'src/os/unix/pa_unix_util.c', line: 454
Expression 'PaUnixThread_Terminate( &stream->thread, !abort, &threadRes )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 3129
Expression 'pthread_join( self->thread, &pret )' failed in 'src/os/unix/pa_unix_util.c', line: 454
Expression 'PaUnixThread_Terminate( &stream->thread, !abort, &threadRes )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 3129
An error occured while using the portaudio stream
Error number: -9987
Error message: Wait timed out

My code:

#include <ctype.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/select.h>
#include <iostream>
#include "portaudio.h"

typedef struct
{
    float left_phase;
    float right_phase;
}   
audioData;

static int audio_callback( const void *inputBuffer, void *outputBuffer,
                       unsigned long framesPerBuffer,
                       const PaStreamCallbackTimeInfo* timeInfo,
                       PaStreamCallbackFlags statusFlags,
                       void *userData )
{
    audioData *data = (audioData*)userData; 
    float *out = (float*)outputBuffer;
    unsigned int i,j=0;;
    float *in = (float*)inputBuffer;

    for( i=0; i<framesPerBuffer; i++ )
    {
    	out[j] = in[j];  /* left */
    	j++;
        out[j] = in[j];  /* right*/
		j++;
    }
    return 0;
}

int device(const char* name)
{
	int i, numDevices;
	const PaDeviceInfo *deviceInfo;
	
	numDevices = Pa_GetDeviceCount();
	if( numDevices < 0 )
	{
		printf( "ERROR: Pa_GetDeviceCount returned 0x%x\n", numDevices );
		return 999;
	}
	
	for( i=0; i<numDevices; i++ )
	{
		deviceInfo = Pa_GetDeviceInfo( i );
		printf("device: %s\n", deviceInfo->name);
		if (strstr(deviceInfo->name, name) != NULL)
		{
			return i;
		}
	}
	return 999;
}

#define SAMPLE_RATE  		(96000)
#define FRAMES_PER_BUFFER 	(256)
#define NUM_CHANNELS    	(2)
#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 PA_SAMPLE_TYPE  	paFloat32
#define SAMPLE_SIZE 			(4)
#define SAMPLE_SILENCE  	(0.0f)
#define CLEAR(a) 				memset( (a), 0, FRAMES_PER_BUFFER * SAMPLE_SIZE )
#define PRINTF_S_FORMAT 	"%.8f"

unsigned int inputdevice, outputdevice, samplerate = SAMPLE_RATE;
float latency;

PaStreamParameters inputParameters, outputParameters;
PaStream *stream = NULL;
PaError err;

static audioData data;

/*******************************************************************/
int main(int argc, char **argv)
{
	err = Pa_Initialize();
	if( err != paNoError ) goto error;
	
	inputdevice		= device("Zero");
	outputdevice		= device("Zero");
	latency			= 1.00;
	
	inputParameters.device = inputdevice;
	printf( "Input device # %d.\n", inputParameters.device );
	printf( "Input LL: %g s\n", Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency );
	printf( "Input HL: %g s\n", Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency );
	inputParameters.channelCount = NUM_CHANNELS;
	inputParameters.sampleFormat = PA_SAMPLE_TYPE|paNonInterleaved;
	inputParameters.suggestedLatency = latency;
	inputParameters.hostApiSpecificStreamInfo = NULL;
	
	outputParameters.device = outputdevice;
	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;
	outputParameters.sampleFormat = PA_SAMPLE_TYPE|paNonInterleaved;
	outputParameters.suggestedLatency = latency;
	outputParameters.hostApiSpecificStreamInfo = NULL;
	
	printf("Configuring...\n"); fflush(stdout);
	
	/* -- setup -- */
	
	err = Pa_OpenStream(
		&stream,
		&inputParameters,
		&outputParameters,
		samplerate,
		FRAMES_PER_BUFFER,
		paClipOff,      /* we won't output out of range samples so don't bother clipping them */
		audio_callback,
		&data ); 
	if( err != paNoError ) goto error;
	
	printf("Starting...\n"); fflush(stdout);
	
	err = Pa_StartStream( stream );
	if( err != paNoError ) goto error;
	
	printf("Running...\n"); fflush(stdout);
	
	while (1)
	{
		Pa_Sleep(1000);
	}
	
	err = Pa_StopStream( stream );
	if( err != paNoError ) goto error;
	
	Pa_Terminate();
	return 0;
	
xrun:
	if( stream ) {
		Pa_AbortStream( stream );
		Pa_CloseStream( stream );
	}

	Pa_Terminate();
	
	if( err & paInputOverflow )
		fprintf( stderr, "Input Overflow.\n" );
	if( err & paOutputUnderflow )
		fprintf( stderr, "Output Underflow.\n" );
	
	return -2;
	
error:
	if( stream ) {
		Pa_AbortStream( stream );
		Pa_CloseStream( stream );
	}
	
	Pa_Terminate();
	
	fprintf( stderr, "An error occured while using the portaudio stream\n" );
	fprintf( stderr, "Error number: %d\n", err );
	fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
	
	return -1;
}

I would expect the input audio to be piped to the output, but instead my application crashes at Pa_StartStream... This does not happen when I use the blocking example. I only added the callback function and then these errors appeared.

  • OS: Raspberry Pi OS Bookworm 64-bit
  • OS Version: 12 / Linux 6.1.63-v8-16k+ aarch64
  • PortAudio version: 0x00130700, V19.7.0-devel
  • If Windows or Linux, which Host API (e.g. WASAPI): ALSA
  • Hardware: Raspberry Pi 5 4GB / IQaudIO Codec Zero

EDIT: I tried a couple of portaudio examples that use callbacks, but all exit with the same errors...

I don't know whether this is the cause of the timeout, but there is an "obvious" issue in PaUnixThread_New: it uses PaUtil_GetTime to compute the cond var timeout, but PaUtil_GetTime is not guaranteed to use the same timebase as the condition variable passed to pthread_cond_timedwait. It was never intended to be used like this and the documentation currently says as much.

There is a meta-issue for PaUtil_GetTime issues here: #807

And here is the equivalent bug in the JACK back-end: #795

That said, looking at the code, if CLOCK_MONOTONIC is defined, it looks like PaUtil_GetTime should use it on Linux, and PaUnixThread_New calls pthread_condattr_setclock at line 288. So maybe this is not the cause. In any case, if I were going to debug this I would first check that the same clock is being used to compute the deadline and by the cond var.

possible dup of #266

@nodemand I've aimed to fix all relevant timeout bugs in the following PR: #877 would you be able to try it and see whether it fixes your issue please?

I checked and PortAudio cannot find any devices anymore, so I really could not say. It could find devices before, so I'm not sure what is happening. aplay -l does show my sound card.

@nodemand thanks for checking. Could you confirm that you were previously testing the latest version of our master branch? If not, could you please check whether devices are visible when using our current master?

In other news, I've updated the PR with some fixes and improvements, but nothing that should impact device visibility.

Missing devices possibly related to #804

@RossBencina I tested previously on PortAudio 0x00130700, V19.7.0-devel. That is all I know. And I checked #804 and adding arm_64bit=0 to /boot/config.txt on Bullseye and rebooting does not give me any devices. Still 0.

@nodemand It would be helpful if you could test our current master branch to determine whether this "no devices" issue is related to my PR or is a previous regression.

Hi @RossBencina, success! It lists my sound card and the code execution goes past Pa_StartStream but right after that my code is generating a segmentation fault. Not sure what part exactly, but it must be in the callback function since I removed Pa_Sleep and it still returns a segmentation fault.

@nodemand so, to be clear, are you saying that now our master branch is working for you (or at least not exhibiting this bug) but that the PR #877 version is not listing any devices? or are both versions now working?

One way to check whether there is a problem with code inside the callback function would be to simply make the callback function return paContinue immediately without doing anything else and see if it runs without crashing.

@RossBencina
EDIT: My apologies. I was tired and forgot an app using the sound card was running in the background. This led to PortAudio not listing any available devices. So, the master branch lists devices and #877 ALSO lists devices!

And the segmentation fault had to do with me indexing the input/outputbuffers wrong. So I guess I can close this issue...

@nodemand thanks for the feedback. Glad to hear everything is working for you now.

However, you wrote:

an app using the sound card was running in the background. This led to PortAudio not listing any available devices.

This sounds like a bug. I mean, PortAudio should still be able to list devices. Could you describe how to reproduce this issue? Can it be reproduced by running pa_devs to list devices?

@nodemand any comment on my previous question?

Replace device("CODEC") with device(<identifiable part of your sound card's name>) in the following code. Then compile it and run it twice in different shells. That'll do it... But I think basically you can run any application that uses portaudio in one shell and then another application that uses portaudio in a second shell to reproduce this issue.

Code:

#include <ctype.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/select.h>
#include <iostream>
#include "portaudio.h"

typedef struct
{
    float left_phase;
    float right_phase;
}   
audioData;

static int audio_callback( const void *inputBuffer, void *outputBuffer,
                       unsigned long framesPerBuffer,
                       const PaStreamCallbackTimeInfo* timeInfo,
                       PaStreamCallbackFlags statusFlags,
                       void *userData )
{
    return 0;
}

int device(const char* name)
{
	int i, numDevices;
	const PaDeviceInfo *deviceInfo;
	
	numDevices = Pa_GetDeviceCount();
	if( numDevices < 0 )
	{
		printf( "ERROR: Pa_GetDeviceCount returned 0x%x\n", numDevices );
		return 999;
	}
	
	for( i=0; i<numDevices; i++ )
	{
		deviceInfo = Pa_GetDeviceInfo( i );
		printf("device: %s\n", deviceInfo->name);
		if (strstr(deviceInfo->name, name) != NULL)
		{
			return i;
		}
	}
	return 999;
}

#define SAMPLE_RATE  		(48000)
#define FRAMES_PER_BUFFER 	(256)
#define NUM_CHANNELS    	(2)
#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 PA_SAMPLE_TYPE  	paFloat32
#define SAMPLE_SIZE 			(4)
#define SAMPLE_SILENCE  	(0.0f)
#define CLEAR(a) 				memset( (a), 0, FRAMES_PER_BUFFER * SAMPLE_SIZE )
#define PRINTF_S_FORMAT 	"%.8f"

unsigned int inputdevice, outputdevice, samplerate = SAMPLE_RATE;
float latency;

PaStreamParameters inputParameters, outputParameters;
PaStream *stream = NULL;
PaError err;

static audioData data;

/*******************************************************************/
int main(int argc, char **argv)
{
	err = Pa_Initialize();
	if( err != paNoError ) goto error;
	
	inputdevice		= device("CODEC");
	outputdevice		= device("CODEC");
	latency			= 1.00;
	
	inputParameters.device = inputdevice;
	printf( "Input device # %d.\n", inputParameters.device );
	printf( "Input LL: %g s\n", Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency );
	printf( "Input HL: %g s\n", Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency );
	inputParameters.channelCount = NUM_CHANNELS;
	inputParameters.sampleFormat = PA_SAMPLE_TYPE|paNonInterleaved;
	inputParameters.suggestedLatency = latency;
	inputParameters.hostApiSpecificStreamInfo = NULL;
	
	outputParameters.device = outputdevice;
	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;
	outputParameters.sampleFormat = PA_SAMPLE_TYPE|paNonInterleaved;
	outputParameters.suggestedLatency = latency;
	outputParameters.hostApiSpecificStreamInfo = NULL;
	
	printf("Configuring...\n"); fflush(stdout);
	
	/* -- setup -- */
	
	err = Pa_OpenStream(
		&stream,
		&inputParameters,
		&outputParameters,
		samplerate,
		FRAMES_PER_BUFFER,
		paClipOff,      /* we won't output out of range samples so don't bother clipping them */
		audio_callback,
		&data ); 
	if( err != paNoError ) goto error;
	
	printf("Starting...\n"); fflush(stdout);
	
	err = Pa_StartStream( stream );
	if( err != paNoError ) goto error;
	
	printf("Running...\n"); fflush(stdout);
	
	while (1)
	{
		Pa_Sleep(1000);
	}
	
	err = Pa_StopStream( stream );
	if( err != paNoError ) goto error;
	
	Pa_Terminate();
	return 0;
	
xrun:
	if( stream ) {
		Pa_AbortStream( stream );
		Pa_CloseStream( stream );
	}

	Pa_Terminate();
	
	if( err & paInputOverflow )
		fprintf( stderr, "Input Overflow.\n" );
	if( err & paOutputUnderflow )
		fprintf( stderr, "Output Underflow.\n" );
	
	return -2;
	
error:
	if( stream ) {
		Pa_AbortStream( stream );
		Pa_CloseStream( stream );
	}
	
	Pa_Terminate();
	
	fprintf( stderr, "An error occured while using the portaudio stream\n" );
	fprintf( stderr, "Error number: %d\n", err );
	fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
	
	return -1;
}

Note to self: Running the code in the previous comment in two shells results in the second shell listing no devices. This is not the expected behavior.

@nodemand Thanks for the reproduction test case. I have created issue #891 to track the "no devices listed" issue. I think I have captured all relevant details from this thread but I'd be most appreciative if you could check #891 and add anything that I've missed. The main thing I'm a bit uncertain of is when the issue started happening, but I gather that it is definitely an issue on our master branch.

I'm closing this one (#870) since the timeout issue is resolved.