From f60826c3a14ba3b49077f17e5364b7347f9b468a Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 23 Mar 2018 16:24:49 +0100 Subject: client API: add a first class hook API, and deprecate old API As it turns out, there are multiple libmpv users who saw a need to use the hook API. The API is kind of shitty and was never meant to be actually public (it was mostly a hack for the ytdl script). Introduce a proper API and deprecate the old one. The old one will probably continue to work for a few releases, but will be removed eventually. There are some slight changes to the old API, but if a user followed the manual properly, it won't break. Mostly untested. Appears to work with ytdl_hook. --- libmpv/client.h | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- libmpv/mpv.def | 2 ++ 2 files changed, 80 insertions(+), 1 deletion(-) (limited to 'libmpv') diff --git a/libmpv/client.h b/libmpv/client.h index cd646eb218..77c149e405 100644 --- a/libmpv/client.h +++ b/libmpv/client.h @@ -1133,6 +1133,9 @@ int mpv_get_property_async(mpv_handle *ctx, uint64_t reply_userdata, * property yourself. Try to avoid endless feedback loops, which could happen * if you react to the change notifications triggered by your own change. * + * Only the mpv_handle on which this was called will receive the property + * change events, or can unobserve them. + * * @param reply_userdata This will be used for the mpv_event.reply_userdata * field for the received MPV_EVENT_PROPERTY_CHANGE * events. (Also see section about asynchronous calls, @@ -1350,7 +1353,14 @@ typedef enum mpv_event_id { * Event delivery will continue normally once this event was returned * (this forces the client to empty the queue completely). */ - MPV_EVENT_QUEUE_OVERFLOW = 24 + MPV_EVENT_QUEUE_OVERFLOW = 24, + /** + * Triggered if a hook handler was registered with mpv_hook_add(), and the + * hook is invoked. If you receive this, you must handle it, and continue + * the hook with mpv_hook_continue(). + * See also mpv_event and mpv_event_hook. + */ + MPV_EVENT_HOOK = 25, // Internal note: adjust INTERNAL_EVENT_BASE when adding new events. } mpv_event_id; @@ -1514,6 +1524,17 @@ typedef struct mpv_event_client_message { const char **args; } mpv_event_client_message; +typedef struct mpv_event_hook { + /** + * The hook name as passed to mpv_hook_add(). + */ + const char *name; + /** + * Internal ID that must be passed to mpv_hook_continue(). + */ + uint64_t id; +} mpv_event_hook; + typedef struct mpv_event { /** * One of mpv_event. Keep in mind that later ABI compatible releases might @@ -1682,6 +1703,62 @@ void mpv_set_wakeup_callback(mpv_handle *ctx, void (*cb)(void *d), void *d); */ void mpv_wait_async_requests(mpv_handle *ctx); +/** + * A hook is like a synchronous event that blocks the player. You register + * a hook handler with this function. You will get an event, which you need + * to handle, and once things are ready, you can let the player continue with + * mpv_hook_continue(). + * + * Currently, hooks can't be removed explicitly. But they will be implicitly + * removed if the mpv_handle it was registered with is destroyed. This also + * continues the hook if it was being handled by the destroyed mpv_handle (but + * this should be avoided, as it might mess up order of hook execution). + * + * Hook handlers are ordered globally by priority and order of registration. + * Handlers for the same hook with same priority are invoked in order of + * registration (the handler registered first is run first). Handlers with + * lower priority are run first (which seems backward). + * + * See the "Hooks" section in the manpage to see which hooks are currently + * defined. + * + * Some hooks might be reentrant (so you get multiple MPV_EVENT_HOOK for the + * same hook). If this can happen for a specific hook type, it will be + * explicitly documented in the manpage. + * + * Only the mpv_handle on which this was called will receive the hook events, + * or can "continue" them. + * + * @param reply_userdata This will be used for the mpv_event.reply_userdata + * field for the received MPV_EVENT_HOOK events. + * If you have no use for this, pass 0. + * @param name The hook name. This should be one of the documented names. But + * if the name is unknown, the hook event will simply be never + * raised. + * @param priority See remarks above. Use 0 as a neutral default. + * @return error code (usually fails only on OOM) + */ +int mpv_hook_add(mpv_handle *ctx, uint64_t reply_userdata, + const char *name, int priority); + +/** + * Respond to a MPV_EVENT_HOOK event. You must call this after you have handled + * the event. There is no way to "cancel" or "stop" the hook. + * + * Calling this will will typically unblock the player for whatever the hook + * is responsible for (e.g. for the "on_load" hook it lets it continue + * playback). + * + * It is explicitly undefined behavior to call this more than once for each + * MPV_EVENT_HOOK, to pass an incorrect ID, or to call this on a mpv_handle + * different from the one that registered the handler and received the event. + * + * @param id This must be the value of the mpv_event_hook.id field for the + * corresponding MPV_EVENT_HOOK. + * @return error code + */ +int mpv_hook_continue(mpv_handle *ctx, uint64_t id); + #if MPV_ENABLE_DEPRECATED /** diff --git a/libmpv/mpv.def b/libmpv/mpv.def index ccd98422a7..1d828f4b2b 100644 --- a/libmpv/mpv.def +++ b/libmpv/mpv.def @@ -21,6 +21,8 @@ mpv_get_property_string mpv_get_sub_api mpv_get_time_us mpv_get_wakeup_pipe +mpv_hook_add +mpv_hook_continue mpv_initialize mpv_load_config_file mpv_observe_property -- cgit v1.2.3