diff --git a/lib/wp/component-loader.c b/lib/wp/component-loader.c index 4172c849..45a63d1c 100644 --- a/lib/wp/component-loader.c +++ b/lib/wp/component-loader.c @@ -32,7 +32,7 @@ */ #define WP_MODULE_INIT_SYMBOL "wireplumber__module_init" -typedef gboolean (*WpModuleInitFunc) (WpCore *, GVariant *, GError **); +typedef GObject *(*WpModuleInitFunc) (WpCore *, GVariant *, GError **); G_DEFINE_ABSTRACT_TYPE (WpComponentLoader, wp_component_loader, WP_TYPE_PLUGIN) @@ -46,7 +46,7 @@ wp_component_loader_class_init (WpComponentLoaderClass * klass) { } -static gboolean +static GObject * load_module (WpCore * core, const gchar * module_name, GVariant * args, GError ** error) { @@ -64,7 +64,7 @@ load_module (WpCore * core, const gchar * module_name, if (!gmodule) { g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED, "Failed to open module %s: %s", module_path, g_module_error ()); - return FALSE; + return NULL; } if (!g_module_symbol (gmodule, WP_MODULE_INIT_SYMBOL, &module_init)) { @@ -72,7 +72,7 @@ load_module (WpCore * core, const gchar * module_name, "Failed to locate symbol " WP_MODULE_INIT_SYMBOL " in %s", module_path); g_module_close (gmodule); - return FALSE; + return NULL; } return ((WpModuleInitFunc) module_init) (core, args, error); @@ -98,13 +98,28 @@ wp_component_loader_find (WpCore * core, const gchar * type) return c ? WP_COMPONENT_LOADER (c) : NULL; } -static gboolean +static void wp_component_loader_load (WpComponentLoader * self, const gchar * component, - const gchar * type, GVariant * args, GError ** error) + const gchar * type, GVariant * args, GAsyncReadyCallback callback, + gpointer data) { - g_return_val_if_fail (WP_IS_COMPONENT_LOADER (self), FALSE); - return WP_COMPONENT_LOADER_GET_CLASS (self)->load (self, component, type, - args, error); + g_return_if_fail (WP_IS_COMPONENT_LOADER (self)); + WP_COMPONENT_LOADER_GET_CLASS (self)->load (self, component, type, + args, callback, data); +} + +static void +on_object_loaded (WpObject *object, GAsyncResult *res, gpointer data) +{ + g_autoptr (GTask) task = G_TASK (data); + g_autoptr (GError) error = NULL; + + if (!wp_object_activate_finish (object, res, &error)) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + g_task_return_pointer (task, g_object_ref (object), g_object_unref); } /*! @@ -121,25 +136,80 @@ wp_component_loader_load (WpComponentLoader * self, const gchar * component, * \param type the type of the component * \param args (transfer floating)(nullable): additional arguments for the component, * usually a dict or a string - * \param error (out) (optional): return location for errors, or NULL to ignore - * \returns TRUE if loaded, FALSE if there was an error + * \param callback (scope async): the callback to call when the operation is done + * \param data (closure): data to pass to \a callback */ -gboolean +void wp_core_load_component (WpCore * self, const gchar * component, - const gchar * type, GVariant * args, GError ** error) + const gchar * type, GVariant * args, GAsyncReadyCallback callback, + gpointer data) { g_autoptr (GVariant) args_ref = args ? g_variant_ref_sink (args) : NULL; + g_autoptr (GTask) task = NULL; + g_autoptr (WpComponentLoader) c = NULL; - if (!g_strcmp0 (type, "module")) - return load_module (self, component, args_ref, error); - else { - g_autoptr (WpComponentLoader) c = wp_component_loader_find (self, type); - if (c) - return wp_component_loader_load (c, component, type, args, error); - else { - g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVALID_ARGUMENT, - "No component loader was found for components of type '%s'", type); - return FALSE; + /* Special case for "module" component type */ + if (g_str_equal (type, "module")) { + task = g_task_new (self, NULL, callback, data); + g_autoptr (GError) error = NULL; + g_autoptr (GObject) o = NULL; + + /* load Module */ + o = load_module (self, component, args_ref, &error); + if (!o) { + g_task_return_error (task, g_steal_pointer (&error)); + return; } + + if (WP_IS_OBJECT (o)) { + /* WpObject needs to be activated */ + if (WP_IS_PLUGIN (o)) + wp_plugin_register (WP_PLUGIN (g_object_ref (o))); + wp_object_activate (WP_OBJECT (o), WP_OBJECT_FEATURES_ALL, NULL, + (GAsyncReadyCallback) on_object_loaded, g_object_ref (task)); + return; + } else if (WP_IS_SI_FACTORY (o)) { + /* WpSiFactory doesn't need to be activated */ + wp_si_factory_register (self, WP_SI_FACTORY (g_object_ref (o))); + g_task_return_pointer (task, g_object_ref (o), g_object_unref); + return; + } + + g_task_return_new_error (task, WP_DOMAIN_LIBRARY, + WP_LIBRARY_ERROR_INVALID_ARGUMENT, + "Invalid module object for component %s", component); + return; } + + /* Otherwise find a component loader for that type and load the component */ + c = wp_component_loader_find (self, type); + if (!c) { + task = g_task_new (self, NULL, callback, data); + g_task_return_new_error (task, WP_DOMAIN_LIBRARY, + WP_LIBRARY_ERROR_INVALID_ARGUMENT, + "No component loader was found for components of type '%s'", type); + return; + } + + wp_component_loader_load (c, component, type, args, callback, data); +} + +/*! + * \brief Finishes the operation started by wp_core_load_component(). + * This is meant to be called in the callback that was passed to that method. + * + * + * \ingroup wpcomponentloader + * \param self the component loader object + * \param res the async result + * \param error (out) (optional): the operation's error, if it occurred + * \returns (transfer full): The loaded component object, or NULL if an + * error happened. + */ +GObject * +wp_core_load_component_finish (WpCore * self, GAsyncResult * res, + GError ** error) +{ + gpointer o = g_task_propagate_pointer (G_TASK (res), error); + return o ? g_object_ref (G_OBJECT (o)) : NULL; } diff --git a/lib/wp/component-loader.h b/lib/wp/component-loader.h index c9bcc9e0..3c6267eb 100644 --- a/lib/wp/component-loader.h +++ b/lib/wp/component-loader.h @@ -28,8 +28,9 @@ struct _WpComponentLoaderClass gboolean (*supports_type) (WpComponentLoader * self, const gchar * type); - gboolean (*load) (WpComponentLoader * self, const gchar * component, - const gchar * type, GVariant * args, GError ** error); + void (*load) (WpComponentLoader * self, const gchar * component, + const gchar * type, GVariant * args, GAsyncReadyCallback callback, + gpointer data); /*< private >*/ WP_PADDING(6) diff --git a/lib/wp/core.h b/lib/wp/core.h index 37997a8c..d62b51ba 100644 --- a/lib/wp/core.h +++ b/lib/wp/core.h @@ -48,8 +48,13 @@ WP_API gchar *wp_core_get_vm_type (WpCore *self); WP_API -gboolean wp_core_load_component (WpCore * self, const gchar * component, - const gchar * type, GVariant * args, GError ** error); +void wp_core_load_component (WpCore * self, const gchar * component, + const gchar * type, GVariant * args, GAsyncReadyCallback callback, + gpointer data); + +WP_API +GObject * wp_core_load_component_finish (WpCore * self, GAsyncResult * res, + GError ** error); /* Connection */ diff --git a/modules/module-default-nodes-api.c b/modules/module-default-nodes-api.c index 8800f67b..212baebf 100644 --- a/modules/module-default-nodes-api.c +++ b/modules/module-default-nodes-api.c @@ -304,12 +304,11 @@ wp_default_nodes_api_class_init (WpDefaultNodesApiClass * klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_plugin_register (g_object_new (wp_default_nodes_api_get_type (), - "name", "default-nodes-api", - "core", core, - NULL)); - return TRUE; + return G_OBJECT (g_object_new (wp_default_nodes_api_get_type (), + "name", "default-nodes-api", + "core", core, + NULL)); } diff --git a/modules/module-file-monitor-api.c b/modules/module-file-monitor-api.c index bd2c9fcf..8f797cd6 100644 --- a/modules/module-file-monitor-api.c +++ b/modules/module-file-monitor-api.c @@ -201,12 +201,11 @@ wp_file_monitor_api_class_init (WpFileMonitorApiClass * klass) G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_plugin_register (g_object_new (wp_file_monitor_api_get_type (), - "name", "file-monitor-api", - "core", core, - NULL)); - return TRUE; + return G_OBJECT (g_object_new (wp_file_monitor_api_get_type (), + "name", "file-monitor-api", + "core", core, + NULL)); } diff --git a/modules/module-logind.c b/modules/module-logind.c index 7724479e..9ed41449 100644 --- a/modules/module-logind.c +++ b/modules/module-logind.c @@ -131,12 +131,11 @@ wp_logind_class_init (WpLogindClass * klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING); } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_plugin_register (g_object_new (wp_logind_get_type (), - "name", NAME, - "core", core, - NULL)); - return TRUE; + return G_OBJECT (g_object_new (wp_logind_get_type (), + "name", NAME, + "core", core, + NULL)); } diff --git a/modules/module-lua-scripting/api/require.c b/modules/module-lua-scripting/api/require.c index 520bd139..e4ae2e6c 100644 --- a/modules/module-lua-scripting/api/require.c +++ b/modules/module-lua-scripting/api/require.c @@ -17,8 +17,7 @@ struct _WpRequireApiTransition }; enum { - STEP_LOAD_MODULES = WP_TRANSITION_STEP_CUSTOM_START, - STEP_ACTIVATE_PLUGINS, + STEP_LOAD_PLUGINS = WP_TRANSITION_STEP_CUSTOM_START, }; G_DECLARE_FINAL_TYPE (WpRequireApiTransition, wp_require_api_transition, @@ -47,23 +46,24 @@ wp_require_api_transition_get_next_step (WpTransition * transition, guint step) WpRequireApiTransition *self = WP_REQUIRE_API_TRANSITION (transition); switch (step) { - case WP_TRANSITION_STEP_NONE: return STEP_LOAD_MODULES; - case STEP_LOAD_MODULES: return STEP_ACTIVATE_PLUGINS; - case STEP_ACTIVATE_PLUGINS: + case WP_TRANSITION_STEP_NONE: return STEP_LOAD_PLUGINS; + case STEP_LOAD_PLUGINS: return (self->pending_plugins > 0) ? - STEP_ACTIVATE_PLUGINS : WP_TRANSITION_STEP_NONE; + STEP_LOAD_PLUGINS : WP_TRANSITION_STEP_NONE; default: g_return_val_if_reached (WP_TRANSITION_STEP_ERROR); } } static void -on_plugin_activated (WpObject * p, GAsyncResult * res, +on_plugin_loaded (WpCore * core, GAsyncResult * res, WpRequireApiTransition *self) { + g_autoptr (GObject) o = NULL; GError *error = NULL; - if (!wp_object_activate_finish (p, res, &error)) { + o = wp_core_load_component_finish (core, res, &error); + if (!o) { wp_transition_return_error (WP_TRANSITION (self), error); return; } @@ -79,49 +79,24 @@ wp_require_api_transition_execute_step (WpTransition * transition, guint step) WpCore *core = wp_transition_get_source_object (transition); switch (step) { - case STEP_LOAD_MODULES: - { + case STEP_LOAD_PLUGINS: + wp_debug_object (self, "Loading plugins..."); + for (guint i = 0; i < self->apis->len; i++) { const gchar *api_name = g_ptr_array_index (self->apis, i); g_autoptr (WpPlugin) plugin = wp_plugin_find (core, api_name); if (!plugin) { - GError *error = NULL; gchar module_name[50]; - g_snprintf (module_name, sizeof (module_name), "libwireplumber-module-%s", api_name); - if (!wp_core_load_component (core, module_name, "module", NULL, &error)) { - wp_transition_return_error (transition, error); - return; - } - - plugin = wp_plugin_find (core, api_name); - if (!plugin) { - wp_transition_return_error (transition, g_error_new ( - WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVALID_ARGUMENT, - "API '%s' was not found in module '%s'", api_name, module_name)); - return; - } + self->pending_plugins++; + wp_core_load_component (core, module_name, "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, self); } } wp_transition_advance (transition); break; - } - - case STEP_ACTIVATE_PLUGINS: - wp_debug_object (self, "Activating plugins..."); - - for (guint i = 0; i < self->apis->len; i++) { - const gchar *api_name = g_ptr_array_index (self->apis, i); - g_autoptr (WpPlugin) plugin = wp_plugin_find (core, api_name); - - self->pending_plugins++; - wp_object_activate (WP_OBJECT (plugin), WP_PLUGIN_FEATURE_ENABLED, NULL, - (GAsyncReadyCallback) on_plugin_activated, self); - } - wp_transition_advance (transition); - break; case WP_TRANSITION_STEP_ERROR: break; diff --git a/modules/module-lua-scripting/module.c b/modules/module-lua-scripting/module.c index e95a9996..1b9a28b5 100644 --- a/modules/module-lua-scripting/module.c +++ b/modules/module-lua-scripting/module.c @@ -18,7 +18,6 @@ struct _WpLuaScriptingPlugin { WpComponentLoader parent; - GPtrArray *scripts; /* element-type: WpPlugin* */ lua_State *L; }; @@ -90,17 +89,6 @@ G_DEFINE_TYPE (WpLuaScriptingPlugin, wp_lua_scripting_plugin, static void wp_lua_scripting_plugin_init (WpLuaScriptingPlugin * self) { - self->scripts = g_ptr_array_new_with_free_func (g_object_unref); -} - -static void -wp_lua_scripting_plugin_finalize (GObject * object) -{ - WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (object); - - g_clear_pointer (&self->scripts, g_ptr_array_unref); - - G_OBJECT_CLASS (wp_lua_scripting_plugin_parent_class)->finalize (object); } static void @@ -129,14 +117,6 @@ wp_lua_scripting_plugin_enable (WpPlugin * plugin, WpTransition * transition) wp_lua_scripting_enable_package_searcher (self->L); wplua_enable_sandbox (self->L, WP_LUA_SANDBOX_ISOLATE_ENV); - /* register scripts that were queued in for loading */ - for (guint i = 0; i < self->scripts->len; i++) { - WpPlugin *script = g_ptr_array_index (self->scripts, i); - g_object_set (script, "lua-engine", self->L, NULL); - wp_plugin_register (g_object_ref (script)); - } - g_ptr_array_set_size (self->scripts, 0); - wp_object_update_features (WP_OBJECT (self), WP_PLUGIN_FEATURE_ENABLED, 0); } @@ -144,6 +124,7 @@ static void wp_lua_scripting_plugin_disable (WpPlugin * plugin) { WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (plugin); + g_clear_pointer (&self->L, wplua_unref); } @@ -165,7 +146,6 @@ find_script (const gchar * script, WpCore *core) g_file_test (script, G_FILE_TEST_IS_REGULAR)) return g_strdup (script); - return wp_find_file (WP_LOOKUP_DIR_ENV_DATA | WP_LOOKUP_DIR_ENV_TEST_SRCDIR | WP_LOOKUP_DIR_XDG_CONFIG_HOME | @@ -174,71 +154,79 @@ find_script (const gchar * script, WpCore *core) script, "scripts"); } -static gboolean +static void +on_script_loaded (WpObject *object, GAsyncResult *res, gpointer data) +{ + g_autoptr (GTask) task = G_TASK (data); + g_autoptr (GError) error = NULL; + + if (!wp_object_activate_finish (object, res, &error)) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + g_task_return_pointer (task, g_object_ref (object), g_object_unref); +} + +static void wp_lua_scripting_plugin_load (WpComponentLoader * cl, const gchar * component, - const gchar * type, GVariant * args, GError ** error) + const gchar * type, GVariant * args, GAsyncReadyCallback callback, + gpointer data) { WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (cl); - g_autoptr (WpCore) core = NULL; + g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (cl)); + g_autoptr (GTask) task = task = g_task_new (core, NULL, callback, data); g_autofree gchar *filepath = NULL; g_autofree gchar *pluginname = NULL; g_autoptr (WpPlugin) script = NULL; + /* make sure the component loader is activated */ + if (!self->L) { + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Lua script component loader cannot load Lua scripts if not enabled"); + return; + } + + /* make sure the type is supported */ if (!g_str_equal (type, "script/lua")) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Could not load script '%s' as its type is not 'script/lua'", component); - return FALSE; - } - - core = wp_object_get_core (WP_OBJECT (cl)); - - if (g_file_test (component, G_FILE_TEST_EXISTS)) { - /* dangling components come with full path */ - g_autofree gchar *filename = g_path_get_basename (component); - filepath = g_strdup (component); - pluginname = g_strdup_printf ("script:%s", filename); - } else { - filepath = find_script (component, core); - pluginname = g_strdup_printf ("script:%s", component); + return; } + /* find the script */ + filepath = find_script (component, core); if (!filepath) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Could not locate script '%s'", component); - return FALSE; + return; } + pluginname = g_strdup_printf ("script:%s", component); + script = g_object_new (WP_TYPE_LUA_SCRIPT, "core", core, "name", pluginname, + "lua-engine", self->L, "filename", filepath, "arguments", args, NULL); - if (self->L) { - wp_debug_object (core, "loading script(%s) plugin name(%s)", - filepath, pluginname); - g_object_set (script, "lua-engine", self->L, NULL); - wp_plugin_register (g_steal_pointer (&script)); - } else { - /* keep in a list and delay registering until the plugin is enabled */ - wp_debug ("queuing script %s", filepath); - g_ptr_array_add (self->scripts, g_steal_pointer (&script)); - } + /* register the script */ + wp_plugin_register (g_object_ref (script)); - return TRUE; + /* enable script */ + wp_object_activate (WP_OBJECT (script), WP_OBJECT_FEATURES_ALL, NULL, + (GAsyncReadyCallback) on_script_loaded, g_object_ref (task)); } static void wp_lua_scripting_plugin_class_init (WpLuaScriptingPluginClass * klass) { - GObjectClass *object_class = (GObjectClass *) klass; WpPluginClass *plugin_class = (WpPluginClass *) klass; WpComponentLoaderClass *cl_class = (WpComponentLoaderClass *) klass; - object_class->finalize = wp_lua_scripting_plugin_finalize; - plugin_class->enable = wp_lua_scripting_plugin_enable; plugin_class->disable = wp_lua_scripting_plugin_disable; @@ -246,12 +234,11 @@ wp_lua_scripting_plugin_class_init (WpLuaScriptingPluginClass * klass) cl_class->load = wp_lua_scripting_plugin_load; } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_plugin_register (g_object_new (wp_lua_scripting_plugin_get_type (), - "name", "lua-scripting", - "core", core, - NULL)); - return TRUE; + return G_OBJECT (g_object_new (wp_lua_scripting_plugin_get_type (), + "name", "lua-scripting", + "core", core, + NULL)); } diff --git a/modules/module-lua-scripting/script.c b/modules/module-lua-scripting/script.c index 6a4826e8..b4f715a9 100644 --- a/modules/module-lua-scripting/script.c +++ b/modules/module-lua-scripting/script.c @@ -272,7 +272,7 @@ wp_lua_script_class_init (WpLuaScriptClass * klass) g_object_class_install_property (object_class, PROP_LUA_ENGINE, g_param_spec_pointer ("lua-engine", "lua-engine", "lua-engine", - G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_FILENAME, g_param_spec_string ("filename", "filename", "filename", NULL, diff --git a/modules/module-mixer-api.c b/modules/module-mixer-api.c index 5d37c9fd..9000fb5a 100644 --- a/modules/module-mixer-api.c +++ b/modules/module-mixer-api.c @@ -614,12 +614,11 @@ wp_mixer_api_class_init (WpMixerApiClass * klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT); } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_plugin_register (g_object_new (wp_mixer_api_get_type (), - "name", "mixer-api", - "core", core, - NULL)); - return TRUE; + return G_OBJECT (g_object_new (wp_mixer_api_get_type (), + "name", "mixer-api", + "core", core, + NULL)); } diff --git a/modules/module-portal-permissionstore.c b/modules/module-portal-permissionstore.c index c4098747..b320e6db 100644 --- a/modules/module-portal-permissionstore.c +++ b/modules/module-portal-permissionstore.c @@ -302,12 +302,12 @@ wp_portal_permissionstore_plugin_class_init ( G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_VARIANT); } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_plugin_register (g_object_new (wp_portal_permissionstore_plugin_get_type(), + return G_OBJECT (g_object_new ( + wp_portal_permissionstore_plugin_get_type(), "name", "portal-permissionstore", "core", core, NULL)); - return TRUE; } diff --git a/modules/module-reserve-device/plugin.c b/modules/module-reserve-device/plugin.c index aba709da..e1000f8d 100644 --- a/modules/module-reserve-device/plugin.c +++ b/modules/module-reserve-device/plugin.c @@ -264,12 +264,11 @@ wp_reserve_device_plugin_class_init (WpReserveDevicePluginClass * klass) } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_plugin_register (g_object_new (wp_reserve_device_plugin_get_type (), + return G_OBJECT (g_object_new (wp_reserve_device_plugin_get_type (), "name", "reserve-device", "core", core, NULL)); - return TRUE; } diff --git a/modules/module-settings.c b/modules/module-settings.c index 1ece400c..56690c96 100644 --- a/modules/module-settings.c +++ b/modules/module-settings.c @@ -336,18 +336,16 @@ wp_settings_plugin_class_init (WpSettingsPluginClass * klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { const gchar *metadata_name = "sm-settings"; - if (args) - metadata_name = g_variant_get_string(args, NULL); + metadata_name = g_variant_get_string (args, NULL); - wp_plugin_register (g_object_new (wp_settings_plugin_get_type (), + return G_OBJECT (g_object_new (wp_settings_plugin_get_type (), "name", "settings", "core", core, "metadata-name", metadata_name, NULL)); - return TRUE; } diff --git a/modules/module-si-audio-adapter.c b/modules/module-si-audio-adapter.c index 6fe67de6..b41c8af4 100644 --- a/modules/module-si-audio-adapter.c +++ b/modules/module-si-audio-adapter.c @@ -777,10 +777,9 @@ si_audio_adapter_linkable_init (WpSiLinkableInterface * iface) iface->get_ports = si_audio_adapter_get_ports; } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_si_factory_register (core, wp_si_factory_new_simple (SI_FACTORY_NAME, + return G_OBJECT (wp_si_factory_new_simple (SI_FACTORY_NAME, si_audio_adapter_get_type ())); - return TRUE; } diff --git a/modules/module-si-audio-virtual.c b/modules/module-si-audio-virtual.c index 25fdbd90..01f2f8be 100644 --- a/modules/module-si-audio-virtual.c +++ b/modules/module-si-audio-virtual.c @@ -355,10 +355,9 @@ si_audio_virtual_adapter_init (WpSiAdapterInterface * iface) iface->set_ports_format_finish = si_audio_virtual_set_ports_format_finish; } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_si_factory_register (core, wp_si_factory_new_simple (SI_FACTORY_NAME, + return G_OBJECT (wp_si_factory_new_simple (SI_FACTORY_NAME, si_audio_virtual_get_type ())); - return TRUE; } diff --git a/modules/module-si-node.c b/modules/module-si-node.c index 8879c1f2..7ce23363 100644 --- a/modules/module-si-node.c +++ b/modules/module-si-node.c @@ -219,10 +219,9 @@ si_node_linkable_init (WpSiLinkableInterface * iface) iface->get_ports = si_node_get_ports; } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_si_factory_register (core, wp_si_factory_new_simple (SI_FACTORY_NAME, + return G_OBJECT (wp_si_factory_new_simple (SI_FACTORY_NAME, si_node_get_type ())); - return TRUE; } diff --git a/modules/module-si-standard-link.c b/modules/module-si-standard-link.c index 2da155d9..1a04631f 100644 --- a/modules/module-si-standard-link.c +++ b/modules/module-si-standard-link.c @@ -775,10 +775,9 @@ si_standard_link_link_init (WpSiLinkInterface * iface) iface->get_in_item = si_standard_link_get_in_item; } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_si_factory_register (core, wp_si_factory_new_simple (SI_FACTORY_NAME, + return G_OBJECT (wp_si_factory_new_simple (SI_FACTORY_NAME, si_standard_link_get_type ())); - return TRUE; } diff --git a/modules/module-standard-event-source.c b/modules/module-standard-event-source.c index df2c61f1..a3114ab0 100644 --- a/modules/module-standard-event-source.c +++ b/modules/module-standard-event-source.c @@ -449,12 +449,11 @@ wp_standard_event_source_class_init (WpStandardEventSourceClass * klass) NULL, NULL, NULL, G_TYPE_NONE, 1, TYPE_RESCAN_CONTEXT); } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_plugin_register (g_object_new (wp_standard_event_source_get_type (), - "name", "standard-event-source", - "core", core, - NULL)); - return TRUE; + return G_OBJECT (g_object_new (wp_standard_event_source_get_type (), + "name", "standard-event-source", + "core", core, + NULL)); } diff --git a/src/main.c b/src/main.c index adedea14..43794bf5 100644 --- a/src/main.c +++ b/src/main.c @@ -36,6 +36,49 @@ static GOptionEntry entries[] = { NULL } }; +struct _ComponentData +{ + gchar *name; + gchar *type; + gint priority; + gint flags; + WpSpaJson *deps; +}; +typedef struct _ComponentData ComponentData; + +static gint +component_cmp_func (const ComponentData *a, const ComponentData *b) +{ + return b->priority - a->priority; +} + +static gint +component_equal_func (const ComponentData *a, ComponentData * b) +{ + return + g_str_equal (a->name, b->name) && g_str_equal (a->type, b->type) ? 0 : 1; +} + +static void +component_data_free (ComponentData *self) +{ + g_clear_pointer (&self->name, g_free); + g_clear_pointer (&self->type, g_free); + g_clear_pointer (&self->deps, wp_spa_json_unref); + g_slice_free (ComponentData, self); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (ComponentData, component_data_free) + +enum +{ + NO_FAIL = 0x1, + IF_EXISTS = 0x2 +}; + +static void +on_plugin_loaded (WpCore *core, GAsyncResult *res, gpointer user_data); + /*** WpInitTransition ***/ struct _WpInitTransition @@ -43,6 +86,7 @@ struct _WpInitTransition WpTransition parent; WpObjectManager *om; GList *components; + ComponentData *curr_component; }; enum { @@ -78,203 +122,101 @@ wp_init_transition_get_next_step (WpTransition * transition, guint step) } } -typedef struct _component_data component_data; - -struct _component_data +static gboolean +component_meets_dependencies (WpCore *core, ComponentData *comp) { - gchar *name; - gchar *type; - gint priority; - gint flags; - WpSpaJson *deps; -}; + g_autoptr (WpConf) conf = NULL; + g_autoptr (WpIterator) it = NULL; + g_auto (GValue) item = G_VALUE_INIT; -static gint -component_cmp_func (const component_data *a, const component_data *b) -{ - return b->priority - a->priority; -} + if (!comp->deps) + return TRUE; -static void -component_unref (component_data *self) -{ - g_free (self->name); - g_free (self->type); - g_clear_pointer (&self->deps, wp_spa_json_unref); - g_slice_free (component_data, self); -} - -G_DEFINE_AUTOPTR_CLEANUP_FUNC (component_data, component_unref) - -static gint -is_component_present (const component_data *listed_cmpnt, - const gchar *new_cmpnt_name) -{ - return !g_str_equal (listed_cmpnt->name, new_cmpnt_name); -} - -enum -{ - NO_FAIL = 0x1, - IF_EXISTS = 0x2 -}; - -static gchar * -extract_base_name (const gchar *filepath) -{ - gchar *basename = g_path_get_basename (filepath); - - if (!basename) - return NULL; - - if (g_str_has_prefix (basename, "libwireplumber-module-")) { - /* strip the file extension for modules */ - basename [strlen (basename) - strlen (".so")] = '\0'; - return basename; - } else if (g_str_has_suffix (basename, ".lua")) - return basename; - else - return NULL; -} - -static gchar * -extract_plugin_name (gchar *name) -{ - if (g_file_test (name, G_FILE_TEST_EXISTS)) { - /* dangling components */ - name = extract_base_name (name); + /* Note that we consider the dependency valid by default if it is not + * found in the settings configuration section */ + conf = wp_conf_get_instance (core); + it = wp_spa_json_new_iterator (comp->deps); + for (; wp_iterator_next (it, &item); g_value_unset (&item)) { + WpSpaJson *dep = g_value_get_boxed (&item); + g_autofree gchar *dep_str = wp_spa_json_parse_string (dep); + gboolean value = wp_conf_get_value_boolean (conf, + "wireplumber.settings", dep_str, TRUE); + if (!value) + return FALSE; } - if (g_str_has_prefix (name, "libwireplumber-module-")) - return g_strdup (name + strlen ("libwireplumber-module-")); - else - return g_strdup_printf ("script:%s", name); + + return TRUE; } -static void -on_plugin_activated (WpObject *p, GAsyncResult *res, WpInitTransition *self); - -static int -load_enable_component (WpInitTransition *self, GError **error) +static gboolean +load_enable_components (WpInitTransition *self) { WpCore *core = wp_transition_get_source_object (WP_TRANSITION (self)); - GList *comps = self->components; - GList *lcomp = g_list_first (comps); - while (lcomp) { - component_data *comp = (component_data *) lcomp->data; - g_autofree gchar *plugin_name = NULL; - g_autoptr (WpPlugin) plugin = NULL; + while (self->components) { + self->curr_component = (ComponentData *) self->components->data; + g_autoptr (GError) error = NULL; - if (comp->deps) { - g_autoptr (WpConf) conf = wp_conf_get_instance (core); - g_autoptr (WpIterator) it = wp_spa_json_new_iterator (comp->deps); - g_auto (GValue) item = G_VALUE_INIT; - gboolean deps_met = TRUE; + /* Advance */ + self->components = g_list_next (self->components); - /* Note that we consider the dependency valid by default if it is not - * found in the settings */ - for (; wp_iterator_next (it, &item); g_value_unset (&item)) { - WpSpaJson *dep = g_value_get_boxed (&item); - g_autofree gchar *dep_str = wp_spa_json_parse_string (dep); - gboolean value = wp_conf_get_value_boolean (conf, - "wireplumber.settings", dep_str, TRUE); - if (!value) { - deps_met = FALSE; - wp_info (".. deps(%s) not met for component(%s), skip loading it", - dep_str, comp->name); - break; - } - } - if (!deps_met) { - comps = g_list_delete_link (comps, g_steal_pointer (&lcomp)); - self->components = comps; - lcomp = g_list_first (comps); - continue; - } - } - - wp_debug (".. loading component(%s) type(%s) priority(%d) flags(%x)", - comp->name, comp->type, comp->priority, comp->flags); - - g_autoptr (GError) load_error = NULL; - if (!wp_core_load_component (core, comp->name, comp->type, NULL, - &load_error)) { - wp_warning (".. error in loading component (%s)", load_error->message); - if ((load_error->code == G_FILE_ERROR_NOENT) || - (load_error->code == G_FILE_ERROR_ACCES)) { - - if (comp->flags & IF_EXISTS) { - wp_warning (".. \"ifexists\" flag set, ignore the failure"); - comps = g_list_delete_link (comps, g_steal_pointer (&lcomp)); - lcomp = g_list_first (comps); - self->components = comps; - continue; - } else if (comp->flags & NO_FAIL) { - wp_warning (".. \"nofail\" flag set, ignore the failure"); - comps = g_list_delete_link (comps, g_steal_pointer (&lcomp)); - lcomp = g_list_first (comps); - self->components = comps; - continue; - } - } - g_propagate_error (error, g_steal_pointer (&load_error)); - - return -EINVAL; + /* Skip component if its dependencies are not met */ + if (!component_meets_dependencies (core, self->curr_component)) { + wp_info ("... skipping comp '%s' as its dependencies are not met", + self->curr_component->name); + continue; } - /* get handle to corresponding plugin & activate it */ - plugin_name = extract_plugin_name (comp->name); - plugin = wp_plugin_find (core, plugin_name); - if (!plugin) { - g_autoptr (WpSiFactory) si = wp_si_factory_find (core, plugin_name); - if (si) { - /* si factory modules register factories they need not be activated */ - comps = g_list_delete_link (comps, g_steal_pointer (&lcomp)); - lcomp = g_list_first (comps); - self->components = comps; - wp_debug (".. enabled si module(%s)", comp->name); - continue; - } else { - wp_warning (".. unable to find (%s) plugin", plugin_name); - g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED, - "unable to find %s plugin", plugin_name); - return -EINVAL; - } - } - wp_debug (".. enabling component(%s) plugin name(%s)", comp->name, - plugin_name); - - comps = g_list_delete_link (comps, g_steal_pointer (&lcomp)); - self->components = comps; - wp_object_activate_closure (WP_OBJECT (plugin), WP_OBJECT_FEATURES_ALL, - NULL, g_cclosure_new_object (G_CALLBACK (on_plugin_activated), - G_OBJECT (self))); - return 1; + /* Load the component */ + wp_debug ("... loading comp '%s' ('%s') with priority '%d' and flags '%x'", + self->curr_component->name, self->curr_component->type, + self->curr_component->priority, self->curr_component->flags); + wp_core_load_component (core, self->curr_component->name, + self->curr_component->type, NULL, + (GAsyncReadyCallback) on_plugin_loaded, self); + return FALSE; } - return 0; + + self->curr_component = NULL; + return TRUE; } static void -on_plugin_activated (WpObject *p, GAsyncResult *res, WpInitTransition *self) +on_plugin_loaded (WpCore *core, GAsyncResult *res, gpointer data) { + WpInitTransition *self = data; + g_autoptr (GObject) o = NULL; g_autoptr (GError) error = NULL; - int ret = 0; - if (!wp_object_activate_finish (p, res, &error)) { - wp_transition_return_error (WP_TRANSITION (self), g_steal_pointer (&error)); + g_return_if_fail (self->curr_component); + + o = wp_core_load_component_finish (core, res, &error); + if (!o) { + if (self->curr_component->flags & IF_EXISTS && + error->code == G_FILE_ERROR_ISDIR) { + wp_info ("skipping component '%s' with 'ifexists' flag because its " + "file does not exist", self->curr_component->name); + goto next; + } else if (self->curr_component->flags & NO_FAIL) { + wp_info ("skipping component '%s' with 'nofail' flag because of " + "loading error: %s", self->curr_component->name, error->message); + goto next; + } + + wp_transition_return_error (WP_TRANSITION (self), g_error_new ( + WP_DOMAIN_DAEMON, WP_EXIT_SOFTWARE, + "failed to activate component '%s': %s", self->curr_component->name, + error->message)); return; } - wp_debug (".. enabled plugin %s", wp_plugin_get_name (WP_PLUGIN (p))); - ret = load_enable_component (self, &error); - if (ret < 0) { - wp_transition_return_error (WP_TRANSITION (self), g_steal_pointer (&error)); - } - else if (ret == 0) - { - wp_debug (".. loading components successful"); + wp_debug ("successfully enabled plugin %s", + wp_plugin_get_name (WP_PLUGIN (o))); + +next: + /* load and enable the rest of components */ + if (load_enable_components (self)) wp_transition_advance (WP_TRANSITION (self)); - } } static void @@ -290,88 +232,66 @@ check_media_session (WpObjectManager * om, WpInitTransition *self) wp_transition_advance (WP_TRANSITION (self)); } -struct data { - WpTransition *transition; - int count; - GList *components; -}; - static gint -pick_default_component_priority (const char *name) +pick_default_component_priority (const char *type) { - if (g_str_has_suffix (name, ".so")) + if (g_str_equal (type, "module")) /* regular module default priority */ return 110; - else if (g_str_has_suffix (name, ".lua")) + else if (g_str_equal (type, "script/lua")) /* Lua Script default priority */ return 100; return 100; } -static char * -pick_component_type (const char *name) +static void +append_json_components (GList **list, WpSpaJson *json) { - if (g_str_has_suffix (name, ".so")) - return g_strdup ("module"); - else if (g_str_has_suffix (name, ".lua")) - return g_strdup ("script/lua"); - - return NULL; -} - -static int -do_parse_json_components (void *data, const char *location, const char *section, - const char *str, size_t len) -{ - struct data *d = data; - WpTransition *transition = d->transition; - g_autoptr (WpSpaJson) json = NULL; g_autoptr (WpIterator) it = NULL; g_auto (GValue) item = G_VALUE_INIT; - json = wp_spa_json_new_from_stringn (str, len); - if (!wp_spa_json_is_array (json)) { - wp_transition_return_error (transition, g_error_new ( - WP_DOMAIN_DAEMON, WP_EXIT_CONFIG, - "wireplumber.components is not a JSON array")); - return -EINVAL; + wp_warning ("components section is not a JSON array, skipping..."); + return; } it = wp_spa_json_new_iterator (json); for (; wp_iterator_next (it, &item); g_value_unset (&item)) { WpSpaJson *cjson = g_value_get_boxed (&item); - g_autoptr (component_data) component = g_slice_new0 (component_data); + g_autoptr (ComponentData) comp = g_slice_new0 (ComponentData); g_autoptr (WpSpaJson) deps = NULL; g_autoptr (WpSpaJson) flags = NULL; - /* name and type are mandatory tags */ + /* Parse name and type (mandatory) */ if (!wp_spa_json_is_object (cjson) || !wp_spa_json_object_get (cjson, - "name", "s", &component->name, - "type", "s", &component->type, + "name", "s", &comp->name, + "type", "s", &comp->type, NULL)) { - wp_transition_return_error (transition, g_error_new ( - WP_DOMAIN_DAEMON, WP_EXIT_CONFIG, - "component must have both a 'name' and a 'type'")); - return -EINVAL; + wp_warning ("component must have both a 'name' and a 'type'"); + component_data_free (comp); + continue; } - if (!wp_spa_json_object_get (cjson, "priority", "i", &component->priority, + /* Parse priority (optional) */ + if (!wp_spa_json_object_get (cjson, "priority", "i", &comp->priority, NULL)) - component->priority = pick_default_component_priority (component->name); + comp->priority = pick_default_component_priority (comp->type); + /* Parse deps (optional) */ if (wp_spa_json_object_get (cjson, "deps", "J", &deps, NULL)) { - if (deps && wp_spa_json_is_array (deps)) { - component->deps = g_steal_pointer (&deps); + if (wp_spa_json_is_array (deps)) { + comp->deps = g_steal_pointer (&deps); } else { - wp_warning ("deps must be an array for component(%s), skip loading it", - component->name); + wp_warning ("skipping component %s as its 'deps' is not a JSON array", + comp->name); + component_data_free (comp); continue; } } + /* Parse flags (optional) */ if (wp_spa_json_object_get (cjson, "flags", "J", &flags, NULL)) { if (flags && wp_spa_json_is_array (flags)) { g_autoptr (WpIterator) it = wp_spa_json_new_iterator (flags); @@ -382,124 +302,34 @@ do_parse_json_components (void *data, const char *location, const char *section, g_autofree gchar *flag_str = wp_spa_json_parse_string (flag); if (g_str_equal (flag_str, "ifexists")) - component->flags |= IF_EXISTS; + comp->flags |= IF_EXISTS; else if (g_str_equal (flag_str, "nofail")) - component->flags |= NO_FAIL; + comp->flags |= NO_FAIL; else - wp_warning ("flag(%s) is not valid for component(%s)", flag_str, - component->name); + wp_warning ("flag '%s' is not valid for component '%s'", flag_str, + comp->name); } } else { - wp_warning ("flags must be an array for component(%s), skip loading it", - component->name); + wp_warning ("skipping component %s as its 'flags' is not a JSON array", + comp->name); + component_data_free (comp); continue; } } - if (!g_list_find_custom (d->components, component->name, - (GCompareFunc) is_component_present)) { - wp_trace (".. parsed component(%s) type(%s) priority(%d) flags(%x) " - "deps defined(%s)", component->name, component->type, - component->priority, component->flags, - (component->deps) ? "true" : "false"); - - d->components = g_list_insert_sorted (d->components, - g_steal_pointer (&component), (GCompareFunc) component_cmp_func); - } else - wp_info (".. component(%s) already present, ignore this entry", - component->name); - - d->count++; + /* Insert component into the list if it does not exist */ + if (!g_list_find_custom (*list, comp, + (GCompareFunc) component_equal_func)) { + wp_trace ("appended component '%s' of type '%s' with priority '%d'", + comp->name, comp->type, comp->priority); + *list = g_list_insert_sorted (*list, g_steal_pointer (&comp), + (GCompareFunc) component_cmp_func); + } else { + wp_debug ("ignoring component '%s' as it is already defined previously", + comp->name); + component_data_free (comp); + } } - return 0; -} - -static gboolean -do_parse_dangling_component (const GValue *item, GValue *ret, gpointer data) -{ - GList *comps = data; - const gchar *path = g_value_dup_string (item); - g_autofree gchar *basename = NULL; - g_autoptr (component_data) comp = g_slice_new0 (component_data); - - comp->type = pick_component_type (path); - comp->name = (gchar *) path; - comp->priority = pick_default_component_priority (path); - - if (!(basename = extract_base_name (path))) { - wp_warning (".. ignore dangling shared object(%s), it is not a wireplumber" - " module", path); - return TRUE; - } - - if (!g_list_find_custom (comps, basename, - (GCompareFunc) is_component_present)) { - wp_debug (".. parsed dangling component(%s) type(%s)", comp->name, - comp->type); - comps = g_list_insert_sorted (comps, g_steal_pointer (&comp), - (GCompareFunc) component_cmp_func); - } else - wp_warning (".. dangling component(%s) already present, ignore this one", - comp->name); - - g_value_set_int (ret, g_value_get_int (ret) + 1); - return TRUE; -} - -#define CONFIG_DIRS_LOOKUP_SET \ - (WP_LOOKUP_DIR_ENV_CONFIG | \ - WP_LOOKUP_DIR_XDG_CONFIG_HOME | \ - WP_LOOKUP_DIR_ETC | \ - WP_LOOKUP_DIR_PREFIX_SHARE) - -/* - * dangling components are those not present in the json config files but - * present in the wireplumber lookup folders. - */ -static gboolean -do_parse_dangling_components (GList *components, GError **error) -{ - g_autoptr (WpIterator) it = NULL; - g_auto (GValue) fold_ret = G_VALUE_INIT; - gint nfiles = 0; - - /* look for 'modules' folder in the look up folders*/ - it = wp_new_files_iterator (CONFIG_DIRS_LOOKUP_SET, "modules", ".so"); - - g_value_init (&fold_ret, G_TYPE_INT); - g_value_set_int (&fold_ret, nfiles); - if (!wp_iterator_fold (it, do_parse_dangling_component, &fold_ret, - components)) { - if (error && G_VALUE_HOLDS (&fold_ret, G_TYPE_ERROR)) - *error = g_value_dup_boxed (&fold_ret); - return FALSE; - } - nfiles = g_value_get_int (&fold_ret); - if (nfiles > 0) { - wp_info (".. parsed %d dangling modules", nfiles); - } - - g_clear_pointer (&it, wp_iterator_unref); - g_value_unset (&fold_ret); - nfiles = 0; - - /* look for 'scripts' folder in the look up folders*/ - it = wp_new_files_iterator (CONFIG_DIRS_LOOKUP_SET, "scripts", ".lua"); - - g_value_init (&fold_ret, G_TYPE_INT); - g_value_set_int (&fold_ret, nfiles); - if (!wp_iterator_fold (it, do_parse_dangling_component, &fold_ret, - components)) { - if (error && G_VALUE_HOLDS (&fold_ret, G_TYPE_ERROR)) - *error = g_value_dup_boxed (&fold_ret); - return FALSE; - } - nfiles = g_value_get_int (&fold_ret); - if (nfiles > 0) { - wp_info (".. parsed %d dangling scripts", nfiles); - } - - return TRUE; } static void @@ -552,47 +382,25 @@ wp_init_transition_execute_step (WpTransition * transition, guint step) } case STEP_PARSE_COMPONENTS: { - struct data data = { .transition = transition, .components = NULL }; - GError *error = NULL; - wp_info_object (self, "parse wireplumber components..."); + g_autoptr (WpConf) conf = wp_conf_get_instance (core); + g_autoptr (WpSpaJson) json_comps = NULL; - if (pw_context_conf_section_for_each (pw_ctx, "wireplumber.components", - do_parse_json_components, &data) < 0) - return; + wp_info_object (self, "parsing components..."); - if (data.count == 0) { - wp_transition_return_error (transition, g_error_new ( - WP_DOMAIN_DAEMON, WP_EXIT_CONFIG, - "No components configured in the context conf file; nothing to do")); - return; - } + /* Append components that are defined in the configuration section */ + json_comps = wp_conf_get_section (conf, "wireplumber.components", NULL); + if (json_comps) + append_json_components (&self->components, json_comps); - if (!do_parse_dangling_components (data.components, &error)) { - wp_warning ("..error in traversing dangling components (%s)", - error->message); - wp_transition_return_error (transition, error); - } - - self->components = g_steal_pointer (&data.components); wp_transition_advance (transition); break; } - case STEP_LOAD_ENABLE_COMPONENTS: { - g_autoptr (GError) error = NULL; - int ret = 0; - wp_info ("load enable components.."); - - ret = load_enable_component (self, &error); - if (ret < 0) { - wp_transition_return_error (transition, g_steal_pointer (&error)); - } else if (ret == 0) { - g_set_error (&error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED, - "list of components not available to load"); - wp_transition_return_error (transition, g_steal_pointer (&error)); - } + case STEP_LOAD_ENABLE_COMPONENTS: + wp_info ("loading and enabling components..."); + if (load_enable_components (self)) + wp_transition_advance (WP_TRANSITION (self)); break; - } case STEP_CHECK_MEDIA_SESSION: { wp_info_object (self, "Checking for session manager conflicts..."); @@ -610,12 +418,14 @@ wp_init_transition_execute_step (WpTransition * transition, guint step) case STEP_CLEANUP: wp_info ("wirePlumber initialized"); g_clear_object (&self->om); - g_list_free_full (self->components, (GDestroyNotify) component_unref); + g_list_free_full (self->components, (GDestroyNotify) component_data_free); + self->components = NULL; break; case WP_TRANSITION_STEP_ERROR: g_clear_object (&self->om); - g_list_free_full (self->components, (GDestroyNotify) component_unref); + g_list_free_full (self->components, (GDestroyNotify) component_data_free); + self->components = NULL; break; default: diff --git a/src/tools/wpctl.c b/src/tools/wpctl.c index b64874ec..ea8ebf5f 100644 --- a/src/tools/wpctl.c +++ b/src/tools/wpctl.c @@ -25,7 +25,6 @@ struct _WpCtl GOptionContext *context; GMainLoop *loop; WpCore *core; - GPtrArray *apis; WpObjectManager *om; guint pending_plugins; gint exit_code; @@ -75,7 +74,6 @@ G_DEFINE_QUARK (wpctl-error, wpctl_error_domain) static void wp_ctl_clear (WpCtl * self) { - g_clear_pointer (&self->apis, g_ptr_array_unref); g_clear_object (&self->om); g_clear_object (&self->core); g_clear_pointer (&self->loop, g_main_loop_unref); @@ -1305,17 +1303,25 @@ static const struct subcommand { }; static void -on_plugin_activated (WpObject * p, GAsyncResult * res, WpCtl * ctl) +on_plugin_loaded (WpCore * core, GAsyncResult * res, WpCtl *ctl) { - g_autoptr (GError) error = NULL; + g_autoptr (GObject) o = NULL; + GError *error = NULL; - if (!wp_object_activate_finish (p, res, &error)) { - fprintf (stderr, "%s", error->message); + o = wp_core_load_component_finish (core, res, &error); + if (!o) { + fprintf (stderr, "%s\n", error->message); ctl->exit_code = 1; g_main_loop_quit (ctl->loop); return; } + if (WP_IS_PLUGIN (o)) { + const gchar *name = wp_plugin_get_name (WP_PLUGIN (o)); + if (g_str_equal (name, "mixer-api")) + g_object_set (o, "scale", 1 /* cubic */, NULL); + } + if (--ctl->pending_plugins == 0) wp_core_install_object_manager (ctl->core, ctl->om); } @@ -1336,7 +1342,6 @@ main (gint argc, gchar **argv) "COMMAND [COMMAND_OPTIONS] - WirePlumber Control CLI"); ctl.loop = g_main_loop_new (NULL, FALSE); ctl.core = wp_core_new (NULL, NULL); - ctl.apis = g_ptr_array_new_with_free_func (g_object_unref); ctl.om = wp_object_manager_new (); /* find the subcommand */ @@ -1403,22 +1408,12 @@ main (gint argc, gchar **argv) } /* load required API modules */ - if (!wp_core_load_component (ctl.core, - "libwireplumber-module-default-nodes-api", "module", NULL, &error)) { - fprintf (stderr, "%s\n", error->message); - return 1; - } - if (!wp_core_load_component (ctl.core, - "libwireplumber-module-mixer-api", "module", NULL, &error)) { - fprintf (stderr, "%s\n", error->message); - return 1; - } - g_ptr_array_add (ctl.apis, wp_plugin_find (ctl.core, "default-nodes-api")); - g_ptr_array_add (ctl.apis, ({ - WpPlugin *p = wp_plugin_find (ctl.core, "mixer-api"); - g_object_set (G_OBJECT (p), "scale", 1 /* cubic */, NULL); - p; - })); + ctl.pending_plugins++; + wp_core_load_component (ctl.core, "libwireplumber-module-default-nodes-api", + "module", NULL, (GAsyncReadyCallback) on_plugin_loaded, &ctl); + ctl.pending_plugins++; + wp_core_load_component (ctl.core, "libwireplumber-module-mixer-api", + "module", NULL, (GAsyncReadyCallback) on_plugin_loaded, &ctl); /* connect */ if (!wp_core_connect (ctl.core)) { @@ -1432,13 +1427,6 @@ main (gint argc, gchar **argv) g_signal_connect_swapped (ctl.om, "installed", (GCallback) cmd->run, &ctl); - for (guint i = 0; i < ctl.apis->len; i++) { - WpPlugin *plugin = g_ptr_array_index (ctl.apis, i); - ctl.pending_plugins++; - wp_object_activate (WP_OBJECT (plugin), WP_PLUGIN_FEATURE_ENABLED, NULL, - (GAsyncReadyCallback) on_plugin_activated, &ctl); - } - g_main_loop_run (ctl.loop); wp_ctl_clear (&ctl); diff --git a/src/tools/wpexec.c b/src/tools/wpexec.c index f207668c..077e3e30 100644 --- a/src/tools/wpexec.c +++ b/src/tools/wpexec.c @@ -103,10 +103,13 @@ wp_init_transition_get_next_step (WpTransition * transition, guint step) } static void -on_plugin_activated (WpObject * p, GAsyncResult * res, WpInitTransition *self) +on_plugin_loaded (WpCore * core, GAsyncResult * res, WpInitTransition *self) { + g_autoptr (GObject) o = NULL; GError *error = NULL; - if (!wp_object_activate_finish (p, res, &error)) { + + o = wp_core_load_component_finish (core, res, &error); + if (!o) { wp_transition_return_error (WP_TRANSITION (self), error); return; } @@ -119,7 +122,6 @@ wp_init_transition_execute_step (WpTransition * transition, guint step) { WpInitTransition *self = WP_INIT_TRANSITION (transition); WpCore *core = wp_transition_get_source_object (transition); - GError *error = NULL; switch (step) { case STEP_CONNECT: @@ -134,42 +136,17 @@ wp_init_transition_execute_step (WpTransition * transition, guint step) break; case STEP_ACTIVATE_PLUGINS: { - if (!wp_core_load_component (core, "libwireplumber-module-lua-scripting", - "module", NULL, &error)) { - wp_transition_return_error (transition, error); - return; - } - if (!wp_core_load_component (core, - "libwireplumber-module-standard-event-source", "module", NULL, - &error)) { - wp_transition_return_error (transition, error); - return; - } - g_autoptr (WpPlugin) p = wp_plugin_find (core, "lua-scripting"); - wp_object_activate (WP_OBJECT (p), WP_PLUGIN_FEATURE_ENABLED, NULL, - (GAsyncReadyCallback) on_plugin_activated, self); - - g_clear_object (&p); - p = wp_plugin_find (core, "standard-event-source"); - wp_object_activate (WP_OBJECT (p), WP_PLUGIN_FEATURE_ENABLED, NULL, - (GAsyncReadyCallback) on_plugin_activated, self); + wp_core_load_component (core, "libwireplumber-module-lua-scripting", + "module", NULL, (GAsyncReadyCallback) on_plugin_loaded, self); + wp_core_load_component (core, "libwireplumber-module-standard-event-source", + "module", NULL, (GAsyncReadyCallback) on_plugin_loaded, self); break; } case STEP_ACTIVATE_SCRIPT: { - GVariant *args = g_variant_builder_end (&exec_args_b); - if (!wp_core_load_component (core, exec_script, "script/lua", args, - &error)) { - wp_transition_return_error (transition, error); - return; - } - - g_autofree gchar *name = g_strdup_printf ("script:%s", exec_script); - g_autoptr (WpPlugin) p = wp_plugin_find (core, name); - - wp_object_activate (WP_OBJECT (p), WP_PLUGIN_FEATURE_ENABLED, NULL, - (GAsyncReadyCallback) on_plugin_activated, self); + wp_core_load_component (core, exec_script, "script/lua", args, + (GAsyncReadyCallback) on_plugin_loaded, self); break; } diff --git a/tests/modules/file-monitor.c b/tests/modules/file-monitor.c index 807ddcbd..68105b29 100644 --- a/tests/modules/file-monitor.c +++ b/tests/modules/file-monitor.c @@ -19,15 +19,28 @@ typedef struct { gchar *evtype; } TestFixture; +static void +on_plugin_loaded (WpCore * core, GAsyncResult * res, TestFixture *f) +{ + g_autoptr (GObject) o = NULL; + GError *error = NULL; + + o = wp_core_load_component_finish (core, res, &error); + g_assert_nonnull (o); + g_assert_no_error (error); + + g_main_loop_quit (f->base.loop); +} + static void test_file_monitor_setup (TestFixture * f, gconstpointer user_data) { wp_base_test_fixture_setup (&f->base, WP_BASE_TEST_FLAG_DONT_CONNECT); - g_autoptr (GError) error = NULL; wp_core_load_component (f->base.core, - "libwireplumber-module-file-monitor-api", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-file-monitor-api", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); + g_main_loop_run (f->base.loop); f->plugin = wp_plugin_find (f->base.core, "file-monitor-api"); g_assert_nonnull (f->plugin); @@ -46,16 +59,6 @@ test_file_monitor_teardown (TestFixture * f, gconstpointer user_data) wp_base_test_fixture_teardown (&f->base); } -static void -on_plugin_activated (WpObject * plugin, GAsyncResult * res, TestFixture * f) -{ - g_autoptr (GError) error = NULL; - if (!wp_object_activate_finish (plugin, res, &error)) { - wp_critical_object (plugin, "%s", error->message); - g_main_loop_quit (f->base.loop); - } -} - static void on_changed (WpPlugin *plugin, const gchar *file, const gchar *old, const char *evtype, TestFixture * f) @@ -72,11 +75,6 @@ test_file_monitor_basic (TestFixture * f, gconstpointer user_data) { gboolean res = FALSE; - /* activate plugin */ - g_assert_nonnull (f->plugin); - wp_object_activate (WP_OBJECT (f->plugin), WP_PLUGIN_FEATURE_ENABLED, - NULL, (GAsyncReadyCallback) on_plugin_activated, f); - /* delete the 'foo' file if it exists in path */ g_autofree gchar *filename = g_build_filename (f->path, "foo", NULL); (void) remove (filename); diff --git a/tests/modules/reserve-device.c b/tests/modules/reserve-device.c index 75de4884..67f9e9b6 100644 --- a/tests/modules/reserve-device.c +++ b/tests/modules/reserve-device.c @@ -21,6 +21,19 @@ typedef struct { gint expected_rd2_state; } RdTestFixture; +static void +on_plugin_loaded (WpCore * core, GAsyncResult * res, RdTestFixture *f) +{ + g_autoptr (GObject) o = NULL; + GError *error = NULL; + + o = wp_core_load_component_finish (core, res, &error); + g_assert_nonnull (o); + g_assert_no_error (error); + + g_main_loop_quit (f->base.loop); +} + static void test_rd_setup (RdTestFixture *f, gconstpointer data) { @@ -31,16 +44,16 @@ test_rd_setup (RdTestFixture *f, gconstpointer data) g_test_dbus_up (f->test_dbus); { - g_autoptr (GError) error = NULL; wp_core_load_component (f->base.core, - "libwireplumber-module-reserve-device", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-reserve-device", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); + g_main_loop_run (f->base.loop); } { - g_autoptr (GError) error = NULL; wp_core_load_component (f->base.client_core, - "libwireplumber-module-reserve-device", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-reserve-device", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); + g_main_loop_run (f->base.loop); } f->rd_plugin_1 = wp_plugin_find (f->base.core, "reserve-device"); @@ -68,16 +81,6 @@ test_rd_teardown (RdTestFixture *f, gconstpointer data) wp_base_test_fixture_teardown (&f->base); } -static void -on_plugin_activated (WpObject * plugin, GAsyncResult * res, RdTestFixture * f) -{ - g_autoptr (GError) error = NULL; - if (!wp_object_activate_finish (plugin, res, &error)) { - wp_critical_object (plugin, "%s", error->message); - g_main_loop_quit (f->base.loop); - } -} - static void ensure_plugins_stable_state (GObject * obj, GParamSpec * spec, RdTestFixture *f) { @@ -92,24 +95,13 @@ static void test_rd_plugin (RdTestFixture *f, gconstpointer data) { GObject *rd1 = NULL, *rd2 = NULL, *rd_video = NULL, *tmp = NULL; - gint state = 0xffff; + gint state = 0; gchar *str; - g_object_get (f->dbus_1, "state", &state, NULL); - g_assert_cmpint (state, ==, 0); - g_object_get (f->dbus_2, "state", &state, NULL); - g_assert_cmpint (state, ==, 0); - - wp_object_activate (WP_OBJECT (f->rd_plugin_1), WP_PLUGIN_FEATURE_ENABLED, - NULL, (GAsyncReadyCallback) on_plugin_activated, f); - wp_object_activate (WP_OBJECT (f->rd_plugin_2), WP_PLUGIN_FEATURE_ENABLED, - NULL, (GAsyncReadyCallback) on_plugin_activated, f); - g_signal_connect (f->dbus_1, "notify::state", G_CALLBACK (ensure_plugins_stable_state), f); g_signal_connect (f->dbus_2, "notify::state", G_CALLBACK (ensure_plugins_stable_state), f); - g_main_loop_run (f->base.loop); g_object_get (f->dbus_1, "state", &state, NULL); g_assert_cmpint (state, ==, 2); @@ -183,23 +175,12 @@ static void test_rd_conn_closed (RdTestFixture *f, gconstpointer data) { GObject *rd1 = NULL; - gint state = 0xffff; - - g_object_get (f->dbus_1, "state", &state, NULL); - g_assert_cmpint (state, ==, 0); - g_object_get (f->dbus_2, "state", &state, NULL); - g_assert_cmpint (state, ==, 0); - - wp_object_activate (WP_OBJECT (f->rd_plugin_1), WP_PLUGIN_FEATURE_ENABLED, - NULL, (GAsyncReadyCallback) on_plugin_activated, f); - wp_object_activate (WP_OBJECT (f->rd_plugin_2), WP_PLUGIN_FEATURE_ENABLED, - NULL, (GAsyncReadyCallback) on_plugin_activated, f); + gint state = 0; g_signal_connect (f->dbus_1, "notify::state", G_CALLBACK (ensure_plugins_stable_state), f); g_signal_connect (f->dbus_2, "notify::state", G_CALLBACK (ensure_plugins_stable_state), f); - g_main_loop_run (f->base.loop); g_object_get (f->dbus_1, "state", &state, NULL); g_assert_cmpint (state, ==, 2); @@ -260,24 +241,13 @@ static void test_rd_acquire_release (RdTestFixture *f, gconstpointer data) { GObject *rd1 = NULL, *rd2 = NULL; - gint state = 0xffff; + gint state = 0; gchar *str = NULL; - g_object_get (f->dbus_1, "state", &state, NULL); - g_assert_cmpint (state, ==, 0); - g_object_get (f->dbus_2, "state", &state, NULL); - g_assert_cmpint (state, ==, 0); - - wp_object_activate (WP_OBJECT (f->rd_plugin_1), WP_PLUGIN_FEATURE_ENABLED, - NULL, (GAsyncReadyCallback) on_plugin_activated, f); - wp_object_activate (WP_OBJECT (f->rd_plugin_2), WP_PLUGIN_FEATURE_ENABLED, - NULL, (GAsyncReadyCallback) on_plugin_activated, f); - g_signal_connect (f->dbus_1, "notify::state", G_CALLBACK (ensure_plugins_stable_state), f); g_signal_connect (f->dbus_2, "notify::state", G_CALLBACK (ensure_plugins_stable_state), f); - g_main_loop_run (f->base.loop); g_object_get (f->dbus_1, "state", &state, NULL); g_assert_cmpint (state, ==, 2); diff --git a/tests/modules/si-audio-adapter.c b/tests/modules/si-audio-adapter.c index 7398f9de..8a6f648b 100644 --- a/tests/modules/si-audio-adapter.c +++ b/tests/modules/si-audio-adapter.c @@ -12,6 +12,17 @@ typedef struct { WpBaseTestFixture base; } TestFixture; +static void +on_plugin_loaded (WpCore * core, GAsyncResult * res, TestFixture *f) +{ + g_autoptr (GObject) o = NULL; + GError *error = NULL; + + o = wp_core_load_component_finish (core, res, &error); + g_assert_nonnull (o); + g_assert_no_error (error); +} + static void test_si_audio_adapter_setup (TestFixture * f, gconstpointer user_data) { @@ -30,10 +41,9 @@ test_si_audio_adapter_setup (TestFixture * f, gconstpointer user_data) "libpipewire-module-adapter", NULL, NULL)); } { - g_autoptr (GError) error = NULL; wp_core_load_component (f->base.core, - "libwireplumber-module-si-audio-adapter", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-si-audio-adapter", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); } } diff --git a/tests/modules/si-audio-virtual.c b/tests/modules/si-audio-virtual.c index ff139872..dc2c5463 100644 --- a/tests/modules/si-audio-virtual.c +++ b/tests/modules/si-audio-virtual.c @@ -12,6 +12,17 @@ typedef struct { WpBaseTestFixture base; } TestFixture; +static void +on_plugin_loaded (WpCore * core, GAsyncResult * res, TestFixture *f) +{ + g_autoptr (GObject) o = NULL; + GError *error = NULL; + + o = wp_core_load_component_finish (core, res, &error); + g_assert_nonnull (o); + g_assert_no_error (error); +} + static void test_si_audio_virtual_setup (TestFixture * f, gconstpointer user_data) { @@ -28,16 +39,14 @@ test_si_audio_virtual_setup (TestFixture * f, gconstpointer user_data) "libpipewire-module-adapter", NULL, NULL)); } { - g_autoptr (GError) error = NULL; wp_core_load_component (f->base.core, - "libwireplumber-module-si-audio-adapter", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-si-audio-adapter", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); } { - g_autoptr (GError) error = NULL; wp_core_load_component (f->base.core, - "libwireplumber-module-si-audio-virtual", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-si-audio-virtual", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); } } diff --git a/tests/modules/si-node.c b/tests/modules/si-node.c index a116a64a..68256c18 100644 --- a/tests/modules/si-node.c +++ b/tests/modules/si-node.c @@ -20,6 +20,17 @@ typedef struct { WpDirection expected_direction; } TestData; +static void +on_plugin_loaded (WpCore * core, GAsyncResult * res, TestFixture *f) +{ + g_autoptr (GObject) o = NULL; + GError *error = NULL; + + o = wp_core_load_component_finish (core, res, &error); + g_assert_nonnull (o); + g_assert_no_error (error); +} + static void test_si_node_setup (TestFixture * f, gconstpointer user_data) { @@ -36,10 +47,9 @@ test_si_node_setup (TestFixture * f, gconstpointer user_data) "libpipewire-module-spa-node-factory", NULL, NULL)); } { - g_autoptr (GError) error = NULL; wp_core_load_component (f->base.core, - "libwireplumber-module-si-node", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-si-node", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); } } diff --git a/tests/modules/si-standard-link.c b/tests/modules/si-standard-link.c index 7845b127..a400c4da 100644 --- a/tests/modules/si-standard-link.c +++ b/tests/modules/si-standard-link.c @@ -65,6 +65,17 @@ load_node (TestFixture * f, const gchar * factory, const gchar * media_class, return g_steal_pointer (&adapter); } +static void +on_plugin_loaded (WpCore * core, GAsyncResult * res, TestFixture *f) +{ + g_autoptr (GObject) o = NULL; + GError *error = NULL; + + o = wp_core_load_component_finish (core, res, &error); + g_assert_nonnull (o); + g_assert_no_error (error); +} + static void test_si_standard_link_setup (TestFixture * f, gconstpointer user_data) { @@ -83,14 +94,13 @@ test_si_standard_link_setup (TestFixture * f, gconstpointer user_data) "libpipewire-module-link-factory", NULL, NULL)); } { - g_autoptr (GError) error = NULL; wp_core_load_component (f->base.core, - "libwireplumber-module-si-audio-adapter", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-si-audio-adapter", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); wp_core_load_component (f->base.core, - "libwireplumber-module-si-standard-link", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-si-standard-link", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); } if (test_is_spa_lib_installed (&f->base, "audiotestsrc")) diff --git a/tests/script-tester.c b/tests/script-tester.c index cf1cd643..66abbdb4 100644 --- a/tests/script-tester.c +++ b/tests/script-tester.c @@ -169,6 +169,20 @@ wp_script_tester_class_init (WpScriptTesterClass *klass) } +static void +on_plugin_loaded (WpCore * core, GAsyncResult * res, ScriptRunnerFixture *f) +{ + g_autoptr (GObject) o = NULL; + GError *error = NULL; + + o = wp_core_load_component_finish (core, res, &error); + g_assert_nonnull (o); + g_assert_no_error (error); + + if (WP_IS_PLUGIN (o)) + g_main_loop_quit (f->base.loop); +} + static void load_component (ScriptRunnerFixture *f, const gchar *name, const gchar *type) { @@ -191,17 +205,11 @@ load_component (ScriptRunnerFixture *f, const gchar *name, const gchar *type) plugin_name = g_strdup (name); } - wp_core_load_component (f->base.core, component_name, type, NULL, &error); - g_assert_no_error (error); - - if (!g_str_has_prefix (name, "si")) { - g_autoptr (WpPlugin) plugin = wp_plugin_find (f->base.core, plugin_name); - - wp_object_activate (WP_OBJECT (plugin), WP_PLUGIN_FEATURE_ENABLED, - NULL, (GAsyncReadyCallback) test_object_activate_finish_cb, f); + wp_core_load_component (f->base.core, component_name, type, NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); + if (!g_str_has_prefix (name, "si")) g_main_loop_run (f->base.loop); - } } static void