component-loader: make wp_core_load_component() API asynchronous

This change completely refactors the way components are loaded in wireplumber:
- The module_init() function must return a GObject now. This object is either
a WpPlugin or a WpSiFactory in the current modules.
- When the component loader initializes a module, it automatically registers
the WpPlugin or WpSiFactory with their respective methods. There is no need
to register the WpPlugin or WpSiFactory in the module now.
- The wp_core_load_component() API has been refactored to be asynchronows. This
allows the component loader to automatically activate WpPlugin objects, and
therefore allows the application to directly get the WpPlugin without having
to find it. This simplifies a lot of things.
- The 'ifexists' and 'nofail' component flags now work even if the respective
WpPlugin could not be activated.
- The code that loads components in main.c has also been simplified a lot,
and the option to load dangling components has also been removed.
This commit is contained in:
Julian Bouzas
2023-02-09 13:11:14 -05:00
parent ad940b6efc
commit c61d1e4245
28 changed files with 519 additions and 703 deletions

View File

@@ -32,7 +32,7 @@
*/ */
#define WP_MODULE_INIT_SYMBOL "wireplumber__module_init" #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) 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, load_module (WpCore * core, const gchar * module_name,
GVariant * args, GError ** error) GVariant * args, GError ** error)
{ {
@@ -64,7 +64,7 @@ load_module (WpCore * core, const gchar * module_name,
if (!gmodule) { if (!gmodule) {
g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED, g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED,
"Failed to open module %s: %s", module_path, g_module_error ()); "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)) { 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", "Failed to locate symbol " WP_MODULE_INIT_SYMBOL " in %s",
module_path); module_path);
g_module_close (gmodule); g_module_close (gmodule);
return FALSE; return NULL;
} }
return ((WpModuleInitFunc) module_init) (core, args, error); 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; return c ? WP_COMPONENT_LOADER (c) : NULL;
} }
static gboolean static void
wp_component_loader_load (WpComponentLoader * self, const gchar * component, 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); g_return_if_fail (WP_IS_COMPONENT_LOADER (self));
return WP_COMPONENT_LOADER_GET_CLASS (self)->load (self, component, type, WP_COMPONENT_LOADER_GET_CLASS (self)->load (self, component, type,
args, error); 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 type the type of the component
* \param args (transfer floating)(nullable): additional arguments for the component, * \param args (transfer floating)(nullable): additional arguments for the component,
* usually a dict or a string * usually a dict or a string
* \param error (out) (optional): return location for errors, or NULL to ignore * \param callback (scope async): the callback to call when the operation is done
* \returns TRUE if loaded, FALSE if there was an error * \param data (closure): data to pass to \a callback
*/ */
gboolean void
wp_core_load_component (WpCore * self, const gchar * component, 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 (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")) /* Special case for "module" component type */
return load_module (self, component, args_ref, error); if (g_str_equal (type, "module")) {
else { task = g_task_new (self, NULL, callback, data);
g_autoptr (WpComponentLoader) c = wp_component_loader_find (self, type); g_autoptr (GError) error = NULL;
if (c) g_autoptr (GObject) o = NULL;
return wp_component_loader_load (c, component, type, args, error);
else { /* load Module */
g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVALID_ARGUMENT, o = load_module (self, component, args_ref, &error);
"No component loader was found for components of type '%s'", type); if (!o) {
return FALSE; 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;
} }

View File

@@ -28,8 +28,9 @@ struct _WpComponentLoaderClass
gboolean (*supports_type) (WpComponentLoader * self, const gchar * type); gboolean (*supports_type) (WpComponentLoader * self, const gchar * type);
gboolean (*load) (WpComponentLoader * self, const gchar * component, void (*load) (WpComponentLoader * self, const gchar * component,
const gchar * type, GVariant * args, GError ** error); const gchar * type, GVariant * args, GAsyncReadyCallback callback,
gpointer data);
/*< private >*/ /*< private >*/
WP_PADDING(6) WP_PADDING(6)

View File

@@ -48,8 +48,13 @@ WP_API
gchar *wp_core_get_vm_type (WpCore *self); gchar *wp_core_get_vm_type (WpCore *self);
WP_API WP_API
gboolean wp_core_load_component (WpCore * self, const gchar * component, 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);
WP_API
GObject * wp_core_load_component_finish (WpCore * self, GAsyncResult * res,
GError ** error);
/* Connection */ /* Connection */

View File

@@ -304,12 +304,11 @@ wp_default_nodes_api_class_init (WpDefaultNodesApiClass * klass)
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); 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) wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
{ {
wp_plugin_register (g_object_new (wp_default_nodes_api_get_type (), return G_OBJECT (g_object_new (wp_default_nodes_api_get_type (),
"name", "default-nodes-api", "name", "default-nodes-api",
"core", core, "core", core,
NULL)); NULL));
return TRUE;
} }

View File

@@ -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); 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) wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
{ {
wp_plugin_register (g_object_new (wp_file_monitor_api_get_type (), return G_OBJECT (g_object_new (wp_file_monitor_api_get_type (),
"name", "file-monitor-api", "name", "file-monitor-api",
"core", core, "core", core,
NULL)); NULL));
return TRUE;
} }

View File

@@ -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); 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) wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
{ {
wp_plugin_register (g_object_new (wp_logind_get_type (), return G_OBJECT (g_object_new (wp_logind_get_type (),
"name", NAME, "name", NAME,
"core", core, "core", core,
NULL)); NULL));
return TRUE;
} }

