core: introduce the notion of provided features on components

Each component can optionally "provide" a feature, which is basically
a string that describes the feature (ex. "support.dbus"). If the
component loads successfully, the feature is marked as provided and
can be tested for its presence with wp_core_test_feature()
This commit is contained in:
George Kiagiadakis
2023-06-12 23:48:32 +03:00
parent f878e2f62d
commit c7cb193588
19 changed files with 67 additions and 27 deletions

View File

@@ -95,6 +95,8 @@ on_component_loader_load_done (WpComponentLoader * cl, GAsyncResult * res,
g_autoptr (GError) error = NULL; g_autoptr (GError) error = NULL;
g_autoptr (GObject) o = NULL; g_autoptr (GObject) o = NULL;
WpCore *core = g_task_get_source_object (task); WpCore *core = g_task_get_source_object (task);
WpRegistry *reg = wp_core_get_registry (core);
gchar *provides = g_task_get_task_data (task);
o = wp_component_loader_load_finish (cl, res, &error); o = wp_component_loader_load_finish (cl, res, &error);
if (error) { if (error) {
@@ -102,11 +104,14 @@ on_component_loader_load_done (WpComponentLoader * cl, GAsyncResult * res,
return; return;
} }
if (provides)
wp_registry_mark_feature_provided (reg, provides);
if (o) { if (o) {
wp_trace_object (cl, "loaded object " WP_OBJECT_FORMAT, WP_OBJECT_ARGS (o)); wp_trace_object (cl, "loaded object " WP_OBJECT_FORMAT, WP_OBJECT_ARGS (o));
/* store object in the registry */ /* store object in the registry */
wp_registry_register_object (wp_core_get_registry (core), g_object_ref (o)); wp_registry_register_object (reg, g_object_ref (o));
if (WP_IS_OBJECT (o)) { if (WP_IS_OBJECT (o)) {
/* WpObject needs to be activated */ /* WpObject needs to be activated */
@@ -132,18 +137,21 @@ on_component_loader_load_done (WpComponentLoader * cl, GAsyncResult * res,
* *
* \ingroup wpcomponentloader * \ingroup wpcomponentloader
* \param self the core * \param self the core
* \param component the module name or file name * \param component (nullable): the module name or file name
* \param type the type of the component * \param type the type of the component
* \param args (transfer none)(nullable): additional arguments for the component, * \param args (transfer none)(nullable): additional arguments for the component,
* expected to be a JSON object * expected to be a JSON object
* \param provides (nullable): the name of the feature that this component will
* provide if it loads successfully; this can be queried later with
* wp_core_test_feature()
* \param cancellable (nullable): optional GCancellable * \param cancellable (nullable): optional GCancellable
* \param callback (scope async): the callback to call when the operation is done * \param callback (scope async): the callback to call when the operation is done
* \param data (closure): data to pass to \a callback * \param data (closure): data to pass to \a callback
*/ */
void void
wp_core_load_component (WpCore * self, const gchar * component, wp_core_load_component (WpCore * self, const gchar * component,
const gchar * type, WpSpaJson * args, GCancellable * cancellable, const gchar * type, WpSpaJson * args, const gchar * provides,
GAsyncReadyCallback callback, gpointer data) GCancellable * cancellable, GAsyncReadyCallback callback, gpointer data)
{ {
g_autoptr (GTask) task = NULL; g_autoptr (GTask) task = NULL;
g_autoptr (WpComponentLoader) cl = NULL; g_autoptr (WpComponentLoader) cl = NULL;
@@ -151,6 +159,9 @@ wp_core_load_component (WpCore * self, const gchar * component,
task = g_task_new (self, cancellable, callback, data); task = g_task_new (self, cancellable, callback, data);
g_task_set_source_tag (task, wp_core_load_component); g_task_set_source_tag (task, wp_core_load_component);
if (provides)
g_task_set_task_data (task, g_strdup (provides), g_free);
/* find a component loader for that type and load the component */ /* find a component loader for that type and load the component */
cl = wp_component_loader_find (self, type); cl = wp_component_loader_find (self, type);
if (!cl) { if (!cl) {

View File

@@ -42,8 +42,8 @@ struct _WpComponentLoaderInterface
WP_API WP_API
void wp_core_load_component (WpCore * self, const gchar * component, void wp_core_load_component (WpCore * self, const gchar * component,
const gchar * type, WpSpaJson * args, GCancellable * cancellable, const gchar * type, WpSpaJson * args, const gchar * provides,
GAsyncReadyCallback callback, gpointer data); GCancellable * cancellable, GAsyncReadyCallback callback, gpointer data);
WP_API WP_API
gboolean wp_core_load_component_finish (WpCore * self, GAsyncResult * res, gboolean wp_core_load_component_finish (WpCore * self, GAsyncResult * res,

View File

@@ -1052,6 +1052,21 @@ wp_core_sync_finish (WpCore * self, GAsyncResult * res, GError ** error)
return g_task_propagate_boolean (G_TASK (res), error); return g_task_propagate_boolean (G_TASK (res), error);
} }
/*!
* \brief Test if a global feature is provided
*
* \ingroup wpcore
* \param self the core
* \param feature the feature name
* \returns TRUE if the feature is provided, FALSE otherwise
*/
gboolean
wp_core_test_feature (WpCore * self, const gchar * feature)
{
return g_ptr_array_find_with_equal_func (self->registry.features, feature,
g_str_equal, NULL);
}
WpRegistry * WpRegistry *
wp_core_get_registry (WpCore * self) wp_core_get_registry (WpCore * self)
{ {

View File

@@ -120,6 +120,11 @@ gboolean wp_core_sync_finish (WpCore * self, GAsyncResult * res,
WP_API WP_API
void wp_core_install_object_manager (WpCore * self, WpObjectManager * om); void wp_core_install_object_manager (WpCore * self, WpObjectManager * om);
/* Global Features */
WP_API
gboolean wp_core_test_feature (WpCore * self, const gchar * feature);
G_END_DECLS G_END_DECLS
#endif #endif

View File

@@ -961,6 +961,7 @@ wp_registry_init (WpRegistry *self)
g_ptr_array_new_with_free_func ((GDestroyNotify) wp_global_unref); g_ptr_array_new_with_free_func ((GDestroyNotify) wp_global_unref);
self->objects = g_ptr_array_new_with_free_func (g_object_unref); self->objects = g_ptr_array_new_with_free_func (g_object_unref);
self->object_managers = g_ptr_array_new (); self->object_managers = g_ptr_array_new ();
self->features = g_ptr_array_new_with_free_func (g_free);
} }
void void
@@ -969,6 +970,7 @@ wp_registry_clear (WpRegistry *self)
wp_registry_detach (self); wp_registry_detach (self);
g_clear_pointer (&self->globals, g_ptr_array_unref); g_clear_pointer (&self->globals, g_ptr_array_unref);
g_clear_pointer (&self->tmp_globals, g_ptr_array_unref); g_clear_pointer (&self->tmp_globals, g_ptr_array_unref);
g_clear_pointer (&self->features, g_ptr_array_unref);
/* remove all the registered objects /* remove all the registered objects
this will normally also destroy the object managers, eventually, since this will normally also destroy the object managers, eventually, since

View File

@@ -292,7 +292,7 @@ wp_component_array_load_task_execute_step (WpTransition * transition, guint step
self->curr_component->name, self->curr_component->type, self->curr_component->name, self->curr_component->type,
self->curr_component->priority, self->curr_component->flags); self->curr_component->priority, self->curr_component->flags);
wp_core_load_component (core, self->curr_component->name, wp_core_load_component (core, self->curr_component->name,
self->curr_component->type, NULL, NULL, self->curr_component->type, NULL, NULL, NULL,
(GAsyncReadyCallback) on_component_loaded, self); (GAsyncReadyCallback) on_component_loaded, self);
break; break;

View File

@@ -30,6 +30,7 @@ struct _WpRegistry
GPtrArray *tmp_globals; // elementy-type: WpGlobal* GPtrArray *tmp_globals; // elementy-type: WpGlobal*
GPtrArray *objects; // element-type: GObject* GPtrArray *objects; // element-type: GObject*
GPtrArray *object_managers; // element-type: WpObjectManager* GPtrArray *object_managers; // element-type: WpObjectManager*
GPtrArray *features; // element-type: gchar*
}; };
void wp_registry_init (WpRegistry *self); void wp_registry_init (WpRegistry *self);
@@ -47,6 +48,12 @@ gpointer wp_registry_find_object (WpRegistry *reg, GEqualFunc func,
void wp_registry_register_object (WpRegistry *reg, gpointer obj); void wp_registry_register_object (WpRegistry *reg, gpointer obj);
void wp_registry_remove_object (WpRegistry *reg, gpointer obj); void wp_registry_remove_object (WpRegistry *reg, gpointer obj);
static inline void
wp_registry_mark_feature_provided (WpRegistry * reg, const gchar * feature)
{
g_ptr_array_add (reg->features, g_strdup (feature));
}
WpCore * wp_registry_get_core (WpRegistry * self) G_GNUC_CONST; WpCore * wp_registry_get_core (WpRegistry * self) G_GNUC_CONST;
/* core */ /* core */

View File

@@ -92,7 +92,7 @@ wp_require_api_transition_execute_step (WpTransition * transition, guint step)
"libwireplumber-module-%s", api_name); "libwireplumber-module-%s", api_name);
self->pending_plugins++; self->pending_plugins++;
wp_core_load_component (core, module_name, "module", NULL, NULL, wp_core_load_component (core, module_name, "module", NULL, NULL, NULL,
(GAsyncReadyCallback) on_plugin_loaded, self); (GAsyncReadyCallback) on_plugin_loaded, self);
} }
} }

View File

@@ -190,7 +190,7 @@ wp_init_transition_execute_step (WpTransition * transition, guint step)
/* Load components that are defined in the configuration section */ /* Load components that are defined in the configuration section */
json_comps = wp_conf_get_section (conf, "wireplumber.components", NULL); json_comps = wp_conf_get_section (conf, "wireplumber.components", NULL);
wp_core_load_component (core, NULL, "array", json_comps, NULL, wp_core_load_component (core, NULL, "array", json_comps, NULL, NULL,
(GAsyncReadyCallback) on_components_loaded, self); (GAsyncReadyCallback) on_components_loaded, self);
break; break;
} }

View File

@@ -1407,10 +1407,10 @@ main (gint argc, gchar **argv)
/* load required API modules */ /* load required API modules */
ctl.pending_plugins++; ctl.pending_plugins++;
wp_core_load_component (ctl.core, "libwireplumber-module-default-nodes-api", wp_core_load_component (ctl.core, "libwireplumber-module-default-nodes-api",
"module", NULL, NULL, (GAsyncReadyCallback) on_plugin_loaded, &ctl); "module", NULL, NULL, NULL, (GAsyncReadyCallback) on_plugin_loaded, &ctl);
ctl.pending_plugins++; ctl.pending_plugins++;
wp_core_load_component (ctl.core, "libwireplumber-module-mixer-api", wp_core_load_component (ctl.core, "libwireplumber-module-mixer-api",
"module", NULL, NULL, (GAsyncReadyCallback) on_plugin_loaded, &ctl); "module", NULL, NULL, NULL, (GAsyncReadyCallback) on_plugin_loaded, &ctl);
/* connect */ /* connect */
if (!wp_core_connect (ctl.core)) { if (!wp_core_connect (ctl.core)) {

View File

@@ -138,14 +138,14 @@ wp_init_transition_execute_step (WpTransition * transition, guint step)
case STEP_ACTIVATE_PLUGINS: { case STEP_ACTIVATE_PLUGINS: {
wp_core_load_component (core, "libwireplumber-module-lua-scripting", wp_core_load_component (core, "libwireplumber-module-lua-scripting",
"module", NULL, NULL, (GAsyncReadyCallback) on_plugin_loaded, self); "module", NULL, NULL, NULL, (GAsyncReadyCallback) on_plugin_loaded, self);
wp_core_load_component (core, "libwireplumber-module-standard-event-source", wp_core_load_component (core, "libwireplumber-module-standard-event-source",
"module", NULL, NULL, (GAsyncReadyCallback) on_plugin_loaded, self); "module", NULL, NULL, NULL, (GAsyncReadyCallback) on_plugin_loaded, self);
break; break;
} }
case STEP_ACTIVATE_SCRIPT: { case STEP_ACTIVATE_SCRIPT: {
wp_core_load_component (core, exec_script, "script/lua", exec_args, NULL, wp_core_load_component (core, exec_script, "script/lua", exec_args, NULL, NULL,
(GAsyncReadyCallback) on_plugin_loaded, self); (GAsyncReadyCallback) on_plugin_loaded, self);
break; break;
} }

View File

@@ -62,7 +62,7 @@ test_dbus_connection (TestFixture *f, gconstpointer user_data)
WpDBusConnectionState state = -1; WpDBusConnectionState state = -1;
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-dbus-connection", "module", NULL, NULL, "libwireplumber-module-dbus-connection", "module", NULL, NULL, NULL,
(GAsyncReadyCallback) on_plugin_loaded, f); (GAsyncReadyCallback) on_plugin_loaded, f);
g_main_loop_run (f->base.loop); g_main_loop_run (f->base.loop);

View File

@@ -38,7 +38,7 @@ test_file_monitor_setup (TestFixture * f, gconstpointer user_data)
wp_base_test_fixture_setup (&f->base, WP_BASE_TEST_FLAG_DONT_CONNECT); wp_base_test_fixture_setup (&f->base, WP_BASE_TEST_FLAG_DONT_CONNECT);
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-file-monitor-api", "module", NULL, NULL, "libwireplumber-module-file-monitor-api", "module", NULL, NULL, NULL,
(GAsyncReadyCallback) on_plugin_loaded, f); (GAsyncReadyCallback) on_plugin_loaded, f);
g_main_loop_run (f->base.loop); g_main_loop_run (f->base.loop);

View File

@@ -47,25 +47,25 @@ test_rd_setup (RdTestFixture *f, gconstpointer data)
{ {
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-dbus-connection", "module", NULL, NULL, "libwireplumber-module-dbus-connection", "module", NULL, NULL, NULL,
(GAsyncReadyCallback) on_plugin_loaded, f); (GAsyncReadyCallback) on_plugin_loaded, f);
g_main_loop_run (f->base.loop); g_main_loop_run (f->base.loop);
} }
{ {
wp_core_load_component (f->base.client_core, wp_core_load_component (f->base.client_core,
"libwireplumber-module-dbus-connection", "module", NULL, NULL, "libwireplumber-module-dbus-connection", "module", NULL, NULL, NULL,
(GAsyncReadyCallback) on_plugin_loaded, f); (GAsyncReadyCallback) on_plugin_loaded, f);
g_main_loop_run (f->base.loop); g_main_loop_run (f->base.loop);
} }
{ {
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-reserve-device", "module", NULL, NULL, "libwireplumber-module-reserve-device", "module", NULL, NULL, NULL,
(GAsyncReadyCallback) on_plugin_loaded, f); (GAsyncReadyCallback) on_plugin_loaded, f);
g_main_loop_run (f->base.loop); g_main_loop_run (f->base.loop);
} }
{ {
wp_core_load_component (f->base.client_core, wp_core_load_component (f->base.client_core,
"libwireplumber-module-reserve-device", "module", NULL, NULL, "libwireplumber-module-reserve-device", "module", NULL, NULL, NULL,
(GAsyncReadyCallback) on_plugin_loaded, f); (GAsyncReadyCallback) on_plugin_loaded, f);
g_main_loop_run (f->base.loop); g_main_loop_run (f->base.loop);
} }

