mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2026-05-07 04:09:02 +02:00
modules: Add new collection-manager module
This module is in charge of creating all the collection metadatas.
This commit is contained in:
parent
6efc077a5a
commit
511d85177d
4 changed files with 264 additions and 0 deletions
|
|
@ -780,6 +780,20 @@ load_settings_instance (GTask * task, WpCore * core, WpSpaJson * args)
|
|||
g_task_return_pointer (task, settings, g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
load_collection_manager_instance (GTask * task, WpCore * core, WpSpaJson * args)
|
||||
{
|
||||
g_autofree gchar *metadata_name = NULL;
|
||||
if (args)
|
||||
wp_spa_json_object_get (args, "metadata.name", "s", &metadata_name, NULL);
|
||||
|
||||
wp_info_object (core, "loading collection manager instance '%s'...",
|
||||
metadata_name ? metadata_name : "(default: sm-collection-manager)");
|
||||
|
||||
WpCollectionManager *cm = wp_collection_manager_new (core, metadata_name);
|
||||
g_task_return_pointer (task, cm, g_object_unref);
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const gchar * name;
|
||||
void (*load) (GTask *, WpCore *, WpSpaJson *);
|
||||
|
|
@ -787,6 +801,7 @@ static const struct {
|
|||
{ "ensure-no-media-session", ensure_no_media_session },
|
||||
{ "export-core", load_export_core },
|
||||
{ "settings-instance", load_settings_instance },
|
||||
{ "collection-manager-instance", load_collection_manager_instance },
|
||||
};
|
||||
|
||||
/*** WpInternalCompLoader ***/
|
||||
|
|
|
|||
|
|
@ -191,3 +191,13 @@ shared_library(
|
|||
install_dir : wireplumber_module_dir,
|
||||
dependencies : [wp_dep],
|
||||
)
|
||||
|
||||
shared_library(
|
||||
'wireplumber-module-collection-manager',
|
||||
[
|
||||
'module-collection-manager.c',
|
||||
],
|
||||
install : true,
|
||||
install_dir : wireplumber_module_dir,
|
||||
dependencies : [wp_dep, pipewire_dep],
|
||||
)
|
||||
|
|
|
|||
217
modules/module-collection-manager.c
Normal file
217
modules/module-collection-manager.c
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
/* 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));
|
||||
}
|
||||
|
|
@ -68,6 +68,7 @@ wireplumber.profiles = {
|
|||
inherits = [ base ]
|
||||
|
||||
metadata.sm-settings = required
|
||||
metadata.sm-collection-manager = required
|
||||
metadata.sm-objects = required
|
||||
|
||||
policy.standard = required
|
||||
|
|
@ -101,6 +102,7 @@ wireplumber.profiles = {
|
|||
policy = {
|
||||
inherits = [ base ]
|
||||
metadata.sm-settings = required
|
||||
metadata.sm-collection-manager = required
|
||||
metadata.sm-objects = required
|
||||
policy.standard = required
|
||||
}
|
||||
|
|
@ -128,6 +130,7 @@ wireplumber.profiles = {
|
|||
base = {
|
||||
check.no-media-session = required
|
||||
support.settings = required
|
||||
support.collection-manager = required
|
||||
support.log-settings = required
|
||||
support.session-services = required
|
||||
}
|
||||
|
|
@ -233,6 +236,13 @@ wireplumber.components = [
|
|||
provides = metadata.sm-settings
|
||||
}
|
||||
|
||||
## Provides the "sm-collection-manager" metadata object
|
||||
{
|
||||
name = libwireplumber-module-collection-manager, type = module
|
||||
arguments = { metadata.name = sm-collection-manager }
|
||||
provides = metadata.sm-collection-manager
|
||||
}
|
||||
|
||||
## Activates a global WpSettings instance, providing settings from
|
||||
## the sm-settings metadata object. Note that this blocks and waits for the
|
||||
## sm-settings metadata object to become available, so one instance must
|
||||
|
|
@ -244,6 +254,18 @@ wireplumber.components = [
|
|||
after = [ metadata.sm-settings ]
|
||||
}
|
||||
|
||||
## Activates a global WpCollectionManager instance, allowing creating
|
||||
## collections for global objects. Note that this blocks and waits for the
|
||||
## sm-collection-manager metadata object to become available, so one instance
|
||||
## must provide that, while others should only load this to access the
|
||||
## collection manager.
|
||||
{
|
||||
name = collection-manager-instance, type = built-in
|
||||
arguments = { metadata.name = sm-collection-manager }
|
||||
provides = support.collection-manager
|
||||
after = [ metadata.sm-collection-manager ]
|
||||
}
|
||||
|
||||
## Log level settings
|
||||
{
|
||||
name = libwireplumber-module-log-settings, type = module
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue