Skip to content

Commit

Permalink
FIX(client): Infinite loop and log spam on ALSA input device disconne…
Browse files Browse the repository at this point in the history
…ction

A user reported that sometimes the client log gets spammed with repeated messages such as:

<W>2025-01-10 10:24:10.638 ALSAAudioInput: No such device: No such device

The error corresponds to ENODEV (19), which we treat like any other.
Since it's unrecoverable, the code gets stuck in a full speed loop until the audio engine is stopped.

This commit:

1. Switches from snd_pcm_prepare() to snd_pcm_recover(), which is specifically designed to recover streams.
2. Breaks the loop if the error is not one of the only three recoverable (EINTR, EPIPE, ESTRPIPE). Example log:

<W>2025-01-14 06:16:44.494 ALSAAudioInput encountered unrecoverable error: File descriptor in bad state -> exiting...

Please note that also ALSAAudioOutput doesn't explicitly handle fatal errors in its loop, but it shouldn't run "infinitely" at full speed because poll-based.
  • Loading branch information
davidebeatrici committed Jan 14, 2025
1 parent 86bd72f commit 14bb94e
Showing 1 changed file with 21 additions and 16 deletions.
37 changes: 21 additions & 16 deletions src/mumble/ALSAAudio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,6 @@ ALSAAudioInput::~ALSAAudioInput() {

void ALSAAudioInput::run() {
QMutexLocker qml(&qmALSA);
snd_pcm_sframes_t readblapp;

QByteArray device_name = Global::get().s.qsALSAInput.toLatin1();
snd_pcm_hw_params_t *hw_params = nullptr;
Expand Down Expand Up @@ -379,21 +378,27 @@ void ALSAAudioInput::run() {
snd_pcm_status_dump(status, log);
snd_pcm_status_free(status);
#endif
readblapp = snd_pcm_readi(capture_handle, inbuff.data(), static_cast< snd_pcm_uframes_t >(wantPeriod));
if (readblapp == -ESTRPIPE) {
qWarning("ALSAAudioInput: PCM suspended, trying to resume");
while (bRunning && snd_pcm_resume(capture_handle) == -EAGAIN)
msleep(1000);
if ((err = snd_pcm_prepare(capture_handle)) < 0)
qWarning("ALSAAudioInput: %s: %s", snd_strerror(static_cast< int >(readblapp)), snd_strerror(err));
} else if (readblapp == -EPIPE) {
err = snd_pcm_prepare(capture_handle);
qWarning("ALSAAudioInput: %s: %s", snd_strerror(static_cast< int >(readblapp)), snd_strerror(err));
} else if (readblapp < 0) {
err = snd_pcm_prepare(capture_handle);
qWarning("ALSAAudioInput: %s: %s", snd_strerror(static_cast< int >(readblapp)), snd_strerror(err));
} else if (wantPeriod == static_cast< unsigned int >(readblapp)) {
addMic(inbuff.data(), static_cast< unsigned int >(readblapp));
const snd_pcm_sframes_t ret = snd_pcm_readi(capture_handle, inbuff.data(), wantPeriod);
if (ret >= 0) {
if (static_cast< snd_pcm_uframes_t >(ret) == wantPeriod) {
addMic(inbuff.data(), static_cast< unsigned int >(ret));
}
} else {
err = static_cast< decltype(err) >(ret);
switch (err) {
case -EINTR:
case -EPIPE:
case -ESTRPIPE:
qWarning("ALSAAudioInput encountered unrecoverable error: %s -> exiting...", snd_strerror(err));
while (bRunning && snd_pcm_recover(capture_handle, err, 1) == -EAGAIN) {
msleep(1000);
}

break;
default:
qWarning("ALSAAudioInput: %s, breaking the loop...", snd_strerror(err));
bRunning = false;
}
}
}

Expand Down

0 comments on commit 14bb94e

Please sign in to comment.