/* WirePlumber * * Copyright © 2020 Collabora Ltd. * @author Julian Bouzas * * SPDX-License-Identifier: MIT */ #define G_LOG_DOMAIN "wp-spa-pod" #include #include #include #include "private.h" #include "spa-pod.h" #include "spa-type.h" #define WP_SPA_POD_BUILDER_REALLOC_STEP_SIZE 64 enum { FLAG_NO_OWNERSHIP = (1 << 0) }; typedef enum { WP_SPA_POD_REGULAR = 0, WP_SPA_POD_PROPERTY, WP_SPA_POD_CONTROL, } WpSpaPodType; struct _WpSpaPod { grefcount ref; guint32 flags; /* The pipewire spa pod API does not have a type for Property and Control, * so we create our own and separate them with their data from the regular * spa pod types */ WpSpaPodType type; /* Pod */ union { struct spa_pod pod_none; struct spa_pod_bool pod_bool; struct spa_pod_id pod_id; struct spa_pod_int pod_int; struct spa_pod_long pod_long; struct spa_pod_float pod_float; struct spa_pod_double pod_double; struct spa_pod_pointer pod_pointer; struct spa_pod_fd pod_fd; struct spa_pod_rectangle pod_rectangle; struct spa_pod_fraction pod_fraction; struct wp_property_data { WpSpaTypeTable table; guint32 key; guint32 flags; } data_property; /* Only used for property pods */ struct wp_control_data { guint32 offset; guint32 type; } data_control; /* Only used for control pods */ } static_pod; /* Only used for statically allocated pods */ WpSpaPodBuilder *builder; /* Only used for dynamically allocated pods */ struct spa_pod *pod; }; 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 */ }; G_DEFINE_BOXED_TYPE (WpSpaPodBuilder, wp_spa_pod_builder, wp_spa_pod_builder_ref, wp_spa_pod_builder_unref) struct _WpSpaPodParser { guint32 type; struct spa_pod_parser parser; WpSpaPod *pod; struct spa_pod_frame frame; WpSpaTypeTable prop_table; /* Only used when parsing properties */ }; G_DEFINE_BOXED_TYPE (WpSpaPodParser, wp_spa_pod_parser, wp_spa_pod_parser_ref, wp_spa_pod_parser_unref) static int wp_spa_pod_builder_overflow (gpointer data, uint32_t size) { WpSpaPodBuilder *self = data; const uint32_t next_size = self->size + WP_SPA_POD_BUILDER_REALLOC_STEP_SIZE; const uint32_t new_size = size > next_size ? size : next_size; self->buf = g_realloc (self->buf, new_size); self->builder.data = self->buf; self->builder.size = new_size; self->size = new_size; return 0; } static const struct spa_pod_builder_callbacks builder_callbacks = { SPA_VERSION_POD_BUILDER_CALLBACKS, .overflow = wp_spa_pod_builder_overflow }; static WpSpaPodBuilder * wp_spa_pod_builder_new (size_t size, uint32_t type) { WpSpaPodBuilder *self = g_rc_box_new0 (WpSpaPodBuilder); self->size = size; self->buf = g_new0 (guint8, self->size); self->builder = SPA_POD_BUILDER_INIT (self->buf, self->size); self->type = type; spa_pod_builder_set_callbacks (&self->builder, &builder_callbacks, self); return self; } /** * wp_spa_pod_ref: * @self: a spa pod object * * Returns: (transfer full): @self with an additional reference count on it */ WpSpaPod * wp_spa_pod_ref (WpSpaPod *self) { g_ref_count_inc (&self->ref); return self; } static void wp_spa_pod_free (WpSpaPod *self) { g_clear_pointer (&self->builder, wp_spa_pod_builder_unref); self->pod = NULL; g_slice_free (WpSpaPod, self); } /** * wp_spa_pod_unref: * @self: (transfer full): a spa pod object * * Decreases the reference count on @self and frees it when the ref count * reaches zero. */ void wp_spa_pod_unref (WpSpaPod *self) { if (g_ref_count_dec (&self->ref)) wp_spa_pod_free (self); } WpSpaPod * wp_spa_pod_new_regular_wrap (struct spa_pod *pod) { WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->flags = FLAG_NO_OWNERSHIP; self->type = WP_SPA_POD_REGULAR; self->pod = pod; /* 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; } return self; } WpSpaPod * wp_spa_pod_new_property_wrap (WpSpaTypeTable table, guint32 key, guint32 flags, struct spa_pod *pod) { WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->flags = FLAG_NO_OWNERSHIP; self->type = WP_SPA_POD_PROPERTY; self->pod = pod; self->static_pod.data_property.table = table; self->static_pod.data_property.key = key; self->static_pod.data_property.flags = flags; return self; } WpSpaPod * wp_spa_pod_new_control_wrap (guint32 offset, guint32 type, struct spa_pod *pod) { WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->flags = FLAG_NO_OWNERSHIP; self->type = WP_SPA_POD_CONTROL; self->pod = pod; self->static_pod.data_control.offset = offset; self->static_pod.data_control.type = type; return self; } WpSpaPod * wp_spa_pod_new_regular_wrap_copy (const struct spa_pod *pod) { WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->type = WP_SPA_POD_REGULAR; self->builder = wp_spa_pod_builder_new ( SPA_ROUND_UP_N (sizeof (*pod) + pod->size, 8), pod->type); self->pod = self->builder->builder.data; spa_pod_builder_primitive (&self->builder->builder, pod); /* 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; } return self; } WpSpaPod * wp_spa_pod_new_property_wrap_copy (WpSpaTypeTable table, guint32 key, guint32 flags, const struct spa_pod *pod) { WpSpaPod *self = wp_spa_pod_new_regular_wrap_copy (pod); self->type = WP_SPA_POD_PROPERTY; self->static_pod.data_property.table = table; self->static_pod.data_property.key = key; self->static_pod.data_property.flags = flags; return self; } WpSpaPod * wp_spa_pod_new_control_wrap_copy (guint32 offset, guint32 type, const struct spa_pod *pod) { WpSpaPod *self = wp_spa_pod_new_regular_wrap_copy (pod); self->type = WP_SPA_POD_CONTROL; self->static_pod.data_control.offset = offset; self->static_pod.data_control.type = type; return self; } struct spa_pod * wp_spa_pod_get_spa_pod (WpSpaPod *self) { return self->pod; } /** * wp_spa_pod_get_type_name: * @self: a spa pod object * * Gets the type name of the spa pod object * * Returns: the type name of the spa pod object */ const char * wp_spa_pod_get_type_name (const 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; } /** * wp_spa_pod_copy: * @other: a spa pod object * * Copies a spa pod object * * Returns: (transfer full): The newly copied spa pod */ WpSpaPod * wp_spa_pod_copy (const WpSpaPod *other) { g_return_val_if_fail (other, NULL); switch (other->type) { case WP_SPA_POD_PROPERTY: return wp_spa_pod_new_property_wrap_copy ( other->static_pod.data_property.table, other->static_pod.data_property.key, other->static_pod.data_property.flags, other->pod); case WP_SPA_POD_CONTROL: return wp_spa_pod_new_control_wrap_copy ( other->static_pod.data_control.offset, other->static_pod.data_control.type, other->pod); case WP_SPA_POD_REGULAR: default: break; } return wp_spa_pod_new_regular_wrap_copy (other->pod); } /** * wp_spa_pod_is_unique_owner: * @self: a spa pod object * * Checks if the pod is the unique owner of its data or not * * Returns: TRUE if the pod owns the data, FALSE otherwise. */ gboolean wp_spa_pod_is_unique_owner (WpSpaPod *self) { return g_ref_count_compare (&self->ref, 1) && !(self->flags & FLAG_NO_OWNERSHIP); } /** * wp_spa_pod_ensure_unique_owner: * @self (transfer full): a spa pod object * * If @self is not uniquely owned already, then it is unrefed and a copy of * it is returned instead. You should always consider @self as unsafe to use * after this call and you should use the returned object instead. * * Returns: (transfer full): the uniquely owned spa pod object which may or may * not be the same as @self. */ WpSpaPod * wp_spa_pod_ensure_unique_owner (WpSpaPod *self) { WpSpaPod *copy = NULL; if (wp_spa_pod_is_unique_owner (self)) return self; copy = wp_spa_pod_copy (self); wp_spa_pod_unref (self); return copy; } /** * wp_spa_pod_new_none: * * Creates a spa pod of type None * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_none (void) { WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->type = WP_SPA_POD_REGULAR; self->static_pod.pod_none = SPA_POD_INIT_None(); self->pod = &self->static_pod.pod_none; return self; } /** * wp_spa_pod_new_boolean: * @value: the boolean value * * Creates a spa pod of type boolean * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_boolean (gboolean value) { WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->type = WP_SPA_POD_REGULAR; self->static_pod.pod_bool = SPA_POD_INIT_Bool (value ? true : false); self->pod = &self->static_pod.pod_bool.pod; return self; } /** * wp_spa_pod_new_id: * @value: the Id value * * Creates a spa pod of type Id * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_id (guint32 value) { WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->type = WP_SPA_POD_REGULAR; self->static_pod.pod_id = SPA_POD_INIT_Id (value); self->pod = &self->static_pod.pod_id.pod; return self; } /** * wp_spa_pod_new_int: * @value: the int value * * Creates a spa pod of type int * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_int (gint value) { WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->static_pod.pod_int = SPA_POD_INIT_Int (value); self->pod = &self->static_pod.pod_int.pod; return self; } /** * wp_spa_pod_new_long: * @value: the long value * * Creates a spa pod of type long * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_long (glong value) { WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->type = WP_SPA_POD_REGULAR; self->static_pod.pod_long = SPA_POD_INIT_Long (value); self->pod = &self->static_pod.pod_long.pod; return self; } /** * wp_spa_pod_new_float: * @value: the float value * * Creates a spa pod of type float * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_float (float value) { WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->type = WP_SPA_POD_REGULAR; self->static_pod.pod_float = SPA_POD_INIT_Float (value); self->pod = &self->static_pod.pod_float.pod; return self; } /** * wp_spa_pod_new_double: * @value: the double value * * Creates a spa pod of type double * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_double (double value) { WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->type = WP_SPA_POD_REGULAR; self->static_pod.pod_double = SPA_POD_INIT_Double (value); self->pod = &self->static_pod.pod_double.pod; return self; } /** * wp_spa_pod_new_string: * @value: the string value * * Creates a spa pod of type string * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_string (const char *value) { const uint32_t len = value ? strlen (value) : 0; const char *str = value ? value : ""; WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->type = WP_SPA_POD_REGULAR; struct spa_pod_string p = SPA_POD_INIT_String (len + 1); self->builder = wp_spa_pod_builder_new ( SPA_ROUND_UP_N (sizeof (p) + len + 1, 8), SPA_TYPE_String); self->pod = self->builder->builder.data; spa_pod_builder_raw (&self->builder->builder, &p, sizeof(p)); spa_pod_builder_write_string (&self->builder->builder, str, len); return self; } /** * wp_spa_pod_new_bytes: * @value: the bytes value * @len: the length of the bytes value * * Creates a spa pod of type bytes * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_bytes (gconstpointer value, guint32 len) { WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->type = WP_SPA_POD_REGULAR; const struct spa_pod_bytes p = SPA_POD_INIT_Bytes (len); self->builder = wp_spa_pod_builder_new ( SPA_ROUND_UP_N (sizeof (p) + p.pod.size, 8), SPA_TYPE_Bytes); self->pod = self->builder->builder.data; spa_pod_builder_raw (&self->builder->builder, &p, sizeof(p)); spa_pod_builder_raw_padded (&self->builder->builder, value, len); return self; } /** * wp_spa_pod_new_pointer: * @type_name: the type name the pointer points to * @value: the pointer value * * Creates a spa pod of type pointer * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_pointer (const char *type_name, gconstpointer value) { 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; } /** * wp_spa_pod_new_fd: * @value: the Fd value * * Creates a spa pod of type Fd * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_fd (gint64 value) { WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->type = WP_SPA_POD_REGULAR; self->static_pod.pod_fd = SPA_POD_INIT_Fd (value); self->pod = &self->static_pod.pod_fd.pod; return self; } /** * wp_spa_pod_new_rectangle: * @width: the width value of the rectangle * @height: the height value of the rectangle * * Creates a spa pod of type rectangle * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_rectangle (guint32 width, guint32 height) { WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->type = WP_SPA_POD_REGULAR; self->static_pod.pod_rectangle = SPA_POD_INIT_Rectangle (SPA_RECTANGLE (width, height)); self->pod = &self->static_pod.pod_rectangle.pod; return self; } /** * wp_spa_pod_new_fraction: * @num: the numerator value of the fraction * @denom: the denominator value of the fraction * * Creates a spa pod of type fraction * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_fraction (guint32 num, guint32 denom) { WpSpaPod *self = g_slice_new0 (WpSpaPod); g_ref_count_init (&self->ref); self->type = WP_SPA_POD_REGULAR; self->static_pod.pod_fraction = SPA_POD_INIT_Fraction (SPA_FRACTION (num, denom)); self->pod = &self->static_pod.pod_fraction.pod; return self; } /** * wp_spa_pod_new_choice: * @type_name: the type name of the choice type * @...: a list of choice values, followed by %NULL * * Creates a spa pod of type choice * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_choice (const char *type_name, ...) { WpSpaPod *self; va_list args; va_start (args, type_name); self = wp_spa_pod_new_choice_valist (type_name, args); va_end (args); return self; } /** * wp_spa_pod_new_choice_valist: * @type_name: the type name of the choice type * @args: the variable arguments passed to wp_spa_pod_new_choice() * * This is the `va_list` version of wp_spa_pod_new_choice() * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_choice_valist (const char *type_name, va_list args) { g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_choice (type_name); wp_spa_pod_builder_add_valist (b, args); return wp_spa_pod_builder_end (b); } /** * wp_spa_pod_new_object: * @type_name: the type name of the object type * @id_name: the id name of the object * @...: a list of object properties with their values, followed by %NULL * * Creates a spa pod of type object * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_object (const char *type_name, const char *id_name, ...) { WpSpaPod *self; va_list args; va_start (args, id_name); self = wp_spa_pod_new_object_valist (type_name, id_name, args); va_end (args); return self; } /** * wp_spa_pod_new_object_valist: * @type_name: the type name of the object type * @id_name: the id name of the object * @args: the variable arguments passed to wp_spa_pod_new_object() * * This is the `va_list` version of wp_spa_pod_new_object() * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_object_valist (const char *type_name, const char *id_name, va_list args) { g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_object (type_name, id_name); wp_spa_pod_builder_add_valist (b, args); return wp_spa_pod_builder_end (b); } /** * wp_spa_pod_new_sequence: * @unit: the unit of the sequence * @...: a list of sequence controls with their values, followed by %NULL * * Creates a spa pod of type sequence * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_sequence (guint unit, ...) { WpSpaPod *self; va_list args; va_start(args, unit); self = wp_spa_pod_new_sequence_valist (unit, args); va_end(args); return self; } /** * wp_spa_pod_new_sequence_valist: * @unit: the unit of the sequence * @args: the variable arguments passed to wp_spa_pod_new_sequence() * * This is the `va_list` version of wp_spa_pod_new_sequence() * * Returns: (transfer full): The new spa pod */ WpSpaPod * wp_spa_pod_new_sequence_valist (guint unit, va_list args) { g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_sequence (unit); wp_spa_pod_builder_add_valist (b, args); return wp_spa_pod_builder_end (b); } /** * wp_spa_pod_is_none: * @self: the spa pod object * * Checks wether the spa pod is of type none or not * * Returns: TRUE if it is of type none, FALSE otherwise */ gboolean wp_spa_pod_is_none (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_none (self->pod); } /** * wp_spa_pod_is_boolean: * @self: the spa pod object * * Checks wether the spa pod is of type boolean or not * * Returns: TRUE if it is of type boolean, FALSE otherwise */ gboolean wp_spa_pod_is_boolean (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_bool (self->pod) ? TRUE : FALSE; } /** * wp_spa_pod_is_id: * @self: the spa pod object * * Checks wether the spa pod is of type Id or not * * Returns: TRUE if it is of type Id, FALSE otherwise */ gboolean wp_spa_pod_is_id (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_id (self->pod); } /** * wp_spa_pod_is_int: * @self: the spa pod object * * Checks wether the spa pod is of type int or not * * Returns: TRUE if it is of type int, FALSE otherwise */ gboolean wp_spa_pod_is_int (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_int (self->pod); } /** * wp_spa_pod_is_long: * @self: the spa pod object * * Checks wether the spa pod is of type long or not * * Returns: TRUE if it is of type long, FALSE otherwise */ gboolean wp_spa_pod_is_long (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_long (self->pod); } /** * wp_spa_pod_is_float: * @self: the spa pod object * * Checks wether the spa pod is of type float or not * * Returns: TRUE if it is of type float, FALSE otherwise */ gboolean wp_spa_pod_is_float (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_float (self->pod); } /** * wp_spa_pod_is_double: * @self: the spa pod object * * Checks wether the spa pod is of type double or not * * Returns: TRUE if it is of type double, FALSE otherwise */ gboolean wp_spa_pod_is_double (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_double (self->pod); } /** * wp_spa_pod_is_string: * @self: the spa pod object * * Checks wether the spa pod is of type string or not * * Returns: TRUE if it is of type string, FALSE otherwise */ gboolean wp_spa_pod_is_string (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_string (self->pod); } /** * wp_spa_pod_is_bytes: * @self: the spa pod object * * Checks wether the spa pod is of type bytes or not * * Returns: TRUE if it is of type bytes, FALSE otherwise */ gboolean wp_spa_pod_is_bytes (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_bytes (self->pod); } /** * wp_spa_pod_is_pointer: * @self: the spa pod object * * Checks wether the spa pod is of type pointer or not * * Returns: TRUE if it is of type pointer, FALSE otherwise */ gboolean wp_spa_pod_is_pointer (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_pointer (self->pod); } /** * wp_spa_pod_is_fd: * @self: the spa pod object * * Checks wether the spa pod is of type Fd or not * * Returns: TRUE if it is of type Fd, FALSE otherwise */ gboolean wp_spa_pod_is_fd (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_fd (self->pod); } /** * wp_spa_pod_is_rectangle: * @self: the spa pod object * * Checks wether the spa pod is of type rectangle or not * * Returns: TRUE if it is of type rectangle, FALSE otherwise */ gboolean wp_spa_pod_is_rectangle (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_rectangle (self->pod); } /** * wp_spa_pod_is_fraction: * @self: the spa pod object * * Checks wether the spa pod is of type fraction or not * * Returns: TRUE if it is of type fraction, FALSE otherwise */ gboolean wp_spa_pod_is_fraction (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_fraction (self->pod); } /** * wp_spa_pod_is_array: * @self: the spa pod object * * Checks wether the spa pod is of type array or not * * Returns: TRUE if it is of type array, FALSE otherwise */ gboolean wp_spa_pod_is_array (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_array (self->pod); } /** * wp_spa_pod_is_choice: * @self: the spa pod object * * Checks wether the spa pod is of type choice or not * * Returns: TRUE if it is of type choice, FALSE otherwise */ gboolean wp_spa_pod_is_choice (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_choice (self->pod); } /** * wp_spa_pod_is_object: * @self: the spa pod object * * Checks wether the spa pod is of type object or not * * Returns: TRUE if it is of type object, FALSE otherwise */ gboolean wp_spa_pod_is_object (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_object (self->pod); } /** * wp_spa_pod_is_struct: * @self: the spa pod object * * Checks wether the spa pod is of type struct or not * * Returns: TRUE if it is of type struct, FALSE otherwise */ gboolean wp_spa_pod_is_struct (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_struct (self->pod); } /** * wp_spa_pod_is_sequence: * @self: the spa pod object * * Checks wether the spa pod is of type sequence or not * * Returns: TRUE if it is of type sequence, FALSE otherwise */ gboolean wp_spa_pod_is_sequence (const WpSpaPod *self) { return self->type == WP_SPA_POD_REGULAR && spa_pod_is_sequence (self->pod); } /** * wp_spa_pod_is_property: * @self: the spa pod object * * Checks wether the spa pod is of type property or not * * Returns: TRUE if it is of type property, FALSE otherwise */ gboolean wp_spa_pod_is_property (const WpSpaPod *self) { return self->type == WP_SPA_POD_PROPERTY; } /** * wp_spa_pod_is_control: * @self: the spa pod object * * Checks wether the spa pod is of type control or not * * Returns: TRUE if it is of type control, FALSE otherwise */ gboolean wp_spa_pod_is_control (const WpSpaPod *self) { return self->type == WP_SPA_POD_CONTROL; } /** * wp_spa_pod_get_boolean: * @self: the spa pod object * @value: (out): the boolean value * * Gets the boolean value of a spa pod object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_get_boolean (const WpSpaPod *self, gboolean *value) { g_return_val_if_fail (self, FALSE); g_return_val_if_fail (value, FALSE); bool v = FALSE; const int res = spa_pod_get_bool (self->pod, &v); *value = v ? TRUE : FALSE; return res >= 0; } /** * wp_spa_pod_get_id: * @self: the spa pod object * @value: (out): the Id value * * Gets the Id value of a spa pod object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_get_id (const WpSpaPod *self, guint32 *value) { g_return_val_if_fail (self, FALSE); g_return_val_if_fail (value, FALSE); uint32_t v = 0; const int res = spa_pod_get_id (self->pod, &v); *value = v; return res >= 0; } /** * wp_spa_pod_get_int: * @self: the spa pod object * @value: (out): the int value * * Gets the int value of a spa pod object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_get_int (const WpSpaPod *self, gint *value) { g_return_val_if_fail (self, FALSE); g_return_val_if_fail (value, FALSE); return spa_pod_get_int (self->pod, value) >= 0; } /** * wp_spa_pod_get_long: * @self: the spa pod object * @value: (out): the long value * * Gets the long value of a spa pod object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_get_long (const WpSpaPod *self, glong *value) { g_return_val_if_fail (self, FALSE); g_return_val_if_fail (value, FALSE); return spa_pod_get_long (self->pod, value) >= 0; } /** * wp_spa_pod_get_float: * @self: the spa pod object * @value: (out): the float value * * Gets the float value of a spa pod object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_get_float (const WpSpaPod *self, float *value) { g_return_val_if_fail (self, FALSE); g_return_val_if_fail (value, FALSE); return spa_pod_get_float (self->pod, value) >= 0; } /** * wp_spa_pod_get_double: * @self: the spa pod object * @value: (out): the double value * * Gets the double value of a spa pod object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_get_double (const WpSpaPod *self, double *value) { g_return_val_if_fail (self, FALSE); g_return_val_if_fail (value, FALSE); return spa_pod_get_double (self->pod, value) >= 0; } /** * wp_spa_pod_get_string: * @self: the spa pod object * @value: (out): the string value * * Gets the string value of a spa pod object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_get_string (const WpSpaPod *self, const char **value) { g_return_val_if_fail (self, FALSE); g_return_val_if_fail (value, FALSE); return spa_pod_get_string (self->pod, value) >= 0; } /** * wp_spa_pod_get_bytes: * @self: the spa pod object * @value: (out): the bytes value * @len: (out): the length of the bytes value * * Gets the bytes value and its len of a spa pod object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_get_bytes (const WpSpaPod *self, gconstpointer *value, guint32 *len) { g_return_val_if_fail (self, FALSE); g_return_val_if_fail (value, FALSE); g_return_val_if_fail (len, FALSE); return spa_pod_get_bytes (self->pod, value, len) >= 0; } /** * 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 * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_get_pointer (const WpSpaPod *self, const char **type_name, 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; } /** * wp_spa_pod_get_fd: * @self: the spa pod object * @value: (out): the Fd value * * Gets the Fd value of a spa pod object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_get_fd (const WpSpaPod *self, gint64 *value) { g_return_val_if_fail (self, FALSE); g_return_val_if_fail (value, FALSE); return spa_pod_get_fd (self->pod, value) >= 0; } /** * wp_spa_pod_get_rectangle: * @self: the spa pod object * @width: (out): the rectangle's width value * @height: (out): the rectangle's height value * * Gets the rectangle's width and height value of a spa pod object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_get_rectangle (const WpSpaPod *self, guint32 *width, guint32 *height) { g_return_val_if_fail (self, FALSE); struct spa_rectangle rectangle = { 0, }; const gboolean res = spa_pod_get_rectangle (self->pod, &rectangle) >= 0; if (width) *width = rectangle.width; if (height) *height = rectangle.height; return res; } /** * wp_spa_pod_get_fraction: * @self: the spa pod object * @num: (out): the fractions's numerator value * @denom: (out): the fractions's denominator value * * Gets the fractions's numerator and denominator value of a spa pod object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_get_fraction (const WpSpaPod *self, guint32 *num, guint32 *denom) { g_return_val_if_fail (self, FALSE); struct spa_fraction fraction = { 0, }; const gboolean res = spa_pod_get_fraction (self->pod, &fraction) >= 0; if (num) *num = fraction.num; if (denom) *denom = fraction.denom; return res; } /** * wp_spa_pod_set_boolean: * @self: the spa pod object * @value: the boolean value * * Sets a boolean value in the spa pod object. * * Returns: TRUE if the value could be set, FALSE othewrise. */ gboolean wp_spa_pod_set_boolean (WpSpaPod *self, gboolean value) { g_return_val_if_fail (wp_spa_pod_is_boolean (self), FALSE); ((struct spa_pod_bool *)self->pod)->value = value ? true : false; return TRUE; } /** * wp_spa_pod_set_id: * @self: the spa pod object * @value: the Id value * * Sets an Id value in the spa pod object. * * Returns: TRUE if the value could be set, FALSE othewrise. */ gboolean wp_spa_pod_set_id (WpSpaPod *self, guint32 value) { g_return_val_if_fail (wp_spa_pod_is_id (self), FALSE); ((struct spa_pod_id *)self->pod)->value = value; return TRUE; } /** * wp_spa_pod_set_int: * @self: the spa pod object * @value: the int value * * Sets an int value in the spa pod object. * * Returns: TRUE if the value could be set, FALSE othewrise. */ gboolean wp_spa_pod_set_int (WpSpaPod *self, gint value) { g_return_val_if_fail (wp_spa_pod_is_int (self), FALSE); ((struct spa_pod_int *)self->pod)->value = value; return TRUE; } /** * wp_spa_pod_set_long: * @self: the spa pod object * @value: the long value * * Sets a long value in the spa pod object. * * Returns: TRUE if the value could be set, FALSE othewrise. */ gboolean wp_spa_pod_set_long (WpSpaPod *self, glong value) { g_return_val_if_fail (wp_spa_pod_is_long (self), FALSE); ((struct spa_pod_long *)self->pod)->value = value; return TRUE; } /** * wp_spa_pod_set_float: * @self: the spa pod object * @value: the float value * * Sets a float value in the spa pod object. * * Returns: TRUE if the value could be set, FALSE othewrise. */ gboolean wp_spa_pod_set_float (WpSpaPod *self, float value) { g_return_val_if_fail (wp_spa_pod_is_float (self), FALSE); ((struct spa_pod_float *)self->pod)->value = value; return TRUE; } /** * wp_spa_pod_set_double: * @self: the spa pod object * @value: the double value * * Sets a double value in the spa pod object. * * Returns: TRUE if the value could be set, FALSE othewrise. */ gboolean wp_spa_pod_set_double (WpSpaPod *self, double value) { g_return_val_if_fail (wp_spa_pod_is_double (self), FALSE); ((struct spa_pod_double *)self->pod)->value = value; return TRUE; } /** * wp_spa_pod_set_pointer: * @self: the spa pod object * @type_name: the type name the pointer points to * @value: the pointer value * * Sets a pointer value with its type name in the spa pod object. * * Returns: TRUE if the value could be set, FALSE othewrise. */ gboolean wp_spa_pod_set_pointer (WpSpaPod *self, const char *type_name, gconstpointer value) { guint32 id = 0; g_return_val_if_fail (wp_spa_pod_is_pointer (self), 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.value = value; return TRUE; } /** * wp_spa_pod_set_fd: * @self: the spa pod object * @value: the Fd value * * Sets a Fd value in the spa pod object. * * Returns: TRUE if the value could be set, FALSE othewrise. */ gboolean wp_spa_pod_set_fd (WpSpaPod *self, gint64 value) { g_return_val_if_fail (wp_spa_pod_is_fd (self), FALSE); ((struct spa_pod_fd *)self->pod)->value = value; return TRUE; } /** * wp_spa_pod_set_rectangle: * @self: the spa pod object * @width: the width value of the rectangle * @height: the height value of the rectangle * * Sets the width and height values of a rectangle in the spa pod object. * * Returns: TRUE if the value could be set, FALSE othewrise. */ gboolean wp_spa_pod_set_rectangle (WpSpaPod *self, guint32 width, guint32 height) { g_return_val_if_fail (wp_spa_pod_is_rectangle (self), FALSE); ((struct spa_pod_rectangle *)self->pod)->value.width = width; ((struct spa_pod_rectangle *)self->pod)->value.height = height; return TRUE; } /** * wp_spa_pod_set_fraction: * @self: the spa pod object * @num: the numerator value of the farction * @denom: the denominator value of the fraction * * Sets the numerator and denominator values of a fraction in the spa pod object. * * Returns: TRUE if the value could be set, FALSE othewrise. */ gboolean wp_spa_pod_set_fraction (WpSpaPod *self, guint32 num, guint32 denom) { g_return_val_if_fail (wp_spa_pod_is_fraction (self), FALSE); ((struct spa_pod_fraction *)self->pod)->value.num = num; ((struct spa_pod_fraction *)self->pod)->value.denom = denom; return TRUE; } /** * wp_spa_pod_set_pod: * @self: the spa pod object * @pod: the pod with the value to be set * * Sets the value of a spa pod object in the current spa pod object. THe spa pod * objects must be of the same value. * * Returns: TRUE if the value could be set, FALSE othewrise. */ gboolean wp_spa_pod_set_pod (WpSpaPod *self, const WpSpaPod *pod) { g_return_val_if_fail (self->type == pod->type, FALSE); g_return_val_if_fail (SPA_POD_TYPE (self->pod) == SPA_POD_TYPE (pod->pod), FALSE); switch (SPA_POD_TYPE (self->pod)) { case SPA_TYPE_None: break; case SPA_TYPE_Bool: ((struct spa_pod_bool *)self->pod)->value = ((struct spa_pod_bool *)pod->pod)->value; break; case SPA_TYPE_Id: ((struct spa_pod_id *)self->pod)->value = ((struct spa_pod_id *)pod->pod)->value; break; case SPA_TYPE_Int: ((struct spa_pod_int *)self->pod)->value = ((struct spa_pod_int *)pod->pod)->value; break; case SPA_TYPE_Long: ((struct spa_pod_long *)self->pod)->value = ((struct spa_pod_long *)pod->pod)->value; break; case SPA_TYPE_Float: ((struct spa_pod_float *)self->pod)->value = ((struct spa_pod_float *)pod->pod)->value; break; case SPA_TYPE_Double: ((struct spa_pod_double *)self->pod)->value = ((struct spa_pod_double *)pod->pod)->value; break; case SPA_TYPE_Pointer: ((struct spa_pod_pointer *)self->pod)->body.type = ((struct spa_pod_pointer *)pod->pod)->body.type; ((struct spa_pod_pointer *)self->pod)->body.value = ((struct spa_pod_pointer *)pod->pod)->body.value; break; case SPA_TYPE_Fd: ((struct spa_pod_fd *)self->pod)->value = ((struct spa_pod_fd *)pod->pod)->value; break; case SPA_TYPE_Rectangle: ((struct spa_pod_rectangle *)self->pod)->value.width = ((struct spa_pod_rectangle *)pod->pod)->value.width; ((struct spa_pod_rectangle *)self->pod)->value.height = ((struct spa_pod_rectangle *)pod->pod)->value.height; break; case SPA_TYPE_Fraction: ((struct spa_pod_fraction *)self->pod)->value.num = ((struct spa_pod_fraction *)pod->pod)->value.num; ((struct spa_pod_fraction *)self->pod)->value.denom = ((struct spa_pod_fraction *)pod->pod)->value.denom; break; default: g_return_val_if_fail (self->pod->size >= pod->pod->size, FALSE); memcpy (SPA_MEMBER (self->pod, sizeof (struct spa_pod), void), SPA_MEMBER (pod->pod, sizeof (struct spa_pod), void), SPA_MIN (self->pod->size, pod->pod->size)); self->pod->type = pod->pod->type; self->pod->size = pod->pod->size; break; } switch (self->type) { case WP_SPA_POD_PROPERTY: 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; break; case WP_SPA_POD_CONTROL: self->static_pod.data_control.offset = pod->static_pod.data_control.offset; self->static_pod.data_control.type = pod->static_pod.data_control.type; break; case WP_SPA_POD_REGULAR: default: break; } return TRUE; } /** * 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 * * Gets the object properties values of a spa pod object * * 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, ...) { va_list args; gboolean res; va_start (args, id_name); res = wp_spa_pod_get_object_valist (self, type_name, id_name, args); va_end (args); return res; } /** * 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() * * This is the `va_list` version of wp_spa_pod_get_object() * * 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) { 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); const gboolean res = wp_spa_pod_parser_get_valist (p, args); wp_spa_pod_parser_end (p); return res; } /** * wp_spa_pod_get_struct: * @self: the spa pod object * @...: (out): the list of the struct values, followed by %NULL * * Gets the struct's values of a spa pod object * * Returns: TRUE if the struct values were obtained, FALSE otherwise */ gboolean wp_spa_pod_get_struct (WpSpaPod *self, ...) { va_list args; gboolean res; va_start (args, self); res = wp_spa_pod_get_struct_valist (self, args); va_end (args); return res; } /** * wp_spa_pod_get_struct_valist: * @self: the spa pod object * @args: (out): the variable arguments passed to wp_spa_pod_get_struct() * * This is the `va_list` version of wp_spa_pod_get_struct() * * Returns: TRUE if the struct values were obtained, FALSE otherwise */ gboolean wp_spa_pod_get_struct_valist (WpSpaPod *self, va_list args) { g_return_val_if_fail (self, FALSE); g_return_val_if_fail (wp_spa_pod_is_struct (self), FALSE); g_autoptr (WpSpaPodParser) p = wp_spa_pod_parser_new_struct (self); const gboolean res = wp_spa_pod_parser_get_valist (p, args); wp_spa_pod_parser_end (p); return res; } /** * wp_spa_pod_get_property: * @self: the spa pod object * @key: (out) (optional): the name of the property * @value: (out) (optional): the spa pod value of the property * * Gets the name, flags and spa pod value of a spa pod property * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_get_property (const WpSpaPod *self, const char **key, WpSpaPod **value) { 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 (value) *value = wp_spa_pod_new_regular_wrap (self->pod); return TRUE; } /** * 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 * @value: (out) (optional): the spa pod value of the control * * Gets the offset, type name and spa pod value of a spa pod control * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_get_control (const WpSpaPod *self, guint32 *offset, const char **type_name, WpSpaPod **value) { g_return_val_if_fail (self, FALSE); g_return_val_if_fail (wp_spa_pod_is_control (self), FALSE); 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 (value) *value = wp_spa_pod_new_regular_wrap (self->pod); return TRUE; } /** * wp_spa_pod_get_choice_child: * @self: a spa pod choice object * * Gets the child of a spa pod choice object * * Returns: (transfer full): the child of the spa pod choice object */ WpSpaPod * wp_spa_pod_get_choice_child (WpSpaPod *self) { g_return_val_if_fail (wp_spa_pod_is_choice (self), NULL); return wp_spa_pod_new_regular_wrap (SPA_POD_CHOICE_CHILD (self->pod)); } /** * wp_spa_pod_get_array_child: * @self: a spa pod choice object * * Gets the child of a spa pod array object * * Returns: (transfer full): the child of the spa pod array object */ WpSpaPod * wp_spa_pod_get_array_child (WpSpaPod *self) { g_return_val_if_fail (wp_spa_pod_is_array (self), NULL); return wp_spa_pod_new_regular_wrap (SPA_POD_ARRAY_CHILD (self->pod)); } /** * wp_spa_pod_builder_ref: * @self: a spa pod builder object * * Returns: (transfer full): @self with an additional reference count on it */ WpSpaPodBuilder * wp_spa_pod_builder_ref (WpSpaPodBuilder *self) { return (WpSpaPodBuilder *) g_rc_box_acquire ((gpointer) self); } static void wp_spa_pod_builder_free (WpSpaPodBuilder *self) { g_clear_pointer (&self->buf, g_free); } /** * wp_spa_pod_builder_unref: * @self: (transfer full): a spa pod builder object * * Decreases the reference count on @self and frees it when the ref count * reaches zero. */ void wp_spa_pod_builder_unref (WpSpaPodBuilder *self) { g_rc_box_release_full (self, (GDestroyNotify) wp_spa_pod_builder_free); } /** * wp_spa_pod_builder_new_array: * * Creates a spa pod builder of type array * * Returns: (transfer full): the new spa pod builder */ WpSpaPodBuilder * wp_spa_pod_builder_new_array (void) { WpSpaPodBuilder *self = wp_spa_pod_builder_new ( WP_SPA_POD_BUILDER_REALLOC_STEP_SIZE, SPA_TYPE_Array); spa_pod_builder_push_array (&self->builder, &self->frame); return self; } /** * wp_spa_pod_builder_new_choice: * @type_name: the type name of the choice type * * 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) { WpSpaPodBuilder *self = NULL; guint32 type = 0; /* 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); return self; } /** * wp_spa_pod_builder_new_object: * @type_name: the type name of the object type * @id_name: the Id name of the object * * Creates a spa pod builder of type object * * Returns: (transfer full): the new spa pod builder */ 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); /* 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); /* 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); /* Push the object */ spa_pod_builder_push_object (&self->builder, &self->frame, type, id); return self; } /** * wp_spa_pod_builder_new_struct: * * Creates a spa pod builder of type struct * * Returns: (transfer full): the new spa pod builder */ WpSpaPodBuilder * wp_spa_pod_builder_new_struct (void) { WpSpaPodBuilder *self = NULL; self = wp_spa_pod_builder_new (WP_SPA_POD_BUILDER_REALLOC_STEP_SIZE, SPA_TYPE_Struct); spa_pod_builder_push_struct (&self->builder, &self->frame); return self; } /** * wp_spa_pod_builder_new_sequence: * * Creates a spa pod builder of type sequence * * Returns: (transfer full): the new spa pod builder */ WpSpaPodBuilder * wp_spa_pod_builder_new_sequence (guint unit) { WpSpaPodBuilder *self = NULL; self = wp_spa_pod_builder_new (WP_SPA_POD_BUILDER_REALLOC_STEP_SIZE, SPA_TYPE_Sequence); spa_pod_builder_push_sequence (&self->builder, &self->frame, unit); return self; } /** * wp_spa_pod_builder_add_none: * @self: the spa pod builder object * * Adds a none value into the builder */ void wp_spa_pod_builder_add_none (WpSpaPodBuilder *self) { spa_pod_builder_none (&self->builder); } /** * wp_spa_pod_builder_add_boolean: * @self: the spa pod builder object * @value: the boolean value * * Adds a boolean value into the builder */ void wp_spa_pod_builder_add_boolean (WpSpaPodBuilder *self, gboolean value) { spa_pod_builder_bool (&self->builder, value ? true : false); } /** * wp_spa_pod_builder_add_id: * @self: the spa pod builder object * @value: the Id value * * Adds a Id value into the builder */ void wp_spa_pod_builder_add_id (WpSpaPodBuilder *self, guint32 value) { spa_pod_builder_id (&self->builder, value); } /** * wp_spa_pod_builder_add_int: * @self: the spa pod builder object * @value: the int value * * Adds a int value into the builder */ void wp_spa_pod_builder_add_int (WpSpaPodBuilder *self, gint value) { spa_pod_builder_int (&self->builder, value); } /** * wp_spa_pod_builder_add_long: * @self: the spa pod builder object * @value: the long value * * Adds a long value into the builder */ void wp_spa_pod_builder_add_long (WpSpaPodBuilder *self, glong value) { spa_pod_builder_long (&self->builder, value); } /** * wp_spa_pod_builder_add_float: * @self: the spa pod builder object * @value: the float value * * Adds a float value into the builder */ void wp_spa_pod_builder_add_float (WpSpaPodBuilder *self, float value) { spa_pod_builder_float (&self->builder, value); } /** * wp_spa_pod_builder_add_double: * @self: the spa pod builder object * @value: the double value * * Adds a double value into the builder */ void wp_spa_pod_builder_add_double (WpSpaPodBuilder *self, double value) { spa_pod_builder_double (&self->builder, value); } /** * wp_spa_pod_builder_add_string: * @self: the spa pod builder object * @value: the string value * * Adds a string value into the builder */ void wp_spa_pod_builder_add_string (WpSpaPodBuilder *self, const char *value) { spa_pod_builder_string (&self->builder, value); } /** * wp_spa_pod_builder_add_bytes: * @self: the spa pod builder object * @value: the bytes value * @len: the length of the bytes value * * Adds a bytes value with its length into the builder */ void wp_spa_pod_builder_add_bytes (WpSpaPodBuilder *self, gconstpointer value, guint32 len) { spa_pod_builder_bytes (&self->builder, value, len); } /** * wp_spa_pod_builder_add_pointer: * @self: the spa pod builder object * @type_name: the type name that the pointer points to * @value: the pointer vaue * * Adds a pointer value with its type name into the builder */ 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 (); spa_pod_builder_pointer (&self->builder, type, value); } /** * wp_spa_pod_builder_add_fd: * @self: the spa pod builder object * @value: the Fd value * * Adds a Fd value into the builder */ void wp_spa_pod_builder_add_fd (WpSpaPodBuilder *self, gint64 value) { spa_pod_builder_fd (&self->builder, value); } /** * wp_spa_pod_builder_add_rectangle: * @self: the spa pod builder object * @width: the width value of the rectangle * @height: the height value of the rectangle * * Adds the width and height values of a rectangle into the builder */ void wp_spa_pod_builder_add_rectangle (WpSpaPodBuilder *self, guint32 width, guint32 height) { spa_pod_builder_rectangle (&self->builder, width, height); } /** * wp_spa_pod_builder_add_fraction: * @self: the spa pod builder object * @num: the numerator value of the fraction * @denom: the denominator value of the fraction * * Adds the numerator and denominator values of a fraction into the builder */ void wp_spa_pod_builder_add_fraction (WpSpaPodBuilder *self, guint32 num, guint32 denom) { spa_pod_builder_fraction (&self->builder, num, denom); } /** * wp_spa_pod_builder_add_pod: * @self: the spa pod builder object * @pod: the pod value * * Adds a pod value into the builder */ void wp_spa_pod_builder_add_pod (WpSpaPodBuilder *self, const WpSpaPod *pod) { spa_pod_builder_primitive (&self->builder, pod->pod); } /** * wp_spa_pod_builder_add_property: * @self: the spa pod builder object * @key: the name of the property * * Adds a property into the builder */ 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); } /** * wp_spa_pod_builder_add_control: * @self: the spa pod builder object * @offset: the offset of the control * @type_name: the type name of the control * * Adds a control into the builder */ 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); } /** * wp_spa_pod_builder_add: * @self: the spa pod builder object * @...: a list of additional values, followed by %NULL * * Adds a list of values into the builder */ void wp_spa_pod_builder_add (WpSpaPodBuilder *self, ...) { va_list args; va_start (args, self); wp_spa_pod_builder_add_valist (self, args); va_end (args); } /** * wp_spa_pod_builder_add_valist: * @self: the spa pod builder object * @args: the variable arguments passed to wp_spa_pod_builder_add() * * Adds a list of values into the builder */ void wp_spa_pod_builder_add_valist (WpSpaPodBuilder *self, va_list args) { do { const char *format; int n_values = 1; struct spa_pod_frame f; gboolean choice; switch (self->type) { case SPA_TYPE_Object: { guint32 key = 0; 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; spa_pod_builder_prop (&self->builder, key, 0); break; } case 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; spa_pod_builder_control (&self->builder, offset, type); } default: break; } if ((format = va_arg(args, const char *)) == NULL) break; choice = *format == '?'; if (choice) { uint32_t type = spa_choice_from_id (*++format); if (*format != '\0') format++; spa_pod_builder_push_choice (&self->builder, &f, type, 0); n_values = va_arg(args, int); } while (n_values-- > 0) { switch (*format) { case 'P': /* Pod */ case 'V': /* Choice */ case 'O': /* Object */ case 'T': /* Struct */ spa_pod_builder_primitive (&self->builder, va_arg(args, WpSpaPod *)->pod); break; default: SPA_POD_BUILDER_COLLECT(&self->builder, *format, args); break; } } if (choice) spa_pod_builder_pop (&self->builder, &f); } while (TRUE); } /** * wp_spa_pod_builder_end: * @self: the spa pod builder object * * Ends the builder process and returns the constructed spa pod object * * Returns: (transfer full): the constructed spa pod object */ WpSpaPod * wp_spa_pod_builder_end (WpSpaPodBuilder *self) { WpSpaPod *ret = NULL; /* Construct the pod */ ret = g_slice_new0 (WpSpaPod); g_ref_count_init (&ret->ref); ret->type = WP_SPA_POD_REGULAR; 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; return ret; } /** * wp_spa_pod_parser_ref: * @self: a spa pod sparser object * * Returns: (transfer full): @self with an additional reference count on it */ WpSpaPodParser * wp_spa_pod_parser_ref (WpSpaPodParser *self) { return (WpSpaPodParser *) g_rc_box_acquire ((gpointer) self); } static void wp_spa_pod_parser_free (WpSpaPodParser *self) { g_clear_pointer (&self->pod, wp_spa_pod_unref); } /** * wp_spa_pod_parser_unref: * @self: (transfer full): a spa pod parser object * * Decreases the reference count on @self and frees it when the ref count * reaches zero. */ void wp_spa_pod_parser_unref (WpSpaPodParser *self) { g_rc_box_release_full (self, (GDestroyNotify) wp_spa_pod_parser_free); } static WpSpaPodParser * wp_spa_pod_parser_new (WpSpaPod *pod, guint32 type) { WpSpaPodParser *self = g_rc_box_new0 (WpSpaPodParser); self->type = type; self->pod = wp_spa_pod_ref (pod); spa_pod_parser_pod (&self->parser, self->pod->pod); return self; } /** * 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 * * 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) { WpSpaPodParser *self = NULL; guint32 type = 0; guint32 id = 0; 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); 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); return self; } /** * wp_spa_pod_parser_new_struct: * @pod: the struct spa pod to parse * * Creates an struct spa pod parser * * Returns: (transfer full): The new spa pod parser */ WpSpaPodParser * wp_spa_pod_parser_new_struct (WpSpaPod *pod) { WpSpaPodParser *self = NULL; g_return_val_if_fail (wp_spa_pod_is_struct (pod), NULL); self = wp_spa_pod_parser_new (pod, SPA_TYPE_Struct); spa_pod_parser_push_struct (&self->parser, &self->frame); return self; } /** * wp_spa_pod_parser_get_boolean: * @self: the spa pod parser object * @value: (out): the boolean value * * Gets the boolean value from a spa pod parser * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_parser_get_boolean (WpSpaPodParser *self, gboolean *value) { g_return_val_if_fail (value, FALSE); bool v = FALSE; gboolean res = spa_pod_parser_get_bool (&self->parser, &v) >= 0; *value = v ? TRUE : FALSE; return res; } /** * wp_spa_pod_parser_get_id: * @self: the spa pod parser object * @value: (out): the Id value * * Gets the Id value from a spa pod parser object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_parser_get_id (WpSpaPodParser *self, guint32 *value) { g_return_val_if_fail (value, FALSE); return spa_pod_parser_get_id (&self->parser, value) >= 0; } /** * wp_spa_pod_parser_get_int: * @self: the spa pod parser object * @value: (out): the int value * * Gets the int value from a spa pod parser object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_parser_get_int (WpSpaPodParser *self, gint *value) { g_return_val_if_fail (value, FALSE); return spa_pod_parser_get_int (&self->parser, value) >= 0; } /** * wp_spa_pod_parser_get_long: * @self: the spa pod parser object * @value: (out): the long value * * Gets the long value from a spa pod parser object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_parser_get_long (WpSpaPodParser *self, glong *value) { g_return_val_if_fail (value, FALSE); return spa_pod_parser_get_long (&self->parser, value) >= 0; } /** * wp_spa_pod_parser_get_float: * @self: the spa pod parser object * @value: (out): the float value * * Gets the float value from a spa pod parser object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_parser_get_float (WpSpaPodParser *self, float *value) { g_return_val_if_fail (value, FALSE); return spa_pod_parser_get_float (&self->parser, value) >= 0; } /** * wp_spa_pod_parser_get_double: * @self: the spa pod parser object * @value: (out): the double value * * Gets the double value from a spa pod parser object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_parser_get_double (WpSpaPodParser *self, double *value) { g_return_val_if_fail (value, FALSE); return spa_pod_parser_get_double (&self->parser, value) >= 0; } /** * wp_spa_pod_parser_get_string: * @self: the spa pod parser object * @value: (out): the string value * * Gets the string value from a spa pod parser object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_parser_get_string (WpSpaPodParser *self, const char **value) { g_return_val_if_fail (value, FALSE); return spa_pod_parser_get_string (&self->parser, value) >= 0; } /** * wp_spa_pod_parser_get_bytes: * @self: the spa pod parser object * @value: (out): the bytes value * @len: (out): the length of the bytes value * * Gets the bytes value and its length from a spa pod parser object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_parser_get_bytes (WpSpaPodParser *self, gconstpointer *value, guint32 *len) { return spa_pod_parser_get_bytes (&self->parser, value, len) >= 0; } /** * 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 * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_parser_get_pointer (WpSpaPodParser *self, const char **type_name, 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; } /** * wp_spa_pod_parser_get_fd: * @self: the spa pod parser object * @value: (out): the Fd value * * Gets the Fd value from a spa pod parser object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_parser_get_fd (WpSpaPodParser *self, gint64 *value) { g_return_val_if_fail (value, FALSE); return spa_pod_parser_get_fd (&self->parser, value) >= 0; } /** * wp_spa_pod_parser_get_rectangle: * @self: the spa pod parser object * @width: (out): the rectangle's width value * @height: (out): the rectangle's height value * * Gets the rectangle's width and height value from a spa pod parser object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_parser_get_rectangle (WpSpaPodParser *self, guint32 *width, guint32 *height) { struct spa_rectangle r = { 0, }; gboolean res = spa_pod_parser_get_rectangle (&self->parser, &r) >= 0; if (width) *width = r.width; if (height) *height = r.height; return res; } /** * wp_spa_pod_parser_get_fraction: * @self: the spa pod parser object * @num: (out): the fractions's numerator value * @denom: (out): the fractions's denominator value * * Gets the fractions's numerator and denominator value from a spa pod parser * object * * Returns: TRUE if the value was obtained, FALSE otherwise */ gboolean wp_spa_pod_parser_get_fraction (WpSpaPodParser *self, guint32 *num, guint32 *denom) { struct spa_fraction f = { 0, }; gboolean res = spa_pod_parser_get_fraction (&self->parser, &f) >= 0; if (num) *num = f.num; if (denom) *denom = f.denom; return res; } /** * wp_spa_pod_parser_get_pod: * @self: the spa pod parser object * * Gets the spa pod value from a spa pod parser object * * Returns: (transfer full): The spa pod value or NULL if it could not be * obtained */ WpSpaPod * wp_spa_pod_parser_get_pod (WpSpaPodParser *self) { struct spa_pod *p = NULL; gboolean res = spa_pod_parser_get_pod (&self->parser, &p) >= 0; if (!res || !p) return NULL; return wp_spa_pod_new_regular_wrap (p); } /** * wp_spa_pod_parser_get: * @self: the spa pod parser object * @...: (out): a list of values to get, followed by %NULL * * Gets a list of values from a spa pod parser object * * Returns: TRUE if the values were obtained, FALSE otherwise */ gboolean wp_spa_pod_parser_get (WpSpaPodParser *self, ...) { gboolean res; va_list args; va_start (args, self); res = wp_spa_pod_parser_get_valist (self, args); va_end (args); return res; } /** * wp_spa_pod_parser_get_valist: * @self: the spa pod parser object * @args: the variable arguments passed to wp_spa_pod_parser_get() * * This is the `va_list` version of wp_spa_pod_parser_get() * * Returns: TRUE if the values were obtained, FALSE otherwise */ gboolean wp_spa_pod_parser_get_valist (WpSpaPodParser *self, va_list args) { const struct spa_pod_prop *prop = NULL; do { bool optional; const struct spa_pod *pod = NULL; const char *format; if (self->type == SPA_TYPE_Object) { guint32 key = 0; const struct spa_pod_object *object; 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); pod = prop ? &prop->value : NULL; } if ((format = va_arg(args, char *)) == NULL) break; if (self->type == SPA_TYPE_Struct) pod = spa_pod_parser_next (&self->parser); if ((optional = (*format == '?'))) format++; if (!spa_pod_parser_can_collect (pod, *format)) { if (!optional) return FALSE; SPA_POD_PARSER_SKIP (*format, args); } else { if (pod->type == SPA_TYPE_Choice && *format != 'V' && SPA_POD_CHOICE_TYPE(pod) == SPA_CHOICE_None) pod = SPA_POD_CHOICE_CHILD(pod); switch (*format) { case 'P': /* Pod */ case 'V': /* Choice */ case 'O': /* Object */ case 'T': /* Struct */ *va_arg(args, WpSpaPod**) = wp_spa_pod_new_regular_wrap_copy (pod); break; default: SPA_POD_PARSER_COLLECT (pod, *format, args); break; } } } while (TRUE); return TRUE; } /** * wp_spa_pod_parser_end: * @self: the spa pod parser object * * Ends the parser process */ void wp_spa_pod_parser_end (WpSpaPodParser *self) { spa_pod_parser_pop (&self->parser, &self->frame); } struct _WpSpaPodIterator { WpSpaPod *pod; union { gpointer value; /* Array and Choice */ struct spa_pod *pod; /* Struct */ struct spa_pod_prop *prop; /* Object */ struct spa_pod_control *control; /* Sequence */ } curr; }; typedef struct _WpSpaPodIterator WpSpaPodIterator; static gboolean wp_spa_pod_iterator_next_choice (WpSpaPodIterator *self, GValue *item) { struct spa_pod_choice *pod_choice = (struct spa_pod_choice *) self->pod->pod; if (!self->curr.value) self->curr.value = SPA_MEMBER (&pod_choice->body, sizeof(struct spa_pod_choice_body), void); else self->curr.value = SPA_MEMBER (self->curr.value, pod_choice->body.child.size, void); if (self->curr.value >= SPA_MEMBER(&pod_choice->body, SPA_POD_BODY_SIZE (pod_choice), void)) return FALSE; if (item) { g_value_init (item, G_TYPE_POINTER); g_value_set_pointer (item, self->curr.value); } return TRUE; } static gboolean wp_spa_pod_iterator_next_array (WpSpaPodIterator *self, GValue *item) { struct spa_pod_array *pod_arr = (struct spa_pod_array *) self->pod->pod; if (!self->curr.value) self->curr.value = SPA_MEMBER (&pod_arr->body, sizeof(struct spa_pod_array_body), void); else self->curr.value = SPA_MEMBER (self->curr.value, pod_arr->body.child.size, void); if (self->curr.value >= SPA_MEMBER(&pod_arr->body, SPA_POD_BODY_SIZE (pod_arr), void)) return FALSE; if (item) { g_value_init (item, G_TYPE_POINTER); g_value_set_pointer (item, self->curr.value); } return TRUE; } static gboolean wp_spa_pod_iterator_next_object (WpSpaPodIterator *self, GValue *item) { struct spa_pod_object *pod_obj = (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); else self->curr.prop = spa_pod_prop_next (self->curr.prop); if (!spa_pod_prop_is_inside (&pod_obj->body, SPA_POD_BODY_SIZE (pod_obj), self->curr.prop)) return FALSE; if (item) { g_value_init (item, WP_TYPE_SPA_POD); g_value_take_boxed (item, wp_spa_pod_new_property_wrap ( self->pod->static_pod.data_property.table, self->curr.prop->key, self->curr.prop->flags, &self->curr.prop->value)); } return TRUE; } static gboolean wp_spa_pod_iterator_next_struct (WpSpaPodIterator *self, GValue *item) { if (!self->curr.pod) self->curr.pod = SPA_POD_BODY (self->pod->pod); else self->curr.pod = spa_pod_next (self->curr.pod); if (!spa_pod_is_inside (SPA_POD_BODY (self->pod->pod), SPA_POD_BODY_SIZE (self->pod->pod), self->curr.pod)) return FALSE; if (item) { g_value_init (item, WP_TYPE_SPA_POD); g_value_take_boxed (item, wp_spa_pod_new_regular_wrap (self->curr.pod)); } return TRUE; } static gboolean wp_spa_pod_iterator_next_sequence (WpSpaPodIterator *self, GValue *item) { struct spa_pod_sequence *pod_seq = (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); else self->curr.control = spa_pod_control_next (self->curr.control); if (!spa_pod_control_is_inside (&pod_seq->body, SPA_POD_BODY_SIZE (pod_seq), self->curr.control)) return FALSE; if (item) { g_value_init (item, WP_TYPE_SPA_POD); g_value_take_boxed (item, wp_spa_pod_new_control_wrap ( self->curr.control->offset, self->curr.control->type, &self->curr.control->value)); } return TRUE; } static void wp_spa_pod_iterator_reset (WpIterator *iterator) { WpSpaPodIterator *self = wp_iterator_get_user_data (iterator); self->curr.value = NULL; self->curr.pod = NULL; self->curr.prop = NULL; self->curr.control = NULL; } static gboolean wp_spa_pod_iterator_next (WpIterator *iterator, GValue *item) { WpSpaPodIterator *self = wp_iterator_get_user_data (iterator); switch (self->pod->pod->type) { case SPA_TYPE_Choice: return wp_spa_pod_iterator_next_choice (self, item); case SPA_TYPE_Array: return wp_spa_pod_iterator_next_array (self, item); case SPA_TYPE_Object: return wp_spa_pod_iterator_next_object (self, item); case SPA_TYPE_Struct: return wp_spa_pod_iterator_next_struct (self, item); case SPA_TYPE_Sequence: return wp_spa_pod_iterator_next_sequence (self, item); default: break; } return FALSE; } static gboolean wp_spa_pod_iterator_fold (WpIterator *iterator, WpIteratorFoldFunc func, GValue *ret, gpointer data) { WpSpaPodIterator *self = wp_iterator_get_user_data (iterator); wp_iterator_reset (iterator); switch (self->pod->pod->type) { case SPA_TYPE_Choice: { struct spa_pod_choice *pod_choice = (struct spa_pod_choice *) self->pod->pod; gpointer p = NULL; SPA_POD_CHOICE_FOREACH (pod_choice, p) { GValue v = G_VALUE_INIT; g_value_init (&v, G_TYPE_POINTER); g_value_set_pointer (&v, p); const gboolean res = func (&v, ret, data); g_value_unset (&v); if (!res) return FALSE; } break; } case SPA_TYPE_Array: { struct spa_pod_array *pod_arr = (struct spa_pod_array *) self->pod->pod; gpointer p = NULL; SPA_POD_ARRAY_FOREACH (pod_arr, p) { GValue v = G_VALUE_INIT; g_value_init (&v, G_TYPE_POINTER); g_value_set_pointer (&v, p); const gboolean res = func (&v, ret, data); g_value_unset (&v); if (!res) return FALSE; } break; } case SPA_TYPE_Object: { struct spa_pod_object *pod_obj = (struct spa_pod_object *) self->pod->pod; struct spa_pod_prop *p = NULL; SPA_POD_OBJECT_FOREACH (pod_obj, p) { GValue v = G_VALUE_INIT; g_value_init (&v, WP_TYPE_SPA_POD); g_value_take_boxed (&v, wp_spa_pod_new_property_wrap ( self->pod->static_pod.data_property.table, p->key, p->flags, &p->value)); const gboolean res = func (&v, ret, data); g_value_unset (&v); if (!res) return FALSE; } break; } case SPA_TYPE_Struct: { struct spa_pod *p = NULL; SPA_POD_STRUCT_FOREACH (self->pod->pod, p) { GValue v = G_VALUE_INIT; g_value_init (&v, WP_TYPE_SPA_POD); g_value_take_boxed (&v, wp_spa_pod_new_regular_wrap (p)); const gboolean res = func (&v, ret, data); g_value_unset (&v); if (!res) return FALSE; } break; } case SPA_TYPE_Sequence: { struct spa_pod_sequence *pod_seq = (struct spa_pod_sequence *) self->pod->pod; struct spa_pod_control *p = NULL; SPA_POD_SEQUENCE_FOREACH (pod_seq, p) { GValue v = G_VALUE_INIT; g_value_init (&v, WP_TYPE_SPA_POD); g_value_take_boxed (&v, wp_spa_pod_new_control_wrap (p->offset, p->type, &p->value)); const gboolean res = func (&v, ret, data); g_value_unset (&v); if (!res) return FALSE; } break; } default: return FALSE; } return TRUE; } static void wp_spa_pod_iterator_finalize (WpIterator *iterator) { WpSpaPodIterator *self = wp_iterator_get_user_data (iterator); g_clear_pointer (&self->pod, wp_spa_pod_unref); } /** * wp_spa_pod_iterator_new: * @pod: a spa pod object * * Creates a new iterator for a spa pod object * * Returns: (transfer full): the new spa pod iterator */ WpIterator * wp_spa_pod_iterator_new (WpSpaPod *pod) { static const WpIteratorMethods methods = { .reset = wp_spa_pod_iterator_reset, .next = wp_spa_pod_iterator_next, .fold = wp_spa_pod_iterator_fold, .foreach = NULL, .finalize = wp_spa_pod_iterator_finalize }; WpIterator *it = wp_iterator_new (&methods, sizeof (WpSpaPodIterator)); WpSpaPodIterator *self = wp_iterator_get_user_data (it); self->pod = wp_spa_pod_ref (pod); return it; }