doc: switch the spa documentation to doxygen

This commit is contained in:
Peter Hutterer 2021-05-25 13:37:47 +10:00 committed by Wim Taymans
parent 9ed9980fa2
commit 46a39e0ba7
7 changed files with 178 additions and 167 deletions

View file

@ -55,10 +55,10 @@ extra_docs = [
'tutorial4.dox', 'tutorial4.dox',
'tutorial5.dox', 'tutorial5.dox',
'tutorial6.dox', 'tutorial6.dox',
'spa-index.md', 'spa-index.dox',
'spa-design.md', 'spa-design.dox',
'spa-pod.md', 'spa-pod.dox',
'spa-buffer.md', 'spa-buffer.dox',
'pulseaudio.md', 'pulseaudio.md',
] ]

View file

@ -1,4 +1,4 @@
# SPA Buffers /** \page page_spa_buffer SPA Buffers
> What is the array of `spa_data` in `spa_buffer`? > What is the array of `spa_data` in `spa_buffer`?
@ -61,3 +61,5 @@ The reason why is this set up like this is that the metadata memory, the data an
* +==============================+ * +==============================+
Taken from [here](https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/11f95fe11e07192cec19fddb4fafc708e023e49c/spa/include/spa/buffer/alloc.h). Taken from [here](https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/11f95fe11e07192cec19fddb4fafc708e023e49c/spa/include/spa/buffer/alloc.h).
*/

View file

