Skip to content

Commit

Permalink
alsa: Use snd_pcm_pause(), recover from buffer underruns
Browse files Browse the repository at this point in the history
Currently the plugout_alsa "pauses" playback simply by ceasing to
call `snd_pcm_writei()`; this causes a buffer underrun error on
resuming playback, and omission of one buffer's worth of samples
from playback (currently 2048 samples).

To mitigate this, check for an underrun retval (`-EPIPE`) after calling
`snd_pcm_writei()` and if applicable, recover by calling
`snd_pcm_prepare()` and	repeating the `snd_pcm_writei()` call to avoid
dropping samples.

Also implement an `alsa_pause()` function to pause and resume playback
without a buffer underrun using `snd_pcm_pause()`. The call will be
ineffective if unsupported by underlying hardware, in which case the
buffer underrun handling above will come into play.
  • Loading branch information
mrehkopf committed Apr 29, 2024
1 parent 51699c0 commit 069bf2a
Showing 1 changed file with 18 additions and 6 deletions.
24 changes: 18 additions & 6 deletions plugout_alsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ static long alsa_open(enum plugout_endian *endian, long rate, long *buffer_bytes
return 0;
}

static void alsa_pause(int pause)
{
snd_pcm_pause(pcm_handle, pause);
}

static long is_suspended(snd_pcm_sframes_t retval)
{
#ifdef HAVE_ESTRPIPE
Expand All @@ -110,18 +115,24 @@ static long is_suspended(snd_pcm_sframes_t retval)
#endif
}

static long is_underrun(snd_pcm_sframes_t retval)
{
return retval == -EPIPE;
}

static ssize_t alsa_write(const void *buf, size_t count)
{
snd_pcm_sframes_t retval;

do {
retval = snd_pcm_writei(pcm_handle, buf, count / 4);
if (!is_suspended(retval))
break;

/* resume from suspend */
while (snd_pcm_resume(pcm_handle) == -EAGAIN)
sleep(1);
if (is_suspended(retval)) {
/* resume from suspend */
while (snd_pcm_resume(pcm_handle) == -EAGAIN)
sleep(1);
} else if (is_underrun(retval)) {
snd_pcm_prepare(pcm_handle);
} else break;
} while (1);
if (retval < 0) {
fprintf(stderr, _("snd_pcm_writei failed: %s\n"), snd_strerror(retval));
Expand All @@ -140,6 +151,7 @@ const struct output_plugin plugout_alsa = {
.name = "alsa",
.description = "ALSA sound driver",
.open = alsa_open,
.pause = alsa_pause,
.write = alsa_write,
.close = alsa_close,
};

0 comments on commit 069bf2a

Please sign in to comment.