From 4e5cea86c29508c24bf6f5539eeddd388abfde0a Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 12 Apr 2014 20:13:07 +0200 Subject: client API: add mpv_get_wakeup_pipe convenience function Should make integreating with some event loops easier. Untested. --- libmpv/client.h | 33 ++++++++++++++++++++++++++++++++- osdep/io.c | 2 +- osdep/io.h | 3 +++ player/client.c | 32 ++++++++++++++++++++++++++++++++ 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 #include #include +#include +#include #include #include @@ -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; -- cgit v1.2.3