PortAudio / portaudio

PortAudio is a cross-platform, open-source C language library for real-time audio input and output.
Other
1.45k stars 303 forks source link

ALSA/RPi-64: No devices listed when another PortAudio application is running #891

Open RossBencina opened 6 months ago

RossBencina commented 6 months ago

Pa_GetDeviceCount() returns 0 (zero) when another application that uses PortAudio is running.

[Originally reported by @nodemand during #870, when written in first person the description below is quoted from @nodemand in #870]

Expected behavior

In general, multiple running PortAudio applications should be able to list available devices. There is no known limitation to doing this on Linux with ALSA.

To Reproduce

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. The second shell lists no devices. 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;
}

Actual behavior

The second shell lists no devices.

Additional context

I checked https://github.com/PortAudio/portaudio/issues/804 and adding arm_64bit=0 to /boot/config.txt on Bullseye and rebooting does not give me any devices. Still 0.

At one stage, prior to realising that it is an issue with multiple concurrent PortAudio apps, @nodemand wrote:

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

philburk commented 4 months ago

I tried to reproduce this. I booted an RPi4 running Linux neuhaus98 6.1.21-v8+ #1642 SMP PREEMPT Mon Apr 3 17:24:16 BST 2023 aarch64 GNU/Linux

entered:

cd portaudio
./configure && make
bin/pa_devs
bin/paex_sine

While paex_sine was running, I entered "bin/pa_devs" is a second window.

When paex_sine is running I get all the same devices except the dmix device! I also noticed dmix "unable to open slave" right before the PortAudio version was printed. That was not printed when paex_sine was not running.