Reorganise SPA tree

Reorganise the SPA includes to make it more extensible later
Simplify the naming of the buffer and meta params
This commit is contained in:
Wim Taymans 2017-11-10 13:36:14 +01:00
parent 58451d626c
commit caaeaff223
151 changed files with 1353 additions and 964 deletions

View file

@ -0,0 +1,196 @@
/* Simple Plugin API
* Copyright (C) 2016 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SPA_DEFS_H__
#define __SPA_DEFS_H__
#ifdef __cplusplus
extern "C" {
#else
#include <stdbool.h>
#endif
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
enum spa_result {
SPA_RESULT_WAIT_SYNC = 2,
SPA_RESULT_MODIFIED = 1,
SPA_RESULT_OK = 0,
SPA_RESULT_ERROR = -1,
SPA_RESULT_ERRNO = -2,
SPA_RESULT_INACTIVE = -3,
SPA_RESULT_NO_FORMAT = -4,
SPA_RESULT_INVALID_COMMAND = -5,
SPA_RESULT_INVALID_PORT = -6,
SPA_RESULT_HAVE_BUFFER = -7,
SPA_RESULT_NEED_BUFFER = -8,
SPA_RESULT_PORTS_CHANGED = -9,
SPA_RESULT_FORMAT_CHANGED = -10,
SPA_RESULT_PROPERTIES_CHANGED = -11,
SPA_RESULT_NOT_IMPLEMENTED = -12,
SPA_RESULT_INVALID_PROPERTY_INDEX = -13,
SPA_RESULT_PROPERTY_UNSET = -14,
SPA_RESULT_ENUM_END = -15,
SPA_RESULT_WRONG_PROPERTY_TYPE = -16,
SPA_RESULT_WRONG_PROPERTY_SIZE = -17,
SPA_RESULT_INVALID_MEDIA_TYPE = -18,
SPA_RESULT_INVALID_FORMAT_PROPERTIES = -19,
SPA_RESULT_FORMAT_INCOMPLETE = -20,
SPA_RESULT_INVALID_ARGUMENTS = -21,
SPA_RESULT_UNKNOWN_INTERFACE = -22,
SPA_RESULT_INVALID_DIRECTION = -23,
SPA_RESULT_TOO_MANY_PORTS = -24,
SPA_RESULT_INVALID_PROPERTY_ACCESS = -25,
SPA_RESULT_UNEXPECTED = -26,
SPA_RESULT_NO_BUFFERS = -27,
SPA_RESULT_INVALID_BUFFER_ID = -28,
SPA_RESULT_WRONG_STATE = -29,
SPA_RESULT_ASYNC_BUSY = -30,
SPA_RESULT_INVALID_OBJECT_ID = -31,
SPA_RESULT_NO_MEMORY = -32,
SPA_RESULT_NO_PERMISSION = -33,
SPA_RESULT_SKIPPED = -34,
SPA_RESULT_OUT_OF_BUFFERS = -35,
SPA_RESULT_INCOMPATIBLE_PROPS = -36,
SPA_RESULT_INCOMPATIBLE_VERSION = -37,
SPA_RESULT_NOT_FOUND = -38,
SPA_RESULT_BUSY = -39,
SPA_RESULT_UNKNOWN_PARAM = -40,
SPA_RESULT_PARAM_INCOMPLETE = -41,
};
#define SPA_ASYNC_BIT (1 << 30)
#define SPA_ASYNC_MASK (3 << 30)
#define SPA_ASYNC_SEQ_MASK (SPA_ASYNC_BIT - 1)
#define SPA_RESULT_IS_OK(res) ((res) >= 0)
#define SPA_RESULT_IS_ERROR(res) ((res) < 0)
#define SPA_RESULT_IS_ASYNC(res) (((res) & SPA_ASYNC_MASK) == SPA_ASYNC_BIT)
#define SPA_RESULT_ASYNC_SEQ(res) ((res) & SPA_ASYNC_SEQ_MASK)
#define SPA_RESULT_RETURN_ASYNC(seq) (SPA_ASYNC_BIT | ((seq) & SPA_ASYNC_SEQ_MASK))
enum spa_direction {
SPA_DIRECTION_INPUT = 0,
SPA_DIRECTION_OUTPUT = 1,
};
#define SPA_RECTANGLE(width,height) (struct spa_rectangle){ width, height }
struct spa_rectangle {
uint32_t width;
uint32_t height;
};
#define SPA_FRACTION(num,denom) (struct spa_fraction){ num, denom }
struct spa_fraction {
uint32_t num;
uint32_t denom;
};
#define SPA_N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0]))
#define SPA_MIN(a,b) ((a)<(b) ? (a) : (b))
#define SPA_MAX(a,b) ((a)>(b) ? (a) : (b))
#define SPA_ABS(a) ((a)>0 ? (a) : -(a))
#define SPA_CLAMP(v,a,b) ((v)>(b) ? (b) : ((v) < (a) ? (a) : (v)))
#define SPA_MEMBER(b,o,t) ((t*)((uint8_t*)(b) + (o)))
#define SPA_CONTAINER_OF(p,t,m) (t*)((uint8_t*)p - offsetof (t,m))
#define SPA_PTRDIFF(p1,p2) ((uint8_t*)(p1) - (uint8_t*)(p2))
#define SPA_PTR_TO_INT(p) ((int) ((intptr_t) (p)))
#define SPA_INT_TO_PTR(u) ((void*) ((intptr_t) (u)))
#define SPA_PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p)))
#define SPA_UINT32_TO_PTR(u) ((void*) ((uintptr_t) (u)))
#define SPA_TIME_INVALID ((int64_t)INT64_MIN)
#define SPA_IDX_INVALID ((unsigned int)-1)
#define SPA_ID_INVALID ((uint32_t)0xffffffff)
#define SPA_NSEC_PER_SEC (1000000000ll)
#define SPA_NSEC_PER_MSEC (1000000ll)
#define SPA_NSEC_PER_USEC (1000ll)
#define SPA_USEC_PER_SEC (1000000ll)
#define SPA_USEC_PER_MSEC (1000ll)
#define SPA_MSEC_PER_SEC (1000ll)
#define SPA_TIMESPEC_TO_TIME(ts) ((ts)->tv_sec * SPA_NSEC_PER_SEC + (ts)->tv_nsec)
#define SPA_TIMEVAL_TO_TIME(tv) ((tv)->tv_sec * SPA_NSEC_PER_SEC + (tv)->tv_usec * 1000ll)
#ifdef __GNUC__
#define SPA_PRINTF_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1)))
#define SPA_ALIGNED(align) __attribute__((aligned(align)))
#define SPA_DEPRECATED __attribute__ ((deprecated))
#else
#define SPA_PRINTF_FUNC(fmt, arg1)
#define SPA_ALIGNED(align)
#define SPA_DEPRECATED
#endif
#define SPA_ROUND_UP_N(num,align) ((((num) + ((align) - 1)) & ~((align) - 1)))
#ifndef SPA_LIKELY
#ifdef __GNUC__
#define SPA_LIKELY(x) (__builtin_expect(!!(x),1))
#define SPA_UNLIKELY(x) (__builtin_expect(!!(x),0))
#else
#define SPA_LIKELY(x) (x)
#define SPA_UNLIKELY(x) (x)
#endif
#endif
#define SPA_STRINGIFY_1(x...) #x
#define SPA_STRINGIFY(x...) SPA_STRINGIFY_1(x)
#define spa_return_if_fail(expr) \
do { \
if (SPA_UNLIKELY(!(expr))) \
return; \
} while(false)
#define spa_return_val_if_fail(expr, val) \
do { \
if (SPA_UNLIKELY(!(expr))) \
return (val); \
} while(false)
/* spa_assert_se() is an assert which guarantees side effects of x,
* i.e. is never optimized away, regardless of NDEBUG or FASTPATH. */
#define spa_assert_se(expr) \
do { \
if (SPA_UNLIKELY(!(expr))) \
abort(); \
} while (false)
/* Does exactly nothing */
#define spa_nop() do {} while (false)
#define spa_memzero(x,l) (memset((x), 0, (l)))
#define spa_zero(x) (spa_memzero(&(x), sizeof(x)))
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __SPA_DEFS_H__ */

View file

@ -0,0 +1,72 @@
/* Simple Plugin API
* Copyright (C) 2016 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SPA_DICT_H__
#define __SPA_DICT_H__
#ifdef __cplusplus
extern "C" {
#endif
#define SPA_TYPE__Dict SPA_TYPE_POINTER_BASE "Dict"
#define SPA_TYPE_DICT_BASE SPA_TYPE__Dict ":"
#include <string.h>
#include <spa/utils/defs.h>
struct spa_dict_item {
const char *key;
const char *value;
};
struct spa_dict {
uint32_t n_items;
const struct spa_dict_item *items;
};
#define SPA_DICT_INIT(n_items,items) { n_items, items }
#define spa_dict_for_each(item, dict) \
for ((item) = (dict)->items; \
(item) < &(dict)->items[(dict)->n_items]; \
(item)++)
static inline const struct spa_dict_item *spa_dict_lookup_item(const struct spa_dict *dict,
const char *key)
{
const struct spa_dict_item *item;
spa_dict_for_each(item, dict) {
if (!strcmp(item->key, key))
return item;
}
return NULL;
}
static inline const char *spa_dict_lookup(const struct spa_dict *dict, const char *key)
{
const struct spa_dict_item *item = spa_dict_lookup_item(dict, key);
return item ? item->value : NULL;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __SPA_DICT_H__ */

View file

@ -0,0 +1,106 @@
/* SPA
* Copyright (C) 2017 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SPA_HOOK_H__
#define __SPA_HOOK_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <spa/utils/list.h>
/** \class spa_hook
*
* \brief a list of hooks
*
* The hook list provides a way to keep track of hooks.
*/
/** A list of hooks */
struct spa_hook_list {
struct spa_list list;
};
/** A hook, contains the structure with functions and the data passed
* to the functions. */
struct spa_hook {
struct spa_list link;
const void *funcs;
void *data;
};
/** Initialize a hook list */
static inline void spa_hook_list_init(struct spa_hook_list *list)
{
spa_list_init(&list->list);
}
/** Append a hook \memberof spa_hook */
static inline void spa_hook_list_append(struct spa_hook_list *list,
struct spa_hook *hook,
const void *funcs, void *data)
{
hook->funcs = funcs;
hook->data = data;
spa_list_append(&list->list, &hook->link);
}
/** Prepend a hook \memberof spa_hook */
static inline void spa_hook_list_prepend(struct spa_hook_list *list,
struct spa_hook *hook,
const void *funcs, void *data)
{
hook->funcs = funcs;
hook->data = data;
spa_list_prepend(&list->list, &hook->link);
}
/** Remove a hook \memberof spa_hook */
static inline void spa_hook_remove(struct spa_hook *hook)
{
spa_list_remove(&hook->link);
}
/** Call all hooks in a list, starting from the given one and optionally stopping
* after calling the first non-NULL function */
#define spa_hook_list_do_call(l,start,type,method,once,...) ({ \
struct spa_hook_list *list = l; \
struct spa_list *s = start ? (struct spa_list *)start : &list->list; \
struct spa_hook *ci, *t; \
spa_list_for_each_safe_next(ci, t, &list->list, s, link) { \
const type *cb = ci->funcs; \
if (cb->method) { \
cb->method(ci->data, ## __VA_ARGS__); \
if (once) \
break; \
} \
} \
})
#define spa_hook_list_call(l,t,m,...) spa_hook_list_do_call(l,NULL,t,m,false,##__VA_ARGS__)
#define spa_hook_list_call_once(l,t,m,...) spa_hook_list_do_call(l,NULL,t,m,true,##__VA_ARGS__)
#define spa_hook_list_call_start(l,s,t,m,...) spa_hook_list_do_call(l,s,t,m,false,##__VA_ARGS__)
#define spa_hook_list_call_once_start(l,s,t,m,...) spa_hook_list_do_call(l,s,t,m,true,##__VA_ARGS__)
#ifdef __cplusplus
}
#endif
#endif /* __SPA_HOOK_H__ */

View file

