cpal
cpal copied to clipboard
ALSA PCM.try_recover: error handling
When passing silent=false
to PCM.try_recover, it'll write to stderr
a detail of the error.
In this case, it's always underrun occurred
or overrun occurred
. It logs this even when successfully recovering. This is the relevant code in ALSA's GitHub mirror, as of now:
if (err == -EPIPE) {
const char *s;
if (snd_pcm_stream(pcm) == SND_PCM_STREAM_PLAYBACK)
s = "underrun";
else
s = "overrun";
if (!silent)
SNDERR("%s occurred", s);
err = snd_pcm_prepare(pcm);
if (err < 0) {
SNDERR("cannot recovery from %s, prepare failed: %s", s, snd_strerror(err));
return err;
}
return 0;
}
By setting it to silent, we lose this detail (whether it was an under- or over-run). But letting it write directly to stderr is messing up my ratatui app :( and I don't think there's a standard, cross-platform, safe way to prevent anything from writing to std(out|err) in-process.
Failures in try_handle
will now call error_callback
, but these noisy underrun occurred
always recovered successfully, in my case.
I guess we could also offer some sort of #[cfg(feature = "alsa-silent-try_recover")]
or adding a run-time arg to the function chain all the way up to build_output_stream
and then Rodio's try_from_device
, or add it as an option in struct StreamConfig
. Personally, I'd prefer avoiding the added code complexity of the run-time option, but I could see some value in the build-time option, if properly documented.
Also, calling the error callback will wind up doing a eprintln
that wasn't happening previously (in rodio, at least), so we're trading one stderr
output for another. That's something to manage in Rodio, but still worth mentioning.
For context, I can consistently trigger these by calling Rodio's sink.try_seek
too quickly (as fast as crossterm's event::poll
will trigger it, while I hold down a key I'm mapping to seek
in my app).
Silencing this error gets rid of the visual noise/glitches, but I still need to manage the sound glitches somehow. But that's probably on me for not debouncing calls to seek
and/or using OutputStream::try_default()
and not setting anything manually in SupportedStreamConfig
(buffer_size
, I guess).