m-config-static-objects: add device parser to create static devices
This commit is contained in:
@@ -82,6 +82,7 @@ shared_library(
|
|||||||
shared_library(
|
shared_library(
|
||||||
'wireplumber-module-config-static-objects',
|
'wireplumber-module-config-static-objects',
|
||||||
[
|
[
|
||||||
|
'module-config-static-objects/parser-device.c',
|
||||||
'module-config-static-objects/parser-node.c',
|
'module-config-static-objects/parser-node.c',
|
||||||
'module-config-static-objects/context.c',
|
'module-config-static-objects/context.c',
|
||||||
'module-config-static-objects.c',
|
'module-config-static-objects.c',
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <wp/wp.h>
|
#include <wp/wp.h>
|
||||||
|
|
||||||
|
#include "parser-device.h"
|
||||||
#include "parser-node.h"
|
#include "parser-node.h"
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
|
|
||||||
@@ -98,6 +99,30 @@ on_device_added (WpObjectManager *om, WpProxy *proxy, gpointer p)
|
|||||||
wp_config_static_objects_context_create_node (self, node_data);
|
wp_config_static_objects_context_create_node (self, node_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
parser_device_foreach_func (const struct WpParserDeviceData *device_data,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
WpConfigStaticObjectsContext *self = data;
|
||||||
|
g_autoptr (WpCore) core = wp_plugin_get_core (WP_PLUGIN (self));
|
||||||
|
g_autoptr (WpDevice) device = NULL;
|
||||||
|
g_return_val_if_fail (core, FALSE);
|
||||||
|
|
||||||
|
/* Create the device */
|
||||||
|
device = wp_device_new_from_factory (core, device_data->factory,
|
||||||
|
device_data->props ? wp_properties_ref (device_data->props) : NULL);
|
||||||
|
if (!device) {
|
||||||
|
wp_warning_object (self, "failed to create device");
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* export */
|
||||||
|
wp_proxy_augment (WP_PROXY (device), WP_PROXY_FEATURES_STANDARD, NULL,
|
||||||
|
on_object_created, self);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
parser_node_foreach_func (const struct WpParserNodeData *node_data,
|
parser_node_foreach_func (const struct WpParserNodeData *node_data,
|
||||||
gpointer data)
|
gpointer data)
|
||||||
@@ -119,20 +144,43 @@ wp_config_static_objects_context_activate (WpPlugin * plugin)
|
|||||||
WpConfigStaticObjectsContext *self = WP_CONFIG_STATIC_OBJECTS_CONTEXT (plugin);
|
WpConfigStaticObjectsContext *self = WP_CONFIG_STATIC_OBJECTS_CONTEXT (plugin);
|
||||||
g_autoptr (WpCore) core = wp_plugin_get_core (plugin);
|
g_autoptr (WpCore) core = wp_plugin_get_core (plugin);
|
||||||
g_autoptr (WpConfiguration) config = wp_configuration_get_instance (core);
|
g_autoptr (WpConfiguration) config = wp_configuration_get_instance (core);
|
||||||
g_autoptr (WpConfigParser) parser = NULL;
|
|
||||||
|
self->static_objects = g_ptr_array_new_with_free_func (g_object_unref);
|
||||||
|
|
||||||
|
/* Create and install the device object manager */
|
||||||
|
self->devices_om = wp_object_manager_new ();
|
||||||
|
wp_object_manager_add_interest (self->devices_om, WP_TYPE_DEVICE, NULL);
|
||||||
|
wp_object_manager_request_proxy_features (self->devices_om, WP_TYPE_DEVICE,
|
||||||
|
WP_PROXY_FEATURE_INFO);
|
||||||
|
g_signal_connect (self->devices_om, "object-added",
|
||||||
|
(GCallback) on_device_added, self);
|
||||||
|
wp_core_install_object_manager (core, self->devices_om);
|
||||||
|
|
||||||
/* Add the node parser and parse the node files */
|
/* Add the node parser and parse the node files */
|
||||||
wp_configuration_add_extension (config, WP_PARSER_NODE_EXTENSION,
|
wp_configuration_add_extension (config, WP_PARSER_NODE_EXTENSION,
|
||||||
WP_TYPE_PARSER_NODE);
|
WP_TYPE_PARSER_NODE);
|
||||||
wp_configuration_reload (config, WP_PARSER_NODE_EXTENSION);
|
wp_configuration_reload (config, WP_PARSER_NODE_EXTENSION);
|
||||||
|
|
||||||
/* Install the object manager */
|
/* Add the device parser and parse the device files */
|
||||||
wp_core_install_object_manager (core, self->devices_om);
|
wp_configuration_add_extension (config, WP_PARSER_DEVICE_EXTENSION,
|
||||||
|
WP_TYPE_PARSER_DEVICE);
|
||||||
|
wp_configuration_reload (config, WP_PARSER_DEVICE_EXTENSION);
|
||||||
|
|
||||||
|
/* Create static devices */
|
||||||
|
{
|
||||||
|
g_autoptr (WpConfigParser) parser =
|
||||||
|
wp_configuration_get_parser (config, WP_PARSER_DEVICE_EXTENSION);
|
||||||
|
wp_parser_device_foreach (WP_PARSER_DEVICE (parser),
|
||||||
|
parser_device_foreach_func, self);
|
||||||
|
}
|
||||||
|
|
||||||
/* Create static nodes without match-device */
|
/* Create static nodes without match-device */
|
||||||
parser = wp_configuration_get_parser (config, WP_PARSER_NODE_EXTENSION);
|
{
|
||||||
wp_parser_node_foreach (WP_PARSER_NODE (parser), parser_node_foreach_func,
|
g_autoptr (WpConfigParser) parser =
|
||||||
self);
|
wp_configuration_get_parser (config, WP_PARSER_NODE_EXTENSION);
|
||||||
|
wp_parser_node_foreach (WP_PARSER_NODE (parser),
|
||||||
|
parser_node_foreach_func, self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -146,6 +194,7 @@ wp_config_static_objects_context_deactivate (WpPlugin *plugin)
|
|||||||
g_autoptr (WpCore) core = wp_plugin_get_core (plugin);
|
g_autoptr (WpCore) core = wp_plugin_get_core (plugin);
|
||||||
if (core) {
|
if (core) {
|
||||||
g_autoptr (WpConfiguration) config = wp_configuration_get_instance (core);
|
g_autoptr (WpConfiguration) config = wp_configuration_get_instance (core);
|
||||||
|
wp_configuration_remove_extension (config, WP_PARSER_DEVICE_EXTENSION);
|
||||||
wp_configuration_remove_extension (config, WP_PARSER_NODE_EXTENSION);
|
wp_configuration_remove_extension (config, WP_PARSER_NODE_EXTENSION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,15 +202,6 @@ wp_config_static_objects_context_deactivate (WpPlugin *plugin)
|
|||||||
static void
|
static void
|
||||||
wp_config_static_objects_context_init (WpConfigStaticObjectsContext *self)
|
wp_config_static_objects_context_init (WpConfigStaticObjectsContext *self)
|
||||||
{
|
{
|
||||||
self->static_objects = g_ptr_array_new_with_free_func (g_object_unref);
|
|
||||||
self->devices_om = wp_object_manager_new ();
|
|
||||||
|
|
||||||
/* Only handle devices */
|
|
||||||
wp_object_manager_add_interest (self->devices_om, WP_TYPE_DEVICE, NULL);
|
|
||||||
wp_object_manager_request_proxy_features (self->devices_om, WP_TYPE_DEVICE,
|
|
||||||
WP_PROXY_FEATURE_INFO);
|
|
||||||
g_signal_connect (self->devices_om, "object-added",
|
|
||||||
(GCallback) on_device_added, self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
222
modules/module-config-static-objects/parser-device.c
Normal file
222
modules/module-config-static-objects/parser-device.c
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
/* WirePlumber
|
||||||
|
*
|
||||||
|
* Copyright © 2019 Collabora Ltd.
|
||||||
|
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <wptoml/wptoml.h>
|
||||||
|
|
||||||
|
#include <pipewire/pipewire.h>
|
||||||
|
|
||||||
|
#include "parser-device.h"
|
||||||
|
|
||||||
|
struct _WpParserDevice
|
||||||
|
{
|
||||||
|
GObject parent;
|
||||||
|
|
||||||
|
GPtrArray *datas;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void wp_parser_device_config_parser_init (gpointer iface,
|
||||||
|
gpointer iface_data);
|
||||||
|
|
||||||
|
G_DEFINE_TYPE_WITH_CODE (WpParserDevice, wp_parser_device,
|
||||||
|
G_TYPE_OBJECT,
|
||||||
|
G_IMPLEMENT_INTERFACE (WP_TYPE_CONFIG_PARSER,
|
||||||
|
wp_parser_device_config_parser_init))
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_parser_device_data_destroy (gpointer p)
|
||||||
|
{
|
||||||
|
struct WpParserDeviceData *data = p;
|
||||||
|
|
||||||
|
/* Free the strings */
|
||||||
|
g_clear_pointer (&data->filename, g_free);
|
||||||
|
g_clear_pointer (&data->factory, g_free);
|
||||||
|
g_clear_pointer (&data->props, wp_properties_unref);
|
||||||
|
|
||||||
|
g_slice_free (struct WpParserDeviceData, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_properties_for_each (const WpTomlTable *table, gpointer user_data)
|
||||||
|
{
|
||||||
|
WpProperties *props = user_data;
|
||||||
|
g_return_if_fail (props);
|
||||||
|
|
||||||
|
/* Skip unparsed tables */
|
||||||
|
if (!table)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Parse the name and value */
|
||||||
|
g_autofree gchar *name = wp_toml_table_get_string (table, "name");
|
||||||
|
g_autofree gchar *value = wp_toml_table_get_string (table, "value");
|
||||||
|
|
||||||
|
/* Set the property */
|
||||||
|
if (name && value)
|
||||||
|
wp_properties_set (props, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static WpProperties *
|
||||||
|
parse_properties (WpTomlTable *table, const char *name)
|
||||||
|
{
|
||||||
|
WpProperties *props = wp_properties_new_empty ();
|
||||||
|
|
||||||
|
g_autoptr (WpTomlTableArray) properties = NULL;
|
||||||
|
properties = wp_toml_table_get_array_table (table, name);
|
||||||
|
if (properties)
|
||||||
|
wp_toml_table_array_for_each (properties, parse_properties_for_each, props);
|
||||||
|
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct WpParserDeviceData *
|
||||||
|
wp_parser_device_data_new (const gchar *location)
|
||||||
|
{
|
||||||
|
g_autoptr (WpTomlFile) file = NULL;
|
||||||
|
g_autoptr (WpTomlTable) table = NULL;
|
||||||
|
struct WpParserDeviceData *res = NULL;
|
||||||
|
|
||||||
|
/* File format:
|
||||||
|
* ------------
|
||||||
|
* factory (string)
|
||||||
|
* properties (WpProperties)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Get the TOML file */
|
||||||
|
file = wp_toml_file_new (location);
|
||||||
|
if (!file)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Get the file table */
|
||||||
|
table = wp_toml_file_get_table (file);
|
||||||
|
if (!table)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Create the endpoint data */
|
||||||
|
res = g_slice_new0 (struct WpParserDeviceData);
|
||||||
|
|
||||||
|
/* Set the file name */
|
||||||
|
res->filename = g_path_get_basename (location);
|
||||||
|
|
||||||
|
/* Get factory */
|
||||||
|
res->factory = wp_toml_table_get_string (table, "factory");
|
||||||
|
if (!res->factory)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Get properties */
|
||||||
|
res->props = parse_properties (table, "properties");
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
error:
|
||||||
|
g_clear_pointer (&res, wp_parser_device_data_destroy);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
compare_datas_func (gconstpointer a, gconstpointer b)
|
||||||
|
{
|
||||||
|
struct WpParserDeviceData *da = *(struct WpParserDeviceData *const *)a;
|
||||||
|
struct WpParserDeviceData *db = *(struct WpParserDeviceData *const *)b;
|
||||||
|
|
||||||
|
return g_strcmp0 (db->filename, da->filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
wp_parser_device_add_file (WpConfigParser *parser, const gchar *name)
|
||||||
|
{
|
||||||
|
WpParserDevice *self = WP_PARSER_DEVICE (parser);
|
||||||
|
struct WpParserDeviceData *data;
|
||||||
|
|
||||||
|
/* Parse the file */
|
||||||
|
data = wp_parser_device_data_new (name);
|
||||||
|
if (!data) {
|
||||||
|
wp_warning_object (parser, "failed to parse file '%s'", name);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the data to the array */
|
||||||
|
g_ptr_array_add (self->datas, data);
|
||||||
|
|
||||||
|
/* Sort the array by priority */
|
||||||
|
g_ptr_array_sort (self->datas, compare_datas_func);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gconstpointer
|
||||||
|
wp_parser_device_get_matched_data (WpConfigParser *parser, gpointer data)
|
||||||
|
{
|
||||||
|
WpParserDevice *self = WP_PARSER_DEVICE (parser);
|
||||||
|
WpProperties *props = data;
|
||||||
|
const struct WpParserDeviceData *d = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (props, NULL);
|
||||||
|
|
||||||
|
/* Find the first data that matches device properties */
|
||||||
|
for (guint i = 0; i < self->datas->len; i++) {
|
||||||
|
d = g_ptr_array_index (self->datas, i);
|
||||||
|
if (d->props && wp_properties_matches (props, d->props))
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_parser_device_reset (WpConfigParser *parser)
|
||||||
|
{
|
||||||
|
WpParserDevice *self = WP_PARSER_DEVICE (parser);
|
||||||
|
|
||||||
|
g_ptr_array_set_size (self->datas, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_parser_device_config_parser_init (gpointer iface, gpointer iface_data)
|
||||||
|
{
|
||||||
|
WpConfigParserInterface *cp_iface = iface;
|
||||||
|
|
||||||
|
cp_iface->add_file = wp_parser_device_add_file;
|
||||||
|
cp_iface->get_matched_data = wp_parser_device_get_matched_data;
|
||||||
|
cp_iface->reset = wp_parser_device_reset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_parser_device_finalize (GObject * object)
|
||||||
|
{
|
||||||
|
WpParserDevice *self = WP_PARSER_DEVICE (object);
|
||||||
|
|
||||||
|
g_clear_pointer (&self->datas, g_ptr_array_unref);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (wp_parser_device_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_parser_device_init (WpParserDevice * self)
|
||||||
|
{
|
||||||
|
self->datas = g_ptr_array_new_with_free_func (wp_parser_device_data_destroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_parser_device_class_init (WpParserDeviceClass * klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = (GObjectClass *) klass;
|
||||||
|
|
||||||
|
object_class->finalize = wp_parser_device_finalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wp_parser_device_foreach (WpParserDevice *self, WpParserDeviceForeachFunction f,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
const struct WpParserDeviceData *d;
|
||||||
|
|
||||||
|
for (guint i = 0; i < self->datas->len; i++) {
|
||||||
|
d = g_ptr_array_index(self->datas, i);
|
||||||
|
if (!f (d, data))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
34
modules/module-config-static-objects/parser-device.h
Normal file
34
modules/module-config-static-objects/parser-device.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/* WirePlumber
|
||||||
|
*
|
||||||
|
* Copyright © 2019 Collabora Ltd.
|
||||||
|
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __WIREPLUMBER_PARSER_DEVICE_H__
|
||||||
|
#define __WIREPLUMBER_PARSER_DEVICE_H__
|
||||||
|
|
||||||
|
#include <wp/wp.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define WP_PARSER_DEVICE_EXTENSION "device"
|
||||||
|
|
||||||
|
struct WpParserDeviceData {
|
||||||
|
char *filename;
|
||||||
|
char *factory;
|
||||||
|
WpProperties *props;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define WP_TYPE_PARSER_DEVICE (wp_parser_device_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (WpParserDevice, wp_parser_device, WP, PARSER_DEVICE, GObject)
|
||||||
|
|
||||||
|
typedef gboolean (*WpParserDeviceForeachFunction) (
|
||||||
|
const struct WpParserDeviceData *parser_data, gpointer data);
|
||||||
|
void wp_parser_device_foreach (WpParserDevice *self,
|
||||||
|
WpParserDeviceForeachFunction f, gpointer data);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
Reference in New Issue
Block a user