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:
@@ -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,
|
||||
/* 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 FALSE;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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 */
|
||||
|
||||
|
@@ -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 (),
|
||||
return G_OBJECT (g_object_new (wp_default_nodes_api_get_type (),
|
||||
"name", "default-nodes-api",
|
||||
"core", core,
|
||||
NULL));
|
||||
return TRUE;
|
||||
}
|
||||
|
@@ -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 (),
|
||||
return G_OBJECT (g_object_new (wp_file_monitor_api_get_type (),
|
||||
"name", "file-monitor-api",
|
||||
"core", core,
|
||||
NULL));
|
||||
return TRUE;
|
||||
}
|
||||
|
@@ -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 (),
|
||||
return G_OBJECT (g_object_new (wp_logind_get_type (),
|
||||
"name", NAME,
|
||||
"core", core,
|
||||
NULL));
|
||||
return TRUE;
|
||||
}
|
||||
|
@@ -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,46 +79,21 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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_core_load_component (core, module_name, "module", NULL,
|
||||
(GAsyncReadyCallback) on_plugin_loaded, self);
|
||||
}
|
||||
}
|
||||
wp_transition_advance (transition);
|
||||
break;
|
||||
|
@@ -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;
|
||||
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 {
|
||||
/* find the script */
|
||||
filepath = find_script (component, core);
|
||||
pluginname = g_strdup_printf ("script:%s", component);
|
||||
if (!filepath) {
|
||||
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
||||
"Could not locate script '%s'", component);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!filepath) {
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
||||
"Could not locate script '%s'", component);
|
||||
return FALSE;
|
||||
}
|
||||
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 (),
|
||||
return G_OBJECT (g_object_new (wp_lua_scripting_plugin_get_type (),
|
||||
"name", "lua-scripting",
|
||||
"core", core,
|
||||
NULL));
|
||||
return TRUE;
|
||||
}
|
||||
|
@@ -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,
|
||||
|
@@ -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 (),
|
||||
return G_OBJECT (g_object_new (wp_mixer_api_get_type (),
|
||||
"name", "mixer-api",
|
||||
"core", core,
|
||||
NULL));
|
||||
return TRUE;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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 (),
|
||||
return G_OBJECT (g_object_new (wp_standard_event_source_get_type (),
|
||||
"name", "standard-event-source",
|
||||
"core", core,
|
||||
NULL));
|
||||
return TRUE;
|
||||
}
|
||||
|
530
src/main.c
530
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;
|
||||
};
|
||||
|
||||
static gint
|
||||
component_cmp_func (const component_data *a, const component_data *b)
|
||||
{
|
||||
return b->priority - a->priority;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
if (g_str_has_prefix (name, "libwireplumber-module-"))
|
||||
return g_strdup (name + strlen ("libwireplumber-module-"));
|
||||
else
|
||||
return g_strdup_printf ("script:%s", name);
|
||||
}
|
||||
|
||||
static void
|
||||
on_plugin_activated (WpObject *p, GAsyncResult *res, WpInitTransition *self);
|
||||
|
||||
static int
|
||||
load_enable_component (WpInitTransition *self, GError **error)
|
||||
{
|
||||
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;
|
||||
|
||||
if (comp->deps) {
|
||||
g_autoptr (WpConf) conf = wp_conf_get_instance (core);
|
||||
g_autoptr (WpIterator) it = wp_spa_json_new_iterator (comp->deps);
|
||||
g_autoptr (WpConf) conf = NULL;
|
||||
g_autoptr (WpIterator) it = NULL;
|
||||
g_auto (GValue) item = G_VALUE_INIT;
|
||||
gboolean deps_met = TRUE;
|
||||
|
||||
if (!comp->deps)
|
||||
return TRUE;
|
||||
|
||||
/* Note that we consider the dependency valid by default if it is not
|
||||
* found in the settings */
|
||||
* 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) {
|
||||
deps_met = FALSE;
|
||||
wp_info (".. deps(%s) not met for component(%s), skip loading it",
|
||||
dep_str, comp->name);
|
||||
break;
|
||||
if (!value)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (!deps_met) {
|
||||
comps = g_list_delete_link (comps, g_steal_pointer (&lcomp));
|
||||
self->components = comps;
|
||||
lcomp = g_list_first (comps);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
load_enable_components (WpInitTransition *self)
|
||||
{
|
||||
WpCore *core = wp_transition_get_source_object (WP_TRANSITION (self));
|
||||
|
||||
while (self->components) {
|
||||
self->curr_component = (ComponentData *) self->components->data;
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
/* Advance */
|
||||
self->components = g_list_next (self->components);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
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++;
|
||||
}
|
||||
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),
|
||||
/* 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_warning (".. dangling component(%s) already present, ignore this one",
|
||||
} else {
|
||||
wp_debug ("ignoring component '%s' as it is already defined previously",
|
||||
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;
|
||||
component_data_free (comp);
|
||||
}
|
||||
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:
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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"))
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user