summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-04-12 20:13:07 +0200
committerwm4 <wm4@nowhere>2014-04-12 20:13:07 +0200
commit4e5cea86c29508c24bf6f5539eeddd388abfde0a (patch)
tree8fa1bd7cd9412a1024b272ba9f1e9756bf299657
parent33f822b7154b8035984bd41607c0c2b1edd0c9fa (diff)
downloadmpv-4e5cea86c29508c24bf6f5539eeddd388abfde0a.tar.bz2
mpv-4e5cea86c29508c24bf6f5539eeddd388abfde0a.tar.xz
client API: add mpv_get_wakeup_pipe convenience function
Should make integreating with some event loops easier. Untested.
-rw-r--r--libmpv/client.h33
-rw-r--r--osdep/io.c2
-rw-r--r--osdep/io.h3
-rw-r--r--player/client.c32
4 files changed, 68 insertions, 2 deletions
diff --git a/libmpv/client.h b/libmpv/client.h
index 375b440dce..bd529d8677 100644
--- a/libmpv/client.h
+++ b/libmpv/client.h
@@ -1010,7 +1010,7 @@ typedef struct mpv_event_end_file {
* 3: the player received the quit command
* Other values should be treated as unknown.
*/
- int reason;
+ int reason;
} mpv_event_end_file;
typedef struct mpv_event_script_input_dispatch {
@@ -1158,9 +1158,40 @@ void mpv_wakeup(mpv_handle *ctx);
* If you actually want to do processing in a callback, spawn a thread that
* does nothing but call mpv_wait_event() in a loop and dispatches the result
* to a callback.
+ *
+ * Only one wakeup callback can be set.
+ *
+ * @param cb function that should be called if a wakeup is required
+ * @param d arbitrary userdata passed to cb
*/
void mpv_set_wakeup_callback(mpv_handle *ctx, void (*cb)(void *d), void *d);
+/**
+ * Return a UNIX file descriptor referring to the read end of a pipe. This
+ * pipe can be used to wake up a poll() based processing loop. The purpose of
+ * this function is very similar to mpv_set_wakeup_callback(), and provides
+ * a primitive mechanism to handle coordinating a foreign event loop and the
+ * libmpv event loop.
+ *
+ * This is in fact implemented using mpv_set_wakeup_callback(), and each
+ * callback invocation writes a single 0 byte to the pipe. When the pipe
+ * becomes readable, the code calling poll() (or select()) on the pipe should
+ * read all contents of the pipe and then call mpv_wait_event(c, 0) until
+ * no new events are returned. The pipe contents do not matter and can just
+ * be discarded.
+ *
+ * Note that this call lazily creates the pipe, and always returns the same
+ * handle once it's created. The client API will destroy both the read and
+ * write ends of the pipe in mpv_destroy(). If you need something more
+ * complex, it's better to implement your own mechanisms using
+ * mpv_set_wakeup_callback().
+ *
+ * On Windows, this will always return -1.
+ *
+ * @return A UNIX FD of the read end of the wakeup pipe, -1 on error.
+ */
+int mpv_get_wakeup_pipe(mpv_handle *ctx);
+
#ifdef __cplusplus
}
#endif
diff --git a/osdep/io.c b/osdep/io.c
index c243b39de4..26507eccfd 100644
--- a/osdep/io.c
+++ b/osdep/io.c
@@ -29,7 +29,7 @@
// On error, false is returned (and errno set).
bool mp_set_cloexec(int fd)
{
-#if defined(FD_CLOEXEC) && defined(F_SETFD)
+#if defined(F_SETFD)
if (fd >= 0) {
int flags = fcntl(fd, F_GETFD);
if (flags == -1)
diff --git a/osdep/io.h b/osdep/io.h
index 5fa36abb1e..4cb16677f2 100644
--- a/osdep/io.h
+++ b/osdep/io.h
@@ -34,6 +34,9 @@
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 0
+#endif
bool mp_set_cloexec(int fd);
diff --git a/player/client.c b/player/client.c
index 642937421d..7bca58e4c5 100644
--- a/player/client.c
+++ b/player/client.c
@@ -14,6 +14,8 @@
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
#include <errno.h>
#include <assert.h>
@@ -26,11 +28,14 @@
#include "options/m_property.h"
#include "osdep/threads.h"
#include "osdep/timer.h"
+#include "osdep/io.h"
#include "command.h"
#include "core.h"
#include "client.h"
+#include "config.h"
+
/*
* Locking hierarchy:
*
@@ -88,6 +93,7 @@ struct mpv_handle {
bool choke_warning;
void (*wakeup_cb)(void *d);
void *wakeup_cb_ctx;
+ int wakeup_pipe[2];
mpv_event *events; // ringbuffer of max_events entries
int max_events; // allocated number of entries in events
@@ -176,6 +182,7 @@ struct mpv_handle *mp_new_client(struct mp_client_api *clients, const char *name
.events = talloc_array(client, mpv_event, num_events),
.max_events = num_events,
.event_mask = ((uint64_t)-1) & ~(1ULL << MPV_EVENT_TICK),
+ .wakeup_pipe = {-1, -1},
};
pthread_mutex_init(&client->lock, NULL);
pthread_cond_init(&client->wakeup, NULL);
@@ -202,6 +209,8 @@ static void wakeup_client(struct mpv_handle *ctx)
pthread_cond_signal(&ctx->wakeup);
if (ctx->wakeup_cb)
ctx->wakeup_cb(ctx->wakeup_cb_ctx);
+ if (ctx->wakeup_pipe[0] == -1)
+ write(ctx->wakeup_pipe[0], &(char){0}, 1);
}
void mpv_set_wakeup_callback(mpv_handle *ctx, void (*cb)(void *d), void *d)
@@ -250,6 +259,10 @@ void mpv_destroy(mpv_handle *ctx)
mp_msg_log_buffer_destroy(ctx->messages);
pthread_cond_destroy(&ctx->wakeup);
pthread_mutex_destroy(&ctx->lock);
+ if (ctx->wakeup_pipe[0] != -1) {
+ close(ctx->wakeup_pipe[0]);
+ close(ctx->wakeup_pipe[1]);
+ }
talloc_free(ctx);
ctx = NULL;
// shutdown_clients() sleeps to avoid wasting CPU
@@ -1233,6 +1246,25 @@ int mpv_request_log_messages(mpv_handle *ctx, const char *min_level)
return 0;
}
+int mpv_get_wakeup_pipe(mpv_handle *ctx)
+{
+ pthread_mutex_lock(&ctx->lock);
+#if defined(F_SETFL)
+ if (ctx->wakeup_pipe[0] == -1) {
+ if (pipe(ctx->wakeup_pipe) != 0)
+ goto fail;
+ for (int i = 0; i < 2; i++) {
+ mp_set_cloexec(ctx->wakeup_pipe[i]);
+ int ret = fcntl(ctx->wakeup_pipe[i], F_GETFL);
+ fcntl(ctx->wakeup_pipe[i], F_SETFL, ret | O_NONBLOCK);
+ }
+ }
+fail:
+#endif
+ pthread_mutex_unlock(&ctx->lock);
+ return ctx->wakeup_pipe[1];
+}
+
unsigned long mpv_client_api_version(void)
{
return MPV_CLIENT_API_VERSION;