
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.
755 lines
22 KiB
C
755 lines
22 KiB
C
/* WirePlumber
|
|
*
|
|
* Copyright © 2020 Collabora Ltd.
|
|
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include "spa-type.h"
|
|
#include "log.h"
|
|
|
|
#include <spa/utils/type-info.h>
|
|
#include <spa/debug/types.h>
|
|
#include <pipewire/pipewire.h>
|
|
|
|
WP_DEFINE_LOCAL_LOG_TOPIC ("wp-spa-type")
|
|
|
|
/*! \defgroup wpspatype WpSpaType
|
|
*
|
|
* Spa has a type system that is represented by a set of arrays that contain
|
|
* `spa_type_info` structures. This type system is simple, yet complex to
|
|
* work with for a couple of reasons.
|
|
*
|
|
* WirePlumber uses this API to access the spa type system, which makes some
|
|
* things easier to understand and work with. The main benefit of using this
|
|
* API is that it makes it easy to work with string representations of the
|
|
* types, allowing easier access from script bindings.
|
|
*
|
|
* \b Type \b hierarchy
|
|
*
|
|
* On the top level, there is a list of types like Int, Bool, String, Id, Object.
|
|
* These are called fundamental types (terms borrowed from GType).
|
|
* Fundamental types can be derived and therefore we can have other types
|
|
* that represent specific objects, for instance.
|
|
*
|
|
* Enum and flag types are all represented with `SPA_TYPE_Id`. These types
|
|
* may have a list of possible values that one can select from (enums)
|
|
* or combine (flags). These values are accessed with the WpSpaIdTable API.
|
|
*
|
|
* Object types can have fields. All objects always have a special "id" field,
|
|
* which is an enum. Its possible values can be given by
|
|
* wp_spa_type_get_object_id_values_table(). Optionally, objects can also have
|
|
* other object-specific fields, which can be accessed with
|
|
* wp_spa_type_get_values_table().
|
|
*
|
|
* Every object field or enum value is represented by a WpSpaIdValue. In the
|
|
* case of object fields, each field can be of a specific type, which is
|
|
* returned by wp_spa_id_value_get_value_type().
|
|
*/
|
|
|
|
static const WpSpaType SPA_TYPE_VENDOR_WirePlumber = 0x03000000;
|
|
static GArray *extra_types = NULL;
|
|
static GArray *extra_id_tables = NULL;
|
|
|
|
typedef struct {
|
|
const char *name;
|
|
const struct spa_type_info *values;
|
|
} WpSpaIdTableInfo;
|
|
|
|
static const WpSpaIdTableInfo static_id_tables[] = {
|
|
{ SPA_TYPE_INFO_Choice, spa_type_choice },
|
|
{ SPA_TYPE_INFO_Direction, spa_type_direction },
|
|
{ SPA_TYPE_INFO_ParamId, spa_type_param },
|
|
{ SPA_TYPE_INFO_MediaType, spa_type_media_type },
|
|
{ SPA_TYPE_INFO_MediaSubtype, spa_type_media_subtype },
|
|
{ SPA_TYPE_INFO_ParamAvailability, spa_type_param_availability },
|
|
{ SPA_TYPE_INFO_ParamPortConfigMode, spa_type_param_port_config_mode },
|
|
{ SPA_TYPE_INFO_VideoFormat, spa_type_video_format },
|
|
{ SPA_TYPE_INFO_AudioFormat, spa_type_audio_format },
|
|
{ SPA_TYPE_INFO_AudioFlags, spa_type_audio_flags },
|
|
{ SPA_TYPE_INFO_AudioChannel, spa_type_audio_channel },
|
|
{ SPA_TYPE_INFO_AudioIEC958Codec, spa_type_audio_iec958_codec },
|
|
{ SPA_TYPE_INFO_IO, spa_type_io },
|
|
{ SPA_TYPE_INFO_Control, spa_type_control },
|
|
{ SPA_TYPE_INFO_Data, spa_type_data_type },
|
|
{ SPA_TYPE_INFO_Meta, spa_type_meta_type },
|
|
{ SPA_TYPE_INFO_DeviceEventId, spa_type_device_event_id },
|
|
{ SPA_TYPE_INFO_NodeEvent, spa_type_node_event_id },
|
|
{ SPA_TYPE_INFO_NodeCommand, spa_type_node_command_id },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
GType wp_spa_type_get_type (void)
|
|
{
|
|
static gsize id__volatile = 0;
|
|
if (g_once_init_enter (&id__volatile)) {
|
|
GType id = g_type_register_static_simple (
|
|
G_TYPE_UINT, g_intern_static_string ("WpSpaType"),
|
|
0, NULL, 0, NULL, 0);
|
|
g_once_init_leave (&id__volatile, id);
|
|
}
|
|
return id__volatile;
|
|
}
|
|
|
|
G_DEFINE_POINTER_TYPE (WpSpaIdTable, wp_spa_id_table)
|
|
|
|
G_DEFINE_POINTER_TYPE (WpSpaIdValue, wp_spa_id_value)
|
|
|
|
|
|
static const struct spa_type_info *
|
|
wp_spa_type_info_find_by_type (WpSpaType type)
|
|
{
|
|
const struct spa_type_info *info;
|
|
|
|
g_return_val_if_fail (type != WP_SPA_TYPE_INVALID, NULL);
|
|
g_return_val_if_fail (type != 0, NULL);
|
|
|
|
if (extra_types)
|
|
info = spa_debug_type_find (
|
|
(const struct spa_type_info *) extra_types->data, type);
|
|
else
|
|
info = spa_debug_type_find (SPA_TYPE_ROOT, type);
|
|
|
|
return info;
|
|
}
|
|
|
|
/* similar to spa_debug_type_find() and unlike spa_debug_type_find_type(),
|
|
which steps into id values / object fields */
|
|
static const struct spa_type_info *
|
|
_spa_type_find_by_name (const struct spa_type_info * info, const char * name)
|
|
{
|
|
const struct spa_type_info * res;
|
|
|
|
while (info->name) {
|
|
if (info->type == SPA_ID_INVALID) {
|
|
if (info->values && (res = _spa_type_find_by_name (info->values, name)))
|
|
return res;
|
|
}
|
|
if (strcmp (info->name, name) == 0)
|
|
return info;
|
|
info++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static const struct spa_type_info *
|
|
wp_spa_type_info_find_by_name (const gchar *name)
|
|
{
|
|
const struct spa_type_info *info = NULL;
|
|
|
|
g_return_val_if_fail (name != NULL, NULL);
|
|
|
|
if (extra_types)
|
|
info = _spa_type_find_by_name (
|
|
(const struct spa_type_info *) extra_types->data, name);
|
|
else
|
|
info = _spa_type_find_by_name (SPA_TYPE_ROOT, name);
|
|
|
|
return info;
|
|
}
|
|
|
|
/*!
|
|
* \brief Looks up the type id from a given type name
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param name the name to look up
|
|
* \returns (transfer none): the corresponding type id or WP_SPA_TYPE_INVALID
|
|
* if not found
|
|
*/
|
|
WpSpaType
|
|
wp_spa_type_from_name (const gchar *name)
|
|
{
|
|
const struct spa_type_info *info = wp_spa_type_info_find_by_name (name);
|
|
return info ? info->type : WP_SPA_TYPE_INVALID;
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets the parent type of an SPA type
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param type a type id
|
|
* \returns (transfer none): the direct parent type of the given \a type; if the
|
|
* type is fundamental (i.e. has no parent), the returned type is the same
|
|
* as \a type
|
|
*/
|
|
WpSpaType
|
|
wp_spa_type_parent (WpSpaType type)
|
|
{
|
|
const struct spa_type_info *info = wp_spa_type_info_find_by_type (type);
|
|
return info ? info->parent : WP_SPA_TYPE_INVALID;
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets the name of an SPA type
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param type a type id
|
|
* \returns the complete name of the given \a type or NULL if \a type is invalid
|
|
*/
|
|
const gchar *
|
|
wp_spa_type_name (WpSpaType type)
|
|
{
|
|
const struct spa_type_info *info = wp_spa_type_info_find_by_type (type);
|
|
return info ? info->name : NULL;
|
|
}
|
|
|
|
/*!
|
|
* \brief Checks if an SPA type is a fundamental type
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param type a type id
|
|
* \returns TRUE if the \a type has no parent, FALSE otherwise
|
|
*/
|
|
gboolean
|
|
wp_spa_type_is_fundamental (WpSpaType type)
|
|
{
|
|
const struct spa_type_info *info = wp_spa_type_info_find_by_type (type);
|
|
return info ? (info->type == info->parent) : FALSE;
|
|
}
|
|
|
|
/*!
|
|
* \brief Checks if an SPA type is an Id type
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param type a type id
|
|
* \returns TRUE if the \a type is a SPA_TYPE_Id, FALSE otherwise
|
|
*/
|
|
gboolean
|
|
wp_spa_type_is_id (WpSpaType type)
|
|
{
|
|
const struct spa_type_info *info = wp_spa_type_info_find_by_type (type);
|
|
return info ? (info->parent == SPA_TYPE_Id) : FALSE;
|
|
}
|
|
|
|
/*!
|
|
* \brief Checks if an SPA type is an Object type
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param type a type id
|
|
* \returns TRUE if the \a type is a SPA_TYPE_Object, FALSE otherwise
|
|
*/
|
|
gboolean
|
|
wp_spa_type_is_object (WpSpaType type)
|
|
{
|
|
const struct spa_type_info *info = wp_spa_type_info_find_by_type (type);
|
|
return info ? (info->parent == SPA_TYPE_Object) : FALSE;
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets the table with the values that can be stored in the special "id"
|
|
* field of an object of the given \a type
|
|
*
|
|
* Object pods (see WpSpaPod) always have a special "id" field along with
|
|
* other fields that can be defined. This "id" field can only store values
|
|
* of a specific `SPA_TYPE_Id` type. This function returns the table that
|
|
* contains the possible values for that field.
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param type the type id of an object type
|
|
* \returns the table with the values that can be stored in the special "id"
|
|
* field of an object of the given \a type
|
|
*/
|
|
WpSpaIdTable
|
|
wp_spa_type_get_object_id_values_table (WpSpaType type)
|
|
{
|
|
const struct spa_type_info *info = wp_spa_type_info_find_by_type (type);
|
|
|
|
g_return_val_if_fail (info != NULL, NULL);
|
|
g_return_val_if_fail (info->parent == SPA_TYPE_Object, NULL);
|
|
g_return_val_if_fail (info->values != NULL, NULL);
|
|
g_return_val_if_fail (info->values->name != NULL, NULL);
|
|
g_return_val_if_fail (info->values->parent == SPA_TYPE_Id, NULL);
|
|
|
|
return info->values->values;
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets the values table of an SPA type
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param type a type id
|
|
* \returns the associated WpSpaIdTable that contains possible
|
|
* values or object fields for this type, or NULL
|
|
*/
|
|
WpSpaIdTable
|
|
wp_spa_type_get_values_table (WpSpaType type)
|
|
{
|
|
const struct spa_type_info *info = wp_spa_type_info_find_by_type (type);
|
|
|
|
g_return_val_if_fail (info != NULL, NULL);
|
|
return info->values;
|
|
}
|
|
|
|
struct spa_type_info_iterator_data
|
|
{
|
|
const struct spa_type_info *base;
|
|
const struct spa_type_info *cur;
|
|
};
|
|
|
|
static void
|
|
spa_type_info_iterator_reset (WpIterator *it)
|
|
{
|
|
struct spa_type_info_iterator_data *it_data = wp_iterator_get_user_data (it);
|
|
it_data->cur = it_data->base;
|
|
}
|
|
|
|
static gboolean
|
|
spa_type_info_iterator_next (WpIterator *it, GValue *item)
|
|
{
|
|
struct spa_type_info_iterator_data *it_data = wp_iterator_get_user_data (it);
|
|
|
|
if (it_data->cur->name) {
|
|
g_value_init (item, WP_TYPE_SPA_ID_VALUE);
|
|
g_value_set_pointer (item, (gpointer) it_data->cur);
|
|
it_data->cur++;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
spa_type_info_iterator_fold (WpIterator *it, WpIteratorFoldFunc func,
|
|
GValue *ret, gpointer data)
|
|
{
|
|
struct spa_type_info_iterator_data *it_data = wp_iterator_get_user_data (it);
|
|
const struct spa_type_info *cur, *base;
|
|
|
|
cur = base = it_data->base;
|
|
|
|
while (cur->name) {
|
|
g_auto (GValue) item = G_VALUE_INIT;
|
|
g_value_init (&item, WP_TYPE_SPA_ID_VALUE);
|
|
g_value_set_pointer (&item, (gpointer) cur);
|
|
if (!func (&item, ret, data))
|
|
return FALSE;
|
|
cur++;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static const WpIteratorMethods spa_type_info_iterator_methods = {
|
|
.version = WP_ITERATOR_METHODS_VERSION,
|
|
.reset = spa_type_info_iterator_reset,
|
|
.next = spa_type_info_iterator_next,
|
|
.fold = spa_type_info_iterator_fold,
|
|
};
|
|
|
|
/*!
|
|
* \brief Finds a WpSpaIdTable given its name.
|
|
*
|
|
* This name can either be the full type name of an object type,
|
|
* or the name of an enum (which is \b not(!!) a type).
|
|
* For example, "Spa:Pod:Object:Param:Format" and "Spa:Enum:ParamId" are
|
|
* both valid table names.
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param name the full name of an id table
|
|
* \returns (nullable): the associated table, or NULL
|
|
*/
|
|
WpSpaIdTable
|
|
wp_spa_id_table_from_name (const gchar *name)
|
|
{
|
|
g_return_val_if_fail (name != NULL, NULL);
|
|
const WpSpaIdTableInfo *info = NULL;
|
|
|
|
/* first look in dynamic id tables */
|
|
if (extra_id_tables) {
|
|
info = (const WpSpaIdTableInfo *) extra_id_tables->data;
|
|
while (info && info->name) {
|
|
if (strcmp (info->name, name) == 0)
|
|
return info->values;
|
|
info++;
|
|
}
|
|
}
|
|
|
|
/* then look at the well-known static ones */
|
|
info = static_id_tables;
|
|
while (info && info->name) {
|
|
if (strcmp (info->name, name) == 0)
|
|
return info->values;
|
|
info++;
|
|
}
|
|
|
|
/* then look into types, hoping to find an object type */
|
|
const struct spa_type_info *tinfo = wp_spa_type_info_find_by_name (name);
|
|
return tinfo ? tinfo->values : NULL;
|
|
}
|
|
|
|
/*!
|
|
* \brief This function returns an iterator that allows you to iterate
|
|
* through the values associated with this table.
|
|
*
|
|
* The items in the iterator are of type WpSpaIdValue.
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param table the id table
|
|
* \returns a WpIterator that iterates over WpSpaIdValue items
|
|
*/
|
|
WpIterator *
|
|
wp_spa_id_table_new_iterator (WpSpaIdTable table)
|
|
{
|
|
g_return_val_if_fail (table != NULL, NULL);
|
|
|
|
WpIterator *it = wp_iterator_new (&spa_type_info_iterator_methods,
|
|
sizeof (struct spa_type_info_iterator_data));
|
|
struct spa_type_info_iterator_data *it_data = wp_iterator_get_user_data (it);
|
|
it_data->base = (const struct spa_type_info *) table;
|
|
it_data->cur = it_data->base;
|
|
return it;
|
|
}
|
|
|
|
/*!
|
|
* \brief Finds a value in an SPA Id table
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param table the id table
|
|
* \param value a numeric value that is contained in the table
|
|
* \returns (nullable): the WpSpaIdValue associated with \a value, or NULL
|
|
*/
|
|
WpSpaIdValue
|
|
wp_spa_id_table_find_value (WpSpaIdTable table, guint value)
|
|
{
|
|
g_return_val_if_fail (table != NULL, NULL);
|
|
|
|
const struct spa_type_info *info = table;
|
|
while (info && info->name) {
|
|
if (info->type == value)
|
|
return info;
|
|
info++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*!
|
|
* \brief Finds a named value in an SPA Id table
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param table the id table
|
|
* \param name the full name of a value that is contained in the table
|
|
* \returns (nullable): the WpSpaIdValue associated with \a name, or NULL
|
|
*/
|
|
WpSpaIdValue
|
|
wp_spa_id_table_find_value_from_name (WpSpaIdTable table, const gchar * name)
|
|
{
|
|
g_return_val_if_fail (table != NULL, NULL);
|
|
|
|
const struct spa_type_info *info = table;
|
|
while (info && info->name) {
|
|
if (!strcmp (info->name, name))
|
|
return info;
|
|
info++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*!
|
|
* \brief Finds a short named value in an SPA Id table
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param table the id table
|
|
* \param short_name the short name of a value that is contained in the table
|
|
* \returns (nullable): the WpSpaIdValue associated with \a short_name, or NULL
|
|
*/
|
|
WpSpaIdValue
|
|
wp_spa_id_table_find_value_from_short_name (WpSpaIdTable table,
|
|
const gchar * short_name)
|
|
{
|
|
g_return_val_if_fail (table != NULL, NULL);
|
|
|
|
const struct spa_type_info *info = table;
|
|
while (info && info->name) {
|
|
if (!strcmp (spa_debug_type_short_name (info->name), short_name))
|
|
return info;
|
|
info++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static WpSpaIdTable
|
|
wp_spa_id_name_find_id_table (const gchar * name)
|
|
{
|
|
WpSpaIdTable table = NULL;
|
|
g_autofree gchar *parent_name = g_strdup (name);
|
|
gchar *h;
|
|
|
|
if ((h = strrchr(parent_name, ':')) != NULL) {
|
|
/* chop the enum name to get the type, ex:
|
|
Spa:Enum:Direction:Input -> Spa:Enum:Direction */
|
|
*h = '\0';
|
|
table = wp_spa_id_table_from_name (parent_name);
|
|
|
|
/* in some cases, the parent name is one layer further up, ex:
|
|
Spa:Pod:Object:Param:Format:Audio:rate -> Spa:Pod:Object:Param:Format */
|
|
if (!table && (h = strrchr(parent_name, ':')) != NULL) {
|
|
*h = '\0';
|
|
table = wp_spa_id_table_from_name (parent_name);
|
|
}
|
|
}
|
|
return table;
|
|
}
|
|
|
|
/*!
|
|
* \brief Looks up an id value (enum, flag or object field) directly from its
|
|
* full name.
|
|
*
|
|
* For instance, "Spa:Enum:Direction:Input" will resolve to the
|
|
* id value that represents "Input" in the "Spa:Enum:Direction" enum.
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param name the full name of an id value
|
|
* \returns the id value for \a name, or NULL if no such id value was found
|
|
*/
|
|
WpSpaIdValue
|
|
wp_spa_id_value_from_name (const gchar * name)
|
|
{
|
|
g_return_val_if_fail (name != NULL, NULL);
|
|
|
|
WpSpaIdTable table = wp_spa_id_name_find_id_table (name);
|
|
return wp_spa_id_table_find_value_from_name (table, name);
|
|
}
|
|
|
|
/*!
|
|
* \brief Looks up an id value given its container \a table_name and its
|
|
* \a short_name
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param table_name the name of the WpSpaIdTable to look up the value in
|
|
* \param short_name the short name of the value to look up
|
|
* \returns the id value or NULL if it was not found
|
|
*/
|
|
WpSpaIdValue
|
|
wp_spa_id_value_from_short_name (const gchar * table_name,
|
|
const gchar * short_name)
|
|
{
|
|
g_return_val_if_fail (table_name != NULL, NULL);
|
|
g_return_val_if_fail (short_name != NULL, NULL);
|
|
|
|
WpSpaIdTable table = wp_spa_id_table_from_name (table_name);
|
|
return wp_spa_id_table_find_value_from_short_name (table, short_name);
|
|
}
|
|
|
|
/*!
|
|
* \brief Looks up an id value given its container \a table_name and its numeric
|
|
* representation, \a id
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param table_name the name of the WpSpaIdTable to look up the value in
|
|
* \param id the numeric representation of the value to look up
|
|
* \returns the id value or NULL if it was not found
|
|
*/
|
|
WpSpaIdValue
|
|
wp_spa_id_value_from_number (const gchar * table_name, guint id)
|
|
{
|
|
g_return_val_if_fail (table_name != NULL, NULL);
|
|
|
|
WpSpaIdTable table = wp_spa_id_table_from_name (table_name);
|
|
return wp_spa_id_table_find_value (table, id);
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets the numeric value of an id value
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param id an id value
|
|
* \returns the numeric representation of this id value
|
|
*/
|
|
guint
|
|
wp_spa_id_value_number (WpSpaIdValue id)
|
|
{
|
|
g_return_val_if_fail (id != NULL, -1);
|
|
|
|
const struct spa_type_info *info = id;
|
|
return info->type;
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets the name of an id value
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param id an id value
|
|
* \returns the full name of this id value
|
|
*/
|
|
const gchar *
|
|
wp_spa_id_value_name (WpSpaIdValue id)
|
|
{
|
|
g_return_val_if_fail (id != NULL, NULL);
|
|
|
|
const struct spa_type_info *info = id;
|
|
return info->name;
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets the short name of an id value
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param id an id value
|
|
* \returns the short name of this id value
|
|
*/
|
|
const gchar *
|
|
wp_spa_id_value_short_name (WpSpaIdValue id)
|
|
{
|
|
g_return_val_if_fail (id != NULL, NULL);
|
|
|
|
const struct spa_type_info *info = id;
|
|
return spa_debug_type_short_name (info->name);
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns the value type associated with this WpSpaIdValue.
|
|
*
|
|
* This information is useful when \a id represents an object field,
|
|
* which can take a value of an arbitrary type.
|
|
*
|
|
* When the returned type is (or is derived from) `SPA_TYPE_Id` or
|
|
* `SPA_TYPE_Object`, \a table is set to point to the WpSpaIdTable
|
|
* that contains the possible Id values / object fields.
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param id an id value
|
|
* \param table (out) (optional): the associated WpSpaIdTable
|
|
* \returns (transfer none): the value type associated with \a id
|
|
*/
|
|
WpSpaType
|
|
wp_spa_id_value_get_value_type (WpSpaIdValue id, WpSpaIdTable * table)
|
|
{
|
|
g_return_val_if_fail (id != NULL, WP_SPA_TYPE_INVALID);
|
|
|
|
const struct spa_type_info *info = id;
|
|
|
|
if (table) {
|
|
/* info->values has different semantics on Array types */
|
|
if (info->values && info->parent != SPA_TYPE_Array) {
|
|
*table = info->values;
|
|
}
|
|
/* derived object types normally don't have info->values directly set,
|
|
so we need to look them up */
|
|
else if (wp_spa_type_is_object (info->parent)) {
|
|
WpSpaIdTable t = wp_spa_type_get_values_table (info->parent);
|
|
if (t) *table = t;
|
|
}
|
|
}
|
|
|
|
return info->parent;
|
|
}
|
|
|
|
/*!
|
|
* \brief If the value type of \a id is `SPA_TYPE_Array`, this function
|
|
* returns the type that is allowed to be contained inside the array.
|
|
*
|
|
* When the returned type is (or is derived from) `SPA_TYPE_Id` or
|
|
* `SPA_TYPE_Object`, \a table is set to point to the WpSpaIdTable
|
|
* that contains the possible Id values / object fields.
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param id an id value
|
|
* \param table (out) (optional): the associated WpSpaIdTable
|
|
* \returns (transfer none): the type that is allowed in the array, if \a id
|
|
* represents an object field that takes an array as value
|
|
*/
|
|
WpSpaType
|
|
wp_spa_id_value_array_get_item_type (WpSpaIdValue id, WpSpaIdTable * table)
|
|
{
|
|
g_return_val_if_fail (id != NULL, WP_SPA_TYPE_INVALID);
|
|
|
|
const struct spa_type_info *info = id;
|
|
g_return_val_if_fail (info->parent == SPA_TYPE_Array, WP_SPA_TYPE_INVALID);
|
|
|
|
return info->values ?
|
|
wp_spa_id_value_get_value_type (info->values, table) :
|
|
WP_SPA_TYPE_INVALID;
|
|
}
|
|
|
|
/*!
|
|
* \brief Initializes the spa dynamic type registry.
|
|
*
|
|
* This allows registering new spa types at runtime. The spa type system
|
|
* still works if this function is not called.
|
|
*
|
|
* Normally called by wp_init() when WP_INIT_SPA_TYPES is passed in its flags.
|
|
*
|
|
* \ingroup wpspatype
|
|
*/
|
|
void
|
|
wp_spa_dynamic_type_init (void)
|
|
{
|
|
extra_types = g_array_new (TRUE, FALSE, sizeof (struct spa_type_info));
|
|
extra_id_tables = g_array_new (TRUE, FALSE, sizeof (WpSpaIdTableInfo));
|
|
|
|
/* init to chain up to spa types */
|
|
struct spa_type_info info = {
|
|
SPA_ID_INVALID, SPA_ID_INVALID, "spa_types", SPA_TYPE_ROOT
|
|
};
|
|
g_array_append_val (extra_types, info);
|
|
}
|
|
|
|
/*!
|
|
* \brief Deinitializes the spa type registry.
|
|
*
|
|
* You do not need to ever call this, unless you want to free memory at the
|
|
* end of the execution of a test, so that it doesn't show as leaked in
|
|
* the memory profiler.
|
|
*
|
|
* \ingroup wpspatype
|
|
*/
|
|
void
|
|
wp_spa_dynamic_type_deinit (void)
|
|
{
|
|
g_clear_pointer (&extra_types, g_array_unref);
|
|
g_clear_pointer (&extra_id_tables, g_array_unref);
|
|
}
|
|
|
|
/*!
|
|
* \brief Registers an additional type in the spa type system.
|
|
*
|
|
* This is useful to add a custom pod object type.
|
|
*
|
|
* Note that both \a name and \a values must be statically allocated, or
|
|
* otherwise guaranteed to be kept in memory until wp_spa_dynamic_type_deinit()
|
|
* is called. No memory copy is done by this function.
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param name the name of the type
|
|
* \param parent the parent type
|
|
* \param values an array of `spa_type_info` that contains the values of the type,
|
|
* used only for Object types
|
|
* \returns (transfer none): the new type
|
|
*/
|
|
WpSpaType
|
|
wp_spa_dynamic_type_register (const gchar *name, WpSpaType parent,
|
|
const struct spa_type_info * values)
|
|
{
|
|
struct spa_type_info info;
|
|
info.type = SPA_TYPE_VENDOR_WirePlumber + extra_types->len;
|
|
info.name = name;
|
|
info.parent = parent;
|
|
info.values = values;
|
|
g_array_append_val (extra_types, info);
|
|
return info.type;
|
|
}
|
|
|
|
/*!
|
|
* \brief Registers an additional WpSpaIdTable in the spa type system.
|
|
*
|
|
* This is useful to add custom enumeration types.
|
|
*
|
|
* Note that both \a name and \a values must be statically allocated, or
|
|
* otherwise guaranteed to be kept in memory until wp_spa_dynamic_type_deinit()
|
|
* is called. No memory copy is done by this function.
|
|
*
|
|
* \ingroup wpspatype
|
|
* \param name the name of the id table
|
|
* \param values an array of `spa_type_info` that contains the values of the table
|
|
* \returns the new table
|
|
*/
|
|
WpSpaIdTable
|
|
wp_spa_dynamic_id_table_register (const gchar *name,
|
|
const struct spa_type_info * values)
|
|
{
|
|
WpSpaIdTableInfo info;
|
|
info.name = name;
|
|
info.values = values;
|
|
g_array_append_val (extra_id_tables, info);
|
|
return values;
|
|
}
|