summaryrefslogtreecommitdiffstats
path: root/audio/out/ao_pulse.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-05-29 23:56:48 +0200
committerwm4 <wm4@nowhere>2014-05-30 02:15:47 +0200
commit5929dc458f46f75648af1ee7a293e899e67d8e66 (patch)
tree6898eb4886328e9cd936ac6a6008acf4bcd6f6ba /audio/out/ao_pulse.c
parent35aba9675dd428f945a09ff9acc20aa068705f46 (diff)
downloadmpv-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.c40
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,