summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-10-10 13:18:53 +0200
committerAlessandro Ghedini <alessandro@ghedini.me>2014-10-11 14:03:08 +0200
commit5c1c99b858a62dc306ba79bca8e616ca184db7f1 (patch)
treeb4e504b81e4d840f3dfdbd4d650572fbb75bc8a9
parentf66e320d7b08c78e05b8a3a523c85809ee7cc6ae (diff)
downloadmpv-5c1c99b858a62dc306ba79bca8e616ca184db7f1.tar.bz2
mpv-5c1c99b858a62dc306ba79bca8e616ca184db7f1.tar.xz
audio/out/push: fix EOF heuristic
Since the internal AO driver API has no proper way to determine EOF, we need to guess by querying get_delay. But some AOs (e.g. ao_pulse with no-latency-hacks set) may never reach 0, maybe because they naively add the latency to the buffer level. In this case our heuristic can break. Fix by always using the delay to estimate the EOF time. It's not even that important - it's mostly used to avoid blocking draining. So this should be ok. CC: @mpv-player/stable (maybe)
-rw-r--r--audio/out/internal.h5
-rw-r--r--audio/out/push.c32
2 files changed, 14 insertions, 23 deletions
diff --git a/audio/out/internal.h b/audio/out/internal.h
index a17aa10f02..7ebdf7bb6d 100644
--- a/audio/out/internal.h
+++ b/audio/out/internal.h
@@ -25,11 +25,6 @@
#include "audio/chmap.h"
#include "audio/chmap_sel.h"
-// If ao_get_delay() reaches this value after ao_play() was called with the
-// AOPLAY_FINAL_CHUNK flag set, the playback core expects that the audio has
-// all been played.
-#define AO_EOF_DELAY 0.05
-
/* global data used by ao.c and ao drivers */
struct ao {
int samplerate;
diff --git a/audio/out/push.c b/audio/out/push.c
index 55359cf4fe..27220e1d29 100644
--- a/audio/out/push.c
+++ b/audio/out/push.c
@@ -90,15 +90,7 @@ static double unlocked_get_delay(struct ao *ao)
double driver_delay = 0;
if (ao->driver->get_delay)
driver_delay = ao->driver->get_delay(ao);
- double delay = driver_delay + mp_audio_buffer_seconds(p->buffer);
- if (delay >= AO_EOF_DELAY && p->expected_end_time) {
- if (mp_time_sec() > p->expected_end_time) {
- MP_ERR(ao, "Audio device EOF reporting is broken!\n");
- MP_ERR(ao, "Please report this problem.\n");
- delay = 0;
- }
- }
- return delay;
+ return driver_delay + mp_audio_buffer_seconds(p->buffer);
}
static float get_delay(struct ao *ao)
@@ -240,7 +232,6 @@ static int play(struct ao *ao, void **data, int samples, int flags)
bool got_data = write_samples > 0 || p->paused || p->final_chunk != is_final;
- p->expected_end_time = 0;
p->final_chunk = is_final;
p->paused = false;
p->still_playing |= write_samples > 0;
@@ -284,11 +275,8 @@ static void ao_play_data(struct ao *ao)
r = max;
}
mp_audio_buffer_skip(p->buffer, r);
- if (p->final_chunk && mp_audio_buffer_samples(p->buffer) == 0) {
- p->expected_end_time = mp_time_sec() + AO_EOF_DELAY + 0.25; // + margin
- if (ao->driver->get_delay)
- p->expected_end_time += ao->driver->get_delay(ao);
- }
+ if (r > 0)
+ p->expected_end_time = 0;
// Nothing written, but more input data than space - this must mean the
// AO's get_space() doesn't do period alignment correctly.
bool stuck = r == 0 && max >= space && space > 0;
@@ -330,10 +318,17 @@ static void *playthread(void *arg)
bool was_playing = p->still_playing;
double timeout = -1;
- if (p->still_playing && !p->paused) {
- timeout = unlocked_get_delay(ao);
- if (timeout < AO_EOF_DELAY)
+ if (p->still_playing && !p->paused && p->final_chunk &&
+ !mp_audio_buffer_samples(p->buffer))
+ {
+ double now = mp_time_sec();
+ if (!p->expected_end_time)
+ p->expected_end_time = now + unlocked_get_delay(ao);
+ if (p->expected_end_time < now) {
p->still_playing = false;
+ } else {
+ timeout = p->expected_end_time - now;
+ }
}
if (was_playing && !p->still_playing)
@@ -346,6 +341,7 @@ static void *playthread(void *arg)
pthread_cond_wait(&p->wakeup, &p->lock);
}
} else {
+ // Wait until the device wants us to write more data to it.
if (!ao->driver->wait || ao->driver->wait(ao, &p->lock) < 0) {
// Fallback to guessing.
double timeout = 0;