summaryrefslogtreecommitdiffstats
path: root/audio/out/push.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/out/push.c')
-rw-r--r--audio/out/push.c27
1 files changed, 19 insertions, 8 deletions
diff --git a/audio/out/push.c b/audio/out/push.c
index 4fa2bc53d5..ac87c62a96 100644
--- a/audio/out/push.c
+++ b/audio/out/push.c
@@ -142,6 +142,7 @@ static void resume(struct ao *ao)
static void drain(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
+ double maxbuffer = ao->buffer / (double)ao->samplerate + 1;
MP_VERBOSE(ao, "draining...\n");
@@ -151,14 +152,23 @@ static void drain(struct ao *ao)
p->final_chunk = true;
wakeup_playthread(ao);
- while (p->still_playing && mp_audio_buffer_samples(p->buffer) > 0)
- pthread_cond_wait(&p->wakeup, &p->lock);
+
+ // Wait until everything is done. Since the audio API (especially ALSA)
+ // can't be trusted to do this right, and we're hard-blocking here, apply
+ // an upper bound timeout.
+ struct timespec until = mp_rel_time_to_timespec(maxbuffer);
+ while (p->still_playing && mp_audio_buffer_samples(p->buffer) > 0) {
+ if (pthread_cond_timedwait(&p->wakeup, &p->lock, &until)) {
+ MP_WARN(ao, "Draining is taking too long, aborting.\n");
+ goto done;
+ }
+ }
if (ao->driver->drain) {
ao->driver->drain(ao);
} else {
double time = unlocked_get_delay(ao);
- mp_sleep_us(MPMIN(time, ao->buffer / (double)ao->samplerate + 1) * 1e6);
+ mp_sleep_us(MPMIN(time, maxbuffer) * 1e6);
}
done:
@@ -292,11 +302,12 @@ static void ao_play_data(struct ao *ao)
// If we just filled the AO completely (r == space), don't refill for a
// while. Prevents wakeup feedback with byte-granular AOs.
int needed = unlocked_get_space(ao);
- bool more = needed >= (r == space ? ao->device_buffer / 4 : 1) && !stuck;
+ bool more = needed >= (r == space ? ao->device_buffer / 4 : 1) && !stuck &&
+ !(flags & AOPLAY_FINAL_CHUNK);
if (more)
mp_input_wakeup(ao->input_ctx); // request more data
- MP_TRACE(ao, "in=%d flags=%d space=%d r=%d wa=%d needed=%d more=%d\n",
- max, flags, space, r, p->wait_on_ao, needed, more);
+ MP_TRACE(ao, "in=%d flags=%d space=%d r=%d wa/pl=%d/%d needed=%d more=%d\n",
+ max, flags, space, r, p->wait_on_ao, p->still_playing, needed, more);
}
static void *playthread(void *arg)
@@ -489,7 +500,7 @@ int ao_wait_poll(struct ao *ao, struct pollfd *fds, int num_fds,
// flush the wakeup pipe contents - might "drown" some wakeups, but
// that's ok for our use-case
char buf[100];
- read(p->wakeup_pipe[0], buf, sizeof(buf));
+ (void)read(p->wakeup_pipe[0], buf, sizeof(buf));
}
return (r >= 0 || r == -EINTR) ? wakeup : -1;
}
@@ -499,7 +510,7 @@ void ao_wakeup_poll(struct ao *ao)
assert(ao->api == &ao_api_push);
struct ao_push_state *p = ao->api_priv;
- write(p->wakeup_pipe[1], &(char){0}, 1);
+ (void)write(p->wakeup_pipe[1], &(char){0}, 1);
}
#endif