wireplumber/modules/module-collection-manager.c
Julian Bouzas 9ac80c53d9 modules: Add new collection-manager module
This module is in charge of creating all the collection metadatas.
2026-03-20 11:10:17 -04:00

217 lines
6.8 KiB
C

/* WirePlumber
*
* Copyright © 2025 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <wp/wp.h>
#include <spa/utils/defs.h>
WP_DEFINE_LOCAL_LOG_TOPIC ("m-collection-manager")
/*
* This module creates the "sm-collection-manager" metadata and also each
* individual collection metadata.
*/
struct _WpCollectionManagerPlugin
{
WpPlugin parent;
/* Props */
gchar *metadata_name;
WpImplMetadata *impl_metadata;
GHashTable *collection_metadatas;
};
enum {
PROP_0,
PROP_METADATA_NAME,
};
G_DECLARE_FINAL_TYPE (WpCollectionManagerPlugin, wp_collection_manager_plugin,
WP, COLLECTION_MANAGER_PLUGIN, WpPlugin)
G_DEFINE_TYPE (WpCollectionManagerPlugin, wp_collection_manager_plugin,
WP_TYPE_PLUGIN)
static void
wp_collection_manager_plugin_init (WpCollectionManagerPlugin * self)
{
}
static void
on_collection_metadata_activated (GObject * o, GAsyncResult * res, gpointer d)
{
WpCollectionManagerPlugin *self = WP_COLLECTION_MANAGER_PLUGIN (d);
g_autoptr (WpImplMetadata) m = WP_IMPL_METADATA (o);
g_autoptr (WpProperties) props = NULL;
const gchar *name = NULL;
g_autoptr (GError) error = NULL;
/* Get the metadata name */
props = wp_global_proxy_get_global_properties (WP_GLOBAL_PROXY (m));
g_return_if_fail (props);
name = wp_properties_get (props, "metadata.name");
g_return_if_fail (name);
/* make sure activation was successful */
if (!wp_object_activate_finish (WP_OBJECT (m), res, &error)) {
wp_warning_object (self, "Failed to activate collection metadata: %s",
name);
return;
}
/* Add the metadata */
g_hash_table_insert (self->collection_metadatas, g_strdup (name),
g_object_ref (m));
wp_info_object (self, "Added collection metadata: %s", name);
}
static void
on_metadata_changed (WpMetadata *m, guint32 subject, const gchar *key,
const gchar *type, const gchar *value, gpointer d)
{
WpCollectionManagerPlugin *self = WP_COLLECTION_MANAGER_PLUGIN (d);
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
if (key) {
WpImplMetadata *collection_m = g_hash_table_lookup (
self->collection_metadatas, key);
if (collection_m && !value) {
/* Remove collection metadata */
g_hash_table_remove (self->collection_metadatas, key);
wp_info_object (self, "Removed collection metadata: %s", key);
} else if (!collection_m && value) {
/* Create new collection metadata */
wp_info_object (self, "Creating collection metadata: %s", key);
WpImplMetadata *new_collection_m = wp_impl_metadata_new_full (core, key,
wp_properties_new ("wireplumber.collection", "true", NULL));
wp_object_activate (WP_OBJECT (new_collection_m), WP_OBJECT_FEATURES_ALL,
NULL, on_collection_metadata_activated, self);
}
} else {
/* Remove all collection metadatas */
g_hash_table_remove_all (self->collection_metadatas);
wp_info_object (self, "Removed all collection metadatas");
}
}
static void
on_metadata_activated (WpMetadata * m, GAsyncResult * res,
gpointer user_data)
{
WpTransition *trans = WP_TRANSITION (user_data);
WpCollectionManagerPlugin *self = wp_transition_get_source_object (trans);
g_autoptr (GError) error = NULL;
if (!wp_object_activate_finish (WP_OBJECT (m), res, &error)) {
wp_transition_return_error (trans, g_error_new (WP_DOMAIN_LIBRARY,
WP_LIBRARY_ERROR_OPERATION_FAILED,
"Failed to activate metadata object %s", self->metadata_name));
return;
}
/* monitor changes in metadata */
g_signal_connect_object (m, "changed", G_CALLBACK (on_metadata_changed), self,
0);
wp_object_update_features (WP_OBJECT (self), WP_PLUGIN_FEATURE_ENABLED, 0);
}
static void
wp_collection_manager_plugin_enable (WpPlugin * plugin,
WpTransition * transition)
{
WpCollectionManagerPlugin * self = WP_COLLECTION_MANAGER_PLUGIN (plugin);
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (plugin));
/* Create the collection metadatas table */
self->collection_metadatas = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
/* Create the collection manager metadata */
self->impl_metadata = wp_impl_metadata_new_full (core, self->metadata_name,
wp_properties_new ("wireplumber.collection-manager", "true", NULL));
wp_object_activate (WP_OBJECT (self->impl_metadata), WP_OBJECT_FEATURES_ALL,
NULL,
(GAsyncReadyCallback)on_metadata_activated, transition);
}
static void
wp_collection_manager_plugin_disable (WpPlugin * plugin)
{
WpCollectionManagerPlugin * self = WP_COLLECTION_MANAGER_PLUGIN (plugin);
g_clear_object (&self->impl_metadata);
g_clear_pointer (&self->collection_metadatas, g_hash_table_unref);
g_clear_pointer (&self->metadata_name, g_free);
}
static void
wp_collection_manager_plugin_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
{
WpCollectionManagerPlugin *self = WP_COLLECTION_MANAGER_PLUGIN (object);
switch (property_id) {
case PROP_METADATA_NAME:
g_clear_pointer (&self->metadata_name, g_free);
self->metadata_name = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
wp_collection_manager_plugin_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
WpCollectionManagerPlugin *self = WP_COLLECTION_MANAGER_PLUGIN (object);
switch (property_id) {
case PROP_METADATA_NAME:
g_value_set_string (value, self->metadata_name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
wp_collection_manager_plugin_class_init (WpCollectionManagerPluginClass * klass)
{
WpPluginClass *plugin_class = (WpPluginClass *) klass;
GObjectClass *object_class = (GObjectClass *) klass;
plugin_class->enable = wp_collection_manager_plugin_enable;
plugin_class->disable = wp_collection_manager_plugin_disable;
object_class->set_property = wp_collection_manager_plugin_set_property;
object_class->get_property = wp_collection_manager_plugin_get_property;
g_object_class_install_property (object_class, PROP_METADATA_NAME,
g_param_spec_string ("metadata-name", "metadata-name",
"The metadata object to look after", NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}
WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, WpSpaJson * args, GError ** error)
{
g_autofree gchar *metadata_name = NULL;
if (args)
wp_spa_json_object_get (args, "metadata.name", "s", &metadata_name, NULL);
return G_OBJECT (g_object_new (wp_collection_manager_plugin_get_type (),
"name", "collection-manager",
"core", core,
"metadata-name", metadata_name ? metadata_name : "sm-collection-manager",
NULL));
}