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',
'tutorial5.dox',
'tutorial6.dox',
'spa-index.md',
'spa-design.md',
'spa-pod.md',
'spa-buffer.md',
'spa-index.dox',
'spa-design.dox',
'spa-pod.dox',
'spa-buffer.dox',
'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`?
@ -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).
*/

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.
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:
* enumeration of object factories and the interfaces provided by the objects
* creation of objects (AKA a handle)
* retrieve interfaces to perform actions on the objects
- enumeration of object factories and the interfaces provided by the objects
- creation of objects (AKA a handle)
- retrieve interfaces to perform actions on the objects
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.
* Very efficient both in space and in time.
* Very configurable and usable in many different environments. All aspects of
- Very efficient both in space and in time.
- Very configurable and usable in many different environments. All aspects of
the plugin environment can be configured and changed, like logging, poll loops,
system calls etc.
* Consistent API
* Extensible, new API can be added with minimal effort, existing API can be
- Consistent API
- Extensible, new API can be added with minimal effort, existing API can be
updated and versioned.
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:
* String types: They identify interfaces and highlevel object types.
* integer types: These are enumerations used in the parts where high
- String types: They identify interfaces and highlevel object types.
- integer types: These are enumerations used in the parts where high
performance/ease of use/low space overhead is needed.
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:
```c
\code{.c}
#define SPA_PLUGIN_PATH /usr/lib64/spa-0.2/"
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
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
typos in the symbol name. We can get the symbol like so:
```c
\code{.c}
spa_handle_factory_enum_func_t enum_func;
enum_func = dlsym(hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME));
```
\endcode
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:
```c
\code{.c}
uint32_t i;
const struct spa_handle_factory *factory = NULL;
for (i = 0;;) {
if (enum_func(&factory, &i) <= 0)
break;
/* check name and version, introspect interfaces,
* do something with the factory. */
// check name and version, introspect interfaces,
// do something with the factory.
}
```
\endcode
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
@ -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
definitions for common functionality, for example:
```c
#define SPA_NAME_SUPPORT_CPU "support.cpu" /**< A CPU interface */
#define SPA_NAME_SUPPORT_LOG "support.log" /**< A Log interface */
#define SPA_NAME_SUPPORT_DBUS "support.dbus" /**< A DBUS interface */
```
\code{.c}
#define SPA_NAME_SUPPORT_CPU "support.cpu" // A CPU interface
#define SPA_NAME_SUPPORT_LOG "support.log" // A Log 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
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:
```c
size_t size = spa_handle_factory_get_size(factory, NULL /* extra params */);
```
\code{.c}
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
`_get_size()`. Next we need to allocate the memory and initialize the object
in it:
```c
\code{.c}
handle = calloc(1, size);
spa_handle_factory_init(factory, handle,
NULL, /* info */
NULL, /* support */
0 /* n_support */);
```
NULL, // info
NULL, // support
0 // n_support
);
\endcode
The info parameter should contain the same extra properties given in
`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
it provides:
```c
\code{.c}
void *iface;
spa_handle_get_interface(handle, SPA_NAME_SUPPORT_LOG, &iface);
```
\endcode
If this method succeeds, you can cast the `iface` variable to
`struct spa_log *` and start using the log interface methods.
```c
\code{.c}
struct spa_log *log = iface;
spa_log_warn(log, "Hello World!\n");
```
\endcode
## Clearing an object
@ -230,7 +232,7 @@ listeners about this.
For example, the `struct spa_node` interface has a method to register such
an event handler like this:
```c
\code{.c}
static void node_info(void *data, const struct spa_node_info *info)
{
printf("got node info!\n");
@ -244,7 +246,7 @@ static struct spa_node_events node_events = {
struct spa_hook listener;
spa_zero(listener);
spa_node_add_listener(node, &listener, &node_event, my_data);
```
\endcode
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
@ -263,9 +265,9 @@ will be checked and the new signal will be ignored for older versions.
You can remove your listener with:
```c
\code{.c}
spa_hook_remove(&listener);
```
\endcode
## API results
@ -284,7 +286,7 @@ Here is an example of enumerating parameters on a node interface.
First install a listener for the result:
```c
\code{.c}
static void node_result(void *data, int seq, int res,
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);
```
\endcode
Then perform the `enum_param` method:
```c
\code{.c}
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
supported format. After this completes, remove the listener again:
```c
\code{.c}
spa_hook_remove(&listener);
```
\endcode
### 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
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);
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
sequence number of the async result code, which can be obtained with:
```c
\code{.c}
expected_seq = SPA_RESULT_ASYNC_SEQ(res);
```
\endcode
# 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
plugins. It is inspired by many other plugin APIs, mostly LV2 and
GStreamer.
* SPA [Design](spa-design.md)
* [Data format](spa-pod.md)
* SPA [Buffers](spa-buffer.md)
- \subpage page_spa_design
- \subpage page_spa_pod
- \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
DBus Variant or LV2 Atom.
@ -23,30 +23,30 @@ the SPA types for more info.
PODs can contain a number of basic SPA types:
* `SPA_TYPE_None`: no value or a NULL pointer.
* `SPA_TYPE_Bool`: a boolean value
* `SPA_TYPE_Id`: an enumerated value
* `SPA_TYPE_Int`, `SPA_TYPE_Long`, `SPA_TYPE_Float`, `SPA_TYPE_Double`:
various numeral types, 32 and 64 bits.
* `SPA_TYPE_String`: a string
* `SPA_TYPE_Bytes`: a byte array
* `SPA_TYPE_Rectangle`: a rectangle with width and height
* `SPA_TYPE_Fraction`: a fraction with numerator and denominator
* `SPA_TYPE_Bitmap`: an array of bits
- `SPA_TYPE_None`: no value or a NULL pointer.
- `SPA_TYPE_Bool`: a boolean value
- `SPA_TYPE_Id`: an enumerated value
- `SPA_TYPE_Int`, `SPA_TYPE_Long`, `SPA_TYPE_Float`, `SPA_TYPE_Double`:
- various numeral types, 32 and 64 bits.
- `SPA_TYPE_String`: a string
- `SPA_TYPE_Bytes`: a byte array
- `SPA_TYPE_Rectangle`: a rectangle with width and height
- `SPA_TYPE_Fraction`: a fraction with numerator and denominator
- `SPA_TYPE_Bitmap`: an array of bits
PODs can be grouped together in these container types:
* `SPA_TYPE_Array`: an array of equal sized objects
* `SPA_TYPE_Struct`: a collection of types and objects
* `SPA_TYPE_Object`: an object with properties
* `SPA_TYPE_Sequence`: a timed sequence of PODs
- `SPA_TYPE_Array`: an array of equal sized objects
- `SPA_TYPE_Struct`: a collection of types and objects
- `SPA_TYPE_Object`: an object with properties
- `SPA_TYPE_Sequence`: a timed sequence of PODs
PODs can also contain some extra types:
* `SPA_TYPE_Pointer`: a typed pointer in memory
* `SPA_TYPE_Fd`: a file descriptor
* `SPA_TYPE_Choice`: a choice of values
* `SPA_TYPE_Pod`: a generic type for the POD itself
- `SPA_TYPE_Pointer`: a typed pointer in memory
- `SPA_TYPE_Fd`: a file descriptor
- `SPA_TYPE_Choice`: a choice of values
- `SPA_TYPE_Pod`: a generic type for the POD itself
# Constructing a POD
@ -62,36 +62,36 @@ appropriate error will be generated.
The code fragment below initializes a pod builder to write into
the stack allocated buffer.
```c
\code{.c}
uint8_t buffer[4096];
struct spa_pod_builder b;
spa_pod_builder_init(&b, buffer, sizeof(buffer));
```
\endcode
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
to JSON arrays.
```c
\code{.c}
struct spa_pod_frame f;
spa_pod_builder_push_struct(&b, &f);
```
\endcode
First we open the struct container, the `struct spa_pod_frame` keeps
track of the container context. Next we add some values to
the container like this:
```c
\code{.c}
spa_pod_builder_int(&b, 5);
spa_pod_builder_float(&b, 3.1415f);
```
\endcode
Then we close the container by popping the frame again:
```c
\code{.c}
struct spa_pod *pod;
pod = spa_pod_builder_pop(&b, &f);
```
\endcode
`spa_pod_builder_pop()` returns a reference to the object we completed
on the stack.
@ -100,21 +100,21 @@ on the stack.
We can also use the following construct to make POD objects:
```c
\code{.c}
spa_pod_builder_push_struct(&b, &f);
spa_pod_builder_add(&b,
SPA_POD_Int(5),
SPA_POD_Float(3.1415f));
pod = spa_pod_builder_pop(&b, &f);
```
\endcode
Or even shorter:
```c
\code{.c}
pod = spa_pod_builder_add_struct(&b,
SPA_POD_Int(5),
SPA_POD_Float(3.1415f));
```
\endcode
It's not possible to use the varargs builder to make a Sequence or
Array, use the normal builder methods for that.
@ -126,9 +126,9 @@ objects.
Start by pushing an object:
```c
\code{.c}
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
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:
```c
\code{.c}
spa_pod_builder_prop(&b, SPA_PROP_device, 0);
spa_pod_builder_string(&b, "hw:0");
spa_pod_builder_prop(&b, SPA_PROP_frequency, 0);
spa_pod_builder_float(&b, 440.0);
```
\endcode
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
@ -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:
```c
\code{.c}
pod = spa_pod_builder_pop(&b, &f);
```
\endcode
There is a shortcut for making objects:
```c
\code{.c}
pod = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Props, SPA_PARAM_Props,
SPA_PROP_device, SPA_POD_String("hw:0"),
SPA_PROP_frequency, SPA_POD_Float(440.0f));
```
\endcode
## Choice values
@ -182,54 +182,54 @@ interpreted in different ways:
Let's illustrate this with a Props object that specifies a range of
possible values for the frequency:
```c
\code{.c}
struct spa_pod_frame f2;
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_push_choice(&b, &f2, SPA_CHOICE_Range, 0);
spa_pod_builder_float(&b, 440.0); /* default */
spa_pod_builder_float(&b, 110.0); /* min */
spa_pod_builder_float(&b, 880.0); /* min */
spa_pod_builder_float(&b, 440.0); // default
spa_pod_builder_float(&b, 110.0); // min
spa_pod_builder_float(&b, 880.0); // min
pod = spa_pod_builder_pop(&b, &f2);
pod = spa_pod_builder_pop(&b, &f);
```
\endcode
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
values. There is a shortcut for this as well using varargs:
```c
\code{.c}
pod = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Props, SPA_PARAM_Props,
SPA_PROP_frequency, SPA_POD_CHOICE_RANGE_Float(440.0f, 110.0f, 880.0f));
```
\endcode
## Choice examples
This is a description of a possible `SPA_TYPE_OBJECT_Format` as used when
enumerating allowed formats (`SPA_PARAM_EnumFormat`) in SPA objects:
```c
\code{.c}
pod = spa_pod_builder_add_object(&b,
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_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
/* audio/raw properties */
// audio/raw properties
SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(
SPA_AUDIO_FORMAT_S16, /* default */
SPA_AUDIO_FORMAT_S16, /* alternative1 */
SPA_AUDIO_FORMAT_S32, /* alternative2 */
SPA_AUDIO_FORMAT_f32 /* alternative3 */
SPA_AUDIO_FORMAT_S16, // default
SPA_AUDIO_FORMAT_S16, // alternative1
SPA_AUDIO_FORMAT_S32, // alternative2
SPA_AUDIO_FORMAT_f32 // alternative3
),
SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_RANGE_Int(
44100, /* default */
8000, /* min */
192000 /* max */
44100, // default
8000, // min
192000 // max
),
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(2));
```
\endcode
## Fixate
@ -241,17 +241,17 @@ only available value in the choice.
Running fixate on our previous example would result in an object equivalent
to:
```c
\code{.c}
pod = spa_pod_builder_add_object(&b,
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_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_rate, SPA_POD_Int(44100),
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(2));
```
\endcode
# 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
the POD size will fit and not overflow.
```c
\code{.c}
struct spa_pod *pod;
pod = spa_pod_from_data(data, maxsize, offset, size);
```
\endcode
## Checking the type of POD
@ -287,12 +287,12 @@ an object of the expected type.
To iterate over the fields of a Struct use:
```c
\code{.c}
struct spa_pod *pod, *obj;
SPA_POD_STRUCT_FOREACH(obj, pod) {
printf("field type:%d\n", pod->type);
}
```
\endcode
For parsing Structs it is usually much easier to use the parser
below.
@ -301,25 +301,25 @@ below.
To iterate over the properties in an object you can do:
```c
\code{.c}
struct spa_pod_prop *prop;
struct spa_pod_object *obj = (struct spa_pod_object*)pod;
SPA_POD_OBJECT_FOREACH(pod, prop) {
printf("prop key:%d\n", prop->key);
}
```
\endcode
There is a function to retrieve the property for a certain key
in the object. If the properties of the object are in ascending
order, you can start searching from the previous key.
```c
\code{.c}
struct spa_pod_prop *prop;
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);
/* .. use next prop */
```
// .. use next prop
\endcode
## Parser
@ -331,18 +331,18 @@ the parser is easier.
First initialize a `struct spa_pod_parser`:
```c
\code{.c}
struct spa_pod_parser p;
spa_pod_parser_pod(&p, obj);
```
\endcode
You can then enter containers such as objects or structs with a push
operation:
```c
\code{.c}
struct spa_pod_frame f;
spa_pod_parser_push_struct(&p, &f);
```
\endcode
You need to store the context in a `struct spa_pod_frame` to be able
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
next field.
```c
\code{.c}
uint32_t id, val;
spa_pod_parser_get_id(&p, &id);
spa_pod_parser_get_int(&p, &val);
...
```
\endcode
And finally exit the container again:
```c
\code{.c}
spa_pod_parser_pop(&p, &f);
```
\endcode
## Parser with variable arguments
@ -371,15 +371,15 @@ functions.
To parse a struct:
```c
\code{.c}
spa_pod_parser_get_struct(&p,
SPA_POD_Id(&id),
SPA_POD_Int(&val));
```
\endcode
To parse properties in an object:
```c
\code{.c}
uint32_t type, subtype, format, rate, channels;
spa_pod_parser_get_object(&p,
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_rate, SPA_POD_Int(&rate),
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(&channels));
```
\endcode
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
@ -397,7 +397,7 @@ for the type.
In the next example, the rate and channels fields are optional
and when they are not present, the variables will not be changed.
```c
\code{.c}
uint32_t type, subtype, format, rate = 0, channels = 0;
spa_pod_parser_get_object(&p,
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_rate, SPA_POD_OPT_Int(&rate),
SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&channels));
```
\endcode
It is not possible to parse a Sequence or Array with the parser.
Use the iterator for this.
@ -421,7 +421,7 @@ manually, if needed.
Here is an example of parsing the format values as a POD:
```c
\code{.c}
uint32_t type, subtype;
struct spa_pod *format;
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_mediaSubtype, SPA_POD_Id(&subtype),
SPA_FORMAT_AUDIO_format, SPA_POD_Pod(&format));
```
\endcode
`spa_pod_get_values()` is a useful function. It returns a
`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
of values:
```c
\code{.c}
struct spa_pod *value;
uint32_t n_vals, choice;
@ -445,11 +445,11 @@ value = spa_pod_get_values(pod, &n_vals, &choice);
switch (choice) {
case SPA_CHOICE_None:
/* one single value */
// one single value
break;
case SPA_CHOICE_Range:
/* array of values of type of pod, cast to right type
* to iterate. */
// array of values of type of pod, cast to right type
// to iterate.
uint32_t *v = SPA_POD_BODY(values);
if (n_vals < 3)
break;
@ -458,11 +458,11 @@ case SPA_CHOICE_Range:
printf("max value: %u\n", v[2]);
break;
/* ... */
// ...
default:
break;
}
```
\endcode
# 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:
```c
\code{.c}
pod = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(
SPA_AUDIO_FORMAT_S16, /* default */
SPA_AUDIO_FORMAT_S16, /* alternative1 */
SPA_AUDIO_FORMAT_S32, /* alternative2 */
SPA_AUDIO_FORMAT_f32 /* alternative3 */
SPA_AUDIO_FORMAT_S16, // default
SPA_AUDIO_FORMAT_S16, // alternative1
SPA_AUDIO_FORMAT_S32, // alternative2
SPA_AUDIO_FORMAT_f32 // alternative3
));
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_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(
SPA_AUDIO_FORMAT_S16, /* default */
SPA_AUDIO_FORMAT_S16, /* alternative1 */
SPA_AUDIO_FORMAT_f64 /* alternative2 */
SPA_AUDIO_FORMAT_S16, // default
SPA_AUDIO_FORMAT_S16, // alternative1
SPA_AUDIO_FORMAT_f64 // alternative2
));
struct spa_pod *result;
if (spa_pod_filter(&b, &result, pod, filter) < 0)
goto exit_error;
```
\endcode
Filter will contain a POD equivalent to:
```c
\code{.c}
result = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
SPA_FORMAT_AUDIO_format, SPA_AUDIO_FORMAT_S16);
```
\endcode
# POD layout
@ -519,3 +519,4 @@ field specifies the size following the type field.
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.
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.
Now we're ready to connect the stream and run the main loop:
@ -289,7 +289,7 @@ static void on_process(void *userdata)
}
\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.
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
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.
Now we're ready to connect the stream and run the main loop: