Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
nodemand opened this issue Dec 23, 2023 · 16 comments
Closed
Labels
bug Something isn't working P2 Priority: High src-alsa ALSA Host API /src/hostapi/alsa

Comments

@nodemand
Copy link

nodemand commented Dec 23, 2023

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...

@RossBencina RossBencina added the bug Something isn't working label Dec 29, 2023
@RossBencina
Copy link
Collaborator

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.

@RossBencina RossBencina added P2 Priority: High src-alsa ALSA Host API /src/hostapi/alsa labels Dec 29, 2023
@RossBencina
Copy link
Collaborator

possible dup of #266

@RossBencina
Copy link
Collaborator

@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?

@nodemand
Copy link
Author

nodemand commented Jan 20, 2024

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.

@RossBencina
Copy link
Collaborator

@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.

@RossBencina
Copy link
Collaborator

Missing devices possibly related to #804

@nodemand
Copy link
Author

nodemand commented Jan 21, 2024

@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.

@RossBencina
Copy link
Collaborator

@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.

@nodemand
Copy link
Author

nodemand commented Feb 3, 2024

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.

@RossBencina
Copy link
Collaborator

@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.

@nodemand
Copy link
Author

nodemand commented Feb 9, 2024

@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...

@RossBencina
Copy link
Collaborator

@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?

@RossBencina
Copy link
Collaborator

@nodemand any comment on my previous question?

@nodemand
Copy link
Author

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;
}

@RossBencina
Copy link
Collaborator

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.

@RossBencina
Copy link
Collaborator

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working P2 Priority: High src-alsa ALSA Host API /src/hostapi/alsa
Projects
None yet
Development

No branches or pull requests

2 participants