@ -1,4 +1,4 @@
# SPA Design /** \page page_spa_design SPA Design
SPA (Simple Plugin API) is an extensible API to implement all kinds of plugins. SPA (Simple Plugin API) is an extensible API to implement all kinds of plugins.
It is inspired by many other plugin APIs, mostly LV2 and GStreamer. It is inspired by many other plugin APIs, mostly LV2 and GStreamer.
@ -8,20 +8,20 @@ can be introspected and used at runtime in any application.
SPA provides the following functionality: SPA provides the following functionality:
* enumeration of object factories and the interfaces provided by the objects - enumeration of object factories and the interfaces provided by the objects
* creation of objects (AKA a handle) - creation of objects (AKA a handle)
* retrieve interfaces to perform actions on the objects - retrieve interfaces to perform actions on the objects
SPA was designed with the following goals in mind: SPA was designed with the following goals in mind:
* No dependencies, SPA is shipped as a set of header files that have no dependencies - No dependencies, SPA is shipped as a set of header files that have no dependencies
except for the standard c library. except for the standard c library.
* Very efficient both in space and in time. - Very efficient both in space and in time.
* Very configurable and usable in many different environments. All aspects of - Very configurable and usable in many different environments. All aspects of
the plugin environment can be configured and changed, like logging, poll loops, the plugin environment can be configured and changed, like logging, poll loops,
system calls etc. system calls etc.
* Consistent API - Consistent API
* Extensible, new API can be added with minimal effort, existing API can be - Extensible, new API can be added with minimal effort, existing API can be
updated and versioned. updated and versioned.
The original user of SPA is PipeWire, which uses SPA to implement the low-level The original user of SPA is PipeWire, which uses SPA to implement the low-level
@ -38,8 +38,8 @@ the API and then talks about implementing new Plugins.
Types are generally divided into two categories: Types are generally divided into two categories:
* String types: They identify interfaces and highlevel object types. - String types: They identify interfaces and highlevel object types.
* integer types: These are enumerations used in the parts where high - integer types: These are enumerations used in the parts where high
performance/ease of use/low space overhead is needed. performance/ease of use/low space overhead is needed.
The SPA type is system is statis and very simple but still allows you The SPA type is system is statis and very simple but still allows you
@ -85,10 +85,10 @@ later, instead of hardcoding the plugin name.
To dlopen a plugin we then need to prefix the plugin path like this: To dlopen a plugin we then need to prefix the plugin path like this:
```c \code{.c}
#define SPA_PLUGIN_PATH /usr/lib64/spa-0.2/" #define SPA_PLUGIN_PATH /usr/lib64/spa-0.2/"
void *hnd = dlopen(SPA_PLUGIN_PATH"/support/libspa-support.so", RTLD_NOW); void *hnd = dlopen(SPA_PLUGIN_PATH"/support/libspa-support.so", RTLD_NOW);
``` \endcode
The environment variable `SPA_PLUGIN_PATH` is usually used to find the The environment variable `SPA_PLUGIN_PATH` is usually used to find the
location of the plugins. You will have to do some more work to construct the location of the plugins. You will have to do some more work to construct the
@ -99,10 +99,10 @@ The plugin has (should have) exactly one public symbol, called
`SPA_HANDLE_FACTORY_ENUM_FUNC_NAME` to get some compile time checks and avoid `SPA_HANDLE_FACTORY_ENUM_FUNC_NAME` to get some compile time checks and avoid
typos in the symbol name. We can get the symbol like so: typos in the symbol name. We can get the symbol like so:
```c \code{.c}
spa_handle_factory_enum_func_t enum_func; spa_handle_factory_enum_func_t enum_func;
enum_func = dlsym(hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)); enum_func = dlsym(hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME));
``` \endcode
If this symbol is not available, this is not a valid SPA plugin. If this symbol is not available, this is not a valid SPA plugin.
@ -110,16 +110,16 @@ If this symbol is not available, this is not a valid SPA plugin.
With the `enum_func` we can now enumerate all the factories in the plugin: With the `enum_func` we can now enumerate all the factories in the plugin:
```c \code{.c}
uint32_t i; uint32_t i;
const struct spa_handle_factory *factory = NULL; const struct spa_handle_factory *factory = NULL;
for (i = 0;;) { for (i = 0;;) {
if (enum_func(&factory, &i) <= 0) if (enum_func(&factory, &i) <= 0)
break; break;
/* check name and version, introspect interfaces, // check name and version, introspect interfaces,
* do something with the factory. */ // do something with the factory.
} }
``` \endcode
A factory has a version, a name, some properties and a couple of functions A factory has a version, a name, some properties and a couple of functions
that we can check and use. The main use of a factory is to create an that we can check and use. The main use of a factory is to create an
@ -134,11 +134,11 @@ The name of the factory is a well-known name that describes the functionality
of the objects created from the factory. `<spa/utils/names.h>` contains of the objects created from the factory. `<spa/utils/names.h>` contains
definitions for common functionality, for example: definitions for common functionality, for example:
```c \code{.c}
#define SPA_NAME_SUPPORT_CPU "support.cpu" /**< A CPU interface */ #define SPA_NAME_SUPPORT_CPU "support.cpu" // A CPU interface
#define SPA_NAME_SUPPORT_LOG "support.log" /**< A Log interface */ #define SPA_NAME_SUPPORT_LOG "support.log" // A Log interface
#define SPA_NAME_SUPPORT_DBUS "support.dbus" /**< A DBUS interface */ #define SPA_NAME_SUPPORT_DBUS "support.dbus" // A DBUS interface
``` \endcode
Usually the name will be mapped to a specific plugin. This way an Usually the name will be mapped to a specific plugin. This way an
alternative compatible implementation can be made in a different library. alternative compatible implementation can be made in a different library.
@ -151,21 +151,23 @@ the application and the stack for storage.
First get the size of the required memory: First get the size of the required memory:
```c \code{.c}
size_t size = spa_handle_factory_get_size(factory, NULL /* extra params */); struct spa_dict *extra_params = NULL;
``` size_t size = spa_handle_factory_get_size(factory, extra_params);
\endcode
Sometimes the memory can depend on the extra parameters given in Sometimes the memory can depend on the extra parameters given in
`_get_size()`. Next we need to allocate the memory and initialize the object `_get_size()`. Next we need to allocate the memory and initialize the object
in it: in it:
```c \code{.c}
handle = calloc(1, size); handle = calloc(1, size);
spa_handle_factory_init(factory, handle, spa_handle_factory_init(factory, handle,
NULL, /* info */ NULL, // info
NULL, /* support */ NULL, // support
0 /* n_support */); 0 // n_support
``` );
\endcode
The info parameter should contain the same extra properties given in The info parameter should contain the same extra properties given in
`spa_handle_factory_get_size()`. `spa_handle_factory_get_size()`.
@ -180,18 +182,18 @@ certain support libraries to function.
When a SPA handle is made, you can retrieve any of the interfaces that When a SPA handle is made, you can retrieve any of the interfaces that
it provides: it provides:
```c \code{.c}
void *iface; void *iface;
spa_handle_get_interface(handle, SPA_NAME_SUPPORT_LOG, &iface); spa_handle_get_interface(handle, SPA_NAME_SUPPORT_LOG, &iface);
``` \endcode
If this method succeeds, you can cast the `iface` variable to If this method succeeds, you can cast the `iface` variable to
`struct spa_log *` and start using the log interface methods. `struct spa_log *` and start using the log interface methods.
```c \code{.c}
struct spa_log *log = iface; struct spa_log *log = iface;
spa_log_warn(log, "Hello World!\n"); spa_log_warn(log, "Hello World!\n");
``` \endcode
## Clearing an object ## Clearing an object
@ -230,7 +232,7 @@ listeners about this.
For example, the `struct spa_node` interface has a method to register such For example, the `struct spa_node` interface has a method to register such
an event handler like this: an event handler like this:
```c \code{.c}
static void node_info(void *data, const struct spa_node_info *info) static void node_info(void *data, const struct spa_node_info *info)
{ {
printf("got node info!\n"); printf("got node info!\n");
@ -244,7 +246,7 @@ static struct spa_node_events node_events = {
struct spa_hook listener; struct spa_hook listener;
spa_zero(listener); spa_zero(listener);
spa_node_add_listener(node, &listener, &node_event, my_data); spa_node_add_listener(node, &listener, &node_event, my_data);
``` \endcode
You make a structure with pointers to the events you are interested in You make a structure with pointers to the events you are interested in
and then use `spa_node_add_listener()` to register a listener. The and then use `spa_node_add_listener()` to register a listener. The
@ -263,9 +265,9 @@ will be checked and the new signal will be ignored for older versions.
You can remove your listener with: You can remove your listener with:
```c \code{.c}
spa_hook_remove(&listener); spa_hook_remove(&listener);
``` \endcode
## API results ## API results
@ -284,7 +286,7 @@ Here is an example of enumerating parameters on a node interface.
First install a listener for the result: First install a listener for the result:
```c \code{.c}
static void node_result(void *data, int seq, int res, static void node_result(void *data, int seq, int res,
uint32_t type, const void *result) uint32_t type, const void *result)
{ {
@ -301,20 +303,20 @@ static const struct spa_node_events node_events = {
}; };
spa_node_add_listener(node, &listener, &node_events, node); spa_node_add_listener(node, &listener, &node_events, node);
``` \endcode
Then perform the `enum_param` method: Then perform the `enum_param` method:
```c \code{.c}
int res = spa_node_enum_params(node, 0, SPA_PARAM_EnumFormat, 0, MAXINT, NULL); int res = spa_node_enum_params(node, 0, SPA_PARAM_EnumFormat, 0, MAXINT, NULL);
``` \endcode
This triggers the result event handler with a 0 sequence number for each This triggers the result event handler with a 0 sequence number for each
supported format. After this completes, remove the listener again: supported format. After this completes, remove the listener again:
```c \code{.c}
spa_hook_remove(&listener); spa_hook_remove(&listener);
``` \endcode
### Asynchronous results ### Asynchronous results
@ -323,20 +325,24 @@ Asynchronous results are pushed to the application in the same way as
synchronous results, they are just pushed later. You can check that synchronous results, they are just pushed later. You can check that
a result is asynchronous by the return value of the enum function: a result is asynchronous by the return value of the enum function:
```c \code{.c}
int res = spa_node_enum_params(node, 0, SPA_PARAM_EnumFormat, 0, MAXINT, NULL); int res = spa_node_enum_params(node, 0, SPA_PARAM_EnumFormat, 0, MAXINT, NULL);
if (SPA_RESULT_IS_ASYNC(res)) { if (SPA_RESULT_IS_ASYNC(res)) {
/* result will be received later */ // result will be received later
... ...
} }
``` \endcode
In the case of async results, the result callback will be called with the In the case of async results, the result callback will be called with the
sequence number of the async result code, which can be obtained with: sequence number of the async result code, which can be obtained with:
```c \code{.c}
expected_seq = SPA_RESULT_ASYNC_SEQ(res); expected_seq = SPA_RESULT_ASYNC_SEQ(res);
``` \endcode
# Implementing a new plugin # Implementing a new plugin
FIXME
*/

View file

@ -1,9 +1,11 @@
# SPA (Simple Plugin API) /** \page page_spa SPA (Simple Plugin API)
SPA (Simple Plugin API) is an extensible API to implement all kinds of SPA (Simple Plugin API) is an extensible API to implement all kinds of
plugins. It is inspired by many other plugin APIs, mostly LV2 and plugins. It is inspired by many other plugin APIs, mostly LV2 and
GStreamer. GStreamer.
* SPA [Design](spa-design.md) - \subpage page_spa_design
* [Data format](spa-pod.md) - \subpage page_spa_pod
* SPA [Buffers](spa-buffer.md) - \subpage page_spa_buffer
*/

View file

@ -1,4 +1,4 @@
# SPA POD /** \page page_spa_pod SPA POD
POD (plain old data) is a sort of data container. It is comparable to POD (plain old data) is a sort of data container. It is comparable to
DBus Variant or LV2 Atom. DBus Variant or LV2 Atom.
@ -23,30 +23,30 @@ the SPA types for more info.
PODs can contain a number of basic SPA types: PODs can contain a number of basic SPA types:
* `SPA_TYPE_None`: no value or a NULL pointer. - `SPA_TYPE_None`: no value or a NULL pointer.
* `SPA_TYPE_Bool`: a boolean value - `SPA_TYPE_Bool`: a boolean value
* `SPA_TYPE_Id`: an enumerated value - `SPA_TYPE_Id`: an enumerated value
* `SPA_TYPE_Int`, `SPA_TYPE_Long`, `SPA_TYPE_Float`, `SPA_TYPE_Double`: - `SPA_TYPE_Int`, `SPA_TYPE_Long`, `SPA_TYPE_Float`, `SPA_TYPE_Double`:
various numeral types, 32 and 64 bits. - various numeral types, 32 and 64 bits.
* `SPA_TYPE_String`: a string - `SPA_TYPE_String`: a string
* `SPA_TYPE_Bytes`: a byte array - `SPA_TYPE_Bytes`: a byte array
* `SPA_TYPE_Rectangle`: a rectangle with width and height - `SPA_TYPE_Rectangle`: a rectangle with width and height
* `SPA_TYPE_Fraction`: a fraction with numerator and denominator - `SPA_TYPE_Fraction`: a fraction with numerator and denominator
* `SPA_TYPE_Bitmap`: an array of bits - `SPA_TYPE_Bitmap`: an array of bits
PODs can be grouped together in these container types: PODs can be grouped together in these container types:
* `SPA_TYPE_Array`: an array of equal sized objects - `SPA_TYPE_Array`: an array of equal sized objects
* `SPA_TYPE_Struct`: a collection of types and objects - `SPA_TYPE_Struct`: a collection of types and objects
* `SPA_TYPE_Object`: an object with properties - `SPA_TYPE_Object`: an object with properties
* `SPA_TYPE_Sequence`: a timed sequence of PODs - `SPA_TYPE_Sequence`: a timed sequence of PODs
PODs can also contain some extra types: PODs can also contain some extra types:
* `SPA_TYPE_Pointer`: a typed pointer in memory - `SPA_TYPE_Pointer`: a typed pointer in memory
* `SPA_TYPE_Fd`: a file descriptor - `SPA_TYPE_Fd`: a file descriptor
* `SPA_TYPE_Choice`: a choice of values - `SPA_TYPE_Choice`: a choice of values
* `SPA_TYPE_Pod`: a generic type for the POD itself - `SPA_TYPE_Pod`: a generic type for the POD itself
# Constructing a POD # Constructing a POD
@ -62,36 +62,36 @@ appropriate error will be generated.
The code fragment below initializes a pod builder to write into The code fragment below initializes a pod builder to write into
the stack allocated buffer. the stack allocated buffer.
```c \code{.c}
uint8_t buffer[4096]; uint8_t buffer[4096];
struct spa_pod_builder b; struct spa_pod_builder b;
spa_pod_builder_init(&b, buffer, sizeof(buffer)); spa_pod_builder_init(&b, buffer, sizeof(buffer));
``` \endcode
Next we need to write some object into the builder. Let's write Next we need to write some object into the builder. Let's write
a simple struct with an Int and Float in it. Structs are comparable a simple struct with an Int and Float in it. Structs are comparable
to JSON arrays. to JSON arrays.
```c \code{.c}
struct spa_pod_frame f; struct spa_pod_frame f;
spa_pod_builder_push_struct(&b, &f); spa_pod_builder_push_struct(&b, &f);
``` \endcode
First we open the struct container, the `struct spa_pod_frame` keeps First we open the struct container, the `struct spa_pod_frame` keeps
track of the container context. Next we add some values to track of the container context. Next we add some values to
the container like this: the container like this:
```c \code{.c}
spa_pod_builder_int(&b, 5); spa_pod_builder_int(&b, 5);
spa_pod_builder_float(&b, 3.1415f); spa_pod_builder_float(&b, 3.1415f);
``` \endcode
Then we close the container by popping the frame again: Then we close the container by popping the frame again:
```c \code{.c}
struct spa_pod *pod; struct spa_pod *pod;
pod = spa_pod_builder_pop(&b, &f); pod = spa_pod_builder_pop(&b, &f);
``` \endcode
`spa_pod_builder_pop()` returns a reference to the object we completed `spa_pod_builder_pop()` returns a reference to the object we completed
on the stack. on the stack.
@ -100,21 +100,21 @@ on the stack.
We can also use the following construct to make POD objects: We can also use the following construct to make POD objects:
```c \code{.c}
spa_pod_builder_push_struct(&b, &f); spa_pod_builder_push_struct(&b, &f);
spa_pod_builder_add(&b, spa_pod_builder_add(&b,
SPA_POD_Int(5), SPA_POD_Int(5),
SPA_POD_Float(3.1415f)); SPA_POD_Float(3.1415f));
pod = spa_pod_builder_pop(&b, &f); pod = spa_pod_builder_pop(&b, &f);
``` \endcode
Or even shorter: Or even shorter:
```c \code{.c}
pod = spa_pod_builder_add_struct(&b, pod = spa_pod_builder_add_struct(&b,
SPA_POD_Int(5), SPA_POD_Int(5),
SPA_POD_Float(3.1415f)); SPA_POD_Float(3.1415f));
``` \endcode
It's not possible to use the varargs builder to make a Sequence or It's not possible to use the varargs builder to make a Sequence or
Array, use the normal builder methods for that. Array, use the normal builder methods for that.
@ -126,9 +126,9 @@ objects.
Start by pushing an object: Start by pushing an object:
```c \code{.c}
spa_pod_builder_push_object(&b, &f, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props); spa_pod_builder_push_object(&b, &f, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props);
``` \endcode
An object requires an object type (`SPA_TYPE_OBJECT_Props`) and a context An object requires an object type (`SPA_TYPE_OBJECT_Props`) and a context
id (`SPA_PARAM_Props`). The object type defines the properties that can be id (`SPA_PARAM_Props`). The object type defines the properties that can be
@ -137,12 +137,12 @@ make this connection (See the type system).
Next we can push some properties in the object: Next we can push some properties in the object:
```c \code{.c}
spa_pod_builder_prop(&b, SPA_PROP_device, 0); spa_pod_builder_prop(&b, SPA_PROP_device, 0);
spa_pod_builder_string(&b, "hw:0"); spa_pod_builder_string(&b, "hw:0");
spa_pod_builder_prop(&b, SPA_PROP_frequency, 0); spa_pod_builder_prop(&b, SPA_PROP_frequency, 0);
spa_pod_builder_float(&b, 440.0); spa_pod_builder_float(&b, 440.0);
``` \endcode
As can be seen, we always need to push a prop (with key and flags) As can be seen, we always need to push a prop (with key and flags)
and then the associated value. For performance reasons it is a good and then the associated value. For performance reasons it is a good
@ -150,18 +150,18 @@ idea to always push (and parse) the object keys in ascending order.
Don't forget to pop the result when the object is finished: Don't forget to pop the result when the object is finished:
```c \code{.c}
pod = spa_pod_builder_pop(&b, &f); pod = spa_pod_builder_pop(&b, &f);
``` \endcode
There is a shortcut for making objects: There is a shortcut for making objects:
```c \code{.c}
pod = spa_pod_builder_add_object(&b, pod = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Props, SPA_PARAM_Props, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props,
SPA_PROP_device, SPA_POD_String("hw:0"), SPA_PROP_device, SPA_POD_String("hw:0"),
SPA_PROP_frequency, SPA_POD_Float(440.0f)); SPA_PROP_frequency, SPA_POD_Float(440.0f));
``` \endcode
## Choice values ## Choice values
@ -182,54 +182,54 @@ interpreted in different ways:
Let's illustrate this with a Props object that specifies a range of Let's illustrate this with a Props object that specifies a range of
possible values for the frequency: possible values for the frequency:
```c \code{.c}
struct spa_pod_frame f2; struct spa_pod_frame f2;
spa_pod_builder_push_object(&b, &f, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props); spa_pod_builder_push_object(&b, &f, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props);
spa_pod_builder_prop(&b, SPA_PROP_frequency, 0); spa_pod_builder_prop(&b, SPA_PROP_frequency, 0);
spa_pod_builder_push_choice(&b, &f2, SPA_CHOICE_Range, 0); spa_pod_builder_push_choice(&b, &f2, SPA_CHOICE_Range, 0);
spa_pod_builder_float(&b, 440.0); /* default */ spa_pod_builder_float(&b, 440.0); // default
spa_pod_builder_float(&b, 110.0); /* min */ spa_pod_builder_float(&b, 110.0); // min
spa_pod_builder_float(&b, 880.0); /* min */ spa_pod_builder_float(&b, 880.0); // min
pod = spa_pod_builder_pop(&b, &f2); pod = spa_pod_builder_pop(&b, &f2);
pod = spa_pod_builder_pop(&b, &f); pod = spa_pod_builder_pop(&b, &f);
``` \endcode
As you can see, first push the choice as a Range, then the values. A Range As you can see, first push the choice as a Range, then the values. A Range
choice expects at least 3 values, the default value, minimum and maximum choice expects at least 3 values, the default value, minimum and maximum
values. There is a shortcut for this as well using varargs: values. There is a shortcut for this as well using varargs:
```c \code{.c}
pod = spa_pod_builder_add_object(&b, pod = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Props, SPA_PARAM_Props, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props,
SPA_PROP_frequency, SPA_POD_CHOICE_RANGE_Float(440.0f, 110.0f, 880.0f)); SPA_PROP_frequency, SPA_POD_CHOICE_RANGE_Float(440.0f, 110.0f, 880.0f));
``` \endcode
## Choice examples ## Choice examples
This is a description of a possible `SPA_TYPE_OBJECT_Format` as used when This is a description of a possible `SPA_TYPE_OBJECT_Format` as used when
enumerating allowed formats (`SPA_PARAM_EnumFormat`) in SPA objects: enumerating allowed formats (`SPA_PARAM_EnumFormat`) in SPA objects:
```c \code{.c}
pod = spa_pod_builder_add_object(&b, pod = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
/* specify the media type and subtype */ // specify the media type and subtype
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
/* audio/raw properties */ // audio/raw properties
SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id( SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(
SPA_AUDIO_FORMAT_S16, /* default */ SPA_AUDIO_FORMAT_S16, // default
SPA_AUDIO_FORMAT_S16, /* alternative1 */ SPA_AUDIO_FORMAT_S16, // alternative1
SPA_AUDIO_FORMAT_S32, /* alternative2 */ SPA_AUDIO_FORMAT_S32, // alternative2
SPA_AUDIO_FORMAT_f32 /* alternative3 */ SPA_AUDIO_FORMAT_f32 // alternative3
), ),
SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_RANGE_Int( SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_RANGE_Int(
44100, /* default */ 44100, // default
8000, /* min */ 8000, // min
192000 /* max */ 192000 // max
), ),
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(2)); SPA_FORMAT_AUDIO_channels, SPA_POD_Int(2));
``` \endcode
## Fixate ## Fixate
@ -241,17 +241,17 @@ only available value in the choice.
Running fixate on our previous example would result in an object equivalent Running fixate on our previous example would result in an object equivalent
to: to:
```c \code{.c}
pod = spa_pod_builder_add_object(&b, pod = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
/* specify the media type and subtype */ // specify the media type and subtype
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
/* audio/raw properties */ // audio/raw properties
SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_S16), SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_S16),
SPA_FORMAT_AUDIO_rate, SPA_POD_Int(44100), SPA_FORMAT_AUDIO_rate, SPA_POD_Int(44100),
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(2)); SPA_FORMAT_AUDIO_channels, SPA_POD_Int(2));
``` \endcode
# Parsing a POD # Parsing a POD
@ -268,10 +268,10 @@ Use `spa_pod_from_data()` to check if maxsize of bytes in data contain
a POD at the size bytes starting at offset. This function checks that a POD at the size bytes starting at offset. This function checks that
the POD size will fit and not overflow. the POD size will fit and not overflow.
```c \code{.c}
struct spa_pod *pod; struct spa_pod *pod;
pod = spa_pod_from_data(data, maxsize, offset, size); pod = spa_pod_from_data(data, maxsize, offset, size);
``` \endcode
## Checking the type of POD ## Checking the type of POD
@ -287,12 +287,12 @@ an object of the expected type.
To iterate over the fields of a Struct use: To iterate over the fields of a Struct use:
```c \code{.c}
struct spa_pod *pod, *obj; struct spa_pod *pod, *obj;
SPA_POD_STRUCT_FOREACH(obj, pod) { SPA_POD_STRUCT_FOREACH(obj, pod) {
printf("field type:%d\n", pod->type); printf("field type:%d\n", pod->type);
} }
``` \endcode
For parsing Structs it is usually much easier to use the parser For parsing Structs it is usually much easier to use the parser
below. below.
@ -301,25 +301,25 @@ below.
To iterate over the properties in an object you can do: To iterate over the properties in an object you can do:
```c \code{.c}
struct spa_pod_prop *prop; struct spa_pod_prop *prop;
struct spa_pod_object *obj = (struct spa_pod_object*)pod; struct spa_pod_object *obj = (struct spa_pod_object*)pod;
SPA_POD_OBJECT_FOREACH(pod, prop) { SPA_POD_OBJECT_FOREACH(pod, prop) {
printf("prop key:%d\n", prop->key); printf("prop key:%d\n", prop->key);
} }
``` \endcode
There is a function to retrieve the property for a certain key There is a function to retrieve the property for a certain key
in the object. If the properties of the object are in ascending in the object. If the properties of the object are in ascending
order, you can start searching from the previous key. order, you can start searching from the previous key.
```c \code{.c}
struct spa_pod_prop *prop; struct spa_pod_prop *prop;
prop = spa_pod_find_prop(obj, NULL, SPA_FORMAT_AUDIO_format); prop = spa_pod_find_prop(obj, NULL, SPA_FORMAT_AUDIO_format);
/* .. use first prop */ // .. use first prop
prop = spa_pod_find_prop(obj, prop, SPA_FORMAT_AUDIO_rate); prop = spa_pod_find_prop(obj, prop, SPA_FORMAT_AUDIO_rate);
/* .. use next prop */ // .. use next prop
``` \endcode
## Parser ## Parser
@ -331,18 +331,18 @@ the parser is easier.
First initialize a `struct spa_pod_parser`: First initialize a `struct spa_pod_parser`:
```c \code{.c}
struct spa_pod_parser p; struct spa_pod_parser p;
spa_pod_parser_pod(&p, obj); spa_pod_parser_pod(&p, obj);
``` \endcode
You can then enter containers such as objects or structs with a push You can then enter containers such as objects or structs with a push
operation: operation:
```c \code{.c}
struct spa_pod_frame f; struct spa_pod_frame f;
spa_pod_parser_push_struct(&p, &f); spa_pod_parser_push_struct(&p, &f);
``` \endcode
You need to store the context in a `struct spa_pod_frame` to be able You need to store the context in a `struct spa_pod_frame` to be able
to exit the container again later. to exit the container again later.
@ -350,18 +350,18 @@ to exit the container again later.
You can then parse each field. The parser takes care of moving to the You can then parse each field. The parser takes care of moving to the
next field. next field.
```c \code{.c}
uint32_t id, val; uint32_t id, val;
spa_pod_parser_get_id(&p, &id); spa_pod_parser_get_id(&p, &id);
spa_pod_parser_get_int(&p, &val); spa_pod_parser_get_int(&p, &val);
... ...
``` \endcode
And finally exit the container again: And finally exit the container again:
```c \code{.c}
spa_pod_parser_pop(&p, &f); spa_pod_parser_pop(&p, &f);
``` \endcode
## Parser with variable arguments ## Parser with variable arguments
@ -371,15 +371,15 @@ functions.
To parse a struct: To parse a struct:
```c \code{.c}
spa_pod_parser_get_struct(&p, spa_pod_parser_get_struct(&p,
SPA_POD_Id(&id), SPA_POD_Id(&id),
SPA_POD_Int(&val)); SPA_POD_Int(&val));
``` \endcode
To parse properties in an object: To parse properties in an object:
```c \code{.c}
uint32_t type, subtype, format, rate, channels; uint32_t type, subtype, format, rate, channels;
spa_pod_parser_get_object(&p, spa_pod_parser_get_object(&p,
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
@ -388,7 +388,7 @@ spa_pod_parser_get_object(&p,
SPA_FORMAT_AUDIO_format, SPA_POD_Id(&format), SPA_FORMAT_AUDIO_format, SPA_POD_Id(&format),
SPA_FORMAT_AUDIO_rate, SPA_POD_Int(&rate), SPA_FORMAT_AUDIO_rate, SPA_POD_Int(&rate),
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(&channels)); SPA_FORMAT_AUDIO_channels, SPA_POD_Int(&channels));
``` \endcode
When parsing objects it is possible to have optional fields. You can When parsing objects it is possible to have optional fields. You can
make a field optional be parsing it with the `SPA_POD_OPT_` prefix make a field optional be parsing it with the `SPA_POD_OPT_` prefix
@ -397,7 +397,7 @@ for the type.
In the next example, the rate and channels fields are optional In the next example, the rate and channels fields are optional
and when they are not present, the variables will not be changed. and when they are not present, the variables will not be changed.
```c \code{.c}
uint32_t type, subtype, format, rate = 0, channels = 0; uint32_t type, subtype, format, rate = 0, channels = 0;
spa_pod_parser_get_object(&p, spa_pod_parser_get_object(&p,
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
@ -406,7 +406,7 @@ spa_pod_parser_get_object(&p,
SPA_FORMAT_AUDIO_format, SPA_POD_Id(&format), SPA_FORMAT_AUDIO_format, SPA_POD_Id(&format),
SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&rate), SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&rate),
SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&channels)); SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&channels));
``` \endcode
It is not possible to parse a Sequence or Array with the parser. It is not possible to parse a Sequence or Array with the parser.
Use the iterator for this. Use the iterator for this.
@ -421,7 +421,7 @@ manually, if needed.
Here is an example of parsing the format values as a POD: Here is an example of parsing the format values as a POD:
```c \code{.c}
uint32_t type, subtype; uint32_t type, subtype;
struct spa_pod *format; struct spa_pod *format;
spa_pod_parser_get_object(&p, spa_pod_parser_get_object(&p,
@ -429,7 +429,7 @@ spa_pod_parser_get_object(&p,
SPA_FORMAT_mediaType, SPA_POD_Id(&type), SPA_FORMAT_mediaType, SPA_POD_Id(&type),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(&subtype), SPA_FORMAT_mediaSubtype, SPA_POD_Id(&subtype),
SPA_FORMAT_AUDIO_format, SPA_POD_Pod(&format)); SPA_FORMAT_AUDIO_format, SPA_POD_Pod(&format));
``` \endcode
`spa_pod_get_values()` is a useful function. It returns a `spa_pod_get_values()` is a useful function. It returns a
`struct spa_pod*` with and array of values. For normal PODs `struct spa_pod*` with and array of values. For normal PODs
@ -437,7 +437,7 @@ and Choice None values, it simply returns the POD and 1 value.
For other Choice values it returns the Choice type and an array For other Choice values it returns the Choice type and an array
of values: of values:
```c \code{.c}
struct spa_pod *value; struct spa_pod *value;
uint32_t n_vals, choice; uint32_t n_vals, choice;
@ -445,11 +445,11 @@ value = spa_pod_get_values(pod, &n_vals, &choice);
switch (choice) { switch (choice) {
case SPA_CHOICE_None: case SPA_CHOICE_None:
/* one single value */ // one single value
break; break;
case SPA_CHOICE_Range: case SPA_CHOICE_Range:
/* array of values of type of pod, cast to right type // array of values of type of pod, cast to right type
* to iterate. */ // to iterate.
uint32_t *v = SPA_POD_BODY(values); uint32_t *v = SPA_POD_BODY(values);
if (n_vals < 3) if (n_vals < 3)
break; break;
@ -458,11 +458,11 @@ case SPA_CHOICE_Range:
printf("max value: %u\n", v[2]); printf("max value: %u\n", v[2]);
break; break;
/* ... */ // ...
default: default:
break; break;
} }
``` \endcode
# Filter # Filter
@ -474,16 +474,16 @@ This is, for example, used to find a compatible format between two ports.
As an example we can run a filter on two simple PODs: As an example we can run a filter on two simple PODs:
```c \code{.c}
pod = spa_pod_builder_add_object(&b, pod = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id( SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(
SPA_AUDIO_FORMAT_S16, /* default */ SPA_AUDIO_FORMAT_S16, // default
SPA_AUDIO_FORMAT_S16, /* alternative1 */ SPA_AUDIO_FORMAT_S16, // alternative1
SPA_AUDIO_FORMAT_S32, /* alternative2 */ SPA_AUDIO_FORMAT_S32, // alternative2
SPA_AUDIO_FORMAT_f32 /* alternative3 */ SPA_AUDIO_FORMAT_f32 // alternative3
)); ));
filter = spa_pod_builder_add_object(&b, filter = spa_pod_builder_add_object(&b,
@ -491,25 +491,25 @@ filter = spa_pod_builder_add_object(&b,
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id( SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(
SPA_AUDIO_FORMAT_S16, /* default */ SPA_AUDIO_FORMAT_S16, // default
SPA_AUDIO_FORMAT_S16, /* alternative1 */ SPA_AUDIO_FORMAT_S16, // alternative1
SPA_AUDIO_FORMAT_f64 /* alternative2 */ SPA_AUDIO_FORMAT_f64 // alternative2
)); ));
struct spa_pod *result; struct spa_pod *result;
if (spa_pod_filter(&b, &result, pod, filter) < 0) if (spa_pod_filter(&b, &result, pod, filter) < 0)
goto exit_error; goto exit_error;
``` \endcode
Filter will contain a POD equivalent to: Filter will contain a POD equivalent to:
```c \code{.c}
result = spa_pod_builder_add_object(&b, result = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
SPA_FORMAT_AUDIO_format, SPA_AUDIO_FORMAT_S16); SPA_FORMAT_AUDIO_format, SPA_AUDIO_FORMAT_S16);
``` \endcode
# POD layout # POD layout
@ -519,3 +519,4 @@ field specifies the size following the type field.
Each POD is aligned to an 8 byte boundary. Each POD is aligned to an 8 byte boundary.
*/

