From 376238883178fce7d3a1525dd840b5ff8cf824fd Mon Sep 17 00:00:00 2001 From: George Kiagiadakis <george.kiagiadakis@collabora.com> Date: Wed, 13 Jan 2021 20:11:41 +0200 Subject: [PATCH] spa-type: refactor * Use a more complete API to introspect SPA types * Avoid the need for the Tables enumeration; the tables are now registered with a string * Avoid the need for initialization, work directly on spa_types and other static data * Allow working with Object pods that are not Params; the PARAMS table was previously hardcoded in the pod implementation * Add a different dynamic type registration system, closer to how spa type works. The only regression is that we can no longer register additional custom object fields (custom SPA_PROP_* for example), but this feature can be re-added later --- lib/wp/endpoint-stream.c | 7 +- lib/wp/endpoint.c | 7 +- lib/wp/private/pipewire-object-mixin.c | 41 +- lib/wp/spa-pod.c | 353 ++++---- lib/wp/spa-pod.h | 31 +- lib/wp/spa-type.c | 854 +++++++++++++----- lib/wp/spa-type.h | 136 ++- lib/wp/wp.c | 2 +- .../module-dbus-reservation/reserve-device.c | 2 +- modules/module-default-profile.c | 6 +- modules/module-device-activation.c | 5 +- .../limited-creation-bluez5.c | 3 +- modules/module-si-adapter.c | 13 +- modules/module-si-adapter/algorithms.c | 28 +- modules/module-si-bluez5-endpoint.c | 2 +- modules/module-si-convert.c | 16 +- modules/module-si-simple-node-endpoint.c | 8 +- tests/modules/algorithms.c | 12 +- tests/wp/endpoint.c | 26 +- tests/wp/proxy.c | 3 +- tests/wp/spa-pod.c | 174 ++-- tests/wp/spa-type.c | 419 +++++++-- tools/wpctl.c | 16 +- 23 files changed, 1384 insertions(+), 780 deletions(-) diff --git a/lib/wp/endpoint-stream.c b/lib/wp/endpoint-stream.c index 88bcf1fa..41a093ea 100644 --- a/lib/wp/endpoint-stream.c +++ b/lib/wp/endpoint-stream.c @@ -535,19 +535,20 @@ wp_impl_endpoint_stream_set_param (gpointer instance, guint32 id, guint32 flags, WpImplEndpointStream *self = WP_IMPL_ENDPOINT_STREAM (instance); g_autoptr (WpPipewireObject) node = wp_session_item_get_associated_proxy ( WP_SESSION_ITEM (self->item), WP_TYPE_NODE); - const gchar *idstr = NULL; if (!node) { wp_warning_object (self, "associated node is no longer available"); return -EPIPE; } - if (!wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_PARAM, id, NULL, &idstr, NULL)) { + WpSpaIdValue idval = wp_spa_id_value_from_number ("Spa:Enum:ParamId", id); + if (!idval) { wp_critical_object (self, "invalid param id: %u", id); return -EINVAL; } - return wp_pipewire_object_set_param (node, idstr, flags, param) ? 0 : -EIO; + return wp_pipewire_object_set_param (node, wp_spa_id_value_short_name (idval), + flags, param) ? 0 : -EIO; } #define pw_endpoint_stream_emit(hooks,method,version,...) \ diff --git a/lib/wp/endpoint.c b/lib/wp/endpoint.c index fed1ad5b..8838bc7f 100644 --- a/lib/wp/endpoint.c +++ b/lib/wp/endpoint.c @@ -1081,19 +1081,20 @@ wp_impl_endpoint_set_param (gpointer instance, guint32 id, guint32 flags, WpImplEndpoint *self = WP_IMPL_ENDPOINT (instance); g_autoptr (WpPipewireObject) node = wp_session_item_get_associated_proxy ( WP_SESSION_ITEM (self->item), WP_TYPE_NODE); - const gchar *idstr = NULL; if (!node) { wp_warning_object (self, "associated node is no longer available"); return -EPIPE; } - if (!wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_PARAM, id, NULL, &idstr, NULL)) { + WpSpaIdValue idval = wp_spa_id_value_from_number ("Spa:Enum:ParamId", id); + if (!idval) { wp_critical_object (self, "invalid param id: %u", id); return -EINVAL; } - return wp_pipewire_object_set_param (node, idstr, flags, param) ? 0 : -EIO; + return wp_pipewire_object_set_param (node, wp_spa_id_value_short_name (idval), + flags, param) ? 0 : -EIO; } #define pw_endpoint_emit(hooks,method,version,...) \ diff --git a/lib/wp/private/pipewire-object-mixin.c b/lib/wp/private/pipewire-object-mixin.c index a0ef4641..62262db1 100644 --- a/lib/wp/private/pipewire-object-mixin.c +++ b/lib/wp/private/pipewire-object-mixin.c @@ -83,12 +83,13 @@ wp_pw_object_mixin_get_param_info (WpPipewireObject * obj) g_variant_builder_init (&b, G_VARIANT_TYPE ("a{ss}")); for (guint i = 0; i < n_params; i++) { + WpSpaIdValue idval; const gchar *nick = NULL; gchar flags[3]; guint flags_idx = 0; - wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_PARAM, info[i].id, NULL, &nick, - NULL); + idval = wp_spa_id_value_from_number ("Spa:Enum:ParamId", info[i].id); + nick = wp_spa_id_value_short_name (idval); g_return_val_if_fail (nick != NULL, NULL); if (info[i].flags & SPA_PARAM_INFO_READ) @@ -170,8 +171,8 @@ wp_pw_object_mixin_enum_params_unchecked (gpointer obj, /* debug */ if (wp_log_level_is_enabled (G_LOG_LEVEL_DEBUG)) { const gchar *name = NULL; - wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_PARAM, id, &name, NULL, NULL); - + name = wp_spa_id_value_short_name ( + wp_spa_id_value_from_number ("Spa:Enum:ParamId", id)); wp_debug_object (obj, "enum id %u (%s), seq 0x%x (%u), task " WP_OBJECT_FORMAT "%s", id, name, seq, seq, WP_OBJECT_ARGS (task), iface->enum_params_sync ? ", sync" : ""); @@ -199,7 +200,7 @@ wp_pw_object_mixin_enum_params (WpPipewireObject * obj, const gchar * id, GAsyncReadyCallback callback, gpointer user_data) { WpPwObjectMixinPrivInterface *iface = WP_PW_OBJECT_MIXIN_PRIV_GET_IFACE (obj); - guint32 param_id = 0; + WpSpaIdValue param_id; if (!(iface->enum_params || iface->enum_params_sync)) { g_task_report_new_error (obj, callback, user_data, NULL, @@ -209,13 +210,14 @@ wp_pw_object_mixin_enum_params (WpPipewireObject * obj, const gchar * id, } /* translate the id */ - if (!wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_PARAM, id, ¶m_id, - NULL, NULL)) { + param_id = wp_spa_id_value_from_short_name ("Spa:Enum:ParamId", id); + if (!param_id) { wp_critical_object (obj, "invalid param id: %s", id); return; } - wp_pw_object_mixin_enum_params_unchecked (obj, param_id, filter, + wp_pw_object_mixin_enum_params_unchecked (obj, + wp_spa_id_value_number (param_id), filter, cancellable, callback, user_data); } @@ -238,22 +240,24 @@ wp_pw_object_mixin_enum_params_sync (WpPipewireObject * obj, const gchar * id, { WpPwObjectMixinPrivInterface *iface = WP_PW_OBJECT_MIXIN_PRIV_GET_IFACE (obj); GPtrArray *params = NULL; - guint32 param_id = 0; + WpSpaIdValue param_id; /* translate the id */ - if (!wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_PARAM, id, ¶m_id, - NULL, NULL)) { + param_id = wp_spa_id_value_from_short_name ("Spa:Enum:ParamId", id); + if (!param_id) { wp_critical_object (obj, "invalid param id: %s", id); return NULL; } if (iface->enum_params_sync) { /* use enum_params_sync if supported */ - params = iface->enum_params_sync (obj, param_id, 0, -1, filter); + params = iface->enum_params_sync (obj, wp_spa_id_value_number (param_id), + 0, -1, filter); } else { /* otherwise, find and return the cached params */ WpPwObjectMixinData *data = wp_pw_object_mixin_get_data (obj); - params = wp_pw_object_mixin_get_stored_params (data, param_id); + params = wp_pw_object_mixin_get_stored_params (data, + wp_spa_id_value_number (param_id)); /* TODO filter */ } @@ -265,7 +269,7 @@ wp_pw_object_mixin_set_param (WpPipewireObject * obj, const gchar * id, guint32 flags, WpSpaPod * param) { WpPwObjectMixinPrivInterface *iface = WP_PW_OBJECT_MIXIN_PRIV_GET_IFACE (obj); - guint32 param_id = 0; + WpSpaIdValue param_id; gint ret; if (!iface->set_param) { @@ -273,14 +277,14 @@ wp_pw_object_mixin_set_param (WpPipewireObject * obj, const gchar * id, return FALSE; } - if (!wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_PARAM, id, ¶m_id, - NULL, NULL)) { + param_id = wp_spa_id_value_from_short_name ("Spa:Enum:ParamId", id); + if (!param_id) { wp_critical_object (obj, "invalid param id: %s", id); wp_spa_pod_unref (param); return FALSE; } - ret = iface->set_param (obj, param_id, flags, param); + ret = iface->set_param (obj, wp_spa_id_value_number (param_id), flags, param); if (G_UNLIKELY (SPA_RESULT_IS_ERROR (ret))) { wp_message_object (obj, "set_param failed: %s", spa_strerror (ret)); @@ -940,7 +944,8 @@ wp_pw_object_mixin_notify_params_changed (gpointer instance, guint32 id) if (wp_log_level_is_enabled (G_LOG_LEVEL_DEBUG)) { const gchar *name = NULL; - wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_PARAM, id, &name, NULL, NULL); + name = wp_spa_id_value_short_name (wp_spa_id_value_from_number ( + "Spa:Enum:ParamId", id)); wp_debug_object (instance, "notify param id:%u (%s)", id, name); } diff --git a/lib/wp/spa-pod.c b/lib/wp/spa-pod.c index b81f878b..f00b6a50 100644 --- a/lib/wp/spa-pod.c +++ b/lib/wp/spa-pod.c @@ -52,13 +52,13 @@ struct _WpSpaPod struct spa_pod_rectangle pod_rectangle; struct spa_pod_fraction pod_fraction; struct wp_property_data { - WpSpaTypeTable table; + WpSpaIdTable table; guint32 key; guint32 flags; } data_property; /* Only used for property pods */ struct wp_control_data { guint32 offset; - guint32 type; + enum spa_control_type type; } data_control; /* Only used for control pods */ } static_pod; /* Only used for statically allocated pods */ WpSpaPodBuilder *builder; /* Only used for dynamically allocated pods */ @@ -69,12 +69,11 @@ G_DEFINE_BOXED_TYPE (WpSpaPod, wp_spa_pod, wp_spa_pod_ref, wp_spa_pod_unref) struct _WpSpaPodBuilder { - size_t size; - guint8 *buf; struct spa_pod_builder builder; - uint32_t type; struct spa_pod_frame frame; - WpSpaTypeTable prop_table; /* Only used when parsing properties */ + WpSpaType type; + size_t size; + guint8 *buf; }; G_DEFINE_BOXED_TYPE (WpSpaPodBuilder, wp_spa_pod_builder, @@ -82,11 +81,10 @@ G_DEFINE_BOXED_TYPE (WpSpaPodBuilder, wp_spa_pod_builder, struct _WpSpaPodParser { - guint32 type; struct spa_pod_parser parser; - WpSpaPod *pod; struct spa_pod_frame frame; - WpSpaTypeTable prop_table; /* Only used when parsing properties */ + WpSpaType type; + WpSpaPod *pod; }; G_DEFINE_BOXED_TYPE (WpSpaPodParser, wp_spa_pod_parser, @@ -111,7 +109,7 @@ static const struct spa_pod_builder_callbacks builder_callbacks = { }; static WpSpaPodBuilder * -wp_spa_pod_builder_new (size_t size, uint32_t type) +wp_spa_pod_builder_new (size_t size, WpSpaType type) { WpSpaPodBuilder *self = g_rc_box_new0 (WpSpaPodBuilder); self->size = size; @@ -180,10 +178,8 @@ wp_spa_pod_new (const struct spa_pod *pod, WpSpaPodType type, guint32 flags) /* Set the prop table if it is an object */ if (pod->type == SPA_TYPE_Object) { - WpSpaTypeTable prop_table = 0; - wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_BASIC, - ((struct spa_pod_object *) pod)->body.type, NULL, NULL, &prop_table); - self->static_pod.data_property.table = prop_table; + self->static_pod.data_property.table = + wp_spa_type_get_values_table (((struct spa_pod_object *) pod)->body.type); } return self; @@ -220,7 +216,7 @@ wp_spa_pod_new_wrap_const (const struct spa_pod *pod) } static WpSpaPod * -wp_spa_pod_new_property_wrap (WpSpaTypeTable table, guint32 key, guint32 flags, +wp_spa_pod_new_property_wrap (WpSpaIdTable table, guint32 key, guint32 flags, struct spa_pod *pod) { WpSpaPod *self = wp_spa_pod_new (pod, WP_SPA_POD_PROPERTY, FLAG_NO_OWNERSHIP); @@ -231,7 +227,7 @@ wp_spa_pod_new_property_wrap (WpSpaTypeTable table, guint32 key, guint32 flags, } static WpSpaPod * -wp_spa_pod_new_control_wrap (guint32 offset, guint32 type, +wp_spa_pod_new_control_wrap (guint32 offset, enum spa_control_type type, struct spa_pod *pod) { WpSpaPod *self = wp_spa_pod_new (pod, WP_SPA_POD_CONTROL, FLAG_NO_OWNERSHIP); @@ -244,7 +240,7 @@ wp_spa_pod_new_control_wrap (guint32 offset, guint32 type, /* there is no use for these _const variants, but let's keep them just in case */ static WpSpaPod * -wp_spa_pod_new_property_wrap_const (WpSpaTypeTable table, guint32 key, +wp_spa_pod_new_property_wrap_const (WpSpaIdTable table, guint32 key, guint32 flags, const struct spa_pod *pod) { WpSpaPod *self = wp_spa_pod_new (pod, WP_SPA_POD_PROPERTY, @@ -256,7 +252,7 @@ wp_spa_pod_new_property_wrap_const (WpSpaTypeTable table, guint32 key, } static WpSpaPod * -wp_spa_pod_new_control_wrap_const (guint32 offset, guint32 type, +wp_spa_pod_new_control_wrap_const (guint32 offset, enum spa_control_type type, const struct spa_pod *pod) { WpSpaPod *self = wp_spa_pod_new (pod, WP_SPA_POD_CONTROL, @@ -274,7 +270,7 @@ wp_spa_pod_new_wrap_copy (const struct spa_pod *pod) } static WpSpaPod * -wp_spa_pod_new_property_wrap_copy (WpSpaTypeTable table, guint32 key, +wp_spa_pod_new_property_wrap_copy (WpSpaIdTable table, guint32 key, guint32 flags, const struct spa_pod *pod) { WpSpaPod *self = wp_spa_pod_new (pod, WP_SPA_POD_PROPERTY, 0); @@ -285,7 +281,7 @@ wp_spa_pod_new_property_wrap_copy (WpSpaTypeTable table, guint32 key, } static WpSpaPod * -wp_spa_pod_new_control_wrap_copy (guint32 offset, guint32 type, +wp_spa_pod_new_control_wrap_copy (guint32 offset, enum spa_control_type type, const struct spa_pod *pod) { WpSpaPod *self = wp_spa_pod_new (pod, WP_SPA_POD_CONTROL, 0); @@ -311,45 +307,43 @@ wp_spa_pod_get_spa_pod (const WpSpaPod *self) } /** - * wp_spa_pod_get_type_name: - * @self: a spa pod object + * wp_spa_pod_get_spa_type: + * @self: a spa pod * - * Gets the type name of the spa pod object + * Gets the SPA type of the spa pod. + * If the pod is an object or pointer, this will return the derived + * object/pointer type directly. + * If the pod is an object property or a control, this will return the type + * of the contained value. * - * Returns: the type name of the spa pod object + * Returns: the type of the spa pod */ -const char * -wp_spa_pod_get_type_name (WpSpaPod *self) +WpSpaType +wp_spa_pod_get_spa_type (WpSpaPod *self) { - const char *nick = NULL; - if (!wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_BASIC, SPA_POD_TYPE (self->pod), - NULL, &nick, NULL)) - g_return_val_if_reached (NULL); - return nick; -} + g_return_val_if_fail (self != NULL, WP_SPA_TYPE_INVALID); -const char * -wp_spa_pod_get_choice_type_name (WpSpaPod *self) -{ - g_return_val_if_fail (wp_spa_pod_is_choice (self), NULL); - - const char *nick = NULL; - if (!wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_CHOICE, - SPA_POD_CHOICE_TYPE (self->pod), NULL, &nick, NULL)) - g_return_val_if_reached (NULL); - return nick; + if (wp_spa_pod_is_object (self) || wp_spa_pod_is_pointer (self)) + return SPA_POD_OBJECT_TYPE (self->pod); + else + return SPA_POD_TYPE (self->pod); } -const char * -wp_spa_pod_get_object_type_name (WpSpaPod *self) +/** + * wp_spa_pod_get_choice_type: + * @self: a choice pod + * + * If the pod is a Choice, this gets the choice type + * (Range, Step, Enum, ...) + * + * Returns: the choice type of the choice pod + */ +WpSpaIdValue +wp_spa_pod_get_choice_type (WpSpaPod *self) { - g_return_val_if_fail (wp_spa_pod_is_object (self), NULL); - - const char *nick = NULL; - if (!wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_BASIC, - SPA_POD_OBJECT_TYPE (self->pod), NULL, &nick, NULL)) - g_return_val_if_reached (NULL); - return nick; + g_return_val_if_fail (wp_spa_pod_is_choice (self), NULL); + return wp_spa_id_value_from_number ( + SPA_TYPE_INFO_Choice, SPA_POD_CHOICE_TYPE (self->pod)); } /** @@ -609,7 +603,7 @@ wp_spa_pod_new_bytes (gconstpointer value, guint32 len) /** * wp_spa_pod_new_pointer: - * @type_name: the type name the pointer points to + * @type_name: the name of the type of the pointer * @value: the pointer value * * Creates a spa pod of type pointer @@ -619,13 +613,12 @@ wp_spa_pod_new_bytes (gconstpointer value, guint32 len) WpSpaPod * wp_spa_pod_new_pointer (const char *type_name, gconstpointer value) { + WpSpaType type = wp_spa_type_from_name (type_name); + g_return_val_if_fail (type != WP_SPA_TYPE_INVALID, NULL); + WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->type = WP_SPA_POD_REGULAR; - guint32 type = 0; - if (!wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, type_name, &type, - NULL, NULL)) - g_return_val_if_reached (NULL); self->static_pod.pod_pointer = SPA_POD_INIT_Pointer (type, value); self->pod = &self->static_pod.pod_pointer.pod; return self; @@ -694,7 +687,7 @@ wp_spa_pod_new_fraction (guint32 num, guint32 denom) /** * wp_spa_pod_new_choice: - * @type_name: the type name of the choice type + * @choice_type: the name of the choice type ("Range", "Step", ...) * @...: a list of choice values, followed by %NULL * * Creates a spa pod of type choice @@ -702,13 +695,13 @@ wp_spa_pod_new_fraction (guint32 num, guint32 denom) * Returns: (transfer full): The new spa pod */ WpSpaPod * -wp_spa_pod_new_choice (const char *type_name, ...) +wp_spa_pod_new_choice (const char *choice_type, ...) { WpSpaPod *self; va_list args; - va_start (args, type_name); - self = wp_spa_pod_new_choice_valist (type_name, args); + va_start (args, choice_type); + self = wp_spa_pod_new_choice_valist (choice_type, args); va_end (args); return self; @@ -716,7 +709,7 @@ wp_spa_pod_new_choice (const char *type_name, ...) /** * wp_spa_pod_new_choice_valist: - * @type_name: the type name of the choice type + * @choice_type: the name of the choice type ("Range", "Step", ...) * @args: the variable arguments passed to wp_spa_pod_new_choice() * * This is the `va_list` version of wp_spa_pod_new_choice() @@ -724,9 +717,9 @@ wp_spa_pod_new_choice (const char *type_name, ...) * Returns: (transfer full): The new spa pod */ WpSpaPod * -wp_spa_pod_new_choice_valist (const char *type_name, va_list args) +wp_spa_pod_new_choice_valist (const char *choice_type, va_list args) { - g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_choice (type_name); + g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_choice (choice_type); wp_spa_pod_builder_add_valist (b, args); return wp_spa_pod_builder_end (b); } @@ -838,8 +831,7 @@ wp_spa_pod_is_none (WpSpaPod *self) gboolean wp_spa_pod_is_boolean (WpSpaPod *self) { - return self->type == WP_SPA_POD_REGULAR && - spa_pod_is_bool (self->pod) ? TRUE : FALSE; + return self->type == WP_SPA_POD_REGULAR && spa_pod_is_bool (self->pod); } /** @@ -1241,7 +1233,6 @@ wp_spa_pod_get_bytes (WpSpaPod *self, gconstpointer *value, guint32 *len) /** * wp_spa_pod_get_pointer: * @self: the spa pod object - * @type_name: (out): the type name of the pointer value * @value: (out): the pointer value * * Gets the pointer value and its type name of a spa pod object @@ -1249,21 +1240,13 @@ wp_spa_pod_get_bytes (WpSpaPod *self, gconstpointer *value, guint32 *len) * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean -wp_spa_pod_get_pointer (WpSpaPod *self, const char **type_name, - gconstpointer *value) +wp_spa_pod_get_pointer (WpSpaPod *self, gconstpointer *value) { - gboolean res; - g_return_val_if_fail (self, FALSE); - g_return_val_if_fail (type_name, FALSE); g_return_val_if_fail (value, FALSE); guint32 type = 0; - res = spa_pod_get_pointer (self->pod, &type, value) >= 0; - if (!wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_BASIC, type, NULL, type_name, - NULL)) - g_return_val_if_reached (FALSE); - return res; + return spa_pod_get_pointer (self->pod, &type, value) >= 0; } /** @@ -1440,7 +1423,7 @@ wp_spa_pod_set_double (WpSpaPod *self, double value) /** * wp_spa_pod_set_pointer: * @self: the spa pod object - * @type_name: the type name the pointer points to + * @type_name: the name of the type of the pointer * @value: the pointer value * * Sets a pointer value with its type name in the spa pod object. @@ -1451,16 +1434,13 @@ gboolean wp_spa_pod_set_pointer (WpSpaPod *self, const char *type_name, gconstpointer value) { - guint32 id = 0; + WpSpaType type = wp_spa_type_from_name (type_name); g_return_val_if_fail (wp_spa_pod_is_pointer (self), FALSE); g_return_val_if_fail (!(self->flags & FLAG_CONSTANT), FALSE); + g_return_val_if_fail (type != WP_SPA_TYPE_INVALID, FALSE); - if (!wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, type_name, &id, NULL, - NULL)) - g_return_val_if_reached (FALSE); - - ((struct spa_pod_pointer *)self->pod)->body.type = id; + ((struct spa_pod_pointer *)self->pod)->body.type = type; ((struct spa_pod_pointer *)self->pod)->body.value = value; return TRUE; } @@ -1679,7 +1659,7 @@ wp_spa_pod_equal (WpSpaPod *self, WpSpaPod *pod) switch (self->type) { case WP_SPA_POD_PROPERTY: if (self->static_pod.data_property.table != pod->static_pod.data_property.table || - self->static_pod.data_property.table != pod->static_pod.data_property.table || + self->static_pod.data_property.key != pod->static_pod.data_property.key || self->static_pod.data_property.flags != pod->static_pod.data_property.flags) return FALSE; break; @@ -1699,7 +1679,6 @@ wp_spa_pod_equal (WpSpaPod *self, WpSpaPod *pod) /** * wp_spa_pod_get_object: * @self: the spa pod object - * @type_name: the type name of the object type * @id_name: (out): the id name of the object * @...: (out): the list of the object properties values, followed by %NULL * @@ -1708,13 +1687,12 @@ wp_spa_pod_equal (WpSpaPod *self, WpSpaPod *pod) * Returns: TRUE if the object properties values were obtained, FALSE otherwise */ gboolean -wp_spa_pod_get_object (WpSpaPod *self, const char *type_name, - const char **id_name, ...) +wp_spa_pod_get_object (WpSpaPod *self, const char **id_name, ...) { va_list args; gboolean res; va_start (args, id_name); - res = wp_spa_pod_get_object_valist (self, type_name, id_name, args); + res = wp_spa_pod_get_object_valist (self, id_name, args); va_end (args); return res; } @@ -1722,7 +1700,6 @@ wp_spa_pod_get_object (WpSpaPod *self, const char *type_name, /** * wp_spa_pod_get_object_valist: * @self: the spa pod object - * @type_name: the type name of the object type * @id_name: (out): the id name of the object * @args: (out): the variable arguments passed to wp_spa_pod_get_object() * @@ -1731,13 +1708,11 @@ wp_spa_pod_get_object (WpSpaPod *self, const char *type_name, * Returns: TRUE if the object properties values were obtained, FALSE otherwise */ gboolean -wp_spa_pod_get_object_valist (WpSpaPod *self, const char *type_name, - const char **id_name, va_list args) +wp_spa_pod_get_object_valist (WpSpaPod *self, const char **id_name, va_list args) { g_return_val_if_fail (self, FALSE); g_return_val_if_fail (wp_spa_pod_is_object (self), FALSE); - g_autoptr (WpSpaPodParser) p = wp_spa_pod_parser_new_object (self, type_name, - id_name); + g_autoptr (WpSpaPodParser) p = wp_spa_pod_parser_new_object (self, id_name); const gboolean res = wp_spa_pod_parser_get_valist (p, args); wp_spa_pod_parser_end (p); return res; @@ -1800,9 +1775,13 @@ wp_spa_pod_get_property (WpSpaPod *self, const char **key, g_return_val_if_fail (self, FALSE); g_return_val_if_fail (wp_spa_pod_is_property (self), FALSE); - if (key && !wp_spa_type_get_by_id (self->static_pod.data_property.table, - self->static_pod.data_property.key, NULL, key, NULL)) - return FALSE; + if (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 (value) *value = wp_spa_pod_new_wrap (self->pod); @@ -1813,7 +1792,7 @@ wp_spa_pod_get_property (WpSpaPod *self, const char **key, * wp_spa_pod_get_control: * @self: the spa pod object * @offset: (out) (optional): the offset of the control - * @type_name: (out) (optional): the type name of the control + * @ctl_type: (out) (optional): the control type (Properties, Midi, ...) * @value: (out) (optional): the spa pod value of the control * * Gets the offset, type name and spa pod value of a spa pod control @@ -1821,7 +1800,7 @@ wp_spa_pod_get_property (WpSpaPod *self, const char **key, * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean -wp_spa_pod_get_control (WpSpaPod *self, guint32 *offset, const char **type_name, +wp_spa_pod_get_control (WpSpaPod *self, guint32 *offset, const char **ctl_type, WpSpaPod **value) { g_return_val_if_fail (self, FALSE); @@ -1829,9 +1808,12 @@ wp_spa_pod_get_control (WpSpaPod *self, guint32 *offset, const char **type_name, if (offset) *offset = self->static_pod.data_control.offset; - if (type_name && !wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_CONTROL, - self->static_pod.data_control.type, NULL, type_name, NULL)) - g_return_val_if_reached (FALSE); + if (ctl_type) { + WpSpaIdValue type_val = wp_spa_id_value_from_number ( + SPA_TYPE_INFO_Control, self->static_pod.data_control.type); + g_return_val_if_fail (type_val != NULL, FALSE); + *ctl_type = wp_spa_id_value_short_name (type_val); + } if (value) *value = wp_spa_pod_new_wrap (self->pod); @@ -1917,30 +1899,27 @@ wp_spa_pod_builder_new_array (void) /** * wp_spa_pod_builder_new_choice: - * @type_name: the type name of the choice type + * @choice_type: the name of the choice type ("Range", "Step", ...) * * Creates a spa pod builder of type choice * * Returns: (transfer full): the new spa pod builder */ WpSpaPodBuilder * -wp_spa_pod_builder_new_choice (const char *type_name) +wp_spa_pod_builder_new_choice (const char *choice_type) { WpSpaPodBuilder *self = NULL; - guint32 type = 0; + WpSpaIdValue type = wp_spa_id_value_from_short_name ( + SPA_TYPE_INFO_Choice, choice_type); + g_return_val_if_fail (type != NULL, NULL); /* Construct the builder */ self = wp_spa_pod_builder_new (WP_SPA_POD_BUILDER_REALLOC_STEP_SIZE, SPA_TYPE_Choice); - /* Find the choice type */ - if (!wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_CHOICE, type_name, &type, - NULL, NULL)) - g_return_val_if_reached (NULL); - /* Push the array */ - spa_pod_builder_push_choice (&self->builder, &self->frame, type, - WP_SPA_TYPE_TABLE_CHOICE); + spa_pod_builder_push_choice (&self->builder, &self->frame, + wp_spa_id_value_number (type), 0); return self; } @@ -1958,25 +1937,27 @@ WpSpaPodBuilder * wp_spa_pod_builder_new_object (const char *type_name, const char *id_name) { WpSpaPodBuilder *self = NULL; - guint32 type = 0; - guint32 id = 0; - - /* Construct the builder */ - self = wp_spa_pod_builder_new (WP_SPA_POD_BUILDER_REALLOC_STEP_SIZE, - SPA_TYPE_Object); + WpSpaType type; + WpSpaIdTable table; + WpSpaIdValue id; /* Find the type */ - if (!wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, type_name, &type, - NULL, &self->prop_table)) - g_return_val_if_reached (NULL); + type = wp_spa_type_from_name (type_name); + g_return_val_if_fail (wp_spa_type_is_object (type), NULL); /* Find the id */ - if (!wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_PARAM, id_name, &id, NULL, - NULL)) - g_return_val_if_reached (NULL); + table = wp_spa_type_get_object_id_values_table (type); + g_return_val_if_fail (table != NULL, NULL); + + id = wp_spa_id_table_find_value_from_short_name (table, id_name); + g_return_val_if_fail (id != NULL, NULL); + + /* Construct the builder */ + self = wp_spa_pod_builder_new (WP_SPA_POD_BUILDER_REALLOC_STEP_SIZE, type); /* Push the object */ - spa_pod_builder_push_object (&self->builder, &self->frame, type, id); + spa_pod_builder_push_object (&self->builder, &self->frame, type, + wp_spa_id_value_number (id)); return self; } @@ -2145,10 +2126,8 @@ void wp_spa_pod_builder_add_pointer (WpSpaPodBuilder *self, const char *type_name, gconstpointer value) { - guint32 type = 0; - if (!wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, type_name, &type, - NULL, NULL)) - g_return_if_reached (); + WpSpaType type = wp_spa_type_from_name (type_name); + g_return_if_fail (wp_spa_type_parent (type) == SPA_TYPE_Pointer); spa_pod_builder_pointer (&self->builder, type, value); } @@ -2218,10 +2197,10 @@ wp_spa_pod_builder_add_pod (WpSpaPodBuilder *self, WpSpaPod *pod) void wp_spa_pod_builder_add_property (WpSpaPodBuilder *self, const char *key) { - guint32 id = 0; - if (!wp_spa_type_get_by_nick (self->prop_table, key, &id, NULL, NULL)) - g_return_if_reached (); - spa_pod_builder_prop (&self->builder, id, 0); + 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); } /** @@ -2249,11 +2228,10 @@ void wp_spa_pod_builder_add_control (WpSpaPodBuilder *self, guint32 offset, const char *type_name) { - guint type = 0; - if (!wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_CONTROL, type_name, &type, - NULL, NULL)) - g_return_if_reached (); - spa_pod_builder_control (&self->builder, offset, type); + WpSpaIdValue id = wp_spa_id_value_from_short_name ( + SPA_TYPE_INFO_Control, type_name); + g_return_if_fail (id != NULL); + spa_pod_builder_control (&self->builder, offset, wp_spa_id_value_number (id)); } /** @@ -2288,41 +2266,30 @@ wp_spa_pod_builder_add_valist (WpSpaPodBuilder *self, va_list args) struct spa_pod_frame f; gboolean choice; - switch (self->type) { - case SPA_TYPE_Object: - { - guint32 key = 0; + if (wp_spa_type_is_object (self->type)) { const char *key_name = va_arg(args, const char *); if (!key_name) return; - if (!wp_spa_type_get_by_nick (self->prop_table, key_name, &key, NULL, - NULL)) - g_return_if_reached (); - if (key == 0) - return; + WpSpaIdTable table = wp_spa_type_get_values_table (self->type); + WpSpaIdValue 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, key, 0); - break; + spa_pod_builder_prop (&self->builder, wp_spa_id_value_number (key), 0); } - case SPA_TYPE_Sequence: - { + else if (self->type == SPA_TYPE_Sequence) { guint32 offset = va_arg(args, uint32_t); - guint32 type = 0; if (offset == 0) return; const char *control_name = va_arg(args, const char *); if (!control_name) return; - if (!wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_CONTROL, control_name, - &type, NULL, NULL)) - g_return_if_reached (); - if (type == 0) - return; + WpSpaIdValue type = wp_spa_id_value_from_short_name ( + SPA_TYPE_INFO_Control, control_name); + g_return_if_fail (type != NULL); - spa_pod_builder_control (&self->builder, offset, type); - } - default: - break; + spa_pod_builder_control (&self->builder, offset, + wp_spa_id_value_number (type)); } if ((format = va_arg(args, const char *)) == NULL) @@ -2376,9 +2343,10 @@ wp_spa_pod_builder_end (WpSpaPodBuilder *self) ret->pod = spa_pod_builder_pop (&self->builder, &self->frame); ret->builder = wp_spa_pod_builder_ref (self); - /* Also copy the property table if it is an object type */ - if (ret->builder->type == SPA_TYPE_Object) - ret->static_pod.data_property.table = ret->builder->prop_table; + /* Also copy the specific object type if it is an object */ + if (spa_pod_is_object (ret->pod)) + ret->static_pod.data_property.table = + wp_spa_type_get_values_table (ret->builder->type); return ret; } @@ -2427,7 +2395,6 @@ wp_spa_pod_parser_new (WpSpaPod *pod, guint32 type) /** * wp_spa_pod_parser_new: * @pod: the object spa pod to parse - * @type_name: the type name of the object type * @id_name: the Id name of the object * * Creates an object spa pod parser. The @pod object must be valid for the @@ -2436,22 +2403,21 @@ wp_spa_pod_parser_new (WpSpaPod *pod, guint32 type) * Returns: (transfer full): The new spa pod parser */ WpSpaPodParser * -wp_spa_pod_parser_new_object (WpSpaPod *pod, const char *type_name, - const char **id_name) +wp_spa_pod_parser_new_object (WpSpaPod *pod, const char **id_name) { WpSpaPodParser *self = NULL; - guint32 type = 0; - guint32 id = 0; + WpSpaType type = wp_spa_pod_get_spa_type (pod); + guint32 id = SPA_ID_INVALID; g_return_val_if_fail (wp_spa_pod_is_object (pod), NULL); - self = wp_spa_pod_parser_new (pod, SPA_TYPE_Object); - if (!wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, type_name, &type, - NULL, &self->prop_table)) - g_return_val_if_reached (NULL); + self = wp_spa_pod_parser_new (pod, type); spa_pod_parser_push_object (&self->parser, &self->frame, type, &id); - if (!wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_PARAM, id, NULL, id_name, NULL)) - g_return_val_if_reached (NULL); + if (id_name) { + WpSpaIdTable table = wp_spa_type_get_object_id_values_table (type); + *id_name = wp_spa_id_value_short_name ( + wp_spa_id_table_find_value (table, id)); + } return self; } @@ -2611,7 +2577,6 @@ wp_spa_pod_parser_get_bytes (WpSpaPodParser *self, gconstpointer *value, /** * wp_spa_pod_parser_get_pointer: * @self: the spa pod parser object - * @type_name: (out): the type name of the pointer value * @value: (out): the pointer value * * Gets the pointer value and its type name from a spa pod parser object @@ -2619,20 +2584,11 @@ wp_spa_pod_parser_get_bytes (WpSpaPodParser *self, gconstpointer *value, * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean -wp_spa_pod_parser_get_pointer (WpSpaPodParser *self, const char **type_name, - gconstpointer *value) +wp_spa_pod_parser_get_pointer (WpSpaPodParser *self, gconstpointer *value) { - guint32 type = 0; - gboolean res; - g_return_val_if_fail (value, FALSE); - - res = spa_pod_parser_get_pointer (&self->parser, &type, value) >= 0; - - if (!wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_BASIC, type, NULL, type_name, - NULL)) - g_return_val_if_reached (FALSE); - return res; + guint32 type = 0; + return spa_pod_parser_get_pointer (&self->parser, &type, value) >= 0; } /** @@ -2759,20 +2715,19 @@ wp_spa_pod_parser_get_valist (WpSpaPodParser *self, va_list args) const struct spa_pod *pod = NULL; const char *format; - if (self->type == SPA_TYPE_Object) { - guint32 key = 0; - const struct spa_pod_object *object; + if (wp_spa_type_is_object (self->type)) { const char *key_name = va_arg(args, const char *); if (!key_name) break; - if (!wp_spa_type_get_by_nick (self->prop_table, key_name, &key, NULL, NULL)) - g_return_val_if_reached (FALSE); - if (key == 0) - break; - - object = (const struct spa_pod_object *)spa_pod_parser_frame ( - &self->parser, &self->frame); - prop = spa_pod_object_find_prop (object, prop, key); + WpSpaIdTable table = wp_spa_type_get_values_table (self->type); + WpSpaIdValue 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)); pod = prop ? &prop->value : NULL; } @@ -2884,7 +2839,6 @@ wp_spa_pod_iterator_next_object (WpSpaPodIterator *self, GValue *item) { const struct spa_pod_object *pod_obj = (const struct spa_pod_object *) self->pod->pod; - g_autoptr (WpSpaPod) pod = NULL; if (!self->curr.prop) self->curr.prop = spa_pod_prop_first (&pod_obj->body); @@ -2928,7 +2882,6 @@ wp_spa_pod_iterator_next_sequence (WpSpaPodIterator *self, GValue *item) { const struct spa_pod_sequence *pod_seq = (const struct spa_pod_sequence *) self->pod->pod; - g_autoptr (WpSpaPod) pod = NULL; if (!self->curr.control) self->curr.control = spa_pod_control_first (&pod_seq->body); diff --git a/lib/wp/spa-pod.h b/lib/wp/spa-pod.h index f66c7879..6627208f 100644 --- a/lib/wp/spa-pod.h +++ b/lib/wp/spa-pod.h @@ -13,6 +13,7 @@ #include "defs.h" #include "iterator.h" +#include "spa-type.h" G_BEGIN_DECLS @@ -45,19 +46,16 @@ WP_API const struct spa_pod * wp_spa_pod_get_spa_pod (const WpSpaPod *self); WP_API -const char *wp_spa_pod_get_type_name (WpSpaPod *self); +WpSpaType wp_spa_pod_get_spa_type (WpSpaPod *self); WP_API -const char *wp_spa_pod_get_choice_type_name (WpSpaPod *self); - -WP_API -const char *wp_spa_pod_get_object_type_name (WpSpaPod *self); +WpSpaIdValue wp_spa_pod_get_choice_type (WpSpaPod *self); WP_API WpSpaPod *wp_spa_pod_copy (WpSpaPod *other); WP_API -gboolean wp_spa_pod_is_unique_owner ( WpSpaPod *self); +gboolean wp_spa_pod_is_unique_owner (WpSpaPod *self); WP_API WpSpaPod *wp_spa_pod_ensure_unique_owner (WpSpaPod *self); @@ -102,11 +100,11 @@ WP_API WpSpaPod *wp_spa_pod_new_fraction (guint32 num, guint32 denom); WP_API -WpSpaPod *wp_spa_pod_new_choice (const char *type_name, ...) +WpSpaPod *wp_spa_pod_new_choice (const char *choice_type, ...) G_GNUC_NULL_TERMINATED; WP_API -WpSpaPod *wp_spa_pod_new_choice_valist (const char *type_name, va_list args); +WpSpaPod *wp_spa_pod_new_choice_valist (const char *choice_type, va_list args); WP_API WpSpaPod *wp_spa_pod_new_object (const char *type_name, const char *id_name, @@ -208,8 +206,7 @@ gboolean wp_spa_pod_get_bytes (WpSpaPod *self, gconstpointer *value, guint32 *len); WP_API -gboolean wp_spa_pod_get_pointer (WpSpaPod *self, const char **type_name, - gconstpointer *value); +gboolean wp_spa_pod_get_pointer (WpSpaPod *self, gconstpointer *value); WP_API gboolean wp_spa_pod_get_fd (WpSpaPod *self, gint64 *value); @@ -260,11 +257,11 @@ WP_API gboolean wp_spa_pod_equal (WpSpaPod *self, WpSpaPod *pod); WP_API -gboolean wp_spa_pod_get_object (WpSpaPod *self, const char *type_name, +gboolean wp_spa_pod_get_object (WpSpaPod *self, const char **id_name, ...) G_GNUC_NULL_TERMINATED; WP_API -gboolean wp_spa_pod_get_object_valist (WpSpaPod *self, const char *type_name, +gboolean wp_spa_pod_get_object_valist (WpSpaPod *self, const char **id_name, va_list args); WP_API @@ -279,7 +276,7 @@ gboolean wp_spa_pod_get_property (WpSpaPod *self, const char **key, WP_API gboolean wp_spa_pod_get_control (WpSpaPod *self, guint32 *offset, - const char **type_name, WpSpaPod **value); + const char **ctl_type, WpSpaPod **value); WP_API WpSpaPod *wp_spa_pod_get_choice_child (WpSpaPod *self); @@ -314,7 +311,7 @@ WP_API WpSpaPodBuilder *wp_spa_pod_builder_new_array (void); WP_API -WpSpaPodBuilder *wp_spa_pod_builder_new_choice (const char *type_name); +WpSpaPodBuilder *wp_spa_pod_builder_new_choice (const char *choice_type); WP_API WpSpaPodBuilder *wp_spa_pod_builder_new_object (const char *type_name, @@ -380,7 +377,7 @@ void wp_spa_pod_builder_add_property_id (WpSpaPodBuilder *self, guint32 id); WP_API void wp_spa_pod_builder_add_control (WpSpaPodBuilder *self, guint32 offset, - const char *type_name); + const char *ctl_type); WP_API void wp_spa_pod_builder_add (WpSpaPodBuilder *self, ...) G_GNUC_NULL_TERMINATED; @@ -413,7 +410,7 @@ void wp_spa_pod_parser_unref (WpSpaPodParser *self); WP_API WpSpaPodParser *wp_spa_pod_parser_new_object (WpSpaPod *pod, - const char *type_name, const char **id_name); + const char **id_name); WP_API WpSpaPodParser *wp_spa_pod_parser_new_struct (WpSpaPod *pod); @@ -446,7 +443,7 @@ gboolean wp_spa_pod_parser_get_bytes (WpSpaPodParser *self, WP_API gboolean wp_spa_pod_parser_get_pointer (WpSpaPodParser *self, - const char **type_name, gconstpointer *value); + gconstpointer *value); WP_API gboolean wp_spa_pod_parser_get_fd (WpSpaPodParser *self, gint64 *value); diff --git a/lib/wp/spa-type.c b/lib/wp/spa-type.c index f7d5783b..9f011562 100644 --- a/lib/wp/spa-type.c +++ b/lib/wp/spa-type.c @@ -6,336 +6,706 @@ * SPDX-License-Identifier: MIT */ +/** + * SECTION: spa-type + * @title: Spa Type Information + * + * Spa has a type system that is represented by a set of arrays that contain + * `spa_type_info` structures. This type system is simple, yet complex to + * work with for a couple of reasons. + * + * WirePlumber uses this API to access the spa type system, which makes some + * things easier to understand and work with. The main benefit of using this + * API is that it makes it easy to work with string representations of the + * types, allowing easier access from script bindings. + * + * ### Type hierarchy + * + * On the top level, there is a list of types like Int, Bool, String, Id, Object. + * These are called fundamental types (terms borrowed from #GType). + * Fundamental types can be derived and therefore we can have other types + * that represent specific enums or objects, for instance. + * + * Enum and flag types are all derived directly from `SPA_TYPE_Id`. These types + * may have a list of possible values that one can select from (enums) + * or combine (flags). These values are accessed with the #WpSpaIdValue API. + * + * Object types can have fields. All objects always have a special "id" field, + * whose type can be given by wp_spa_object_type_get_id_type() and optionally, + * they can also have other object-specific fields, which are also accessed + * with the #WpSpaIdValue API. + */ + #define G_LOG_DOMAIN "wp-spa-type" +#include "spa-type.h" + #include <spa/utils/type-info.h> +#include <spa/debug/types.h> +#include <pipewire/pipewire.h> + +static const WpSpaType SPA_TYPE_VENDOR_WirePlumber = 0x03000000; +static GArray *extra_types = NULL; +static GArray *extra_id_tables = NULL; + +typedef struct { + const char *name; + const struct spa_type_info *values; +} WpSpaIdTableInfo; + +static const WpSpaIdTableInfo static_id_tables[] = { + { SPA_TYPE_INFO_Choice, spa_type_choice }, + { SPA_TYPE_INFO_Direction, spa_type_direction }, + { SPA_TYPE_INFO_ParamId, spa_type_param }, + { SPA_TYPE_INFO_MediaType, spa_type_media_type }, + { SPA_TYPE_INFO_MediaSubtype, spa_type_media_subtype }, + { SPA_TYPE_INFO_ParamAvailability, spa_type_param_availability }, + { SPA_TYPE_INFO_ParamPortConfigMode, spa_type_param_port_config_mode }, + { SPA_TYPE_INFO_VideoFormat, spa_type_video_format }, + { SPA_TYPE_INFO_AudioFormat, spa_type_audio_format }, + { SPA_TYPE_INFO_AudioFlags, spa_type_audio_flags }, + { SPA_TYPE_INFO_AudioChannel, spa_type_audio_channel }, + { SPA_TYPE_INFO_IO, spa_type_io }, + { SPA_TYPE_INFO_Control, spa_type_control }, + { SPA_TYPE_INFO_Data, spa_type_data_type }, + { SPA_TYPE_INFO_Meta, spa_type_meta_type }, + { SPA_TYPE_INFO_NodeEvent, spa_type_node_event_id }, + { SPA_TYPE_INFO_NodeCommand, spa_type_node_command_id }, + { NULL, NULL } +}; -#include "spa-type.h" +/** + * WpSpaType: + */ +GType wp_spa_type_get_type (void) +{ + static volatile gsize id__volatile = 0; + if (g_once_init_enter (&id__volatile)) { + GType id = g_type_register_static_simple ( + G_TYPE_UINT, g_intern_static_string ("WpSpaType"), + 0, NULL, 0, NULL, 0); + g_once_init_leave (&id__volatile, id); + } + return id__volatile; +} -static gboolean -name_equal_func (gconstpointer a, gconstpointer b) { - const struct spa_type_info *ti = a; - const char *name = b; - return g_strcmp0 (ti->name, name) == 0; +/** + * WpSpaIdTable: + */ +G_DEFINE_POINTER_TYPE (WpSpaIdTable, wp_spa_id_table) + +/** + * WpSpaIdValue: + */ +G_DEFINE_POINTER_TYPE (WpSpaIdValue, wp_spa_id_value) + + +static const struct spa_type_info * +wp_spa_type_info_find_by_type (WpSpaType type) +{ + const struct spa_type_info *info; + + g_return_val_if_fail (type != WP_SPA_TYPE_INVALID, NULL); + g_return_val_if_fail (type != 0, NULL); + + if (extra_types) + info = spa_debug_type_find ( + (const struct spa_type_info *) extra_types->data, type); + else + info = spa_debug_type_find (SPA_TYPE_ROOT, type); + + return info; } +/* similar to spa_debug_type_find() and unlike spa_debug_type_find_type(), + which steps into id values / object fields */ static const struct spa_type_info * -spa_type_find (const struct spa_type_info *table, GEqualFunc func, - gconstpointer data) +_spa_type_find_by_name (const struct spa_type_info * info, const char * name) { - for (guint32 i = 0; table[i].name; i++) - if (func (table + i, data)) - return table + i; + const struct spa_type_info * res; + + while (info->name) { + if (info->type == SPA_ID_INVALID) { + if (info->values && (res = _spa_type_find_by_name (info->values, name))) + return res; + } + if (strcmp (info->name, name) == 0) + return info; + info++; + } return NULL; } static const struct spa_type_info * -spa_type_find_by_name (const struct spa_type_info *table, const char *name) +wp_spa_type_info_find_by_name (const gchar *name) +{ + const struct spa_type_info *info = NULL; + + g_return_val_if_fail (name != NULL, NULL); + + if (extra_types) + info = _spa_type_find_by_name ( + (const struct spa_type_info *) extra_types->data, name); + else + info = _spa_type_find_by_name (SPA_TYPE_ROOT, name); + + return info; +} + +/** + * wp_spa_type_from_name: + * @name: the name to look up + * + * Looks up the type id from a given type name + * + * Returns: the corresponding type id or %WP_SPA_TYPE_INVALID if not found + */ +WpSpaType +wp_spa_type_from_name (const gchar *name) { - return spa_type_find (table, name_equal_func, name); + const struct spa_type_info *info = wp_spa_type_info_find_by_name (name); + return info ? info->type : WP_SPA_TYPE_INVALID; } -struct type_info { - gboolean is_spa_type; - union { - const struct spa_type_info *spa; - struct { - guint32 type; - char *name; - } custom; - } info; - char *nick; -}; +/** + * wp_spa_type_parent: + * @type: a type id + * + * Returns: the direct parent type of the given @type; if the type is + * fundamental (i.e. has no parent), the returned type is the same as @type + */ +WpSpaType +wp_spa_type_parent (WpSpaType type) +{ + const struct spa_type_info *info = wp_spa_type_info_find_by_type (type); + return info ? info->parent : WP_SPA_TYPE_INVALID; +} -static struct type_info * -type_info_new_spa (const struct spa_type_info *info, const char* nick) { - struct type_info *ti = g_slice_new0 (struct type_info); - ti->is_spa_type = TRUE; - ti->info.spa = info; - ti->nick = g_strdup (nick); - return ti; +/** + * wp_spa_type_name: + * @type: a type id + * + * Returns: the complete name of the given @type or %NULL if @type is invalid + */ +const gchar * +wp_spa_type_name (WpSpaType type) +{ + const struct spa_type_info *info = wp_spa_type_info_find_by_type (type); + return info ? info->name : NULL; } -static struct type_info * -type_info_new_custom (uint32_t type, const char *name, const char* nick) { - struct type_info *ti = g_slice_new0 (struct type_info); - ti->is_spa_type = FALSE; - ti->info.custom.type = type; - ti->info.custom.name = g_strdup (name); - ti->nick = g_strdup (nick); - return ti; +/** + * wp_spa_type_is_fundamental: + * @type: a type id + * + * Returns: %TRUE if the @type has no parent, %FALSE otherwise + */ +gboolean +wp_spa_type_is_fundamental (WpSpaType type) +{ + const struct spa_type_info *info = wp_spa_type_info_find_by_type (type); + return info ? (info->type == info->parent) : FALSE; } -static void -type_info_free (struct type_info *ti) { - g_return_if_fail (ti); - if (!ti->is_spa_type) - g_clear_pointer (&ti->info.custom.name, g_free); - g_clear_pointer (&ti->nick, g_free); - g_slice_free (struct type_info, ti); -} - -struct spa_type_table_data { - const struct spa_type_info *spa_table; - guint32 last_id; - GPtrArray *info_array; - GHashTable *id_table; - GHashTable *nick_table; -}; +/** + * wp_spa_type_is_id: + * @type: a type id + * + * Returns: %TRUE if the @type is a SPA_TYPE_Id, %FALSE otherwise + */ +gboolean +wp_spa_type_is_id (WpSpaType type) +{ + const struct spa_type_info *info = wp_spa_type_info_find_by_type (type); + return info ? (info->parent == SPA_TYPE_Id) : FALSE; +} -static struct spa_type_table_data s_tables [WP_SPA_TYPE_TABLE_LAST] = { - [WP_SPA_TYPE_TABLE_BASIC] = {spa_types, SPA_TYPE_VENDOR_Other, NULL, NULL, NULL }, - [WP_SPA_TYPE_TABLE_PARAM] = {spa_type_param, SPA_N_ELEMENTS (spa_type_param), NULL, NULL, NULL, }, - [WP_SPA_TYPE_TABLE_PROPS] = {spa_type_props, SPA_PROP_START_CUSTOM, NULL, NULL, NULL, }, - [WP_SPA_TYPE_TABLE_PROP_INFO] = {spa_type_prop_info, SPA_N_ELEMENTS (spa_type_prop_info), NULL, NULL, NULL, }, - [WP_SPA_TYPE_TABLE_FORMAT] = {spa_type_format, SPA_N_ELEMENTS (spa_type_format), NULL, NULL, NULL, }, - [WP_SPA_TYPE_TABLE_PARAM_PORT_CONFIG] = {spa_type_param_port_config, SPA_N_ELEMENTS (spa_type_param_port_config), NULL, NULL, NULL, }, - [WP_SPA_TYPE_TABLE_PARAM_PROFILE] = {spa_type_param_profile, SPA_N_ELEMENTS (spa_type_param_profile), NULL, NULL, NULL, }, - [WP_SPA_TYPE_TABLE_CONTROL] = {spa_type_control, SPA_CONTROL_LAST, NULL, NULL, NULL, }, - [WP_SPA_TYPE_TABLE_CHOICE] = {spa_type_choice, SPA_N_ELEMENTS (spa_type_choice), NULL, NULL, NULL, }, - [WP_SPA_TYPE_TABLE_AUDIO_CHANNEL] = {spa_type_audio_channel, SPA_N_ELEMENTS (spa_type_audio_channel), NULL, NULL, NULL, }, -}; +/** + * wp_spa_type_is_object: + * @type: a type id + * + * Returns: %TRUE if the @type is a SPA_TYPE_Object, %FALSE otherwise + */ +gboolean +wp_spa_type_is_object (WpSpaType type) +{ + const struct spa_type_info *info = wp_spa_type_info_find_by_type (type); + return info ? (info->parent == SPA_TYPE_Object) : FALSE; +} -static WpSpaTypeTable -wp_spa_type_table_find_by_spa_table (const struct spa_type_info *spa_table) +/** + * wp_spa_type_get_object_id_values_table: + * @type: the type id of an object type + * + * Object pods (see #WpSpaPod) always have a special "id" field along with + * other fields that can be defined. This "id" field can only store values + * of a specific `SPA_TYPE_Id` type. This function returns the table that + * contains the possible values for that field. + * + * Returns: the table with the values that can be stored in the special "id" + * field of an object of the given @type + */ +WpSpaIdTable +wp_spa_type_get_object_id_values_table (WpSpaType type) { - for (guint32 i = 0; i < WP_SPA_TYPE_TABLE_LAST; i++) - if (s_tables[i].spa_table == spa_table) - return i; - return 0; + const struct spa_type_info *info = wp_spa_type_info_find_by_type (type); + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (info->parent == SPA_TYPE_Object, NULL); + g_return_val_if_fail (info->values != NULL, NULL); + g_return_val_if_fail (info->values->name != NULL, NULL); + g_return_val_if_fail (info->values->parent == SPA_TYPE_Id, NULL); + + return info->values->values; } /** - * wp_spa_type_init: - * @register_spa: whether spa types will be registered or not + * wp_spa_type_get_values_table: + * @type: a type id * - * Initializes the spa type registry + * Returns: the associated #WpSpaIdTable that contains possible + * values or object fields for this type, or %NULL */ -void -wp_spa_type_init (gboolean register_spa) -{ - /* Init the array and hash tables */ - for (guint32 i = 0; i < WP_SPA_TYPE_TABLE_LAST; i++) { - struct spa_type_table_data *td = s_tables + i; - if (!td->info_array) - td->info_array = g_ptr_array_new_with_free_func ((GDestroyNotify) - type_info_free); - if (!td->id_table) - td->id_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, NULL); - if (!td->nick_table) - td->nick_table = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); +WpSpaIdTable +wp_spa_type_get_values_table (WpSpaType type) +{ + const struct spa_type_info *info = wp_spa_type_info_find_by_type (type); + + g_return_val_if_fail (info != NULL, NULL); + return info->values; +} + + +struct spa_type_info_iterator_data +{ + const struct spa_type_info *base; + const struct spa_type_info *cur; +}; + +static void +spa_type_info_iterator_reset (WpIterator *it) +{ + struct spa_type_info_iterator_data *it_data = wp_iterator_get_user_data (it); + it_data->cur = it_data->base; +} + +static gboolean +spa_type_info_iterator_next (WpIterator *it, GValue *item) +{ + struct spa_type_info_iterator_data *it_data = wp_iterator_get_user_data (it); + + if (it_data->cur->name) { + g_value_init (item, WP_TYPE_SPA_ID_VALUE); + g_value_set_pointer (item, (gpointer) it_data->cur); + it_data->cur++; + return TRUE; + } + return FALSE; +} + +static gboolean +spa_type_info_iterator_fold (WpIterator *it, WpIteratorFoldFunc func, + GValue *ret, gpointer data) +{ + struct spa_type_info_iterator_data *it_data = wp_iterator_get_user_data (it); + const struct spa_type_info *cur, *base; + + cur = base = it_data->base; + + while (cur->name) { + g_auto (GValue) item = G_VALUE_INIT; + g_value_init (&item, WP_TYPE_SPA_ID_VALUE); + g_value_set_pointer (&item, (gpointer) cur); + if (!func (&item, ret, data)) + return FALSE; + cur++; } + return TRUE; +} + +static const WpIteratorMethods spa_type_info_iterator_methods = { + .version = WP_ITERATOR_METHODS_VERSION, + .reset = spa_type_info_iterator_reset, + .next = spa_type_info_iterator_next, + .fold = spa_type_info_iterator_fold, +}; - /* Register the spa types if requested */ - if (register_spa) { - for (guint32 i = 0; i < WP_SPA_TYPE_TABLE_LAST; i++) { - struct spa_type_table_data *td = s_tables + i; - for (guint32 j = 0; td->spa_table && td->spa_table[j].name; j++) { - const struct spa_type_info *t = td->spa_table + j; - const char *nick = strrchr (t->name, ':'); - if (nick && strlen (nick) > 1) - wp_spa_type_register (i, t->name, nick + 1); - } +WpSpaIdTable +wp_spa_id_table_from_name (const gchar *name) +{ + g_return_val_if_fail (name != NULL, NULL); + const WpSpaIdTableInfo *info = NULL; + + /* first look in dynamic id tables */ + if (extra_id_tables) { + info = (const WpSpaIdTableInfo *) extra_id_tables->data; + while (info && info->name) { + if (strcmp (info->name, name) == 0) + return info->values; + info++; } } + + /* then look at the well-known static ones */ + info = static_id_tables; + while (info && info->name) { + if (strcmp (info->name, name) == 0) + return info->values; + info++; + } + + /* then look into types, hoping to find an object type */ + const struct spa_type_info *tinfo = wp_spa_type_info_find_by_name (name); + return tinfo ? tinfo->values : NULL; } /** - * wp_spa_type_deinit: + * wp_spa_id_table_iterate: + * @type: the id table + * + * This function returns an iterator that allows you to iterate through the + * values associated with this table. + * The items in the iterator are of type #WpSpaIdValue. * - * Deinitializes the spa type registry + * Returns: a #WpIterator that iterates over #WpSpaIdValue items */ -void -wp_spa_type_deinit (void) +WpIterator * +wp_spa_id_table_iterate (WpSpaIdTable table) { - for (guint32 i = 0; i < WP_SPA_TYPE_TABLE_LAST; i++) { - struct spa_type_table_data *td = s_tables + i; - g_clear_pointer (&td->info_array, g_ptr_array_unref); - g_clear_pointer (&td->id_table, g_hash_table_unref); - g_clear_pointer (&td->nick_table, g_hash_table_unref); + g_return_val_if_fail (table != NULL, NULL); + + WpIterator *it = wp_iterator_new (&spa_type_info_iterator_methods, + sizeof (struct spa_type_info_iterator_data)); + struct spa_type_info_iterator_data *it_data = wp_iterator_get_user_data (it); + it_data->base = (const struct spa_type_info *) table; + it_data->cur = it_data->base; + return it; +} + +WpSpaIdValue +wp_spa_id_table_find_value (WpSpaIdTable table, guint value) +{ + g_return_val_if_fail (table != NULL, NULL); + + const struct spa_type_info *info = table; + while (info && info->name) { + if (info->type == value) + return info; + info++; + } + return NULL; +} + +WpSpaIdValue +wp_spa_id_table_find_value_from_name (WpSpaIdTable table, const gchar * name) +{ + g_return_val_if_fail (table != NULL, NULL); + + const struct spa_type_info *info = table; + while (info && info->name) { + if (!strcmp (info->name, name)) + return info; + info++; } + return NULL; +} + +WpSpaIdValue +wp_spa_id_table_find_value_from_short_name (WpSpaIdTable table, + const gchar * short_name) +{ + g_return_val_if_fail (table != NULL, NULL); + + const struct spa_type_info *info = table; + while (info && info->name) { + if (!strcmp (spa_debug_type_short_name (info->name), short_name)) + return info; + info++; + } + return NULL; +} + + +static WpSpaIdTable +wp_spa_id_name_find_id_table (const gchar * name) +{ + WpSpaIdTable table = NULL; + g_autofree gchar *parent_name = g_strdup (name); + gchar *h; + + if ((h = strrchr(parent_name, ':')) != NULL) { + /* chop the enum name to get the type, ex: + Spa:Enum:Direction:Input -> Spa:Enum:Direction */ + *h = '\0'; + table = wp_spa_id_table_from_name (parent_name); + + /* in some cases, the parent name is one layer further up, ex: + Spa:Pod:Object:Param:Format:Audio:rate -> Spa:Pod:Object:Param:Format */ + if (!table && (h = strrchr(parent_name, ':')) != NULL) { + *h = '\0'; + table = wp_spa_id_table_from_name (parent_name); + } + } + return table; } /** - * wp_spa_type_get_table_size: - * @table: the table + * wp_spa_id_value_from_name: + * @name: the full name of an id value * - * Gets the number of registered types in a given table + * Looks up an id value (enum, flag or object field) directly from its full + * name. For instance, "Spa:Enum:Direction:Input" will resolve to the + * id value that represents "Input" in the "Spa:Enum:Direction" enum. * - * Returns: The number of registered types + * Returns: the id value for @name, or %NULL if no such id value was found */ -size_t -wp_spa_type_get_table_size (WpSpaTypeTable table) +WpSpaIdValue +wp_spa_id_value_from_name (const gchar * name) { - struct spa_type_table_data *td = NULL; + g_return_val_if_fail (name != NULL, NULL); - g_return_val_if_fail (table < WP_SPA_TYPE_TABLE_LAST, 0); + WpSpaIdTable table = wp_spa_id_name_find_id_table (name); + return wp_spa_id_table_find_value_from_name (table, name); +} - /* Get the table data */ - td = s_tables + table; +/** + * wp_spa_id_value_from_short_name: + * @table_name: the name of the #WpSpaIdTable to look up the value in + * @short_name: the short name of the value to look up + * + * Looks up an id value given its container @table_name and its @short_name + * + * Returns: the id value or %NULL if it was not found + */ +WpSpaIdValue +wp_spa_id_value_from_short_name (const gchar * table_name, + const gchar * short_name) +{ + g_return_val_if_fail (table_name != NULL, NULL); + g_return_val_if_fail (short_name != NULL, NULL); - return td->info_array->len; + WpSpaIdTable table = wp_spa_id_table_from_name (table_name); + return wp_spa_id_table_find_value_from_short_name (table, short_name); } /** - * wp_spa_type_register: - * @table: the table - * @name: the name of the type - * @nick: the nick name of the type + * wp_spa_id_value_from_number: + * @table_name: the name of the #WpSpaIdTable to look up the value in + * @id: the numeric representation of the value to look up * - * Registers a type name with a nickname in the registry + * Looks up an id value given its container @table_name and its numeric + * representation, @id * - * Returns: TRUE if the type could be registered, FALSE otherwise + * Returns: the id value or %NULL if it was not found */ -gboolean -wp_spa_type_register (WpSpaTypeTable table, const char *name, const char *nick) -{ - struct spa_type_table_data *td = NULL; - const struct spa_type_info *spa_info = NULL; - struct type_info *info = NULL; - guint32 id; - - g_return_val_if_fail (table < WP_SPA_TYPE_TABLE_LAST, FALSE); - g_return_val_if_fail (name, FALSE); - g_return_val_if_fail (nick, FALSE); - - /* Get the table data */ - td = s_tables + table; - - /* Return false if the nick already exists in the nick table */ - if (g_hash_table_contains (td->nick_table, nick)) - return FALSE; - - /* Add the type in the custom table */ - spa_info = spa_type_find_by_name (td->spa_table, name); - if (spa_info) { - id = spa_info->type; - info = type_info_new_spa (spa_info, nick); - } else { - id = ++td->last_id; - info = type_info_new_custom (id, name, nick); - } - g_ptr_array_add (td->info_array, info); +WpSpaIdValue +wp_spa_id_value_from_number (const gchar * table_name, guint id) +{ + g_return_val_if_fail (table_name != NULL, NULL); - /* Insert the id and nick in the hash tables */ - return g_hash_table_insert (td->id_table, GUINT_TO_POINTER (id), info) && - g_hash_table_insert (td->nick_table, g_strdup (nick), info); + WpSpaIdTable table = wp_spa_id_table_from_name (table_name); + return wp_spa_id_table_find_value (table, id); } /** - * wp_spa_type_unregister: - * @table: the table - * @nick: the nick name of the type + * wp_spa_id_value_number: + * @id: an id value * - * Unregisters a type given its nick name + * Returns: the numeric representation of this id value */ -void -wp_spa_type_unregister (WpSpaTypeTable table, const char *nick) +guint +wp_spa_id_value_number (WpSpaIdValue id) { - struct spa_type_table_data *td = NULL; - struct type_info *info = NULL; - guint32 id; - - g_return_if_fail (table < WP_SPA_TYPE_TABLE_LAST); - g_return_if_fail (nick); + g_return_val_if_fail (id != NULL, -1); - /* Get the table data */ - td = s_tables + table; + const struct spa_type_info *info = id; + return info->type; +} - /* Lookup the info by nick */ - info = g_hash_table_lookup (td->nick_table, nick); - if (!info) - return; +/** + * wp_spa_id_value_name: + * @id: an id value + * + * Returns: the full name of this id value + */ +const gchar * +wp_spa_id_value_name (WpSpaIdValue id) +{ + g_return_val_if_fail (id != NULL, NULL); - /* Get id */ - id = info->is_spa_type ? info->info.spa->type : info->info.custom.type; + const struct spa_type_info *info = id; + return info->name; +} - /* Remove info from hash tables */ - g_hash_table_remove (td->nick_table, nick); - g_hash_table_remove (td->id_table, GUINT_TO_POINTER (id)); +/** + * wp_spa_id_value_short_name: + * @id: an id value + * + * Returns: the short name of this id value + */ +const gchar * +wp_spa_id_value_short_name (WpSpaIdValue id) +{ + g_return_val_if_fail (id != NULL, NULL); - /* Remove info from array */ - g_ptr_array_remove_fast (td->info_array, info); + const struct spa_type_info *info = id; + return spa_debug_type_short_name (info->name); } /** - * wp_spa_type_get_by_nick: - * @table: the table - * @nick: the nick name of the type - * @id: (out) (optional): the id of the type - * @name: (out) (optional): the name of the type - * @values_table: (out) (optional): the values table of the type + * wp_spa_id_value_get_value_type + * @id: an id value + * @table: (out) (optional): the associated #WpSpaIdTable + * + * Returns the value type associated with this #WpSpaIdValue. This information + * is useful when @id represents an object field, which can take a value + * of an arbitrary type. * - * Gets the id and name of the registered type given its nick name + * When the returned type is (or is derived from) `SPA_TYPE_Id` or + * `SPA_TYPE_Object`, @table is set to point to the #WpSpaIdTable that contains + * the possible Id values / object fields. * - * Returns: TRUE if the type was found, FALSE otherwise + * Returns: the value type associated with @id */ -gboolean -wp_spa_type_get_by_nick (WpSpaTypeTable table, const char *nick, - guint32 *id, const char **name, WpSpaTypeTable *values_table) +WpSpaType +wp_spa_id_value_get_value_type (WpSpaIdValue id, WpSpaIdTable * table) { - struct spa_type_table_data *td = NULL; - const struct type_info *info = NULL; + g_return_val_if_fail (id != NULL, WP_SPA_TYPE_INVALID); - g_return_val_if_fail (table < WP_SPA_TYPE_TABLE_LAST, FALSE); + const struct spa_type_info *info = id; - /* Make sure nick is valid */ - if (!nick) - return FALSE; + if (table) { + /* info->values has different semantics on Array types */ + if (info->values && info->parent != SPA_TYPE_Array) { + *table = info->values; + } + /* derived object types normally don't have info->values directly set, + so we need to look them up */ + else if (wp_spa_type_is_object (info->parent)) { + WpSpaIdTable t = wp_spa_type_get_values_table (info->parent); + if (t) *table = t; + } + } + + return info->parent; +} - /* Get the table data */ - td = s_tables + table; +/** + * wp_spa_id_value_array_get_item_type: + * @id: an id value + * @table: (out) (optional): the associated #WpSpaIdTable + * + * If the value type of @id is `SPA_TYPE_Array`, this function returns the + * type that is allowed to be contained inside the array. + * + * When the returned type is (or is derived from) `SPA_TYPE_Id` or + * `SPA_TYPE_Object`, @table is set to point to the #WpSpaIdTable that contains + * the possible Id values / object fields. + * + * Returns: the type that is allowed in the array, if @id represents + * an object field that takes an array as value + */ +WpSpaType +wp_spa_id_value_array_get_item_type (WpSpaIdValue id, WpSpaIdTable * table) +{ + g_return_val_if_fail (id != NULL, WP_SPA_TYPE_INVALID); - /* Lookup the info by nick */ - info = g_hash_table_lookup (td->nick_table, nick); - if (!info) - return FALSE; + const struct spa_type_info *info = id; + g_return_val_if_fail (info->parent == SPA_TYPE_Array, WP_SPA_TYPE_INVALID); - if (id) - *id = info->is_spa_type ? info->info.spa->type : info->info.custom.type; - if (name) - *name = info->is_spa_type ? info->info.spa->name : info->info.custom.name; - if (values_table && info->is_spa_type) - *values_table = wp_spa_type_table_find_by_spa_table (info->info.spa->values); - return TRUE; + return info->values ? + wp_spa_id_value_get_value_type (info->values, table) : + WP_SPA_TYPE_INVALID; } + /** - * wp_spa_type_get_by_id: - * @table: the table - * @id: the id of the type - * @name: (out) (optional): the name of the type - * @nick: (out) (optional): the nick name of the type - * @values_table: (out) (optional): the values table of the type + * wp_spa_dynamic_type_init: * - * Gets the name and nick name of the registered type given its id + * Initializes the spa dynamic type registry. + * This allows registering new spa types at runtime. The spa type system + * still works if this function is not called. * - * Returns: TRUE if the type was found, FALSE otherwise + * Normally called by wp_init() when %WP_INIT_SPA_TYPES is passed in its flags. */ -gboolean -wp_spa_type_get_by_id (WpSpaTypeTable table, guint32 id, - const char **name, const char **nick, WpSpaTypeTable *values_table) +void +wp_spa_dynamic_type_init (void) { - struct spa_type_table_data *td = NULL; - const struct type_info *info = NULL; - - g_return_val_if_fail (table < WP_SPA_TYPE_TABLE_LAST, FALSE); + extra_types = g_array_new (TRUE, FALSE, sizeof (struct spa_type_info)); + extra_id_tables = g_array_new (TRUE, FALSE, sizeof (WpSpaIdTableInfo)); + + /* init to chain up to spa types */ + struct spa_type_info info = { + SPA_ID_INVALID, SPA_ID_INVALID, "spa_types", SPA_TYPE_ROOT + }; + g_array_append_val (extra_types, info); +} - /* Get the table data */ - td = s_tables + table; +/** + * wp_spa_dynamic_type_deinit: + * + * Deinitializes the spa type registry. + * You do not need to ever call this, unless you want to free memory at the + * end of the execution of a test, so that it doesn't show as leaked in + * the memory profiler. + */ +void +wp_spa_dynamic_type_deinit (void) +{ + g_clear_pointer (&extra_types, g_array_unref); + g_clear_pointer (&extra_id_tables, g_array_unref); +} - /* Lookup the info by id */ - info = g_hash_table_lookup (td->id_table, GUINT_TO_POINTER (id)); - if (!info) - return FALSE; +/** + * wp_spa_dynamic_type_register: + * @name: the name of the type + * @parent: the parent type + * @values: an array of `spa_type_info` that contains the values of the type, + * used only for Object types + * + * Registers an additional type in the spa type system. + * This is useful to add a custom pod object type. + * + * Note that both @name and @values must be statically allocated, or + * otherwise guaranteed to be kept in memory until wp_spa_dynamic_type_deinit() + * is called. No memory copy is done by this function. + * + * Returns: the new type + */ +WpSpaType +wp_spa_dynamic_type_register (const gchar *name, WpSpaType parent, + const struct spa_type_info * values) +{ + struct spa_type_info info; + info.type = SPA_TYPE_VENDOR_WirePlumber + extra_types->len; + info.name = name; + info.parent = parent; + info.values = values; + g_array_append_val (extra_types, info); + return info.type; +} - if (name) - *name = info->is_spa_type ? info->info.spa->name : info->info.custom.name; - if (nick) - *nick = info->nick; - if (values_table && info->is_spa_type) - *values_table = wp_spa_type_table_find_by_spa_table (info->info.spa->values); - return TRUE; +/** + * wp_spa_dynamic_id_table_register: + * @name: the name of the id table + * @values: an array of `spa_type_info` that contains the values of the table + * + * Registers an additional #WpSpaIdTable in the spa type system. + * This is useful to add custom enumeration types. + * + * Note that both @name and @values must be statically allocated, or + * otherwise guaranteed to be kept in memory until wp_spa_dynamic_type_deinit() + * is called. No memory copy is done by this function. + * + * Returns: the new table + */ +WpSpaIdTable +wp_spa_dynamic_id_table_register (const gchar *name, + const struct spa_type_info * values) +{ + WpSpaIdTableInfo info; + info.name = name; + info.values = values; + g_array_append_val (extra_id_tables, info); + return values; } diff --git a/lib/wp/spa-type.h b/lib/wp/spa-type.h index 41ea40d1..2a85fe91 100644 --- a/lib/wp/spa-type.h +++ b/lib/wp/spa-type.h @@ -9,63 +9,121 @@ #ifndef __WIREPLUMBER_SPA_TYPE_H__ #define __WIREPLUMBER_SPA_TYPE_H__ -#include <gio/gio.h> #include "defs.h" +#include "iterator.h" G_BEGIN_DECLS -/** - * WpSpaTypeTable: - * @WP_SPA_TYPE_TABLE_BASIC: The basic type table - * @WP_SPA_TYPE_TABLE_PARAM: The param type table (used as object id) - * @WP_SPA_TYPE_TABLE_PROPS: The object properties type table - * @WP_SPA_TYPE_TABLE_PROP_INFO: The object property info type table - * @WP_SPA_TYPE_TABLE_CONTROL: The sequence control type table - * @WP_SPA_TYPE_TABLE_CHOICE: The choice type table - * @WP_SPA_TYPE_TABLE_FORMAT: The object format type table - * @WP_SPA_TYPE_TABLE_PARAM_PORT_CONFIG: The object param port config type table - * @WP_SPA_TYPE_TABLE_PARAM_PROFILE: The sequence control type table - * @WP_SPA_TYPE_TABLE_AUDIO_CHANNEL: The audio channel type table - * - * The diferent tables (namespaces) the registry has. - */ -typedef enum { - WP_SPA_TYPE_TABLE_BASIC = 0, - WP_SPA_TYPE_TABLE_PARAM, - WP_SPA_TYPE_TABLE_PROPS, - WP_SPA_TYPE_TABLE_PROP_INFO, - WP_SPA_TYPE_TABLE_CONTROL, - WP_SPA_TYPE_TABLE_CHOICE, - WP_SPA_TYPE_TABLE_FORMAT, - WP_SPA_TYPE_TABLE_PARAM_PORT_CONFIG, - WP_SPA_TYPE_TABLE_PARAM_PROFILE, - WP_SPA_TYPE_TABLE_AUDIO_CHANNEL, - WP_SPA_TYPE_TABLE_LAST, -} WpSpaTypeTable; +typedef guint32 WpSpaType; +typedef gconstpointer WpSpaIdTable; +typedef gconstpointer WpSpaIdValue; +struct spa_type_info; + +/* WpSpaType */ + +#define WP_TYPE_SPA_TYPE (wp_spa_type_get_type ()) +WP_API +GType wp_spa_type_get_type (void); + +static const WpSpaType WP_SPA_TYPE_INVALID = 0xffffffff; + +WP_API +WpSpaType wp_spa_type_from_name (const gchar *name); + +WP_API +WpSpaType wp_spa_type_parent (WpSpaType type); + +WP_API +const gchar * wp_spa_type_name (WpSpaType type); + +WP_API +gboolean wp_spa_type_is_fundamental (WpSpaType type); + +WP_API +gboolean wp_spa_type_is_id (WpSpaType type); + +WP_API +gboolean wp_spa_type_is_object (WpSpaType type); + +WP_API +WpSpaIdTable wp_spa_type_get_object_id_values_table (WpSpaType type); + +WP_API +WpSpaIdTable wp_spa_type_get_values_table (WpSpaType type); + + +/* WpSpaIdTable */ + +#define WP_TYPE_SPA_ID_TABLE (wp_spa_id_table_get_type ()) +WP_API +GType wp_spa_id_table_get_type (void); WP_API -void wp_spa_type_init (gboolean register_spa); +WpSpaIdTable wp_spa_id_table_from_name (const gchar *name); WP_API -void wp_spa_type_deinit (void); +WpIterator * wp_spa_id_table_iterate (WpSpaIdTable table); WP_API -size_t wp_spa_type_get_table_size (WpSpaTypeTable table); +WpSpaIdValue wp_spa_id_table_find_value (WpSpaIdTable table, guint value); + +WP_API +WpSpaIdValue wp_spa_id_table_find_value_from_name (WpSpaIdTable table, + const gchar * name); + +WP_API +WpSpaIdValue wp_spa_id_table_find_value_from_short_name (WpSpaIdTable table, + const gchar * short_name); + + +/* WpSpaIdValue */ + +#define WP_TYPE_SPA_ID_VALUE (wp_spa_id_value_get_type ()) +WP_API +GType wp_spa_id_value_get_type (void); + +WP_API +WpSpaIdValue wp_spa_id_value_from_name (const gchar * name); + +WP_API +WpSpaIdValue wp_spa_id_value_from_short_name (const gchar * table_name, + const gchar * short_name); + +WP_API +WpSpaIdValue wp_spa_id_value_from_number (const gchar * table_name, guint id); + +WP_API +guint wp_spa_id_value_number (WpSpaIdValue id); + +WP_API +const gchar * wp_spa_id_value_name (WpSpaIdValue id); + +WP_API +const gchar * wp_spa_id_value_short_name (WpSpaIdValue id); + +WP_API +WpSpaType wp_spa_id_value_get_value_type (WpSpaIdValue id, WpSpaIdTable *table); + +WP_API +WpSpaType wp_spa_id_value_array_get_item_type (WpSpaIdValue id, + WpSpaIdTable *table); + + +/* Dynamic type registration */ WP_API -gboolean wp_spa_type_register (WpSpaTypeTable table, const char *name, - const char *nick); +void wp_spa_dynamic_type_init (void); WP_API -void wp_spa_type_unregister (WpSpaTypeTable table, const char *nick); +void wp_spa_dynamic_type_deinit (void); WP_API -gboolean wp_spa_type_get_by_nick (WpSpaTypeTable table, const char *nick, - guint32 *id, const char **name, WpSpaTypeTable *values_table); +WpSpaType wp_spa_dynamic_type_register (const gchar *name, WpSpaType parent, + const struct spa_type_info * values); WP_API -gboolean wp_spa_type_get_by_id (WpSpaTypeTable table, guint32 id, - const char **name, const char **nick, WpSpaTypeTable *values_table); +WpSpaIdTable wp_spa_dynamic_id_table_register (const gchar *name, + const struct spa_type_info * values); G_END_DECLS diff --git a/lib/wp/wp.c b/lib/wp/wp.c index 8a3ad8e1..be23c739 100644 --- a/lib/wp/wp.c +++ b/lib/wp/wp.c @@ -63,7 +63,7 @@ wp_init (WpInitFlags flags) pw_log_set_level (lvl); if (flags & WP_INIT_SPA_TYPES) - wp_spa_type_init (TRUE); + wp_spa_dynamic_type_init (); /* ensure WpProxy subclasses are loaded, which is needed to be able to autodetect the GType of proxies created through wp_proxy_new_global() */ diff --git a/modules/module-dbus-reservation/reserve-device.c b/modules/module-dbus-reservation/reserve-device.c index 6b872e40..73db0add 100644 --- a/modules/module-dbus-reservation/reserve-device.c +++ b/modules/module-dbus-reservation/reserve-device.c @@ -42,7 +42,7 @@ set_device_profile (WpPipewireObject *device, gint index) { g_return_if_fail (device); g_autoptr (WpSpaPod) profile = wp_spa_pod_new_object ( - "Profile", "Profile", + "Spa:Pod:Object:Param:Profile", "Profile", "index", "i", index, NULL); wp_debug_object (device, "set profile %d", index); diff --git a/modules/module-default-profile.c b/modules/module-default-profile.c index 35da6761..7cda94e2 100644 --- a/modules/module-default-profile.c +++ b/modules/module-default-profile.c @@ -63,8 +63,7 @@ find_device_profile (WpPipewireObject *device, const gchar *lookup_name) const gchar *name = NULL; /* Parse */ - if (!wp_spa_pod_get_object (pod, - "Profile", NULL, + if (!wp_spa_pod_get_object (pod, NULL, "index", "i", &index, "name", "s", &name, NULL)) { @@ -191,8 +190,7 @@ on_device_profile_notified (WpPipewireObject *device, GAsyncResult *res, /* Parse the profile */ WpSpaPod *pod = g_value_get_boxed (&item); - if (!wp_spa_pod_get_object (pod, - "Profile", NULL, + if (!wp_spa_pod_get_object (pod, NULL, "index", "i", &index, "name", "s", &name, NULL)) { diff --git a/modules/module-device-activation.c b/modules/module-device-activation.c index 2c704427..d0c0c781 100644 --- a/modules/module-device-activation.c +++ b/modules/module-device-activation.c @@ -34,7 +34,7 @@ set_device_profile (WpDeviceActivation *self, /* Set profile */ wp_pipewire_object_set_param (device, "Profile", 0, wp_spa_pod_new_object ( - "Profile", "Profile", + "Spa:Pod:Object:Param:Profile", "Profile", "index", "i", index, NULL)); @@ -72,8 +72,7 @@ on_device_enum_profile_done (WpPipewireObject *proxy, GAsyncResult *res, const gchar *n = NULL; /* Parse */ - if (!wp_spa_pod_get_object (pod, - "Profile", NULL, + if (!wp_spa_pod_get_object (pod, NULL, "index", "i", &i, "name", "s", &n, NULL)) { diff --git a/modules/module-endpoint-creation/limited-creation-bluez5.c b/modules/module-endpoint-creation/limited-creation-bluez5.c index 47ca635c..3ab8bb00 100644 --- a/modules/module-endpoint-creation/limited-creation-bluez5.c +++ b/modules/module-endpoint-creation/limited-creation-bluez5.c @@ -207,8 +207,7 @@ on_device_enum_profile_done (WpPipewireObject *proxy, GAsyncResult *res, /* Parse profile */ { - g_autoptr (WpSpaPodParser) pp = wp_spa_pod_parser_new_object (pod, - "Profile", NULL); + g_autoptr (WpSpaPodParser) pp = wp_spa_pod_parser_new_object (pod, NULL); g_return_if_fail (pp); g_return_if_fail (wp_spa_pod_parser_get (pp, "index", "i", &index, NULL)); if (index == 0) { diff --git a/modules/module-si-adapter.c b/modules/module-si-adapter.c index 33ac017a..c09d0826 100644 --- a/modules/module-si-adapter.c +++ b/modules/module-si-adapter.c @@ -259,7 +259,7 @@ static WpSpaPod * format_audio_raw_build (const struct spa_audio_info_raw *info) { g_autoptr (WpSpaPodBuilder) builder = wp_spa_pod_builder_new_object ( - "Format", "Format"); + "Spa:Pod:Object:Param:Format", "Format"); wp_spa_pod_builder_add (builder, "mediaType", "I", SPA_MEDIA_TYPE_audio, "mediaSubtype", "I", SPA_MEDIA_SUBTYPE_raw, @@ -327,7 +327,8 @@ si_adapter_activate_execute_step (WpSessionItem * item, self->format.channels, self->format.rate); port_format = format_audio_raw_build (&self->format); - pod = wp_spa_pod_new_object ("PortConfig", "PortConfig", + pod = wp_spa_pod_new_object ( + "Spa:Pod:Object:Param:PortConfig", "PortConfig", "direction", "I", self->direction, "mode", "I", SPA_PARAM_PORT_CONFIG_MODE_dsp, "monitor", "b", self->monitor, @@ -543,8 +544,12 @@ si_adapter_get_ports (WpSiPortInfo * item, const gchar * context) /* try to find the audio channel; if channel is NULL, this will silently leave the channel_id to its default value, 0 */ channel = wp_properties_get (props, PW_KEY_AUDIO_CHANNEL); - wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_AUDIO_CHANNEL, channel, - &channel_id, NULL, NULL); + if (channel) { + WpSpaIdValue idval = wp_spa_id_value_from_short_name ( + "Spa:Enum:AudioChannel", channel); + if (idval) + channel_id = wp_spa_id_value_number (idval); + } g_variant_builder_add (&b, "(uuu)", node_id, port_id, channel_id); } diff --git a/modules/module-si-adapter/algorithms.c b/modules/module-si-adapter/algorithms.c index 052f3c9c..592ea888 100644 --- a/modules/module-si-adapter/algorithms.c +++ b/modules/module-si-adapter/algorithms.c @@ -84,16 +84,17 @@ select_format (WpSpaPod *value) return ret; } - const gchar * choice_type_name = wp_spa_pod_get_choice_type_name (value); + guint32 choice_type = + wp_spa_id_value_number (wp_spa_pod_get_choice_type (value)); /* None */ - if (g_strcmp0 ("None", choice_type_name) == 0) { + if (choice_type == SPA_CHOICE_None) { g_autoptr (WpSpaPod) child = wp_spa_pod_get_choice_child (value); wp_spa_pod_get_id (child, &ret); } /* Enum */ - else if (g_strcmp0 ("Enum", choice_type_name) == 0) { + else if (choice_type == SPA_CHOICE_Enum) { g_autoptr (WpIterator) it = wp_spa_pod_iterate (value); GValue next = G_VALUE_INIT; while (wp_iterator_next (it, &next)) { @@ -125,16 +126,17 @@ select_rate (WpSpaPod *value) return ret; } - const gchar * choice_type_name = wp_spa_pod_get_choice_type_name (value); + guint32 choice_type = + wp_spa_id_value_number (wp_spa_pod_get_choice_type (value)); /* None */ - if (g_strcmp0 ("None", choice_type_name) == 0) { + if (choice_type == SPA_CHOICE_None) { g_autoptr (WpSpaPod) child = wp_spa_pod_get_choice_child (value); wp_spa_pod_get_int (child, &ret); } /* Enum */ - else if (g_strcmp0 ("Enum", choice_type_name) == 0) { + else if (choice_type == SPA_CHOICE_Enum) { /* pick the one closest to 48Khz */ g_autoptr (WpIterator) it = wp_spa_pod_iterate (value); GValue next = G_VALUE_INIT; @@ -147,7 +149,7 @@ select_rate (WpSpaPod *value) } /* Range */ - else if (g_strcmp0 ("Range", choice_type_name) == 0) { + else if (choice_type == SPA_CHOICE_Range) { /* a range is typically 3 items: default, min, max; however, sometimes ALSA drivers give bad min & max values and pipewire picks a bad default... try to fix that here; @@ -180,16 +182,17 @@ select_channels (WpSpaPod *value, gint preference) return ret; } - const gchar * choice_type_name = wp_spa_pod_get_choice_type_name (value); + guint32 choice_type = + wp_spa_id_value_number (wp_spa_pod_get_choice_type (value)); /* None */ - if (g_strcmp0 ("None", choice_type_name) == 0) { + if (choice_type == SPA_CHOICE_None) { g_autoptr (WpSpaPod) child = wp_spa_pod_get_choice_child (value); wp_spa_pod_get_int (child, &ret); } /* Enum */ - else if (g_strcmp0 ("Enum", choice_type_name) == 0) { + else if (choice_type == SPA_CHOICE_Enum) { /* choose the most channels */ g_autoptr (WpIterator) it = wp_spa_pod_iterate (value); GValue next = G_VALUE_INIT; @@ -205,7 +208,7 @@ select_channels (WpSpaPod *value, gint preference) } /* Range */ - else if (g_strcmp0 ("Range", choice_type_name) == 0) { + else if (choice_type == SPA_CHOICE_Range) { /* a range is typically 3 items: default, min, max; we want the most channels, but let's not trust max to really be the max... ALSA drivers can be broken */ @@ -247,8 +250,7 @@ choose_sensible_raw_audio_format (WpIterator *formats, continue; } - if (!wp_spa_pod_get_object (pod, - "Format", NULL, + if (!wp_spa_pod_get_object (pod, NULL, "mediaType", "I", &mtype, "mediaSubtype", "I", &mstype, NULL)) { diff --git a/modules/module-si-bluez5-endpoint.c b/modules/module-si-bluez5-endpoint.c index c3647a06..f8160dc5 100644 --- a/modules/module-si-bluez5-endpoint.c +++ b/modules/module-si-bluez5-endpoint.c @@ -453,7 +453,7 @@ set_device_profile (WpDevice *device, gint index) { g_return_if_fail (device); g_autoptr (WpSpaPod) profile = wp_spa_pod_new_object ( - "Profile", "Profile", + "Spa:Pod:Object:Param:Profile", "Profile", "index", "i", index, NULL); wp_pipewire_object_set_param (WP_PIPEWIRE_OBJECT (device), diff --git a/modules/module-si-convert.c b/modules/module-si-convert.c index a6da805c..5b8017ab 100644 --- a/modules/module-si-convert.c +++ b/modules/module-si-convert.c @@ -288,7 +288,7 @@ si_convert_activate_execute_step (WpSessionItem * item, g_steal_pointer (&props)); format = wp_spa_pod_new_object ( - "Format", "Format", + "Spa:Pod:Object:Param:Format", "Format", "mediaType", "I", SPA_MEDIA_TYPE_audio, "mediaSubtype", "I", SPA_MEDIA_SUBTYPE_raw, "format", "I", SPA_AUDIO_FORMAT_F32P, @@ -303,7 +303,8 @@ si_convert_activate_execute_step (WpSessionItem * item, as doing merge + split is heavy for our needs */ wp_pipewire_object_set_param (WP_PIPEWIRE_OBJECT (self->node), "PortConfig", 0, - wp_spa_pod_new_object ("PortConfig", "PortConfig", + wp_spa_pod_new_object ( + "Spa:Pod:Object:Param:PortConfig", "PortConfig", "direction", "I", pw_direction_reverse (self->direction), "mode", "I", SPA_PARAM_PORT_CONFIG_MODE_dsp, "format", "P", format, @@ -311,7 +312,8 @@ si_convert_activate_execute_step (WpSessionItem * item, wp_pipewire_object_set_param (WP_PIPEWIRE_OBJECT (self->node), "PortConfig", 0, - wp_spa_pod_new_object ("PortConfig", "PortConfig", + wp_spa_pod_new_object ( + "Spa:Pod:Object:Param:PortConfig", "PortConfig", "direction", "I", self->direction, "mode", "I", SPA_PARAM_PORT_CONFIG_MODE_dsp, "control", "b", self->control_port, @@ -460,8 +462,12 @@ si_convert_get_ports (WpSiPortInfo * item, const gchar * context) leave the channel_id to its default value, 0 */ props = wp_pipewire_object_get_properties (WP_PIPEWIRE_OBJECT (port)); channel = wp_properties_get (props, PW_KEY_AUDIO_CHANNEL); - wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_AUDIO_CHANNEL, channel, - &channel_id, NULL, NULL); + if (channel) { + WpSpaIdValue idval = wp_spa_id_value_from_short_name ( + "Spa:Enum:AudioChannel", channel); + if (idval) + channel_id = wp_spa_id_value_number (idval); + } g_variant_builder_add (&b, "(uuu)", node_id, port_id, channel_id); } diff --git a/modules/module-si-simple-node-endpoint.c b/modules/module-si-simple-node-endpoint.c index 992925e4..ac264be4 100644 --- a/modules/module-si-simple-node-endpoint.c +++ b/modules/module-si-simple-node-endpoint.c @@ -396,8 +396,12 @@ si_simple_node_endpoint_get_ports (WpSiPortInfo * item, const gchar * context) /* try to find the audio channel; if channel is NULL, this will silently leave the channel_id to its default value, 0 */ channel = wp_properties_get (props, PW_KEY_AUDIO_CHANNEL); - wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_AUDIO_CHANNEL, channel, - &channel_id, NULL, NULL); + if (channel) { + WpSpaIdValue idval = wp_spa_id_value_from_short_name ( + "Spa:Enum:AudioChannel", channel); + if (idval) + channel_id = wp_spa_id_value_number (idval); + } g_variant_builder_add (&b, "(uuu)", node_id, port_id, channel_id); } diff --git a/tests/modules/algorithms.c b/tests/modules/algorithms.c index 130961d6..a61edd5e 100644 --- a/tests/modules/algorithms.c +++ b/tests/modules/algorithms.c @@ -19,8 +19,6 @@ static void test_choose_sensible_raw_audio_format (void) { - wp_spa_type_init (TRUE); - uint32_t layout[] = { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR }; @@ -31,7 +29,7 @@ test_choose_sensible_raw_audio_format (void) { g_ptr_array_remove_range (formats, 0, formats->len); g_autoptr (WpSpaPod) param1 = wp_spa_pod_new_object ( - "Format", "Format", + "Spa:Pod:Object:Param:Format", "Format", "mediaType", SPA_POD_Id(SPA_MEDIA_TYPE_audio), "mediaSubtype", SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), "format", SPA_POD_CHOICE_ENUM_Id(3, @@ -56,7 +54,7 @@ test_choose_sensible_raw_audio_format (void) { g_ptr_array_remove_range (formats, 0, formats->len); g_autoptr (WpSpaPod) param1 = wp_spa_pod_new_object ( - "Format", "Format", + "Spa:Pod:Object:Param:Format", "Format", "mediaType", SPA_POD_Id(SPA_MEDIA_TYPE_audio), "mediaSubtype", SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), "format", SPA_POD_CHOICE_ENUM_Id(3, @@ -81,7 +79,7 @@ test_choose_sensible_raw_audio_format (void) { g_ptr_array_remove_range (formats, 0, formats->len); g_autoptr (WpSpaPod) param2 = wp_spa_pod_new_object ( - "Format", "Format", + "Spa:Pod:Object:Param:Format", "Format", "mediaType", SPA_POD_Id(SPA_MEDIA_TYPE_audio), "mediaSubtype", SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), "format", SPA_POD_CHOICE_ENUM_Id(3, @@ -95,7 +93,7 @@ test_choose_sensible_raw_audio_format (void) g_assert_nonnull (param2); g_ptr_array_add (formats, g_steal_pointer (¶m2)); g_autoptr (WpSpaPod) param3 = wp_spa_pod_new_object ( - "Format", "Format", + "Spa:Pod:Object:Param:Format", "Format", "mediaType", SPA_POD_Id(SPA_MEDIA_TYPE_audio), "mediaSubtype", SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), "format", SPA_POD_CHOICE_ENUM_Id(3, @@ -123,8 +121,6 @@ test_choose_sensible_raw_audio_format (void) g_assert_cmpint (info.position[4], ==, layout[4]); g_assert_cmpint (info.position[5], ==, 0); } - - wp_spa_type_deinit (); } int diff --git a/tests/wp/endpoint.c b/tests/wp/endpoint.c index 0b5bb380..7847b00c 100644 --- a/tests/wp/endpoint.c +++ b/tests/wp/endpoint.c @@ -527,7 +527,7 @@ test_endpoint_with_props (TestEndpointFixture *fixture, gconstpointer data) g_assert_true (wp_iterator_next (iterator, &item)); g_assert_nonnull ((pod = g_value_dup_boxed (&item))); - g_assert_true (wp_spa_pod_get_object (pod, "Props", NULL, + g_assert_true (wp_spa_pod_get_object (pod, NULL, "volume", "f", &float_value, "mute", "b", &boolean_value, NULL)); @@ -547,7 +547,7 @@ test_endpoint_with_props (TestEndpointFixture *fixture, gconstpointer data) fixture->n_events = 0; wp_pipewire_object_set_param (WP_PIPEWIRE_OBJECT (fixture->proxy_endpoint), "Props", 0, - wp_spa_pod_new_object ("Props", "Props", + wp_spa_pod_new_object ("Spa:Pod:Object:Param:Props", "Props", "volume", "f", 0.7f, NULL)); /* run until the change is on all sides */ @@ -569,7 +569,7 @@ test_endpoint_with_props (TestEndpointFixture *fixture, gconstpointer data) g_assert_true (wp_iterator_next (iterator, &item)); g_assert_nonnull ((pod = g_value_dup_boxed (&item))); - g_assert_true (wp_spa_pod_get_object (pod, "Props", NULL, + g_assert_true (wp_spa_pod_get_object (pod, NULL, "volume", "f", &float_value, "mute", "b", &boolean_value, NULL)); @@ -590,7 +590,7 @@ test_endpoint_with_props (TestEndpointFixture *fixture, gconstpointer data) g_assert_true (wp_iterator_next (iterator, &item)); g_assert_nonnull ((pod = g_value_dup_boxed (&item))); - g_assert_true (wp_spa_pod_get_object (pod, "Props", NULL, + g_assert_true (wp_spa_pod_get_object (pod, NULL, "volume", "f", &float_value, "mute", "b", &boolean_value, NULL)); @@ -611,7 +611,7 @@ test_endpoint_with_props (TestEndpointFixture *fixture, gconstpointer data) g_assert_true (wp_iterator_next (iterator, &item)); g_assert_nonnull ((pod = g_value_dup_boxed (&item))); - g_assert_true (wp_spa_pod_get_object (pod, "Props", NULL, + g_assert_true (wp_spa_pod_get_object (pod, NULL, "volume", "f", &float_value, "mute", "b", &boolean_value, NULL)); @@ -623,7 +623,7 @@ test_endpoint_with_props (TestEndpointFixture *fixture, gconstpointer data) fixture->n_events = 0; wp_pipewire_object_set_param (WP_PIPEWIRE_OBJECT (fixture->impl_endpoint), "Props", 0, - wp_spa_pod_new_object ("Props", "Props", + wp_spa_pod_new_object ("Spa:Pod:Object:Param:Props", "Props", "mute", "b", TRUE, NULL)); /* run until the change is on all sides */ @@ -645,7 +645,7 @@ test_endpoint_with_props (TestEndpointFixture *fixture, gconstpointer data) g_assert_true (wp_iterator_next (iterator, &item)); g_assert_nonnull ((pod = g_value_dup_boxed (&item))); - g_assert_true (wp_spa_pod_get_object (pod, "Props", NULL, + g_assert_true (wp_spa_pod_get_object (pod, NULL, "volume", "f", &float_value, "mute", "b", &boolean_value, NULL)); @@ -666,7 +666,7 @@ test_endpoint_with_props (TestEndpointFixture *fixture, gconstpointer data) g_assert_true (wp_iterator_next (iterator, &item)); g_assert_nonnull ((pod = g_value_dup_boxed (&item))); - g_assert_true (wp_spa_pod_get_object (pod, "Props", NULL, + g_assert_true (wp_spa_pod_get_object (pod, NULL, "volume", "f", &float_value, "mute", "b", &boolean_value, NULL)); @@ -687,7 +687,7 @@ test_endpoint_with_props (TestEndpointFixture *fixture, gconstpointer data) g_assert_true (wp_iterator_next (iterator, &item)); g_assert_nonnull ((pod = g_value_dup_boxed (&item))); - g_assert_true (wp_spa_pod_get_object (pod, "Props", NULL, + g_assert_true (wp_spa_pod_get_object (pod, NULL, "volume", "f", &float_value, "mute", "b", &boolean_value, NULL)); @@ -699,7 +699,7 @@ test_endpoint_with_props (TestEndpointFixture *fixture, gconstpointer data) fixture->n_events = 0; wp_pipewire_object_set_param (WP_PIPEWIRE_OBJECT (endpoint->node), "Props", 0, - wp_spa_pod_new_object ("Props", "Props", + wp_spa_pod_new_object ("Spa:Pod:Object:Param:Props", "Props", "volume", "f", 0.2f, NULL)); /* run until the change is on all sides */ @@ -721,7 +721,7 @@ test_endpoint_with_props (TestEndpointFixture *fixture, gconstpointer data) g_assert_true (wp_iterator_next (iterator, &item)); g_assert_nonnull ((pod = g_value_dup_boxed (&item))); - g_assert_true (wp_spa_pod_get_object (pod, "Props", NULL, + g_assert_true (wp_spa_pod_get_object (pod, NULL, "volume", "f", &float_value, "mute", "b", &boolean_value, NULL)); @@ -742,7 +742,7 @@ test_endpoint_with_props (TestEndpointFixture *fixture, gconstpointer data) g_assert_true (wp_iterator_next (iterator, &item)); g_assert_nonnull ((pod = g_value_dup_boxed (&item))); - g_assert_true (wp_spa_pod_get_object (pod, "Props", NULL, + g_assert_true (wp_spa_pod_get_object (pod, NULL, "volume", "f", &float_value, "mute", "b", &boolean_value, NULL)); @@ -763,7 +763,7 @@ test_endpoint_with_props (TestEndpointFixture *fixture, gconstpointer data) g_assert_true (wp_iterator_next (iterator, &item)); g_assert_nonnull ((pod = g_value_dup_boxed (&item))); - g_assert_true (wp_spa_pod_get_object (pod, "Props", NULL, + g_assert_true (wp_spa_pod_get_object (pod, NULL, "volume", "f", &float_value, "mute", "b", &boolean_value, NULL)); diff --git a/tests/wp/proxy.c b/tests/wp/proxy.c index e18a4132..023acdac 100644 --- a/tests/wp/proxy.c +++ b/tests/wp/proxy.c @@ -106,7 +106,8 @@ test_node_enum_params_done (WpPipewireObject *node, GAsyncResult *res, g_assert_cmpuint (G_VALUE_TYPE (&item), ==, WP_TYPE_SPA_POD); g_assert_nonnull (pod = g_value_get_boxed (&item)); g_assert_true (wp_spa_pod_is_object (pod)); - g_assert_cmpstr ("PropInfo", ==, wp_spa_pod_get_object_type_name (pod)); + g_assert_cmpuint (wp_spa_type_from_name ("Spa:Pod:Object:Param:PropInfo"), + ==, wp_spa_pod_get_spa_type (pod)); n_params++; } g_assert_cmpint (n_params, >, 0); diff --git a/tests/wp/spa-pod.c b/tests/wp/spa-pod.c index d48f77f4..c5a218eb 100644 --- a/tests/wp/spa-pod.c +++ b/tests/wp/spa-pod.c @@ -11,15 +11,14 @@ static void test_spa_pod_basic (void) { - wp_spa_type_init (TRUE); - /* None */ { g_autoptr (WpSpaPod) pod = wp_spa_pod_new_none (); g_assert_nonnull (pod); g_assert_true (wp_spa_pod_is_none (pod)); g_assert_false (wp_spa_pod_is_id (pod)); - g_assert_cmpstr ("None", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:None", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); g_autoptr (WpSpaPod) other = wp_spa_pod_new_none (); g_assert_true (wp_spa_pod_equal (pod, other)); } @@ -36,7 +35,8 @@ test_spa_pod_basic (void) gboolean value = FALSE; g_assert_true (wp_spa_pod_get_boolean (pod, &value)); g_assert_true (value); - g_assert_cmpstr ("Bool", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Bool", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); g_assert_true (wp_spa_pod_set_boolean (pod, FALSE)); g_assert_true (wp_spa_pod_get_boolean (pod, &value)); g_assert_false (value); @@ -49,7 +49,8 @@ test_spa_pod_basic (void) gboolean value = FALSE; g_assert_true (wp_spa_pod_get_boolean (copy, &value)); g_assert_false (value); - g_assert_cmpstr ("Bool", ==, wp_spa_pod_get_type_name (copy)); + g_assert_cmpstr ("Spa:Bool", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (copy))); g_autoptr (WpSpaPod) other = wp_spa_pod_new_boolean (TRUE); g_assert_true (wp_spa_pod_set_pod (copy, other)); g_assert_true (wp_spa_pod_get_boolean (copy, &value)); @@ -65,7 +66,8 @@ test_spa_pod_basic (void) guint32 value = 0; g_assert_true (wp_spa_pod_get_id (pod, &value)); g_assert_cmpuint (value, ==, 5); - g_assert_cmpstr ("Id", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Id", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); g_assert_true (wp_spa_pod_set_id (pod, 10)); g_assert_true (wp_spa_pod_get_id (pod, &value)); g_assert_cmpuint (value, ==, 10); @@ -84,7 +86,8 @@ test_spa_pod_basic (void) gint value = 0; g_assert_true (wp_spa_pod_get_int (pod, &value)); g_assert_cmpint (value, ==, -12); - g_assert_cmpstr ("Int", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Int", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); g_assert_true (wp_spa_pod_set_int (pod, 9999)); g_assert_true (wp_spa_pod_get_int (pod, &value)); g_assert_cmpint (value, ==, 9999); @@ -103,7 +106,8 @@ test_spa_pod_basic (void) long value = 0; g_assert_true (wp_spa_pod_get_long (pod, &value)); g_assert_cmpint (value, ==, LONG_MAX); - g_assert_cmpstr ("Long", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Long", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); g_assert_true (wp_spa_pod_set_long (pod, LONG_MIN)); g_assert_true (wp_spa_pod_get_long (pod, &value)); g_assert_cmpuint (value, ==, LONG_MIN); @@ -122,7 +126,8 @@ test_spa_pod_basic (void) float value = 0; g_assert_true (wp_spa_pod_get_float (pod, &value)); g_assert_cmpfloat_with_epsilon (value, 3.14, 0.001); - g_assert_cmpstr ("Float", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Float", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); g_assert_true (wp_spa_pod_set_float (pod, 1.0)); g_assert_true (wp_spa_pod_get_float (pod, &value)); g_assert_cmpfloat_with_epsilon (value, 1.0, 0.001); @@ -141,7 +146,8 @@ test_spa_pod_basic (void) double value = 0; g_assert_true (wp_spa_pod_get_double (pod, &value)); g_assert_cmpfloat_with_epsilon (value, 2.718281828, 0.0000000001); - g_assert_cmpstr ("Double", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Double", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); g_assert_true (wp_spa_pod_set_double (pod, 2.0)); g_assert_true (wp_spa_pod_get_double (pod, &value)); g_assert_cmpfloat_with_epsilon (value, 2.0, 0.0000000001); @@ -161,7 +167,8 @@ test_spa_pod_basic (void) g_assert_true (wp_spa_pod_get_string (pod, &value)); g_assert_nonnull (value); g_assert_cmpstr (value, ==, "WirePlumber"); - g_assert_cmpstr ("String", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:String", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); g_autoptr (WpSpaPod) other = wp_spa_pod_new_string ("Other"); g_assert_nonnull (other); g_assert_true (wp_spa_pod_set_pod (pod, other)); @@ -182,7 +189,8 @@ test_spa_pod_basic (void) g_assert_nonnull (value); g_assert_cmpmem (value, len, "bytes", 5); g_assert_cmpuint (len, ==, 5); - g_assert_cmpstr ("Bytes", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Bytes", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); g_autoptr (WpSpaPod) other = wp_spa_pod_new_bytes ("pod", 3); g_assert_true (wp_spa_pod_set_pod (pod, other)); g_assert_true (wp_spa_pod_get_bytes (pod, &value, &len)); @@ -195,35 +203,26 @@ test_spa_pod_basic (void) /* Pointer */ { gint i = 3; - g_autoptr (WpSpaPod) pod = wp_spa_pod_new_pointer ("Int", &i); + g_autoptr (WpSpaPod) pod = wp_spa_pod_new_pointer ("Spa:Pointer:Buffer", &i); g_assert_nonnull (pod); g_assert_true (wp_spa_pod_is_pointer (pod)); - const char *type_name = NULL; gconstpointer p = NULL; - g_assert_true (wp_spa_pod_get_pointer (pod, &type_name, &p)); - g_assert_nonnull (type_name); + g_assert_true (wp_spa_pod_get_pointer (pod, &p)); g_assert_nonnull (p); - g_assert_cmpstr (type_name, ==, "Int"); g_assert_true (p == &i); g_assert_cmpint (*(gint *)p, ==, 3); - g_assert_cmpstr ("Pointer", ==, wp_spa_pod_get_type_name (pod)); - gboolean b = TRUE; - g_assert_true (wp_spa_pod_set_pointer (pod, "Bool", &b)); - g_assert_true (wp_spa_pod_get_pointer (pod, &type_name, &p)); - g_assert_nonnull (type_name); - g_assert_nonnull (p); - g_assert_cmpstr (type_name, ==, "Bool"); - g_assert_true (p == &b); - g_assert_cmpint (*(gboolean *)p, ==, TRUE); + g_assert_cmpstr ("Spa:Pointer:Buffer", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); + float f = 1.1; - g_autoptr (WpSpaPod) other = wp_spa_pod_new_pointer ("Float", &f); + g_autoptr (WpSpaPod) other = wp_spa_pod_new_pointer ("Spa:Pointer:Meta", &f); g_assert_true (wp_spa_pod_set_pod (pod, other)); - g_assert_true (wp_spa_pod_get_pointer (pod, &type_name, &p)); - g_assert_nonnull (type_name); + g_assert_true (wp_spa_pod_get_pointer (pod, &p)); g_assert_nonnull (p); - g_assert_cmpstr (type_name, ==, "Float"); g_assert_true (p == &f); g_assert_cmpfloat_with_epsilon (*(float *)p, 1.1, 0.01); + g_assert_cmpstr ("Spa:Pointer:Meta", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); g_assert_true (wp_spa_pod_equal (pod, other)); } @@ -235,7 +234,8 @@ test_spa_pod_basic (void) gint64 value = 0; g_assert_true (wp_spa_pod_get_fd (pod, &value)); g_assert_cmpint (value, ==, 4); - g_assert_cmpstr ("Fd", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Fd", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); g_assert_true (wp_spa_pod_set_fd (pod, 1)); g_assert_true (wp_spa_pod_get_fd (pod, &value)); g_assert_cmpuint (value, ==, 1); @@ -256,7 +256,8 @@ test_spa_pod_basic (void) g_assert_true (wp_spa_pod_get_rectangle (pod, &width, &height)); g_assert_cmpint (width, ==, 1920); g_assert_cmpint (height, ==, 1080); - g_assert_cmpstr ("Rectangle", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Rectangle", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); g_assert_true (wp_spa_pod_set_rectangle (pod, 640, 480)); g_assert_true (wp_spa_pod_get_rectangle (pod, &width, &height)); g_assert_cmpint (width, ==, 640); @@ -279,7 +280,8 @@ test_spa_pod_basic (void) g_assert_true (wp_spa_pod_get_fraction (pod, &num, &denom)); g_assert_cmpint (num, ==, 16); g_assert_cmpint (denom, ==, 9); - g_assert_cmpstr ("Fraction", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Fraction", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); g_assert_true (wp_spa_pod_set_fraction (pod, 4, 3)); g_assert_true (wp_spa_pod_get_fraction (pod, &num, &denom)); g_assert_cmpint (num, ==, 4); @@ -291,27 +293,26 @@ test_spa_pod_basic (void) g_assert_cmpint (denom, ==, 1); g_assert_true (wp_spa_pod_equal (pod, other)); } - - wp_spa_type_deinit (); } static void test_spa_pod_choice (void) { - wp_spa_type_init (TRUE); - /* Static Enum */ { g_autoptr (WpSpaPod) pod = wp_spa_pod_new_choice ( "Enum", "i", 0, "i", 1, "i", 2, NULL); g_assert_nonnull (pod); g_assert_true (wp_spa_pod_is_choice (pod)); - g_assert_cmpstr ("Choice", ==, wp_spa_pod_get_type_name (pod)); - g_assert_cmpstr ("Enum", ==, wp_spa_pod_get_choice_type_name (pod)); + g_assert_cmpstr ("Spa:Pod:Choice", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); + g_assert_cmpstr ("Enum", ==, + wp_spa_id_value_short_name (wp_spa_pod_get_choice_type (pod))); g_autoptr (WpSpaPod) child = wp_spa_pod_get_choice_child (pod); g_assert_nonnull (child); - g_assert_cmpstr ("Int", ==, wp_spa_pod_get_type_name (child)); + g_assert_cmpstr ("Spa:Int", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (child))); gint value = 1; g_assert_true (wp_spa_pod_get_int (child, &value)); g_assert_cmpint (value, ==, 0); @@ -326,12 +327,14 @@ test_spa_pod_choice (void) "default value", NULL); g_assert_nonnull (pod); g_assert_true (wp_spa_pod_is_choice (pod)); - g_assert_cmpstr ("Choice", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Pod:Choice", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); { g_autoptr (WpSpaPod) child = wp_spa_pod_get_choice_child (pod); g_assert_nonnull (child); - g_assert_cmpstr ("String", ==, wp_spa_pod_get_type_name (child)); + g_assert_cmpstr ("Spa:String", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (child))); const char *value = NULL; g_assert_true (wp_spa_pod_get_string (child, &value)); g_assert_nonnull (value); @@ -345,7 +348,8 @@ test_spa_pod_choice (void) { g_autoptr (WpSpaPod) child = wp_spa_pod_get_choice_child (pod); g_assert_nonnull (child); - g_assert_cmpstr ("String", ==, wp_spa_pod_get_type_name (child)); + g_assert_cmpstr ("Spa:String", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (child))); const char *value = NULL; g_assert_true (wp_spa_pod_get_string (child, &value)); g_assert_nonnull (value); @@ -362,21 +366,18 @@ test_spa_pod_choice (void) g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b); g_assert_nonnull (pod); g_assert_true (wp_spa_pod_is_choice (pod)); - g_assert_cmpstr ("Choice", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Pod:Choice", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); } /* It is not possible to use the parser to get the contents of a choice, you * need to use the iterator API to achieve that. This is because there is no * `spa_pod_parser_get_choice` API in the SPA library */ - - wp_spa_type_deinit (); } static void test_spa_pod_array (void) { - wp_spa_type_init (TRUE); - /* Dynamic */ { WpSpaPodBuilder *b = wp_spa_pod_builder_new_array (); @@ -388,13 +389,15 @@ test_spa_pod_array (void) g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b); g_assert_nonnull (pod); g_assert_true (wp_spa_pod_is_array (pod)); - g_assert_cmpstr ("Array", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Array", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); wp_spa_pod_builder_unref (b); g_assert_true (wp_spa_pod_is_array (pod)); g_autoptr (WpSpaPod) child = wp_spa_pod_get_array_child (pod); g_assert_nonnull (child); - g_assert_cmpstr ("Bool", ==, wp_spa_pod_get_type_name (child)); + g_assert_cmpstr ("Spa:Bool", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (child))); gboolean value = TRUE; g_assert_true (wp_spa_pod_get_boolean (child, &value)); g_assert_false (value); @@ -403,19 +406,15 @@ test_spa_pod_array (void) /* It is not possible to use the parser to get the contents of an array, you * need to use the iterator API to achieve that. This is because there is no * `spa_pod_parser_get_array` API in the SPA library. */ - - wp_spa_type_deinit (); } static void test_spa_pod_object (void) { - wp_spa_type_init (TRUE); - /* Static */ { g_autoptr (WpSpaPod) pod = wp_spa_pod_new_object ( - "Props", "Props", + "Spa:Pod:Object:Param:Props", "Props", "mute", "b", FALSE, "volume", "f", 0.5, "frequency", "i", 440, @@ -424,8 +423,8 @@ test_spa_pod_object (void) NULL); g_assert_nonnull (pod); g_assert_true (wp_spa_pod_is_object (pod)); - g_assert_cmpstr ("Object", ==, wp_spa_pod_get_type_name (pod)); - g_assert_cmpstr ("Props", ==, wp_spa_pod_get_object_type_name (pod)); + g_assert_cmpstr ("Spa:Pod:Object:Param:Props", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); const char *id_name; gboolean mute = TRUE; @@ -434,7 +433,7 @@ test_spa_pod_object (void) const char *device; gint64 device_fd; g_assert_true (wp_spa_pod_get_object (pod, - "Props", &id_name, + &id_name, "mute", "b", &mute, "volume", "f", &vol, "frequency", "i", &frequency, @@ -452,7 +451,7 @@ test_spa_pod_object (void) /* Dynamic */ { g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_object ( - "Props", "Props"); + "Spa:Pod:Object:Param:Props", "Props"); wp_spa_pod_builder_add_property (b, "mute"); wp_spa_pod_builder_add_boolean (b, FALSE); wp_spa_pod_builder_add_property (b, "volume"); @@ -466,7 +465,8 @@ test_spa_pod_object (void) g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b); g_assert_nonnull (pod); g_assert_true (wp_spa_pod_is_object (pod)); - g_assert_cmpstr ("Object", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Pod:Object:Param:Props", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); const char *id_name; gboolean mute = TRUE; @@ -474,8 +474,7 @@ test_spa_pod_object (void) gint frequency; const char *device; gint64 device_fd; - g_autoptr (WpSpaPodParser) p = wp_spa_pod_parser_new_object (pod, - "Props", &id_name); + 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)); g_assert_true (wp_spa_pod_parser_get (p, "volume", "f", &vol, NULL)); @@ -490,15 +489,11 @@ test_spa_pod_object (void) g_assert_cmpstr (device, ==, "device-name"); g_assert_cmpint (device_fd, ==, 5); } - - wp_spa_type_deinit (); } static void test_spa_pod_struct (void) { - wp_spa_type_init (TRUE); - /* Dynamic */ { g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_struct (); @@ -510,7 +505,7 @@ test_spa_pod_struct (void) wp_spa_pod_builder_add_double (b, 2.718281828); wp_spa_pod_builder_add_string (b, "WirePlumber"); wp_spa_pod_builder_add_bytes (b, "bytes", 5); - wp_spa_pod_builder_add_pointer (b, "Struct", b); + wp_spa_pod_builder_add_pointer (b, "Spa:Pointer:Buffer", b); wp_spa_pod_builder_add_fd (b, 4); wp_spa_pod_builder_add_rectangle (b, 1920, 1080); wp_spa_pod_builder_add_fraction (b, 16, 9); @@ -520,7 +515,7 @@ test_spa_pod_struct (void) } { g_autoptr (WpSpaPod) pod = wp_spa_pod_new_object ( - "Props", "Props", + "Spa:Pod:Object:Param:Props", "Props", "mute", "b", FALSE, NULL); wp_spa_pod_builder_add (b, "P", pod, NULL); @@ -528,7 +523,8 @@ test_spa_pod_struct (void) g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b); g_assert_nonnull (pod); g_assert_true (wp_spa_pod_is_struct (pod)); - g_assert_cmpstr ("Struct", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Pod:Struct", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); g_autoptr (WpSpaPodParser) p = wp_spa_pod_parser_new_struct (pod); g_assert_nonnull (pod); @@ -568,11 +564,8 @@ test_spa_pod_struct (void) g_assert_cmpuint (len_bytes, ==, 5); gconstpointer value_pointer; - const char *type_pointer; - g_assert_true (wp_spa_pod_parser_get_pointer (p, &type_pointer, &value_pointer)); - g_assert_nonnull (type_pointer); + g_assert_true (wp_spa_pod_parser_get_pointer (p, &value_pointer)); g_assert_nonnull (value_pointer); - g_assert_cmpstr (type_pointer, ==, "Struct"); g_assert_true (value_pointer == b); gint64 value_fd; @@ -604,28 +597,25 @@ test_spa_pod_struct (void) gboolean mute = TRUE; g_assert_true (wp_spa_pod_get_object (value_object, - "Props", &id_name, + &id_name, "mute", "b", &mute, NULL)); g_assert_cmpstr (id_name, ==, "Props"); g_assert_false (mute); } - - wp_spa_type_deinit (); } static void test_spa_pod_sequence (void) { - wp_spa_type_init (TRUE); - /* Static */ { g_autoptr (WpSpaPod) pod = wp_spa_pod_new_sequence (0, 10, "Properties", "l", 9999, NULL); g_assert_nonnull (pod); g_assert_true (wp_spa_pod_is_sequence (pod)); - g_assert_cmpstr ("Sequence", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Pod:Sequence", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); } /* Dynamic */ @@ -636,14 +626,13 @@ test_spa_pod_sequence (void) g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b); g_assert_nonnull (pod); g_assert_true (wp_spa_pod_is_sequence (pod)); - g_assert_cmpstr ("Sequence", ==, wp_spa_pod_get_type_name (pod)); + g_assert_cmpstr ("Spa:Pod:Sequence", ==, + wp_spa_type_name (wp_spa_pod_get_spa_type (pod))); } /* It is not possible to use the parser to get the contents of a sequence, you * need to use the iterator API to achieve that. This is because there is no * `spa_pod_parser_get_sequence` API in the SPA library. */ - - wp_spa_type_deinit (); } static void @@ -692,8 +681,6 @@ sequence_foreach (const GValue *item, gpointer data) static void test_spa_pod_iterator (void) { - wp_spa_type_init (TRUE); - /* Choice */ { g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_choice ("Enum"); @@ -794,7 +781,7 @@ test_spa_pod_iterator (void) /* Object */ { g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_object ( - "Props", "Props"); + "Spa:Pod:Object:Param:Props", "Props"); wp_spa_pod_builder_add_property (b, "mute"); wp_spa_pod_builder_add_boolean (b, FALSE); wp_spa_pod_builder_add_property (b, "device"); @@ -957,18 +944,14 @@ test_spa_pod_iterator (void) g_assert_true (wp_iterator_foreach (it, sequence_foreach, &offset_total)); g_assert_cmpuint (offset_total, ==, 50); } - - wp_spa_type_deinit (); } static void test_spa_pod_unique_owner (void) { - wp_spa_type_init (TRUE); - /* Create an object */ WpSpaPod *pod = wp_spa_pod_new_object ( - "PropInfo", "PropInfo", + "Spa:Pod:Object:Param:PropInfo", "PropInfo", "id", "I", 1, "name", "s", "prop-info-name", NULL); @@ -1024,21 +1007,17 @@ test_spa_pod_unique_owner (void) /* Destroy the property */ g_value_unset (&next); - - wp_spa_type_deinit (); } static void test_spa_pod_port_config (void) { - wp_spa_type_init (TRUE); - const gint rate = 48000; const gint channels = 2; /* Build the format to make sure the types exist */ g_autoptr (WpSpaPodBuilder) builder = wp_spa_pod_builder_new_object ( - "Format", "Format"); + "Spa:Pod:Object:Param:Format", "Format"); wp_spa_pod_builder_add (builder, "mediaType", "I", 0, "mediaSubtype", "I", 0, @@ -1056,7 +1035,8 @@ test_spa_pod_port_config (void) g_assert_nonnull (format); /* Build the port config to make sure the types exist */ - g_autoptr (WpSpaPod) pod = wp_spa_pod_new_object ("PortConfig", "PortConfig", + g_autoptr (WpSpaPod) pod = wp_spa_pod_new_object ( + "Spa:Pod:Object:Param:PortConfig", "PortConfig", "direction", "I", 0, "mode", "I", 0, "monitor", "b", FALSE, @@ -1064,8 +1044,6 @@ test_spa_pod_port_config (void) "format", "P", format, NULL); g_assert_nonnull (pod); - - wp_spa_type_deinit (); } int diff --git a/tests/wp/spa-type.c b/tests/wp/spa-type.c index 438ef8b5..ea6d4efc 100644 --- a/tests/wp/spa-type.c +++ b/tests/wp/spa-type.c @@ -12,143 +12,369 @@ static void test_spa_type_basic (void) { - wp_spa_type_init (TRUE); + g_assert_cmpuint (WP_SPA_TYPE_INVALID, ==, SPA_ID_INVALID); - /* Make sure table sizes are not 0 */ - g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), >, 0); - g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_PARAM), >, 0); - g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_PROPS), >, 0); - g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_PROP_INFO), >, 0); - g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_CONTROL), >, 0); - g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_CHOICE), >, 0); + { + WpSpaType type = SPA_TYPE_Int; + g_assert_cmpstr (wp_spa_type_name (type), ==, "Spa:Int"); + g_assert_true (wp_spa_type_is_fundamental (type)); + g_assert_cmpuint (wp_spa_type_parent (type), ==, SPA_TYPE_Int); + } - /* Make sure SPA_TYPE_OBJECT_Props type from WP_SPA_TYPE_TABLE_BASIC is registered */ { - const char *name = NULL; - const char *nick = NULL; - WpSpaTypeTable table = WP_SPA_TYPE_TABLE_BASIC; - g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_BASIC, SPA_TYPE_OBJECT_Props, - &name, &nick, &table)); - g_assert_cmpstr (name, ==, "Spa:Pod:Object:Param:Props"); - g_assert_cmpstr (nick, ==, "Props"); - g_assert_cmpuint (table, ==, WP_SPA_TYPE_TABLE_PROPS); + WpSpaType type = wp_spa_type_from_name ("Spa:Enum:ParamId"); + g_assert_cmpuint (type, ==, WP_SPA_TYPE_INVALID); + + WpSpaIdTable table = wp_spa_id_table_from_name ("Spa:Enum:ParamId"); + g_assert_nonnull (table); } - /* Make sure SPA_PARAM_Props type from WP_SPA_TYPE_TABLE_PARAM is registered */ { - const char *name = NULL; - const char *nick = NULL; - g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_PARAM, SPA_PARAM_Props, &name, &nick, NULL)); - g_assert_cmpstr (name, ==, "Spa:Enum:ParamId:Props"); - g_assert_cmpstr (nick, ==, "Props"); + WpSpaType type = SPA_TYPE_OBJECT_Props; + g_assert_cmpstr (wp_spa_type_name (type), ==, "Spa:Pod:Object:Param:Props"); + g_assert_cmpuint (wp_spa_type_from_name (SPA_TYPE_INFO_Props), ==, type); + g_assert_true (wp_spa_type_is_object (type)); + g_assert_false (wp_spa_type_is_fundamental (type)); + g_assert_cmpuint (wp_spa_type_parent (type), ==, SPA_TYPE_Object); + g_assert_nonnull (wp_spa_type_get_object_id_values_table (type)); + g_assert_true (wp_spa_type_get_object_id_values_table (type) == + wp_spa_id_table_from_name ("Spa:Enum:ParamId")); } - /* Make sure SPA_PROP_mute type from WP_SPA_TYPE_TABLE_PROPS is registered */ + /* enums */ { - const char *name = NULL; - const char *nick = NULL; - g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_PROPS, SPA_PROP_mute, &name, &nick, NULL)); - g_assert_cmpstr (name, ==, "Spa:Pod:Object:Param:Props:mute"); - g_assert_cmpstr (nick, ==, "mute"); + WpSpaIdValue id = wp_spa_id_value_from_name ("Spa:Enum:ParamId:Props"); + g_assert_nonnull (id); + g_assert_cmpstr (wp_spa_id_value_name (id), ==, "Spa:Enum:ParamId:Props"); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "Props"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_PARAM_Props); + + g_assert_true (id == wp_spa_id_value_from_short_name ( + "Spa:Enum:ParamId", "Props")); + g_assert_true (id == wp_spa_id_value_from_number ( + "Spa:Enum:ParamId", SPA_PARAM_Props)); } - /* Make sure SPA_PROP_INFO_id type from WP_SPA_TYPE_TABLE_PROP_INFO is registered */ { - const char *name = NULL; - const char *nick = NULL; - g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_PROP_INFO, SPA_PROP_INFO_id, &name, &nick, NULL)); - g_assert_cmpstr (name, ==, "Spa:Pod:Object:Param:PropInfo:id"); - g_assert_cmpstr (nick, ==, "id"); + WpSpaIdValue id = + wp_spa_id_value_from_name ("Spa:Enum:Control:Properties"); + g_assert_nonnull (id); + g_assert_cmpstr (wp_spa_id_value_name (id), ==, + "Spa:Enum:Control:Properties"); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "Properties"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_CONTROL_Properties); + + g_assert_true (id == wp_spa_id_value_from_short_name ( + "Spa:Enum:Control", "Properties")); + g_assert_true (id == wp_spa_id_value_from_number ( + "Spa:Enum:Control", SPA_CONTROL_Properties)); } - /* Make sure SPA_CONTROL_Properties type from WP_SPA_TYPE_TABLE_CONTROL is registered */ { - const char *name = NULL; - const char *nick = NULL; - g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_CONTROL, SPA_CONTROL_Properties, &name, &nick, NULL)); - g_assert_cmpstr (name, ==, "Spa:Enum:Control:Properties"); - g_assert_cmpstr (nick, ==, "Properties"); + WpSpaIdValue id = wp_spa_id_value_from_name ("Spa:Enum:Choice:Enum"); + g_assert_nonnull (id); + g_assert_cmpstr (wp_spa_id_value_name (id), ==, "Spa:Enum:Choice:Enum"); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "Enum"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_CHOICE_Enum); + + g_assert_true (id == wp_spa_id_value_from_short_name ( + "Spa:Enum:Choice", "Enum")); + g_assert_true (id == wp_spa_id_value_from_number ( + "Spa:Enum:Choice", SPA_CHOICE_Enum)); } - /* Make sure SPA_CHOICE_Enum type from WP_SPA_TYPE_TABLE_CHOICE is registered */ + /* objects */ { - const char *name = NULL; - const char *nick = NULL; - g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_CHOICE, SPA_CHOICE_Enum, &name, &nick, NULL)); - g_assert_cmpstr (name, ==, "Spa:Enum:Choice:Enum"); - g_assert_cmpstr (nick, ==, "Enum"); + WpSpaIdValue id = + wp_spa_id_value_from_name ("Spa:Pod:Object:Param:Props:mute"); + g_assert_nonnull (id); + g_assert_cmpstr (wp_spa_id_value_name (id), ==, + "Spa:Pod:Object:Param:Props:mute"); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "mute"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_PROP_mute); + + g_assert_true (id == wp_spa_id_value_from_short_name ( + SPA_TYPE_INFO_Props, "mute")); + g_assert_true (id == wp_spa_id_value_from_number ( + SPA_TYPE_INFO_Props, SPA_PROP_mute)); } - wp_spa_type_deinit (); + { + WpSpaIdValue id = + wp_spa_id_value_from_name ("Spa:Pod:Object:Param:PropInfo:id"); + g_assert_nonnull (id); + g_assert_cmpstr (wp_spa_id_value_name (id), ==, + "Spa:Pod:Object:Param:PropInfo:id"); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "id"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_PROP_INFO_id); + + /* WpSpaIdValue is a pointer to static spa_type_info, + so it should be the same on all queries */ + g_assert_true (id == wp_spa_id_value_from_short_name ( + SPA_TYPE_INFO_PropInfo, "id")); + g_assert_true (id == wp_spa_id_value_from_number ( + SPA_TYPE_INFO_PropInfo, SPA_PROP_INFO_id)); + } + + /* array value type check */ + { + WpSpaIdValue id = + wp_spa_id_value_from_name ("Spa:Pod:Object:Param:Props:channelVolumes"); + g_assert_nonnull (id); + g_assert_cmpstr (wp_spa_id_value_name (id), ==, + "Spa:Pod:Object:Param:Props:channelVolumes"); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "channelVolumes"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_PROP_channelVolumes); + + g_assert_cmpuint (wp_spa_id_value_array_get_item_type (id, NULL), ==, + SPA_TYPE_Float); + } + + { + WpSpaIdValue id = + wp_spa_id_value_from_name ("Spa:Pod:Object:Param:Props:channelMap"); + g_assert_nonnull (id); + g_assert_cmpstr (wp_spa_id_value_name (id), ==, + "Spa:Pod:Object:Param:Props:channelMap"); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "channelMap"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_PROP_channelMap); + + WpSpaIdTable table = NULL; + g_assert_cmpuint (wp_spa_id_value_array_get_item_type (id, &table), ==, + SPA_TYPE_Id); + g_assert_nonnull (table); + g_assert_true (table == wp_spa_id_table_from_name ("Spa:Enum:AudioChannel")); + } } static void -test_spa_type_register (void) +test_spa_type_iterate (void) { - wp_spa_type_init (FALSE); + { + WpSpaType type = wp_spa_type_from_name (SPA_TYPE_INFO_PropInfo); + g_assert_cmpuint (type, !=, WP_SPA_TYPE_INVALID); + g_assert_true (wp_spa_type_is_object (type)); - /* Make sure no types are registered */ - g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), ==, 0); - g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_PARAM), ==, 0); - g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_PROPS), ==, 0); - g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_CONTROL), ==, 0); - g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_CHOICE), ==, 0); + WpSpaIdTable table = wp_spa_type_get_values_table (type); + g_autoptr (WpIterator) it = wp_spa_id_table_iterate (table); + g_auto (GValue) value = G_VALUE_INIT; + WpSpaIdValue id = NULL; - /* Register SPA_TYPE_Bool */ - { - g_assert_true (wp_spa_type_register (WP_SPA_TYPE_TABLE_BASIC, "Spa:Bool", "spa-bool")); + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, ""); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_PROP_INFO_START); + table = NULL; + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, &table), ==, SPA_TYPE_Id); + g_assert_nonnull (table); + g_assert_true (table == wp_spa_id_table_from_name ("Spa:Enum:ParamId")); + g_value_unset (&value); + + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "id"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_PROP_INFO_id); + table = NULL; + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, &table), ==, SPA_TYPE_Id); + g_assert_nonnull (table); + g_assert_true (table == + wp_spa_id_table_from_name ("Spa:Pod:Object:Param:Props")); + g_value_unset (&value); - guint32 id = 0; - const char *name = NULL; - g_assert_true (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "spa-bool", &id, &name, NULL)); - g_assert_cmpuint (id, ==, SPA_TYPE_Bool); - g_assert_cmpstr (name, ==, "Spa:Bool"); + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "name"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_PROP_INFO_name); + table = NULL; + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, &table), ==, SPA_TYPE_String); + g_assert_null (table); + g_value_unset (&value); - name = NULL; - const char *nick = NULL; - g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_BASIC, id, &name, &nick, NULL)); - g_assert_cmpstr (name, ==, "Spa:Bool"); - g_assert_cmpstr (nick, ==, "spa-bool"); + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "type"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_PROP_INFO_type); + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, &table), ==, SPA_TYPE_Pod); + g_assert_null (table); + g_value_unset (&value); - g_assert_false (wp_spa_type_register (WP_SPA_TYPE_TABLE_BASIC, "Spa:Bool", "spa-bool")); + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "labels"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_PROP_INFO_labels); + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, &table), ==, SPA_TYPE_Struct); + g_assert_null (table); + g_value_unset (&value); - g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), ==, 1); + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "container"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_PROP_INFO_container); + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, &table), ==, SPA_TYPE_Id); + g_assert_null (table); + g_value_unset (&value); } - /* Register Custom */ { - g_assert_true (wp_spa_type_register (WP_SPA_TYPE_TABLE_BASIC, "Wp:Bool", "wp-bool")); + WpSpaIdTable table = wp_spa_id_table_from_name ("Spa:Enum:Choice"); + g_assert_nonnull (table); - guint32 id = 0; - const char *name = NULL; - g_assert_true (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "wp-bool", &id, &name, NULL)); - g_assert_cmpuint (id, ==, SPA_TYPE_VENDOR_Other + 1); - g_assert_cmpstr (name, ==, "Wp:Bool"); + g_autoptr (WpIterator) it = wp_spa_id_table_iterate (table); + g_auto (GValue) value = G_VALUE_INIT; + WpSpaIdValue id = NULL; - name = NULL; - const char *nick = NULL; - g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_BASIC, id, &name, &nick, NULL)); - g_assert_cmpstr (name, ==, "Wp:Bool"); - g_assert_cmpstr (nick, ==, "wp-bool"); + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "None"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_CHOICE_None); + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, NULL), ==, SPA_TYPE_Int); + g_value_unset (&value); - g_assert_false (wp_spa_type_register (WP_SPA_TYPE_TABLE_BASIC, "Wp:Bool", "wp-bool")); + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "Range"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_CHOICE_Range); + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, NULL), ==, SPA_TYPE_Int); + g_value_unset (&value); - g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), ==, 2); + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "Step"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_CHOICE_Step); + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, NULL), ==, SPA_TYPE_Int); + g_value_unset (&value); + + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "Enum"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_CHOICE_Enum); + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, NULL), ==, SPA_TYPE_Int); + g_value_unset (&value); + + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "Flags"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, SPA_CHOICE_Flags); + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, NULL), ==, SPA_TYPE_Int); + g_value_unset (&value); } +} - /* Unregister SPA_TYPE_Bool */ - g_assert_true (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "spa-bool", NULL, NULL, NULL)); - wp_spa_type_unregister (WP_SPA_TYPE_TABLE_BASIC, "spa-bool"); - g_assert_false (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "spa-bool", NULL, NULL, NULL)); - g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), ==, 1); +static void +test_spa_type_register (void) +{ + static const struct spa_type_info custom_enum_info[] = { + { 0, SPA_TYPE_Int, "Spa:Enum:CustomEnum:Invalid", NULL }, + { 1, SPA_TYPE_Int, "Spa:Enum:CustomEnum:Valid", NULL }, + { 0, 0, NULL, NULL } + }; + + static const struct spa_type_info custom_obj_info[] = { + { 0, SPA_TYPE_Id, "Spa:Pod:Object:CustomObj:", custom_enum_info }, + { 1, SPA_TYPE_Int, "Spa:Pod:Object:CustomObj:id", NULL }, + { 2, SPA_TYPE_String, "Spa:Pod:Object:CustomObj:name", NULL }, + { 3, SPA_TYPE_Float, "Spa:Pod:Object:CustomObj:volume", NULL }, + { 4, SPA_TYPE_Rectangle, "Spa:Pod:Object:CustomObj:box", NULL }, + { 5, SPA_TYPE_Bytes, "Spa:Pod:Object:CustomObj:data", NULL }, + { 0, 0, NULL, NULL }, + }; + + wp_spa_dynamic_type_init (); + + WpSpaIdTable enum_table = + wp_spa_dynamic_id_table_register ("Spa:Enum:CustomEnum", custom_enum_info); + WpSpaType obj_type = wp_spa_dynamic_type_register ("Spa:Pod:Object:CustomObj", + SPA_TYPE_Object, custom_obj_info); + + g_assert_nonnull (enum_table); + g_assert_true (obj_type != WP_SPA_TYPE_INVALID); + + g_assert_true (enum_table == + wp_spa_id_table_from_name ("Spa:Enum:CustomEnum")); + + { + g_autoptr (WpIterator) it = wp_spa_id_table_iterate (enum_table); + g_auto (GValue) value = G_VALUE_INIT; + WpSpaIdValue id = NULL; + + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "Invalid"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, 0); + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, NULL), ==, SPA_TYPE_Int); + g_value_unset (&value); + + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "Valid"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, 1); + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, NULL), ==, SPA_TYPE_Int); + g_value_unset (&value); - /* Unregister Custom */ - g_assert_true (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "wp-bool", NULL, NULL, NULL)); - wp_spa_type_unregister (WP_SPA_TYPE_TABLE_BASIC, "wp-bool"); - g_assert_false (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "wp-bool", NULL, NULL, NULL)); - g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), ==, 0); + g_assert_false (wp_iterator_next (it, &value)); + } + + g_assert_cmpstr (wp_spa_type_name (obj_type), ==, "Spa:Pod:Object:CustomObj"); + g_assert_true (wp_spa_type_is_object (obj_type)); + g_assert_false (wp_spa_type_is_fundamental (obj_type)); + g_assert_cmpuint (wp_spa_type_parent (obj_type), ==, SPA_TYPE_Object); + g_assert_cmpuint (obj_type, ==, + wp_spa_type_from_name ("Spa:Pod:Object:CustomObj")); + g_assert_true (enum_table == + wp_spa_type_get_object_id_values_table (obj_type)); + + { + WpSpaIdTable table = wp_spa_type_get_values_table (obj_type); + g_autoptr (WpIterator) it = wp_spa_id_table_iterate (table); + g_auto (GValue) value = G_VALUE_INIT; + WpSpaIdValue id = NULL; + + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, ""); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, 0); + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, NULL), ==, SPA_TYPE_Id); + g_value_unset (&value); + + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "id"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, 1); + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, NULL), ==, SPA_TYPE_Int); + g_value_unset (&value); + + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "name"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, 2); + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, NULL), ==, SPA_TYPE_String); + g_value_unset (&value); + + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "volume"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, 3); + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, NULL), ==, SPA_TYPE_Float); + g_value_unset (&value); + + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "box"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, 4); + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, NULL), ==, SPA_TYPE_Rectangle); + g_value_unset (&value); + + g_assert_true (wp_iterator_next (it, &value)); + id = g_value_get_pointer (&value); + g_assert_cmpstr (wp_spa_id_value_short_name (id), ==, "data"); + g_assert_cmpuint (wp_spa_id_value_number (id), ==, 5); + g_assert_cmpuint (wp_spa_id_value_get_value_type (id, NULL), ==, SPA_TYPE_Bytes); + g_value_unset (&value); + + g_assert_false (wp_iterator_next (it, &value)); + } - wp_spa_type_deinit (); + wp_spa_dynamic_type_deinit (); } int @@ -158,6 +384,7 @@ main (int argc, char *argv[]) g_log_set_writer_func (wp_log_writer_default, NULL, NULL); g_test_add_func ("/wp/spa-type/basic", test_spa_type_basic); + g_test_add_func ("/wp/spa-type/iterate", test_spa_type_iterate); g_test_add_func ("/wp/spa-type/register", test_spa_type_register); return g_test_run (); diff --git a/tools/wpctl.c b/tools/wpctl.c index 9873bee7..8684ec04 100644 --- a/tools/wpctl.c +++ b/tools/wpctl.c @@ -107,7 +107,7 @@ print_controls (WpPipewireObject * pwobj) it = wp_pipewire_object_enum_params_sync (pwobj, "Props", NULL); if (!it || !wp_iterator_next (it, &value) || - !wp_spa_pod_get_object (g_value_get_boxed (&value), "Props", NULL, + !wp_spa_pod_get_object (g_value_get_boxed (&value), NULL, "volume", "f", &volume, "mute", "b", &mute, NULL)) @@ -654,14 +654,16 @@ set_volume_run (WpCtl * self) it = wp_pipewire_object_enum_params_sync (proxy, "Props", NULL); if (!it || !wp_iterator_next (it, &value) || - !wp_spa_pod_get_object (g_value_get_boxed (&value), "Props", NULL, + !wp_spa_pod_get_object (g_value_get_boxed (&value), NULL, "volume", "f", &volume, NULL)) { printf ("Object '%d' does not support volume\n", cmdline.set_volume.id); goto out; } wp_pipewire_object_set_param (proxy, "Props", 0, wp_spa_pod_new_object ( - "Props", "Props", "volume", "f", cmdline.set_volume.volume, NULL)); + "Spa:Pod:Object:Param:Props", "Props", + "volume", "f", cmdline.set_volume.volume, + NULL)); wp_core_sync (self->core, NULL, (GAsyncReadyCallback) async_quit, self); return; @@ -741,7 +743,7 @@ set_mute_run (WpCtl * self) it = wp_pipewire_object_enum_params_sync (proxy, "Props", NULL); if (!it || !wp_iterator_next (it, &value) || - !wp_spa_pod_get_object (g_value_get_boxed (&value), "Props", NULL, + !wp_spa_pod_get_object (g_value_get_boxed (&value), NULL, "mute", "b", &mute, NULL)) { printf ("Object '%d' does not support mute\n", cmdline.set_mute.id); goto out; @@ -753,7 +755,9 @@ set_mute_run (WpCtl * self) mute = !!cmdline.set_mute.mute; wp_pipewire_object_set_param (proxy, "Props", 0, wp_spa_pod_new_object ( - "Props", "Props", "mute", "b", mute, NULL)); + "Spa:Pod:Object:Param:Props", "Props", + "mute", "b", mute, + NULL)); wp_core_sync (self->core, NULL, (GAsyncReadyCallback) async_quit, self); return; @@ -810,7 +814,7 @@ set_profile_run (WpCtl * self) } wp_pipewire_object_set_param (proxy, "Profile", 0, wp_spa_pod_new_object ( - "Profile", "Profile", + "Spa:Pod:Object:Param:Profile", "Profile", "index", "i", cmdline.set_profile.index, NULL)); wp_core_sync (self->core, NULL, (GAsyncReadyCallback) async_quit, self); -- GitLab