audio: add hack against broken pulseaudio EOF condition

This was reported with PulseAudio 2.1. Apparently it still has problems
with reporting the correct delay. Since ao_pulse.c still has our custom
get_delay implementation, there's a possibility that this is our fault,
but this seems unlikely, because it's full of workarounds for issues
like this. It's also possible that this problem doesn't exist on
PulseAudio 5.0 anymore (I didn't explicitly retest it).

The check is general and works for all push based AOs. For pull based
AOs, this can't happen as pull.c implements all the logic correctly.
This commit is contained in:
wm4 2014-04-17 22:50:49 +02:00
parent fe298bc2a5
commit 40a072480c
1 changed files with 16 additions and 1 deletions

View File

@ -31,6 +31,7 @@
#include "input/input.h"
#include "osdep/threads.h"
#include "osdep/timer.h"
#include "compat/atomics.h"
#include "audio/audio.h"
@ -53,6 +54,7 @@ struct ao_push_state {
// Whether the current buffer contains the complete audio.
bool final_chunk;
double expected_end_time;
// -- protected by wakeup_lock
bool need_wakeup;
@ -88,6 +90,13 @@ static float get_delay(struct ao *ao)
driver_delay = ao->driver->get_delay(ao);
double delay = driver_delay + mp_audio_buffer_seconds(p->buffer);
pthread_mutex_unlock(&p->lock);
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;
}
@ -121,6 +130,7 @@ static void resume(struct ao *ao)
if (ao->driver->resume)
ao->driver->resume(ao);
p->playing = true; // tentatively
p->expected_end_time = 0;
wakeup_playthread(ao);
pthread_mutex_unlock(&p->lock);
}
@ -178,6 +188,7 @@ static int play(struct ao *ao, void **data, int samples, int flags)
p->final_chunk = !!(flags & AOPLAY_FINAL_CHUNK);
p->playing = true;
p->expected_end_time = 0;
wakeup_playthread(ao);
pthread_mutex_unlock(&p->lock);
@ -206,8 +217,12 @@ static int ao_play_data(struct ao *ao)
}
if (r > 0)
mp_audio_buffer_skip(p->buffer, r);
if (p->final_chunk && mp_audio_buffer_samples(p->buffer) == 0)
if (p->final_chunk && mp_audio_buffer_samples(p->buffer) == 0) {
p->playing = false;
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);
}
return r;
}