View file

@ -206,7 +206,7 @@ which means that it enumerates the possible formats for this stream. We have
only one, a Signed 16 bit stereo format at 44.1KHz. only one, a Signed 16 bit stereo format at 44.1KHz.
We use `spa_format_audio_raw_build()` which is a helper function to make the param We use `spa_format_audio_raw_build()` which is a helper function to make the param
with the builder. See [SPA POD](spa-pod.md) for more information about how to with the builder. See \ref page_spa_pod for more information about how to
make these POD objects. make these POD objects.
Now we're ready to connect the stream and run the main loop: Now we're ready to connect the stream and run the main loop:
@ -289,7 +289,7 @@ static void on_process(void *userdata)
} }
\endcode \endcode
Check out the docs for [buffers](spa-buffer.md) for more information Check out the docs for \ref page_spa_buffer for more information
about how to work with buffers. about how to work with buffers.
Try to change the number of channels, samplerate or format; the stream Try to change the number of channels, samplerate or format; the stream

View file

@ -243,7 +243,7 @@ We have something similar for the framerate.
Note that there are other video parameters that we don't specify here. This Note that there are other video parameters that we don't specify here. This
means that we don't have any restrictions for their values. means that we don't have any restrictions for their values.
See [SPA POD](spa-pod.md) for more information about how to make these See \ref page_spa_pod for more information about how to make these
POD objects. POD objects.
Now we're ready to connect the stream and run the main loop: Now we're ready to connect the stream and run the main loop: