interface: add an interface struct

The interface struct has the type,version and methods of the
interface.
Make spa interfaces extend from spa_interface and make a
separate structure for the methods.
Pass a generic void* as the first argument of methods, like
we don in PipeWire.
Bundle the methods + implementation in a versioned inteface
and use that to invoke methods. This way we can do version
checks on the methods.
Make resource and proxy interfaces that we can can call. We
can then make the core interfaces independent on proxy/resource and
hide them in the lower layers.
Add add_listener method to methods of core interfaces, just
like SPA.
This commit is contained in:
Wim Taymans 2019-05-20 16:11:23 +02:00
parent eb6481efb3
commit ff946e3d4b
85 changed files with 3051 additions and 3000 deletions

View file

@ -32,6 +32,13 @@ extern "C" {
#include <stdarg.h>
#include <spa/utils/defs.h>
#include <spa/utils/hook.h>
/**
* The CPU features interface
*/
#define SPA_VERSION_CPU 0
struct spa_cpu { struct spa_interface iface; };
/* x86 specific */
#define SPA_CPU_FLAG_MMX (1<<0) /**< standard MMX */
@ -72,35 +79,40 @@ extern "C" {
#define SPA_CPU_FORCE_AUTODETECT ((uint32_t)-1)
/**
* The CPU features interface
* methods
*/
struct spa_cpu {
/** the version of this interface. This can be used to expand this
struct spa_cpu_methods {
/** the version of the methods. This can be used to expand this
structure in the future */
#define SPA_VERSION_CPU 0
#define SPA_VERSION_CPU_METHODS 0
uint32_t version;
/**
* Extra information about the interface
*/
const struct spa_dict *info;
/** get CPU flags */
uint32_t (*get_flags) (struct spa_cpu *cpu);
uint32_t (*get_flags) (void *object);
/** force CPU flags, use SPA_CPU_FORCE_AUTODETECT to autodetect CPU flags */
int (*force_flags) (struct spa_cpu *cpu, uint32_t flags);
int (*force_flags) (void *object, uint32_t flags);
/** get number of CPU cores */
uint32_t (*get_count) (struct spa_cpu *cpu);
uint32_t (*get_count) (void *object);
/** get maximum required alignment of data */
uint32_t (*get_max_align) (struct spa_cpu *cpu);
uint32_t (*get_max_align) (void *object);
};
#define spa_cpu_get_flags(c) (c)->get_flags((c))
#define spa_cpu_force_flags(c,f) (c)->force_flags((c), (f))
#define spa_cpu_get_count(c) (c)->get_count((c))
#define spa_cpu_get_max_align(c) (c)->get_max_align((c))
#define spa_cpu_method(o,method,version,...) \
({ \
int _res = -ENOTSUP; \
struct spa_cpu *_c = o; \
spa_interface_call_res(&_c->iface, \
struct spa_cpu_methods, _res, \
method, version, ##__VA_ARGS__); \
_res; \
})
#define spa_cpu_get_flags(c) spa_cpu_method(c, get_flags, 0)
#define spa_cpu_force_flags(c,f) spa_cpu_method(c, force_flags, 0, f)
#define spa_cpu_get_count(c) spa_cpu_method(c, get_count, 0)
#define spa_cpu_get_max_align(c) spa_cpu_method(c, get_max_align, 0)
#ifdef __cplusplus
} /* extern "C" */

View file

@ -31,6 +31,9 @@ extern "C" {
#include <spa/support/loop.h>
#define SPA_VERSION_DBUS 0
struct spa_dbus { struct spa_interface iface; };
enum spa_dbus_type {
SPA_DBUS_TYPE_SESSION, /**< The login session bus */
SPA_DBUS_TYPE_SYSTEM, /**< The systemwide bus */
@ -58,10 +61,8 @@ struct spa_dbus_connection {
#define spa_dbus_connection_get(c) (c)->get((c))
#define spa_dbus_connection_destroy(c) (c)->destroy((c))
struct spa_dbus {
/* the version of this structure. This can be used to expand this
* structure in the future */
#define SPA_VERSION_DBUS 0
struct spa_dbus_methods {
#define SPA_VERSION_DBUS_METHODS 0
uint32_t version;
/**
@ -76,11 +77,19 @@ struct spa_dbus {
* \param error location for the DBusError
* \return a new dbus connection wrapper or NULL on error
*/
struct spa_dbus_connection * (*get_connection) (struct spa_dbus *dbus,
struct spa_dbus_connection * (*get_connection) (void *object,
enum spa_dbus_type type);
};
#define spa_dbus_get_connection(d,...) (d)->get_connection((d),__VA_ARGS__)
static inline struct spa_dbus_connection *
spa_dbus_get_connection(struct spa_dbus *dbus, enum spa_dbus_type type)
{
struct spa_dbus_connection *res = NULL;
spa_interface_call_res(&dbus->iface,
struct spa_dbus_methods, res,
get_connection, 0, type);
return res;
}
#ifdef __cplusplus
} /* extern "C" */

View file

@ -33,7 +33,7 @@ extern "C" {
#include <spa/support/log.h>
static inline void spa_log_impl_logv(struct spa_log *log,
static inline void spa_log_impl_logv(void *object,
enum spa_log_level level,
const char *file,
int line,
@ -49,7 +49,7 @@ static inline void spa_log_impl_logv(struct spa_log *log,
levels[level], strrchr(file, '/') + 1, line, func, text);
fputs(location, stderr);
}
static inline void spa_log_impl_log(struct spa_log *log,
static inline void spa_log_impl_log(void *object,
enum spa_log_level level,
const char *file,
int line,
@ -58,24 +58,26 @@ static inline void spa_log_impl_log(struct spa_log *log,
{
va_list args;
va_start(args, fmt);
spa_log_impl_logv(log, level, file, line, func, fmt, args);
spa_log_impl_logv(object, level, file, line, func, fmt, args);
va_end(args);
}
#define SPA_LOG_IMPL_DEFINE(name) \
struct { \
struct spa_log log; \
struct spa_log_methods methods; \
} name
#define SPA_LOG_IMPL_INIT \
{ { SPA_VERSION_LOG, \
SPA_LOG_LEVEL_INFO, \
NULL, \
spa_log_impl_log, \
#define SPA_LOG_IMPL_INIT(name) \
{ { { SPA_TYPE_INTERFACE_Log, SPA_VERSION_LOG, \
SPA_CALLBACKS_INIT(&name.methods, &name) }, \
SPA_LOG_LEVEL_INFO, }, \
{ SPA_VERSION_LOG_METHODS, \
spa_log_impl_log, \
spa_log_impl_logv,} }
#define SPA_LOG_IMPL(name) \
SPA_LOG_IMPL_DEFINE(name) = SPA_LOG_IMPL_INIT
SPA_LOG_IMPL_DEFINE(name) = SPA_LOG_IMPL_INIT(name)
#ifdef __cplusplus
} /* extern "C" */

View file

@ -32,6 +32,7 @@ extern "C" {
#include <stdarg.h>
#include <spa/utils/defs.h>
#include <spa/utils/hook.h>
enum spa_log_level {
SPA_LOG_LEVEL_NONE = 0,
@ -49,17 +50,16 @@ struct spa_log {
/** the version of this log. This can be used to expand this
* structure in the future */
#define SPA_VERSION_LOG 0
uint32_t version;
struct spa_interface iface;
/**
* Logging level, everything above this level is not logged
*/
enum spa_log_level level;
};
/**
* Extra information about the log
*/
const struct spa_dict *info;
struct spa_log_methods {
#define SPA_VERSION_LOG_METHODS 0
uint32_t version;
/**
* Log a message with the given log level.
*
@ -71,7 +71,7 @@ struct spa_log {
* \param fmt printf style format
* \param ... format arguments
*/
void (*log) (struct spa_log *log,
void (*log) (void *object,
enum spa_log_level level,
const char *file,
int line,
@ -89,7 +89,7 @@ struct spa_log {
* \param fmt printf style format
* \param args format arguments
*/
void (*logv) (struct spa_log *log,
void (*logv) (void *object,
enum spa_log_level level,
const char *file,
int line,
@ -105,8 +105,20 @@ struct spa_log {
#define spa_log_log(l,lev,...) \
({ \
if (SPA_UNLIKELY (spa_log_level_enabled (l, lev))) \
(l)->log((l),lev,__VA_ARGS__); \
struct spa_log *_l = l; \
if (SPA_UNLIKELY (spa_log_level_enabled(_l, lev))) \
spa_interface_call(&_l->iface, \
struct spa_log_methods, log, 0, lev, \
__VA_ARGS__); \
})
#define spa_log_logv(l,lev,...) \
({ \
struct spa_log *_l = l; \
if (SPA_UNLIKELY (spa_log_level_enabled(_l, lev))) \
spa_interface_call(&_l->iface, \
struct spa_log_methods, logv, 0, lev, \
__VA_ARGS__); \
})
#define spa_log_error(l,...) spa_log_log(l,SPA_LOG_LEVEL_ERROR,__FILE__,__LINE__,__func__,__VA_ARGS__)
@ -129,7 +141,9 @@ static inline void spa_log_##name (struct spa_log *l, const char *format, ...)
if (SPA_UNLIKELY (spa_log_level_enabled (l, lev))) { \
va_list varargs; \
va_start (varargs, format); \
(l)->logv((l),lev,__FILE__,__LINE__,__func__,format,varargs); \
spa_interface_call(&l->iface, \
struct spa_log_methods, logv, 0, lev, \
__FILE__,__LINE__,__func__,format,varargs); \
va_end (varargs); \
} \
}

View file

@ -29,15 +29,18 @@
extern "C" {
#endif
struct spa_loop;
struct spa_loop_control;
struct spa_loop_utils;
struct spa_source;
#include <spa/utils/defs.h>
#include <spa/utils/hook.h>
#include <spa/utils/result.h>
#define SPA_VERSION_LOOP 0
struct spa_loop { struct spa_interface iface; };
#define SPA_VERSION_LOOP_CONTROL 0
struct spa_loop_control { struct spa_interface iface; };
#define SPA_VERSION_LOOP_UTILS 0
struct spa_loop_utils { struct spa_interface iface; };
struct spa_source;
enum spa_io {
SPA_IO_IN = (1 << 0),
SPA_IO_OUT = (1 << 1),
@ -66,24 +69,26 @@ typedef int (*spa_invoke_func_t) (struct spa_loop *loop,
/**
* Register sources and work items to an event loop
*/
struct spa_loop {
struct spa_loop_methods {
/* the version of this structure. This can be used to expand this
* structure in the future */
#define SPA_VERSION_LOOP 0
#define SPA_VERSION_LOOP_METHODS 0
uint32_t version;
/** add a source to the loop */
int (*add_source) (struct spa_loop *loop,
int (*add_source) (void *object,
struct spa_source *source);
/** update the source io mask */
int (*update_source) (struct spa_source *source);
int (*update_source) (void *object,
struct spa_source *source);
/** remove a source from the loop */
void (*remove_source) (struct spa_source *source);
int (*remove_source) (void *object,
struct spa_source *source);
/** invoke a function in the context of this loop */
int (*invoke) (struct spa_loop *loop,
int (*invoke) (void *object,
spa_invoke_func_t func,
uint32_t seq,
const void *data,
@ -92,10 +97,20 @@ struct spa_loop {
void *user_data);
};
#define spa_loop_add_source(l,...) (l)->add_source((l),__VA_ARGS__)
#define spa_loop_update_source(l,...) (l)->update_source(__VA_ARGS__)
#define spa_loop_remove_source(l,...) (l)->remove_source(__VA_ARGS__)
#define spa_loop_invoke(l,...) (l)->invoke((l),__VA_ARGS__)
#define spa_loop_method(o,method,version,...) \
({ \
int _res = -ENOTSUP; \
struct spa_loop *_o = o; \
spa_interface_call_res(&_o->iface, \
struct spa_loop_methods, _res, \
method, version, ##__VA_ARGS__); \
_res; \
})
#define spa_loop_add_source(l,...) spa_loop_method(l,add_source,0,##__VA_ARGS__)
#define spa_loop_update_source(l,...) spa_loop_method(l,update_source,0,##__VA_ARGS__)
#define spa_loop_remove_source(l,...) spa_loop_method(l,remove_source,0,##__VA_ARGS__)
#define spa_loop_invoke(l,...) spa_loop_method(l,invoke,0,##__VA_ARGS__)
/** Control hooks */
@ -116,13 +131,13 @@ struct spa_loop_control_hooks {
/**
* Control an event loop
*/
struct spa_loop_control {
struct spa_loop_control_methods {
/* the version of this structure. This can be used to expand this
* structure in the future */
#define SPA_VERSION_LOOP_CONTROL 0
#define SPA_VERSION_LOOP_CONTROL_METHODS 0
uint32_t version;
int (*get_fd) (struct spa_loop_control *ctrl);
int (*get_fd) (void *object);
/** Add a hook
* \param ctrl the control to change
@ -130,7 +145,7 @@ struct spa_loop_control {
*
* Adds hooks to the loop controlled by \a ctrl.
*/
void (*add_hook) (struct spa_loop_control *ctrl,
void (*add_hook) (void *object,
struct spa_hook *hook,
const struct spa_loop_control_hooks *hooks,
void *data);
@ -142,14 +157,14 @@ struct spa_loop_control {
* before calling iterate and is typically used to capture the thread
* that this loop will run in.
*/
void (*enter) (struct spa_loop_control *ctrl);
void (*enter) (void *object);
/** Leave a loop
* \param ctrl the control
*
* Ends the iteration of a loop. This should be called after calling
* iterate.
*/
void (*leave) (struct spa_loop_control *ctrl);
void (*leave) (void *object);
/** Perform one iteration of the loop.
* \param ctrl the control
@ -160,14 +175,32 @@ struct spa_loop_control {
* up to \a timeout and then dispatch the fds with activity.
* The number of dispatched fds is returned.
*/
int (*iterate) (struct spa_loop_control *ctrl, int timeout);
int (*iterate) (void *object, int timeout);
};
#define spa_loop_control_get_fd(l) (l)->get_fd(l)
#define spa_loop_control_add_hook(l,...) (l)->add_hook((l),__VA_ARGS__)
#define spa_loop_control_enter(l) (l)->enter(l)
#define spa_loop_control_iterate(l,...) (l)->iterate((l),__VA_ARGS__)
#define spa_loop_control_leave(l) (l)->leave(l)
#define spa_loop_control_method_v(o,method,version,...) \
({ \
struct spa_loop_control *_o = o; \
spa_interface_call(&_o->iface, \
struct spa_loop_control_methods, \
method, version, ##__VA_ARGS__); \
})
#define spa_loop_control_method_r(o,method,version,...) \
({ \
int _res = -ENOTSUP; \
struct spa_loop_control *_o = o; \
spa_interface_call_res(&_o->iface, \
struct spa_loop_control_methods, _res, \
method, version, ##__VA_ARGS__); \
_res; \
})
#define spa_loop_control_get_fd(l) spa_loop_control_method_r(l,get_fd,0)
#define spa_loop_control_add_hook(l,...) spa_loop_control_method_v(l,add_hook,0,__VA_ARGS__)
#define spa_loop_control_enter(l) spa_loop_control_method_v(l,enter,0)
#define spa_loop_control_leave(l) spa_loop_control_method_v(l,leave,0)
#define spa_loop_control_iterate(l,...) spa_loop_control_method_r(l,iterate,0,__VA_ARGS__)
typedef void (*spa_source_io_func_t) (void *data, int fd, enum spa_io mask);
@ -179,55 +212,84 @@ typedef void (*spa_source_signal_func_t) (void *data, int signal_number);
/**
* Create sources for an event loop
*/
struct spa_loop_utils {
struct spa_loop_utils_methods {
/* the version of this structure. This can be used to expand this
* structure in the future */
#define SPA_VERSION_LOOP_UTILS 0
#define SPA_VERSION_LOOP_UTILS_METHODS 0
uint32_t version;
struct spa_source *(*add_io) (struct spa_loop_utils *utils,
struct spa_source *(*add_io) (void *object,
int fd,
enum spa_io mask,
bool close,
spa_source_io_func_t func, void *data);
int (*update_io) (struct spa_source *source, enum spa_io mask);
int (*update_io) (void *object, struct spa_source *source, enum spa_io mask);
struct spa_source *(*add_idle) (struct spa_loop_utils *utils,
struct spa_source *(*add_idle) (void *object,
bool enabled,
spa_source_idle_func_t func, void *data);
void (*enable_idle) (struct spa_source *source, bool enabled);
void (*enable_idle) (void *object, struct spa_source *source, bool enabled);
struct spa_source *(*add_event) (struct spa_loop_utils *utils,
struct spa_source *(*add_event) (void *object,
spa_source_event_func_t func, void *data);
void (*signal_event) (struct spa_source *source);
void (*signal_event) (void *object, struct spa_source *source);
struct spa_source *(*add_timer) (struct spa_loop_utils *utils,
struct spa_source *(*add_timer) (void *object,
spa_source_timer_func_t func, void *data);
int (*update_timer) (struct spa_source *source,
int (*update_timer) (void *object,
struct spa_source *source,
struct timespec *value,
struct timespec *interval,
bool absolute);
struct spa_source *(*add_signal) (struct spa_loop_utils *utils,
struct spa_source *(*add_signal) (void *object,
int signal_number,
spa_source_signal_func_t func, void *data);
/** destroy a source allocated with this interface. This function
* should only be called when the loop is not running or from the
* context of the running loop */
void (*destroy_source) (struct spa_source *source);
void (*destroy_source) (void *object, struct spa_source *source);
};
#define spa_loop_utils_add_io(l,...) (l)->add_io(l,__VA_ARGS__)
#define spa_loop_utils_update_io(l,...) (l)->update_io(__VA_ARGS__)
#define spa_loop_utils_add_idle(l,...) (l)->add_idle(l,__VA_ARGS__)
#define spa_loop_utils_enable_idle(l,...) (l)->enable_idle(__VA_ARGS__)
#define spa_loop_utils_add_event(l,...) (l)->add_event(l,__VA_ARGS__)
#define spa_loop_utils_signal_event(l,...) (l)->signal_event(__VA_ARGS__)
#define spa_loop_utils_add_timer(l,...) (l)->add_timer(l,__VA_ARGS__)
#define spa_loop_utils_update_timer(l,...) (l)->update_timer(__VA_ARGS__)
#define spa_loop_utils_add_signal(l,...) (l)->add_signal(l,__VA_ARGS__)
#define spa_loop_utils_destroy_source(l,...) (l)->destroy_source(__VA_ARGS__)
#define spa_loop_utils_method_v(o,method,version,...) \
({ \
struct spa_loop_utils *_o = o; \
spa_interface_call(&_o->iface, \
struct spa_loop_utils_methods, \
method, version, ##__VA_ARGS__); \
})
#define spa_loop_utils_method_r(o,method,version,...) \
({ \
int _res = -ENOTSUP; \
struct spa_loop_utils *_o = o; \
spa_interface_call_res(&_o->iface, \
struct spa_loop_utils_methods, _res, \
method, version, ##__VA_ARGS__); \
_res; \
})
#define spa_loop_utils_method_s(o,method,version,...) \
({ \
struct spa_source *_res = NULL; \
struct spa_loop_utils *_o = o; \
spa_interface_call_res(&_o->iface, \
struct spa_loop_utils_methods, _res, \
method, version, ##__VA_ARGS__); \
_res; \
})
#define spa_loop_utils_add_io(l,...) spa_loop_utils_method_s(l,add_io,0,__VA_ARGS__)
#define spa_loop_utils_update_io(l,...) spa_loop_utils_method_r(l,update_io,0,__VA_ARGS__)
#define spa_loop_utils_add_idle(l,...) spa_loop_utils_method_s(l,add_idle,0,__VA_ARGS__)
#define spa_loop_utils_enable_idle(l,...) spa_loop_utils_method_v(l,enable_idle,0,__VA_ARGS__)
#define spa_loop_utils_add_event(l,...) spa_loop_utils_method_s(l,add_event,0,__VA_ARGS__)
#define spa_loop_utils_signal_event(l,...) spa_loop_utils_method_v(l,signal_event,0,__VA_ARGS__)
#define spa_loop_utils_add_timer(l,...) spa_loop_utils_method_s(l,add_timer,0,__VA_ARGS__)
#define spa_loop_utils_update_timer(l,...) spa_loop_utils_method_r(l,update_timer,0,__VA_ARGS__)
#define spa_loop_utils_add_signal(l,...) spa_loop_utils_method_s(l,add_signal,0,__VA_ARGS__)
#define spa_loop_utils_destroy_source(l,...) spa_loop_utils_method_v(l,destroy_source,0,__VA_ARGS__)
#ifdef __cplusplus
} /* extern "C" */

View file

@ -37,11 +37,12 @@ struct spa_handle {
#define SPA_VERSION_HANDLE 0
uint32_t version;
/* user_data that can be set by the application */
void *user_data;
/**
* Get the interface provided by \a handle with \a type.
*
* \a interface is always a struct spa_interface but depending on
* \a type, the struct might contain other information.
*
* \param handle a spa_handle
* \param type the interface type
* \param interface result to hold the interface.