Interfaces
SPA » Utilities

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

## Files

file | hook.h
| `spa/utils/hook.h`

## 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_VERSION_MIN(c, v) ((c) && ((v) == 0 || (c)->version > (v)-1))
| Check if a callback c is of at least version v. More...
#define | SPA_CALLBACK_CHECK(c, m, v) (SPA_CALLBACK_VERSION_MIN(c,v) && (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_callback_version_min(callbacks, type, vers)
| True if the callbacks are of version vers, false otherwise. More...
#define | spa_callback_check(callbacks, type, method, vers)
| True if the callbacks contains method of version vers, false otherwise. More...
#define | spa_callbacks_call_res(callbacks, type, res, method, vers, ...)
| Invoke method named method in the callbacks. More...
#define | spa_interface_callback_version_min(iface, method_type, vers) spa_callback_version_min(&(iface)->cb, method_type, vers)
| True if the iface's callbacks are of version vers, false otherwise. More...
#define | spa_interface_callback_check(iface, method_type, method, vers) spa_callback_check(&(iface)->cb, method_type, method, vers)
| True if the iface's callback method is of version vers and exists, false otherwise. 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
);/
})
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:245
spa_interface
Definition: hook.h:158

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");
}
spa_thread_utils_methods::version
uint32_t version
Definition: thread.h:71

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_VERSION_MIN

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

Check if a callback c is of at least version v.

## SPA_CALLBACK_CHECK

#define SPA_CALLBACK_CHECK | ( |  | c,
|  |  | m,
|  |  | v
| ) |  | (SPA_CALLBACK_VERSION_MIN(c,v) && (c)->m)

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

## 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_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_INIT
#define SPA_INTERFACE_INIT(_type, _version, _funcs, _data)
Initialize a spa_interface.
Definition: hook.h:177

Examples
  export-sink.c, export-source.c, and local-v4l2.c.

## spa_callbacks_call

#define spa_callbacks_call | ( |  | callbacks,
|  |  | type,
|  |  | method,
|  |  | vers,
|  |  | ...
| ) |  |

Invoke method named method in the callbacks.

The method_type defines the type of the method struct. Returns true if the method could be called, false otherwise.

## spa_callback_version_min

#define spa_callback_version_min | ( |  | callbacks,
|  |  | type,
|  |  | vers
| ) |  |

True if the callbacks are of version vers, false otherwise.

## spa_callback_check

#define spa_callback_check | ( |  | callbacks,
|  |  | type,
|  |  | method,
|  |  | vers
| ) |  |

True if the callbacks contains method of version vers, false otherwise.

## spa_callbacks_call_res

#define spa_callbacks_call_res | ( |  | callbacks,
|  |  | type,
|  |  | res,
|  |  | method,
|  |  | vers,
|  |  | ...
| ) |  |

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_interface_callback_version_min

#define spa_interface_callback_version_min | ( |  | iface,
|  |  | method_type,
|  |  | vers
| ) |  | spa_callback_version_min(&(iface)->cb, method_type, vers)

True if the iface's callbacks are of version vers, false otherwise.

## spa_interface_callback_check

#define spa_interface_callback_check | ( |  | iface,
|  |  | method_type,
|  |  | method,
|  |  | vers
| ) |  | spa_callback_check(&(iface)->cb, method_type, method, vers)

True if the iface's callback method is of version vers and exists, false otherwise.

## 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.