View File

@@ -17,8 +17,7 @@ struct _WpRequireApiTransition
}; };
enum { enum {
STEP_LOAD_MODULES = WP_TRANSITION_STEP_CUSTOM_START, STEP_LOAD_PLUGINS = WP_TRANSITION_STEP_CUSTOM_START,
STEP_ACTIVATE_PLUGINS,
}; };
G_DECLARE_FINAL_TYPE (WpRequireApiTransition, wp_require_api_transition, 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); WpRequireApiTransition *self = WP_REQUIRE_API_TRANSITION (transition);
switch (step) { switch (step) {
case WP_TRANSITION_STEP_NONE: return STEP_LOAD_MODULES; case WP_TRANSITION_STEP_NONE: return STEP_LOAD_PLUGINS;
case STEP_LOAD_MODULES: return STEP_ACTIVATE_PLUGINS; case STEP_LOAD_PLUGINS:
case STEP_ACTIVATE_PLUGINS:
return (self->pending_plugins > 0) ? return (self->pending_plugins > 0) ?
STEP_ACTIVATE_PLUGINS : WP_TRANSITION_STEP_NONE; STEP_LOAD_PLUGINS : WP_TRANSITION_STEP_NONE;
default: default:
g_return_val_if_reached (WP_TRANSITION_STEP_ERROR); g_return_val_if_reached (WP_TRANSITION_STEP_ERROR);
} }
} }
static void static void
on_plugin_activated (WpObject * p, GAsyncResult * res, on_plugin_loaded (WpCore * core, GAsyncResult * res,
WpRequireApiTransition *self) WpRequireApiTransition *self)
{ {
g_autoptr (GObject) o = NULL;
GError *error = 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); wp_transition_return_error (WP_TRANSITION (self), error);
return; return;
} }
@@ -79,49 +79,24 @@ wp_require_api_transition_execute_step (WpTransition * transition, guint step)
WpCore *core = wp_transition_get_source_object (transition); WpCore *core = wp_transition_get_source_object (transition);
switch (step) { 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++) { for (guint i = 0; i < self->apis->len; i++) {
const gchar *api_name = g_ptr_array_index (self->apis, i); const gchar *api_name = g_ptr_array_index (self->apis, i);
g_autoptr (WpPlugin) plugin = wp_plugin_find (core, api_name); g_autoptr (WpPlugin) plugin = wp_plugin_find (core, api_name);
if (!plugin) { if (!plugin) {
GError *error = NULL;
gchar module_name[50]; gchar module_name[50];
g_snprintf (module_name, sizeof (module_name), g_snprintf (module_name, sizeof (module_name),
"libwireplumber-module-%s", api_name); "libwireplumber-module-%s", api_name);
if (!wp_core_load_component (core, module_name, "module", NULL, &error)) { self->pending_plugins++;
wp_transition_return_error (transition, error); wp_core_load_component (core, module_name, "module", NULL,
return; (GAsyncReadyCallback) on_plugin_loaded, self);
}
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;
}
} }
} }
wp_transition_advance (transition); wp_transition_advance (transition);
break; 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: case WP_TRANSITION_STEP_ERROR:
break; break;

View File

@@ -18,7 +18,6 @@ struct _WpLuaScriptingPlugin
{ {
WpComponentLoader parent; WpComponentLoader parent;
GPtrArray *scripts; /* element-type: WpPlugin* */
lua_State *L; lua_State *L;
}; };
@@ -90,17 +89,6 @@ G_DEFINE_TYPE (WpLuaScriptingPlugin, wp_lua_scripting_plugin,
static void static void
wp_lua_scripting_plugin_init (WpLuaScriptingPlugin * self) 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 static void
@@ -129,14 +117,6 @@ wp_lua_scripting_plugin_enable (WpPlugin * plugin, WpTransition * transition)
wp_lua_scripting_enable_package_searcher (self->L); wp_lua_scripting_enable_package_searcher (self->L);
wplua_enable_sandbox (self->L, WP_LUA_SANDBOX_ISOLATE_ENV); 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); 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) wp_lua_scripting_plugin_disable (WpPlugin * plugin)
{ {
WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (plugin); WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (plugin);
g_clear_pointer (&self->L, wplua_unref); 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)) g_file_test (script, G_FILE_TEST_IS_REGULAR))
return g_strdup (script); return g_strdup (script);
return wp_find_file (WP_LOOKUP_DIR_ENV_DATA | return wp_find_file (WP_LOOKUP_DIR_ENV_DATA |
WP_LOOKUP_DIR_ENV_TEST_SRCDIR | WP_LOOKUP_DIR_ENV_TEST_SRCDIR |
WP_LOOKUP_DIR_XDG_CONFIG_HOME | WP_LOOKUP_DIR_XDG_CONFIG_HOME |
@@ -174,71 +154,79 @@ find_script (const gchar * script, WpCore *core)
script, "scripts"); 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, 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); 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 *filepath = NULL;
g_autofree gchar *pluginname = NULL; g_autofree gchar *pluginname = NULL;
g_autoptr (WpPlugin) script = 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")) { 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'", "Could not load script '%s' as its type is not 'script/lua'",
component); component);
return FALSE; return;
}
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);
} }
/* find the script */
filepath = find_script (component, core);
if (!filepath) { 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); "Could not locate script '%s'", component);
return FALSE; return;
} }
pluginname = g_strdup_printf ("script:%s", component);
script = g_object_new (WP_TYPE_LUA_SCRIPT, script = g_object_new (WP_TYPE_LUA_SCRIPT,
"core", core, "core", core,
"name", pluginname, "name", pluginname,
"lua-engine", self->L,
"filename", filepath, "filename", filepath,
"arguments", args, "arguments", args,
NULL); NULL);
if (self->L) { /* register the script */
wp_debug_object (core, "loading script(%s) plugin name(%s)", wp_plugin_register (g_object_ref (script));
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));
}
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 static void
wp_lua_scripting_plugin_class_init (WpLuaScriptingPluginClass * klass) wp_lua_scripting_plugin_class_init (WpLuaScriptingPluginClass * klass)
{ {
GObjectClass *object_class = (GObjectClass *) klass;
WpPluginClass *plugin_class = (WpPluginClass *) klass; WpPluginClass *plugin_class = (WpPluginClass *) klass;
WpComponentLoaderClass *cl_class = (WpComponentLoaderClass *) klass; WpComponentLoaderClass *cl_class = (WpComponentLoaderClass *) klass;
object_class->finalize = wp_lua_scripting_plugin_finalize;
plugin_class->enable = wp_lua_scripting_plugin_enable; plugin_class->enable = wp_lua_scripting_plugin_enable;
plugin_class->disable = wp_lua_scripting_plugin_disable; 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; 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) wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
{ {
wp_plugin_register (g_object_new (wp_lua_scripting_plugin_get_type (), return G_OBJECT (g_object_new (wp_lua_scripting_plugin_get_type (),
"name", "lua-scripting", "name", "lua-scripting",
"core", core, "core", core,
NULL)); NULL));
return TRUE;
} }

View File

@@ -272,7 +272,7 @@ wp_lua_script_class_init (WpLuaScriptClass * klass)
g_object_class_install_property (object_class, PROP_LUA_ENGINE, g_object_class_install_property (object_class, PROP_LUA_ENGINE,
g_param_spec_pointer ("lua-engine", "lua-engine", "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_object_class_install_property (object_class, PROP_FILENAME,
g_param_spec_string ("filename", "filename", "filename", NULL, g_param_spec_string ("filename", "filename", "filename", NULL,

View File

@@ -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); 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) wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
{ {
wp_plugin_register (g_object_new (wp_mixer_api_get_type (), return G_OBJECT (g_object_new (wp_mixer_api_get_type (),
"name", "mixer-api", "name", "mixer-api",
"core", core, "core", core,
NULL)); NULL));
return TRUE;
} }

View File

@@ -302,12 +302,12 @@ wp_portal_permissionstore_plugin_class_init (
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_VARIANT); 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) 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", "name", "portal-permissionstore",
"core", core, "core", core,
NULL)); NULL));
return TRUE;
} }

View File

@@ -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) 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", "name", "reserve-device",
"core", core, "core", core,
NULL)); NULL));
return TRUE;
} }

View File

@@ -336,18 +336,16 @@ wp_settings_plugin_class_init (WpSettingsPluginClass * klass)
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); 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) wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
{ {
const gchar *metadata_name = "sm-settings"; const gchar *metadata_name = "sm-settings";
if (args) 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", "name", "settings",
"core", core, "core", core,
"metadata-name", metadata_name, "metadata-name", metadata_name,
NULL)); NULL));
return TRUE;
} }

View File

@@ -777,10 +777,9 @@ si_audio_adapter_linkable_init (WpSiLinkableInterface * iface)
iface->get_ports = si_audio_adapter_get_ports; 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) 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 ())); si_audio_adapter_get_type ()));
return TRUE;
} }

View File

@@ -355,10 +355,9 @@ si_audio_virtual_adapter_init (WpSiAdapterInterface * iface)
iface->set_ports_format_finish = si_audio_virtual_set_ports_format_finish; 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) 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 ())); si_audio_virtual_get_type ()));
return TRUE;
} }

View File

@@ -219,10 +219,9 @@ si_node_linkable_init (WpSiLinkableInterface * iface)
iface->get_ports = si_node_get_ports; iface->get_ports = si_node_get_ports;
} }
WP_PLUGIN_EXPORT gboolean WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) 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 ())); si_node_get_type ()));
return TRUE;
} }

View File

@@ -775,10 +775,9 @@ si_standard_link_link_init (WpSiLinkInterface * iface)
iface->get_in_item = si_standard_link_get_in_item; 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) 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 ())); si_standard_link_get_type ()));
return TRUE;
} }

View File

@@ -449,12 +449,11 @@ wp_standard_event_source_class_init (WpStandardEventSourceClass * klass)
NULL, NULL, NULL, G_TYPE_NONE, 1, TYPE_RESCAN_CONTEXT); 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) wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
{ {
wp_plugin_register (g_object_new (wp_standard_event_source_get_type (), return G_OBJECT (g_object_new (wp_standard_event_source_get_type (),
"name", "standard-event-source", "name", "standard-event-source",
"core", core, "core", core,
NULL)); NULL));
return TRUE;
} }

View File

@@ -36,6 +36,49 @@ static GOptionEntry entries[] =
{ NULL } { 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 ***/ /*** WpInitTransition ***/
struct _WpInitTransition struct _WpInitTransition
@@ -43,6 +86,7 @@ struct _WpInitTransition
WpTransition parent; WpTransition parent;
WpObjectManager *om; WpObjectManager *om;
GList *components; GList *components;
ComponentData *curr_component;
}; };
enum { enum {
@@ -78,203 +122,101 @@ wp_init_transition_get_next_step (WpTransition * transition, guint step)
} }
} }
typedef struct _component_data component_data; static gboolean
component_meets_dependencies (WpCore *core, ComponentData *comp)
struct _component_data
{ {
gchar *name; g_autoptr (WpConf) conf = NULL;
gchar *type; g_autoptr (WpIterator) it = NULL;
gint priority; g_auto (GValue) item = G_VALUE_INIT;
gint flags;
WpSpaJson *deps;
};
static gint if (!comp->deps)
component_cmp_func (const component_data *a, const component_data *b) return TRUE;
{
return b->priority - a->priority;
}
static void /* Note that we consider the dependency valid by default if it is not
component_unref (component_data *self) * found in the settings configuration section */
{ conf = wp_conf_get_instance (core);
g_free (self->name); it = wp_spa_json_new_iterator (comp->deps);
g_free (self->type); for (; wp_iterator_next (it, &item); g_value_unset (&item)) {
g_clear_pointer (&self->deps, wp_spa_json_unref); WpSpaJson *dep = g_value_get_boxed (&item);
g_slice_free (component_data, self); g_autofree gchar *dep_str = wp_spa_json_parse_string (dep);
} gboolean value = wp_conf_get_value_boolean (conf,
"wireplumber.settings", dep_str, TRUE);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (component_data, component_unref) if (!value)
return FALSE;
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);
} }
if (g_str_has_prefix (name, "libwireplumber-module-"))
return g_strdup (name + strlen ("libwireplumber-module-")); return TRUE;
else
return g_strdup_printf ("script:%s", name);
} }
static void static gboolean
on_plugin_activated (WpObject *p, GAsyncResult *res, WpInitTransition *self); load_enable_components (WpInitTransition *self)
static int
load_enable_component (WpInitTransition *self, GError **error)
{ {
WpCore *core = wp_transition_get_source_object (WP_TRANSITION (self)); WpCore *core = wp_transition_get_source_object (WP_TRANSITION (self));
GList *comps = self->components;
GList *lcomp = g_list_first (comps);
while (lcomp) { while (self->components) {
component_data *comp = (component_data *) lcomp->data; self->curr_component = (ComponentData *) self->components->data;
g_autofree gchar *plugin_name = NULL; g_autoptr (GError) error = NULL;
g_autoptr (WpPlugin) plugin = NULL;
if (comp->deps) { /* Advance */
g_autoptr (WpConf) conf = wp_conf_get_instance (core); self->components = g_list_next (self->components);
g_autoptr (WpIterator) it = wp_spa_json_new_iterator (comp->deps);
g_auto (GValue) item = G_VALUE_INIT;
gboolean deps_met = TRUE;
/* Note that we consider the dependency valid by default if it is not /* Skip component if its dependencies are not met */
* found in the settings */ if (!component_meets_dependencies (core, self->curr_component)) {
for (; wp_iterator_next (it, &item); g_value_unset (&item)) { wp_info ("... skipping comp '%s' as its dependencies are not met",
WpSpaJson *dep = g_value_get_boxed (&item); self->curr_component->name);
g_autofree gchar *dep_str = wp_spa_json_parse_string (dep); continue;
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;
} }
/* get handle to corresponding plugin & activate it */
plugin_name = extract_plugin_name (comp->name);
plugin = wp_plugin_find (core, plugin_name);
if (!plugin) { /* Load the component */
g_autoptr (WpSiFactory) si = wp_si_factory_find (core, plugin_name); wp_debug ("... loading comp '%s' ('%s') with priority '%d' and flags '%x'",
if (si) { self->curr_component->name, self->curr_component->type,
/* si factory modules register factories they need not be activated */ self->curr_component->priority, self->curr_component->flags);
comps = g_list_delete_link (comps, g_steal_pointer (&lcomp)); wp_core_load_component (core, self->curr_component->name,
lcomp = g_list_first (comps); self->curr_component->type, NULL,
self->components = comps; (GAsyncReadyCallback) on_plugin_loaded, self);
wp_debug (".. enabled si module(%s)", comp->name); return FALSE;
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;
} }
return 0;
self->curr_component = NULL;
return TRUE;
} }
static void 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; g_autoptr (GError) error = NULL;
int ret = 0;
if (!wp_object_activate_finish (p, res, &error)) { g_return_if_fail (self->curr_component);
wp_transition_return_error (WP_TRANSITION (self), g_steal_pointer (&error));
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; return;
} }
wp_debug (".. enabled plugin %s", wp_plugin_get_name (WP_PLUGIN (p))); wp_debug ("successfully enabled plugin %s",
ret = load_enable_component (self, &error); wp_plugin_get_name (WP_PLUGIN (o)));
if (ret < 0) {
wp_transition_return_error (WP_TRANSITION (self), g_steal_pointer (&error)); next:
} /* load and enable the rest of components */
else if (ret == 0) if (load_enable_components (self))
{
wp_debug (".. loading components successful");
wp_transition_advance (WP_TRANSITION (self)); wp_transition_advance (WP_TRANSITION (self));
}
} }
static void static void
@@ -290,88 +232,66 @@ check_media_session (WpObjectManager * om, WpInitTransition *self)
wp_transition_advance (WP_TRANSITION (self)); wp_transition_advance (WP_TRANSITION (self));
} }
struct data {
WpTransition *transition;
int count;
GList *components;
};
static gint 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 */ /* regular module default priority */
return 110; return 110;
else if (g_str_has_suffix (name, ".lua")) else if (g_str_equal (type, "script/lua"))
/* Lua Script default priority */ /* Lua Script default priority */
return 100; return 100;
return 100; return 100;
} }
static char * static void
pick_component_type (const char *name) 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_autoptr (WpIterator) it = NULL;
g_auto (GValue) item = G_VALUE_INIT; g_auto (GValue) item = G_VALUE_INIT;
json = wp_spa_json_new_from_stringn (str, len);
if (!wp_spa_json_is_array (json)) { if (!wp_spa_json_is_array (json)) {
wp_transition_return_error (transition, g_error_new ( wp_warning ("components section is not a JSON array, skipping...");
WP_DOMAIN_DAEMON, WP_EXIT_CONFIG, return;
"wireplumber.components is not a JSON array"));
return -EINVAL;
} }
it = wp_spa_json_new_iterator (json); it = wp_spa_json_new_iterator (json);
for (; wp_iterator_next (it, &item); g_value_unset (&item)) { for (; wp_iterator_next (it, &item); g_value_unset (&item)) {
WpSpaJson *cjson = g_value_get_boxed (&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) deps = NULL;
g_autoptr (WpSpaJson) flags = NULL; g_autoptr (WpSpaJson) flags = NULL;
/* name and type are mandatory tags */ /* Parse name and type (mandatory) */
if (!wp_spa_json_is_object (cjson) || if (!wp_spa_json_is_object (cjson) ||
!wp_spa_json_object_get (cjson, !wp_spa_json_object_get (cjson,
"name", "s", &component->name, "name", "s", &comp->name,
"type", "s", &component->type, "type", "s", &comp->type,
NULL)) { NULL)) {
wp_transition_return_error (transition, g_error_new ( wp_warning ("component must have both a 'name' and a 'type'");
WP_DOMAIN_DAEMON, WP_EXIT_CONFIG, component_data_free (comp);
"component must have both a 'name' and a 'type'")); continue;
return -EINVAL;
} }
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)) 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 (wp_spa_json_object_get (cjson, "deps", "J", &deps, NULL)) {
if (deps && wp_spa_json_is_array (deps)) { if (wp_spa_json_is_array (deps)) {
component->deps = g_steal_pointer (&deps); comp->deps = g_steal_pointer (&deps);
} else { } else {
wp_warning ("deps must be an array for component(%s), skip loading it", wp_warning ("skipping component %s as its 'deps' is not a JSON array",
component->name); comp->name);
component_data_free (comp);
continue; continue;
} }
} }
/* Parse flags (optional) */
if (wp_spa_json_object_get (cjson, "flags", "J", &flags, NULL)) { if (wp_spa_json_object_get (cjson, "flags", "J", &flags, NULL)) {
if (flags && wp_spa_json_is_array (flags)) { if (flags && wp_spa_json_is_array (flags)) {
g_autoptr (WpIterator) it = wp_spa_json_new_iterator (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); g_autofree gchar *flag_str = wp_spa_json_parse_string (flag);
if (g_str_equal (flag_str, "ifexists")) if (g_str_equal (flag_str, "ifexists"))
component->flags |= IF_EXISTS; comp->flags |= IF_EXISTS;
else if (g_str_equal (flag_str, "nofail")) else if (g_str_equal (flag_str, "nofail"))
component->flags |= NO_FAIL; comp->flags |= NO_FAIL;
else else
wp_warning ("flag(%s) is not valid for component(%s)", flag_str, wp_warning ("flag '%s' is not valid for component '%s'", flag_str,
component->name); comp->name);
} }
} else { } else {
wp_warning ("flags must be an array for component(%s), skip loading it", wp_warning ("skipping component %s as its 'flags' is not a JSON array",
component->name); comp->name);
component_data_free (comp);
continue; continue;
} }
} }
if (!g_list_find_custom (d->components, component->name, /* Insert component into the list if it does not exist */
(GCompareFunc) is_component_present)) { if (!g_list_find_custom (*list, comp,
wp_trace (".. parsed component(%s) type(%s) priority(%d) flags(%x) " (GCompareFunc) component_equal_func)) {
"deps defined(%s)", component->name, component->type, wp_trace ("appended component '%s' of type '%s' with priority '%d'",
component->priority, component->flags, comp->name, comp->type, comp->priority);
(component->deps) ? "true" : "false"); *list = g_list_insert_sorted (*list, g_steal_pointer (&comp),
(GCompareFunc) component_cmp_func);
d->components = g_list_insert_sorted (d->components, } else {
g_steal_pointer (&component), (GCompareFunc) component_cmp_func); wp_debug ("ignoring component '%s' as it is already defined previously",
} else comp->name);
wp_info (".. component(%s) already present, ignore this entry", component_data_free (comp);
component->name); }
d->count++;
} }
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 static void
@@ -552,47 +382,25 @@ wp_init_transition_execute_step (WpTransition * transition, guint step)
} }
case STEP_PARSE_COMPONENTS: { case STEP_PARSE_COMPONENTS: {
struct data data = { .transition = transition, .components = NULL }; g_autoptr (WpConf) conf = wp_conf_get_instance (core);
GError *error = NULL; g_autoptr (WpSpaJson) json_comps = NULL;
wp_info_object (self, "parse wireplumber components...");
if (pw_context_conf_section_for_each (pw_ctx, "wireplumber.components", wp_info_object (self, "parsing components...");
do_parse_json_components, &data) < 0)
return;
if (data.count == 0) { /* Append components that are defined in the configuration section */
wp_transition_return_error (transition, g_error_new ( json_comps = wp_conf_get_section (conf, "wireplumber.components", NULL);
WP_DOMAIN_DAEMON, WP_EXIT_CONFIG, if (json_comps)
"No components configured in the context conf file; nothing to do")); append_json_components (&self->components, json_comps);
return;
}
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); wp_transition_advance (transition);
break; break;
} }
case STEP_LOAD_ENABLE_COMPONENTS: { case STEP_LOAD_ENABLE_COMPONENTS:
g_autoptr (GError) error = NULL; wp_info ("loading and enabling components...");
int ret = 0; if (load_enable_components (self))
wp_info ("load enable components.."); wp_transition_advance (WP_TRANSITION (self));
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));
}
break; break;
}
case STEP_CHECK_MEDIA_SESSION: { case STEP_CHECK_MEDIA_SESSION: {
wp_info_object (self, "Checking for session manager conflicts..."); 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: case STEP_CLEANUP:
wp_info ("wirePlumber initialized"); wp_info ("wirePlumber initialized");
g_clear_object (&self->om); 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; break;
case WP_TRANSITION_STEP_ERROR: case WP_TRANSITION_STEP_ERROR:
g_clear_object (&self->om); 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; break;
default: default:

View File

@@ -25,7 +25,6 @@ struct _WpCtl
GOptionContext *context; GOptionContext *context;
GMainLoop *loop; GMainLoop *loop;
WpCore *core; WpCore *core;
GPtrArray *apis;
WpObjectManager *om; WpObjectManager *om;
guint pending_plugins; guint pending_plugins;
gint exit_code; gint exit_code;
@@ -75,7 +74,6 @@ G_DEFINE_QUARK (wpctl-error, wpctl_error_domain)
static void static void
wp_ctl_clear (WpCtl * self) wp_ctl_clear (WpCtl * self)
{ {
g_clear_pointer (&self->apis, g_ptr_array_unref);
g_clear_object (&self->om); g_clear_object (&self->om);
g_clear_object (&self->core); g_clear_object (&self->core);
g_clear_pointer (&self->loop, g_main_loop_unref); g_clear_pointer (&self->loop, g_main_loop_unref);
@@ -1305,17 +1303,25 @@ static const struct subcommand {
}; };
static void 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)) { o = wp_core_load_component_finish (core, res, &error);
fprintf (stderr, "%s", error->message); if (!o) {
fprintf (stderr, "%s\n", error->message);
ctl->exit_code = 1; ctl->exit_code = 1;
g_main_loop_quit (ctl->loop); g_main_loop_quit (ctl->loop);
return; 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) if (--ctl->pending_plugins == 0)
wp_core_install_object_manager (ctl->core, ctl->om); wp_core_install_object_manager (ctl->core, ctl->om);
} }
@@ -1336,7 +1342,6 @@ main (gint argc, gchar **argv)
"COMMAND [COMMAND_OPTIONS] - WirePlumber Control CLI"); "COMMAND [COMMAND_OPTIONS] - WirePlumber Control CLI");
ctl.loop = g_main_loop_new (NULL, FALSE); ctl.loop = g_main_loop_new (NULL, FALSE);
ctl.core = wp_core_new (NULL, NULL); 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 (); ctl.om = wp_object_manager_new ();
/* find the subcommand */ /* find the subcommand */
@@ -1403,22 +1408,12 @@ main (gint argc, gchar **argv)
} }
/* load required API modules */ /* load required API modules */
if (!wp_core_load_component (ctl.core, ctl.pending_plugins++;
"libwireplumber-module-default-nodes-api", "module", NULL, &error)) { wp_core_load_component (ctl.core, "libwireplumber-module-default-nodes-api",
fprintf (stderr, "%s\n", error->message); "module", NULL, (GAsyncReadyCallback) on_plugin_loaded, &ctl);
return 1; ctl.pending_plugins++;
} wp_core_load_component (ctl.core, "libwireplumber-module-mixer-api",
if (!wp_core_load_component (ctl.core, "module", NULL, (GAsyncReadyCallback) on_plugin_loaded, &ctl);
"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;
}));
/* connect */ /* connect */
if (!wp_core_connect (ctl.core)) { if (!wp_core_connect (ctl.core)) {
@@ -1432,13 +1427,6 @@ main (gint argc, gchar **argv)
g_signal_connect_swapped (ctl.om, "installed", g_signal_connect_swapped (ctl.om, "installed",
(GCallback) cmd->run, &ctl); (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); g_main_loop_run (ctl.loop);
wp_ctl_clear (&ctl); wp_ctl_clear (&ctl);

View File

@@ -103,10 +103,13 @@ wp_init_transition_get_next_step (WpTransition * transition, guint step)
} }
static void 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; 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); wp_transition_return_error (WP_TRANSITION (self), error);
return; return;
} }
@@ -119,7 +122,6 @@ wp_init_transition_execute_step (WpTransition * transition, guint step)
{ {
WpInitTransition *self = WP_INIT_TRANSITION (transition); WpInitTransition *self = WP_INIT_TRANSITION (transition);
WpCore *core = wp_transition_get_source_object (transition); WpCore *core = wp_transition_get_source_object (transition);
GError *error = NULL;
switch (step) { switch (step) {
case STEP_CONNECT: case STEP_CONNECT:
@@ -134,42 +136,17 @@ wp_init_transition_execute_step (WpTransition * transition, guint step)
break; break;
case STEP_ACTIVATE_PLUGINS: { case STEP_ACTIVATE_PLUGINS: {
if (!wp_core_load_component (core, "libwireplumber-module-lua-scripting", wp_core_load_component (core, "libwireplumber-module-lua-scripting",
"module", NULL, &error)) { "module", NULL, (GAsyncReadyCallback) on_plugin_loaded, self);
wp_transition_return_error (transition, error); wp_core_load_component (core, "libwireplumber-module-standard-event-source",
return; "module", NULL, (GAsyncReadyCallback) on_plugin_loaded, self);
}
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);
break; break;
} }
case STEP_ACTIVATE_SCRIPT: { case STEP_ACTIVATE_SCRIPT: {
GVariant *args = g_variant_builder_end (&exec_args_b); GVariant *args = g_variant_builder_end (&exec_args_b);
if (!wp_core_load_component (core, exec_script, "script/lua", args, wp_core_load_component (core, exec_script, "script/lua", args,
&error)) { (GAsyncReadyCallback) on_plugin_loaded, self);
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);
break; break;
} }

View File

@@ -19,15 +19,28 @@ typedef struct {
gchar *evtype; gchar *evtype;
} TestFixture; } 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 static void
test_file_monitor_setup (TestFixture * f, gconstpointer user_data) 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);
g_autoptr (GError) error = NULL;
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-file-monitor-api", "module", NULL, &error); "libwireplumber-module-file-monitor-api", "module", NULL,
g_assert_no_error (error); (GAsyncReadyCallback) on_plugin_loaded, f);
g_main_loop_run (f->base.loop);
f->plugin = wp_plugin_find (f->base.core, "file-monitor-api"); f->plugin = wp_plugin_find (f->base.core, "file-monitor-api");
g_assert_nonnull (f->plugin); 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); 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 static void
on_changed (WpPlugin *plugin, const gchar *file, const gchar *old, on_changed (WpPlugin *plugin, const gchar *file, const gchar *old,
const char *evtype, TestFixture * f) const char *evtype, TestFixture * f)
@@ -72,11 +75,6 @@ test_file_monitor_basic (TestFixture * f, gconstpointer user_data)
{ {
gboolean res = FALSE; 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 */ /* delete the 'foo' file if it exists in path */
g_autofree gchar *filename = g_build_filename (f->path, "foo", NULL); g_autofree gchar *filename = g_build_filename (f->path, "foo", NULL);
(void) remove (filename); (void) remove (filename);

View File

@@ -21,6 +21,19 @@ typedef struct {
gint expected_rd2_state; gint expected_rd2_state;
} RdTestFixture; } 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 static void
test_rd_setup (RdTestFixture *f, gconstpointer data) 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_test_dbus_up (f->test_dbus);
{ {
g_autoptr (GError) error = NULL;
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-reserve-device", "module", NULL, &error); "libwireplumber-module-reserve-device", "module", NULL,
g_assert_no_error (error); (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, wp_core_load_component (f->base.client_core,
"libwireplumber-module-reserve-device", "module", NULL, &error); "libwireplumber-module-reserve-device", "module", NULL,
g_assert_no_error (error); (GAsyncReadyCallback) on_plugin_loaded, f);
g_main_loop_run (f->base.loop);
} }
f->rd_plugin_1 = wp_plugin_find (f->base.core, "reserve-device"); 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); 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 static void
ensure_plugins_stable_state (GObject * obj, GParamSpec * spec, RdTestFixture *f) ensure_plugins_stable_state (GObject * obj, GParamSpec * spec, RdTestFixture *f)
{ {
@@ -92,24 +95,13 @@ static void
test_rd_plugin (RdTestFixture *f, gconstpointer data) test_rd_plugin (RdTestFixture *f, gconstpointer data)
{ {
GObject *rd1 = NULL, *rd2 = NULL, *rd_video = NULL, *tmp = NULL; GObject *rd1 = NULL, *rd2 = NULL, *rd_video = NULL, *tmp = NULL;
gint state = 0xffff; gint state = 0;
gchar *str; 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_signal_connect (f->dbus_1, "notify::state",
G_CALLBACK (ensure_plugins_stable_state), f); G_CALLBACK (ensure_plugins_stable_state), f);
g_signal_connect (f->dbus_2, "notify::state", g_signal_connect (f->dbus_2, "notify::state",
G_CALLBACK (ensure_plugins_stable_state), f); G_CALLBACK (ensure_plugins_stable_state), f);
g_main_loop_run (f->base.loop);
g_object_get (f->dbus_1, "state", &state, NULL); g_object_get (f->dbus_1, "state", &state, NULL);
g_assert_cmpint (state, ==, 2); g_assert_cmpint (state, ==, 2);
@@ -183,23 +175,12 @@ static void
test_rd_conn_closed (RdTestFixture *f, gconstpointer data) test_rd_conn_closed (RdTestFixture *f, gconstpointer data)
{ {
GObject *rd1 = NULL; GObject *rd1 = NULL;
gint state = 0xffff; gint state = 0;
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_signal_connect (f->dbus_1, "notify::state",
G_CALLBACK (ensure_plugins_stable_state), f); G_CALLBACK (ensure_plugins_stable_state), f);
g_signal_connect (f->dbus_2, "notify::state", g_signal_connect (f->dbus_2, "notify::state",
G_CALLBACK (ensure_plugins_stable_state), f); G_CALLBACK (ensure_plugins_stable_state), f);
g_main_loop_run (f->base.loop);
g_object_get (f->dbus_1, "state", &state, NULL); g_object_get (f->dbus_1, "state", &state, NULL);
g_assert_cmpint (state, ==, 2); g_assert_cmpint (state, ==, 2);
@@ -260,24 +241,13 @@ static void
test_rd_acquire_release (RdTestFixture *f, gconstpointer data) test_rd_acquire_release (RdTestFixture *f, gconstpointer data)
{ {
GObject *rd1 = NULL, *rd2 = NULL; GObject *rd1 = NULL, *rd2 = NULL;
gint state = 0xffff; gint state = 0;
gchar *str = NULL; 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_signal_connect (f->dbus_1, "notify::state",
G_CALLBACK (ensure_plugins_stable_state), f); G_CALLBACK (ensure_plugins_stable_state), f);
g_signal_connect (f->dbus_2, "notify::state", g_signal_connect (f->dbus_2, "notify::state",
G_CALLBACK (ensure_plugins_stable_state), f); G_CALLBACK (ensure_plugins_stable_state), f);
g_main_loop_run (f->base.loop);
g_object_get (f->dbus_1, "state", &state, NULL); g_object_get (f->dbus_1, "state", &state, NULL);
g_assert_cmpint (state, ==, 2); g_assert_cmpint (state, ==, 2);

View File

@@ -12,6 +12,17 @@ typedef struct {
WpBaseTestFixture base; WpBaseTestFixture base;
} TestFixture; } 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 static void
test_si_audio_adapter_setup (TestFixture * f, gconstpointer user_data) 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)); "libpipewire-module-adapter", NULL, NULL));
} }
{ {
g_autoptr (GError) error = NULL;
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-si-audio-adapter", "module", NULL, &error); "libwireplumber-module-si-audio-adapter", "module", NULL,
g_assert_no_error (error); (GAsyncReadyCallback) on_plugin_loaded, f);
} }
} }