View File

@@ -44,7 +44,7 @@ test_si_audio_adapter_setup (TestFixture * f, gconstpointer user_data)
} }
{ {
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-si-audio-adapter", "module", NULL, NULL, "libwireplumber-module-si-audio-adapter", "module", NULL, NULL, NULL,
(GAsyncReadyCallback) on_plugin_loaded, f); (GAsyncReadyCallback) on_plugin_loaded, f);
g_main_loop_run (f->base.loop); g_main_loop_run (f->base.loop);
} }

View File

@@ -42,13 +42,13 @@ test_si_audio_virtual_setup (TestFixture * f, gconstpointer user_data)
} }
{ {
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-si-audio-adapter", "module", NULL, NULL, "libwireplumber-module-si-audio-adapter", "module", NULL, NULL, NULL,
(GAsyncReadyCallback) on_plugin_loaded, f); (GAsyncReadyCallback) on_plugin_loaded, f);
g_main_loop_run (f->base.loop); g_main_loop_run (f->base.loop);
} }
{ {
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-si-audio-virtual", "module", NULL, NULL, "libwireplumber-module-si-audio-virtual", "module", NULL, NULL, NULL,
(GAsyncReadyCallback) on_plugin_loaded, f); (GAsyncReadyCallback) on_plugin_loaded, f);
g_main_loop_run (f->base.loop); g_main_loop_run (f->base.loop);
} }

View File

@@ -50,7 +50,7 @@ test_si_node_setup (TestFixture * f, gconstpointer user_data)
} }
{ {
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-si-node", "module", NULL, NULL, "libwireplumber-module-si-node", "module", NULL, NULL, NULL,
(GAsyncReadyCallback) on_plugin_loaded, f); (GAsyncReadyCallback) on_plugin_loaded, f);
g_main_loop_run (f->base.loop); g_main_loop_run (f->base.loop);
} }

View File

@@ -97,12 +97,12 @@ test_si_standard_link_setup (TestFixture * f, gconstpointer user_data)
} }
{ {
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-si-audio-adapter", "module", NULL, NULL, "libwireplumber-module-si-audio-adapter", "module", NULL, NULL, NULL,
(GAsyncReadyCallback) on_plugin_loaded, f); (GAsyncReadyCallback) on_plugin_loaded, f);
g_main_loop_run (f->base.loop); g_main_loop_run (f->base.loop);
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-si-standard-link", "module", NULL, NULL, "libwireplumber-module-si-standard-link", "module", NULL, NULL, NULL,
(GAsyncReadyCallback) on_plugin_loaded, f); (GAsyncReadyCallback) on_plugin_loaded, f);
g_main_loop_run (f->base.loop); g_main_loop_run (f->base.loop);
} }

View File

@@ -204,7 +204,7 @@ load_component (ScriptRunnerFixture *f, const gchar *name, const gchar *type)
plugin_name = g_strdup (name); plugin_name = g_strdup (name);
} }
wp_core_load_component (f->base.core, component_name, type, NULL, NULL, wp_core_load_component (f->base.core, component_name, type, NULL, NULL, NULL,
(GAsyncReadyCallback) on_plugin_loaded, f); (GAsyncReadyCallback) on_plugin_loaded, f);
g_main_loop_run (f->base.loop); g_main_loop_run (f->base.loop);
} }