Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/* WirePlumber
*
* Copyright © 2019 Collabora Ltd.
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "module.h"
#include "error.h"
#include <gmodule.h>
#define WP_MODULE_INIT_SYMBOL "wireplumber__module_init"
typedef void (*WpModuleInitFunc) (WpModule *, WpCore *, GVariant *);
struct _WpModule
{
GObject parent;
GVariant *properties;
GDestroyNotify destroy;
gpointer destroy_data;
};
G_DEFINE_TYPE (WpModule, wp_module, G_TYPE_OBJECT)
static void
wp_module_init (WpModule * self)
{
}
static void
wp_module_finalize (GObject * object)
{
WpModule *self = WP_MODULE (object);
if (self->destroy)
self->destroy (self->destroy_data);
g_clear_pointer (&self->properties, g_variant_unref);
G_OBJECT_CLASS (wp_module_parent_class)->finalize (object);
}
static void
wp_module_class_init (WpModuleClass * klass)
{
GObjectClass * object_class = (GObjectClass *) klass;
object_class->finalize = wp_module_finalize;
}
static const gchar *
get_module_dir (void)
{
const gchar *module_dir = NULL;
if (!module_dir)
module_dir = g_getenv ("WIREPLUMBER_MODULE_DIR");
return module_dir;
}
static gboolean
wp_module_load_c (WpModule * self, WpCore * core,
const gchar * module_name, GVariant * args, GError ** error)
{
g_autofree gchar *module_path = NULL;
GModule *gmodule;
gpointer module_init;
GVariantDict properties;
module_path = g_module_build_path (get_module_dir (), module_name);
gmodule = g_module_open (module_path, G_MODULE_BIND_LOCAL);
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;
}
if (!g_module_symbol (gmodule, WP_MODULE_INIT_SYMBOL, &module_init)) {
g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED,
"Failed to locate symbol " WP_MODULE_INIT_SYMBOL " in %s",
module_path);
g_module_close (gmodule);
return FALSE;
}
g_variant_dict_init (&properties, NULL);
g_variant_dict_insert (&properties, "module.name", "s", module_name);
g_variant_dict_insert (&properties, "module.abi", "s", "C");
g_variant_dict_insert (&properties, "module.path", "s", module_path);
if (args) {
g_variant_take_ref (args);
g_variant_dict_insert_value (&properties, "module.args", args);
}
self->properties = g_variant_ref_sink (g_variant_dict_end (&properties));
((WpModuleInitFunc) module_init) (self, core, args);
if (args)
g_variant_unref (args);
return TRUE;
}
WpModule *
wp_module_load (WpCore * core, const gchar * abi,
const gchar * module_name, GVariant * args, GError ** error)
{
g_autoptr (WpModule) module = NULL;
if (!g_strcmp0 (abi, "C")) {
module = g_object_new (WP_TYPE_MODULE, NULL);
if (!wp_module_load_c (module, core, module_name, args, error))
return NULL;
} else {
g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVALID_ARGUMENT,
"unknown module ABI %s", abi);
return NULL;
}
wp_core_register_global (core, g_quark_from_string (module_name),
g_object_ref (module), g_object_unref);
return module;
}
GVariant *
wp_module_get_properties (WpModule * self)
{
return self->properties;
}
void
wp_module_set_destroy_callback (WpModule * self, GDestroyNotify callback,
gpointer data)
{
g_return_if_fail (self->destroy == NULL);
self->destroy = callback;
self->destroy_data = data;
}