diff options
author | wm4 <wm4@nowhere> | 2014-05-29 23:56:48 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2014-05-30 02:15:47 +0200 |
commit | 5929dc458f46f75648af1ee7a293e899e67d8e66 (patch) | |
tree | 6898eb4886328e9cd936ac6a6008acf4bcd6f6ba /audio/out/ao_pulse.c | |
parent | 35aba9675dd428f945a09ff9acc20aa068705f46 (diff) | |
download | mpv-5929dc458f46f75648af1ee7a293e899e67d8e66.tar.bz2 mpv-5929dc458f46f75648af1ee7a293e899e67d8e66.tar.xz |
audio/out/push: add mechanism for event-based waiting
Until now, we've always calculated a timeout based on a heuristic when
to refill the audio buffers. Allow AOs to do it completely event-based
by providing wait and wakeup callbacks.
This also shuffles around the heuristic used for other AOs, and there is
a minor possibility that behavior slightly changes in real-world cases.
But in general it should be much more robust now.
ao_pulse.c now makes use of event-based waiting. It already did before,
but the code for time-based waiting was also involved. This commit also
removes one awkward artifact of the PulseAudio API out of the generic
code: the callback asking for more data can be reentrant, and thus
requires a separate lock for waiting (or a recursive mutex).
Diffstat (limited to 'audio/out/ao_pulse.c')
-rw-r--r-- | audio/out/ao_pulse.c | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/audio/out/ao_pulse.c b/audio/out/ao_pulse.c index e327643154..dad21fe1f1 100644 --- a/audio/out/ao_pulse.c +++ b/audio/out/ao_pulse.c @@ -24,6 +24,7 @@ #include <stdbool.h> #include <string.h> #include <stdint.h> +#include <pthread.h> #include <pulse/pulseaudio.h> @@ -55,6 +56,11 @@ struct priv { bool broken_pause; int retval; + // for wakeup handling + pthread_mutex_t wakeup_lock; + pthread_cond_t wakeup; + int wakeup_status; + char *cfg_host; char *cfg_sink; int cfg_buffer; @@ -90,14 +96,38 @@ static void stream_state_cb(pa_stream *s, void *userdata) } } +static void wakeup(struct ao *ao) +{ + struct priv *priv = ao->priv; + pthread_mutex_lock(&priv->wakeup_lock); + priv->wakeup_status = 1; + pthread_cond_signal(&priv->wakeup); + pthread_mutex_unlock(&priv->wakeup_lock); +} + static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { struct ao *ao = userdata; struct priv *priv = ao->priv; - ao_need_data(ao); + wakeup(ao); pa_threaded_mainloop_signal(priv->mainloop, 0); } +static int wait(struct ao *ao, pthread_mutex_t *lock) +{ + struct priv *priv = ao->priv; + // We don't use this mutex, because pulse like to call stream_request_cb + // while we have the central mutex held. + pthread_mutex_unlock(lock); + pthread_mutex_lock(&priv->wakeup_lock); + while (!priv->wakeup_status) + pthread_cond_wait(&priv->wakeup, &priv->wakeup_lock); + priv->wakeup_status = 0; + pthread_mutex_unlock(&priv->wakeup_lock); + pthread_mutex_lock(lock); + return 0; +} + static void stream_latency_update_cb(pa_stream *s, void *userdata) { struct ao *ao = userdata; @@ -237,6 +267,9 @@ static void uninit(struct ao *ao) pa_threaded_mainloop_free(priv->mainloop); priv->mainloop = NULL; } + + pthread_cond_destroy(&priv->wakeup); + pthread_mutex_destroy(&priv->wakeup_lock); } static int init(struct ao *ao) @@ -249,6 +282,9 @@ static int init(struct ao *ao) char *sink = priv->cfg_sink && priv->cfg_sink[0] ? priv->cfg_sink : NULL; const char *version = pa_get_library_version(); + pthread_mutex_init(&priv->wakeup_lock, NULL); + pthread_cond_init(&priv->wakeup, NULL); + ao->per_application_mixer = true; priv->broken_pause = false; @@ -626,6 +662,8 @@ const struct ao_driver audio_out_pulse = { .pause = pause, .resume = resume, .drain = drain, + .wait = wait, + .wakeup = wakeup, .priv_size = sizeof(struct priv), .priv_defaults = &(const struct priv) { .cfg_buffer = 250, |