summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-05-29 23:57:11 +0200
committerwm4 <wm4@nowhere>2014-05-30 02:16:25 +0200
commit5dcfc4f6048329e72c077af7a152983c14c8ffd0 (patch)
tree535530834e64ec16c797f35bdec82a6fe768f1ed /audio
parentec18df84661189b11e426eefd999348b9e60c16a (diff)
downloadmpv-5dcfc4f6048329e72c077af7a152983c14c8ffd0.tar.bz2
mpv-5dcfc4f6048329e72c077af7a152983c14c8ffd0.tar.xz
audio/out/push: add a way to wait for the audio device with poll()
Will be used for ALSA.
Diffstat (limited to 'audio')
-rw-r--r--audio/out/internal.h4
-rw-r--r--audio/out/push.c67
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 <stddef.h>
#include <pthread.h>
#include <inttypes.h>
-#include <limits.h>
+#include <unistd.h>
+#include <errno.h>
#include <assert.h>
+#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 <poll.h>
+
+#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