@ -0,0 +1,96 @@
/* Simple Plugin API
* Copyright (C) 2016 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SPA_LIST_H__
#define __SPA_LIST_H__
#ifdef __cplusplus
extern "C" {
#endif
struct spa_list {
struct spa_list *next;
struct spa_list *prev;
};
static inline void spa_list_init(struct spa_list *list)
{
list->next = list;
list->prev = list;
}
static inline void spa_list_insert(struct spa_list *list, struct spa_list *elem)
{
elem->prev = list;
elem->next = list->next;
list->next = elem;
elem->next->prev = elem;
}
static inline void spa_list_insert_list(struct spa_list *list, struct spa_list *other)
{
other->next->prev = list;
other->prev->next = list->next;
list->next->prev = other->prev;
list->next = other->next;
}
static inline void spa_list_remove(struct spa_list *elem)
{
elem->prev->next = elem->next;
elem->next->prev = elem->prev;
}
#define spa_list_is_empty(l) ((l)->next == (l))
#define spa_list_first(head, type, member) \
SPA_CONTAINER_OF((head)->next, type, member)
#define spa_list_last(head, type, member) \
SPA_CONTAINER_OF((head)->prev, type, member)
#define spa_list_append(list, item) \
spa_list_insert((list)->prev, item);
#define spa_list_prepend(list, item) \
spa_list_insert(list, item);
#define spa_list_for_each_next(pos, head, curr, member) \
for (pos = SPA_CONTAINER_OF((curr)->next, __typeof__(*pos), member); \
&pos->member != (head); \
pos = SPA_CONTAINER_OF(pos->member.next, __typeof__(*pos), member))
#define spa_list_for_each(pos, head, member) \
spa_list_for_each_next(pos, head, head, member) \
#define spa_list_for_each_safe_next(pos, tmp, head, curr, member) \
for (pos = SPA_CONTAINER_OF((curr)->next, __typeof__(*pos), member), \
tmp = SPA_CONTAINER_OF((pos)->member.next, __typeof__(*tmp), member); \
&pos->member != (head); \
pos = tmp, \
tmp = SPA_CONTAINER_OF(pos->member.next, __typeof__(*tmp), member))
#define spa_list_for_each_safe(pos, tmp, head, member) \
spa_list_for_each_safe_next(pos, tmp, head, head, member) \
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __SPA_LIST_H__ */

View file

@ -0,0 +1,179 @@
/* Simple Plugin API
* Copyright (C) 2016 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SPA_RINGBUFFER_H__
#define __SPA_RINGBUFFER_H__
#ifdef __cplusplus
extern "C" {
#endif
struct spa_ringbuffer;
#define SPA_TYPE__RingBuffer SPA_TYPE_INTERFACE_BASE "RingBuffer"
#define SPA_TYPE_RINGBUFFER_BASE SPA_TYPE__RingBuffer ":"
#include <string.h>
#include <spa/utils/defs.h>
/**
* spa_ringbuffer:
* @readindex: the current read index
* @writeindex: the current write index
* @size: the size of the ringbuffer
* @mask: mask as @size - 1
*/
struct spa_ringbuffer {
uint32_t readindex;
uint32_t writeindex;
uint32_t size;
uint32_t mask;
};
#define SPA_RINGBUFFER_INIT(size) (struct spa_ringbuffer) { 0, 0, (size), (size)-1 }
/**
* spa_ringbuffer_init:
* @rbuf: a #struct spa_ringbuffer
* @size: the number of elements in the ringbuffer
*
* Initialize a #struct spa_ringbuffer with @size.
*/
static inline void spa_ringbuffer_init(struct spa_ringbuffer *rbuf, uint32_t size)
{
*rbuf = SPA_RINGBUFFER_INIT(size);
}
/**
* spa_ringbuffer_clear:
* @rbuf: a #struct spa_ringbuffer
*
* Clear @rbuf
*/
static inline void spa_ringbuffer_clear(struct spa_ringbuffer *rbuf)
{
rbuf->readindex = 0;
rbuf->writeindex = 0;
}
/**
* spa_ringbuffer_get_read_index:
* @rbuf: a #struct spa_ringbuffer
* @index: the value of readindex, should be masked to get the
* offset in the ringbuffer memory
*
* Returns: number of available bytes to read. values < 0 mean
* there was an underrun. values > rbuf->size means there
* was an overrun.
*/
static inline int32_t spa_ringbuffer_get_read_index(struct spa_ringbuffer *rbuf, uint32_t *index)
{
int32_t avail;
*index = __atomic_load_n(&rbuf->readindex, __ATOMIC_RELAXED);
avail = (int32_t) (__atomic_load_n(&rbuf->writeindex, __ATOMIC_ACQUIRE) - *index);
return avail;
}
/**
* spa_ringbuffer_read_data:
* @rbuf: a #struct spa_ringbuffer
* @buffer: memory to read from
* @offset: offset in @buffer to read from
* @data: destination memory
* @len: number of bytes to read
*
* Read @len bytes from @rbuf starting @offset. @offset must be masked
* with the size of @rbuf and len should be smaller than the size.
*/
static inline void
spa_ringbuffer_read_data(struct spa_ringbuffer *rbuf,
void *buffer, uint32_t offset, void *data, uint32_t len)
{
uint32_t first = SPA_MIN(len, rbuf->size - offset);
memcpy(data, buffer + offset, first);
if (SPA_UNLIKELY(len > first)) {
memcpy(data + first, buffer, len - first);
}
}
/**
* spa_ringbuffer_read_update:
* @rbuf: a #struct spa_ringbuffer
* @index: new index
*
* Update the read pointer to @index
*/
static inline void spa_ringbuffer_read_update(struct spa_ringbuffer *rbuf, int32_t index)
{
__atomic_store_n(&rbuf->readindex, index, __ATOMIC_RELEASE);
}
/**
* spa_ringbuffer_get_write_index:
* @rbuf: a #struct spa_ringbuffer
* @index: the value of writeindex, should be masked to get the
* offset in the ringbuffer memory
*
* Returns: the fill level of @rbuf. values < 0 mean
* there was an underrun. values > rbuf->size means there
* was an overrun. Subtract from the buffer size to get
* the number of bytes available for writing.
*/
static inline int32_t spa_ringbuffer_get_write_index(struct spa_ringbuffer *rbuf, uint32_t *index)
{
int32_t filled;
*index = __atomic_load_n(&rbuf->writeindex, __ATOMIC_RELAXED);
filled = (int32_t) (*index - __atomic_load_n(&rbuf->readindex, __ATOMIC_ACQUIRE));
return filled;
}
static inline void
spa_ringbuffer_write_data(struct spa_ringbuffer *rbuf,
void *buffer, uint32_t offset, void *data, uint32_t len)
{
uint32_t first = SPA_MIN(len, rbuf->size - offset);
memcpy(buffer + offset, data, first);
if (SPA_UNLIKELY(len > first)) {
memcpy(buffer, data + first, len - first);
}
}
/**
* spa_ringbuffer_write_update:
* @rbuf: a #struct spa_ringbuffer
* @index: new index
*
* Update the write pointer to @index
*
*/
static inline void spa_ringbuffer_write_update(struct spa_ringbuffer *rbuf, int32_t index)
{
__atomic_store_n(&rbuf->writeindex, index, __ATOMIC_RELEASE);
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __SPA_RINGBUFFER_H__ */

View file

@ -0,0 +1,52 @@
/* Simple Plugin API
* Copyright (C) 2016 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SPA_TYPE_H__
#define __SPA_TYPE_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <spa/utils/defs.h>
#define SPA_TYPE_BASE "Spa:"
#define SPA_TYPE__Enum SPA_TYPE_BASE "Enum"
#define SPA_TYPE_ENUM_BASE SPA_TYPE__Enum ":"
#define SPA_TYPE__Pointer SPA_TYPE_BASE "Pointer"
#define SPA_TYPE_POINTER_BASE SPA_TYPE__Pointer ":"
#define SPA_TYPE__Interface SPA_TYPE_BASE "Interface"
#define SPA_TYPE_INTERFACE_BASE SPA_TYPE__Interface ":"
#define SPA_TYPE__Object SPA_TYPE_BASE "Object"
#define SPA_TYPE_OBJECT_BASE SPA_TYPE__Object ":"
static inline bool spa_type_is_a(const char *type, const char *parent)
{
return type != NULL && parent != NULL && strncmp(type, parent, strlen(parent)) == 0;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __SPA_TYPE_H__ */