Port: Add tag param

The tag param has a list of arbitrary key/value pairs. Like the Latency
param, it travels up and downstream. Mixers will append the info
dictionaries or do some more fancy merging.

The purpose is to transport arbirary metadata, out-of-band, through the
graph and it's used for stream metadata and other stream properties.
This commit is contained in:
Wim Taymans 2023-08-24 16:41:21 +02:00
parent 6bf42e9bcd
commit 41dcac0ecd
20 changed files with 566 additions and 24 deletions

View file

@ -40,6 +40,7 @@ static const struct spa_type_info spa_type_param[] = {
{ SPA_PARAM_Control, SPA_TYPE_Sequence, SPA_TYPE_INFO_PARAM_ID_BASE "Control", NULL },
{ SPA_PARAM_Latency, SPA_TYPE_OBJECT_ParamLatency, SPA_TYPE_INFO_PARAM_ID_BASE "Latency", NULL },
{ SPA_PARAM_ProcessLatency, SPA_TYPE_OBJECT_ParamProcessLatency, SPA_TYPE_INFO_PARAM_ID_BASE "ProcessLatency", NULL },
{ SPA_PARAM_Tag, SPA_TYPE_OBJECT_ParamTag, SPA_TYPE_INFO_PARAM_ID_BASE "Tag", NULL },
{ 0, 0, NULL, NULL },
};

View file

@ -39,6 +39,7 @@ enum spa_param_type {
SPA_PARAM_Control, /**< Control parameter, a SPA_TYPE_Sequence */
SPA_PARAM_Latency, /**< latency reporting, a SPA_TYPE_OBJECT_ParamLatency */
SPA_PARAM_ProcessLatency, /**< processing latency, a SPA_TYPE_OBJECT_ParamProcessLatency */
SPA_PARAM_Tag, /**< tag reporting, a SPA_TYPE_OBJECT_ParamTag. Since 0.3.79 */
};
/** information about a parameter */

View file

@ -0,0 +1,39 @@
/* Simple Plugin API */
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#ifndef SPA_PARAM_TAG_TYPES_H
#define SPA_PARAM_TAG_TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* \addtogroup spa_param
* \{
*/
#include <spa/utils/enum-types.h>
#include <spa/param/param-types.h>
#include <spa/param/tag.h>
#define SPA_TYPE_INFO_PARAM_Tag SPA_TYPE_INFO_PARAM_BASE "Tag"
#define SPA_TYPE_INFO_PARAM_TAG_BASE SPA_TYPE_INFO_PARAM_Tag ":"
static const struct spa_type_info spa_type_param_tag[] = {
{ SPA_PARAM_TAG_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_TAG_BASE, spa_type_param, },
{ SPA_PARAM_TAG_direction, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_TAG_BASE "direction", spa_type_direction, },
{ SPA_PARAM_TAG_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_TAG_BASE "info", NULL, },
{ 0, 0, NULL, NULL },
};
/**
* \}
*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SPA_PARAM_TAG_TYPES_H */

View file

@ -0,0 +1,143 @@
/* Simple Plugin API */
/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#ifndef SPA_PARAM_TAG_UTILS_H
#define SPA_PARAM_TAG_UTILS_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* \addtogroup spa_param
* \{
*/
#include <float.h>
#include <spa/utils/dict.h>
#include <spa/pod/builder.h>
#include <spa/pod/parser.h>
#include <spa/param/tag.h>
static inline int
spa_tag_compare(const struct spa_pod *a, const struct spa_pod *b)
{
return ((a == b) || (a && b && SPA_POD_SIZE(a) == SPA_POD_SIZE(b) &&
memcmp(a, b, SPA_POD_SIZE(b)) == 0)) ? 0 : 1;
}
static inline int
spa_tag_parse(const struct spa_pod *tag, struct spa_tag_info *info, void **state)
{
int res;
const struct spa_pod_object *obj = (const struct spa_pod_object*)tag;
const struct spa_pod_prop *first, *start, *cur;
spa_zero(*info);
if ((res = spa_pod_parse_object(tag,
SPA_TYPE_OBJECT_ParamTag, NULL,
SPA_PARAM_TAG_direction, SPA_POD_Id(&info->direction))) < 0)
return res;
first = spa_pod_prop_first(&obj->body);
start = *state ? spa_pod_prop_next((struct spa_pod_prop*)*state) : first;
res = 0;
for (cur = start; spa_pod_prop_is_inside(&obj->body, obj->pod.size, cur);
cur = spa_pod_prop_next(cur)) {
if (cur->key == SPA_PARAM_TAG_info) {
info->info = &cur->value;
*state = (void*)cur;
return 1;
}
}
return 0;
}
static inline int
spa_tag_info_parse(const struct spa_tag_info *info, struct spa_dict *dict, struct spa_dict_item *items)
{
struct spa_pod_parser prs;
uint32_t n, n_items;
const char *key, *value;
struct spa_pod_frame f[1];
spa_pod_parser_pod(&prs, info->info);
if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
spa_pod_parser_get_int(&prs, (int32_t*)&n_items) < 0)
return -EINVAL;
if (items == NULL) {
dict->n_items = n_items;
return 0;
}
n_items = SPA_MIN(dict->n_items, n_items);
for (n = 0; n < n_items; n++) {
if (spa_pod_parser_get(&prs,
SPA_POD_String(&key),
SPA_POD_String(&value),
NULL) < 0)
break;
items[n].key = key;
items[n].value = value;
}
dict->items = items;
spa_pod_parser_pop(&prs, &f[0]);
return 0;
}
static inline void
spa_tag_build_start(struct spa_pod_builder *builder, struct spa_pod_frame *f,
uint32_t id, enum spa_direction direction)
{
spa_pod_builder_push_object(builder, f, SPA_TYPE_OBJECT_ParamTag, id);
spa_pod_builder_add(builder,
SPA_PARAM_TAG_direction, SPA_POD_Id(direction),
0);
}
static inline void
spa_tag_build_add_info(struct spa_pod_builder *builder, const struct spa_pod *info)
{
spa_pod_builder_add(builder,
SPA_PARAM_TAG_info, SPA_POD_Pod(info),
0);
}
static inline void
spa_tag_build_add_dict(struct spa_pod_builder *builder, const struct spa_dict *dict)
{
uint32_t i, n_items;
struct spa_pod_frame f;
n_items = dict ? dict->n_items : 0;
spa_pod_builder_prop(builder, SPA_PARAM_TAG_info, SPA_POD_PROP_FLAG_HINT_DICT);
spa_pod_builder_push_struct(builder, &f);
spa_pod_builder_int(builder, n_items);
for (i = 0; i < n_items; i++) {
spa_pod_builder_string(builder, dict->items[i].key);
spa_pod_builder_string(builder, dict->items[i].value);
}
spa_pod_builder_pop(builder, &f);
}
static inline struct spa_pod *
spa_tag_build_end(struct spa_pod_builder *builder, struct spa_pod_frame *f)
{
return (struct spa_pod*)spa_pod_builder_pop(builder, f);
}
/**
* \}
*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SPA_PARAM_TAG_UTILS_H */

View file

@ -0,0 +1,46 @@
/* Simple Plugin API */
/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#ifndef SPA_PARAM_TAG_H
#define SPA_PARAM_TAG_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* \addtogroup spa_param
* \{
*/
#include <spa/param/param.h>
/** properties for SPA_TYPE_OBJECT_ParamTag */
enum spa_param_tag {
SPA_PARAM_TAG_START,
SPA_PARAM_TAG_direction, /**< direction, input/output (Id enum spa_direction) */
SPA_PARAM_TAG_info, /**< Struct(
* Int: n_items
* (String: key
* String: value)*
* ) */
};
/** helper structure for managing tag objects */
struct spa_tag_info {
enum spa_direction direction;
const struct spa_pod *info;
};
#define SPA_TAG_INFO(dir,...) ((struct spa_tag_info) { .direction = (dir), ## __VA_ARGS__ })
/**
* \}
*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SPA_PARAM_TAG_H */

View file

@ -14,5 +14,6 @@
#include <spa/param/profiler-types.h>
#include <spa/param/profile-types.h>
#include <spa/param/route-types.h>
#include <spa/param/tag-types.h>
#endif /* SPA_PARAM_TYPE_INFO_H */

View file

@ -83,6 +83,7 @@ static const struct spa_type_info spa_types[] = {
{ SPA_TYPE_OBJECT_Profiler, SPA_TYPE_Object, SPA_TYPE_INFO_Profiler, spa_type_profiler },
{ SPA_TYPE_OBJECT_ParamLatency, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_Latency, spa_type_param_latency },
{ SPA_TYPE_OBJECT_ParamProcessLatency, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_ProcessLatency, spa_type_param_process_latency },
{ SPA_TYPE_OBJECT_ParamTag, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_Tag, spa_type_param_tag },
{ 0, 0, NULL, NULL }
};

View file

@ -78,6 +78,7 @@ enum {
SPA_TYPE_OBJECT_Profiler,
SPA_TYPE_OBJECT_ParamLatency,
SPA_TYPE_OBJECT_ParamProcessLatency,
SPA_TYPE_OBJECT_ParamTag,
_SPA_TYPE_OBJECT_LAST, /**< not part of ABI */
/* vendor extensions */