From 211088943c494adf4313c0b4bca8d99eca81436a Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 9 Jun 2015 18:21:07 +0200 Subject: 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. --- audio/out/pull.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'audio') 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); -- cgit v1.2.3