How to properly handle xrun in ALSA programming when playing audio with snd_pcm_writei()?

admin

Administrator
Staff member
I've tried multiple example programs that appear to have code to handle xruns under playback:

<a href="https://albertlockett.wordpress.com/2013/11/06/creating-digital-audio-with-alsa/" rel="nofollow noreferrer">https://albertlockett.wordpress.com/2013/11/06/creating-digital-audio-with-alsa/</a>

<a href="https://www.linuxjournal.com/article/6735" rel="nofollow noreferrer">https://www.linuxjournal.com/article/6735</a> (listing 3)

When using snd_pcm_writei(), it appears that when the return value is -EPIPE (which is xrun/underrun), they do:

Code:
if (rc == -EPIPE) {
  /* EPIPE means underrun */
  fprintf(stderr, "underrun occurred\n");
  snd_pcm_prepare(handle);
}

I.e. call snd_pcm_prepare() on the handle.

However, I still get stuttering when I attempt to run programs like these. Typically, I will get at least a few, to maybe half a dozen xrun, and then it will play smoothly and continuously without further xruns. However, if I have something else using the sound card, such as Firefox, I will get many more xruns, and sometimes only xruns. But again, even if I kill any other program that uses the sound card, I still experience the issue with some initial xruns and actual stuttering on the speakers.

This is not acceptable for me, how can I modify this type of xrun handling to prevent stuttering?

My own attempt at figuring this out:

From the ALSA API, I see that snd_pcm_prepare() does:

<blockquote>
Prepare PCM for use.
</blockquote>

This is not very helpful to an ALSA beginner like myself. It is not explained how this can be used to recover xrun issues.

I also note, from: <a href="https://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html" rel="nofollow noreferrer">https://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html</a>

<blockquote>
SND_PCM_STATE_XRUN
The PCM device reached overrun (capture) or underrun (playback). You can use the -EPIPE return code from I/O functions
(snd_pcm_writei(), snd_pcm_writen(), snd_pcm_readi(), snd_pcm_readn())
to determine this state without checking the actual state via
snd_pcm_state() call. It is recommended to use the helper function
snd_pcm_recover() to recover from this state, but you can also use
snd_pcm_prepare(), snd_pcm_drop() or snd_pcm_drain() calls.
</blockquote>

Again, it is not clear to me. I can use snd_pcm_prepare() OR I can use these other calls? What is the difference? What should I use?