Skip to content
Snippets Groups Projects
Commit b79fcf94 authored by Julian Bouzas's avatar Julian Bouzas
Browse files

lib: add spa type API

parent 5846fb91
No related branches found
No related tags found
No related merge requests found
......@@ -17,6 +17,7 @@ wp_lib_sources = files(
'properties.c',
'proxy.c',
'session.c',
'spa-type.c',
'spa-props.c',
)
......@@ -40,6 +41,7 @@ wp_lib_headers = files(
'properties.h',
'proxy.h',
'session.h',
'spa-type.h',
'wp.h',
)
......
......@@ -12,6 +12,7 @@
#include "core.h"
#include "object-manager.h"
#include "proxy.h"
#include "iterator.h"
#include <stdint.h>
#include <pipewire/pipewire.h>
......@@ -116,12 +117,6 @@ void wp_proxy_handle_event_param (void * proxy, int seq, uint32_t id,
/* iterator */
typedef struct _WpIterator WpIterator;
typedef gboolean (*WpIteratorFoldFunc) (const GValue *item, GValue *ret,
gpointer data);
typedef void (*WpIteratorForeachFunc) (const GValue *item, gpointer data);
struct _WpIteratorMethods {
void (*reset) (WpIterator *self);
gboolean (*next) (WpIterator *self, GValue *item);
......
/* WirePlumber
*
* Copyright © 2020 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <spa/utils/type-info.h>
#include "spa-type.h"
static gboolean
name_equal_func (gconstpointer a, gconstpointer b) {
const struct spa_type_info *ti = a;
const char *name = b;
return g_strcmp0 (ti->name, name) == 0;
}
static const struct spa_type_info *
spa_type_find (const struct spa_type_info *table, GEqualFunc func,
gconstpointer data)
{
for (guint32 i = 0; table[i].name; i++)
if (func (table + i, data))
return table + i;
return NULL;
}
static const struct spa_type_info *
spa_type_find_by_name (const struct spa_type_info *table, const char *name)
{
return spa_type_find (table, name_equal_func, name);
}
struct type_info {
gboolean is_spa_type;
union {
const struct spa_type_info *spa;
struct {
guint32 type;
char *name;
} custom;
} info;
char *nick;
};
static struct type_info *
type_info_new_spa (const struct spa_type_info *info, const char* nick) {
struct type_info *ti = g_slice_new0 (struct type_info);
ti->is_spa_type = TRUE;
ti->info.spa = info;
ti->nick = g_strdup (nick);
return ti;
}
static struct type_info *
type_info_new_custom (uint32_t type, const char *name, const char* nick) {
struct type_info *ti = g_slice_new0 (struct type_info);
ti->is_spa_type = FALSE;
ti->info.custom.type = type;
ti->info.custom.name = g_strdup (name);
ti->nick = g_strdup (nick);
return ti;
}
static void
type_info_free (struct type_info *ti) {
g_return_if_fail (ti);
if (!ti->is_spa_type)
g_clear_pointer (&ti->info.custom.name, g_free);
g_clear_pointer (&ti->nick, g_free);
g_slice_free (struct type_info, ti);
}
struct spa_type_table_data {
const struct spa_type_info *spa_table;
guint32 last_id;
GPtrArray *info_array;
GHashTable *id_table;
GHashTable *nick_table;
};
static struct spa_type_table_data s_tables [WP_SPA_TYPE_TABLE_LAST] = {
[WP_SPA_TYPE_TABLE_BASIC] = {spa_types, SPA_TYPE_VENDOR_Other, NULL, NULL, NULL },
[WP_SPA_TYPE_TABLE_PARAM] = {spa_type_param, SPA_N_ELEMENTS (spa_type_param), NULL, NULL, NULL, },
[WP_SPA_TYPE_TABLE_PROPS] = {spa_type_props, SPA_PROP_START_CUSTOM, NULL, NULL, NULL, },
[WP_SPA_TYPE_TABLE_PROP_INFO] = {spa_type_prop_info, SPA_N_ELEMENTS (spa_type_prop_info), NULL, NULL, NULL, },
[WP_SPA_TYPE_TABLE_CONTROL] = {spa_type_control, SPA_CONTROL_LAST, NULL, NULL, NULL, },
[WP_SPA_TYPE_TABLE_CHOICE] = {spa_type_choice, SPA_N_ELEMENTS (spa_type_choice), NULL, NULL, NULL, },
};
static WpSpaTypeTable
wp_spa_type_table_find_by_spa_table (const struct spa_type_info *spa_table)
{
for (guint32 i = 0; i < WP_SPA_TYPE_TABLE_LAST; i++)
if (s_tables[i].spa_table == spa_table)
return i;
return 0;
}
/**
* wp_spa_type_init:
* @register_spa: whether spa types will be registered or not
*
* Initializes the spa type registry
*/
void
wp_spa_type_init (gboolean register_spa)
{
/* Init the array and hash tables */
for (guint32 i = 0; i < WP_SPA_TYPE_TABLE_LAST; i++) {
struct spa_type_table_data *td = s_tables + i;
if (!td->info_array)
td->info_array = g_ptr_array_new_with_free_func ((GDestroyNotify)
type_info_free);
if (!td->id_table)
td->id_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, NULL);
if (!td->nick_table)
td->nick_table = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
}
/* Register the spa types if requested */
if (register_spa) {
for (guint32 i = 0; i < WP_SPA_TYPE_TABLE_LAST; i++) {
struct spa_type_table_data *td = s_tables + i;
for (guint32 j = 0; td->spa_table && td->spa_table[j].name; j++) {
const struct spa_type_info *t = td->spa_table + j;
const char *nick = strrchr (t->name, ':');
if (nick && strlen (nick) > 1)
wp_spa_type_register (i, t->name, nick + 1);
}
}
}
}
/**
* wp_spa_type_deinit:
*
* Deinitializes the spa type registry
*/
void
wp_spa_type_deinit (void)
{
for (guint32 i = 0; i < WP_SPA_TYPE_TABLE_LAST; i++) {
struct spa_type_table_data *td = s_tables + i;
g_clear_pointer (&td->info_array, g_ptr_array_unref);
g_clear_pointer (&td->id_table, g_hash_table_unref);
g_clear_pointer (&td->nick_table, g_hash_table_unref);
}
}
/**
* wp_spa_type_get_table_size:
* @table: the table
*
* Gets the number of registered types in a given table
*
* Returns: The number of registered types
*/
size_t
wp_spa_type_get_table_size (WpSpaTypeTable table)
{
struct spa_type_table_data *td = NULL;
g_return_val_if_fail (table < WP_SPA_TYPE_TABLE_LAST, 0);
/* Get the table data */
td = s_tables + table;
return td->info_array->len;
}
/**
* wp_spa_type_register:
* @table: the table
* @name: the name of the type
* @nick: the nick name of the type
*
* Registers a type name with a nickname in the registry
*
* Returns: TRUE if the type could be registered, FALSE otherwise
*/
gboolean
wp_spa_type_register (WpSpaTypeTable table, const char *name, const char *nick)
{
struct spa_type_table_data *td = NULL;
const struct spa_type_info *spa_info = NULL;
struct type_info *info = NULL;
guint32 id;
g_return_val_if_fail (table < WP_SPA_TYPE_TABLE_LAST, FALSE);
g_return_val_if_fail (name, FALSE);
g_return_val_if_fail (nick, FALSE);
/* Get the table data */
td = s_tables + table;
/* Return false if the nick already exists in the nick table */
if (g_hash_table_contains (td->nick_table, nick))
return FALSE;
/* Add the type in the custom table */
spa_info = spa_type_find_by_name (td->spa_table, name);
if (spa_info) {
id = spa_info->type;
info = type_info_new_spa (spa_info, nick);
} else {
id = ++td->last_id;
info = type_info_new_custom (id, name, nick);
}
g_ptr_array_add (td->info_array, info);
/* Insert the id and nick in the hash tables */
return g_hash_table_insert (td->id_table, GUINT_TO_POINTER (id), info) &&
g_hash_table_insert (td->nick_table, g_strdup (nick), info);
}
/**
* wp_spa_type_unregister:
* @table: the table
* @nick: the nick name of the type
*
* Unregisters a type given its nick name
*/
void
wp_spa_type_unregister (WpSpaTypeTable table, const char *nick)
{
struct spa_type_table_data *td = NULL;
struct type_info *info = NULL;
guint32 id;
g_return_if_fail (table < WP_SPA_TYPE_TABLE_LAST);
g_return_if_fail (nick);
/* Get the table data */
td = s_tables + table;
/* Lookup the info by nick */
info = g_hash_table_lookup (td->nick_table, nick);
if (!info)
return;
/* Get id */
id = info->is_spa_type ? info->info.spa->type : info->info.custom.type;
/* Remove info from hash tables */
g_hash_table_remove (td->nick_table, nick);
g_hash_table_remove (td->id_table, GUINT_TO_POINTER (id));
/* Remove info from array */
g_ptr_array_remove_fast (td->info_array, info);
}
/**
* wp_spa_type_get_by_nick:
* @table: the table
* @nick: the nick name of the type
* @id: (out) (optional): the id of the type
* @name: (out) (optional): the name of the type
* @values_table: (out) (optional): the values table of the type
*
* Gets the id and name of the registered type given its nick name
*
* Returns: TRUE if the type was found, FALSE otherwise
*/
gboolean
wp_spa_type_get_by_nick (WpSpaTypeTable table, const char *nick,
guint32 *id, const char **name, WpSpaTypeTable *values_table)
{
struct spa_type_table_data *td = NULL;
const struct type_info *info = NULL;
g_return_val_if_fail (table < WP_SPA_TYPE_TABLE_LAST, FALSE);
/* Make sure nick is valid */
if (!nick)
return FALSE;
/* Get the table data */
td = s_tables + table;
/* Lookup the info by nick */
info = g_hash_table_lookup (td->nick_table, nick);
if (!info)
return FALSE;
if (id)
*id = info->is_spa_type ? info->info.spa->type : info->info.custom.type;
if (name)
*name = info->is_spa_type ? info->info.spa->name : info->info.custom.name;
if (values_table && info->is_spa_type)
*values_table = wp_spa_type_table_find_by_spa_table (info->info.spa->values);
return TRUE;
}
/**
* wp_spa_type_get_by_id:
* @table: the table
* @id: the id of the type
* @name: (out) (optional): the name of the type
* @nick: (out) (optional): the nick name of the type
* @values_table: (out) (optional): the values table of the type
*
* Gets the name and nick name of the registered type given its id
*
* Returns: TRUE if the type was found, FALSE otherwise
*/
gboolean
wp_spa_type_get_by_id (WpSpaTypeTable table, guint32 id,
const char **name, const char **nick, WpSpaTypeTable *values_table)
{
struct spa_type_table_data *td = NULL;
const struct type_info *info = NULL;
g_return_val_if_fail (table < WP_SPA_TYPE_TABLE_LAST, FALSE);
/* Get the table data */
td = s_tables + table;
/* Lookup the info by id */
info = g_hash_table_lookup (td->id_table, GUINT_TO_POINTER (id));
if (!info)
return FALSE;
if (name)
*name = info->is_spa_type ? info->info.spa->name : info->info.custom.name;
if (nick)
*nick = info->nick;
if (values_table && info->is_spa_type)
*values_table = wp_spa_type_table_find_by_spa_table (info->info.spa->values);
return TRUE;
}
/* WirePlumber
*
* Copyright © 2020 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#ifndef __WIREPLUMBER_SPA_TYPE_H__
#define __WIREPLUMBER_SPA_TYPE_H__
#include <gio/gio.h>
#include "defs.h"
G_BEGIN_DECLS
/**
* WpSpaTypeTable:
*
* The diferent tables (namespaces) the registry has.
* WP_SPA_TYPE_TABLE_BASIC (0) - The basic type table
* WP_SPA_TYPE_TABLE_PARAM (1) – The param type table (used as object id)
* WP_SPA_TYPE_TABLE_PROPS (2) – The object properties type table
* WP_SPA_TYPE_TABLE_PROP_INFO (3) – The object property info type table
* WP_SPA_TYPE_TABLE_CONTROL (4) - The sequence control type table
* WP_SPA_TYPE_TABLE_CHOICE (5) - The choice type table
*/
typedef enum {
WP_SPA_TYPE_TABLE_BASIC = 0,
WP_SPA_TYPE_TABLE_PARAM,
WP_SPA_TYPE_TABLE_PROPS,
WP_SPA_TYPE_TABLE_PROP_INFO,
WP_SPA_TYPE_TABLE_CONTROL,
WP_SPA_TYPE_TABLE_CHOICE,
WP_SPA_TYPE_TABLE_LAST,
} WpSpaTypeTable;
WP_API
void wp_spa_type_init (gboolean register_spa);
WP_API
void wp_spa_type_deinit (void);
WP_API
size_t wp_spa_type_get_table_size (WpSpaTypeTable table);
WP_API
gboolean wp_spa_type_register (WpSpaTypeTable table, const char *name,
const char *nick);
WP_API
void wp_spa_type_unregister (WpSpaTypeTable table, const char *nick);
WP_API
gboolean wp_spa_type_get_by_nick (WpSpaTypeTable table, const char *nick,
guint32 *id, const char **name, WpSpaTypeTable *values_table);
WP_API
gboolean wp_spa_type_get_by_id (WpSpaTypeTable table, guint32 id,
const char **name, const char **nick, WpSpaTypeTable *values_table);
G_END_DECLS
#endif
......@@ -24,4 +24,5 @@
#include "properties.h"
#include "proxy.h"
#include "session.h"
#include "spa-type.h"
#include "wpenums.h"
......@@ -33,3 +33,9 @@ test(
executable('test-spa-props', 'spa-props.c', dependencies: common_deps),
env: common_env,
)
test(
'test-spa-type',
executable('test-spa-type', 'spa-type.c', dependencies: common_deps),
env: common_env,
)
/* WirePlumber
*
* Copyright © 2020 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <wp/wp.h>
#include <spa/utils/type-info.h>
static void
test_spa_type_basic (void)
{
wp_spa_type_init (TRUE);
/* Make sure table sizes are not 0 */
g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), >, 0);
g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_PARAM), >, 0);
g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_PROPS), >, 0);
g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_PROP_INFO), >, 0);
g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_CONTROL), >, 0);
g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_CHOICE), >, 0);
/* Make sure SPA_TYPE_OBJECT_Props type from WP_SPA_TYPE_TABLE_BASIC is registered */
{
const char *name = NULL;
const char *nick = NULL;
WpSpaTypeTable table = WP_SPA_TYPE_TABLE_BASIC;
g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_BASIC, SPA_TYPE_OBJECT_Props,
&name, &nick, &table));
g_assert_cmpstr (name, ==, "Spa:Pod:Object:Param:Props");
g_assert_cmpstr (nick, ==, "Props");
g_assert_cmpuint (table, ==, WP_SPA_TYPE_TABLE_PROPS);
}
/* Make sure SPA_PARAM_Props type from WP_SPA_TYPE_TABLE_PARAM is registered */
{
const char *name = NULL;
const char *nick = NULL;
g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_PARAM, SPA_PARAM_Props, &name, &nick, NULL));
g_assert_cmpstr (name, ==, "Spa:Enum:ParamId:Props");
g_assert_cmpstr (nick, ==, "Props");
}
/* Make sure SPA_PROP_mute type from WP_SPA_TYPE_TABLE_PROPS is registered */
{
const char *name = NULL;
const char *nick = NULL;
g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_PROPS, SPA_PROP_mute, &name, &nick, NULL));
g_assert_cmpstr (name, ==, "Spa:Pod:Object:Param:Props:mute");
g_assert_cmpstr (nick, ==, "mute");
}
/* Make sure SPA_PROP_INFO_id type from WP_SPA_TYPE_TABLE_PROP_INFO is registered */
{
const char *name = NULL;
const char *nick = NULL;
g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_PROP_INFO, SPA_PROP_INFO_id, &name, &nick, NULL));
g_assert_cmpstr (name, ==, "Spa:Pod:Object:Param:PropInfo:id");
g_assert_cmpstr (nick, ==, "id");
}
/* Make sure SPA_CONTROL_Properties type from WP_SPA_TYPE_TABLE_CONTROL is registered */
{
const char *name = NULL;
const char *nick = NULL;
g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_CONTROL, SPA_CONTROL_Properties, &name, &nick, NULL));
g_assert_cmpstr (name, ==, "Spa:Enum:Control:Properties");
g_assert_cmpstr (nick, ==, "Properties");
}
/* Make sure SPA_CHOICE_Enum type from WP_SPA_TYPE_TABLE_CHOICE is registered */
{
const char *name = NULL;
const char *nick = NULL;
g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_CHOICE, SPA_CHOICE_Enum, &name, &nick, NULL));
g_assert_cmpstr (name, ==, "Spa:Enum:Choice:Enum");
g_assert_cmpstr (nick, ==, "Enum");
}
wp_spa_type_deinit ();
}
static void
test_spa_type_register (void)
{
wp_spa_type_init (FALSE);
/* Make sure no types are registered */
g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), ==, 0);
g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_PARAM), ==, 0);
g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_PROPS), ==, 0);
g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_CONTROL), ==, 0);
g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_CHOICE), ==, 0);
/* Register SPA_TYPE_Bool */
{
g_assert_true (wp_spa_type_register (WP_SPA_TYPE_TABLE_BASIC, "Spa:Bool", "spa-bool"));
guint32 id = 0;
const char *name = NULL;
g_assert_true (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "spa-bool", &id, &name, NULL));
g_assert_cmpuint (id, ==, SPA_TYPE_Bool);
g_assert_cmpstr (name, ==, "Spa:Bool");
name = NULL;
const char *nick = NULL;
g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_BASIC, id, &name, &nick, NULL));
g_assert_cmpstr (name, ==, "Spa:Bool");
g_assert_cmpstr (nick, ==, "spa-bool");
g_assert_false (wp_spa_type_register (WP_SPA_TYPE_TABLE_BASIC, "Spa:Bool", "spa-bool"));
g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), ==, 1);
}
/* Register Custom */
{
g_assert_true (wp_spa_type_register (WP_SPA_TYPE_TABLE_BASIC, "Wp:Bool", "wp-bool"));
guint32 id = 0;
const char *name = NULL;
g_assert_true (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "wp-bool", &id, &name, NULL));
g_assert_cmpuint (id, ==, SPA_TYPE_VENDOR_Other + 1);
g_assert_cmpstr (name, ==, "Wp:Bool");
name = NULL;
const char *nick = NULL;
g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_BASIC, id, &name, &nick, NULL));
g_assert_cmpstr (name, ==, "Wp:Bool");
g_assert_cmpstr (nick, ==, "wp-bool");
g_assert_false (wp_spa_type_register (WP_SPA_TYPE_TABLE_BASIC, "Wp:Bool", "wp-bool"));
g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), ==, 2);
}
/* Unregister SPA_TYPE_Bool */
g_assert_true (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "spa-bool", NULL, NULL, NULL));
wp_spa_type_unregister (WP_SPA_TYPE_TABLE_BASIC, "spa-bool");
g_assert_false (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "spa-bool", NULL, NULL, NULL));
g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), ==, 1);
/* Unregister Custom */
g_assert_true (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "wp-bool", NULL, NULL, NULL));
wp_spa_type_unregister (WP_SPA_TYPE_TABLE_BASIC, "wp-bool");
g_assert_false (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "wp-bool", NULL, NULL, NULL));
g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), ==, 0);
wp_spa_type_deinit ();
}
int
main (int argc, char *argv[])
{
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/wp/spa-type/basic", test_spa_type_basic);
g_test_add_func ("/wp/spa-type/register", test_spa_type_register);
return g_test_run ();
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment