diff --git a/lib/wp/spa-pod.c b/lib/wp/spa-pod.c index 1d061cb1..6690cfc1 100644 --- a/lib/wp/spa-pod.c +++ b/lib/wp/spa-pod.c @@ -16,6 +16,7 @@ #include #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; } diff --git a/modules/module-lua-scripting/pod.c b/modules/module-lua-scripting/pod.c index 67908d08..4dc0e63a 100644 --- a/modules/module-lua-scripting/pod.c +++ b/modules/module-lua-scripting/pod.c @@ -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); + } + } } } } diff --git a/tests/wp/spa-pod.c b/tests/wp/spa-pod.c index 70b9b4d6..3366385d 100644 --- a/tests/wp/spa-pod.c +++ b/tests/wp/spa-pod.c @@ -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 */ diff --git a/tests/wplua/scripts/pod.lua b/tests/wplua/scripts/pod.lua index 3c9f88fa..91e2441f 100644 --- a/tests/wplua/scripts/pod.lua +++ b/tests/wplua/scripts/pod.lua @@ -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")