mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2026-05-08 13:58:19 +02:00
spa-pod: add support for custom Id properties
Allows creating and parsing Pod Objects with custom properties.
This commit is contained in:
parent
7c03da82e7
commit
711d1ee686
4 changed files with 133 additions and 35 deletions
|
|
@ -16,6 +16,7 @@
|
|||
#include <spa/pod/parser.h>
|
||||
|
||||
#define WP_SPA_POD_BUILDER_REALLOC_STEP_SIZE 64
|
||||
#define WP_SPA_POD_ID_PROPERTY_NAME_MAX 16
|
||||
|
||||
/*! \defgroup wpspapod WpSpaPod */
|
||||
/*!
|
||||
|
|
@ -66,6 +67,7 @@ struct _WpSpaPod
|
|||
WpSpaIdTable table;
|
||||
guint32 key;
|
||||
guint32 flags;
|
||||
gchar id_key_name[WP_SPA_POD_ID_PROPERTY_NAME_MAX];
|
||||
} data_property; /* Only used for property pods */
|
||||
struct wp_control_data {
|
||||
guint32 offset;
|
||||
|
|
@ -1717,8 +1719,14 @@ wp_spa_pod_get_property (WpSpaPod *self, const char **key,
|
|||
WpSpaIdValue key_val = wp_spa_id_table_find_value (
|
||||
self->static_pod.data_property.table,
|
||||
self->static_pod.data_property.key);
|
||||
g_return_val_if_fail (key_val != NULL, FALSE);
|
||||
*key = wp_spa_id_value_short_name (key_val);
|
||||
if (key_val) {
|
||||
*key = wp_spa_id_value_short_name (key_val);
|
||||
} else {
|
||||
g_snprintf (self->static_pod.data_property.id_key_name,
|
||||
WP_SPA_POD_ID_PROPERTY_NAME_MAX, "id-%08x",
|
||||
self->static_pod.data_property.key);
|
||||
*key = self->static_pod.data_property.id_key_name;
|
||||
}
|
||||
}
|
||||
if (value)
|
||||
*value = wp_spa_pod_new_wrap (self->pod);
|
||||
|
|
@ -2128,10 +2136,16 @@ wp_spa_pod_builder_add_pod (WpSpaPodBuilder *self, WpSpaPod *pod)
|
|||
void
|
||||
wp_spa_pod_builder_add_property (WpSpaPodBuilder *self, const char *key)
|
||||
{
|
||||
WpSpaIdTable table = wp_spa_type_get_values_table (self->type);
|
||||
WpSpaIdValue id = wp_spa_id_table_find_value_from_short_name (table, key);
|
||||
g_return_if_fail (id != NULL);
|
||||
spa_pod_builder_prop (&self->builder, wp_spa_id_value_number (id), 0);
|
||||
guint key_id;
|
||||
if (g_str_has_prefix (key, "id-")) {
|
||||
g_return_if_fail (sscanf (key, "id-%08x", &key_id) == 1);
|
||||
} else {
|
||||
WpSpaIdTable table = wp_spa_type_get_values_table (self->type);
|
||||
WpSpaIdValue id = wp_spa_id_table_find_value_from_short_name (table, key);
|
||||
g_return_if_fail (id != NULL);
|
||||
key_id = wp_spa_id_value_number (id);
|
||||
}
|
||||
spa_pod_builder_prop (&self->builder, key_id, 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -2201,13 +2215,18 @@ wp_spa_pod_builder_add_valist (WpSpaPodBuilder *self, va_list args)
|
|||
gboolean choice;
|
||||
|
||||
if (wp_spa_type_is_object (self->type)) {
|
||||
guint key_id;
|
||||
const char *key_name = va_arg(args, const char *);
|
||||
if (!key_name)
|
||||
return;
|
||||
key = wp_spa_id_table_find_value_from_short_name (table, key_name);
|
||||
g_return_if_fail (key != NULL);
|
||||
|
||||
spa_pod_builder_prop (&self->builder, wp_spa_id_value_number (key), 0);
|
||||
if (g_str_has_prefix (key_name, "id-")) {
|
||||
g_return_if_fail (sscanf (key_name, "id-%08x", &key_id) == 1);
|
||||
} else {
|
||||
key = wp_spa_id_table_find_value_from_short_name (table, key_name);
|
||||
g_return_if_fail (key != NULL);
|
||||
key_id = wp_spa_id_value_number (key);
|
||||
}
|
||||
spa_pod_builder_prop (&self->builder, key_id, 0);
|
||||
}
|
||||
else if (self->type == SPA_TYPE_Sequence) {
|
||||
guint32 offset = va_arg(args, uint32_t);
|
||||
|
|
@ -2643,16 +2662,23 @@ wp_spa_pod_parser_get_valist (WpSpaPodParser *self, va_list args)
|
|||
const char *format;
|
||||
|
||||
if (wp_spa_type_is_object (self->type)) {
|
||||
guint key_id;
|
||||
const struct spa_pod_object *object;
|
||||
const char *key_name = va_arg(args, const char *);
|
||||
if (!key_name)
|
||||
break;
|
||||
key = wp_spa_id_table_find_value_from_short_name (table, key_name);
|
||||
g_return_val_if_fail (key != NULL, FALSE);
|
||||
|
||||
const struct spa_pod_object *object = (const struct spa_pod_object *)
|
||||
spa_pod_parser_frame (&self->parser, &self->frame);
|
||||
prop = spa_pod_object_find_prop (object, prop,
|
||||
wp_spa_id_value_number (key));
|
||||
if (g_str_has_prefix (key_name, "id-")) {
|
||||
g_return_val_if_fail (sscanf (key_name, "id-%08x", &key_id) == 1, FALSE);
|
||||
} else {
|
||||
key = wp_spa_id_table_find_value_from_short_name (table, key_name);
|
||||
g_return_val_if_fail (key != NULL, FALSE);
|
||||
key_id = wp_spa_id_value_number (key);
|
||||
}
|
||||
|
||||
object = (const struct spa_pod_object *)spa_pod_parser_frame
|
||||
(&self->parser, &self->frame);
|
||||
prop = spa_pod_object_find_prop (object, prop, key_id);
|
||||
pod = prop ? &prop->value : NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -276,8 +276,13 @@ builder_add_lua_userdata (WpSpaPodBuilder *b, WpSpaIdValue key_id,
|
|||
{
|
||||
WpSpaPod *pod = wplua_checkboxed (L, idx, WP_TYPE_SPA_POD);
|
||||
if (pod) {
|
||||
WpSpaType prop_type = wp_spa_id_value_get_value_type (key_id, NULL);
|
||||
if (is_pod_type_compatible (prop_type, pod)) {
|
||||
if (key_id) {
|
||||
WpSpaType prop_type = wp_spa_id_value_get_value_type (key_id, NULL);
|
||||
if (is_pod_type_compatible (prop_type, pod)) {
|
||||
wp_spa_pod_builder_add_pod (b, pod);
|
||||
return TRUE;
|
||||
}
|
||||
} else {
|
||||
wp_spa_pod_builder_add_pod (b, pod);
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -603,28 +608,25 @@ object_add_property (WpSpaPodBuilder *b, WpSpaIdTable table,
|
|||
{
|
||||
guint i;
|
||||
WpSpaIdValue prop_id = NULL;
|
||||
WpSpaType prop_type = WP_SPA_TYPE_INVALID;
|
||||
int ltype = lua_type (L, idx);
|
||||
|
||||
if (ltype < 0 || ltype >= MAX_LUA_TYPES)
|
||||
return FALSE;
|
||||
|
||||
/* Get the property type name */
|
||||
prop_id = wp_spa_id_table_find_value_from_short_name (table, key);
|
||||
if (!prop_id)
|
||||
return FALSE;
|
||||
prop_type = wp_spa_id_value_get_value_type (prop_id, NULL);
|
||||
if (prop_type == WP_SPA_TYPE_INVALID)
|
||||
return FALSE;
|
||||
|
||||
/* Check if we can add primitive property directly from LUA type */
|
||||
for (i = 0; primitive_lua_types[i].primitive_type; i++) {
|
||||
const struct primitive_lua_type *t = primitive_lua_types + i;
|
||||
if (t->primitive_type == prop_type) {
|
||||
primitive_lua_add_func f = t->primitive_lua_add_funcs[ltype];
|
||||
if (f) {
|
||||
wp_spa_pod_builder_add_property (b, key);
|
||||
return f (b, prop_id, L, idx);
|
||||
prop_id = wp_spa_id_table_find_value_from_short_name (table, key);
|
||||
if (prop_id) {
|
||||
WpSpaType prop_type = wp_spa_id_value_get_value_type (prop_id, NULL);
|
||||
if (prop_type != WP_SPA_TYPE_INVALID) {
|
||||
for (i = 0; primitive_lua_types[i].primitive_type; i++) {
|
||||
const struct primitive_lua_type *t = primitive_lua_types + i;
|
||||
if (t->primitive_type == prop_type) {
|
||||
primitive_lua_add_func f = t->primitive_lua_add_funcs[ltype];
|
||||
if (f) {
|
||||
wp_spa_pod_builder_add_property (b, key);
|
||||
return f (b, prop_id, L, idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -420,6 +420,7 @@ test_spa_pod_object (void)
|
|||
"frequency", "i", 440,
|
||||
"device", "s", "device-name",
|
||||
"deviceFd", "h", 5,
|
||||
"id-01000000", "b", TRUE,
|
||||
NULL);
|
||||
g_assert_nonnull (pod);
|
||||
g_assert_true (wp_spa_pod_is_object (pod));
|
||||
|
|
@ -432,6 +433,7 @@ test_spa_pod_object (void)
|
|||
gint32 frequency;
|
||||
const char *device;
|
||||
gint64 device_fd;
|
||||
gboolean custom = FALSE;
|
||||
g_assert_true (wp_spa_pod_get_object (pod,
|
||||
&id_name,
|
||||
"mute", "b", &mute,
|
||||
|
|
@ -439,6 +441,7 @@ test_spa_pod_object (void)
|
|||
"frequency", "i", &frequency,
|
||||
"device", "s", &device,
|
||||
"deviceFd", "h", &device_fd,
|
||||
"id-01000000", "b", &custom,
|
||||
NULL));
|
||||
g_assert_cmpstr (id_name, ==, "Props");
|
||||
g_assert_false (mute);
|
||||
|
|
@ -446,6 +449,7 @@ test_spa_pod_object (void)
|
|||
g_assert_cmpint (frequency, ==, 440);
|
||||
g_assert_cmpstr (device, ==, "device-name");
|
||||
g_assert_cmpint (device_fd, ==, 5);
|
||||
g_assert_true (custom);
|
||||
}
|
||||
|
||||
/* Dynamic */
|
||||
|
|
@ -462,6 +466,8 @@ test_spa_pod_object (void)
|
|||
wp_spa_pod_builder_add_string (b, "device-name");
|
||||
wp_spa_pod_builder_add_property (b, "deviceFd");
|
||||
wp_spa_pod_builder_add_fd (b, 5);
|
||||
wp_spa_pod_builder_add_property (b, "id-01000000");
|
||||
wp_spa_pod_builder_add_boolean (b, TRUE);
|
||||
g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b);
|
||||
g_assert_nonnull (pod);
|
||||
g_assert_true (wp_spa_pod_is_object (pod));
|
||||
|
|
@ -474,6 +480,7 @@ test_spa_pod_object (void)
|
|||
gint32 frequency;
|
||||
const char *device;
|
||||
gint64 device_fd;
|
||||
gboolean custom = FALSE;
|
||||
g_autoptr (WpSpaPodParser) p = wp_spa_pod_parser_new_object (pod, &id_name);
|
||||
g_assert_nonnull (pod);
|
||||
g_assert_true (wp_spa_pod_parser_get (p, "mute", "b", &mute, NULL));
|
||||
|
|
@ -481,6 +488,7 @@ test_spa_pod_object (void)
|
|||
g_assert_true (wp_spa_pod_parser_get (p, "frequency", "i", &frequency, NULL));
|
||||
g_assert_true (wp_spa_pod_parser_get (p, "device", "s", &device, NULL));
|
||||
g_assert_true (wp_spa_pod_parser_get (p, "deviceFd", "h", &device_fd, NULL));
|
||||
g_assert_true (wp_spa_pod_parser_get (p, "id-01000000", "b", &custom, NULL));
|
||||
wp_spa_pod_parser_end (p);
|
||||
g_assert_cmpstr (id_name, ==, "Props");
|
||||
g_assert_false (mute);
|
||||
|
|
@ -488,6 +496,7 @@ test_spa_pod_object (void)
|
|||
g_assert_cmpint (frequency, ==, 440);
|
||||
g_assert_cmpstr (device, ==, "device-name");
|
||||
g_assert_cmpint (device_fd, ==, 5);
|
||||
g_assert_true (custom);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -786,6 +795,8 @@ test_spa_pod_iterator (void)
|
|||
wp_spa_pod_builder_add_boolean (b, FALSE);
|
||||
wp_spa_pod_builder_add_property (b, "device");
|
||||
wp_spa_pod_builder_add_string (b, "device-name");
|
||||
wp_spa_pod_builder_add_property (b, "id-01000000");
|
||||
wp_spa_pod_builder_add_boolean (b, TRUE);
|
||||
g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b);
|
||||
g_assert_nonnull (pod);
|
||||
|
||||
|
|
@ -824,13 +835,29 @@ test_spa_pod_iterator (void)
|
|||
g_value_unset (&next);
|
||||
}
|
||||
|
||||
{
|
||||
GValue next = G_VALUE_INIT;
|
||||
g_assert_true (wp_iterator_next (it, &next));
|
||||
WpSpaPod *p = g_value_get_boxed (&next);
|
||||
g_assert_nonnull (p);
|
||||
g_assert_true (wp_spa_pod_is_property (p));
|
||||
const char *key = NULL;
|
||||
g_autoptr (WpSpaPod) value = NULL;
|
||||
g_assert_true (wp_spa_pod_get_property (p, &key, &value));
|
||||
g_assert_cmpstr (key, ==, "id-01000000");
|
||||
gboolean b = FALSE;
|
||||
g_assert_true (wp_spa_pod_get_boolean (value, &b));
|
||||
g_assert_true (b);
|
||||
g_value_unset (&next);
|
||||
}
|
||||
|
||||
{
|
||||
g_assert_false (wp_iterator_next (it, NULL));
|
||||
}
|
||||
|
||||
guint32 total_props = 0;
|
||||
g_assert_true (wp_iterator_foreach (it, object_foreach, &total_props));
|
||||
g_assert_cmpuint (total_props, ==, 2);
|
||||
g_assert_cmpuint (total_props, ==, 3);
|
||||
}
|
||||
|
||||
/* Struct */
|
||||
|
|
|
|||
|
|
@ -93,6 +93,27 @@ assert (val.properties.direction == "Input")
|
|||
assert (val.properties.mode == "dsp")
|
||||
assert (val.properties.monitor)
|
||||
assert (pod:get_type_name() == "Spa:Pod:Object:Param:PortConfig")
|
||||
pod = Pod.Object {
|
||||
"Spa:Pod:Object:Param:Props", "Props",
|
||||
device = "hw:Generic",
|
||||
deviceName = "",
|
||||
cardName = "",
|
||||
minLatency = 16,
|
||||
maxLatency = 8192,
|
||||
["id-01000000"] = Pod.Boolean (true),
|
||||
latencyOffsetNsec = 0
|
||||
}
|
||||
val = pod:parse()
|
||||
assert (val.pod_type == "Object")
|
||||
assert (val.object_id == "Props")
|
||||
assert (val.properties.device == "hw:Generic")
|
||||
assert (val.properties.deviceName == "")
|
||||
assert (val.properties.cardName == "")
|
||||
assert (val.properties.minLatency == 16)
|
||||
assert (val.properties.maxLatency == 8192)
|
||||
assert (val.properties["id-01000000"] == true)
|
||||
assert (val.properties.latencyOffsetNsec == 0)
|
||||
assert (pod:get_type_name() == "Spa:Pod:Object:Param:Props")
|
||||
|
||||
-- Sequence
|
||||
pod = Pod.Sequence {
|
||||
|
|
@ -206,3 +227,25 @@ assert (val.properties.format.properties.position.value_type == "Spa:Id")
|
|||
assert (val.properties.format.properties.position[1] == "FL")
|
||||
assert (val.properties.format.properties.position[2] == "FR")
|
||||
assert (pod:get_type_name() == "Spa:Pod:Object:Param:PortConfig")
|
||||
|
||||
-- Nested Object Id Properties
|
||||
pod = Pod.Object {
|
||||
"Spa:Pod:Object:Param:Props", "Props",
|
||||
device = "my-device",
|
||||
["id-01000000"] = Pod.Int (4),
|
||||
["id-02000000"] = Pod.Object {
|
||||
"Spa:Pod:Object:Param:Props", "Props",
|
||||
device = "my-sub-device",
|
||||
["id-03000000"] = Pod.Boolean (true),
|
||||
["id-04000000"] = Pod.String ("string")
|
||||
}
|
||||
}
|
||||
val = pod:parse()
|
||||
assert (val.pod_type == "Object")
|
||||
assert (val.object_id == "Props")
|
||||
assert (val.properties.device == "my-device")
|
||||
assert (val.properties["id-01000000"] == 4)
|
||||
assert (val.properties["id-02000000"].properties.device == "my-sub-device")
|
||||
assert (val.properties["id-02000000"].properties["id-03000000"] == true)
|
||||
assert (val.properties["id-02000000"].properties["id-04000000"] == "string")
|
||||
assert (pod:get_type_name() == "Spa:Pod:Object:Param:Props")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue