mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-12-22 08:56:59 -05:00
doc: reorganize files
Separate various autogen files from the documentation .dox files. Rename .dox files to match the intended tree structure.
This commit is contained in:
parent
eca773fc12
commit
77fad4ee13
41 changed files with 60 additions and 59 deletions
90
doc/dox/api/index.dox
Normal file
90
doc/dox/api/index.dox
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/** \page page_api PipeWire API
|
||||
|
||||
The PipeWire API consists of several parts:
|
||||
|
||||
- The \ref pw_stream for a convenient way to send and receive data streams from/to PipeWire.
|
||||
|
||||
- The \ref pw_filter for a convenient way to implement processing filters.
|
||||
|
||||
- The \ref api_pw_core to access a PipeWire instance. This API is used
|
||||
by all clients that need to communicate with the \ref page_daemon and provides
|
||||
the necessary structs to interface with the daemon.
|
||||
|
||||
- The \ref api_pw_impl is primarily used by the \ref page_daemon itself but also by the
|
||||
\ref page_session_manager and modules/extensions that need to build objects in
|
||||
the graph.
|
||||
|
||||
- The \ref api_pw_util containing various utility functions and structures.
|
||||
|
||||
- The \ref api_pw_ext for interfacing with certain extension modules.
|
||||
|
||||
The APIs work through proxy objects, so that calling a method on an object
|
||||
invokes that same method on the remote side. Marshalling and de-marshalling is
|
||||
handled transparently by the \ref page_module_protocol_native.
|
||||
The below graph illustrates this approach:
|
||||
|
||||
\dot
|
||||
digraph API {
|
||||
compound=true;
|
||||
node [shape="box"];
|
||||
rankdir="RL";
|
||||
|
||||
subgraph cluster_daemon {
|
||||
rankdir="TB";
|
||||
label="PipeWire daemon";
|
||||
style="dashed";
|
||||
|
||||
impl_core [label="Core Impl. Object"];
|
||||
impl_device [label="Device Impl. Object"];
|
||||
impl_node [label="Node Impl. Object"];
|
||||
}
|
||||
|
||||
subgraph cluster_client {
|
||||
rankdir="TB";
|
||||
label="PipeWire client";
|
||||
style="dashed";
|
||||
|
||||
obj_core [label="Core Object"];
|
||||
obj_device [label="Device Object"];
|
||||
obj_node [label="Node Object"];
|
||||
}
|
||||
|
||||
obj_core -> impl_core;
|
||||
obj_device -> impl_device;
|
||||
obj_node -> impl_node;
|
||||
|
||||
}
|
||||
\enddot
|
||||
|
||||
It is common for clients to use both the \ref api_pw_core and the \ref api_pw_impl
|
||||
and both APIs are provided by the same library.
|
||||
|
||||
- \subpage page_spa
|
||||
- \subpage page_client_impl
|
||||
- \subpage page_proxy
|
||||
- \subpage page_streams
|
||||
- \subpage page_thread_loop
|
||||
|
||||
|
||||
\addtogroup api_pw_core Core API
|
||||
|
||||
The Core API to access a PipeWire instance. This API is used by all
|
||||
clients to communicate with the \ref page_daemon.
|
||||
|
||||
If you are familiar with Wayland implementation, the Core API is
|
||||
roughly equivalent to libwayland-client.
|
||||
|
||||
See: \ref page_api
|
||||
|
||||
|
||||
\addtogroup api_pw_impl Implementation API
|
||||
|
||||
The implementation API provides the tools to build new objects and
|
||||
modules.
|
||||
|
||||
If you are familiar with Wayland implementation, the Implementation API is
|
||||
roughly equivalent to libwayland-server.
|
||||
|
||||
See: \ref page_api
|
||||
|
||||
*/
|
||||
71
doc/dox/api/spa-buffer.dox
Normal file
71
doc/dox/api/spa-buffer.dox
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/** \page page_spa_buffer SPA Buffers
|
||||
|
||||
> What is the array of `spa_data` in `spa_buffer`?
|
||||
|
||||
A \ref spa_buffer "SPA Buffer" contains metadata and data. There can be many metadata items (headers, color info, cursor position, etc) in the buffer. The metadata items are stored in the metas array. In the same way, the buffer can contain multiple data blocks in the datas array. Each data block is, for example, a video plane or an audio channel. There are `n_datas` of those blocks.
|
||||
|
||||
> What is the `void*` data pointer in `spa_data`?
|
||||
|
||||
The data information either has a file descriptor or a data pointer. The type of the `spa_data` tells you what to expect. For a file descriptor, the data pointer can optionally be set when the FD is mapped into memory. Otherwise the user has to mmap the data themselves.
|
||||
|
||||
Also associated with each `spa_data` is a chunk, which is read/write and contains the valid region in the `spa_data` (offset, size, stride and some flags).
|
||||
|
||||
The reason why is this set up like this is that the metadata memory, the data and chunks can be directly transported in shared memory while the buffer structure can be negotiated separately (describing the shared memory). This way buffers can be shared but no process can destroy the structure of the buffers.
|
||||
|
||||
|
||||
* The buffer skeleton is placed in memory like below and can
|
||||
* be accessed as a regular structure.
|
||||
*
|
||||
* +==============================+
|
||||
* | struct spa_buffer |
|
||||
* | uint32_t n_metas | number of metas
|
||||
* | uint32_t n_datas | number of datas
|
||||
* +-| struct spa_meta *metas | pointer to array of metas
|
||||
* +|-| struct spa_data *datas | pointer to array of datas
|
||||
* || +------------------------------+
|
||||
* |+>| struct spa_meta |
|
||||
* | | uint32_t type | metadata
|
||||
* | | uint32_t size | size of metadata
|
||||
* +|--| void *data | pointer to metadata
|
||||
* || | ... <n_metas> | more spa_meta follow
|
||||
* || +------------------------------+
|
||||
* |+->| struct spa_data |
|
||||
* | | uint32_t type | memory type
|
||||
* | | uint32_t flags |
|
||||
* | | int fd | fd of shared memory block
|
||||
* | | uint32_t mapoffset | offset in shared memory of data
|
||||
* | | uint32_t maxsize | size of data block
|
||||
* | +-| void *data | pointer to data
|
||||
* |+|-| struct spa_chunk *chunk | pointer to chunk
|
||||
* ||| | ... <n_datas> | more spa_data follow
|
||||
* ||| +==============================+
|
||||
* VVV
|
||||
*
|
||||
* metadata, chunk and memory can either be placed right
|
||||
* after the skeleton (inlined) or in a separate piece of memory.
|
||||
*
|
||||
* vvv
|
||||
* ||| +==============================+
|
||||
* +-->| meta data memory | metadata memory, 8 byte aligned
|
||||
* || | ... <n_metas> |
|
||||
* || +------------------------------+
|
||||
* +->| struct spa_chunk | memory for n_datas chunks
|
||||
* | | uint32_t offset |
|
||||
* | | uint32_t size |
|
||||
* | | int32_t stride |
|
||||
* | | int32_t dummy |
|
||||
* | | ... <n_datas> chunks |
|
||||
* | +------------------------------+
|
||||
* +>| data | memory for n_datas data, aligned
|
||||
* | ... <n_datas> blocks | according to alignments
|
||||
* +==============================+
|
||||
|
||||
Taken from [here](https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/11f95fe11e07192cec19fddb4fafc708e023e49c/spa/include/spa/buffer/alloc.h).
|
||||
|
||||
|
||||
|
||||
\addtogroup spa_buffer
|
||||
|
||||
See: \ref page_spa_buffer
|
||||
|
||||
*/
|
||||
35
doc/dox/api/spa-design.dox
Normal file
35
doc/dox/api/spa-design.dox
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/** \page page_spa_design SPA Design
|
||||
|
||||
# Conventions
|
||||
|
||||
## Types
|
||||
|
||||
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
|
||||
performance/ease of use/low space overhead is needed.
|
||||
|
||||
The SPA type is system is statis and very simple but still allows you
|
||||
to make and introspect complex object type hierarchies.
|
||||
|
||||
See the type system docs for more info.
|
||||
|
||||
## Error Codes
|
||||
|
||||
SPA uses negative integers as errno style error codes. Functions that return an
|
||||
int result code generated an error when < 0. `spa_strerror()` can be used to
|
||||
get a string representation of the error code.
|
||||
|
||||
SPA also has a way to encode asynchronous results. This is done by setting a
|
||||
high bit (bit 30, the `ASYNC_BIT`) in the result code and a sequence number
|
||||
in the lower bits. This result is normally identified as a positive success
|
||||
result code and the sequence number can later be matched to the completion
|
||||
event.
|
||||
|
||||
## Useful Macros
|
||||
|
||||
SPA comes with some useful macros defined in `<spa/utils/defs.h>` and a
|
||||
number of utility functions, see \ref spa_utils.
|
||||
|
||||
*/
|
||||
88
doc/dox/api/spa-index.dox
Normal file
88
doc/dox/api/spa-index.dox
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/** \page page_spa SPA (Simple Plugin API)
|
||||
|
||||
\ref 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 provides two parts:
|
||||
|
||||
- A header-only API with no external dependencies.
|
||||
- A set of support libraries ("plugins") for commonly used functionality.
|
||||
|
||||
The usual approach is that PipeWire and PipeWire clients can use the
|
||||
header-only functions to interact with the plugins. Those plugins are
|
||||
usually loaded at runtime (through `dlopen(3)`).
|
||||
|
||||
|
||||
# Motivation
|
||||
|
||||
SPA was designed with the following goals in mind:
|
||||
|
||||
- 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 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 updated and versioned.
|
||||
|
||||
The original user of SPA is PipeWire, which uses SPA to implement the
|
||||
low-level multimedia processing plugins, device detection, mainloops, CPU
|
||||
detection, logging, among other things. SPA however can be used outside
|
||||
of PipeWire with minimal problems.
|
||||
|
||||
|
||||
# The SPA Header-Only API
|
||||
|
||||
A very simple example on how SPA headers work are the \ref spa_utils, a set
|
||||
of utilities commonly required by C projects. SPA functions use the `spa_`
|
||||
namespace and are easy to identify.
|
||||
|
||||
\code
|
||||
/* cc $(pkg-config --cflags libspa-0.2) -o spa-test spa-test.c */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <spa/utils/string.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
uint32_t val;
|
||||
|
||||
if (spa_atoi32(argv[1], &val, 16))
|
||||
printf("argv[1] is hex %#x\n", val);
|
||||
else
|
||||
printf("argv[1] is not a hex number\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
\endcode
|
||||
|
||||
|
||||
# SPA Plugins
|
||||
|
||||
SPA plugins are shared libraries (`.so` files) that can be loaded at
|
||||
runtime. Each library provides one or more "factories", each of which may
|
||||
implement several "interfaces". Code that uses SPA plugins then uses those
|
||||
interfaces (through SPA header files) to interact with the plugin.
|
||||
|
||||
For example, the PipeWire daemon can load the normal `printf`-based logger
|
||||
or a systemd journal-based logger. Both of those provide the \ref spa_log
|
||||
interface and once instantiated, PipeWire no longer has to differentiate
|
||||
between the two logging facilities.
|
||||
|
||||
Please see \ref page_spa_plugins for the details on how to use SPA plugins.
|
||||
|
||||
|
||||
# Further details
|
||||
|
||||
- \ref api_spa
|
||||
- \subpage page_spa_design
|
||||
- \subpage page_spa_plugins
|
||||
- \subpage page_spa_pod
|
||||
- \subpage page_spa_buffer
|
||||
|
||||
|
||||
\addtogroup api_spa
|
||||
|
||||
See: \ref page_spa, \ref page_spa_design
|
||||
|
||||
*/
|
||||
360
doc/dox/api/spa-plugins.dox
Normal file
360
doc/dox/api/spa-plugins.dox
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
/** \page page_spa_plugins SPA Plugins
|
||||
|
||||
\ref spa_handle "SPA plugins" are dynamically loadable objects that contain objects and interfaces that
|
||||
can be introspected and used at runtime in any application. This document
|
||||
introduces the basic concepts of SPA plugins. It first covers using the API
|
||||
and then talks about implementing new plugins.
|
||||
|
||||
|
||||
# Outline
|
||||
|
||||
To use a plugin, the following steps are required:
|
||||
|
||||
- **Load** the shared library.
|
||||
- **Enumerate** the available factories.
|
||||
- **Enumerate** the interfaces in each factory.
|
||||
- **Instantiate** the desired interface.
|
||||
- **Use** the interface-specific functions.
|
||||
|
||||
In pseudo-code, loading a logger interface looks like this:
|
||||
|
||||
\code{.py}
|
||||
handle = dlopen("$SPA_PLUGIN_DIR/support/libspa-support.so")
|
||||
factory_enumeration_func = dlsym(handle, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)
|
||||
spa_log *logger = NULL
|
||||
|
||||
while True:
|
||||
factory = get_next_factory(factory_enumeration_func):
|
||||
if factory != SPA_NAME_SUPPORT_LOG: # <spa/utils/name.h>
|
||||
continue
|
||||
|
||||
interface_info = get_next_interface_info(factory)
|
||||
if info->type != SPA_TYPE_INTERFACE_Log: # </spa/support/log.h>
|
||||
continue
|
||||
|
||||
interface = spa_load_interface(handle, interface_info->type)
|
||||
logger = (struct spa_log *)interface
|
||||
break
|
||||
|
||||
spa_log_error(log, "This is an error message\n")
|
||||
\endcode
|
||||
|
||||
SPA does not specify where plugins need to live, although plugins are
|
||||
normally installed in `/usr/lib64/spa-0.2/` or equivalent. Plugins and API
|
||||
are versioned and many versions can live on the same system.
|
||||
|
||||
\note The directory the SPA plugins reside in is available through
|
||||
`pkg-config --variable plugindir libspa-0.2`
|
||||
|
||||
The `spa-inspect` tool provides a CLI interface to inspect SPA plugins:
|
||||
|
||||
\verbatim
|
||||
$ export SPA_PLUGIN_DIR=$(pkg-config --variable plugindir libspa-0.2)
|
||||
$ spa-inspect ${SPA_PLUGIN_DIR}/support/libspa-support.so
|
||||
...
|
||||
factory version: 1
|
||||
factory name: 'support.cpu'
|
||||
factory info:
|
||||
none
|
||||
factory interfaces:
|
||||
interface: 'Spa:Pointer:Interface:CPU'
|
||||
factory instance:
|
||||
interface: 'Spa:Pointer:Interface:CPU'
|
||||
skipping unknown interface
|
||||
factory version: 1
|
||||
factory name: 'support.loop'
|
||||
factory info:
|
||||
none
|
||||
factory interfaces:
|
||||
interface: 'Spa:Pointer:Interface:Loop'
|
||||
interface: 'Spa:Pointer:Interface:LoopControl'
|
||||
interface: 'Spa:Pointer:Interface:LoopUtils'
|
||||
...
|
||||
\endverbatim
|
||||
|
||||
|
||||
# Open A Plugin
|
||||
|
||||
A plugin is opened with a platform specific API. In this example we use
|
||||
`dlopen()` as the method used on Linux.
|
||||
|
||||
A plugin always consists of two parts, the vendor path and then the .so file.
|
||||
|
||||
As an example we will load the "support/libspa-support.so" plugin. You will
|
||||
usually use some mapping between functionality and plugin path as we'll see
|
||||
later, instead of hardcoding the plugin name.
|
||||
|
||||
To `dlopen` a plugin we then need to prefix the plugin path like this:
|
||||
|
||||
\code{.c}
|
||||
#define SPA_PLUGIN_DIR /usr/lib64/spa-0.2/"
|
||||
void *hnd = dlopen(SPA_PLUGIN_DIR"/support/libspa-support.so", RTLD_NOW);
|
||||
\endcode
|
||||
|
||||
The environment variable `SPA_PLUGIN_DIR` and `pkg-config` variable
|
||||
`plugindir` are usually used to find the location of the plugins. You will
|
||||
have to do some more work to construct the shared object path.
|
||||
|
||||
The plugin must have exactly one public symbol, called
|
||||
`spa_handle_factory_enum`, which is defined with the macro
|
||||
`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:
|
||||
|
||||
\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, the library is not a valid SPA plugin.
|
||||
|
||||
|
||||
# Enumerating Factories
|
||||
|
||||
With the `enum_func` we can now enumerate all the factories in the plugin:
|
||||
|
||||
\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.
|
||||
}
|
||||
\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
|
||||
actual new object from it.
|
||||
|
||||
We can enumerate the interfaces that we will find on this new object with
|
||||
the `spa_handle_factory_enum_interface_info()` method. Interface types
|
||||
are simple strings that uniquely define the interface (see also the type
|
||||
system).
|
||||
|
||||
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:
|
||||
|
||||
\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.
|
||||
|
||||
|
||||
# Making A Handle
|
||||
|
||||
Once we have a suitable factory, we need to allocate memory for the object
|
||||
it can create. SPA usually does not allocate memory itself but relies on
|
||||
the application and the stack for storage.
|
||||
|
||||
First get the size of the required memory:
|
||||
|
||||
\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:
|
||||
|
||||
\code{.c}
|
||||
handle = calloc(1, size);
|
||||
spa_handle_factory_init(factory, handle,
|
||||
NULL, // info
|
||||
NULL, // support
|
||||
0 // n_support
|
||||
);
|
||||
\endcode
|
||||
|
||||
The info parameter should contain the same extra properties given in
|
||||
`spa_handle_factory_get_size()`.
|
||||
|
||||
The support parameter is an array of `struct spa_support` items. They
|
||||
contain a string type and a pointer to extra support objects. This can
|
||||
be a logging API or a main loop API for example. Some plugins require
|
||||
certain support libraries to function.
|
||||
|
||||
|
||||
# Retrieving An Interface
|
||||
|
||||
When a SPA handle is made, you can retrieve any of the interfaces that
|
||||
it provides:
|
||||
|
||||
\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.
|
||||
|
||||
\code{.c}
|
||||
struct spa_log *log = iface;
|
||||
spa_log_warn(log, "Hello World!\n");
|
||||
\endcode
|
||||
|
||||
|
||||
# Clearing An Object
|
||||
|
||||
After you are done with a handle you can clear it with
|
||||
`spa_handle_clear()` and you can unload the library with `dlclose()`.
|
||||
|
||||
|
||||
# SPA Interfaces
|
||||
|
||||
We briefly talked about retrieving an interface from a plugin in the
|
||||
previous section. Now we will explore what an interface actually is
|
||||
and how to use it.
|
||||
|
||||
When you retrieve an interface from a handle, you get a reference to
|
||||
a small structure that contains the type (string) of the interface,
|
||||
a version and a structure with a set of methods (and data) that are
|
||||
the implementation of the interface. Calling a method on the interface
|
||||
will just call the appropriate method in the implementation.
|
||||
|
||||
Interfaces are defined in a header file (for example see
|
||||
`<spa/support/log.h>` for the logger API). It is a self contained
|
||||
definition that you can just use in your application after you `dlopen()`
|
||||
the plugin.
|
||||
|
||||
Some interfaces also provide extra fields in the interface, like the
|
||||
log interface above that has the log level as a read/write parameter.
|
||||
|
||||
See \ref spa_interface for some implementation details on interfaces.
|
||||
|
||||
|
||||
# SPA Events
|
||||
|
||||
Some interfaces will also allow you to register a callback (a hook or
|
||||
listener) to be notified of events. This is usually when something
|
||||
changed internally in the interface and it wants to notify the registered
|
||||
listeners about this.
|
||||
|
||||
For example, the `struct spa_node` interface has a method to register such
|
||||
an event handler like this:
|
||||
|
||||
\code{.c}
|
||||
static void node_info(void *data, const struct spa_node_info *info)
|
||||
{
|
||||
printf("got node info!\n");
|
||||
}
|
||||
|
||||
static struct spa_node_events node_events = {
|
||||
SPA_VERSION_NODE_EVENTS,
|
||||
.info = node_info,
|
||||
};
|
||||
|
||||
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
|
||||
`struct spa_hook` is used by the interface to keep track of registered
|
||||
event listeners.
|
||||
|
||||
Whenever the node information is changed, your `node_info` method will
|
||||
be called with `my_data` as the first data field. The events are usually
|
||||
also triggered when the listener is added, to enumerate the current
|
||||
state of the object.
|
||||
|
||||
Events have a `version` field, set to `SPA_VERSION_NODE_EVENTS` in the
|
||||
above example. It should contain the version of the event structure
|
||||
you compiled with. When new events are added later, the version field
|
||||
will be checked and the new signal will be ignored for older versions.
|
||||
|
||||
You can remove your listener with:
|
||||
|
||||
\code{.c}
|
||||
spa_hook_remove(&listener);
|
||||
\endcode
|
||||
|
||||
|
||||
# API Results
|
||||
|
||||
Some interfaces provide API that gives you a list or enumeration of
|
||||
objects/values. To avoid allocation overhead and ownership problems,
|
||||
SPA uses events to push results to the application. This makes it
|
||||
possible for the plugin to temporarily create complex objects on the
|
||||
stack and push this to the application without allocation or ownership
|
||||
problems. The application can look at the pushed result and keep/copy
|
||||
only what it wants to keep.
|
||||
|
||||
## Synchronous Results
|
||||
|
||||
Here is an example of enumerating parameters on a node interface.
|
||||
|
||||
First install a listener for the result:
|
||||
|
||||
\code{.c}
|
||||
static void node_result(void *data, int seq, int res,
|
||||
uint32_t type, const void *result)
|
||||
{
|
||||
const struct spa_result_node_params *r =
|
||||
(const struct spa_result_node_params *) result;
|
||||
printf("got param:\n");
|
||||
spa_debug_pod(0, NULL, r->param);
|
||||
}
|
||||
|
||||
struct spa_hook listener = { 0 };
|
||||
static const struct spa_node_events node_events = {
|
||||
SPA_VERSION_NODE_EVENTS,
|
||||
.result = node_result,
|
||||
};
|
||||
|
||||
spa_node_add_listener(node, &listener, &node_events, node);
|
||||
\endcode
|
||||
|
||||
Then perform the `enum_param` method:
|
||||
|
||||
\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:
|
||||
|
||||
\code{.c}
|
||||
spa_hook_remove(&listener);
|
||||
\endcode
|
||||
|
||||
## Asynchronous Results
|
||||
|
||||
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:
|
||||
|
||||
\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
|
||||
...
|
||||
}
|
||||
\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:
|
||||
|
||||
\code{.c}
|
||||
expected_seq = SPA_RESULT_ASYNC_SEQ(res);
|
||||
\endcode
|
||||
|
||||
# Implementing A New Plugin
|
||||
|
||||
***FIXME***
|
||||
|
||||
|
||||
|
||||
\addtogroup spa_handle
|
||||
|
||||
See: \ref page_spa_plugins
|
||||
|
||||
*/
|
||||
1034
doc/dox/api/spa-pod.dox
Normal file
1034
doc/dox/api/spa-pod.dox
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue