summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-06-09 18:21:07 +0200
committerwm4 <wm4@nowhere>2015-06-09 18:26:14 +0200
commit211088943c494adf4313c0b4bca8d99eca81436a (patch)
tree8837c33bd90acb7fa9e5de678544de2ed9c50aef
parenta2b1c6d3f69a97369d582494fbc5c51db62d1613 (diff)
downloadmpv-211088943c494adf4313c0b4bca8d99eca81436a.tar.bz2
mpv-211088943c494adf4313c0b4bca8d99eca81436a.tar.xz
audio/out/pull: avoid dropping some audio when draining
If the audio API takes a while for starting the audio callback, the current heuristic can be off. In particular, with very short files, it can happen that the audio callback is not called before playback is stopped, so no audio is output at all. Change draining so that it essentially waits for the ringbuffer to empty. The assumption is that once the audio API has read the data via the callback, it will always output it, even if the audio API is stopped right after the callback has returned.
-rw-r--r--audio/out/pull.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/audio/out/pull.c b/audio/out/pull.c
index c658144a2d..ed85c4ee00 100644
--- a/audio/out/pull.c
+++ b/audio/out/pull.c
@@ -206,15 +206,6 @@ static void resume(struct ao *ao)
ao->driver->resume(ao);
}
-static void drain(struct ao *ao)
-{
- struct ao_pull_state *p = ao->api_priv;
- int state = atomic_load(&p->state);
- if (IS_PLAYING(state))
- mp_sleep_us(get_delay(ao) * 1000000);
- reset(ao);
-}
-
static bool get_eof(struct ao *ao)
{
struct ao_pull_state *p = ao->api_priv;
@@ -223,6 +214,24 @@ static bool get_eof(struct ao *ao)
return mp_ring_buffered(p->buffers[0]) == 0;
}
+static void drain(struct ao *ao)
+{
+ struct ao_pull_state *p = ao->api_priv;
+ int state = atomic_load(&p->state);
+ if (IS_PLAYING(state)) {
+ // Wait for lower bound.
+ mp_sleep_us(mp_ring_buffered(p->buffers[0]) / (double)ao->bps * 1e6);
+ // And then poll for actual end. (Unfortunately, this code considers
+ // audio APIs which do not want you to use mutexes in the audio
+ // callback, and an extra semaphore would require slightly more effort.)
+ // Limit to arbitrary ~250ms max. waiting for robustness.
+ int64_t max = mp_time_us() + 250000;
+ while (mp_time_us() < max && !get_eof(ao))
+ mp_sleep_us(1);
+ }
+ reset(ao);
+}
+
static void uninit(struct ao *ao)
{
ao->driver->uninit(ao);