mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2026-05-09 03:58:05 +02:00
m-settings: add settings schema to metadata
This patch improves module-settings to load the settings schema into a 'schema-sm-settings' metadata for clients to know what values types and range are accepted for each particular setting. This settings schema is defined in the wireplumber.conf, under a new section called 'wireplumber.settings.schema'.
This commit is contained in:
parent
a23248847a
commit
a492d23019
3 changed files with 197 additions and 11 deletions
|
|
@ -12,6 +12,9 @@
|
|||
#include "object.h"
|
||||
#include "spa-json.h"
|
||||
|
||||
#define WP_SETTINGS_SCHEMA_METADATA_NAME_PREFIX "schema-"
|
||||
#define WP_SETTINGS_PERSISTENT_METADATA_NAME_PREFIX "persistent-"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -30,9 +30,11 @@ struct _WpSettingsPlugin
|
|||
|
||||
/* Props */
|
||||
gchar *metadata_name;
|
||||
gchar *persistent_metadata_name;
|
||||
gchar *metadata_schema_name;
|
||||
gchar *metadata_persistent_name;
|
||||
|
||||
WpImplMetadata *impl_metadata;
|
||||
WpImplMetadata *schema_impl_metadata;
|
||||
WpImplMetadata *persistent_impl_metadata;
|
||||
WpState *state;
|
||||
WpProperties *persistent_settings;
|
||||
|
|
@ -183,7 +185,7 @@ on_persistent_metadata_activated (WpMetadata * m, GAsyncResult * res,
|
|||
|
||||
if (!wp_object_activate_finish (WP_OBJECT (m), res, &error)) {
|
||||
g_prefix_error (&error, "Failed to activate \"%s\": "
|
||||
"Metadata object ", self->metadata_name);
|
||||
"Metadata object ", self->metadata_persistent_name);
|
||||
wp_transition_return_error (transition, g_steal_pointer (&error));
|
||||
return;
|
||||
}
|
||||
|
|
@ -201,7 +203,7 @@ on_persistent_metadata_activated (WpMetadata * m, GAsyncResult * res,
|
|||
const gchar *value = wp_properties_item_get_value (pi);
|
||||
|
||||
wp_debug_object (self, "adding persistent setting to %s metadata: %s = %s",
|
||||
self->persistent_metadata_name, key, value);
|
||||
self->metadata_persistent_name, key, value);
|
||||
wp_metadata_set (m, 0, key, "Spa:String:JSON", value);
|
||||
}
|
||||
|
||||
|
|
@ -219,19 +221,85 @@ on_persistent_metadata_activated (WpMetadata * m, GAsyncResult * res,
|
|||
transition);
|
||||
}
|
||||
|
||||
static void
|
||||
on_schema_metadata_activated (WpMetadata * m, GAsyncResult * res,
|
||||
gpointer user_data)
|
||||
{
|
||||
WpTransition *transition = WP_TRANSITION (user_data);
|
||||
WpSettingsPlugin *self = wp_transition_get_source_object (transition);
|
||||
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
|
||||
g_autoptr (WpConf) conf = wp_conf_get_instance (core);
|
||||
g_autoptr (GError) error = NULL;
|
||||
g_autoptr (WpSpaJson) schema_json = NULL;
|
||||
|
||||
if (!wp_object_activate_finish (WP_OBJECT (m), res, &error)) {
|
||||
wp_transition_return_error (transition, g_error_new (
|
||||
WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED,
|
||||
"Failed to activate metadata object %s", self->metadata_schema_name));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Load the schema into metadata if any */
|
||||
schema_json = wp_conf_get_section (conf, "wireplumber.settings.schema", NULL);
|
||||
if (schema_json) {
|
||||
g_autoptr (WpIterator) it = NULL;
|
||||
g_auto (GValue) item = G_VALUE_INIT;
|
||||
|
||||
if (!wp_spa_json_is_object (schema_json)) {
|
||||
wp_transition_return_error (transition, g_error_new (
|
||||
WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED,
|
||||
"Settings schema is not a JSON object: %s",
|
||||
wp_spa_json_get_data (schema_json)));
|
||||
return;
|
||||
}
|
||||
|
||||
it = wp_spa_json_new_iterator (schema_json);
|
||||
while (wp_iterator_next (it, &item)) {
|
||||
WpSpaJson *j = g_value_get_boxed (&item);
|
||||
g_autofree gchar *key = wp_spa_json_parse_string (j);
|
||||
g_autofree gchar *value = NULL;
|
||||
|
||||
g_value_unset (&item);
|
||||
if (!wp_iterator_next (it, &item)) {
|
||||
wp_transition_return_error (transition, g_error_new (WP_DOMAIN_LIBRARY,
|
||||
WP_LIBRARY_ERROR_INVARIANT, "Malformed settings schema"));
|
||||
return;
|
||||
}
|
||||
j = g_value_get_boxed (&item);
|
||||
value = wp_spa_json_to_string (j);
|
||||
g_value_unset (&item);
|
||||
|
||||
wp_debug_object (self, "adding schema setting to %s metadata: %s = %s",
|
||||
self->metadata_schema_name, key, value);
|
||||
wp_metadata_set (m, 0, key, "Spa:String:JSON", value);
|
||||
}
|
||||
} else {
|
||||
wp_warning_object (self, "settings schema not found in configuration");
|
||||
}
|
||||
|
||||
/* create persistent metadata object */
|
||||
self->persistent_impl_metadata = wp_impl_metadata_new_full (core,
|
||||
self->metadata_persistent_name, NULL);
|
||||
wp_object_activate (WP_OBJECT (self->persistent_impl_metadata),
|
||||
WP_OBJECT_FEATURES_ALL,
|
||||
NULL,
|
||||
(GAsyncReadyCallback)on_persistent_metadata_activated,
|
||||
transition);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_settings_plugin_enable (WpPlugin * plugin, WpTransition * transition)
|
||||
{
|
||||
WpSettingsPlugin * self = WP_SETTINGS_PLUGIN (plugin);
|
||||
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (plugin));
|
||||
|
||||
/* create persistent metadata object */
|
||||
self->persistent_impl_metadata = wp_impl_metadata_new_full (core,
|
||||
self->persistent_metadata_name, NULL);
|
||||
wp_object_activate (WP_OBJECT (self->persistent_impl_metadata),
|
||||
/* create schema metadata object */
|
||||
self->schema_impl_metadata = wp_impl_metadata_new_full (core,
|
||||
self->metadata_schema_name, NULL);
|
||||
wp_object_activate (WP_OBJECT (self->schema_impl_metadata),
|
||||
WP_OBJECT_FEATURES_ALL,
|
||||
NULL,
|
||||
(GAsyncReadyCallback)on_persistent_metadata_activated,
|
||||
(GAsyncReadyCallback)on_schema_metadata_activated,
|
||||
transition);
|
||||
}
|
||||
|
||||
|
|
@ -246,7 +314,8 @@ wp_settings_plugin_disable (WpPlugin * plugin)
|
|||
g_clear_object (&self->state);
|
||||
|
||||
g_clear_pointer (&self->metadata_name, g_free);
|
||||
g_clear_pointer (&self->persistent_metadata_name, g_free);
|
||||
g_clear_pointer (&self->metadata_schema_name, g_free);
|
||||
g_clear_pointer (&self->metadata_persistent_name, g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -258,8 +327,10 @@ wp_settings_plugin_set_property (GObject * object, guint property_id,
|
|||
switch (property_id) {
|
||||
case PROP_METADATA_NAME:
|
||||
self->metadata_name = g_value_dup_string (value);
|
||||
self->persistent_metadata_name = g_strdup_printf ("persistent-%s",
|
||||
self->metadata_name);
|
||||
self->metadata_schema_name = g_strdup_printf (
|
||||
WP_SETTINGS_SCHEMA_METADATA_NAME_PREFIX "%s", self->metadata_name);
|
||||
self->metadata_persistent_name = g_strdup_printf (
|
||||
WP_SETTINGS_PERSISTENT_METADATA_NAME_PREFIX "%s", self->metadata_name);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
|
|
|
|||
|
|
@ -664,3 +664,115 @@ wireplumber.components.rules = [
|
|||
}
|
||||
}
|
||||
]
|
||||
|
||||
wireplumber.settings.schema = {
|
||||
## Bluetooth
|
||||
bluetooth.use-persistent-storage = {
|
||||
description = "Whether to use persistent BT storage or not"
|
||||
type = "bool"
|
||||
default = true
|
||||
}
|
||||
bluetooth.autoswitch-to-headset-profile = {
|
||||
description = "Whether to autoswitch to BT headset profile or not"
|
||||
type = "bool"
|
||||
default = true
|
||||
}
|
||||
|
||||
## Device
|
||||
device.restore-profile = {
|
||||
description = "Whether to restore device profile or not"
|
||||
type = "bool"
|
||||
default = true
|
||||
}
|
||||
device.restore-routes = {
|
||||
description = "Whether to restore device routes or not"
|
||||
type = "bool"
|
||||
default = true
|
||||
}
|
||||
device.routes.default-sink-volume = {
|
||||
description = "The default volume for sink devices"
|
||||
type = "float"
|
||||
default = 0.064
|
||||
min = 0.0
|
||||
max = 1.0
|
||||
}
|
||||
device.routes.default-source-volume = {
|
||||
description = "The default volume for source devices"
|
||||
type = "float"
|
||||
default = 1.0
|
||||
min = 0.0
|
||||
max = 1.0
|
||||
}
|
||||
|
||||
## Linking
|
||||
linking.allow-moving-streams = {
|
||||
description = "Whether to allow metadata to move streams at runtime or not"
|
||||
type = "bool"
|
||||
default = true
|
||||
}
|
||||
linking.follow-default-target = {
|
||||
description = "Whether to allow streams follow the default device or not"
|
||||
type = "bool"
|
||||
default = true
|
||||
}
|
||||
|
||||
## Monitor
|
||||
monitor.camera-discovery-timeout = {
|
||||
description = "The camera discovery timeout in milliseconds"
|
||||
type = "int"
|
||||
default = 100
|
||||
min = 0
|
||||
max = 60000
|
||||
}
|
||||
|
||||
## Node
|
||||
node.features.audio.no-dsp = {
|
||||
description = "Whether to never convert audio to F32 format or not"
|
||||
type = "bool"
|
||||
default = false
|
||||
}
|
||||
node.eatures.audio.monitor-ports = {
|
||||
description = "Whether to enable monitor ports on audio nodes or not"
|
||||
type = "bool"
|
||||
default = true
|
||||
}
|
||||
node.features.audio.control-port = {
|
||||
description = "Whether to enable control ports on audio nodes or not"
|
||||
type = "bool"
|
||||
default = false
|
||||
}
|
||||
node.stream.restore-props = {
|
||||
description = "Whether to restore properties on stream nodes or not"
|
||||
type = "bool"
|
||||
default = true
|
||||
}
|
||||
node.stream.restore-target = {
|
||||
description = "Whether to restore target on stream nodes or not"
|
||||
type = "bool"
|
||||
default = true
|
||||
}
|
||||
node.default-playback-volume = {
|
||||
description = "The default volume for playback nodes"
|
||||
type = "float"
|
||||
default = 1.0
|
||||
min = 0.0
|
||||
max = 1.0
|
||||
}
|
||||
node.default-capture-volume = {
|
||||
description = "The default volume for capture nodes"
|
||||
type = "float"
|
||||
default = 1.0
|
||||
min = 0.0
|
||||
max = 1.0
|
||||
}
|
||||
node.filter.forward-format = {
|
||||
description = "Whether to forward format on filter nodes or not"
|
||||
type = "bool"
|
||||
default = false
|
||||
}
|
||||
node.restore-default-targets = {
|
||||
description = "Whether to restore default targets or not"
|
||||
type = "bool"
|
||||
default = true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue