PipeWire  0.3.33
SPA Interfaces

Generic implementation of implementation-independent interfaces. More...

Data Structures

struct  spa_callbacks
 Callbacks, contains the structure with functions and the data passed to the functions. More...
 
struct  spa_interface
 

Macros

#define SPA_CALLBACK_CHECK(c, m, v)   ((c) && ((v) == 0 || (c)->version > (v)-1) && (c)->m)
 Check if a callback c has method m of version v. More...
 
#define SPA_CALLBACKS_INIT(_funcs, _data)   (struct spa_callbacks){ _funcs, _data, }
 Initialize the set of functions funcs as a spa_callbacks, together with _data. More...
 
#define SPA_INTERFACE_INIT(_type, _version, _funcs, _data)    (struct spa_interface){ _type, _version, SPA_CALLBACKS_INIT(_funcs,_data), }
 Initialize a spa_interface. More...
 
#define spa_callbacks_call(callbacks, type, method, vers, ...)
 Invoke method named method in the callbacks. More...
 
#define spa_callbacks_call_res(callbacks, type, res, method, vers, ...)
 Invoke method named method in the callbacks. More...
 
#define spa_interface_call(iface, method_type, method, vers, ...)    spa_callbacks_call(&(iface)->cb,method_type,method,vers,##__VA_ARGS__)
 Invoke method named method in the callbacks on the given interface object. More...
 
#define spa_interface_call_res(iface, method_type, res, method, vers, ...)    spa_callbacks_call_res(&(iface)->cb,method_type,res,method,vers,##__VA_ARGS__)
 Invoke method named method in the callbacks on the given interface object. More...
 

Detailed Description

Generic implementation of implementation-independent interfaces.

A SPA Interface is a generic struct that, together with a few macros, provides a generic way of invoking methods on objects without knowing the details of the implementation.

The primary interaction with interfaces is through macros that expand into the right method call. For the implementation of an interface, we need two structs and a macro to invoke the bar method:

// this struct must be public and defines the interface to a
// struct foo
struct foo_methods {
uint32_t version;
void (*bar)(void *object, const char *msg);
};
// this struct does not need to be public
struct foo {
struct spa_interface iface; // must be first element, see foo_bar()
int some_other_field;
...
};
// if struct foo is private, we need to cast to a
// generic spa_interface object
#define foo_bar(obj, ...) ({ \
struct foo *f = obj;
spa_interface_call((struct spa_interface *)f, // pointer to spa_interface in foo
struct foo_methods, // type of callbacks
bar, // name of methods
0, // hardcoded version to match foo_methods->version
__VA_ARGS__ // pass rest of args through
);/
})

The struct foo_methods and the invocation macro foo_bar() must be available to the caller. The implementation of struct foo can be private.

void main(void) {
struct foo *myfoo = get_foo_from_somewhere();
foo_bar(myfoo, "Invoking bar() on myfoo");
}

The expansion of foo_bar() resolves roughly into this code:

void main(void) {
struct foo *myfoo = get_foo_from_somewhere();
// foo_bar(myfoo, "Invoking bar() on myfoo");
const struct foo_methods *methods = ((struct spa_interface*)myfoo)->cb;
if (0 >= methods->version && // version check
methods->bar) // compile error if this function does not exist,
methods->bar(myfoo, "Invoking bar() on myfoo");
}

The typecast used in foo_bar() allows struct foo to be opaque to the caller. The implementation may assign the callback methods at object instantiation, and the caller will transparently invoke the method on the given object. For example, the following code assigns a different bar() method on Mondays - the caller does not need to know this.

static void bar_stdout(struct foo *f, const char *msg) {
printf(msg);
}
static void bar_stderr(struct foo *f, const char *msg) {
fprintf(stderr, msg);
}
struct foo* get_foo_from_somewhere() {
struct foo *f = calloc(sizeof struct foo);
// illustrative only, use SPA_INTERFACE_INIT()
f->iface->cb = (struct foo_methods*) { .bar = bar_stdout };
if (today_is_monday)
f->iface->cb = (struct foo_methods*) { .bar = bar_stderr };
return f;
}

