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.c33
1 files changed, 27 insertions, 6 deletions
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c
index dfbe9f1ceb..3185cb4c4b 100644
--- a/audio/out/ao_alsa.c
+++ b/audio/out/ao_alsa.c
@@ -94,6 +94,7 @@ struct priv {
snd_pcm_format_t alsa_fmt;
bool can_pause;
bool paused;
+ bool final_chunk_written;
snd_pcm_sframes_t prepause_frames;
double delay_before_pause;
snd_pcm_uframes_t buffersize;
@@ -135,6 +136,18 @@ static bool check_device_present(struct ao *ao, int alsa_err)
return false;
}
+static void handle_underrun(struct ao *ao)
+{
+ struct priv *p = ao->priv;
+
+ if (!p->final_chunk_written) {
+ MP_WARN(ao, "Device underrun detected.\n");
+ int err = snd_pcm_prepare(p->alsa);
+ CHECK_ALSA_ERROR("pcm prepare error");
+ alsa_error: ;
+ }
+}
+
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
{
struct priv *p = ao->priv;
@@ -975,8 +988,12 @@ static double get_delay(struct ao *ao)
if (p->paused)
return p->delay_before_pause;
- if (snd_pcm_delay(p->alsa, &delay) < 0)
+ int err = snd_pcm_delay(p->alsa, &delay);
+ if (err < 0) {
+ if (err == -EPIPE)
+ handle_underrun(ao);
return 0;
+ }
if (delay < 0) {
/* underrun - move the application pointer forward to catch up */
@@ -1082,6 +1099,7 @@ static void reset(struct ao *ao)
p->paused = false;
p->prepause_frames = 0;
p->delay_before_pause = 0;
+ p->final_chunk_written = false;
if (ao->stream_silence) {
soft_reset(ao);
@@ -1099,11 +1117,13 @@ static int play(struct ao *ao, void **data, int samples, int flags)
{
struct priv *p = ao->priv;
snd_pcm_sframes_t res = 0;
- if (!(flags & AOPLAY_FINAL_CHUNK))
+ bool final_chunk = flags & AOPLAY_FINAL_CHUNK;
+
+ if (!final_chunk)
samples = samples / p->outburst * p->outburst;
if (samples == 0)
- return 0;
+ goto done;
ao_convert_inplace(&p->convert, data, samples);
do {
@@ -1121,12 +1141,11 @@ static int play(struct ao *ao, void **data, int samples, int flags)
if (res == -ESTRPIPE) { /* suspend */
resume_device(ao);
} else if (res == -EPIPE) {
- MP_WARN(ao, "Device underrun detected.\n");
+ handle_underrun(ao);
} else {
MP_ERR(ao, "Write error: %s\n", snd_strerror(res));
}
- res = snd_pcm_prepare(p->alsa);
- int err = res;
+ int err = snd_pcm_prepare(p->alsa);
CHECK_ALSA_ERROR("pcm prepare error");
res = 0;
}
@@ -1134,6 +1153,8 @@ static int play(struct ao *ao, void **data, int samples, int flags)
p->paused = false;
+done:
+ p->final_chunk_written = res == samples && final_chunk;
return res < 0 ? -1 : res;
alsa_error: