wireplumber/lib/wp/spa-pod.c
George Kiagiadakis 4736d56557 log: implement a log topics system, like pipewire
The intention is to make checks for enabled log topics faster.

Every topic has its own structure that is statically defined in the file
where the logs are printed from. The structure is initialized transparently
when it is first used and it contains all the log level flags for the levels
that this topic should print messages. It is then checked on the wp_log()
macro before printing the message.

Topics from SPA/PipeWire are also handled natively, so messages are printed
directly without checking if the topic is enabled, since the PipeWire and SPA
macros do the checking themselves.

Messages coming from GLib are checked inside the handler.

An internal WpLogFields object is used to manage the state of each log
message, populating all the fields appropriately from the place they
are coming from (wp_log, spa_log, glib log), formatting the message and
then printing it. For printing to the journald, we still use the glib
message handler, converting all the needed fields to GLogField on demand.
That message handler does not do any checks for the topic or the level, so
we can just call it to send the message.
2023-05-16 20:42:28 +03:00

3098 lines
84 KiB
C

/* WirePlumber
*
* Copyright © 2020 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include "spa-pod.h"
#include "spa-type.h"
#include "log.h"
#include <spa/utils/type-info.h>
#include <spa/pod/builder.h>
#include <spa/pod/parser.h>
#include <spa/pod/filter.h>
WP_DEFINE_LOCAL_LOG_TOPIC ("wp-spa-pod")
#define WP_SPA_POD_BUILDER_REALLOC_STEP_SIZE 64
#define WP_SPA_POD_ID_PROPERTY_NAME_MAX 16
/*! \defgroup wpspapod WpSpaPod */
/*!
* \struct WpSpaPod
*/
/*!
* \struct WpSpaPodBuilder
*/
/*!
* \struct WpSpaPodParser
*/
enum {
FLAG_NO_OWNERSHIP = (1 << 0),
FLAG_CONSTANT = (1 << 1)
};
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 {
WpSpaIdTable table;
guint32 key;
guint32 flags;
gchar id_key_name[WP_SPA_POD_ID_PROPERTY_NAME_MAX];
} data_property; /* Only used for property pods */
struct wp_control_data {
guint32 offset;
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 */
struct spa_pod *pod;
};
G_DEFINE_BOXED_TYPE (WpSpaPod, wp_spa_pod, wp_spa_pod_ref, wp_spa_pod_unref)
struct _WpSpaPodBuilder
{
struct spa_pod_builder builder;
struct spa_pod_frame frame;
WpSpaType type;
size_t size;
guint8 *buf;
};
G_DEFINE_BOXED_TYPE (WpSpaPodBuilder, wp_spa_pod_builder,
wp_spa_pod_builder_ref, wp_spa_pod_builder_unref)
struct _WpSpaPodParser
{
struct spa_pod_parser parser;
struct spa_pod_frame frame;
WpSpaType type;
WpSpaPod *pod;
};
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, WpSpaType 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;
}
/*!
* \brief Increases the reference count of a spa pod object
* \ingroup wpspapod
* \param self a spa pod object
* \returns (transfer full): \a 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);
}
/*!
* \brief Decreases the reference count on \a self and frees it when the ref
* count reaches zero.
* \ingroup wpspapod
* \param self (transfer full): a spa pod object
*/
void
wp_spa_pod_unref (WpSpaPod *self)
{
if (g_ref_count_dec (&self->ref))
wp_spa_pod_free (self);
}
static WpSpaPod *
wp_spa_pod_new (const struct spa_pod *pod, WpSpaPodType type, guint32 flags)
{
WpSpaPod *self = g_slice_new0 (WpSpaPod);
g_ref_count_init (&self->ref);
self->flags = flags;
self->type = type;
/* Copy the reference if no ownership, otherwise copy the pod */
if (self->flags & FLAG_NO_OWNERSHIP) {
self->pod = (struct spa_pod *)pod;
} else {
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) {
self->static_pod.data_property.table =
wp_spa_type_get_values_table (((struct spa_pod_object *) pod)->body.type);
}
return self;
}
/*!
* \brief Constructs a new WpSpaPod that wraps the given `spa_pod`.
*
* \ingroup wpspapod
* \param pod a spa_pod
* \returns a new WpSpaPod that references the data in \a pod. \a pod is not
* copied, so it needs to stay alive. The returned WpSpaPod can be modified
* by using the setter functions, in which case \a pod will be modified
* underneath.
*/
WpSpaPod *
wp_spa_pod_new_wrap (struct spa_pod *pod)
{
return wp_spa_pod_new (pod, WP_SPA_POD_REGULAR, FLAG_NO_OWNERSHIP);
}
/*!
* \brief Constructs a new immutable WpSpaPod that wraps the given `spa_pod`.
*
* \ingroup wpspapod
* \param pod a constant spa_pod
* \returns a new WpSpaPod that references the data in \a pod. \a pod is not
* copied, so it needs to stay alive. The returned WpSpaPod cannot be
* modified, unless it's copied first.
*/
WpSpaPod *
wp_spa_pod_new_wrap_const (const struct spa_pod *pod)
{
return wp_spa_pod_new (pod, WP_SPA_POD_REGULAR,
FLAG_NO_OWNERSHIP | FLAG_CONSTANT);
}
static WpSpaPod *
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);
self->static_pod.data_property.table = table;
self->static_pod.data_property.key = key;
self->static_pod.data_property.flags = flags;
return self;
}
static WpSpaPod *
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);
self->static_pod.data_control.offset = offset;
self->static_pod.data_control.type = type;
return self;
}
#if 0
/* 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 (WpSpaIdTable table, guint32 key,
guint32 flags, const struct spa_pod *pod)
{
WpSpaPod *self = wp_spa_pod_new (pod, WP_SPA_POD_PROPERTY,
FLAG_NO_OWNERSHIP | FLAG_CONSTANT);
self->static_pod.data_property.table = table;
self->static_pod.data_property.key = key;
self->static_pod.data_property.flags = flags;
return self;
}
static WpSpaPod *
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,
FLAG_NO_OWNERSHIP | FLAG_CONSTANT);
self->static_pod.data_control.offset = offset;
self->static_pod.data_control.type = type;
return self;
}
#endif
static WpSpaPod *
wp_spa_pod_new_wrap_copy (const struct spa_pod *pod)
{
return wp_spa_pod_new (pod, WP_SPA_POD_REGULAR, 0);
}
static WpSpaPod *
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);
self->static_pod.data_property.table = table;
self->static_pod.data_property.key = key;
self->static_pod.data_property.flags = flags;
return self;
}
static WpSpaPod *
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);
self->static_pod.data_control.offset = offset;
self->static_pod.data_control.type = type;
return self;
}
/*!
* \brief Converts a WpSpaPod pointer to a `struct spa_pod` one, for use with
* native pipewire & spa functions. The returned pointer is owned by WpSpaPod
* and may not be modified or freed.
*
* \ingroup wpspapod
* \param self a spa pod object
* \returns a const pointer to the underlying spa_pod structure
*/
const struct spa_pod *
wp_spa_pod_get_spa_pod (const WpSpaPod *self)
{
return self->pod;
}
/*!
* \brief 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.
*
* \ingroup wpspapod
* \param self a spa pod
* \returns (transfer none): the type of the spa pod
*/
WpSpaType
wp_spa_pod_get_spa_type (WpSpaPod *self)
{
g_return_val_if_fail (self != NULL, WP_SPA_TYPE_INVALID);
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);
}
/*!
* \brief If the pod is a Choice, this gets the choice type
* (Range, Step, Enum, ...)
*
* \ingroup wpspapod
* \param self a choice pod
* \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_choice (self), NULL);
return wp_spa_id_value_from_number (
SPA_TYPE_INFO_Choice, SPA_POD_CHOICE_TYPE (self->pod));
}
/*!
* \brief Copies a spa pod object
*
* \ingroup wpspapod
* \param other a spa pod object
* \returns (transfer full): The newly copied spa pod
*/
WpSpaPod *
wp_spa_pod_copy (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_wrap_copy (other->pod);
}
/*!
* \brief Checks if the pod is the unique owner of its data or not
*
* \ingroup wpspapod
* \param self a spa pod object
* \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);
}
/*!
* \brief If \a self is not uniquely owned already, then it is unrefed and a
* copy of it is returned instead. You should always consider \a self as unsafe
* to use after this call and you should use the returned object instead.
*
* \ingroup wpspapod
* \param self (transfer full): a spa pod object
* \returns (transfer full): the uniquely owned spa pod object which may or may
* not be the same as \a 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;
}
/*!
* \brief Creates a spa pod of type None
* \ingroup wpspapod
* \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;
}
/*!
* \brief Creates a spa pod of type boolean
*
* \ingroup wpspapod
* \param value the boolean value
* \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;
}
/*!
* \brief Creates a spa pod of type Id
*
* \ingroup wpspapod
* \param value the Id value
* \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;
}
/*!
* \brief Creates a spa pod of type int
*
* \ingroup wpspapod
* \param value the int value
* \returns (transfer full): The new spa pod
*/
WpSpaPod *
wp_spa_pod_new_int (gint32 value)
{
WpSpaPod *self = g_slice_new0 (WpSpaPod);
g_ref_count_init (&self->ref);
self->type = WP_SPA_POD_REGULAR;
self->static_pod.pod_int = SPA_POD_INIT_Int (value);
self->pod = &self->static_pod.pod_int.pod;
return self;
}
/*!
* \brief Creates a spa pod of type long
*
* \ingroup wpspapod
* \param value the long value
* \returns (transfer full): The new spa pod
*/
WpSpaPod *
wp_spa_pod_new_long (gint64 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;
}
/*!
* \brief Creates a spa pod of type float
*
* \ingroup wpspapod
* \param value the float value
* \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;
}
/*!
* \brief Creates a spa pod of type double
*
* \ingroup wpspapod
* \param value the double value
* \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;
}
/*!
* \brief Creates a spa pod of type string
*
* \ingroup wpspapod
* \param value the string value
* \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;
}
/*!
* \brief Creates a spa pod of type bytes
*
* \ingroup wpspapod
* \param value the bytes value
* \param len the length of the bytes value
* \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;
}
/*!
* \brief Creates a spa pod of type pointer
*
* \ingroup wpspapod
* \param type_name the name of the type of the pointer
* \param value the pointer value
* \returns (transfer full): The new spa pod
*/
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;
self->static_pod.pod_pointer = SPA_POD_INIT_Pointer (type, value);
self->pod = &self->static_pod.pod_pointer.pod;
return self;
}
/*!
* \brief Creates a spa pod of type Fd
*
* \ingroup wpspapod
* \param value the Fd value
* \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;
}
/*!
* \brief Creates a spa pod of type rectangle
*
* \ingroup wpspapod
* \param width the width value of the rectangle
* \param height the height value of the 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;
}
/*!
* \brief Creates a spa pod of type fraction
*
* \ingroup wpspapod
* \param num the numerator value of the fraction
* \param denom the denominator value of the 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;
}
/*!
* \brief Creates a spa pod of type choice
*
* \ingroup wpspapod
* \param choice_type the name of the choice type ("Range", "Step", ...),
* \param ... a list of choice values, followed by NULL
* \returns (transfer full): The new spa pod
*/
WpSpaPod *
wp_spa_pod_new_choice (const char *choice_type, ...)
{
WpSpaPod *self;
va_list args;
va_start (args, choice_type);
self = wp_spa_pod_new_choice_valist (choice_type, args);
va_end (args);
return self;
}
/*!
* \brief This is the `va_list` version of wp_spa_pod_new_choice()
*
* \ingroup wpspapod
* \param choice_type the name of the choice type ("Range", "Step", ...)
* \param args the variable arguments passed to wp_spa_pod_new_choice()
* \returns (transfer full): The new spa pod
*/
WpSpaPod *
wp_spa_pod_new_choice_valist (const char *choice_type, va_list args)
{
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);
}
/*!
* \brief Creates a spa pod of type object
*
* \ingroup wpspapod
* \param type_name the type name of the object type
* \param id_name the id name of the object,
* \param ... a list of object properties with their values, followed by NULL
* \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;
}
/*!
* \brief This is the `va_list` version of wp_spa_pod_new_object()
*
* \ingroup wpspapod
* \param type_name the type name of the object type
* \param id_name the id name of the object
* \param args the variable arguments passed to 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);
}
/*!
* \brief Creates a spa pod of type sequence
*
* \ingroup wpspapod
* \param unit the unit of the sequence
* \param ... a list of sequence controls with their values, followed by NULL
* \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;
}
/*!
* \brief This is the `va_list` version of wp_spa_pod_new_sequence()
*
* \ingroup wpspapod
* \param unit the unit of the sequence
* \param args the variable arguments passed to 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);
}
/*!
* \brief Checks wether the spa pod is of type none or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type none, FALSE otherwise
*/
gboolean
wp_spa_pod_is_none (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_none (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type boolean or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type boolean, FALSE otherwise
*/
gboolean
wp_spa_pod_is_boolean (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_bool (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type Id or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type Id, FALSE otherwise
*/
gboolean
wp_spa_pod_is_id (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_id (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type int or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type int, FALSE otherwise
*/
gboolean
wp_spa_pod_is_int (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_int (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type long or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type long, FALSE otherwise
*/
gboolean
wp_spa_pod_is_long (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_long (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type float or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type float, FALSE otherwise
*/
gboolean
wp_spa_pod_is_float (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_float (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type double or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type double, FALSE otherwise
*/
gboolean
wp_spa_pod_is_double (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_double (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type string or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type string, FALSE otherwise
*/
gboolean
wp_spa_pod_is_string (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_string (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type bytes or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type bytes, FALSE otherwise
*/
gboolean
wp_spa_pod_is_bytes (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_bytes (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type pointer or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type pointer, FALSE otherwise
*/
gboolean
wp_spa_pod_is_pointer (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_pointer (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type Fd or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type Fd, FALSE otherwise
*/
gboolean
wp_spa_pod_is_fd (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_fd (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type rectangle or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type rectangle, FALSE otherwise
*/
gboolean
wp_spa_pod_is_rectangle (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_rectangle (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type fraction or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type fraction, FALSE otherwise
*/
gboolean
wp_spa_pod_is_fraction (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_fraction (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type array or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type array, FALSE otherwise
*/
gboolean
wp_spa_pod_is_array (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_array (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type choice or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type choice, FALSE otherwise
*/
gboolean
wp_spa_pod_is_choice (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_choice (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type object or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type object, FALSE otherwise
*/
gboolean
wp_spa_pod_is_object (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_object (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type struct or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type struct, FALSE otherwise
*/
gboolean
wp_spa_pod_is_struct (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_struct (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type sequence or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type sequence, FALSE otherwise
*/
gboolean
wp_spa_pod_is_sequence (WpSpaPod *self)
{
return self->type == WP_SPA_POD_REGULAR && spa_pod_is_sequence (self->pod);
}
/*!
* \brief Checks wether the spa pod is of type property or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type property, FALSE otherwise
*/
gboolean
wp_spa_pod_is_property (WpSpaPod *self)
{
return self->type == WP_SPA_POD_PROPERTY;
}
/*!
* \brief Checks wether the spa pod is of type control or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \returns TRUE if it is of type control, FALSE otherwise
*/
gboolean
wp_spa_pod_is_control (WpSpaPod *self)
{
return self->type == WP_SPA_POD_CONTROL;
}
/*!
* \brief Gets the boolean value of a spa pod object
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value (out): the boolean value
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_get_boolean (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;
}
/*!
* \brief Gets the Id value of a spa pod object
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value (out): the Id value
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_get_id (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;
}
/*!
* \brief Gets the int value of a spa pod object
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value (out): the int value
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_get_int (WpSpaPod *self, gint32 *value)
{
g_return_val_if_fail (self, FALSE);
g_return_val_if_fail (value, FALSE);
return spa_pod_get_int (self->pod, value) >= 0;
}
/*!
* \brief Gets the long value of a spa pod object
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value (out): the long value
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_get_long (WpSpaPod *self, gint64 *value)
{
g_return_val_if_fail (self, FALSE);
g_return_val_if_fail (value, FALSE);
return spa_pod_get_long (self->pod, value) >= 0;
}
/*!
* \brief Gets the float value of a spa pod object
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value (out): the float value
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_get_float (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;
}
/*!
* \brief Gets the double value of a spa pod object
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value (out): the double value
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_get_double (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;
}
/*!
* \brief Gets the string value of a spa pod object
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value (out): the string value
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_get_string (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;
}
/*!
* \brief Gets the bytes value and its len of a spa pod object
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value (out): the bytes value
* \param len (out): the length of the bytes value
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_get_bytes (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;
}
/*!
* \brief Gets the pointer value and its type name of a spa pod object
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value (out): the pointer value
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_get_pointer (WpSpaPod *self, gconstpointer *value)
{
g_return_val_if_fail (self, FALSE);
g_return_val_if_fail (value, FALSE);
guint32 type = 0;
return spa_pod_get_pointer (self->pod, &type, value) >= 0;
}
/*!
* \brief Gets the Fd value of a spa pod object
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value (out): the Fd value
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_get_fd (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;
}
/*!
* \brief Gets the rectangle's width and height value of a spa pod object
*
* \ingroup wpspapod
* \param self the spa pod object
* \param width (out): the rectangle's width value
* \param height (out): the rectangle's height value
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_get_rectangle (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;
}
/*!
* \brief Gets the fractions's numerator and denominator value of a spa pod object
*
* \ingroup wpspapod
* \param self the spa pod object
* \param num (out): the fractions's numerator value
* \param denom (out): the fractions's denominator value
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_get_fraction (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;
}
/*!
* \brief Sets a boolean value in the spa pod object.
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value the boolean value
* \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);
g_return_val_if_fail (!(self->flags & FLAG_CONSTANT), FALSE);
((struct spa_pod_bool *)self->pod)->value = value ? true : false;
return TRUE;
}
/*!
* \brief Sets an Id value in the spa pod object.
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value the Id value
* \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);
g_return_val_if_fail (!(self->flags & FLAG_CONSTANT), FALSE);
((struct spa_pod_id *)self->pod)->value = value;
return TRUE;
}
/*!
* \brief Sets an int value in the spa pod object.
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value the int value
* \returns TRUE if the value could be set, FALSE othewrise.
*/
gboolean
wp_spa_pod_set_int (WpSpaPod *self, gint32 value)
{
g_return_val_if_fail (wp_spa_pod_is_int (self), FALSE);
g_return_val_if_fail (!(self->flags & FLAG_CONSTANT), FALSE);
((struct spa_pod_int *)self->pod)->value = value;
return TRUE;
}
/*!
* \brief Sets a long value in the spa pod object.
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value the long value
* \returns TRUE if the value could be set, FALSE othewrise.
*/
gboolean
wp_spa_pod_set_long (WpSpaPod *self, gint64 value)
{
g_return_val_if_fail (wp_spa_pod_is_long (self), FALSE);
g_return_val_if_fail (!(self->flags & FLAG_CONSTANT), FALSE);
((struct spa_pod_long *)self->pod)->value = value;
return TRUE;
}
/*!
* \brief Sets a float value in the spa pod object.
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value the float value
* \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);
g_return_val_if_fail (!(self->flags & FLAG_CONSTANT), FALSE);
((struct spa_pod_float *)self->pod)->value = value;
return TRUE;
}
/*!
* \brief Sets a double value in the spa pod object.
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value the double value
* \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);
g_return_val_if_fail (!(self->flags & FLAG_CONSTANT), FALSE);
((struct spa_pod_double *)self->pod)->value = value;
return TRUE;
}
/*!
* \brief Sets a pointer value with its type name in the spa pod object.
*
* \ingroup wpspapod
* \param self the spa pod object
* \param type_name the name of the type of the pointer
* \param value the pointer value
* \returns TRUE if the value could be set, FALSE othewrise.
*/
gboolean
wp_spa_pod_set_pointer (WpSpaPod *self, const char *type_name,
gconstpointer value)
{
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);
((struct spa_pod_pointer *)self->pod)->body.type = type;
((struct spa_pod_pointer *)self->pod)->body.value = value;
return TRUE;
}
/*!
* \brief Sets a Fd value in the spa pod object.
*
* \ingroup wpspapod
* \param self the spa pod object
* \param value the Fd value
* \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);
g_return_val_if_fail (!(self->flags & FLAG_CONSTANT), FALSE);
((struct spa_pod_fd *)self->pod)->value = value;
return TRUE;
}
/*!
* \brief Sets the width and height values of a rectangle in the spa pod object.
*
* \ingroup wpspapod
* \param self the spa pod object
* \param width the width value of the rectangle
* \param height the height value of the rectangle
* \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);
g_return_val_if_fail (!(self->flags & FLAG_CONSTANT), FALSE);
((struct spa_pod_rectangle *)self->pod)->value.width = width;
((struct spa_pod_rectangle *)self->pod)->value.height = height;
return TRUE;
}
/*!
* \brief Sets the numerator and denominator values of a fraction in the
* spa pod object.
*
* \ingroup wpspapod
* \param self the spa pod object
* \param num the numerator value of the farction
* \param denom the denominator value of the fraction
* \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);
g_return_val_if_fail (!(self->flags & FLAG_CONSTANT), FALSE);
((struct spa_pod_fraction *)self->pod)->value.num = num;
((struct spa_pod_fraction *)self->pod)->value.denom = denom;
return TRUE;
}
/*!
* \brief Sets the value of a spa pod object in the current spa pod object.
* The spa pod objects must be of the same value.
*
* \ingroup wpspapod
* \param self the spa pod object
* \param pod the pod with the value to be set
* \returns TRUE if the value could be set, FALSE othewrise.
*/
gboolean
wp_spa_pod_set_pod (WpSpaPod *self, 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);
g_return_val_if_fail (!(self->flags & FLAG_CONSTANT), 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;
}
/*!
* \brief Checks whether two spa pod objects have the same value or not
*
* \ingroup wpspapod
* \param self the spa pod object
* \param pod the pod with the value to be compared with
* \returns TRUE if both spa pod objects have the same values, FALSE othewrise.
*/
gboolean
wp_spa_pod_equal (WpSpaPod *self, WpSpaPod *pod)
{
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (pod != NULL, FALSE);
if (self->type != pod->type)
return FALSE;
if (SPA_POD_TYPE (self->pod) != SPA_POD_TYPE (pod->pod))
return FALSE;
switch (SPA_POD_TYPE (self->pod)) {
case SPA_TYPE_None:
break;
case SPA_TYPE_Bool:
if (((struct spa_pod_bool *)self->pod)->value != ((struct spa_pod_bool *)pod->pod)->value)
return FALSE;
break;
case SPA_TYPE_Id:
if (((struct spa_pod_id *)self->pod)->value != ((struct spa_pod_id *)pod->pod)->value)
return FALSE;
break;
case SPA_TYPE_Int:
if (((struct spa_pod_int *)self->pod)->value != ((struct spa_pod_int *)pod->pod)->value)
return FALSE;
break;
case SPA_TYPE_Long:
if (((struct spa_pod_long *)self->pod)->value != ((struct spa_pod_long *)pod->pod)->value)
return FALSE;
break;
case SPA_TYPE_Float:
if (((struct spa_pod_float *)self->pod)->value != ((struct spa_pod_float *)pod->pod)->value)
return FALSE;
break;
case SPA_TYPE_Double:
if (((struct spa_pod_double *)self->pod)->value != ((struct spa_pod_double *)pod->pod)->value)
return FALSE;
break;
case SPA_TYPE_Pointer:
if (((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)
return FALSE;
break;
case SPA_TYPE_Fd:
if (((struct spa_pod_fd *)self->pod)->value != ((struct spa_pod_fd *)pod->pod)->value)
return FALSE;
break;
case SPA_TYPE_Rectangle:
if (((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)
return FALSE;
break;
case SPA_TYPE_Fraction:
if (((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)
return FALSE;
break;
default:
if (self->pod->size != pod->pod->size ||
memcmp (SPA_MEMBER (self->pod, sizeof (struct spa_pod), void),
SPA_MEMBER (pod->pod, sizeof (struct spa_pod), void),
self->pod->size) != 0)
return FALSE;
break;
}
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.key != pod->static_pod.data_property.key ||
self->static_pod.data_property.flags != pod->static_pod.data_property.flags)
return FALSE;
break;
case WP_SPA_POD_CONTROL:
if (self->static_pod.data_control.offset != pod->static_pod.data_control.offset ||
self->static_pod.data_control.type != pod->static_pod.data_control.type)
return FALSE;
break;
case WP_SPA_POD_REGULAR:
default:
break;
}
return TRUE;
}
/*!
* \brief Gets the object properties values of a spa pod object
*
* \ingroup wpspapod
* \param self the spa pod object
* \param id_name (out): the id name of the object,
* \param ... (out): the list of the object properties values, followed by NULL
* \returns TRUE if the object properties values were obtained, FALSE otherwise
*/
gboolean
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, id_name, args);
va_end (args);
return res;
}
/*!
* \brief This is the `va_list` version of wp_spa_pod_get_object()
*
* \ingroup wpspapod
* \param self the spa pod object
* \param id_name (out): the id name of the object
* \param args (out): the variable arguments passed to 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 **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, id_name);
const gboolean res = wp_spa_pod_parser_get_valist (p, args);
wp_spa_pod_parser_end (p);
return res;
}
/*!
* \brief Gets the struct's values of a spa pod object
*
* \ingroup wpspapod
* \param self the spa pod object
* \param ... (out): the list of the struct values, followed by NULL
* \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;
}
/*!
* \brief This is the `va_list` version of wp_spa_pod_get_struct()
*
* \ingroup wpspapod
* \param self the spa pod object
* \param args (out): the variable arguments passed to 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;
}
/*!
* \brief Gets the name, flags and spa pod value of a spa pod property
*
* \ingroup wpspapod
* \param self the spa pod object
* \param key (out) (optional): the name of the property
* \param value (out) (optional): the spa pod value of the property
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_get_property (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) {
WpSpaIdValue key_val = wp_spa_id_table_find_value (
self->static_pod.data_property.table,
self->static_pod.data_property.key);
if (key_val) {
*key = wp_spa_id_value_short_name (key_val);
} else {
g_snprintf (self->static_pod.data_property.id_key_name,
WP_SPA_POD_ID_PROPERTY_NAME_MAX, "id-%08x",
self->static_pod.data_property.key);
*key = self->static_pod.data_property.id_key_name;
}
}
if (value)
*value = wp_spa_pod_new_wrap (self->pod);
return TRUE;
}
/*!
* \brief Gets the offset, type name and spa pod value of a spa pod control
*
* \ingroup wpspapod
* \param self the spa pod object
* \param offset (out) (optional): the offset of the control
* \param ctl_type (out) (optional): the control type (Properties, Midi, ...)
* \param value (out) (optional): the spa pod value of the control
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_get_control (WpSpaPod *self, guint32 *offset, const char **ctl_type,
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 (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);
return TRUE;
}
/*!
* \brief Gets the child of a spa pod choice object
*
* \ingroup wpspapod
* \param self 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_wrap (SPA_POD_CHOICE_CHILD (self->pod));
}
/*!
* \brief Gets the child of a spa pod array object
*
* \ingroup wpspapod
* \param self a spa pod choice 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_wrap (SPA_POD_ARRAY_CHILD (self->pod));
}
/*!
* \brief Fixates choices in an object pod so that they only have one value
*
* \ingroup wpspapod
* \param self a spa pod
* \returns TRUE if the pod was an object and it went through the fixation
* procedure, FALSE otherwise
*/
gboolean
wp_spa_pod_fixate (WpSpaPod *self)
{
g_return_val_if_fail (self, FALSE);
if (wp_spa_pod_is_object (self))
return spa_pod_object_fixate ((struct spa_pod_object *) self->pod) == 0;
return FALSE;
}
/*!
* \brief Returns the intersection between \a self and \a filter
*
* This is typically used to intersect pods that describe formats, in order to
* find a common format that is accceptable by both sides. For that purpose,
* this is not exactly an intersection with its mathematical meaning.
* Object properties can be thought of as format constraints. When one side does
* not specify a specific property, it is considered to accept any value for it,
* so the value of this property from the other side is added in the result.
*
* Both input pods are left unmodified after this function call.
*
* If NULL is passed in the \a filter, this function just copies \a self and
* returns the copy.
*
* \param self the first pod
* \param filter (nullable): the second pod
* \return (transfer full) (nullable): a new pod that contains the intersection
* between \a self and \a filter, or NULL if the intersection was not possible
* to make
*/
WpSpaPod *
wp_spa_pod_filter (WpSpaPod *self, WpSpaPod *filter)
{
char buffer[1024];
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(&buffer, sizeof(buffer));
struct spa_pod *result = NULL;
g_return_val_if_fail (self, NULL);
if (spa_pod_filter(&b, &result, self->pod, filter ? filter->pod : NULL) >= 0)
return wp_spa_pod_new_wrap_copy (result);
return NULL;
}
/*!
* \brief Increases the reference count of a spa pod builder
*
* \ingroup wpspapod
* \param self a spa pod builder object
* \returns (transfer full): \a 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);
}
/*!
* \brief Decreases the reference count on \a self and frees it when the ref
* count reaches zero.
*
* \ingroup wpspapod
* \param self (transfer full): a spa pod builder object
*/
void
wp_spa_pod_builder_unref (WpSpaPodBuilder *self)
{
g_rc_box_release_full (self, (GDestroyNotify) wp_spa_pod_builder_free);
}
/*!
* \brief Creates a spa pod builder of type array
* \ingroup wpspapod
* \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;
}
/*!
* \brief Creates a spa pod builder of type choice
*
* \ingroup wpspapod
* \param choice_type the name of the choice type ("Range", "Step", ...)
* \returns (transfer full): the new spa pod builder
*/
WpSpaPodBuilder *
wp_spa_pod_builder_new_choice (const char *choice_type)
{
WpSpaPodBuilder *self = NULL;
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);
/* Push the array */
spa_pod_builder_push_choice (&self->builder, &self->frame,
wp_spa_id_value_number (type), 0);
return self;
}
/*!
* \brief Creates a spa pod builder of type object
*
* \ingroup wpspapod
* \param type_name the type name of the object type
* \param id_name the Id name of the 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;
WpSpaType type;
WpSpaIdTable table;
WpSpaIdValue id;
/* Find the type */
type = wp_spa_type_from_name (type_name);
g_return_val_if_fail (wp_spa_type_is_object (type), NULL);
/* Find the id */
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,
wp_spa_id_value_number (id));
return self;
}
/*!
* \brief Creates a spa pod builder of type struct
*
* \ingroup wpspapod
* \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;
}
/*!
* \brief Creates a spa pod builder of type sequence
*
* \ingroup wpspapod
* \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;
}
/*!
* \brief Adds a none value into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
*/
void
wp_spa_pod_builder_add_none (WpSpaPodBuilder *self)
{
spa_pod_builder_none (&self->builder);
}
/*!
* \brief Adds a boolean value into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param value the boolean value
*/
void
wp_spa_pod_builder_add_boolean (WpSpaPodBuilder *self, gboolean value)
{
spa_pod_builder_bool (&self->builder, value ? true : false);
}
/*!
* \brief Adds a Id value into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param value the Id value
*/
void
wp_spa_pod_builder_add_id (WpSpaPodBuilder *self, guint32 value)
{
spa_pod_builder_id (&self->builder, value);
}
/*!
* \brief Adds a int value into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param value the int value
*/
void
wp_spa_pod_builder_add_int (WpSpaPodBuilder *self, gint32 value)
{
spa_pod_builder_int (&self->builder, value);
}
/*!
* \brief Adds a long value into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param value the long value
*/
void
wp_spa_pod_builder_add_long (WpSpaPodBuilder *self, gint64 value)
{
spa_pod_builder_long (&self->builder, value);
}
/*!
* \brief Adds a float value into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param value the float value
*/
void
wp_spa_pod_builder_add_float (WpSpaPodBuilder *self, float value)
{
spa_pod_builder_float (&self->builder, value);
}
/*!
* \brief Adds a double value into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param value the double value
*/
void
wp_spa_pod_builder_add_double (WpSpaPodBuilder *self, double value)
{
spa_pod_builder_double (&self->builder, value);
}
/*!
* \brief Adds a string value into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param value the string value
*/
void
wp_spa_pod_builder_add_string (WpSpaPodBuilder *self, const char *value)
{
spa_pod_builder_string (&self->builder, value);
}
/*!
* \brief Adds a bytes value with its length into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param value the bytes value
* \param len the length of the bytes value
*/
void
wp_spa_pod_builder_add_bytes (WpSpaPodBuilder *self, gconstpointer value,
guint32 len)
{
spa_pod_builder_bytes (&self->builder, value, len);
}
/*!
* \brief Adds a pointer value with its type name into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param type_name the type name that the pointer points to
* \param value the pointer vaue
*/
void
wp_spa_pod_builder_add_pointer (WpSpaPodBuilder *self, const char *type_name,
gconstpointer value)
{
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);
}
/*!
* \brief Adds a Fd value into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param value the Fd value
*/
void
wp_spa_pod_builder_add_fd (WpSpaPodBuilder *self, gint64 value)
{
spa_pod_builder_fd (&self->builder, value);
}
/*!
* \brief Adds the width and height values of a rectangle into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param width the width value of the rectangle
* \param height the height value of the rectangle
*/
void
wp_spa_pod_builder_add_rectangle (WpSpaPodBuilder *self, guint32 width,
guint32 height)
{
spa_pod_builder_rectangle (&self->builder, width, height);
}
/*!
* \brief Adds the numerator and denominator values of a fraction into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param num the numerator value of the fraction
* \param denom the denominator value of the fraction
*/
void
wp_spa_pod_builder_add_fraction (WpSpaPodBuilder *self, guint32 num,
guint32 denom)
{
spa_pod_builder_fraction (&self->builder, num, denom);
}
/*!
* \brief Adds a pod value into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param pod the pod value
*/
void
wp_spa_pod_builder_add_pod (WpSpaPodBuilder *self, WpSpaPod *pod)
{
spa_pod_builder_primitive (&self->builder, pod->pod);
}
/*!
* \brief Adds a property into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param key the name of the property
*/
void
wp_spa_pod_builder_add_property (WpSpaPodBuilder *self, const char *key)
{
guint key_id;
if (g_str_has_prefix (key, "id-")) {
g_return_if_fail (sscanf (key, "id-%08x", &key_id) == 1);
} else {
WpSpaIdTable table = wp_spa_type_get_values_table (self->type);
WpSpaIdValue id = wp_spa_id_table_find_value_from_short_name (table, key);
g_return_if_fail (id != NULL);
key_id = wp_spa_id_value_number (id);
}
spa_pod_builder_prop (&self->builder, key_id, 0);
}
/*!
* \brief Adds a property into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param id the id of the property
*/
void
wp_spa_pod_builder_add_property_id (WpSpaPodBuilder *self, guint32 id)
{
spa_pod_builder_prop (&self->builder, id, 0);
}
/*!
* \brief Adds a control into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param offset the offset of the control
* \param ctl_type the type name of the control
*/
void
wp_spa_pod_builder_add_control (WpSpaPodBuilder *self, guint32 offset,
const char *ctl_type)
{
WpSpaIdValue id = wp_spa_id_value_from_short_name (
SPA_TYPE_INFO_Control, ctl_type);
g_return_if_fail (id != NULL);
spa_pod_builder_control (&self->builder, offset, wp_spa_id_value_number (id));
}
/*!
* \brief Adds a list of values into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param ... a list of additional values, followed by NULL
*/
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);
}
/*!
* \brief Adds a list of values into the builder
*
* \ingroup wpspapod
* \param self the spa pod builder object
* \param args the variable arguments passed to wp_spa_pod_builder_add()
*/
void
wp_spa_pod_builder_add_valist (WpSpaPodBuilder *self, va_list args)
{
WpSpaIdTable table = wp_spa_type_get_values_table (self->type);
do {
WpSpaIdValue key = NULL;
const char *format;
int n_values = 1;
struct spa_pod_frame f;
gboolean choice;
if (wp_spa_type_is_object (self->type)) {
guint key_id;
const char *key_name = va_arg(args, const char *);
if (!key_name)
return;
if (g_str_has_prefix (key_name, "id-")) {
g_return_if_fail (sscanf (key_name, "id-%08x", &key_id) == 1);
} else {
key = wp_spa_id_table_find_value_from_short_name (table, key_name);
g_return_if_fail (key != NULL);
key_id = wp_spa_id_value_number (key);
}
spa_pod_builder_prop (&self->builder, key_id, 0);
}
else if (self->type == SPA_TYPE_Sequence) {
guint32 offset = va_arg(args, uint32_t);
if (offset == 0)
return;
const char *control_name = va_arg(args, const char *);
if (!control_name)
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,
wp_spa_id_value_number (type));
}
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 */
WpSpaPod *arg = va_arg(args, WpSpaPod *);
if (arg == NULL)
spa_pod_builder_none (&self->builder);
else
spa_pod_builder_primitive (&self->builder, arg->pod);
break;
}
case 'K': { /* Id as string - WirePlumber extension */
const char * id = va_arg(args, const char *);
if (key) {
WpSpaIdTable id_table = NULL;
wp_spa_id_value_get_value_type (key, &id_table);
WpSpaIdValue id_val =
wp_spa_id_table_find_value_from_short_name (id_table, id);
spa_pod_builder_id (&self->builder, wp_spa_id_value_number (id_val));
}
break;
}
case 'b':
spa_pod_builder_bool(&self->builder,
va_arg(args, gboolean) ? true : false);
break;
default:
SPA_POD_BUILDER_COLLECT(&self->builder, *format, args);
break;
}
}
if (choice)
spa_pod_builder_pop (&self->builder, &f);
} while (TRUE);
}
/*!
* \brief Ends the builder process and returns the constructed spa pod object
*
* \ingroup wpspapod
* \param self the spa pod builder 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 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;
}
/*!
* \brief Increases the reference count of a spa pod parser
* \ingroup wpspapod
* \param self a spa pod sparser object
* \returns (transfer full): \a 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)
{
self->pod = NULL;
}
/*!
* \brief Decreases the reference count on \a self and frees it when the ref
* count reaches zero.
*
* \ingroup wpspapod
* \param self (transfer full): a spa pod parser object
*/
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 = pod;
spa_pod_parser_pod (&self->parser, self->pod->pod);
return self;
}
/*!
* \brief Creates an object spa pod parser. The \a pod object must be valid for
* the entire life-cycle of the returned parser.
*
* \ingroup wpspapod
* \param pod the object spa pod to parse
* \param id_name the Id name of the object
* \returns (transfer full): The new spa pod parser
*/
WpSpaPodParser *
wp_spa_pod_parser_new_object (WpSpaPod *pod, const char **id_name)
{
WpSpaPodParser *self = NULL;
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, type);
spa_pod_parser_push_object (&self->parser, &self->frame, type, &id);
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;
}
/*!
* \brief Creates an struct spa pod parser. The \a pod object must be valid for
* the entire life-cycle of the returned parser.
*
* \ingroup wpspapod
* \param pod the struct spa pod to parse
* \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;
}
/*!
* \brief Gets the boolean value from a spa pod parser
*
* \ingroup wpspapod
* \param self the spa pod parser object
* \param value (out): the boolean value
* \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;
}
/*!
* \brief Gets the Id value from a spa pod parser object
*
* \ingroup wpspapod
* \param self the spa pod parser object
* \param value (out): the Id value
* \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;
}
/*!
* \brief Gets the int value from a spa pod parser object
*
* \ingroup wpspapod
* \param self the spa pod parser object
* \param value (out): the int value
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_parser_get_int (WpSpaPodParser *self, gint32 *value)
{
g_return_val_if_fail (value, FALSE);
return spa_pod_parser_get_int (&self->parser, value) >= 0;
}
/*!
* \brief Gets the long value from a spa pod parser object
*
* \ingroup wpspapod
* \param self the spa pod parser object
* \param value (out): the long value
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_parser_get_long (WpSpaPodParser *self, gint64 *value)
{
g_return_val_if_fail (value, FALSE);
return spa_pod_parser_get_long (&self->parser, value) >= 0;
}
/*!
* \brief Gets the float value from a spa pod parser object
*
* \ingroup wpspapod
* \param self the spa pod parser object
* \param value (out): the float value
* \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;
}
/*!
* \brief Gets the double value from a spa pod parser object
*
* \ingroup wpspapod
* \param self the spa pod parser object
* \param value (out): the double value
* \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;
}
/*!
* \brief Gets the string value from a spa pod parser object
*
* \ingroup wpspapod
* \param self the spa pod parser object
* \param value (out): the string value
* \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;
}
/*!
* \brief Gets the bytes value and its length from a spa pod parser object
*
* \ingroup wpspapod
* \param self the spa pod parser object
* \param value (out): the bytes value
* \param len (out): the length of the bytes value
* \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;
}
/*!
* \brief Gets the pointer value and its type name from a spa pod parser object
*
* \ingroup wpspapod
* \param self the spa pod parser object
* \param value (out): the pointer value
* \returns TRUE if the value was obtained, FALSE otherwise
*/
gboolean
wp_spa_pod_parser_get_pointer (WpSpaPodParser *self, gconstpointer *value)
{
g_return_val_if_fail (value, FALSE);
guint32 type = 0;
return spa_pod_parser_get_pointer (&self->parser, &type, value) >= 0;
}
/*!
* \brief Gets the Fd value from a spa pod parser object
*
* \ingroup wpspapod
* \param self the spa pod parser object
* \param value (out): the Fd value
* \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;
}
/*!
* \brief Gets the rectangle's width and height value from a spa pod parser object
*
* \ingroup wpspapod
* \param self the spa pod parser object
* \param width (out): the rectangle's width value
* \param height (out): the rectangle's height value
* \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;
}
/*!
* \brief Gets the fractions's numerator and denominator value from a spa pod
* parser object
*
* \ingroup wpspapod
* \param self the spa pod parser object
* \param num (out): the fractions's numerator value
* \param denom (out): the fractions's denominator value
* \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;
}
/*!
* \brief Gets the spa pod value from a spa pod parser object
*
* \ingroup wpspapod
* \param self the 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_wrap (p);
}
/*!
* \brief Gets a list of values from a spa pod parser object
*
* \ingroup wpspapod
* \param self the spa pod parser object
* \param ... (out): a list of values to get, followed by NULL
* \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;
}
/*!
* \brief This is the `va_list` version of wp_spa_pod_parser_get()
*
* \ingroup wpspapod
* \param self the spa pod parser object
* \param args the variable arguments passed to 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;
WpSpaIdTable table = wp_spa_type_get_values_table (self->type);
do {
WpSpaIdValue key = NULL;
bool optional;
const struct spa_pod *pod = NULL;
const char *format;
if (wp_spa_type_is_object (self->type)) {
guint key_id;
const struct spa_pod_object *object;
const char *key_name = va_arg(args, const char *);
if (!key_name)
break;
if (g_str_has_prefix (key_name, "id-")) {
g_return_val_if_fail (sscanf (key_name, "id-%08x", &key_id) == 1, FALSE);
} else {
key = wp_spa_id_table_find_value_from_short_name (table, key_name);
g_return_val_if_fail (key != NULL, FALSE);
key_id = wp_spa_id_value_number (key);
}
object = (const struct spa_pod_object *)spa_pod_parser_frame
(&self->parser, &self->frame);
prop = spa_pod_object_find_prop (object, prop, key_id);
pod = prop ? &prop->value : NULL;
}
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 (!pod || !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_wrap_copy (pod);
break;
case 'K': { /* Id as string - WirePlumber extension */
const char ** idstr = va_arg(args, const char **);
uint32_t id = SPA_POD_VALUE(struct spa_pod_id, pod);
if (key) {
WpSpaIdTable id_table = NULL;
wp_spa_id_value_get_value_type (key, &id_table);
WpSpaIdValue id_val = wp_spa_id_table_find_value (id_table, id);
*idstr = wp_spa_id_value_short_name (id_val);
}
break;
}
case 'b':
*va_arg(args, gboolean*) =
SPA_POD_VALUE(struct spa_pod_bool, pod) ? TRUE : FALSE;
break;
default:
SPA_POD_PARSER_COLLECT (pod, *format, args);
break;
}
}
} while (TRUE);
return TRUE;
}
/*!
* \brief Ends the parser process
*
* \ingroup wpspapod
* \param self the spa pod parser object
*/
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)
{
const struct spa_pod_choice *pod_choice =
(const 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)
{
const struct spa_pod_array *pod_arr =
(const 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)
{
const struct spa_pod_object *pod_obj =
(const struct spa_pod_object *) self->pod->pod;
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_wrap (self->curr.pod));
}
return TRUE;
}
static gboolean
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;
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:
{
const struct spa_pod_choice *pod_choice =
(const 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:
{
const struct spa_pod_array *pod_arr =
(const 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:
{
const struct spa_pod_object *pod_obj =
(const 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_wrap (p));
const gboolean res = func (&v, ret, data);
g_value_unset (&v);
if (!res)
return FALSE;
}
break;
}
case SPA_TYPE_Sequence:
{
const struct spa_pod_sequence *pod_seq =
(const 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);
}
/*!
* \brief Creates a new iterator for a spa pod object.
*
* \ingroup wpspapod
* \param pod a spa pod object
* \returns (transfer full): the new spa pod iterator
*/
WpIterator *
wp_spa_pod_new_iterator (WpSpaPod *pod)
{
static const WpIteratorMethods methods = {
.version = WP_ITERATOR_METHODS_VERSION,
.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;
}