Macro Definition Documentation

◆ SPA_CALLBACK_CHECK

#define SPA_CALLBACK_CHECK (   c,
  m,
 
)    ((c) && ((v) == 0 || (c)->version > (v)-1) && (c)->m)

Check if a callback c has method m of version v.

◆ spa_callbacks_call

#define spa_callbacks_call (   callbacks,
  type,
  method,
  vers,
  ... 
)
Value:
({ \
const type *_f = (const type *) (callbacks)->funcs; \
if (SPA_LIKELY(SPA_CALLBACK_CHECK(_f,method,vers))) \
_f->method((callbacks)->data, ## __VA_ARGS__); \
})

Invoke method named method in the callbacks.

The method_type defines the type of the method struct.

◆ spa_callbacks_call_res

#define spa_callbacks_call_res (   callbacks,
  type,
  res,
  method,
  vers,
  ... 
)
Value:
({ \
const type *_f = (const type *) (callbacks)->funcs; \
if (SPA_LIKELY(SPA_CALLBACK_CHECK(_f,method,vers))) \
res = _f->method((callbacks)->data, ## __VA_ARGS__); \
res; \
})

Invoke method named method in the callbacks.

The method_type defines the type of the method struct.

The return value is stored in res.

◆ SPA_CALLBACKS_INIT

#define SPA_CALLBACKS_INIT (   _funcs,
  _data 
)    (struct spa_callbacks){ _funcs, _data, }

Initialize the set of functions funcs as a spa_callbacks, together with _data.

◆ spa_interface_call

#define spa_interface_call (   iface,
  method_type,
  method,
  vers,
  ... 
)     spa_callbacks_call(&(iface)->cb,method_type,method,vers,##__VA_ARGS__)

Invoke method named method in the callbacks on the given interface object.

The method_type defines the type of the method struct, not the interface itself.

◆ spa_interface_call_res

#define spa_interface_call_res (   iface,
  method_type,
  res,
  method,
  vers,
  ... 
)     spa_callbacks_call_res(&(iface)->cb,method_type,res,method,vers,##__VA_ARGS__)

Invoke method named method in the callbacks on the given interface object.

The method_type defines the type of the method struct, not the interface itself.

The return value is stored in res.

◆ SPA_INTERFACE_INIT

#define SPA_INTERFACE_INIT (   _type,
  _version,
  _funcs,
  _data 
)     (struct spa_interface){ _type, _version, SPA_CALLBACKS_INIT(_funcs,_data), }

Initialize a spa_interface.

const static struct foo_methods foo_funcs = {
.bar = some_bar_implementation,
};
struct foo *f = malloc(...);
f->iface = SPA_INTERFACE_INIT("foo type", 0, foo_funcs, NULL);
spa_interface
Definition: hook.h:146
main
int main(int argc, char *argv[])
Definition: media-session.c:2431
SPA_CALLBACK_CHECK
#define SPA_CALLBACK_CHECK(c, m, v)
Check if a callback c has method m of version v.
Definition: hook.h:136
data
user data to add to an object
Definition: filter.c:75
SPA_INTERFACE_INIT
#define SPA_INTERFACE_INIT(_type, _version, _funcs, _data)
Initialize a spa_interface.
Definition: hook.h:165
SPA_LIKELY
#define SPA_LIKELY(x)
Definition: defs.h:234
spa_interface_call
#define spa_interface_call(iface, method_type, method, vers,...)
Invoke method named method in the callbacks on the given interface object.
Definition: hook.h:198
spa_thread_utils_methods::version
uint32_t version
Definition: build-12683127/doc/spa/support/thread.h:57
methods
struct spa_thread_utils_methods methods
Definition: thread.c:68