summaryrefslogtreecommitdiffstats
path: root/player/command.c
diff options
context:
space:
mode:
Diffstat (limited to 'player/command.c')
-rw-r--r--player/command.c138
1 files changed, 138 insertions, 0 deletions
diff --git a/player/command.c b/player/command.c
index ee782da8ee..2d05ff6c4e 100644
--- a/player/command.c
+++ b/player/command.c
@@ -85,6 +85,10 @@ struct command_ctx {
struct sub_bitmaps overlay_osd[2];
struct sub_bitmaps *overlay_osd_current;
+ struct hook_handler **hooks;
+ int num_hooks;
+ int64_t hook_seq; // for hook_handler.seq
+
struct ao_device_list *cached_ao_devices;
};
@@ -94,11 +98,107 @@ struct overlay {
struct sub_bitmap osd;
};
+struct hook_handler {
+ char *client; // client API user name
+ char *type; // kind of hook, e.g. "on_load"
+ char *user_id; // numeric user-chosen ID, printed as string
+ int priority; // priority for global hook order
+ int64_t seq; // unique ID (also age -> fixed order for equal priorities)
+ bool active; // hook is currently in progress (only 1 at a time for now)
+};
+
static int edit_filters(struct MPContext *mpctx, enum stream_type mediatype,
const char *cmd, const char *arg);
static int set_filters(struct MPContext *mpctx, enum stream_type mediatype,
struct m_obj_settings *new_chain);
+bool mp_hook_test_completion(struct MPContext *mpctx, char *type)
+{
+ struct command_ctx *cmd = mpctx->command_ctx;
+ for (int n = 0; n < cmd->num_hooks; n++) {
+ struct hook_handler *h = cmd->hooks[n];
+ if (h->active && strcmp(h->type, type) == 0)
+ return false;
+ }
+ return true;
+}
+
+static bool send_hook_msg(struct MPContext *mpctx, struct hook_handler *h,
+ char *cmd)
+{
+ mpv_event_client_message *m = talloc_ptrtype(NULL, m);
+ *m = (mpv_event_client_message){0};
+ MP_TARRAY_APPEND(m, m->args, m->num_args, "hook_run");
+ MP_TARRAY_APPEND(m, m->args, m->num_args, talloc_strdup(m, h->user_id));
+ MP_TARRAY_APPEND(m, m->args, m->num_args, talloc_strdup(m, h->type));
+ bool r =
+ mp_client_send_event(mpctx, h->client, MPV_EVENT_CLIENT_MESSAGE, m) >= 0;
+ if (!r)
+ MP_WARN(mpctx, "Sending hook command failed.\n");
+ return r;
+}
+
+// client==NULL means start the hook chain
+void mp_hook_run(struct MPContext *mpctx, char *client, char *type)
+{
+ struct command_ctx *cmd = mpctx->command_ctx;
+ struct hook_handler *next = NULL;
+ bool found_current = !client;
+ for (int n = 0; n < cmd->num_hooks; n++) {
+ struct hook_handler *h = cmd->hooks[n];
+ if (!found_current) {
+ if (h->active && strcmp(h->type, type) == 0) {
+ h->active = false;
+ found_current = true;
+ }
+ } else if (strcmp(h->type, type) == 0) {
+ next = h;
+ break;
+ }
+ }
+ if (!next)
+ return;
+ MP_VERBOSE(mpctx, "Running hook: %s/%s\n", next->client, type);
+ next->active = true;
+ send_hook_msg(mpctx, next, "hook_run");
+}
+
+void mp_hook_abort(struct MPContext *mpctx, char *type)
+{
+ struct command_ctx *cmd = mpctx->command_ctx;
+ for (int n = 0; n < cmd->num_hooks; n++) {
+ struct hook_handler *h = cmd->hooks[n];
+ if (h->active && strcmp(h->type, type) == 0)
+ send_hook_msg(mpctx, h, "hook_abort");
+ }
+}
+
+static int compare_hook(const void *pa, const void *pb)
+{
+ struct hook_handler **h1 = (void *)pa;
+ struct hook_handler **h2 = (void *)pb;
+ if ((*h1)->priority != (*h2)->priority)
+ return (*h1)->priority - (*h2)->priority;
+ return (*h1)->seq - (*h2)->seq;
+}
+
+static void mp_hook_add(struct MPContext *mpctx, char *client, char *name,
+ int id, int pri)
+{
+ struct command_ctx *cmd = mpctx->command_ctx;
+ struct hook_handler *h = talloc_ptrtype(cmd, h);
+ int64_t seq = cmd->hook_seq++;
+ *h = (struct hook_handler){
+ .client = talloc_strdup(h, client),
+ .type = talloc_strdup(h, name),
+ .user_id = talloc_asprintf(h, "%d", id),
+ .priority = pri,
+ .seq = seq,
+ };
+ MP_TARRAY_APPEND(cmd, cmd->hooks, cmd->num_hooks, h);
+ qsort(cmd->hooks, cmd->num_hooks, sizeof(cmd->hooks[0]), compare_hook);
+}
+
// Call before a seek, in order to allow revert_seek to undo the seek.
static void mark_seek(struct MPContext *mpctx)
{
@@ -213,6 +313,27 @@ static int mp_property_filename(void *ctx, struct m_property *prop,
return r;
}
+static int mp_property_stream_open_filename(void *ctx, struct m_property *prop,
+ int action, void *arg)
+{
+ MPContext *mpctx = ctx;
+ if (!mpctx->stream_open_filename || !mpctx->playing)
+ return M_PROPERTY_UNAVAILABLE;
+ switch (action) {
+ case M_PROPERTY_SET: {
+ if (mpctx->stream)
+ return M_PROPERTY_ERROR;
+ mpctx->stream_open_filename =
+ talloc_strdup(mpctx->stream_open_filename, *(char **)arg);
+ return M_PROPERTY_OK;
+ }
+ case M_PROPERTY_GET_TYPE:
+ case M_PROPERTY_GET:
+ return m_property_strdup_ro(action, arg, mpctx->stream_open_filename);
+ }
+ return M_PROPERTY_NOT_IMPLEMENTED;
+}
+
static int mp_property_file_size(void *ctx, struct m_property *prop,
int action, void *arg)
{
@@ -2771,6 +2892,7 @@ static const struct m_property mp_properties[] = {
{"loop-file", mp_property_generic_option},
{"speed", mp_property_playback_speed},
{"filename", mp_property_filename},
+ {"stream-open-filename", mp_property_stream_open_filename},
{"file-size", mp_property_file_size},
{"path", mp_property_path},
{"media-title", mp_property_media_title},
@@ -4066,6 +4188,22 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd)
break;
}
+ case MP_CMD_HOOK_ADD:
+ if (!cmd->sender) {
+ MP_ERR(mpctx, "Can be used from client API only.\n");
+ return -1;
+ }
+ mp_hook_add(mpctx, cmd->sender, cmd->args[0].v.s, cmd->args[1].v.i,
+ cmd->args[2].v.i);
+ break;
+ case MP_CMD_HOOK_ACK:
+ if (!cmd->sender) {
+ MP_ERR(mpctx, "Can be used from client API only.\n");
+ return -1;
+ }
+ mp_hook_run(mpctx, cmd->sender, cmd->args[0].v.s);
+ break;
+
default:
MP_VERBOSE(mpctx, "Received unknown cmd %s\n", cmd->name);
return -1;