From f318edb699fe0d928f247f63eadf128414a88346 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 14 Apr 2023 15:07:26 +0200 Subject: [PATCH] metadata: add support for initial metadata Add a metadata.values property that is used to fill the metadata store with initial values. Fixes #3076 --- src/daemon/minimal.conf.in | 10 ++++- src/daemon/pipewire.conf.in | 11 +++++ src/modules/module-metadata.c | 65 +++++++++++++++++++++++++++++- src/pipewire/extensions/metadata.h | 1 + 4 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/daemon/minimal.conf.in b/src/daemon/minimal.conf.in index 72f44fa1b..9c885a38f 100644 --- a/src/daemon/minimal.conf.in +++ b/src/daemon/minimal.conf.in @@ -152,7 +152,15 @@ context.objects = [ #{ factory = spa-node-factory args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } } # Make a default metadata store - { factory = metadata args = { metadata.name = default } } + { factory = metadata + args = { + metadata.name = default + # metadata.values = [ + # { key = default.audio.sink value = { name = somesink } } + # { key = default.audio.source value = { name = somesource } } + # ] + } + } # A default dummy driver. This handles nodes marked with the "node.always-driver" # property when no other driver is currently active. JACK clients need this. diff --git a/src/daemon/pipewire.conf.in b/src/daemon/pipewire.conf.in index 01ef26e42..b8ba514f6 100644 --- a/src/daemon/pipewire.conf.in +++ b/src/daemon/pipewire.conf.in @@ -263,6 +263,17 @@ context.objects = [ # audio.position = "FL,FR" # } #} + + # Use the metadata factory to create metadata and some default values. + #{ factory = metadata + # args = { + # metadata.name = my-metadata + # metadata.values = [ + # { key = default.audio.sink value = { name = somesink } } + # { key = default.audio.source value = { name = somesource } } + # ] + # } + #} ] context.exec = [ diff --git a/src/modules/module-metadata.c b/src/modules/module-metadata.c index b5f3338a2..33ec61c8a 100644 --- a/src/modules/module-metadata.c +++ b/src/modules/module-metadata.c @@ -10,6 +10,7 @@ #include "config.h" #include +#include #include #include @@ -19,6 +20,12 @@ #define NAME "metadata" +#define FACTORY_USAGE "("PW_KEY_METADATA_NAME" = ) " \ + "("PW_KEY_METADATA_VALUES" = [ " \ + " { ( id = ) key = ( type = ) value = } " \ + " ..." \ + " ] )" + PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); #define PW_LOG_TOPIC_DEFAULT mod_topic @@ -47,6 +54,56 @@ struct factory_data { struct pw_export_type export_metadata; }; +/* + * [ + * { ( "id" = , ) "key" = ("type" = ) "value" = } + * .... + * ] + */ +static int fill_metadata(struct pw_metadata *metadata, const char *str) +{ + struct spa_json it[3]; + + spa_json_init(&it[0], str, strlen(str)); + if (spa_json_enter_array(&it[0], &it[1]) <= 0) + return -EINVAL; + + while (spa_json_enter_object(&it[1], &it[2]) > 0) { + char key[256], *k = NULL, *v = NULL, *t = NULL; + int id = 0; + + while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) { + int len; + const char *val; + + if ((len = spa_json_next(&it[2], &val)) <= 0) + return -EINVAL; + + if (spa_streq(key, "id")) { + if (spa_json_parse_int(val, len, &id) <= 0) + return -EINVAL; + } else if (spa_streq(key, "key")) { + if ((k = malloc(len+1)) != NULL) + spa_json_parse_stringn(val, len, k, len+1); + } else if (spa_streq(key, "type")) { + if ((t = malloc(len+1)) != NULL) + spa_json_parse_stringn(val, len, t, len+1); + } else if (spa_streq(key, "value")) { + if (spa_json_is_container(val, len)) + len = spa_json_container_len(&it[2], val, len); + if ((v = malloc(len+1)) != NULL) + spa_json_parse_stringn(val, len, v, len+1); + } + } + if (k != NULL && v != NULL) + pw_metadata_set_property(metadata, id, k, t, v); + free(k); + free(v); + free(t); + } + return 0; +} + static void *create_object(void *_data, struct pw_resource *resource, const char *type, @@ -59,6 +116,7 @@ static void *create_object(void *_data, struct pw_metadata *result; struct pw_resource *metadata_resource = NULL; struct pw_impl_client *client = resource ? pw_resource_get_client(resource) : NULL; + const char *str; int res; if (properties == NULL) @@ -102,6 +160,9 @@ static void *create_object(void *_data, pw_impl_metadata_register(impl, NULL); result = pw_impl_metadata_get_implementation(impl); } + if ((str = pw_properties_get(properties, PW_KEY_METADATA_VALUES)) != NULL) + fill_metadata(result, str); + return result; error_resource: @@ -192,7 +253,9 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) "metadata", PW_TYPE_INTERFACE_Metadata, PW_VERSION_METADATA, - NULL, + pw_properties_new( + PW_KEY_FACTORY_USAGE, FACTORY_USAGE, + NULL), sizeof(*data)); if (factory == NULL) return -errno; diff --git a/src/pipewire/extensions/metadata.h b/src/pipewire/extensions/metadata.h index c17affb3d..f448eb1b2 100644 --- a/src/pipewire/extensions/metadata.h +++ b/src/pipewire/extensions/metadata.h @@ -80,6 +80,7 @@ struct pw_metadata_methods { #define pw_metadata_clear(c) pw_metadata_method(c,clear,0) #define PW_KEY_METADATA_NAME "metadata.name" +#define PW_KEY_METADATA_VALUES "metadata.values" /** * \}