View File

@@ -12,6 +12,17 @@ typedef struct {
WpBaseTestFixture base; WpBaseTestFixture base;
} TestFixture; } 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 static void
test_si_audio_virtual_setup (TestFixture * f, gconstpointer user_data) 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)); "libpipewire-module-adapter", NULL, NULL));
} }
{ {
g_autoptr (GError) error = NULL;
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-si-audio-adapter", "module", NULL, &error); "libwireplumber-module-si-audio-adapter", "module", NULL,
g_assert_no_error (error); (GAsyncReadyCallback) on_plugin_loaded, f);
} }
{ {
g_autoptr (GError) error = NULL;
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-si-audio-virtual", "module", NULL, &error); "libwireplumber-module-si-audio-virtual", "module", NULL,
g_assert_no_error (error); (GAsyncReadyCallback) on_plugin_loaded, f);
} }
} }

View File

@@ -20,6 +20,17 @@ typedef struct {
WpDirection expected_direction; WpDirection expected_direction;
} TestData; } 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 static void
test_si_node_setup (TestFixture * f, gconstpointer user_data) 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)); "libpipewire-module-spa-node-factory", NULL, NULL));
} }
{ {
g_autoptr (GError) error = NULL;
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-si-node", "module", NULL, &error); "libwireplumber-module-si-node", "module", NULL,
g_assert_no_error (error); (GAsyncReadyCallback) on_plugin_loaded, f);
} }
} }

View File

@@ -65,6 +65,17 @@ load_node (TestFixture * f, const gchar * factory, const gchar * media_class,
return g_steal_pointer (&adapter); 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 static void
test_si_standard_link_setup (TestFixture * f, gconstpointer user_data) 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)); "libpipewire-module-link-factory", NULL, NULL));
} }
{ {
g_autoptr (GError) error = NULL;
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-si-audio-adapter", "module", NULL, &error); "libwireplumber-module-si-audio-adapter", "module", NULL,
g_assert_no_error (error); (GAsyncReadyCallback) on_plugin_loaded, f);
wp_core_load_component (f->base.core, wp_core_load_component (f->base.core,
"libwireplumber-module-si-standard-link", "module", NULL, &error); "libwireplumber-module-si-standard-link", "module", NULL,
g_assert_no_error (error); (GAsyncReadyCallback) on_plugin_loaded, f);
} }
if (test_is_spa_lib_installed (&f->base, "audiotestsrc")) if (test_is_spa_lib_installed (&f->base, "audiotestsrc"))

View File

@@ -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 static void
load_component (ScriptRunnerFixture *f, const gchar *name, const gchar *type) 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); plugin_name = g_strdup (name);
} }
wp_core_load_component (f->base.core, component_name, type, NULL, &error); wp_core_load_component (f->base.core, component_name, type, NULL,
g_assert_no_error (error); (GAsyncReadyCallback) on_plugin_loaded, f);
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);
if (!g_str_has_prefix (name, "si"))
g_main_loop_run (f->base.loop); g_main_loop_run (f->base.loop);
}
} }
static void static void