From a7f3cf473707b19bff9ea80b227490c8b305b601 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 9 Mar 2018 06:00:51 +0100 Subject: client API: add mpv_create_weak_client() --- DOCS/client-api-changes.rst | 1 + libmpv/client.h | 22 +++++++++++++++++++--- libmpv/mpv.def | 1 + player/client.c | 23 +++++++++++++++++++++-- player/client.h | 1 + player/scripting.c | 1 + 6 files changed, 44 insertions(+), 5 deletions(-) diff --git a/DOCS/client-api-changes.rst b/DOCS/client-api-changes.rst index 49964f5071..9b964da59a 100644 --- a/DOCS/client-api-changes.rst +++ b/DOCS/client-api-changes.rst @@ -37,6 +37,7 @@ API changes changes subtly (see documentation in the header file). In particular, mpv_detach_destroy() will not leave the player running in all situations anymore (it gets closer to refcounting). + - add mpv_create_weak_client(), which makes use of above changes 1.28 - deprecate the render opengl_cb API, and replace it with render.h and render_gl.h. The goal is allowing support for APIs other than OpenGL. The old API is emulated with the new API. diff --git a/libmpv/client.h b/libmpv/client.h index 536000229e..335e1417bc 100644 --- a/libmpv/client.h +++ b/libmpv/client.h @@ -452,9 +452,11 @@ int mpv_initialize(mpv_handle *ctx); * API call. * * Since mpv client API version 1.29: - * If the last mpv_handle is detached, the core player is destroyed. Note that - * internal mpv_handles created due to scripts (e.g. the OSC) will keep the - * player running. (To be fixed in the following commit.) + * If the last mpv_handle is detached, the core player is destroyed. In + * addition, if there are only weak mpv_handles (such as created by + * mpv_create_weak_client() or internal scripts), these mpv_handles will + * be sent MPV_EVENT_SHUTDOWN. This function may block until these clients + * have responded to the shutdown event, and the core is finally destroyed. * * Before mpv client API version 1.29: * This left the player running. If you want to be sure that the @@ -516,6 +518,20 @@ void mpv_terminate_destroy(mpv_handle *ctx); */ mpv_handle *mpv_create_client(mpv_handle *ctx, const char *name); +/** + * This is the same as mpv_create_client(), but the created mpv_handle is + * treated as a weak reference. If all mpv_handles referencing a core are + * weak references, the core is automatically destroyed. (This still goes + * through normal uninit of course. Effectively, if the last non-weak mpv_handle + * is destroyed, then the weak mpv_handles receive MPV_EVENT_SHUTDOWN and are + * asked to terminate as well.) + * + * Note if you want to use this like refcounting: you have to be aware that + * mpv_terminate_destroy() _and_ mpv_detach_destroy() for the last non-weak + * mpv_handle will block until all weak mpv_handles are destroyed. + */ +mpv_handle *mpv_create_weak_client(mpv_handle *ctx, const char *name); + /** * Load a config file. This loads and parses the file, and sets every entry in * the config file's default section as if mpv_set_option_string() is called. diff --git a/libmpv/mpv.def b/libmpv/mpv.def index 5299f69c9a..202f2071f0 100644 --- a/libmpv/mpv.def +++ b/libmpv/mpv.def @@ -7,6 +7,7 @@ mpv_command_node_async mpv_command_string mpv_create mpv_create_client +mpv_create_weak_client mpv_detach_destroy mpv_error_string mpv_event_name diff --git a/player/client.c b/player/client.c index a887a16d2a..d347033fe5 100644 --- a/player/client.c +++ b/player/client.c @@ -136,6 +136,7 @@ struct mpv_handle { uint64_t property_event_masks; // or-ed together event masks of all properties bool fuzzy_initialized; // see scripting.c wait_loaded() + bool is_weak; // can not keep core alive on its own struct mp_log_buffer *messages; }; @@ -269,6 +270,13 @@ struct mpv_handle *mp_new_client(struct mp_client_api *clients, const char *name return client; } +void mp_client_set_weak(struct mpv_handle *ctx) +{ + pthread_mutex_lock(&ctx->lock); + ctx->is_weak = true; + pthread_mutex_unlock(&ctx->lock); +} + const char *mpv_client_name(mpv_handle *ctx) { return ctx->name; @@ -416,8 +424,11 @@ static void mp_destroy_client(mpv_handle *ctx, bool terminate) if (mpctx->is_cli) { terminate = false; } else { - // If the last mpv_handle got destroyed, destroy the core. - if (clients->num_clients == 0) + // If the last strong mpv_handle got destroyed, destroy the core. + bool has_strong_ref = false; + for (int n = 0; n < clients->num_clients; n++) + has_strong_ref |= !clients->clients[n]->is_weak; + if (!has_strong_ref) terminate = true; // Reserve the right to destroy mpctx for us. @@ -550,6 +561,14 @@ mpv_handle *mpv_create_client(mpv_handle *ctx, const char *name) return new; } +mpv_handle *mpv_create_weak_client(mpv_handle *ctx, const char *name) +{ + mpv_handle *new = mpv_create_client(ctx, name); + if (new) + mp_client_set_weak(new); + return new; +} + int mpv_initialize(mpv_handle *ctx) { lock_core(ctx); diff --git a/player/client.h b/player/client.h index deec3c793b..9ecbe2ed35 100644 --- a/player/client.h +++ b/player/client.h @@ -32,6 +32,7 @@ bool mp_client_event_is_registered(struct MPContext *mpctx, int event); void mp_client_property_change(struct MPContext *mpctx, const char *name); struct mpv_handle *mp_new_client(struct mp_client_api *clients, const char *name); +void mp_client_set_weak(struct mpv_handle *ctx); struct mp_log *mp_client_get_log(struct mpv_handle *ctx); struct mpv_global *mp_client_get_global(struct mpv_handle *ctx); struct MPContext *mp_client_get_core(struct mpv_handle *ctx); diff --git a/player/scripting.c b/player/scripting.c index db622f0fe8..0838630bed 100644 --- a/player/scripting.c +++ b/player/scripting.c @@ -138,6 +138,7 @@ static int mp_load_script(struct MPContext *mpctx, const char *fname) talloc_free(arg); return -1; } + mp_client_set_weak(arg->client); arg->log = mp_client_get_log(arg->client); MP_DBG(arg, "Loading %s %s...\n", backend->name, fname); -- cgit v1.2.3