summaryrefslogtreecommitdiffstats
path: root/audio/out/ao_alsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/out/ao_alsa.c')
-rw-r--r--audio/out/ao_alsa.c29
1 files changed, 22 insertions, 7 deletions
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c
index d8a1ec5cae..df78a67178 100644
--- a/audio/out/ao_alsa.c
+++ b/audio/out/ao_alsa.c
@@ -939,17 +939,32 @@ static void drain(struct ao *ao)
static int get_space(struct ao *ao)
{
struct priv *p = ao->priv;
- snd_pcm_status_t *status;
- int err;
- snd_pcm_status_alloca(&status);
+ // in case of pausing or the device still being configured,
+ // just return our buffer size.
+ if (p->paused || snd_pcm_state(p->alsa) == SND_PCM_STATE_SETUP)
+ return p->buffersize;
+
+ snd_pcm_sframes_t space = snd_pcm_avail(p->alsa);
+ if (space < 0) {
+ if (space == -EPIPE) {
+ MP_WARN(ao, "ALSA XRUN hit, attempting to recover...\n");
+ int err = snd_pcm_prepare(p->alsa);
+ CHECK_ALSA_ERROR("Unable to recover from under/overrun!");
+ return p->buffersize;
+ }
+
+ MP_ERR(ao, "Error received from snd_pcm_avail "
+ "(%ld, %s with ALSA state %s)!\n",
+ space, snd_strerror(space),
+ snd_pcm_state_name(snd_pcm_state(p->alsa)));
- err = snd_pcm_status(p->alsa, status);
- if (!check_device_present(ao, err))
+ // request a reload of the AO if device is not present,
+ // then error out.
+ check_device_present(ao, space);
goto alsa_error;
- CHECK_ALSA_ERROR("cannot get pcm status");
+ }
- unsigned space = snd_pcm_status_get_avail(status);
if (space > p->buffersize) // Buffer underrun?
space = p->buffersize;
return space / p->outburst * p->outburst;