From 5dcfc4f6048329e72c077af7a152983c14c8ffd0 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 29 May 2014 23:57:11 +0200 Subject: [PATCH] audio/out/push: add a way to wait for the audio device with poll() Will be used for ALSA. --- audio/out/internal.h | 4 +++ audio/out/push.c | 67 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/audio/out/internal.h b/audio/out/internal.h index 32c6aa7b27..3d586f3848 100644 --- a/audio/out/internal.h +++ b/audio/out/internal.h @@ -160,6 +160,10 @@ struct ao_driver { int ao_play_silence(struct ao *ao, int samples); void ao_wait_drain(struct ao *ao); int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_us); +struct pollfd; +int ao_wait_poll(struct ao *ao, struct pollfd *fds, int num_fds, + pthread_mutex_t *lock); +void ao_wakeup_poll(struct ao *ao); bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s, struct mp_chmap *map); diff --git a/audio/out/push.c b/audio/out/push.c index 9f744323ac..dd1015d441 100644 --- a/audio/out/push.c +++ b/audio/out/push.c @@ -18,9 +18,12 @@ #include #include #include -#include +#include +#include #include +#include "osdep/io.h" + #include "ao.h" #include "internal.h" #include "audio/format.h" @@ -56,6 +59,8 @@ struct ao_push_state { // Whether the current buffer contains the complete audio. bool final_chunk; double expected_end_time; + + int wakeup_pipe[2]; }; // lock must be held @@ -111,7 +116,7 @@ static void reset(struct ao *ao) pthread_mutex_unlock(&p->lock); } -static void pause(struct ao *ao) +static void audio_pause(struct ao *ao) { struct ao_push_state *p = ao->api_priv; pthread_mutex_lock(&p->lock); @@ -321,6 +326,9 @@ static void uninit(struct ao *ao) ao->driver->uninit(ao); + for (int n = 0; n < 2; n++) + close(p->wakeup_pipe[n]); + pthread_cond_destroy(&p->wakeup); pthread_mutex_destroy(&p->lock); } @@ -331,6 +339,7 @@ static int init(struct ao *ao) pthread_mutex_init(&p->lock, NULL); pthread_cond_init(&p->wakeup, NULL); + mp_make_wakeup_pipe(p->wakeup_pipe); p->buffer = mp_audio_buffer_create(ao); mp_audio_buffer_reinit_fmt(p->buffer, ao->format, @@ -351,7 +360,7 @@ const struct ao_driver ao_api_push = { .get_space = get_space, .play = play, .get_delay = get_delay, - .pause = pause, + .pause = audio_pause, .resume = resume, .drain = drain, .priv_size = sizeof(struct ao_push_state), @@ -372,3 +381,55 @@ int ao_play_silence(struct ao *ao, int samples) talloc_free(p); return r; } + +#ifndef __MINGW32__ + +#include + +#define MAX_POLL_FDS 20 + +// Call poll() for the given fds. This will extend the given fds with the +// wakeup pipe, so ao_wakeup_poll() will basically interrupt this function. +// Unlocks the lock temporarily. +// Returns <0 on error, 0 on success. +int ao_wait_poll(struct ao *ao, struct pollfd *fds, int num_fds, + pthread_mutex_t *lock) +{ + struct ao_push_state *p = ao->api_priv; + assert(ao->api == &ao_api_push); + assert(&p->lock == lock); + + if (num_fds > MAX_POLL_FDS || p->wakeup_pipe[0] < 0) + return -1; + + struct pollfd p_fds[MAX_POLL_FDS]; + memcpy(p_fds, fds, num_fds * sizeof(p_fds[0])); + p_fds[num_fds] = (struct pollfd){ + .fd = p->wakeup_pipe[0], + .events = POLLIN, + }; + + pthread_mutex_unlock(&p->lock); + int r = poll(p_fds, num_fds + 1, -1); + r = r < 0 ? -errno : 0; + pthread_mutex_lock(&p->lock); + + memcpy(fds, p_fds, num_fds * sizeof(fds[0])); + if (p_fds[num_fds].revents & POLLIN) { + // 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)); + } + return (r >= 0 || r == -EINTR) ? 0 : -1; +} + +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); +} + +#endif