Reputation: 11
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:
Debugging terminal prints
To see if audio was actually getting passed through my program, I printed out each input and output frame in the AudioCallback
. The results were inconsistent, as sometimes it would run continuously without errors, sometimes it would run but throw underrun errors without recovery, and sometimes it would throw errors immediately. Below is the terminal output showing this.
Good run:
Recording (enter to quit)...
0x5a6496731c30 | 0x5a6496731ec0
0x5a6496731c30 | 0x5a6496731ec0
0x5a6496731c30 | 0x5a6496731ec0
0x5a6496731c30 | 0x5a6496731ec0
0x5a6496731c30 | 0x5a6496731ec0
0x5a6496731c30 | 0x5a6496731ec0
0x5a6496731c30 | 0x5a6496731ec0
0x5a6496731c30 | 0x5a6496731ec0
0x5a6496731c30 | 0x5a6496731ec0
...(continues until enter key pressed)
Bad run:
Recording (enter to quit)...
ALSA lib pcm.c:8568:(snd_pcm_recover) underrun occurred
ALSA lib pcm.c:8568:(snd_pcm_recover) underrun occurred
0x5d3159751c30 | 0x5d3159751d80
0x5d3159751c30 | 0x5d3159751d80
0x5d3159751c30 | 0x5d3159751d80
0x5d3159751c30 | 0x5d3159751d80
ALSA lib pcm.c:8568:(snd_pcm_recover) underrun occurred
0x5d3159751c30 | 0x5d3159751d80
0x5d3159751c30 | 0x5d3159751d80
0x5d3159751c30 | 0x5d3159751d80
ALSA lib pcm.c:8568:(snd_pcm_recover) underrun occurred
Expression 'err' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 3397
Expression 'ContinuePoll( self, StreamDirection_In, &pollTimeout, &pollCapture )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 3948
Expression 'PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 4335
Bad run:
Recording (enter to quit)...
ALSA lib pcm.c:8568:(snd_pcm_recover) underrun occurred
Expression 'err' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 3397
Expression 'ContinuePoll( self, StreamDirection_In, &pollTimeout, &pollCapture )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 3948
Expression 'PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 4335
Manual I/O Assignment
/// @brief Lists all I/O devices on OS
void ListDevices() {
int numDevices = Pa_GetDeviceCount();
if (numDevices < 0) {
std::cerr << "ERROR: Pa_GetDeviceCount returned " << numDevices << std::endl;
return;
}
const PaDeviceInfo *deviceInfo;
for (int i = 0; i < numDevices; i++) {
deviceInfo = Pa_GetDeviceInfo(i);
std::cout << "Device " << i << ": " << deviceInfo->name << std::endl;
}
}
// 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);
ListDevices(); //CALL TO LIST DEVICES HERE
// Create an I/O stream
PaStream *stream;
Device 0: Intel 82801AA-ICH: - (hw:0,0)
Device 1: Intel 82801AA-ICH: MIC ADC (hw:0,1)
Device 2: front
Device 3: surround40
Device 4: pulse
Device 5: upmix
Device 6: vdownmix
Device 7: dmix
Device 8: default
Recording (enter to quit)...
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
ALSA lib pcm.c:8568:(snd_pcm_recover) underrun occurred
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
0x55dc14d1a1c0 | 0x55dc14d1a310
ALSA lib pcm.c:8568:(snd_pcm_recover) underrun occurred
Expression 'err' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 3397
Expression 'ContinuePoll( self, StreamDirection_In, &pollTimeout, &pollCapture )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 3948
Expression 'PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 4335
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