From 9f1102bafd8608235ce0d2e24ea70a42b8b8886f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Dzi=C4=99giel?= Date: Wed, 18 Jun 2025 13:03:26 +0200 Subject: [PATCH] clapper: Add ability to enable/disable creation of given enhancer Allow apps to enable or disable given enhancer instances from being created. Also as a safely measure, by default only enable enhancers that work on-demand (extractables) and disable others (reactables). --- src/lib/clapper/clapper-enhancer-proxy.c | 109 +++++++++++++++++- src/lib/clapper/clapper-enhancer-proxy.h | 6 + src/lib/clapper/clapper-enhancers-loader.c | 43 ++++--- src/lib/clapper/clapper-player.c | 2 - .../clapper-reactables-manager-private.h | 3 - src/lib/clapper/clapper-reactables-manager.c | 27 ++--- .../clapper/gst/clapper-enhancer-director.c | 2 +- 7 files changed, 150 insertions(+), 42 deletions(-) diff --git a/src/lib/clapper/clapper-enhancer-proxy.c b/src/lib/clapper/clapper-enhancer-proxy.c index cb19aba8..a7f7c8a2 100644 --- a/src/lib/clapper/clapper-enhancer-proxy.c +++ b/src/lib/clapper/clapper-enhancer-proxy.c @@ -86,6 +86,8 @@ struct _ClapperEnhancerProxy ClapperEnhancerParamFlags scope; GstStructure *local_config; + gboolean allowed; + /* GSettings are not thread-safe, * so store schema instead */ GSettingsSchema *schema; @@ -100,6 +102,7 @@ enum PROP_MODULE_DIR, PROP_DESCRIPTION, PROP_VERSION, + PROP_TARGET_CREATION_ALLOWED, PROP_LAST }; @@ -229,6 +232,8 @@ clapper_enhancer_proxy_copy (ClapperEnhancerProxy *src_proxy, const gchar *copy_ if (src_proxy->local_config) copy->local_config = gst_structure_copy (src_proxy->local_config); + copy->allowed = src_proxy->allowed; + GST_OBJECT_UNLOCK (src_proxy); gst_object_ref_sink (copy); @@ -359,6 +364,8 @@ clapper_enhancer_proxy_fill_from_cache (ClapperEnhancerProxy *self) if (G_UNLIKELY ((self->ifaces[i] = clapper_cache_read_iface (&data)) == 0)) goto abort_reading; } + /* Reactable type is always last */ + self->allowed = (self->ifaces[self->n_ifaces - 1] != CLAPPER_TYPE_REACTABLE); } /* Restore ParamSpecs */ @@ -456,6 +463,7 @@ clapper_enhancer_proxy_export_to_cache (ClapperEnhancerProxy *self) gboolean clapper_enhancer_proxy_fill_from_instance (ClapperEnhancerProxy *self, GObject *enhancer) { + /* NOTE: REACTABLE must be last for "allowed" to work as expected */ const GType enhancer_types[] = { CLAPPER_TYPE_EXTRACTABLE, CLAPPER_TYPE_REACTABLE }; GType *ifaces; GParamSpec **pspecs; @@ -465,9 +473,12 @@ clapper_enhancer_proxy_fill_from_instance (ClapperEnhancerProxy *self, GObject * /* Filter to only Clapper interfaces */ ifaces = g_type_interfaces (G_OBJECT_TYPE (enhancer), &n); for (i = 0; i < n; ++i) { - for (j = 0; j < G_N_ELEMENTS (enhancer_types); ++j) { + const guint n_types = G_N_ELEMENTS (enhancer_types); + + for (j = 0; j < n_types; ++j) { if (ifaces[i] == enhancer_types[j]) { ifaces[write_index++] = ifaces[i]; + self->allowed = (j < n_types - 1); break; // match found, do next iface } } @@ -1088,6 +1099,58 @@ clapper_enhancer_proxy_set_locally_with_table (ClapperEnhancerProxy *self, GHash gst_structure_free (structure); } +/** + * clapper_enhancer_proxy_set_target_creation_allowed: + * @proxy: a #ClapperEnhancerProxy + * @allowed: whether allowed + * + * Set whether to allow instances of proxy target to be created. + * + * See [property@Clapper.EnhancerProxy:target-creation-allowed] for + * detailed descripton what this does. + * + * Since: 0.10 + */ +void +clapper_enhancer_proxy_set_target_creation_allowed (ClapperEnhancerProxy *self, gboolean allowed) +{ + gboolean changed; + + g_return_if_fail (CLAPPER_IS_ENHANCER_PROXY (self)); + + GST_OBJECT_LOCK (self); + if ((changed = self->allowed != allowed)) + self->allowed = allowed; + GST_OBJECT_UNLOCK (self); + + if (changed) + g_object_notify_by_pspec (G_OBJECT (self), param_specs[PROP_TARGET_CREATION_ALLOWED]); +} + +/** + * clapper_enhancer_proxy_get_target_creation_allowed: + * @proxy: a #ClapperEnhancerProxy + * + * Get whether it is allowed to create instances of enhancer that this proxy targets. + * + * Returns: whether target creation is allowed. + * + * Since: 0.10 + */ +gboolean +clapper_enhancer_proxy_get_target_creation_allowed (ClapperEnhancerProxy *self) +{ + gboolean allowed; + + g_return_val_if_fail (CLAPPER_IS_ENHANCER_PROXY (self), FALSE); + + GST_OBJECT_LOCK (self); + allowed = self->allowed; + GST_OBJECT_UNLOCK (self); + + return allowed; +} + static void clapper_enhancer_proxy_init (ClapperEnhancerProxy *self) { @@ -1137,6 +1200,25 @@ clapper_enhancer_proxy_get_property (GObject *object, guint prop_id, case PROP_VERSION: g_value_set_string (value, clapper_enhancer_proxy_get_version (self)); break; + case PROP_TARGET_CREATION_ALLOWED: + g_value_set_boolean (value, clapper_enhancer_proxy_get_target_creation_allowed (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +clapper_enhancer_proxy_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + ClapperEnhancerProxy *self = CLAPPER_ENHANCER_PROXY_CAST (object); + + switch (prop_id) { + case PROP_TARGET_CREATION_ALLOWED: + clapper_enhancer_proxy_set_target_creation_allowed (self, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1152,6 +1234,7 @@ clapper_enhancer_proxy_class_init (ClapperEnhancerProxyClass *klass) "Clapper Enhancer Proxy"); gobject_class->get_property = clapper_enhancer_proxy_get_property; + gobject_class->set_property = clapper_enhancer_proxy_set_property; gobject_class->finalize = clapper_enhancer_proxy_finalize; /** @@ -1209,5 +1292,29 @@ clapper_enhancer_proxy_class_init (ClapperEnhancerProxyClass *klass) NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + /** + * ClapperEnhancerProxy:target-creation-allowed: + * + * Whether to allow instances of proxy target to be created. + * + * This effectively means whether the given enhancer can be used. + * + * By default all enhancers that work on-demand such as [iface@Clapper.Extractable] + * are allowed while enhancers implementing [iface@Clapper.Reactable] are not. + * + * Value of this property from a `GLOBAL` [class@Clapper.EnhancerProxyList] will carry + * over to all newly created [class@Clapper.Player] objects, while altering this on + * `LOCAL` proxy list will only influence given player instance that list belongs to. + * + * Changing this property will not remove already created enhancer instances, thus + * it is usually best practice to allow/disallow creation of given enhancer plugin + * right after [class@Clapper.Player] is created (before it or its queue are used). + * + * Since: 0.10 + */ + param_specs[PROP_TARGET_CREATION_ALLOWED] = g_param_spec_boolean ("target-creation-allowed", + NULL, NULL, FALSE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (gobject_class, PROP_LAST, param_specs); } diff --git a/src/lib/clapper/clapper-enhancer-proxy.h b/src/lib/clapper/clapper-enhancer-proxy.h index cfa61847..1e69c37d 100644 --- a/src/lib/clapper/clapper-enhancer-proxy.h +++ b/src/lib/clapper/clapper-enhancer-proxy.h @@ -76,4 +76,10 @@ void clapper_enhancer_proxy_set_locally (ClapperEnhancerProxy *proxy, const gcha CLAPPER_API void clapper_enhancer_proxy_set_locally_with_table (ClapperEnhancerProxy *proxy, GHashTable *table); +CLAPPER_API +void clapper_enhancer_proxy_set_target_creation_allowed (ClapperEnhancerProxy *proxy, gboolean allowed); + +CLAPPER_API +gboolean clapper_enhancer_proxy_get_target_creation_allowed (ClapperEnhancerProxy *proxy); + G_END_DECLS diff --git a/src/lib/clapper/clapper-enhancers-loader.c b/src/lib/clapper/clapper-enhancers-loader.c index aed8c8b3..0ef148e6 100644 --- a/src/lib/clapper/clapper-enhancers-loader.c +++ b/src/lib/clapper/clapper-enhancers-loader.c @@ -54,6 +54,28 @@ _import_enhancers (const gchar *enhancers_path) g_strfreev (dir_paths); } +static GObject * +_force_create_enhancer (ClapperEnhancerProxy *proxy, GType iface_type) +{ + GObject *enhancer = NULL; + PeasPluginInfo *info = (PeasPluginInfo *) clapper_enhancer_proxy_get_peas_info (proxy); + + g_mutex_lock (&load_lock); + + if (!peas_plugin_info_is_loaded (info) && !peas_engine_load_plugin (_engine, info)) { + GST_ERROR ("Could not load enhancer: %s", peas_plugin_info_get_module_name (info)); + } else if (!peas_engine_provides_extension (_engine, info, iface_type)) { + GST_LOG ("No \"%s\" enhancer in module: %s", g_type_name (iface_type), + peas_plugin_info_get_module_name (info)); + } else { + enhancer = peas_engine_create_extension (_engine, info, iface_type, NULL); + } + + g_mutex_unlock (&load_lock); + + return enhancer; +} + /* * clapper_enhancers_loader_initialize: * @@ -155,7 +177,7 @@ clapper_enhancers_loader_initialize (ClapperEnhancerProxyList *proxies) /* We cannot ask libpeas for "any" of our main interfaces, so try each one until found */ for (j = 0; j < G_N_ELEMENTS (main_types); ++j) { - if ((enhancer = clapper_enhancers_loader_create_enhancer (proxy, main_types[j]))) { + if ((enhancer = _force_create_enhancer (proxy, main_types[j]))) { filled = clapper_enhancer_proxy_fill_from_instance (proxy, enhancer); g_object_unref (enhancer); @@ -200,21 +222,8 @@ clapper_enhancers_loader_initialize (ClapperEnhancerProxyList *proxies) GObject * clapper_enhancers_loader_create_enhancer (ClapperEnhancerProxy *proxy, GType iface_type) { - GObject *enhancer = NULL; - PeasPluginInfo *info = (PeasPluginInfo *) clapper_enhancer_proxy_get_peas_info (proxy); + if (!clapper_enhancer_proxy_get_target_creation_allowed (proxy)) + return NULL; - g_mutex_lock (&load_lock); - - if (!peas_plugin_info_is_loaded (info) && !peas_engine_load_plugin (_engine, info)) { - GST_ERROR ("Could not load enhancer: %s", peas_plugin_info_get_module_name (info)); - } else if (!peas_engine_provides_extension (_engine, info, iface_type)) { - GST_LOG ("No \"%s\" enhancer in module: %s", g_type_name (iface_type), - peas_plugin_info_get_module_name (info)); - } else { - enhancer = peas_engine_create_extension (_engine, info, iface_type, NULL); - } - - g_mutex_unlock (&load_lock); - - return enhancer; + return _force_create_enhancer (proxy, iface_type); } diff --git a/src/lib/clapper/clapper-player.c b/src/lib/clapper/clapper-player.c index 6267179b..75b382e0 100644 --- a/src/lib/clapper/clapper-player.c +++ b/src/lib/clapper/clapper-player.c @@ -2339,8 +2339,6 @@ clapper_player_init (ClapperPlayer *self) if (clapper_enhancer_proxy_list_has_proxy_with_interface (self->enhancer_proxies, CLAPPER_TYPE_REACTABLE)) { self->reactables_manager = clapper_reactables_manager_new (); gst_object_set_parent (GST_OBJECT_CAST (self->reactables_manager), GST_OBJECT_CAST (self)); - - clapper_reactables_manager_trigger_prepare (self->reactables_manager); } self->position_query = gst_query_new_position (GST_FORMAT_TIME); diff --git a/src/lib/clapper/clapper-reactables-manager-private.h b/src/lib/clapper/clapper-reactables-manager-private.h index 8f205ca5..d9e27586 100644 --- a/src/lib/clapper/clapper-reactables-manager-private.h +++ b/src/lib/clapper/clapper-reactables-manager-private.h @@ -36,9 +36,6 @@ void clapper_reactables_manager_initialize (void); G_GNUC_INTERNAL ClapperReactablesManager * clapper_reactables_manager_new (void); -G_GNUC_INTERNAL -void clapper_reactables_manager_trigger_prepare (ClapperReactablesManager *manager); - G_GNUC_INTERNAL void clapper_reactables_manager_trigger_configure_take_config (ClapperReactablesManager *manager, ClapperEnhancerProxy *proxy, GstStructure *config); diff --git a/src/lib/clapper/clapper-reactables-manager.c b/src/lib/clapper/clapper-reactables-manager.c index 3f5e3a7f..faccfb66 100644 --- a/src/lib/clapper/clapper-reactables-manager.c +++ b/src/lib/clapper/clapper-reactables-manager.c @@ -43,6 +43,8 @@ struct _ClapperReactablesManager GstBus *bus; GPtrArray *array; + + gboolean prepare_called; }; #define parent_class clapper_reactables_manager_parent_class @@ -74,15 +76,13 @@ enum enum { - CLAPPER_REACTABLES_MANAGER_QUARK_PREPARE = 0, - CLAPPER_REACTABLES_MANAGER_QUARK_CONFIGURE, + CLAPPER_REACTABLES_MANAGER_QUARK_CONFIGURE = 0, CLAPPER_REACTABLES_MANAGER_QUARK_EVENT, CLAPPER_REACTABLES_MANAGER_QUARK_VALUE, CLAPPER_REACTABLES_MANAGER_QUARK_EXTRA_VALUE }; static ClapperBusQuark _quarks[] = { - {"prepare", 0}, {"configure", 0}, {"event", 0}, {"value", 0}, @@ -161,7 +161,7 @@ clapper_reactables_manager_handle_prepare (ClapperReactablesManager *self) clapper_enhancers_loader_create_enhancer (proxy, CLAPPER_TYPE_REACTABLE)); #endif - if (G_LIKELY (reactable != NULL)) { + if (reactable) { ClapperReactableManagerData *data; GstStructure *config; @@ -216,11 +216,9 @@ clapper_reactables_manager_handle_configure (ClapperReactablesManager *self, con if (data->proxy == proxy) { clapper_enhancer_proxy_apply_config_to_enhancer (data->proxy, config, (GObject *) data->reactable); - return; + break; } } - - GST_ERROR_OBJECT (self, "Triggered configure, but no matching enhancer proxy found"); } static inline void @@ -319,9 +317,11 @@ _bus_message_func (GstBus *bus, GstMessage *msg, gpointer user_data G_GNUC_UNUSE GQuark quark = gst_structure_get_name_id (structure); if (quark == _QUARK (EVENT)) { + if (G_UNLIKELY (!self->prepare_called)) { + clapper_reactables_manager_handle_prepare (self); + self->prepare_called = TRUE; + } clapper_reactables_manager_handle_event (self, structure); - } else if (quark == _QUARK (PREPARE)) { - clapper_reactables_manager_handle_prepare (self); } else if (quark == _QUARK (CONFIGURE)) { clapper_reactables_manager_handle_configure (self, structure); } else { @@ -365,15 +365,6 @@ clapper_reactables_manager_new (void) return reactables_manager; } -void -clapper_reactables_manager_trigger_prepare (ClapperReactablesManager *self) -{ - GstStructure *structure = gst_structure_new_id_empty (_QUARK (PREPARE)); - - gst_bus_post (self->bus, gst_message_new_application ( - GST_OBJECT_CAST (self), structure)); -} - void clapper_reactables_manager_trigger_configure_take_config (ClapperReactablesManager *self, ClapperEnhancerProxy *proxy, GstStructure *config) diff --git a/src/lib/clapper/gst/clapper-enhancer-director.c b/src/lib/clapper/gst/clapper-enhancer-director.c index d6ee1861..455df25f 100644 --- a/src/lib/clapper/gst/clapper-enhancer-director.c +++ b/src/lib/clapper/gst/clapper-enhancer-director.c @@ -93,7 +93,7 @@ clapper_enhancer_director_extract_in_thread (ClapperEnhancerDirectorData *data) clapper_enhancers_loader_create_enhancer (proxy, CLAPPER_TYPE_EXTRACTABLE)); #endif - if (G_LIKELY (extractable != NULL)) { + if (extractable) { if (config) clapper_enhancer_proxy_apply_config_to_enhancer (proxy, config, (GObject *) extractable);