mrnc
mrnc

Reputation: 11

Portaudio underruns for real-time input/output audio

Background:

I am making a minimal program in C++ for real-time audio I/O. I am using the portaudio library for linux (ubuntu 22.04).

My program detects the default microphone/speaker and uses them for input/output audio, respectively. This allows whatever is picked up by the microphone to be played out the speaker, in real-time.

Problem:

The program runs, but is very inconsistent in its results. Most times, it runs for a second or 2 (with no audible sound), then results in the terminal error message ALSA lib pcm.c:8568:(snd_pcm_recover) underrun occurred, but continues to run. Once in a while I do get an audible sound in real-time without errors.

My code:

main.cpp:

#include <iostream>
#include <portaudio.h>
#include <cstring>

#define SAMPLE_RATE 16000
#define FRAMES_PER_BUFFER 160
#define CHANNELS 1

/// @brief Handles each frame of the audio stream
/// @param inputBuffer 
/// @param outputBuffer 
/// @param framesPerBuffer 
/// @param timeInfo 
/// @param statusFlags 
/// @param userData 
/// @return integer representing status to continue
static int AudioCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData) {
    const int16_t *in = (const int16_t*)inputBuffer;
    int16_t *out = (int16_t*)outputBuffer;

    // Set output as input
    if (in != NULL) {
        memcpy(out, in, sizeof(int16_t) * framesPerBuffer);
    } else {
        memset(out, 0, sizeof(int16_t) * framesPerBuffer);
    }

    std::cout << in << " | " << out << std::endl;

    return paContinue;
}

/// @brief Handles port audio errors
/// @param err 
void PaErrorStatement(PaError err) {
    if (err != paNoError) {
        std::cout << "PortAudio error: " << Pa_GetErrorText(err) << std::endl;
        exit(1);
    }
}

int main() {
    // Redirect stderr to /dev/null to suppress PortAudio messages
    freopen("/dev/null","w",stderr);
    PaError err = Pa_Initialize();
    freopen("/dev/tty","w",stderr);
    PaErrorStatement(err);

    // Create an I/O stream
    PaStream *stream;

    // Open default input and output streams
    err = Pa_OpenDefaultStream(&stream, CHANNELS, CHANNELS, paInt16, SAMPLE_RATE, FRAMES_PER_BUFFER, AudioCallback, NULL);
    PaErrorStatement(err);

    // Start audio stream
    err = Pa_StartStream(stream);
    PaErrorStatement(err);

    std::cout << "Recording (enter to quit)..." << std::endl;
    std::cin.get();

    // Stop stream
    err = Pa_StopStream(stream);
    PaErrorStatement(err);

    // Close stream
    err = Pa_CloseStream(stream);
    PaErrorStatement(err);

    // Terminate PortAudio
    err = Pa_Terminate();
    PaErrorStatement(err);
    
    return 0;
}


What I've Tried:

My question:

I am leaning towards that this is a linux issue (since it is running on virtual box on my windows computer).

Any other tips to point me in the right direction would be much appreciated!

Upvotes: 1

Views: 212

Answers (0)

Related Questions