8348600: Update PipeWire to 1.3.81

Reviewed-by: psadhukhan, prr, honkar
This commit is contained in:
Alexander Zvegintsev 2025-02-13 11:42:46 +00:00
parent efc597bf47
commit add3cd1ca4
72 changed files with 2300 additions and 631 deletions

View File

@ -1,4 +1,4 @@
## PipeWire 0.3.68
## PipeWire 1.3.81
### PipeWire license:
@ -39,3 +39,8 @@ spa/include/spa/utils/string.h
```
Copyright © 2021 Red Hat, Inc.
```
spa/utils/cleanup.h:
```
Copyright © 2023 PipeWire authors
```

View File

@ -43,6 +43,7 @@ struct pw_context;
struct pw_global;
struct pw_impl_client;
struct pw_impl_node;
#include <pipewire/core.h>
#include <pipewire/loop.h>
@ -50,7 +51,7 @@ struct pw_impl_client;
/** context events emitted by the context object added with \ref pw_context_add_listener */
struct pw_context_events {
#define PW_VERSION_CONTEXT_EVENTS 0
#define PW_VERSION_CONTEXT_EVENTS 1
uint32_t version;
/** The context is being destroyed */
@ -63,12 +64,24 @@ struct pw_context_events {
void (*global_added) (void *data, struct pw_global *global);
/** a global object was removed */
void (*global_removed) (void *data, struct pw_global *global);
/** a driver was added, since 0.3.75 version:1 */
void (*driver_added) (void *data, struct pw_impl_node *node);
/** a driver was removed, since 0.3.75 version:1 */
void (*driver_removed) (void *data, struct pw_impl_node *node);
};
/** Make a new context object for a given main_loop. Ownership of the properties is taken */
struct pw_context * pw_context_new(struct pw_loop *main_loop, /**< a main loop to run in */
struct pw_properties *props, /**< extra properties */
size_t user_data_size /**< extra user data size */);
/** Make a new context object for a given main_loop. Ownership of the properties is taken, even
* if the function returns NULL.
*
* \param main_loop A main loop to run in. This must stay alive unil pw_context_destroy() is called.
* \param props extra properties
* \param user_data_size extra user data size
* \return The context object on success, or NULL on failure, in which case errno is set.
* */
struct pw_context * pw_context_new(struct pw_loop *main_loop,
struct pw_properties *props,
size_t user_data_size);
/** destroy a context object, all resources except the main_loop will be destroyed */
void pw_context_destroy(struct pw_context *context);
@ -113,15 +126,27 @@ int pw_context_conf_section_match_rules(struct pw_context *context, const char *
/** Get the context support objects */
const struct spa_support *pw_context_get_support(struct pw_context *context, uint32_t *n_support);
/** get the context main loop */
/** Get the context main loop. Returns the value passed to pw_context_new(). */
struct pw_loop *pw_context_get_main_loop(struct pw_context *context);
/** get the context data loop. Since 0.3.56 */
/** Get the context data loop. This loop runs on the realtime thread. This
* acquires a loop from the generic data.rt class. Use pw_context_acquire_loop() instead.
* Since 0.3.56 */
struct pw_data_loop *pw_context_get_data_loop(struct pw_context *context);
/** Get a data-loop.
* Since 1.1.0 */
struct pw_loop *pw_context_acquire_loop(struct pw_context *context, const struct spa_dict *props);
/** Release a data-loop.
* Since 1.1.0 */
void pw_context_release_loop(struct pw_context *context, struct pw_loop *loop);
/** Get the work queue from the context: Since 0.3.26 */
struct pw_work_queue *pw_context_get_work_queue(struct pw_context *context);
/** Get the memory pool from the context: Since 0.3.74 */
struct pw_mempool *pw_context_get_mempool(struct pw_context *context);
/** Iterate the globals of the context. The callback should return
* 0 to fetch the next item, any other value stops the iteration and returns
* the value. When all callbacks return 0, this function returns 0 when all
@ -130,7 +155,10 @@ int pw_context_for_each_global(struct pw_context *context,
int (*callback) (void *data, struct pw_global *global),
void *data);
/** Find a context global by id */
/** Find a context global by id.
*
* \return The global on success, or NULL on failure. If id is \ref PW_ID_CORE,
* this function will always return a non-NULL value. */
struct pw_global *pw_context_find_global(struct pw_context *context, /**< the context */
uint32_t id /**< the global id */);
@ -140,6 +168,7 @@ int pw_context_add_spa_lib(struct pw_context *context, const char *factory_regex
/** find the library name for a spa factory */
const char * pw_context_find_spa_lib(struct pw_context *context, const char *factory_name);
/** Load a SPA handle from a context. On failure returns NULL and sets errno. */
struct spa_handle *pw_context_load_spa_handle(struct pw_context *context,
const char *factory_name,
const struct spa_dict *info);
@ -160,9 +189,21 @@ int pw_context_register_export_type(struct pw_context *context, struct pw_export
/** find information about registered export type */
const struct pw_export_type *pw_context_find_export_type(struct pw_context *context, const char *type);
/** add an object to the context */
/** add an object to the context
*
* \param context The context.
* \param type The type of the object, usually a `TYPE_INTERFACE_` value.
* \param value The object value. Must last as long as the context and must
* be of the type corresponding to the type.
* \return A negative number on failure (out of memory).
* */
int pw_context_set_object(struct pw_context *context, const char *type, void *value);
/** get an object from the context */
/** get an object from the context
*
* \param context The context.
* \param type The string corresponding to the object's interface.
* \return The object, or NULL if the object does not exist.
* */
void *pw_context_get_object(struct pw_context *context, const char *type);
/**

View File

@ -14,6 +14,8 @@ extern "C" {
#include <spa/utils/hook.h>
#include <pipewire/type.h>
/** \defgroup pw_core Core
*
* \brief The core global object.
@ -34,11 +36,20 @@ extern "C" {
#define PW_TYPE_INTERFACE_Core PW_TYPE_INFO_INTERFACE_BASE "Core"
#define PW_TYPE_INTERFACE_Registry PW_TYPE_INFO_INTERFACE_BASE "Registry"
#define PW_CORE_PERM_MASK PW_PERM_R|PW_PERM_X|PW_PERM_M
#define PW_VERSION_CORE 4
struct pw_core;
#define PW_VERSION_REGISTRY 3
struct pw_registry;
#ifndef PW_API_CORE_IMPL
#define PW_API_CORE_IMPL static inline
#endif
#ifndef PW_API_REGISTRY_IMPL
#define PW_API_REGISTRY_IMPL static inline
#endif
/** The default remote name to connect to */
#define PW_DEFAULT_REMOTE "pipewire-0"
@ -67,11 +78,13 @@ struct pw_core_info {
#include <pipewire/properties.h>
#include <pipewire/proxy.h>
/** Update an existing \ref pw_core_info with \a update with reset */
/** Update an existing \ref pw_core_info with \a update with reset. When info is NULL,
* a new one will be allocated. Returns NULL on failure. */
struct pw_core_info *
pw_core_info_update(struct pw_core_info *info,
const struct pw_core_info *update);
/** Update an existing \ref pw_core_info with \a update */
/** Update an existing \ref pw_core_info with \a update. When info is NULL, a new one
* will be allocated. Returns NULL on failure */
struct pw_core_info *
pw_core_info_merge(struct pw_core_info *info,
const struct pw_core_info *update, bool reset);
@ -162,6 +175,9 @@ struct pw_core_events {
* global ID. It is emitted before the global becomes visible in the
* registry.
*
* The bound_props event is an enhanced version of this event that
* also contains the extra global properties.
*
* \param id bound object ID
* \param global_id the global id bound to
*/
@ -190,6 +206,21 @@ struct pw_core_events {
*/
void (*remove_mem) (void *data, uint32_t id);
/**
* Notify an object binding
*
* This event is emitted when a local object ID is bound to a
* global ID. It is emitted before the global becomes visible in the
* registry.
*
* This is an enhanced version of the bound_id event.
*
* \param id bound object ID
* \param global_id the global id bound to
* \param props The properties of the new global object.
*
* Since version 4:1
*/
void (*bound_props) (void *data, uint32_t id, uint32_t global_id, const struct spa_dict *props);
};
@ -223,6 +254,8 @@ struct pw_core_methods {
* Start a conversation with the server. This will send
* the core info and will destroy all resources for the client
* (except the core and client resource).
*
* This requires X permissions on the core.
*/
int (*hello) (void *object, uint32_t version);
/**
@ -235,6 +268,8 @@ struct pw_core_methods {
* methods and the resulting events have been handled.
*
* \param seq the seq number passed to the done event
*
* This requires X permissions on the core.
*/
int (*sync) (void *object, uint32_t id, int seq);
/**
@ -243,6 +278,8 @@ struct pw_core_methods {
* Reply to the server ping event with the same seq.
*
* \param seq the seq number received in the ping event
*
* This requires X permissions on the core.
*/
int (*pong) (void *object, uint32_t id, int seq);
/**
@ -257,9 +294,11 @@ struct pw_core_methods {
* This method is usually also emitted on the resource object with
* \a id.
*
* \param id object where the error occurred
* \param id resource id where the error occurred
* \param res error code
* \param message error description
*
* This requires X permissions on the core.
*/
int (*error) (void *object, uint32_t id, int seq, int res, const char *message);
/**
@ -269,6 +308,8 @@ struct pw_core_methods {
* the global objects available from the PipeWire server
* \param version the client version
* \param user_data_size extra size
*
* This requires X permissions on the core.
*/
struct pw_registry * (*get_registry) (void *object, uint32_t version,
size_t user_data_size);
@ -281,6 +322,8 @@ struct pw_core_methods {
* \param version the version of the interface
* \param props extra properties
* \param user_data_size extra size
*
* This requires X permissions on the core.
*/
void * (*create_object) (void *object,
const char *factory_name,
@ -294,27 +337,57 @@ struct pw_core_methods {
* Destroy the server resource for the given proxy.
*
* \param obj the proxy to destroy
*
* This requires X permissions on the core.
*/
int (*destroy) (void *object, void *proxy);
};
#define pw_core_method(o,method,version,...) \
({ \
int _res = -ENOTSUP; \
spa_interface_call_res((struct spa_interface*)o, \
struct pw_core_methods, _res, \
method, version, ##__VA_ARGS__); \
_res; \
})
#define pw_core_add_listener(c,...) pw_core_method(c,add_listener,0,__VA_ARGS__)
#define pw_core_hello(c,...) pw_core_method(c,hello,0,__VA_ARGS__)
#define pw_core_sync(c,...) pw_core_method(c,sync,0,__VA_ARGS__)
#define pw_core_pong(c,...) pw_core_method(c,pong,0,__VA_ARGS__)
#define pw_core_error(c,...) pw_core_method(c,error,0,__VA_ARGS__)
static inline
/** \copydoc pw_core_methods.add_listener
* \sa pw_core_methods.add_listener */
PW_API_CORE_IMPL int pw_core_add_listener(struct pw_core *object,
struct spa_hook *listener,
const struct pw_core_events *events,
void *data)
{
return spa_api_method_r(int, -ENOTSUP,
pw_core, (struct spa_interface*)object, add_listener, 0,
listener, events, data);
}
/** \copydoc pw_core_methods.hello
* \sa pw_core_methods.hello */
PW_API_CORE_IMPL int pw_core_hello(struct pw_core *object, uint32_t version)
{
return spa_api_method_r(int, -ENOTSUP,
pw_core, (struct spa_interface*)object, hello, 0,
version);
}
/** \copydoc pw_core_methods.sync
* \sa pw_core_methods.sync */
PW_API_CORE_IMPL int pw_core_sync(struct pw_core *object, uint32_t id, int seq)
{
return spa_api_method_r(int, -ENOTSUP,
pw_core, (struct spa_interface*)object, sync, 0,
id, seq);
}
/** \copydoc pw_core_methods.pong
* \sa pw_core_methods.pong */
PW_API_CORE_IMPL int pw_core_pong(struct pw_core *object, uint32_t id, int seq)
{
return spa_api_method_r(int, -ENOTSUP,
pw_core, (struct spa_interface*)object, pong, 0,
id, seq);
}
/** \copydoc pw_core_methods.error
* \sa pw_core_methods.error */
PW_API_CORE_IMPL int pw_core_error(struct pw_core *object, uint32_t id, int seq, int res, const char *message)
{
return spa_api_method_r(int, -ENOTSUP,
pw_core, (struct spa_interface*)object, error, 0,
id, seq, res, message);
}
PW_API_CORE_IMPL
SPA_PRINTF_FUNC(5, 0) int
pw_core_errorv(struct pw_core *core, uint32_t id, int seq,
int res, const char *message, va_list args)
@ -325,7 +398,7 @@ pw_core_errorv(struct pw_core *core, uint32_t id, int seq,
return pw_core_error(core, id, seq, res, buffer);
}
static inline
PW_API_CORE_IMPL
SPA_PRINTF_FUNC(5, 6) int
pw_core_errorf(struct pw_core *core, uint32_t id, int seq,
int res, const char *message, ...)
@ -338,17 +411,18 @@ pw_core_errorf(struct pw_core *core, uint32_t id, int seq,
return r;
}
static inline struct pw_registry *
/** \copydoc pw_core_methods.get_registry
* \sa pw_core_methods.get_registry */
PW_API_CORE_IMPL struct pw_registry *
pw_core_get_registry(struct pw_core *core, uint32_t version, size_t user_data_size)
{
struct pw_registry *res = NULL;
spa_interface_call_res((struct spa_interface*)core,
struct pw_core_methods, res,
get_registry, 0, version, user_data_size);
return res;
return spa_api_method_r(struct pw_registry*, NULL,
pw_core, (struct spa_interface*)core, get_registry, 0,
version, user_data_size);
}
static inline void *
/** \copydoc pw_core_methods.create_object
* \sa pw_core_methods.create_object */
PW_API_CORE_IMPL void *
pw_core_create_object(struct pw_core *core,
const char *factory_name,
const char *type,
@ -356,15 +430,18 @@ pw_core_create_object(struct pw_core *core,
const struct spa_dict *props,
size_t user_data_size)
{
void *res = NULL;
spa_interface_call_res((struct spa_interface*)core,
struct pw_core_methods, res,
create_object, 0, factory_name,
type, version, props, user_data_size);
return res;
return spa_api_method_r(void*, NULL,
pw_core, (struct spa_interface*)core, create_object, 0,
factory_name, type, version, props, user_data_size);
}
/** \copydoc pw_core_methods.destroy
* \sa pw_core_methods.destroy */
PW_API_CORE_IMPL void
pw_core_destroy(struct pw_core *core, void *proxy)
{
spa_api_method_v(pw_core, (struct spa_interface*)core, destroy, 0,
proxy);
}
#define pw_core_destroy(c,...) pw_core_method(c,destroy,0,__VA_ARGS__)
/**
* \}
@ -474,36 +551,44 @@ struct pw_registry_methods {
*
* Try to destroy the global object.
*
* \param id the global id to destroy
* \param id the global id to destroy. The client needs X permissions
* on the global.
*/
int (*destroy) (void *object, uint32_t id);
};
#define pw_registry_method(o,method,version,...) \
({ \
int _res = -ENOTSUP; \
spa_interface_call_res((struct spa_interface*)o, \
struct pw_registry_methods, _res, \
method, version, ##__VA_ARGS__); \
_res; \
})
/** Registry */
#define pw_registry_add_listener(p,...) pw_registry_method(p,add_listener,0,__VA_ARGS__)
static inline void *
/** \copydoc pw_registry_methods.add_listener
* \sa pw_registry_methods.add_listener */
PW_API_REGISTRY_IMPL int pw_registry_add_listener(struct pw_registry *registry,
struct spa_hook *listener,
const struct pw_registry_events *events,
void *data)
{
return spa_api_method_r(int, -ENOTSUP,
pw_registry, (struct spa_interface*)registry, add_listener, 0,
listener, events, data);
}
/** \copydoc pw_registry_methods.bind
* \sa pw_registry_methods.bind */
PW_API_REGISTRY_IMPL void *
pw_registry_bind(struct pw_registry *registry,
uint32_t id, const char *type, uint32_t version,
size_t user_data_size)
{
void *res = NULL;
spa_interface_call_res((struct spa_interface*)registry,
struct pw_registry_methods, res,
bind, 0, id, type, version, user_data_size);
return res;
return spa_api_method_r(void*, NULL,
pw_registry, (struct spa_interface*)registry, bind, 0,
id, type, version, user_data_size);
}
/** \copydoc pw_registry_methods.destroy
* \sa pw_registry_methods.destroy */
PW_API_REGISTRY_IMPL int
pw_registry_destroy(struct pw_registry *registry, uint32_t id)
{
return spa_api_method_r(int, -ENOTSUP,
pw_registry, (struct spa_interface*)registry, destroy, 0, id);
}
#define pw_registry_destroy(p,...) pw_registry_method(p,destroy,0,__VA_ARGS__)
/**
* \}

View File

@ -38,6 +38,14 @@ extern "C" {
#define PW_KEY_SEC_GID "pipewire.sec.gid" /**< client gid, set by protocol*/
#define PW_KEY_SEC_LABEL "pipewire.sec.label" /**< client security label, set by protocol*/
#define PW_KEY_SEC_SOCKET "pipewire.sec.socket" /**< client socket name, set by protocol */
#define PW_KEY_SEC_ENGINE "pipewire.sec.engine" /**< client secure context engine, set by protocol.
* This can also be set by a client when making a
* new security context. */
#define PW_KEY_SEC_APP_ID "pipewire.sec.app-id" /**< client secure application id */
#define PW_KEY_SEC_INSTANCE_ID "pipewire.sec.instance-id" /**< client secure instance id */
#define PW_KEY_LIBRARY_NAME_SYSTEM "library.name.system" /**< name of the system library to use */
#define PW_KEY_LIBRARY_NAME_LOOP "library.name.loop" /**< name of the loop library to use */
#define PW_KEY_LIBRARY_NAME_DBUS "library.name.dbus" /**< name of the dbus library to use */
@ -52,7 +60,8 @@ extern "C" {
#define PW_KEY_OBJECT_LINGER "object.linger" /**< the object lives on even after the client
* that created it has been destroyed */
#define PW_KEY_OBJECT_REGISTER "object.register" /**< If the object should be registered. */
#define PW_KEY_OBJECT_EXPORT "object.export" /**< If the object should be exported,
* since 0.3.72 */
/* config */
#define PW_KEY_CONFIG_PREFIX "config.prefix" /**< a config prefix directory */
@ -60,6 +69,12 @@ extern "C" {
#define PW_KEY_CONFIG_OVERRIDE_PREFIX "config.override.prefix" /**< a config override prefix directory */
#define PW_KEY_CONFIG_OVERRIDE_NAME "config.override.name" /**< a config override file name */
/* loop */
#define PW_KEY_LOOP_NAME "loop.name" /**< the name of a loop */
#define PW_KEY_LOOP_CLASS "loop.class" /**< the classes this loop handles, array of strings */
#define PW_KEY_LOOP_RT_PRIO "loop.rt-prio" /**< realtime priority of the loop */
#define PW_KEY_LOOP_CANCEL "loop.cancel" /**< if the loop can be canceled */
/* context */
#define PW_KEY_CONTEXT_PROFILE_MODULES "context.profile.modules" /**< a context profile for modules, deprecated */
#define PW_KEY_USER_NAME "context.user-name" /**< The user name that runs pipewire */
@ -87,7 +102,9 @@ extern "C" {
/* remote keys */
#define PW_KEY_REMOTE_NAME "remote.name" /**< The name of the remote to connect to,
* default pipewire-0, overwritten by
* env(PIPEWIRE_REMOTE) */
* env(PIPEWIRE_REMOTE). May also be
* a SPA-JSON array of sockets, to be tried
* in order. */
#define PW_KEY_REMOTE_INTENTION "remote.intention" /**< The intention of the remote connection,
* "generic", "screencast" */
@ -132,7 +149,14 @@ extern "C" {
#define PW_KEY_NODE_SESSION "node.session" /**< the session id this node is part of */
#define PW_KEY_NODE_GROUP "node.group" /**< the group id this node is part of. Nodes
* in the same group are always scheduled
* with the same driver. */
* with the same driver. Can be an array of
* group names. */
#define PW_KEY_NODE_SYNC_GROUP "node.sync-group" /**< the sync group this node is part of. Nodes
* in the same sync group are always scheduled
* together with the same driver when the sync
* is active. Can be an array of sync names. */
#define PW_KEY_NODE_SYNC "node.sync" /**< if the sync-group is active or not */
#define PW_KEY_NODE_TRANSPORT "node.transport" /**< if the transport is active or not */
#define PW_KEY_NODE_EXCLUSIVE "node.exclusive" /**< node wants exclusive access to resources */
#define PW_KEY_NODE_AUTOCONNECT "node.autoconnect" /**< node wants to be automatically connected
* to a compatible node */
@ -163,7 +187,23 @@ extern "C" {
#define PW_KEY_NODE_SUSPEND_ON_IDLE "node.suspend-on-idle" /**< suspend the node when idle */
#define PW_KEY_NODE_CACHE_PARAMS "node.cache-params" /**< cache the node params */
#define PW_KEY_NODE_TRANSPORT_SYNC "node.transport.sync" /**< the node handles transport sync */
#define PW_KEY_NODE_DRIVER "node.driver" /**< node can drive the graph */
#define PW_KEY_NODE_DRIVER "node.driver" /**< node can drive the graph. When the node is
* selected as the driver, it needs to start
* the graph periodically. */
#define PW_KEY_NODE_SUPPORTS_LAZY "node.supports-lazy" /**< the node can be a lazy driver. It will listen
* to RequestProcess commands and take them into
* account when deciding to start the graph.
* A value of 0 disables support, a value of > 0
* enables with increasing preference. */
#define PW_KEY_NODE_SUPPORTS_REQUEST "node.supports-request" /**< The node supports emiting RequestProcess events
* when it wants the graph to be scheduled.
* A value of 0 disables support, a value of > 0
* enables with increasing preference. */
#define PW_KEY_NODE_DRIVER_ID "node.driver-id" /**< the node id of the node assigned as driver
* for this node */
#define PW_KEY_NODE_ASYNC "node.async" /**< the node wants async scheduling */
#define PW_KEY_NODE_LOOP_NAME "node.loop.name" /**< the loop name fnmatch pattern to run in */
#define PW_KEY_NODE_LOOP_CLASS "node.loop.class" /**< the loop class fnmatch pattern to run in */
#define PW_KEY_NODE_STREAM "node.stream" /**< node is a stream, the server side should
* add a converter */
#define PW_KEY_NODE_VIRTUAL "node.virtual" /**< the node is some sort of virtual
@ -172,17 +212,20 @@ extern "C" {
* on output/input/all ports when the value is
* "out"/"in"/"true" respectively */
#define PW_KEY_NODE_LINK_GROUP "node.link-group" /**< the node is internally linked to
* nodes with the same link-group */
* nodes with the same link-group. Can be an
* array of group names. */
#define PW_KEY_NODE_NETWORK "node.network" /**< the node is on a network */
#define PW_KEY_NODE_TRIGGER "node.trigger" /**< the node is not scheduled automatically
* based on the dependencies in the graph
* but it will be triggered explicitly. */
#define PW_KEY_NODE_CHANNELNAMES "node.channel-names" /**< names of node's
* channels (unrelated to positions) */
#define PW_KEY_NODE_DEVICE_PORT_NAME_PREFIX "node.device-port-name-prefix" /** override
* port name prefix for device ports, like capture and playback
* or disable the prefix completely if an empty string is provided */
#define PW_KEY_NODE_CHANNELNAMES "node.channel-names" /**< names of node's
* channels (unrelated to positions) */
#define PW_KEY_NODE_DEVICE_PORT_NAME_PREFIX \
"node.device-port-name-prefix" /**< override port name prefix for
* device ports, like capture and
* playback or disable the prefix
* completely if an empty string
* is provided */
/** Port keys */
#define PW_KEY_PORT_ID "port.id" /**< port id */
#define PW_KEY_PORT_NAME "port.name" /**< port name */
@ -197,6 +240,8 @@ extern "C" {
#define PW_KEY_PORT_EXTRA "port.extra" /**< api specific extra port info, API name
* should be prefixed. "jack:flags:56" */
#define PW_KEY_PORT_PASSIVE "port.passive" /**< the ports wants passive links, since 0.3.67 */
#define PW_KEY_PORT_IGNORE_LATENCY "port.ignore-latency" /**< latency ignored by peers, since 0.3.71 */
#define PW_KEY_PORT_GROUP "port.group" /**< the port group of the port 1.2.0 */
/** link properties */
#define PW_KEY_LINK_ID "link.id" /**< a link id */
@ -210,6 +255,7 @@ extern "C" {
#define PW_KEY_LINK_FEEDBACK "link.feedback" /**< indicate that a link is a feedback
* link and the target will receive data
* in the next cycle */
#define PW_KEY_LINK_ASYNC "link.async" /**< the link is using async io */
/** device properties */
#define PW_KEY_DEVICE_ID "device.id" /**< device id */
@ -260,6 +306,7 @@ extern "C" {
#define PW_KEY_MODULE_USAGE "module.usage" /**< a human readable usage description of
* the module's arguments. */
#define PW_KEY_MODULE_VERSION "module.version" /**< a version string for the module. */
#define PW_KEY_MODULE_DEPRECATED "module.deprecated" /**< the module is deprecated with this message */
/** Factory properties */
#define PW_KEY_FACTORY_ID "factory.id" /**< the factory id */
@ -274,7 +321,10 @@ extern "C" {
#define PW_KEY_STREAM_LATENCY_MAX "stream.latency.max" /**< The maximum latency of the stream */
#define PW_KEY_STREAM_MONITOR "stream.monitor" /**< Indicates that the stream is monitoring
* and might select a less accurate but faster
* conversion algorithm. */
* conversion algorithm. Monitor streams are also
* ignored when calculating the latency of their peer
* ports (since 0.3.71).
*/
#define PW_KEY_STREAM_DONT_REMIX "stream.dont-remix" /**< don't remix channels */
#define PW_KEY_STREAM_CAPTURE_SINK "stream.capture.sink" /**< Try to capture the sink output instead of
* source output */
@ -292,6 +342,7 @@ extern "C" {
#define PW_KEY_MEDIA_NAME "media.name" /**< media name. Ex: "Pink Floyd: Time" */
#define PW_KEY_MEDIA_TITLE "media.title" /**< title. Ex: "Time" */
#define PW_KEY_MEDIA_ARTIST "media.artist" /**< artist. Ex: "Pink Floyd" */
#define PW_KEY_MEDIA_ALBUM "media.album" /**< album. Ex: "Dark Side of the Moon" */
#define PW_KEY_MEDIA_COPYRIGHT "media.copyright" /**< copyright string */
#define PW_KEY_MEDIA_SOFTWARE "media.software" /**< generator software */
#define PW_KEY_MEDIA_LANGUAGE "media.language" /**< language in POSIX format. Ex: en_GB */
@ -327,9 +378,11 @@ extern "C" {
# ifdef PW_ENABLE_DEPRECATED
# define PW_KEY_PRIORITY_MASTER "priority.master" /**< deprecated, use priority.driver */
# define PW_KEY_NODE_TARGET "node.target" /**< deprecated since 0.3.64, use target.object. */
# define PW_KEY_LOOP_RETRY_TIMEOUT "loop.retry-timeout" /**< deprecated since 1.3.0 */
# else
# define PW_KEY_PRIORITY_MASTER PW_DEPRECATED("priority.master")
# define PW_KEY_NODE_TARGET PW_DEPRECATED("node.target")
# define PW_KEY_LOOP_RETRY_TIMEOUT PW_DEPRECATED("loop.retry-timeout")
# endif /* PW_ENABLE_DEPRECATED */
#endif /* PW_REMOVE_DEPRECATED */

View File

@ -17,6 +17,8 @@ extern "C" {
* PipeWire loop object provides an implementation of
* the spa loop interfaces. It can be used to implement various
* event loops.
*
* The members of \ref pw_loop are read-only.
*/
/**
@ -29,35 +31,118 @@ struct pw_loop {
struct spa_loop *loop; /**< wrapped loop */
struct spa_loop_control *control; /**< loop control */
struct spa_loop_utils *utils; /**< loop utils */
const char *name;
};
#ifndef PW_API_LOOP_IMPL
#define PW_API_LOOP_IMPL static inline
#endif
struct pw_loop *
pw_loop_new(const struct spa_dict *props);
void
pw_loop_destroy(struct pw_loop *loop);
#define pw_loop_add_source(l,...) spa_loop_add_source((l)->loop,__VA_ARGS__)
#define pw_loop_update_source(l,...) spa_loop_update_source((l)->loop,__VA_ARGS__)
#define pw_loop_remove_source(l,...) spa_loop_remove_source((l)->loop,__VA_ARGS__)
#define pw_loop_invoke(l,...) spa_loop_invoke((l)->loop,__VA_ARGS__)
int pw_loop_set_name(struct pw_loop *loop, const char *name);
#define pw_loop_get_fd(l) spa_loop_control_get_fd((l)->control)
#define pw_loop_add_hook(l,...) spa_loop_control_add_hook((l)->control,__VA_ARGS__)
#define pw_loop_enter(l) spa_loop_control_enter((l)->control)
#define pw_loop_iterate(l,...) spa_loop_control_iterate((l)->control,__VA_ARGS__)
#define pw_loop_leave(l) spa_loop_control_leave((l)->control)
PW_API_LOOP_IMPL int pw_loop_add_source(struct pw_loop *object, struct spa_source *source)
{
return spa_loop_add_source(object->loop, source);
}
PW_API_LOOP_IMPL int pw_loop_update_source(struct pw_loop *object, struct spa_source *source)
{
return spa_loop_update_source(object->loop, source);
}
PW_API_LOOP_IMPL int pw_loop_remove_source(struct pw_loop *object, struct spa_source *source)
{
return spa_loop_remove_source(object->loop, source);
}
PW_API_LOOP_IMPL int pw_loop_invoke(struct pw_loop *object,
spa_invoke_func_t func, uint32_t seq, const void *data,
size_t size, bool block, void *user_data)
{
return spa_loop_invoke(object->loop, func, seq, data, size, block, user_data);
}
#define pw_loop_add_io(l,...) spa_loop_utils_add_io((l)->utils,__VA_ARGS__)
#define pw_loop_update_io(l,...) spa_loop_utils_update_io((l)->utils,__VA_ARGS__)
#define pw_loop_add_idle(l,...) spa_loop_utils_add_idle((l)->utils,__VA_ARGS__)
#define pw_loop_enable_idle(l,...) spa_loop_utils_enable_idle((l)->utils,__VA_ARGS__)
#define pw_loop_add_event(l,...) spa_loop_utils_add_event((l)->utils,__VA_ARGS__)
#define pw_loop_signal_event(l,...) spa_loop_utils_signal_event((l)->utils,__VA_ARGS__)
#define pw_loop_add_timer(l,...) spa_loop_utils_add_timer((l)->utils,__VA_ARGS__)
#define pw_loop_update_timer(l,...) spa_loop_utils_update_timer((l)->utils,__VA_ARGS__)
#define pw_loop_add_signal(l,...) spa_loop_utils_add_signal((l)->utils,__VA_ARGS__)
#define pw_loop_destroy_source(l,...) spa_loop_utils_destroy_source((l)->utils,__VA_ARGS__)
PW_API_LOOP_IMPL int pw_loop_get_fd(struct pw_loop *object)
{
return spa_loop_control_get_fd(object->control);
}
PW_API_LOOP_IMPL void pw_loop_add_hook(struct pw_loop *object,
struct spa_hook *hook, const struct spa_loop_control_hooks *hooks,
void *data)
{
spa_loop_control_add_hook(object->control, hook, hooks, data);
}
PW_API_LOOP_IMPL void pw_loop_enter(struct pw_loop *object)
{
spa_loop_control_enter(object->control);
}
PW_API_LOOP_IMPL void pw_loop_leave(struct pw_loop *object)
{
spa_loop_control_leave(object->control);
}
PW_API_LOOP_IMPL int pw_loop_iterate(struct pw_loop *object,
int timeout)
{
return spa_loop_control_iterate_fast(object->control, timeout);
}
PW_API_LOOP_IMPL struct spa_source *
pw_loop_add_io(struct pw_loop *object, int fd, uint32_t mask,
bool close, spa_source_io_func_t func, void *data)
{
return spa_loop_utils_add_io(object->utils, fd, mask, close, func, data);
}
PW_API_LOOP_IMPL int pw_loop_update_io(struct pw_loop *object,
struct spa_source *source, uint32_t mask)
{
return spa_loop_utils_update_io(object->utils, source, mask);
}
PW_API_LOOP_IMPL struct spa_source *
pw_loop_add_idle(struct pw_loop *object, bool enabled,
spa_source_idle_func_t func, void *data)
{
return spa_loop_utils_add_idle(object->utils, enabled, func, data);
}
PW_API_LOOP_IMPL int pw_loop_enable_idle(struct pw_loop *object,
struct spa_source *source, bool enabled)
{
return spa_loop_utils_enable_idle(object->utils, source, enabled);
}
PW_API_LOOP_IMPL struct spa_source *
pw_loop_add_event(struct pw_loop *object, spa_source_event_func_t func, void *data)
{
return spa_loop_utils_add_event(object->utils, func, data);
}
PW_API_LOOP_IMPL int pw_loop_signal_event(struct pw_loop *object,
struct spa_source *source)
{
return spa_loop_utils_signal_event(object->utils, source);
}
PW_API_LOOP_IMPL struct spa_source *
pw_loop_add_timer(struct pw_loop *object, spa_source_timer_func_t func, void *data)
{
return spa_loop_utils_add_timer(object->utils, func, data);
}
PW_API_LOOP_IMPL int pw_loop_update_timer(struct pw_loop *object,
struct spa_source *source, struct timespec *value,
struct timespec *interval, bool absolute)
{
return spa_loop_utils_update_timer(object->utils, source, value, interval, absolute);
}
PW_API_LOOP_IMPL struct spa_source *
pw_loop_add_signal(struct pw_loop *object, int signal_number,
spa_source_signal_func_t func, void *data)
{
return spa_loop_utils_add_signal(object->utils, signal_number, func, data);
}
PW_API_LOOP_IMPL void pw_loop_destroy_source(struct pw_loop *object,
struct spa_source *source)
{
return spa_loop_utils_destroy_source(object->utils, source);
}
/**
* \}

View File

@ -29,9 +29,15 @@ extern "C" {
#define PW_TYPE_INTERFACE_Port PW_TYPE_INFO_INTERFACE_BASE "Port"
#define PW_PORT_PERM_MASK PW_PERM_R|PW_PERM_X|PW_PERM_M
#define PW_VERSION_PORT 3
struct pw_port;
#ifndef PW_API_PORT_IMPL
#define PW_API_PORT_IMPL static inline
#endif
/** The direction of a port */
#define pw_direction spa_direction
#define PW_DIRECTION_INPUT SPA_DIRECTION_INPUT
@ -115,6 +121,8 @@ struct pw_port_methods {
*
* \param ids an array of param ids
* \param n_ids the number of ids in \a ids
*
* This requires X permissions on the port.
*/
int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
@ -129,24 +137,43 @@ struct pw_port_methods {
* \param start the start index or 0 for the first param
* \param num the maximum number of params to retrieve
* \param filter a param filter or NULL
*
* This requires X permissions on the port.
*/
int (*enum_params) (void *object, int seq,
uint32_t id, uint32_t start, uint32_t num,
const struct spa_pod *filter);
};
#define pw_port_method(o,method,version,...) \
({ \
int _res = -ENOTSUP; \
spa_interface_call_res((struct spa_interface*)o, \
struct pw_port_methods, _res, \
method, version, ##__VA_ARGS__); \
_res; \
})
#define pw_port_add_listener(c,...) pw_port_method(c,add_listener,0,__VA_ARGS__)
#define pw_port_subscribe_params(c,...) pw_port_method(c,subscribe_params,0,__VA_ARGS__)
#define pw_port_enum_params(c,...) pw_port_method(c,enum_params,0,__VA_ARGS__)
/** \copydoc pw_port_methods.add_listener
* \sa pw_port_methods.add_listener */
PW_API_PORT_IMPL int pw_port_add_listener(struct pw_port *object,
struct spa_hook *listener,
const struct pw_port_events *events,
void *data)
{
return spa_api_method_r(int, -ENOTSUP,
pw_port, (struct spa_interface*)object, add_listener, 0,
listener, events, data);
}
/** \copydoc pw_port_methods.subscribe_params
* \sa pw_port_methods.subscribe_params */
PW_API_PORT_IMPL int pw_port_subscribe_params(struct pw_port *object, uint32_t *ids, uint32_t n_ids)
{
return spa_api_method_r(int, -ENOTSUP,
pw_port, (struct spa_interface*)object, subscribe_params, 0,
ids, n_ids);
}
/** \copydoc pw_port_methods.enum_params
* \sa pw_port_methods.enum_params */
PW_API_PORT_IMPL int pw_port_enum_params(struct pw_port *object,
int seq, uint32_t id, uint32_t start, uint32_t num,
const struct spa_pod *filter)
{
return spa_api_method_r(int, -ENOTSUP,
pw_port, (struct spa_interface*)object, enum_params, 0,
seq, id, start, num, filter);
}
/**
* \}

View File

@ -11,9 +11,14 @@ extern "C" {
#include <stdarg.h>
#include <spa/utils/cleanup.h>
#include <spa/utils/dict.h>
#include <spa/utils/string.h>
#ifndef PW_API_PROPERTIES
#define PW_API_PROPERTIES static inline
#endif
/** \defgroup pw_properties Properties
*
* Properties are used to pass around arbitrary key/value pairs.
@ -40,6 +45,10 @@ pw_properties_new_dict(const struct spa_dict *dict);
struct pw_properties *
pw_properties_new_string(const char *args);
struct pw_properties *
pw_properties_new_string_checked(const char *args, size_t size,
struct spa_error_location *loc);
struct pw_properties *
pw_properties_copy(const struct pw_properties *properties);
@ -51,10 +60,14 @@ int pw_properties_update_ignore(struct pw_properties *props,
/* Update props with all key/value pairs from dict */
int pw_properties_update(struct pw_properties *props,
const struct spa_dict *dict);
/* Update props with all key/value pairs from str */
int pw_properties_update_string(struct pw_properties *props,
const char *str, size_t size);
int pw_properties_update_string_checked(struct pw_properties *props,
const char *str, size_t size, struct spa_error_location *loc);
int pw_properties_add(struct pw_properties *oldprops,
const struct spa_dict *dict);
int pw_properties_add_keys(struct pw_properties *oldprops,
@ -92,7 +105,7 @@ pw_properties_fetch_int64(const struct pw_properties *properties, const char *ke
int
pw_properties_fetch_bool(const struct pw_properties *properties, const char *key, bool *value);
static inline uint32_t
PW_API_PROPERTIES uint32_t
pw_properties_get_uint32(const struct pw_properties *properties, const char *key, uint32_t deflt)
{
uint32_t val = deflt;
@ -100,7 +113,7 @@ pw_properties_get_uint32(const struct pw_properties *properties, const char *key
return val;
}
static inline int32_t
PW_API_PROPERTIES int32_t
pw_properties_get_int32(const struct pw_properties *properties, const char *key, int32_t deflt)
{
int32_t val = deflt;
@ -108,7 +121,7 @@ pw_properties_get_int32(const struct pw_properties *properties, const char *key,
return val;
}
static inline uint64_t
PW_API_PROPERTIES uint64_t
pw_properties_get_uint64(const struct pw_properties *properties, const char *key, uint64_t deflt)
{
uint64_t val = deflt;
@ -116,7 +129,7 @@ pw_properties_get_uint64(const struct pw_properties *properties, const char *key
return val;
}
static inline int64_t
PW_API_PROPERTIES int64_t
pw_properties_get_int64(const struct pw_properties *properties, const char *key, int64_t deflt)
{
int64_t val = deflt;
@ -125,7 +138,7 @@ pw_properties_get_int64(const struct pw_properties *properties, const char *key,
}
static inline bool
PW_API_PROPERTIES bool
pw_properties_get_bool(const struct pw_properties *properties, const char *key, bool deflt)
{
bool val = deflt;
@ -136,34 +149,38 @@ pw_properties_get_bool(const struct pw_properties *properties, const char *key,
const char *
pw_properties_iterate(const struct pw_properties *properties, void **state);
#define PW_PROPERTIES_FLAG_NL (1<<0)
#define PW_PROPERTIES_FLAG_NL (1<<0)
#define PW_PROPERTIES_FLAG_RECURSE (1<<1)
#define PW_PROPERTIES_FLAG_ENCLOSE (1<<2)
#define PW_PROPERTIES_FLAG_ARRAY (1<<3)
#define PW_PROPERTIES_FLAG_COLORS (1<<4)
int pw_properties_serialize_dict(FILE *f, const struct spa_dict *dict, uint32_t flags);
static inline bool pw_properties_parse_bool(const char *value) {
PW_API_PROPERTIES bool pw_properties_parse_bool(const char *value) {
return spa_atob(value);
}
static inline int pw_properties_parse_int(const char *value) {
PW_API_PROPERTIES int pw_properties_parse_int(const char *value) {
int v;
return spa_atoi32(value, &v, 0) ? v: 0;
}
static inline int64_t pw_properties_parse_int64(const char *value) {
PW_API_PROPERTIES int64_t pw_properties_parse_int64(const char *value) {
int64_t v;
return spa_atoi64(value, &v, 0) ? v : 0;
}
static inline uint64_t pw_properties_parse_uint64(const char *value) {
PW_API_PROPERTIES uint64_t pw_properties_parse_uint64(const char *value) {
uint64_t v;
return spa_atou64(value, &v, 0) ? v : 0;
}
static inline float pw_properties_parse_float(const char *value) {
PW_API_PROPERTIES float pw_properties_parse_float(const char *value) {
float v;
return spa_atof(value, &v) ? v : 0.0f;
}
static inline double pw_properties_parse_double(const char *value) {
PW_API_PROPERTIES double pw_properties_parse_double(const char *value) {
double v;
return spa_atod(value, &v) ? v : 0.0;
}
@ -172,6 +189,10 @@ static inline double pw_properties_parse_double(const char *value) {
* \}
*/
SPA_DEFINE_AUTOPTR_CLEANUP(pw_properties, struct pw_properties, {
spa_clear_ptr(*thing, pw_properties_free);
})
#ifdef __cplusplus
}
#endif

View File

@ -81,7 +81,7 @@ struct pw_protocol_marshal {
};
struct pw_protocol_implementation {
#define PW_VERSION_PROTOCOL_IMPLEMENTATION 0
#define PW_VERSION_PROTOCOL_IMPLEMENTATION 1
uint32_t version;
struct pw_protocol_client * (*new_client) (struct pw_protocol *protocol,
@ -90,6 +90,10 @@ struct pw_protocol_implementation {
struct pw_protocol_server * (*add_server) (struct pw_protocol *protocol,
struct pw_impl_core *core,
const struct spa_dict *props);
struct pw_protocol_server * (*add_fd_server) (struct pw_protocol *protocol,
struct pw_impl_core *core,
int listen_fd, int close_fd,
const struct spa_dict *props);
};
struct pw_protocol_events {
@ -101,6 +105,7 @@ struct pw_protocol_events {
#define pw_protocol_new_client(p,...) (pw_protocol_get_implementation(p)->new_client(p,__VA_ARGS__))
#define pw_protocol_add_server(p,...) (pw_protocol_get_implementation(p)->add_server(p,__VA_ARGS__))
#define pw_protocol_add_fd_server(p,...) (pw_protocol_get_implementation(p)->add_fd_server(p,__VA_ARGS__))
#define pw_protocol_ext(p,type,method,...) (((type*)pw_protocol_get_extension(p))->method( __VA_ARGS__))
struct pw_protocol *pw_protocol_new(struct pw_context *context, const char *name, size_t user_data_size);

View File

@ -12,6 +12,8 @@ extern "C" {
#include <spa/utils/hook.h>
/** \page page_proxy Proxy
*
* \see \ref pw_proxy
*
* \section sec_page_proxy_overview Overview
*
@ -76,7 +78,7 @@ extern "C" {
* invoked by the client to PipeWire messages. Events will call the handlers
* set in listener.
*
* See \ref page_proxy
* \see \ref page_proxy
*/
/**

View File

@ -10,6 +10,8 @@ extern "C" {
#endif
/** \page page_streams Streams
*
* \see \ref pw_stream
*
* \section sec_overview Overview
*
@ -56,11 +58,15 @@ extern "C" {
* \li PW_DIRECTION_INPUT for a stream that *consumes* data. This can be a
* stream that captures from a Source or a when the stream is used to
* implement a Sink.
* implement a Sink. An application will use a \ref PW_DIRECTION_INPUT
* stream to record data. A virtual sound card will use a
* \ref PW_DIRECTION_INPUT stream to implement audio playback.
*
* \li PW_DIRECTION_OUTPUT for a stream that *produces* data. This can be a
* stream that plays to a Sink or when the stream is used to implement
* a Source.
* a Source. An application will use a \ref PW_DIRECTION_OUTPUT
* stream to produce data. A virtual sound card or camera will use a
* \ref PW_DIRECTION_OUTPUT stream to implement audio or video recording.
*
* \subsection ssec_stream_target Stream target
*
@ -127,8 +133,25 @@ extern "C" {
* When the buffer has been processed, call \ref pw_stream_queue_buffer()
* to let PipeWire reuse the buffer.
*
* Although not strictly required, it is recommended to call \ref
* pw_stream_dequeue_buffer() and pw_stream_queue_buffer() from the
* process() callback to minimize the amount of buffering and
* maximize the amount of buffer reuse in the stream.
*
* It is also possible to dequeue the buffer from the process event,
* then process and queue the buffer from a helper thread. It is also
* possible to dequeue, process and queue a buffer from a helper thread
* after receiving the process event.
*
* \subsection ssec_produce Produce data
*
* The process event is emitted when a new buffer should be queued.
*
* When the PW_STREAM_FLAG_RT_PROCESS flag was given, this function will be
* called from a realtime thread and it is not safe to call non-reatime
* functions such as doing file operations, blocking operations or any of
* the PipeWire functions that are not explicitly marked as being RT safe.
*
* \ref pw_stream_dequeue_buffer() gives an empty buffer that can be filled.
*
* The buffer is owned by the stream and stays alive until the
@ -136,8 +159,45 @@ extern "C" {
*
* Filled buffers should be queued with \ref pw_stream_queue_buffer().
*
* The process event is emitted when PipeWire has emptied a buffer that
* can now be refilled.
* Although not strictly required, it is recommended to call \ref
* pw_stream_dequeue_buffer() and pw_stream_queue_buffer() from the
* process() callback to minimize the amount of buffering and
* maximize the amount of buffer reuse in the stream.
*
* Buffers that are queued after the process event completes will be delayed
* to the next processing cycle.
*
* \section sec_stream_driving Driving the graph
*
* Starting in 0.3.34, it is possible for a stream to drive the graph.
* This allows interrupt-driven scheduling for drivers implemented as
* PipeWire streams, without having to reimplement the stream as a SPA
* plugin.
*
* A stream cannot drive the graph unless it is in the
* \ref PW_STREAM_STATE_STREAMING state and \ref pw_stream_is_driving() returns
* true. It must then use pw_stream_trigger_process() to start the graph
* cycle.
*
* \ref pw_stream_trigger_process() will result in a process event, where a buffer
* should be dequeued, and queued again. This is the recommended behaviour that
* minimizes buffering and maximized buffer reuse.
*
* Producers of data that drive the graph can also dequeue a buffer in a helper
* thread, fill it with data and then call \ref pw_stream_trigger_process() to
* start the graph cycle. In the process event they will then queue the filled
* buffer and dequeue a new empty buffer to fill again in the helper thread,
*
* Consumers of data that drive the graph (pull based scheduling) will use
* \ref pw_stream_trigger_process() to start the graph and will dequeue, process
* and queue the buffers in the process event.
*
* \section sec_stream_process_requests Request processing
*
* A stream that is not driving the graph can request a new graph cycle by doing
* \ref pw_stream_trigger_process(). This will result in a RequestProcess command
* in the driver stream. If the driver supports this, it can then perform
* \ref pw_stream_trigger_process() to start the actual graph cycle.
*
* \section sec_stream_disconnect Disconnect
*
@ -151,6 +211,9 @@ extern "C" {
*
* \section sec_stream_environment Environment Variables
*
* The environment variable PIPEWIRE_AUTOCONNECT can be used to override the
* flag and force apps to autoconnect or not.
*
*/
/** \defgroup pw_stream Stream
*
@ -159,7 +222,7 @@ extern "C" {
* The stream object provides a convenient way to send and
* receive data streams from/to PipeWire.
*
* See also \ref page_streams and \ref api_pw_core
* \see \ref page_streams, \ref api_pw_core
*/
/**
@ -171,6 +234,7 @@ struct pw_stream;
#include <spa/buffer/buffer.h>
#include <spa/param/param.h>
#include <spa/pod/command.h>
#include <spa/pod/event.h>
/** \enum pw_stream_state The state of a stream */
enum pw_stream_state {
@ -182,19 +246,29 @@ enum pw_stream_state {
};
/** a buffer structure obtained from pw_stream_dequeue_buffer(). The size of this
* structure can grow as more field are added in the future */
* structure can grow as more fields are added in the future */
struct pw_buffer {
struct spa_buffer *buffer; /**< the spa buffer */
void *user_data; /**< user data attached to the buffer */
void *user_data; /**< user data attached to the buffer. The user of
* the stream can set custom data associated with the
* buffer, typically in the add_buffer event. Any
* cleanup should be performed in the remove_buffer
* event. The user data is returned unmodified each
* time a buffer is dequeued. */
uint64_t size; /**< This field is set by the user and the sum of
* all queued buffer is returned in the time info.
* all queued buffers is returned in the time info.
* For audio, it is advised to use the number of
* samples in the buffer for this field. */
* frames in the buffer for this field. */
uint64_t requested; /**< For playback streams, this field contains the
* suggested amount of data to provide. For audio
* streams this will be the amount of samples
* streams this will be the amount of frames
* required by the resampler. This field is 0
* when no suggestion is provided. Since 0.3.49 */
uint64_t time; /**< For capture streams, this field contains the
* cycle time in nanoseconds when this buffer was
* queued in the stream. It can be compared against
* the pw_time values or pw_stream_get_nsec()
* Since 1.0.5 */
};
struct pw_stream_control {
@ -223,25 +297,33 @@ struct pw_stream_control {
* value, and pw_time.ticks, were captured at pw_time.now and can be extrapolated
* to the current time like this:
*
* struct timespec ts;
* clock_gettime(CLOCK_MONOTONIC, &ts);
* int64_t diff = SPA_TIMESPEC_TO_NSEC(&ts) - pw_time.now;
*\code{.c}
* uint64_t now = pw_stream_get_nsec(stream);
* int64_t diff = now - pw_time.now;
* int64_t elapsed = (pw_time.rate.denom * diff) / (pw_time.rate.num * SPA_NSEC_PER_SEC);
*\endcode
*
* pw_time.delay contains the total delay that a signal will travel through the
* graph. This includes the delay caused by filters in the graph as well as delays
* caused by the hardware. The delay is usually quite stable and should only change when
* the topology, quantum or samplerate of the graph changes.
*
* The delay requires the application to send the stream early relative to other synchronized
* streams in order to arrive at the edge of the graph in time. This is usually done by
* delaying the other streams with the given delay.
*
* Note that the delay can be negative. A negative delay means that this stream should be
* delayed with the (positive) delay relative to other streams.
*
* pw_time.queued and pw_time.buffered is expressed in the time domain of the stream,
* or the format that is used for the buffers of this stream.
*
* pw_time.queued is the sum of all the pw_buffer.size fields of the buffers that are
* currently queued in the stream but not yet processed. The application can choose
* the units of this value, for example, time, samples or bytes (below expressed
* as app.rate).
* the units of this value, for example, time, samples, frames or bytes (below
* expressed as app.rate).
*
* pw_time.buffered is format dependent, for audio/raw it contains the number of samples
* pw_time.buffered is format dependent, for audio/raw it contains the number of frames
* that are buffered inside the resampler/converter.
*
* The total delay of data in a stream is the sum of the queued and buffered data
@ -252,15 +334,21 @@ struct pw_stream_control {
* in milliseconds for the first sample in the newly queued buffer to be played
* by the hardware can be calculated as:
*
*\code{.unparsed}
* (pw_time.buffered * 1000 / stream.samplerate) +
* (pw_time.queued * 1000 / app.rate) +
* ((pw_time.delay - elapsed) * 1000 * pw_time.rate.num / pw_time.rate.denom)
*\endcode
*
* The current extrapolated time (in ms) in the source or sink can be calculated as:
*
*\code{.unparsed}
* (pw_time.ticks + elapsed) * 1000 * pw_time.rate.num / pw_time.rate.denom
*\endcode
*
* Below is an overview of the different timing values:
*
*\code{.unparsed}
* stream time domain graph time domain
* /-----------------------\/-----------------------------\
*
@ -272,14 +360,15 @@ struct pw_stream_control {
* latency latency
* \--------/\-------------/\-----------------------------/
* queued buffered delay
*\endcode
*/
struct pw_time {
int64_t now; /**< the monotonic time in nanoseconds. This is the time
* when this time report was updated. It is usually
* updated every graph cycle. You can use the current
* monotonic time to calculate the elapsed time between
* this report and the current state and calculate
* updated ticks and delay values. */
int64_t now; /**< the time in nanoseconds. This is the time when this
* time report was updated. It is usually updated every
* graph cycle. You can use pw_stream_get_nsec() to
* calculate the elapsed time between this report and
* the current time and calculate updated ticks and delay
* values. */
struct spa_fraction rate; /**< the rate of \a ticks and delay. This is usually
* expressed in 1/<samplerate>. */
uint64_t ticks; /**< the ticks at \a now. This is the current time that
@ -298,10 +387,14 @@ struct pw_time {
* of the size fields in the pw_buffer that are
* currently queued */
uint64_t buffered; /**< for audio/raw streams, this contains the extra
* number of samples buffered in the resampler.
* number of frames buffered in the resampler.
* Since 0.3.50. */
uint32_t queued_buffers; /**< The number of buffers that are queued. Since 0.3.50 */
uint32_t avail_buffers; /**< The number of buffers that can be dequeued. Since 0.3.50 */
uint32_t queued_buffers; /**< the number of buffers that are queued. Since 0.3.50 */
uint32_t avail_buffers; /**< the number of buffers that can be dequeued. Since 0.3.50 */
uint64_t size; /**< for audio/raw playback streams, this contains the number of
* samples requested by the resampler for the current
* quantum. for audio/raw capture streams this will be the number
* of samples available for the current quantum. Since 1.1.0 */
};
#include <pipewire/port.h>
@ -342,7 +435,10 @@ struct pw_stream_events {
/** A command notify, Since 0.3.39:1 */
void (*command) (void *data, const struct spa_command *command);
/** a trigger_process completed. Since version 0.3.40:2 */
/** a trigger_process completed. Since version 0.3.40:2.
* This is normally called from the mainloop but since 1.1.0 it
* can also be called directly from the realtime data
* thread if the user is prepared to deal with this. */
void (*trigger_done) (void *data);
};
@ -357,7 +453,8 @@ enum pw_stream_flags {
PW_STREAM_FLAG_INACTIVE = (1 << 1), /**< start the stream inactive,
* pw_stream_set_active() needs to be
* called explicitly */
PW_STREAM_FLAG_MAP_BUFFERS = (1 << 2), /**< mmap the buffers except DmaBuf */
PW_STREAM_FLAG_MAP_BUFFERS = (1 << 2), /**< mmap the buffers except DmaBuf that is not
* explicitly marked as mappable. */
PW_STREAM_FLAG_DRIVER = (1 << 3), /**< be a driver */
PW_STREAM_FLAG_RT_PROCESS = (1 << 4), /**< call process from the realtime
* thread. You MUST use RT safe functions
@ -375,9 +472,24 @@ enum pw_stream_flags {
* needs to be called. This can be used
* when the output of the stream depends
* on input from other streams. */
PW_STREAM_FLAG_ASYNC = (1 << 10), /**< Buffers will not be dequeued/queued from
* the realtime process() function. This is
* assumed when RT_PROCESS is unset but can
* also be the case when the process() function
* does a trigger_process() that will then
* dequeue/queue a buffer from another process()
* function. since 0.3.73 */
PW_STREAM_FLAG_EARLY_PROCESS = (1 << 11), /**< Call process as soon as there is a buffer
* to dequeue. This is only relevant for
* playback and when not using RT_PROCESS. It
* can be used to keep the maximum number of
* buffers queued. Since 0.3.81 */
PW_STREAM_FLAG_RT_TRIGGER_DONE = (1 << 12), /**< Call trigger_done from the realtime
* thread. You MUST use RT safe functions
* in the trigger_done callback. Since 1.1.0 */
};
/** Create a new unconneced \ref pw_stream
/** Create a new unconnected \ref pw_stream
* \return a newly allocated \ref pw_stream */
struct pw_stream *
pw_stream_new(struct pw_core *core, /**< a \ref pw_core */
@ -385,7 +497,7 @@ pw_stream_new(struct pw_core *core, /**< a \ref pw_core */
struct pw_properties *props /**< stream properties, ownership is taken */);
struct pw_stream *
pw_stream_new_simple(struct pw_loop *loop, /**< a \ref pw_loop to use */
pw_stream_new_simple(struct pw_loop *loop, /**< a \ref pw_loop to use as the main loop */
const char *name, /**< a stream media name */
struct pw_properties *props,/**< stream properties, ownership is taken */
const struct pw_stream_events *events, /**< stream events */
@ -447,45 +559,62 @@ int pw_stream_set_error(struct pw_stream *stream, /**< a \ref pw_stream */
const char *error, /**< an error message */
...) SPA_PRINTF_FUNC(3, 4);
/** Complete the negotiation process with result code \a res
*
* This function should be called after notification of the format.
* When \a res indicates success, \a params contain the parameters for the
* allocation state. */
/** Update the param exposed on the stream. */
int
pw_stream_update_params(struct pw_stream *stream, /**< a \ref pw_stream */
const struct spa_pod **params, /**< an array of params. The params should
* ideally contain parameters for doing
* buffer allocation. */
const struct spa_pod **params, /**< an array of params. */
uint32_t n_params /**< number of elements in \a params */);
/**
* Set a parameter on the stream. This is like pw_stream_set_control() but with
* a complete spa_pod param. It can also be called from the param_changed event handler
* to intercept and modify the param for the adapter. Since 0.3.70 */
int pw_stream_set_param(struct pw_stream *stream, /**< a \ref pw_stream */
uint32_t id, /**< the id of the param */
const struct spa_pod *param /**< the params to set */);
/** Get control values */
const struct pw_stream_control *pw_stream_get_control(struct pw_stream *stream, uint32_t id);
/** Set control values */
int pw_stream_set_control(struct pw_stream *stream, uint32_t id, uint32_t n_values, float *values, ...);
/** Query the time on the stream */
/** Query the time on the stream, RT safe */
int pw_stream_get_time_n(struct pw_stream *stream, struct pw_time *time, size_t size);
/** Get the current time in nanoseconds. This value can be compared with
* the \ref pw_time.now value. RT safe. Since 1.1.0 */
uint64_t pw_stream_get_nsec(struct pw_stream *stream);
/** Get the data loop that is doing the processing of this stream. This loop
* is assigned after pw_stream_connect(). * Since 1.1.0 */
struct pw_loop *pw_stream_get_data_loop(struct pw_stream *stream);
/** Query the time on the stream, deprecated since 0.3.50,
* use pw_stream_get_time_n() to get the fields added since 0.3.50. */
* use pw_stream_get_time_n() to get the fields added since 0.3.50. RT safe. */
SPA_DEPRECATED
int pw_stream_get_time(struct pw_stream *stream, struct pw_time *time);
/** Get a buffer that can be filled for playback streams or consumed
* for capture streams. */
* for capture streams. RT safe. */
struct pw_buffer *pw_stream_dequeue_buffer(struct pw_stream *stream);
/** Submit a buffer for playback or recycle a buffer for capture. */
/** Submit a buffer for playback or recycle a buffer for capture. RT safe. */
int pw_stream_queue_buffer(struct pw_stream *stream, struct pw_buffer *buffer);
/** Return a buffer to the queue without using it. This makes the buffer
* immediately available to dequeue again. RT safe. */
int pw_stream_return_buffer(struct pw_stream *stream, struct pw_buffer *buffer);
/** Activate or deactivate the stream */
int pw_stream_set_active(struct pw_stream *stream, bool active);
/** Flush a stream. When \a drain is true, the drained callback will
* be called when all data is played or recorded */
* be called when all data is played or recorded. The stream can be resumed
* after the drain by setting it active again with
* \ref pw_stream_set_active(). A flush without a drain is mostly useful afer
* a state change to PAUSED, to flush any remaining data from the queues and
* the converters. RT safe. */
int pw_stream_flush(struct pw_stream *stream, bool drain);
/** Check if the stream is driving. The stream needs to have the
@ -494,10 +623,64 @@ int pw_stream_flush(struct pw_stream *stream, bool drain);
* available (output) or needed (input). Since 0.3.34 */
bool pw_stream_is_driving(struct pw_stream *stream);
/** Check if the graph is using lazy scheduling. If the stream is
* driving according to \ref pw_stream_is_driving(), then it should
* consider taking into account the RequestProcess commands when
* driving the graph.
*
* If the stream is not driving, it should send out RequestProcess
* events with \ref pw_stream_emit_event() or indirectly with
* \ref pw_stream_trigger_process() to suggest a new graph cycle
* to the driver.
*
* It is not a requirement that all RequestProcess events/commands
* need to start a graph cycle.
* Since 1.4.0 */
bool pw_stream_is_lazy(struct pw_stream *stream);
/** Trigger a push/pull on the stream. One iteration of the graph will
* scheduled and process() will be called. Since 0.3.34 */
* be scheduled when the stream is driving according to
* \ref pw_stream_is_driving(). If it successfully finishes, process()
* will be called and the trigger_done event will be emitted. It is
* possible for the graph iteration to not finish, so
* pw_stream_trigger_process() needs to be called again even if process()
* and trigger_done is not called.
*
* If there is a deadline after which the stream will have xrun,
* pw_stream_trigger_process() should be called then, whether or not
* process()/trigger_done has been called. Sound hardware will xrun if
* there is any delay in audio processing, so the ALSA plugin triggers the
* graph every quantum to ensure audio keeps flowing. Drivers that
* do not have a deadline, such as the freewheel driver, should
* use a timeout to ensure that forward progress keeps being made.
* A reasonable choice of deadline is three times the quantum: if
* the graph is taking 3x longer than normal, it is likely that it
* is hung and should be retriggered.
*
* Streams that are not drivers according to \ref pw_stream_is_driving()
* can also call this method. The result is that a RequestProcess event
* is sent to the driver. If the graph is lazy scheduling according to
* \ref pw_stream_is_lazy(), this might result in a graph cycle by the
* driver. If the graph is not lazy scheduling and the stream is not a
* driver, this method will have no effect.
*
* RT safe.
*
* Since 0.3.34 */
int pw_stream_trigger_process(struct pw_stream *stream);
/** Emit an event from this stream. RT safe.
* Since 1.2.6 */
int pw_stream_emit_event(struct pw_stream *stream, const struct spa_event *event);
/** Adjust the rate of the stream.
* When the stream is using an adaptive resampler, adjust the resampler rate.
* When there is no resampler, -ENOTSUP is returned. Activating the adaptive
* resampler will add a small amount of delay to the samples, you can deactivate
* it again by setting a value <= 0.0. RT safe.
* Since 1.4.0 */
int pw_stream_set_rate(struct pw_stream *stream, double rate);
/**
* \}
*/

View File

@ -0,0 +1,45 @@
/* PipeWire */
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#ifndef PIPEWIRE_TYPE_H
#define PIPEWIRE_TYPE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <spa/utils/type.h>
/** \defgroup pw_type Type info
* Type information
*/
/**
* \addtogroup pw_type
* \{
*/
enum {
PW_TYPE_FIRST = SPA_TYPE_VENDOR_PipeWire,
};
#define PW_TYPE_INFO_BASE "PipeWire:"
#define PW_TYPE_INFO_Object PW_TYPE_INFO_BASE "Object"
#define PW_TYPE_INFO_OBJECT_BASE PW_TYPE_INFO_Object ":"
#define PW_TYPE_INFO_Interface PW_TYPE_INFO_BASE "Interface"
#define PW_TYPE_INFO_INTERFACE_BASE PW_TYPE_INFO_Interface ":"
const struct spa_type_info * pw_type_info(void);
/**
* \}
*/
#ifdef __cplusplus
}
#endif
#endif /* PIPEWIRE_TYPE_H */

View File

@ -15,11 +15,13 @@ extern "C" {
#ifndef _POSIX_C_SOURCE
# include <sys/mount.h>
#endif
#include <errno.h>
#ifndef ENODATA
#define ENODATA 9919
#endif
#include <spa/utils/cleanup.h>
#include <spa/utils/defs.h>
#include <spa/pod/pod.h>
@ -45,6 +47,12 @@ pw_split_strv(const char *str, const char *delimiter, int max_tokens, int *n_tok
int
pw_split_ip(char *str, const char *delimiter, int max_tokens, char *tokens[]);
char **pw_strv_parse(const char *val, size_t len, int max_tokens, int *n_tokens);
int pw_strv_find(char **a, const char *b);
int pw_strv_find_common(char **a, char **b);
void
pw_free_strv(char **str);
@ -92,6 +100,10 @@ void* pw_reallocarray(void *ptr, size_t nmemb, size_t size);
* \}
*/
SPA_DEFINE_AUTO_CLEANUP(pw_strv, char **, {
spa_clear_ptr(*thing, pw_free_strv);
})
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@ -12,6 +12,14 @@ extern "C" {
#include <spa/utils/defs.h>
#include <spa/buffer/meta.h>
#ifndef SPA_API_BUFFER
#ifdef SPA_API_IMPL
#define SPA_API_BUFFER SPA_API_IMPL
#else
#define SPA_API_BUFFER static inline
#endif
#endif
/** \defgroup spa_buffer Buffers
*
* Buffers describe the data and metadata that is exchanged between
@ -27,9 +35,15 @@ enum spa_data_type {
SPA_DATA_Invalid,
SPA_DATA_MemPtr, /**< pointer to memory, the data field in
* struct spa_data is set. */
SPA_DATA_MemFd, /**< generic fd, mmap to get to memory */
SPA_DATA_DmaBuf, /**< fd to dmabuf memory */
SPA_DATA_MemId, /**< memory is identified with an id */
SPA_DATA_MemFd, /**< memfd, mmap to get to memory. */
SPA_DATA_DmaBuf, /**< fd to dmabuf memory. This might not be readily
* mappable (unless the MAPPABLE flag is set) and should
* normally be handled with DMABUF apis. */
SPA_DATA_MemId, /**< memory is identified with an id. The actual memory
* can be obtained in some other way and can be identified
* with this id. */
SPA_DATA_SyncObj, /**< a syncobj, usually requires a spa_meta_sync_timeline metadata
* with timeline points. */
_SPA_DATA_LAST, /**< not part of ABI */
};
@ -65,9 +79,12 @@ struct spa_data {
#define SPA_DATA_FLAG_WRITABLE (1u<<1) /**< data is writable */
#define SPA_DATA_FLAG_DYNAMIC (1u<<2) /**< data pointer can be changed */
#define SPA_DATA_FLAG_READWRITE (SPA_DATA_FLAG_READABLE|SPA_DATA_FLAG_WRITABLE)
#define SPA_DATA_FLAG_MAPPABLE (1u<<3) /**< data is mappable with simple mmap/munmap. Some memory
* types are not simply mappable (DmaBuf) unless explicitly
* specified with this flag. */
uint32_t flags; /**< data flags */
int64_t fd; /**< optional fd for data */
uint32_t mapoffset; /**< offset to map fd at */
uint32_t mapoffset; /**< offset to map fd at, this is page aligned */
uint32_t maxsize; /**< max size of data */
void *data; /**< optional data pointer */
struct spa_chunk *chunk; /**< valid chunk of memory */
@ -82,7 +99,7 @@ struct spa_buffer {
};
/** Find metadata in a buffer */
static inline struct spa_meta *spa_buffer_find_meta(const struct spa_buffer *b, uint32_t type)
SPA_API_BUFFER struct spa_meta *spa_buffer_find_meta(const struct spa_buffer *b, uint32_t type)
{
uint32_t i;
@ -93,7 +110,7 @@ static inline struct spa_meta *spa_buffer_find_meta(const struct spa_buffer *b,
return NULL;
}
static inline void *spa_buffer_find_meta_data(const struct spa_buffer *b, uint32_t type, size_t size)
SPA_API_BUFFER void *spa_buffer_find_meta_data(const struct spa_buffer *b, uint32_t type, size_t size)
{
struct spa_meta *m;
if ((m = spa_buffer_find_meta(b, type)) && m->size >= size)

View File

@ -12,6 +12,14 @@ extern "C" {
#include <spa/utils/defs.h>
#include <spa/pod/pod.h>
#ifndef SPA_API_META
#ifdef SPA_API_IMPL
#define SPA_API_META SPA_API_IMPL
#else
#define SPA_API_META static inline
#endif
#endif
/**
* \addtogroup spa_buffer
* \{
@ -28,6 +36,7 @@ enum spa_meta_type {
* associated with the data */
SPA_META_Busy, /**< don't write to buffer when count > 0 */
SPA_META_VideoTransform, /**< struct spa_meta_transform */
SPA_META_SyncTimeline, /**< struct spa_meta_sync_timeline */
_SPA_META_LAST, /**< not part of ABI/API */
};
@ -45,14 +54,13 @@ struct spa_meta {
void *data; /**< pointer to metadata */
};
static inline void *spa_meta_first(const struct spa_meta *m) {
SPA_API_META void *spa_meta_first(const struct spa_meta *m) {
return m->data;
}
#define spa_meta_first spa_meta_first
static inline void *spa_meta_end(const struct spa_meta *m) {
SPA_API_META void *spa_meta_end(const struct spa_meta *m) {
return SPA_PTROFF(m->data,m->size,void);
}
#define spa_meta_end spa_meta_end
#define spa_meta_check(p,m) (SPA_PTROFF(p,sizeof(*(p)),void) <= spa_meta_end(m))
/**
@ -79,19 +87,16 @@ struct spa_meta_region {
struct spa_region region;
};
static inline bool spa_meta_region_is_valid(const struct spa_meta_region *m) {
SPA_API_META bool spa_meta_region_is_valid(const struct spa_meta_region *m) {
return m->region.size.width != 0 && m->region.size.height != 0;
}
#define spa_meta_region_is_valid spa_meta_region_is_valid
/** iterate all the items in a metadata */
#define spa_meta_for_each(pos,meta) \
for ((pos) = (__typeof(pos))spa_meta_first(meta); \
for ((pos) = (__typeof(pos))spa_meta_first(meta); \
spa_meta_check(pos, meta); \
(pos)++)
#define spa_meta_bitmap_is_valid(m) ((m)->format != 0)
/**
* Bitmap information
*
@ -111,7 +116,9 @@ struct spa_meta_bitmap {
* info. */
};
#define spa_meta_cursor_is_valid(m) ((m)->id != 0)
SPA_API_META bool spa_meta_bitmap_is_valid(const struct spa_meta_bitmap *m) {
return m->format != 0;
}
/**
* Cursor information
@ -131,6 +138,10 @@ struct spa_meta_cursor {
* struct spa_meta_bitmap at the offset. */
};
SPA_API_META bool spa_meta_cursor_is_valid(const struct spa_meta_cursor *m) {
return m->id != 0;
}
/** a timed set of events associated with the buffer */
struct spa_meta_control {
struct spa_pod_sequence sequence;
@ -149,7 +160,7 @@ enum spa_meta_videotransform_value {
SPA_META_TRANSFORMATION_270, /**< 270 degree counter-clockwise */
SPA_META_TRANSFORMATION_Flipped, /**< 180 degree flipped around the vertical axis. Equivalent
* to a reflexion through the vertical line splitting the
* bufffer in two equal sized parts */
* buffer in two equal sized parts */
SPA_META_TRANSFORMATION_Flipped90, /**< flip then rotate around 90 degree counter-clockwise */
SPA_META_TRANSFORMATION_Flipped180, /**< flip then rotate around 180 degree counter-clockwise */
SPA_META_TRANSFORMATION_Flipped270, /**< flip then rotate around 270 degree counter-clockwise */
@ -161,6 +172,26 @@ struct spa_meta_videotransform {
* one of enum spa_meta_videotransform_value */
};
/**
* A timeline point for explicit sync
*
* Metadata to describe the time on the timeline when the buffer
* can be acquired and when it can be reused.
*
* This metadata will require negotiation of 2 extra fds for the acquire
* and release timelines respectively. One way to achieve this is to place
* this metadata as SPA_PARAM_BUFFERS_metaType when negotiating a buffer
* layout with 2 extra fds.
*/
struct spa_meta_sync_timeline {
uint32_t flags;
uint32_t padding;
uint64_t acquire_point; /**< the timeline acquire point, this is when the data
* can be accessed. */
uint64_t release_point; /**< the timeline release point, this timeline point should
* be signaled when the data is no longer accessed. */
};
/**
* \}
*/

View File

@ -35,6 +35,7 @@ static const struct spa_type_info spa_type_data_type[] = {
{ SPA_DATA_MemFd, SPA_TYPE_Int, SPA_TYPE_INFO_DATA_FD_BASE "MemFd", NULL },
{ SPA_DATA_DmaBuf, SPA_TYPE_Int, SPA_TYPE_INFO_DATA_FD_BASE "DmaBuf", NULL },
{ SPA_DATA_MemId, SPA_TYPE_Int, SPA_TYPE_INFO_DATA_BASE "MemId", NULL },
{ SPA_DATA_SyncObj, SPA_TYPE_Int, SPA_TYPE_INFO_DATA_BASE "SyncObj", NULL },
{ 0, 0, NULL, NULL },
};
@ -50,6 +51,22 @@ static const struct spa_type_info spa_type_data_type[] = {
#define SPA_TYPE_INFO_META_ARRAY_Region SPA_TYPE_INFO_META_ARRAY_BASE "Region"
#define SPA_TYPE_INFO_META_ARRAY_REGION_BASE SPA_TYPE_INFO_META_ARRAY_Region ":"
/* VideoTransform meta */
#define SPA_TYPE_INFO_META_Transformation SPA_TYPE_INFO_ENUM_BASE "Meta:Transformation"
#define SPA_TYPE_INFO_META_TRANSFORMATION_BASE SPA_TYPE_INFO_META_Transformation ":"
static const struct spa_type_info spa_type_meta_videotransform_type[] = {
{ SPA_META_TRANSFORMATION_None, SPA_TYPE_Int, SPA_TYPE_INFO_META_TRANSFORMATION_BASE "None", NULL },
{ SPA_META_TRANSFORMATION_90, SPA_TYPE_Int, SPA_TYPE_INFO_META_TRANSFORMATION_BASE "90", NULL },
{ SPA_META_TRANSFORMATION_180, SPA_TYPE_Int, SPA_TYPE_INFO_META_TRANSFORMATION_BASE "180", NULL },
{ SPA_META_TRANSFORMATION_270, SPA_TYPE_Int, SPA_TYPE_INFO_META_TRANSFORMATION_BASE "270", NULL },
{ SPA_META_TRANSFORMATION_Flipped, SPA_TYPE_Int, SPA_TYPE_INFO_META_TRANSFORMATION_BASE "Flipped", NULL },
{ SPA_META_TRANSFORMATION_Flipped90, SPA_TYPE_Int, SPA_TYPE_INFO_META_TRANSFORMATION_BASE "Flipped90", NULL },
{ SPA_META_TRANSFORMATION_Flipped180, SPA_TYPE_Int, SPA_TYPE_INFO_META_TRANSFORMATION_BASE "Flipped180", NULL },
{ SPA_META_TRANSFORMATION_Flipped270, SPA_TYPE_Int, SPA_TYPE_INFO_META_TRANSFORMATION_BASE "Flipped270", NULL },
{ 0, 0, NULL, NULL },
};
static const struct spa_type_info spa_type_meta_type[] = {
{ SPA_META_Invalid, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Invalid", NULL },
{ SPA_META_Header, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Header", NULL },
@ -60,6 +77,7 @@ static const struct spa_type_info spa_type_meta_type[] = {
{ SPA_META_Control, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Control", NULL },
{ SPA_META_Busy, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Busy", NULL },
{ SPA_META_VideoTransform, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "VideoTransform", NULL },
{ SPA_META_SyncTimeline, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "SyncTimeline", NULL },
{ 0, 0, NULL, NULL },
};

View File

@ -24,9 +24,12 @@ extern "C" {
/** Different Control types */
enum spa_control_type {
SPA_CONTROL_Invalid,
SPA_CONTROL_Properties, /**< data contains a SPA_TYPE_OBJECT_Props */
SPA_CONTROL_Midi, /**< data contains a spa_pod_bytes with raw midi data */
SPA_CONTROL_OSC, /**< data contains a spa_pod_bytes with an OSC packet */
SPA_CONTROL_Properties, /**< SPA_TYPE_OBJECT_Props */
SPA_CONTROL_Midi, /**< spa_pod_bytes with raw midi data (deprecated, use SPA_CONTROL_UMP) */
SPA_CONTROL_OSC, /**< spa_pod_bytes with an OSC packet */
SPA_CONTROL_UMP, /**< spa_pod_bytes with raw UMP (universal MIDI packet)
* data. The UMP 32 bit words are stored in native endian
* format. */
_SPA_CONTROL_LAST, /**< not part of ABI */
};

View File

@ -27,6 +27,7 @@ static const struct spa_type_info spa_type_control[] = {
{ SPA_CONTROL_Properties, SPA_TYPE_Int, SPA_TYPE_INFO_CONTROL_BASE "Properties", NULL },
{ SPA_CONTROL_Midi, SPA_TYPE_Int, SPA_TYPE_INFO_CONTROL_BASE "Midi", NULL },
{ SPA_CONTROL_OSC, SPA_TYPE_Int, SPA_TYPE_INFO_CONTROL_BASE "OSC", NULL },
{ SPA_CONTROL_UMP, SPA_TYPE_Int, SPA_TYPE_INFO_CONTROL_BASE "UMP", NULL },
{ 0, 0, NULL, NULL },
};

View File

@ -18,7 +18,16 @@ extern "C" {
#include <string.h>
static inline const struct spa_type_info *spa_debug_type_find(const struct spa_type_info *info, uint32_t type)
#ifndef SPA_API_DEBUG_TYPES
#ifdef SPA_API_IMPL
#define SPA_API_DEBUG_TYPES SPA_API_IMPL
#else
#define SPA_API_DEBUG_TYPES static inline
#endif
#endif
SPA_API_DEBUG_TYPES const struct spa_type_info *spa_debug_type_find(const struct spa_type_info *info, uint32_t type)
{
const struct spa_type_info *res;
@ -37,22 +46,19 @@ static inline const struct spa_type_info *spa_debug_type_find(const struct spa_t
return NULL;
}
static inline const char *spa_debug_type_short_name(const char *name)
SPA_API_DEBUG_TYPES const char *spa_debug_type_short_name(const char *name)
{
const char *h;
if ((h = strrchr(name, ':')) != NULL)
name = h + 1;
return name;
return spa_type_short_name(name);
}
static inline const char *spa_debug_type_find_name(const struct spa_type_info *info, uint32_t type)
SPA_API_DEBUG_TYPES const char *spa_debug_type_find_name(const struct spa_type_info *info, uint32_t type)
{
if ((info = spa_debug_type_find(info, type)) == NULL)
return NULL;
return info->name;
}
static inline const char *spa_debug_type_find_short_name(const struct spa_type_info *info, uint32_t type)
SPA_API_DEBUG_TYPES const char *spa_debug_type_find_short_name(const struct spa_type_info *info, uint32_t type)
{
const char *str;
if ((str = spa_debug_type_find_name(info, type)) == NULL)
@ -60,7 +66,7 @@ static inline const char *spa_debug_type_find_short_name(const struct spa_type_i
return spa_debug_type_short_name(str);
}
static inline uint32_t spa_debug_type_find_type(const struct spa_type_info *info, const char *name)
SPA_API_DEBUG_TYPES uint32_t spa_debug_type_find_type(const struct spa_type_info *info, const char *name)
{
if (info == NULL)
info = SPA_TYPE_ROOT;
@ -76,7 +82,7 @@ static inline uint32_t spa_debug_type_find_type(const struct spa_type_info *info
return SPA_ID_INVALID;
}
static inline const struct spa_type_info *spa_debug_type_find_short(const struct spa_type_info *info, const char *name)
SPA_API_DEBUG_TYPES const struct spa_type_info *spa_debug_type_find_short(const struct spa_type_info *info, const char *name)
{
while (info && info->name) {
if (strcmp(spa_debug_type_short_name(info->name), name) == 0)
@ -90,7 +96,7 @@ static inline const struct spa_type_info *spa_debug_type_find_short(const struct
return NULL;
}
static inline uint32_t spa_debug_type_find_type_short(const struct spa_type_info *info, const char *name)
SPA_API_DEBUG_TYPES uint32_t spa_debug_type_find_type_short(const struct spa_type_info *info, const char *name)
{
if ((info = spa_debug_type_find_short(info, name)) == NULL)
return SPA_ID_INVALID;

View File

@ -31,14 +31,16 @@ extern "C" {
enum spa_io_type {
SPA_IO_Invalid,
SPA_IO_Buffers, /**< area to exchange buffers, struct spa_io_buffers */
SPA_IO_Range, /**< expected byte range, struct spa_io_range */
SPA_IO_Range, /**< expected byte range, struct spa_io_range (currently not used in PipeWire) */
SPA_IO_Clock, /**< area to update clock information, struct spa_io_clock */
SPA_IO_Latency, /**< latency reporting, struct spa_io_latency */
SPA_IO_Latency, /**< latency reporting, struct spa_io_latency (currently not used in
* PipeWire). \see spa_param_latency */
SPA_IO_Control, /**< area for control messages, struct spa_io_sequence */
SPA_IO_Notify, /**< area for notify messages, struct spa_io_sequence */
SPA_IO_Position, /**< position information in the graph, struct spa_io_position */
SPA_IO_RateMatch, /**< rate matching between nodes, struct spa_io_rate_match */
SPA_IO_Memory, /**< memory pointer, struct spa_io_memory */
SPA_IO_Memory, /**< memory pointer, struct spa_io_memory (currently not used in PipeWire) */
SPA_IO_AsyncBuffers, /**< async area to exchange buffers, struct spa_io_async_buffers */
};
/**
@ -108,29 +110,52 @@ struct spa_io_range {
*
* The clock counts the elapsed time according to the clock provider
* since the provider was last started.
*
* Driver nodes are supposed to update the contents of \ref SPA_IO_Clock before
* signaling the start of a graph cycle. These updated clock values become
* visible to other nodes in \ref SPA_IO_Position. Non-driver nodes do
* not need to update the contents of their \ref SPA_IO_Clock.
*
* The host generally gives each node a separate \ref spa_io_clock in \ref
* SPA_IO_Clock, so that updates made by the driver are not visible in the
* contents of \ref SPA_IO_Clock of other nodes. Instead, \ref SPA_IO_Position
* is used to look up the current graph time.
*
* A node is a driver when \ref spa_io_clock.id in \ref SPA_IO_Clock and
* \ref spa_io_position.clock.id in \ref SPA_IO_Position are the same.
*/
struct spa_io_clock {
#define SPA_IO_CLOCK_FLAG_FREEWHEEL (1u<<0)
uint32_t flags; /**< clock flags */
uint32_t id; /**< unique clock id, set by application */
char name[64]; /**< clock name prefixed with API, set by node. The clock name
* is unique per clock and can be used to check if nodes
* share the same clock. */
uint64_t nsec; /**< time in nanoseconds against monotonic clock */
struct spa_fraction rate; /**< rate for position/duration/delay */
uint64_t position; /**< current position */
uint64_t duration; /**< duration of current cycle */
int64_t delay; /**< delay between position and hardware,
* positive for capture, negative for playback */
double rate_diff; /**< rate difference between clock and monotonic time */
uint64_t next_nsec; /**< estimated next wakeup time in nanoseconds */
#define SPA_IO_CLOCK_FLAG_FREEWHEEL (1u<<0) /* graph is freewheeling */
#define SPA_IO_CLOCK_FLAG_XRUN_RECOVER (1u<<1) /* recovering from xrun */
#define SPA_IO_CLOCK_FLAG_LAZY (1u<<2) /* lazy scheduling */
#define SPA_IO_CLOCK_FLAG_NO_RATE (1u<<3) /* the rate of the clock is only approximately.
* it is recommended to use the nsec as a clock source.
* The rate_diff contains the measured inaccuracy. */
uint32_t flags; /**< Clock flags */
uint32_t id; /**< Unique clock id, set by host application */
char name[64]; /**< Clock name prefixed with API, set by node when it receives
* \ref SPA_IO_Clock. The clock name is unique per clock and
* can be used to check if nodes share the same clock. */
uint64_t nsec; /**< Time in nanoseconds against monotonic clock
* (CLOCK_MONOTONIC). This fields reflects a real time instant
* in the past. The value may have jitter. */
struct spa_fraction rate; /**< Rate for position/duration/delay/xrun */
uint64_t position; /**< Current position, in samples @ \ref rate */
uint64_t duration; /**< Duration of current cycle, in samples @ \ref rate */
int64_t delay; /**< Delay between position and hardware, in samples @ \ref rate */
double rate_diff; /**< Rate difference between clock and monotonic time, as a ratio of
* clock speeds. */
uint64_t next_nsec; /**< Estimated next wakeup time in nanoseconds.
* This time is a logical start time of the next cycle, and
* is not necessarily in the future.
*/
struct spa_fraction target_rate; /**< target rate of next cycle */
uint64_t target_duration; /**< target duration of next cycle */
uint32_t target_seq; /**< seq counter. must be equal at start and
struct spa_fraction target_rate; /**< Target rate of next cycle */
uint64_t target_duration; /**< Target duration of next cycle */
uint32_t target_seq; /**< Seq counter. must be equal at start and
* end of read and lower bit must be 0 */
uint32_t padding[3];
uint32_t cycle; /**< incremented each time the graph is started */
uint64_t xrun; /**< Estimated accumulated xrun duration */
};
/* the size of the video in this cycle */
@ -145,7 +170,11 @@ struct spa_io_video_size {
uint32_t padding[4];
};
/** latency reporting */
/**
* Latency reporting
*
* Currently not used in PipeWire. Instead, \see spa_param_latency
*/
struct spa_io_latency {
struct spa_fraction rate; /**< rate for min/max */
uint64_t min; /**< min latency */
@ -166,7 +195,9 @@ struct spa_io_segment_bar {
float signature_denom; /**< time signature denominator */
double bpm; /**< beats per minute */
double beat; /**< current beat in segment */
uint32_t padding[8];
double bar_start_tick;
double ticks_per_beat;
uint32_t padding[4];
};
/** video frame segment */
@ -245,8 +276,13 @@ enum spa_io_position_state {
/**
* The position information adds extra meaning to the raw clock times.
*
* It is set on all nodes and the clock id will contain the clock of the
* driving node in the graph.
* It is set on all nodes in \ref SPA_IO_Position, and the contents of \ref
* spa_io_position.clock contain the clock updates made by the driving node in
* the graph in its \ref SPA_IO_Clock. Also, \ref spa_io_position.clock.id
* will contain the clock id of the driving node in the graph.
*
* The position clock indicates the logical start time of the current graph
* cycle.
*
* The position information contains 1 or more segments that convert the
* raw clock times to a stream time. They are sorted based on their
@ -269,14 +305,56 @@ struct spa_io_position {
struct spa_io_segment segments[SPA_IO_POSITION_MAX_SEGMENTS]; /**< segments */
};
/** rate matching */
/**
* Rate matching.
*
* It is usually set on the nodes that process resampled data, by
* the component (audioadapter) that handles resampling between graph
* and node rates. The \a flags and \a rate fields may be modified by the node.
*
* The node can request a correction to the resampling rate in its process(), by setting
* \ref SPA_IO_RATE_MATCH_ACTIVE on \a flags, and setting \a rate to the desired rate
* correction. Usually the rate is obtained from DLL or other adaptive mechanism that
* e.g. drives the node buffer fill level toward a specific value.
*
* When resampling to (graph->node) direction, the number of samples produced
* by the resampler varies on each cycle, as the rates are not commensurate.
*
* When resampling to (node->graph) direction, the number of samples consumed by the
* resampler varies. Node output ports in process() should produce \a size number of
* samples to match what the resampler needs to produce one graph quantum of output
* samples.
*
* Resampling filters introduce processing delay, given by \a delay and \a delay_frac, in
* samples at node rate. The delay varies on each cycle e.g. when resampling between
* noncommensurate rates.
*
* The first sample output (graph->node) or consumed (node->graph) by the resampler is
* offset by \a delay + \a delay_frac / 1e9 node samples relative to the nominal graph
* cycle start position:
*
* \code{.unparsed}
* first_resampled_sample_nsec =
* first_original_sample_nsec
* - (rate_match->delay * SPA_NSEC_PER_SEC + rate_match->delay_frac) / node_rate
* \endcode
*/
struct spa_io_rate_match {
uint32_t delay; /**< extra delay in samples for resampler */
uint32_t delay; /**< resampling delay, in samples at
* node rate */
uint32_t size; /**< requested input size for resampler */
double rate; /**< rate for resampler */
double rate; /**< rate for resampler (set by node) */
#define SPA_IO_RATE_MATCH_FLAG_ACTIVE (1 << 0)
uint32_t flags; /**< extra flags */
uint32_t padding[7];
uint32_t flags; /**< extra flags (set by node) */
int32_t delay_frac; /**< resampling delay fractional part,
* in units of nanosamples (1/10^9 sample) at node rate */
uint32_t padding[6];
};
/** async buffers */
struct spa_io_async_buffers {
struct spa_io_buffers buffers[2]; /**< async buffers, writers write to current (cycle+1)&1,
* readers read from (cycle)&1 */
};
/**

View File

@ -34,6 +34,7 @@ static const struct spa_type_info spa_type_io[] = {
{ SPA_IO_Position, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Position", NULL },
{ SPA_IO_RateMatch, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "RateMatch", NULL },
{ SPA_IO_Memory, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Memory", NULL },
{ SPA_IO_AsyncBuffers, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "AsyncBuffers", NULL },
{ 0, 0, NULL, NULL },
};

View File

@ -12,6 +12,11 @@ extern "C" {
#include <spa/utils/type.h>
#include <spa/param/audio/aac.h>
/**
* \addtogroup spa_param
* \{
*/
#define SPA_TYPE_INFO_AudioAACStreamFormat SPA_TYPE_INFO_ENUM_BASE "AudioAACStreamFormat"
#define SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE SPA_TYPE_INFO_AudioAACStreamFormat ":"

View File

@ -11,6 +11,11 @@ extern "C" {
#include <spa/param/audio/raw.h>
/**
* \addtogroup spa_param
* \{
*/
enum spa_audio_aac_stream_format {
SPA_AUDIO_AAC_STREAM_FORMAT_UNKNOWN,
/* Raw AAC frames */

View File

@ -12,6 +12,11 @@ extern "C" {
#include <spa/utils/type.h>
#include <spa/param/audio/amr.h>
/**
* \addtogroup spa_param
* \{
*/
#define SPA_TYPE_INFO_AudioAMRBandMode SPA_TYPE_INFO_ENUM_BASE "AudioAMRBandMode"
#define SPA_TYPE_INFO_AUDIO_AMR_BAND_MODE_BASE SPA_TYPE_INFO_AudioAMRBandMode ":"

View File

@ -11,6 +11,11 @@ extern "C" {
#include <spa/param/audio/raw.h>
/**
* \addtogroup spa_param
* \{
*/
enum spa_audio_amr_band_mode {
SPA_AUDIO_AMR_BAND_MODE_UNKNOWN,
SPA_AUDIO_AMR_BAND_MODE_NB,

View File

@ -12,6 +12,19 @@ extern "C" {
#include <spa/utils/type.h>
#include <spa/param/audio/iec958.h>
/**
* \addtogroup spa_param
* \{
*/
#ifndef SPA_API_AUDIO_IEC958_TYPES
#ifdef SPA_API_IMPL
#define SPA_API_AUDIO_IEC958_TYPES SPA_API_IMPL
#else
#define SPA_API_AUDIO_IEC958_TYPES static inline
#endif
#endif
#define SPA_TYPE_INFO_AudioIEC958Codec SPA_TYPE_INFO_ENUM_BASE "AudioIEC958Codec"
#define SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE SPA_TYPE_INFO_AudioIEC958Codec ":"
@ -28,6 +41,14 @@ static const struct spa_type_info spa_type_audio_iec958_codec[] = {
{ 0, 0, NULL, NULL },
};
SPA_API_AUDIO_IEC958_TYPES uint32_t spa_type_audio_iec958_codec_from_short_name(const char *name)
{
return spa_type_from_short_name(name, spa_type_audio_iec958_codec, SPA_AUDIO_IEC958_CODEC_UNKNOWN);
}
SPA_API_AUDIO_IEC958_TYPES const char * spa_type_audio_iec958_codec_to_short_name(uint32_t type)
{
return spa_type_to_short_name(type, spa_type_audio_iec958_codec, "UNKNOWN");
}
/**
* \}
*/

View File

@ -12,6 +12,11 @@ extern "C" {
#include <spa/utils/type.h>
#include <spa/param/audio/mp3.h>
/**
* \addtogroup spa_param
* \{
*/
#define SPA_TYPE_INFO_AudioMP3ChannelMode SPA_TYPE_INFO_ENUM_BASE "AudioMP3ChannelMode"
#define SPA_TYPE_INFO_AUDIO_MP3_CHANNEL_MODE_BASE SPA_TYPE_INFO_AudioMP3ChannelMode ":"

View File

@ -11,6 +11,11 @@ extern "C" {
#include <spa/param/audio/raw.h>
/**
* \addtogroup spa_param
* \{
*/
enum spa_audio_mp3_channel_mode {
SPA_AUDIO_MP3_CHANNEL_MODE_UNKNOWN,
SPA_AUDIO_MP3_CHANNEL_MODE_MONO,

View File

@ -15,8 +15,17 @@ extern "C" {
*/
#include <spa/utils/type.h>
#include <spa/utils/string.h>
#include <spa/param/audio/raw.h>
#ifndef SPA_API_AUDIO_RAW_TYPES
#ifdef SPA_API_IMPL
#define SPA_API_AUDIO_RAW_TYPES SPA_API_IMPL
#else
#define SPA_API_AUDIO_RAW_TYPES static inline
#endif
#endif
#define SPA_TYPE_INFO_AudioFormat SPA_TYPE_INFO_ENUM_BASE "AudioFormat"
#define SPA_TYPE_INFO_AUDIO_FORMAT_BASE SPA_TYPE_INFO_AudioFormat ":"
@ -128,6 +137,15 @@ static const struct spa_type_info spa_type_audio_format[] = {
{ 0, 0, NULL, NULL },
};
SPA_API_AUDIO_RAW_TYPES uint32_t spa_type_audio_format_from_short_name(const char *name)
{
return spa_type_from_short_name(name, spa_type_audio_format, SPA_AUDIO_FORMAT_UNKNOWN);
}
SPA_API_AUDIO_RAW_TYPES const char * spa_type_audio_format_to_short_name(uint32_t type)
{
return spa_type_to_short_name(type, spa_type_audio_format, "UNKNOWN");
}
#define SPA_TYPE_INFO_AudioFlags SPA_TYPE_INFO_FLAGS_BASE "AudioFlags"
#define SPA_TYPE_INFO_AUDIO_FLAGS_BASE SPA_TYPE_INFO_AudioFlags ":"
@ -247,6 +265,16 @@ static const struct spa_type_info spa_type_audio_channel[] = {
{ 0, 0, NULL, NULL },
};
SPA_API_AUDIO_RAW_TYPES uint32_t spa_type_audio_channel_from_short_name(const char *name)
{
return spa_type_from_short_name(name, spa_type_audio_channel, SPA_AUDIO_CHANNEL_UNKNOWN);
}
SPA_API_AUDIO_RAW_TYPES const char * spa_type_audio_channel_to_short_name(uint32_t type)
{
return spa_type_to_short_name(type, spa_type_audio_channel, "UNK");
}
/**
* \}
*/

View File

@ -11,15 +11,7 @@ extern "C" {
#include <stdint.h>
#if !defined(__FreeBSD__) && !defined(__MidnightBSD__) && !defined(AIX)
#include <endian.h>
#endif
#if defined(AIX)
#include <sys/machine.h>
#define __BIG_ENDIAN BIG_ENDIAN
#define __BYTE_ORDER BIG_ENDIAN
#endif
#include <spa/utils/endian.h>
/**
* \addtogroup spa_param

View File

@ -12,6 +12,11 @@ extern "C" {
#include <spa/utils/type.h>
#include <spa/param/audio/wma.h>
/**
* \addtogroup spa_param
* \{
*/
#define SPA_TYPE_INFO_AudioWMAProfile SPA_TYPE_INFO_ENUM_BASE "AudioWMAProfile"
#define SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE SPA_TYPE_INFO_AudioWMAProfile ":"

View File

@ -11,6 +11,11 @@ extern "C" {
#include <spa/param/audio/raw.h>
/**
* \addtogroup spa_param
* \{
*/
enum spa_audio_wma_profile {
SPA_AUDIO_WMA_PROFILE_UNKNOWN,

View File

@ -21,6 +21,7 @@ enum spa_bluetooth_audio_codec {
SPA_BLUETOOTH_AUDIO_CODEC_SBC_XQ,
SPA_BLUETOOTH_AUDIO_CODEC_MPEG,
SPA_BLUETOOTH_AUDIO_CODEC_AAC,
SPA_BLUETOOTH_AUDIO_CODEC_AAC_ELD,
SPA_BLUETOOTH_AUDIO_CODEC_APTX,
SPA_BLUETOOTH_AUDIO_CODEC_APTX_HD,
SPA_BLUETOOTH_AUDIO_CODEC_LDAC,
@ -34,13 +35,18 @@ enum spa_bluetooth_audio_codec {
SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_71,
SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_DUPLEX,
SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_PRO,
SPA_BLUETOOTH_AUDIO_CODEC_OPUS_G,
/* HFP */
SPA_BLUETOOTH_AUDIO_CODEC_CVSD = 0x100,
SPA_BLUETOOTH_AUDIO_CODEC_MSBC,
SPA_BLUETOOTH_AUDIO_CODEC_LC3_SWB,
/* BAP */
SPA_BLUETOOTH_AUDIO_CODEC_LC3 = 0x200,
/* ASHA */
SPA_BLUETOOTH_AUDIO_CODEC_G722 = 0x300,
};
/**

View File

@ -25,6 +25,7 @@ static const struct spa_type_info spa_type_bluetooth_audio_codec[] = {
{ SPA_BLUETOOTH_AUDIO_CODEC_SBC_XQ, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "sbc_xq", NULL },
{ SPA_BLUETOOTH_AUDIO_CODEC_MPEG, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "mpeg", NULL },
{ SPA_BLUETOOTH_AUDIO_CODEC_AAC, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "aac", NULL },
{ SPA_BLUETOOTH_AUDIO_CODEC_AAC_ELD, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "aac_eld", NULL },
{ SPA_BLUETOOTH_AUDIO_CODEC_APTX, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "aptx", NULL },
{ SPA_BLUETOOTH_AUDIO_CODEC_APTX_HD, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "aptx_hd", NULL },
{ SPA_BLUETOOTH_AUDIO_CODEC_LDAC, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "ldac", NULL },
@ -38,12 +39,16 @@ static const struct spa_type_info spa_type_bluetooth_audio_codec[] = {
{ SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_71, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "opus_05_71", NULL },
{ SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_DUPLEX, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "opus_05_duplex", NULL },
{ SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_PRO, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "opus_05_pro", NULL },
{ SPA_BLUETOOTH_AUDIO_CODEC_OPUS_G, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "opus_g", NULL },
{ SPA_BLUETOOTH_AUDIO_CODEC_CVSD, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "cvsd", NULL },
{ SPA_BLUETOOTH_AUDIO_CODEC_MSBC, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "msbc", NULL },
{ SPA_BLUETOOTH_AUDIO_CODEC_LC3_SWB, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "lc3_swb", NULL },
{ SPA_BLUETOOTH_AUDIO_CODEC_LC3, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "lc3", NULL },
{ SPA_BLUETOOTH_AUDIO_CODEC_G722, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "g722", NULL },
{ 0, 0, NULL, NULL },
};

View File

@ -56,6 +56,7 @@ static const struct spa_type_info spa_type_param_buffers[] = {
{ SPA_PARAM_BUFFERS_stride, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "stride", NULL },
{ SPA_PARAM_BUFFERS_align, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "align", NULL },
{ SPA_PARAM_BUFFERS_dataType, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "dataType", NULL },
{ SPA_PARAM_BUFFERS_metaType, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "metaType", NULL },
{ 0, 0, NULL, NULL },
};

View File

@ -24,14 +24,15 @@ enum spa_param_buffers {
SPA_PARAM_BUFFERS_size, /**< size of a data block memory (Int)*/
SPA_PARAM_BUFFERS_stride, /**< stride of data block memory (Int) */
SPA_PARAM_BUFFERS_align, /**< alignment of data block memory (Int) */
SPA_PARAM_BUFFERS_dataType, /**< possible memory types (Int, mask of enum spa_data_type) */
SPA_PARAM_BUFFERS_dataType, /**< possible memory types (flags choice Int, mask of enum spa_data_type) */
SPA_PARAM_BUFFERS_metaType, /**< required meta data types (Int, mask of enum spa_meta_type) */
};
/** properties for SPA_TYPE_OBJECT_ParamMeta */
enum spa_param_meta {
SPA_PARAM_META_START,
SPA_PARAM_META_type, /**< the metadata, one of enum spa_meta_type (Id enum spa_meta_type) */
SPA_PARAM_META_size, /**< the expected maximum size the meta (Int) */
SPA_PARAM_META_type, /**< the metadata, one of enum spa_meta_type (Id enum spa_meta_type) */
SPA_PARAM_META_size, /**< the expected maximum size the meta (Int) */
};
/** properties for SPA_TYPE_OBJECT_ParamIO */

View File

@ -18,7 +18,15 @@ extern "C" {
#include <spa/pod/parser.h>
#include <spa/param/format.h>
static inline int
#ifndef SPA_API_FORMAT_UTILS
#ifdef SPA_API_IMPL
#define SPA_API_FORMAT_UTILS SPA_API_IMPL
#else
#define SPA_API_FORMAT_UTILS static inline
#endif
#endif
SPA_API_FORMAT_UTILS int
spa_format_parse(const struct spa_pod *format, uint32_t *media_type, uint32_t *media_subtype)
{
return spa_pod_parse_object(format,

View File

@ -141,6 +141,8 @@ enum spa_format {
SPA_FORMAT_START_Stream = 0x50000,
/* Application Format keys */
SPA_FORMAT_START_Application = 0x60000,
SPA_FORMAT_CONTROL_types, /**< possible control types (flags choice Int,
* mask of enum spa_control_type) */
};
#define SPA_KEY_FORMAT_DSP "format.dsp" /**< a predefined DSP format,

View File

@ -16,14 +16,31 @@ extern "C" {
#include <spa/param/param.h>
/** properties for SPA_TYPE_OBJECT_ParamLatency */
/**
* Properties for SPA_TYPE_OBJECT_ParamLatency
*
* The latency indicates:
*
* - for playback: time delay between start of a graph cycle, and the rendering of
* the first sample of that cycle in audio output.
*
* - for capture: time delay between start of a graph cycle, and the first sample
* of that cycle having occurred in audio input.
*
* For physical output/input, the latency is intended to correspond to the
* rendering/capture of physical audio, including hardware internal rendering delay.
*
* The latency values are adjusted by \ref SPA_PROP_latencyOffsetNsec or
* SPA_PARAM_ProcessLatency, if present. (e.g. for ALSA this is used to adjust for
* the internal hardware latency).
*/
enum spa_param_latency {
SPA_PARAM_LATENCY_START,
SPA_PARAM_LATENCY_direction, /**< direction, input/output (Id enum spa_direction) */
SPA_PARAM_LATENCY_minQuantum, /**< min latency relative to quantum (Float) */
SPA_PARAM_LATENCY_maxQuantum, /**< max latency relative to quantum (Float) */
SPA_PARAM_LATENCY_minRate, /**< min latency (Int) relative to rate */
SPA_PARAM_LATENCY_maxRate, /**< max latency (Int) relative to rate */
SPA_PARAM_LATENCY_minRate, /**< min latency (Int) relative to graph rate */
SPA_PARAM_LATENCY_maxRate, /**< max latency (Int) relative to graph rate */
SPA_PARAM_LATENCY_minNs, /**< min latency (Long) in nanoseconds */
SPA_PARAM_LATENCY_maxNs, /**< max latency (Long) in nanoseconds */
};
@ -33,27 +50,32 @@ struct spa_latency_info {
enum spa_direction direction;
float min_quantum;
float max_quantum;
uint32_t min_rate;
uint32_t max_rate;
uint64_t min_ns;
uint64_t max_ns;
int32_t min_rate;
int32_t max_rate;
int64_t min_ns;
int64_t max_ns;
};
#define SPA_LATENCY_INFO(dir,...) ((struct spa_latency_info) { .direction = (dir), ## __VA_ARGS__ })
/** properties for SPA_TYPE_OBJECT_ParamProcessLatency */
/**
* Properties for SPA_TYPE_OBJECT_ParamProcessLatency
*
* The processing latency indicates logical time delay between a sample in an input port,
* and a corresponding sample in an output port, relative to the graph time.
*/
enum spa_param_process_latency {
SPA_PARAM_PROCESS_LATENCY_START,
SPA_PARAM_PROCESS_LATENCY_quantum, /**< latency relative to quantum (Float) */
SPA_PARAM_PROCESS_LATENCY_rate, /**< latency (Int) relative to rate */
SPA_PARAM_PROCESS_LATENCY_rate, /**< latency (Int) relative to graph rate */
SPA_PARAM_PROCESS_LATENCY_ns, /**< latency (Long) in nanoseconds */
};
/** Helper structure for managing process latency objects */
struct spa_process_latency_info {
float quantum;
uint32_t rate;
uint64_t ns;
int32_t rate;
int64_t ns;
};
#define SPA_PROCESS_LATENCY_INFO_INIT(...) ((struct spa_process_latency_info) { __VA_ARGS__ })

View File

@ -40,6 +40,7 @@ static const struct spa_type_info spa_type_param[] = {
{ SPA_PARAM_Control, SPA_TYPE_Sequence, SPA_TYPE_INFO_PARAM_ID_BASE "Control", NULL },
{ SPA_PARAM_Latency, SPA_TYPE_OBJECT_ParamLatency, SPA_TYPE_INFO_PARAM_ID_BASE "Latency", NULL },
{ SPA_PARAM_ProcessLatency, SPA_TYPE_OBJECT_ParamProcessLatency, SPA_TYPE_INFO_PARAM_ID_BASE "ProcessLatency", NULL },
{ SPA_PARAM_Tag, SPA_TYPE_OBJECT_ParamTag, SPA_TYPE_INFO_PARAM_ID_BASE "Tag", NULL },
{ 0, 0, NULL, NULL },
};
@ -54,6 +55,11 @@ static const struct spa_type_info spa_type_prop_float_array[] = {
{ 0, 0, NULL, NULL },
};
static const struct spa_type_info spa_type_prop_int_array[] = {
{ SPA_PROP_START, SPA_TYPE_Int, SPA_TYPE_INFO_BASE "intArray", NULL, },
{ 0, 0, NULL, NULL },
};
static const struct spa_type_info spa_type_prop_channel_map[] = {
{ SPA_PROP_START, SPA_TYPE_Id, SPA_TYPE_INFO_BASE "channelMap", spa_type_audio_channel, },
{ 0, 0, NULL, NULL },

View File

@ -39,6 +39,7 @@ enum spa_param_type {
SPA_PARAM_Control, /**< Control parameter, a SPA_TYPE_Sequence */
SPA_PARAM_Latency, /**< latency reporting, a SPA_TYPE_OBJECT_ParamLatency */
SPA_PARAM_ProcessLatency, /**< processing latency, a SPA_TYPE_OBJECT_ParamProcessLatency */
SPA_PARAM_Tag, /**< tag reporting, a SPA_TYPE_OBJECT_ParamTag. Since 0.3.79 */
};
/** information about a parameter */

View File

@ -26,6 +26,7 @@ static const struct spa_type_info spa_type_profiler[] = {
{ SPA_PROFILER_clock, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "clock", NULL, },
{ SPA_PROFILER_driverBlock, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "driverBlock", NULL, },
{ SPA_PROFILER_followerBlock, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "followerBlock", NULL, },
{ SPA_PROFILER_followerClock, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "followerClock", NULL, },
{ 0, 0, NULL, NULL },
};

View File

@ -39,7 +39,10 @@ enum spa_profiler {
* Long : clock duration,
* Long : clock delay,
* Double : clock rate_diff,
* Long : clock next_nsec)) */
* Long : clock next_nsec,
* Int : transport_state,
* Int : clock cycle,
* Long : xrun duration)) */
SPA_PROFILER_driverBlock, /**< generic driver info block
* (Struct(
* Int : driver_id,
@ -48,8 +51,9 @@ enum spa_profiler {
* Long : driver signal,
* Long : driver awake,
* Long : driver finish,
* Int : driver status),
* Fraction : latency)) */
* Int : driver status,
* Fraction : latency,
* Int : xrun_count)) */
SPA_PROFILER_START_Follower = 0x20000, /**< follower related profiler properties */
SPA_PROFILER_followerBlock, /**< generic follower info block
@ -61,8 +65,20 @@ enum spa_profiler {
* Long : awake,
* Long : finish,
* Int : status,
* Fraction : latency)) */
* Fraction : latency,
* Int : xrun_count)) */
SPA_PROFILER_followerClock, /**< follower clock information
* (Struct(
* Int : clock id,
* String: clock name,
* Long : clock nsec,
* Fraction : clock rate,
* Long : clock position,
* Long : clock duration,
* Long : clock delay,
* Double : clock rate_diff,
* Long : clock next_nsec,
* Long : xrun duration)) */
SPA_PROFILER_START_CUSTOM = 0x1000000,
};

View File

@ -64,14 +64,14 @@ static const struct spa_type_info spa_type_props[] = {
{ SPA_PROP_volumeRampStepTime, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "volumeRampStepTime", NULL },
{ SPA_PROP_volumeRampScale, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "volumeRampScale", NULL },
{ SPA_PROP_brightness, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "brightness", NULL },
{ SPA_PROP_contrast, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "contrast", NULL },
{ SPA_PROP_saturation, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "saturation", NULL },
{ SPA_PROP_brightness, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "brightness", NULL },
{ SPA_PROP_contrast, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "contrast", NULL },
{ SPA_PROP_saturation, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "saturation", NULL },
{ SPA_PROP_hue, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "hue", NULL },
{ SPA_PROP_gamma, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "gamma", NULL },
{ SPA_PROP_exposure, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "exposure", NULL },
{ SPA_PROP_gain, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "gain", NULL },
{ SPA_PROP_sharpness, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "sharpness", NULL },
{ SPA_PROP_gain, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "gain", NULL },
{ SPA_PROP_sharpness, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "sharpness", NULL },
{ SPA_PROP_params, SPA_TYPE_Struct, SPA_TYPE_INFO_PROPS_BASE "params", NULL },
{ 0, 0, NULL, NULL },

View File

@ -59,24 +59,31 @@ enum spa_prop {
SPA_PROP_START_Audio = 0x10000, /**< audio related properties */
SPA_PROP_waveType,
SPA_PROP_frequency,
SPA_PROP_volume, /**< a volume (Float), 0.0 silence, 1.0 normal */
SPA_PROP_volume, /**< a volume (Float), 0.0 silence, 1.0 no attenutation */
SPA_PROP_mute, /**< mute (Bool) */
SPA_PROP_patternType,
SPA_PROP_ditherType,
SPA_PROP_truncate,
SPA_PROP_channelVolumes, /**< a volume array, one volume per
* channel (Array of Float) */
SPA_PROP_channelVolumes, /**< a volume array, one (linear) volume per channel
* (Array of Float). 0.0 is silence, 1.0 is
* without attenuation. This is the effective
* volume that is applied. It can result
* in a hardware volume and software volume
* (see softVolumes) */
SPA_PROP_volumeBase, /**< a volume base (Float) */
SPA_PROP_volumeStep, /**< a volume step (Float) */
SPA_PROP_channelMap, /**< a channelmap array
* (Array (Id enum spa_audio_channel)) */
SPA_PROP_monitorMute, /**< mute (Bool) */
SPA_PROP_monitorVolumes, /**< a volume array, one volume per
SPA_PROP_monitorVolumes, /**< a volume array, one (linear) volume per
* channel (Array of Float) */
SPA_PROP_latencyOffsetNsec, /**< delay adjustment */
SPA_PROP_softMute, /**< mute (Bool) */
SPA_PROP_softVolumes, /**< a volume array, one volume per
* channel (Array of Float) */
SPA_PROP_softMute, /**< mute (Bool) applied in software */
SPA_PROP_softVolumes, /**< a volume array, one (linear) volume per channel
* (Array of Float). 0.0 is silence, 1.0 is without
* attenuation. This is the volume applied in
* software, there might be a part applied in
* hardware. */
SPA_PROP_iec958Codecs, /**< enabled IEC958 (S/PDIF) codecs,
* (Array (Id enum spa_audio_iec958_codec) */

View File

@ -32,9 +32,9 @@ static const struct spa_type_info spa_type_param_route[] = {
{ SPA_PARAM_ROUTE_priority, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "priority", NULL, },
{ SPA_PARAM_ROUTE_available, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_ROUTE_BASE "available", spa_type_param_availability, },
{ SPA_PARAM_ROUTE_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_ROUTE_BASE "info", NULL, },
{ SPA_PARAM_ROUTE_profiles, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "profiles", NULL, },
{ SPA_PARAM_ROUTE_profiles, SPA_TYPE_Array, SPA_TYPE_INFO_PARAM_ROUTE_BASE "profiles", spa_type_prop_int_array, },
{ SPA_PARAM_ROUTE_props, SPA_TYPE_OBJECT_Props, SPA_TYPE_INFO_PARAM_ROUTE_BASE "props", NULL, },
{ SPA_PARAM_ROUTE_devices, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "devices", NULL, },
{ SPA_PARAM_ROUTE_devices, SPA_TYPE_Array, SPA_TYPE_INFO_PARAM_ROUTE_BASE "devices", spa_type_prop_int_array, },
{ SPA_PARAM_ROUTE_profile, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "profile", NULL, },
{ SPA_PARAM_ROUTE_save, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_ROUTE_BASE "save", NULL, },
{ 0, 0, NULL, NULL },

View File

@ -0,0 +1,39 @@
/* Simple Plugin API */
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#ifndef SPA_PARAM_TAG_TYPES_H
#define SPA_PARAM_TAG_TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* \addtogroup spa_param
* \{
*/
#include <spa/utils/enum-types.h>
#include <spa/param/param-types.h>
#include <spa/param/tag.h>
#define SPA_TYPE_INFO_PARAM_Tag SPA_TYPE_INFO_PARAM_BASE "Tag"
#define SPA_TYPE_INFO_PARAM_TAG_BASE SPA_TYPE_INFO_PARAM_Tag ":"
static const struct spa_type_info spa_type_param_tag[] = {
{ SPA_PARAM_TAG_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_TAG_BASE, spa_type_param, },
{ SPA_PARAM_TAG_direction, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_TAG_BASE "direction", spa_type_direction, },
{ SPA_PARAM_TAG_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_TAG_BASE "info", NULL, },
{ 0, 0, NULL, NULL },
};
/**
* \}
*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SPA_PARAM_TAG_TYPES_H */

View File

@ -0,0 +1,46 @@
/* Simple Plugin API */
/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#ifndef SPA_PARAM_TAG_H
#define SPA_PARAM_TAG_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* \addtogroup spa_param
* \{
*/
#include <spa/param/param.h>
/** properties for SPA_TYPE_OBJECT_ParamTag */
enum spa_param_tag {
SPA_PARAM_TAG_START,
SPA_PARAM_TAG_direction, /**< direction, input/output (Id enum spa_direction) */
SPA_PARAM_TAG_info, /**< Struct(
* Int: n_items
* (String: key
* String: value)*
* ) */
};
/** helper structure for managing tag objects */
struct spa_tag_info {
enum spa_direction direction;
const struct spa_pod *info;
};
#define SPA_TAG_INFO(dir,...) ((struct spa_tag_info) { .direction = (dir), ## __VA_ARGS__ })
/**
* \}
*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SPA_PARAM_TAG_H */

View File

@ -14,5 +14,6 @@
#include <spa/param/profiler-types.h>
#include <spa/param/profile-types.h>
#include <spa/param/route-types.h>
#include <spa/param/tag-types.h>
#endif /* SPA_PARAM_TYPE_INFO_H */

View File

@ -18,13 +18,24 @@ extern "C" {
#include <spa/pod/builder.h>
#include <spa/param/video/dsp.h>
static inline int
#ifndef SPA_API_VIDEO_DSP_UTILS
#ifdef SPA_API_IMPL
#define SPA_API_VIDEO_DSP_UTILS SPA_API_IMPL
#else
#define SPA_API_VIDEO_DSP_UTILS static inline
#endif
#endif
SPA_API_VIDEO_DSP_UTILS int
spa_format_video_dsp_parse(const struct spa_pod *format,
struct spa_video_info_dsp *info)
{
info->flags = SPA_VIDEO_FLAG_NONE;
if (spa_pod_find_prop (format, NULL, SPA_FORMAT_VIDEO_modifier)) {
const struct spa_pod_prop *mod_prop;
if ((mod_prop = spa_pod_find_prop (format, NULL, SPA_FORMAT_VIDEO_modifier)) != NULL) {
info->flags |= SPA_VIDEO_FLAG_MODIFIER;
if ((mod_prop->flags & SPA_POD_PROP_FLAG_DONT_FIXATE) == SPA_POD_PROP_FLAG_DONT_FIXATE)
info->flags |= SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED;
}
return spa_pod_parse_object(format,
@ -33,9 +44,9 @@ spa_format_video_dsp_parse(const struct spa_pod *format,
SPA_FORMAT_VIDEO_modifier, SPA_POD_OPT_Long(&info->modifier));
}
static inline struct spa_pod *
SPA_API_VIDEO_DSP_UTILS struct spa_pod *
spa_format_video_dsp_build(struct spa_pod_builder *builder, uint32_t id,
struct spa_video_info_dsp *info)
const struct spa_video_info_dsp *info)
{
struct spa_pod_frame f;
spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
@ -46,9 +57,11 @@ spa_format_video_dsp_build(struct spa_pod_builder *builder, uint32_t id,
if (info->format != SPA_VIDEO_FORMAT_UNKNOWN)
spa_pod_builder_add(builder,
SPA_FORMAT_VIDEO_format, SPA_POD_Id(info->format), 0);
if (info->modifier != 0 || info->flags & SPA_VIDEO_FLAG_MODIFIER)
spa_pod_builder_add(builder,
SPA_FORMAT_VIDEO_modifier, SPA_POD_Long(info->modifier), 0);
if (info->modifier != 0 || info->flags & SPA_VIDEO_FLAG_MODIFIER) {
spa_pod_builder_prop(builder,
SPA_FORMAT_VIDEO_modifier, SPA_POD_PROP_FLAG_MANDATORY);
spa_pod_builder_long(builder, info->modifier);
}
return (struct spa_pod*)spa_pod_builder_pop(builder, &f);
}

View File

@ -16,7 +16,15 @@ extern "C" {
#include <spa/param/video/h264-utils.h>
#include <spa/param/video/mjpg-utils.h>
static inline int
#ifndef SPA_API_VIDEO_FORMAT_UTILS
#ifdef SPA_API_IMPL
#define SPA_API_VIDEO_FORMAT_UTILS SPA_API_IMPL
#else
#define SPA_API_VIDEO_FORMAT_UTILS static inline
#endif
#endif
SPA_API_VIDEO_FORMAT_UTILS int
spa_format_video_parse(const struct spa_pod *format, struct spa_video_info *info)
{
int res;
@ -40,8 +48,9 @@ spa_format_video_parse(const struct spa_pod *format, struct spa_video_info *info
return -ENOTSUP;
}
static inline struct spa_pod *
spa_format_video_build(struct spa_pod_builder *builder, uint32_t id, struct spa_video_info *info)
SPA_API_VIDEO_FORMAT_UTILS struct spa_pod *
spa_format_video_build(struct spa_pod_builder *builder, uint32_t id,
const struct spa_video_info *info)
{
switch (info->media_subtype) {
case SPA_MEDIA_SUBTYPE_raw:

View File

@ -18,7 +18,15 @@ extern "C" {
#include <spa/pod/builder.h>
#include <spa/param/video/h264.h>
static inline int
#ifndef SPA_API_VIDEO_H264_UTILS
#ifdef SPA_API_IMPL
#define SPA_API_VIDEO_H264_UTILS SPA_API_IMPL
#else
#define SPA_API_VIDEO_H264_UTILS static inline
#endif
#endif
SPA_API_VIDEO_H264_UTILS int
spa_format_video_h264_parse(const struct spa_pod *format,
struct spa_video_info_h264 *info)
{
@ -31,9 +39,9 @@ spa_format_video_h264_parse(const struct spa_pod *format,
SPA_FORMAT_VIDEO_H264_alignment, SPA_POD_OPT_Id(&info->alignment));
}
static inline struct spa_pod *
SPA_API_VIDEO_H264_UTILS struct spa_pod *
spa_format_video_h264_build(struct spa_pod_builder *builder, uint32_t id,
struct spa_video_info_h264 *info)
const struct spa_video_info_h264 *info)
{
struct spa_pod_frame f;
spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
@ -49,7 +57,7 @@ spa_format_video_h264_build(struct spa_pod_builder *builder, uint32_t id,
SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&info->framerate), 0);
if (info->max_framerate.denom != 0)
spa_pod_builder_add(builder,
SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_Fraction(info->max_framerate), 0);
SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_Fraction(&info->max_framerate), 0);
if (info->stream_format != 0)
spa_pod_builder_add(builder,
SPA_FORMAT_VIDEO_H264_streamFormat, SPA_POD_Id(info->stream_format), 0);

View File

@ -18,7 +18,15 @@ extern "C" {
#include <spa/pod/builder.h>
#include <spa/param/video/mjpg.h>
static inline int
#ifndef SPA_API_VIDEO_MJPG_UTILS
#ifdef SPA_API_IMPL
#define SPA_API_VIDEO_MJPG_UTILS SPA_API_IMPL
#else
#define SPA_API_VIDEO_MJPG_UTILS static inline
#endif
#endif
SPA_API_VIDEO_MJPG_UTILS int
spa_format_video_mjpg_parse(const struct spa_pod *format,
struct spa_video_info_mjpg *info)
{
@ -29,9 +37,9 @@ spa_format_video_mjpg_parse(const struct spa_pod *format,
SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_OPT_Fraction(&info->max_framerate));
}
static inline struct spa_pod *
SPA_API_VIDEO_MJPG_UTILS struct spa_pod *
spa_format_video_mjpg_build(struct spa_pod_builder *builder, uint32_t id,
struct spa_video_info_mjpg *info)
const struct spa_video_info_mjpg *info)
{
struct spa_pod_frame f;
spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
@ -47,7 +55,7 @@ spa_format_video_mjpg_build(struct spa_pod_builder *builder, uint32_t id,
SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&info->framerate), 0);
if (info->max_framerate.denom != 0)
spa_pod_builder_add(builder,
SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_Fraction(info->max_framerate), 0);
SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_Fraction(&info->max_framerate), 0);
return (struct spa_pod*)spa_pod_builder_pop(builder, &f);
}

View File

@ -59,12 +59,11 @@ enum spa_video_multiview_mode {
* sequence. This method only applies to
* raw video buffers at the moment.
* Specific view identification is via
* \ref spa_video_multiview_meta on raw
* video buffers. */
* metadata on raw video buffers. */
SPA_VIDEO_MULTIVIEW_MODE_SEPARATED, /**< Multiple views are provided as separate
* \ref spa_data framebuffers attached
* to each \ref spa_buffer, described
* by the \ref spa_video_multiview_meta */
* by the metadata */
/* future expansion for annotated modes */
};
@ -97,9 +96,7 @@ enum spa_video_multiview_flags {
SPA_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO = (1 << 15), /**< The video stream contains both
* mono and multiview portions,
* signalled on each buffer by the
* absence or presence of the
* \ref SPA_VIDEO_BUFFER_FLAG_MULTIPLE_VIEW
* buffer flag. */
* absence or presence of a buffer flag. */
};

View File

@ -16,11 +16,20 @@ extern "C" {
#include <spa/utils/type.h>
#include <spa/param/video/raw.h>
#ifndef SPA_API_VIDEO_RAW_TYPES
#ifdef SPA_API_IMPL
#define SPA_API_VIDEO_RAW_TYPES SPA_API_IMPL
#else
#define SPA_API_VIDEO_RAW_TYPES static inline
#endif
#endif
#define SPA_TYPE_INFO_VideoFormat SPA_TYPE_INFO_ENUM_BASE "VideoFormat"
#define SPA_TYPE_INFO_VIDEO_FORMAT_BASE SPA_TYPE_INFO_VideoFormat ":"
static const struct spa_type_info spa_type_video_format[] = {
{ SPA_VIDEO_FORMAT_ENCODED, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "encoded", NULL },
{ SPA_VIDEO_FORMAT_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "UNKNOWN", NULL },
{ SPA_VIDEO_FORMAT_ENCODED, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ENCODED", NULL },
{ SPA_VIDEO_FORMAT_I420, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420", NULL },
{ SPA_VIDEO_FORMAT_YV12, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YV12", NULL },
{ SPA_VIDEO_FORMAT_YUY2, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YUY2", NULL },
@ -110,6 +119,15 @@ static const struct spa_type_info spa_type_video_format[] = {
{ 0, 0, NULL, NULL },
};
SPA_API_VIDEO_RAW_TYPES uint32_t spa_type_video_format_from_short_name(const char *name)
{
return spa_type_from_short_name(name, spa_type_video_format, SPA_VIDEO_FORMAT_UNKNOWN);
}
SPA_API_VIDEO_RAW_TYPES const char * spa_type_video_format_to_short_name(uint32_t type)
{
return spa_type_to_short_name(type, spa_type_video_format, "UNKNOWN");
}
#define SPA_TYPE_INFO_VideoFlags SPA_TYPE_INFO_FLAGS_BASE "VideoFlags"
#define SPA_TYPE_INFO_VIDEO_FLAGS_BASE SPA_TYPE_INFO_VideoFlags ":"

View File

@ -18,13 +18,24 @@ extern "C" {
#include <spa/pod/builder.h>
#include <spa/param/video/raw.h>
static inline int
#ifndef SPA_API_VIDEO_RAW_UTILS
#ifdef SPA_API_IMPL
#define SPA_API_VIDEO_RAW_UTILS SPA_API_IMPL
#else
#define SPA_API_VIDEO_RAW_UTILS static inline
#endif
#endif
SPA_API_VIDEO_RAW_UTILS int
spa_format_video_raw_parse(const struct spa_pod *format,
struct spa_video_info_raw *info)
{
info->flags = SPA_VIDEO_FLAG_NONE;
if (spa_pod_find_prop (format, NULL, SPA_FORMAT_VIDEO_modifier)) {
const struct spa_pod_prop *mod_prop;
if ((mod_prop = spa_pod_find_prop (format, NULL, SPA_FORMAT_VIDEO_modifier)) != NULL) {
info->flags |= SPA_VIDEO_FLAG_MODIFIER;
if ((mod_prop->flags & SPA_POD_PROP_FLAG_DONT_FIXATE) == SPA_POD_PROP_FLAG_DONT_FIXATE)
info->flags |= SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED;
}
return spa_pod_parse_object(format,
@ -46,9 +57,9 @@ spa_format_video_raw_parse(const struct spa_pod *format,
SPA_FORMAT_VIDEO_colorPrimaries, SPA_POD_OPT_Id(&info->color_primaries));
}
static inline struct spa_pod *
SPA_API_VIDEO_RAW_UTILS struct spa_pod *
spa_format_video_raw_build(struct spa_pod_builder *builder, uint32_t id,
struct spa_video_info_raw *info)
const struct spa_video_info_raw *info)
{
struct spa_pod_frame f;
spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
@ -65,12 +76,14 @@ spa_format_video_raw_build(struct spa_pod_builder *builder, uint32_t id,
if (info->framerate.denom != 0)
spa_pod_builder_add(builder,
SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&info->framerate), 0);
if (info->modifier != 0 || info->flags & SPA_VIDEO_FLAG_MODIFIER)
spa_pod_builder_add(builder,
SPA_FORMAT_VIDEO_modifier, SPA_POD_Long(info->modifier), 0);
if (info->modifier != 0 || info->flags & SPA_VIDEO_FLAG_MODIFIER) {
spa_pod_builder_prop(builder,
SPA_FORMAT_VIDEO_modifier, SPA_POD_PROP_FLAG_MANDATORY);
spa_pod_builder_long(builder, info->modifier);
}
if (info->max_framerate.denom != 0)
spa_pod_builder_add(builder,
SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_Fraction(info->max_framerate), 0);
SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_Fraction(&info->max_framerate), 0);
if (info->views != 0)
spa_pod_builder_add(builder,
SPA_FORMAT_VIDEO_views, SPA_POD_Int(info->views), 0);
@ -79,7 +92,7 @@ spa_format_video_raw_build(struct spa_pod_builder *builder, uint32_t id,
SPA_FORMAT_VIDEO_interlaceMode, SPA_POD_Id(info->interlace_mode), 0);
if (info->pixel_aspect_ratio.denom != 0)
spa_pod_builder_add(builder,
SPA_FORMAT_VIDEO_pixelAspectRatio,SPA_POD_Fraction(info->pixel_aspect_ratio), 0);
SPA_FORMAT_VIDEO_pixelAspectRatio, SPA_POD_Fraction(&info->pixel_aspect_ratio), 0);
if (info->multiview_mode != 0)
spa_pod_builder_add(builder,
SPA_FORMAT_VIDEO_multiviewMode, SPA_POD_Id(info->multiview_mode), 0);

View File

@ -134,11 +134,12 @@ enum spa_video_format {
* Extra video flags
*/
enum spa_video_flags {
SPA_VIDEO_FLAG_NONE = 0, /**< no flags */
SPA_VIDEO_FLAG_VARIABLE_FPS = (1 << 0), /**< a variable fps is selected, fps_n and fps_d
* denote the maximum fps of the video */
SPA_VIDEO_FLAG_PREMULTIPLIED_ALPHA = (1 << 1), /**< Each color has been scaled by the alpha value. */
SPA_VIDEO_FLAG_MODIFIER = (1 << 2), /**< use the format modifier */
SPA_VIDEO_FLAG_NONE = 0, /**< no flags */
SPA_VIDEO_FLAG_VARIABLE_FPS = (1 << 0), /**< a variable fps is selected, fps_n and fps_d
* denote the maximum fps of the video */
SPA_VIDEO_FLAG_PREMULTIPLIED_ALPHA = (1 << 1), /**< Each color has been scaled by the alpha value. */
SPA_VIDEO_FLAG_MODIFIER = (1 << 2), /**< use the format modifier */
SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED = (1 << 3), /**< format modifier was not fixated yet */
};
/**

View File

@ -24,6 +24,14 @@ extern "C" {
#include <spa/pod/iter.h>
#include <spa/pod/vararg.h>
#ifndef SPA_API_POD_BUILDER
#ifdef SPA_API_IMPL
#define SPA_API_POD_BUILDER SPA_API_IMPL
#else
#define SPA_API_POD_BUILDER static inline
#endif
#endif
struct spa_pod_builder_state {
uint32_t offset;
#define SPA_POD_BUILDER_FLAG_BODY (1<<0)
@ -49,22 +57,22 @@ struct spa_pod_builder {
struct spa_callbacks callbacks;
};
#define SPA_POD_BUILDER_INIT(buffer,size) ((struct spa_pod_builder){ (buffer), (size), 0, {}, {} })
#define SPA_POD_BUILDER_INIT(buffer,size) ((struct spa_pod_builder){ (buffer), (size), 0, {0,0,NULL},{NULL,NULL}})
static inline void
SPA_API_POD_BUILDER void
spa_pod_builder_get_state(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
{
*state = builder->state;
}
static inline void
SPA_API_POD_BUILDER void
spa_pod_builder_set_callbacks(struct spa_pod_builder *builder,
const struct spa_pod_builder_callbacks *callbacks, void *data)
{
builder->callbacks = SPA_CALLBACKS_INIT(callbacks, data);
}
static inline void
SPA_API_POD_BUILDER void
spa_pod_builder_reset(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
{
struct spa_pod_frame *f;
@ -74,12 +82,12 @@ spa_pod_builder_reset(struct spa_pod_builder *builder, struct spa_pod_builder_st
f->pod.size -= size;
}
static inline void spa_pod_builder_init(struct spa_pod_builder *builder, void *data, uint32_t size)
SPA_API_POD_BUILDER void spa_pod_builder_init(struct spa_pod_builder *builder, void *data, uint32_t size)
{
*builder = SPA_POD_BUILDER_INIT(data, size);
}
static inline struct spa_pod *
SPA_API_POD_BUILDER struct spa_pod *
spa_pod_builder_deref(struct spa_pod_builder *builder, uint32_t offset)
{
uint32_t size = builder->size;
@ -91,7 +99,7 @@ spa_pod_builder_deref(struct spa_pod_builder *builder, uint32_t offset)
return NULL;
}
static inline struct spa_pod *
SPA_API_POD_BUILDER struct spa_pod *
spa_pod_builder_frame(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
{
if (frame->offset + SPA_POD_SIZE(&frame->pod) <= builder->size)
@ -99,7 +107,7 @@ spa_pod_builder_frame(struct spa_pod_builder *builder, struct spa_pod_frame *fra
return NULL;
}
static inline void
SPA_API_POD_BUILDER void
spa_pod_builder_push(struct spa_pod_builder *builder,
struct spa_pod_frame *frame,
const struct spa_pod *pod,
@ -115,7 +123,7 @@ spa_pod_builder_push(struct spa_pod_builder *builder,
builder->state.flags = SPA_POD_BUILDER_FLAG_FIRST | SPA_POD_BUILDER_FLAG_BODY;
}
static inline int spa_pod_builder_raw(struct spa_pod_builder *builder, const void *data, uint32_t size)
SPA_API_POD_BUILDER int spa_pod_builder_raw(struct spa_pod_builder *builder, const void *data, uint32_t size)
{
int res = 0;
struct spa_pod_frame *f;
@ -139,14 +147,14 @@ static inline int spa_pod_builder_raw(struct spa_pod_builder *builder, const voi
return res;
}
static inline int spa_pod_builder_pad(struct spa_pod_builder *builder, uint32_t size)
SPA_API_POD_BUILDER int spa_pod_builder_pad(struct spa_pod_builder *builder, uint32_t size)
{
uint64_t zeroes = 0;
size = SPA_ROUND_UP_N(size, 8) - size;
return size ? spa_pod_builder_raw(builder, &zeroes, size) : 0;
}
static inline int
SPA_API_POD_BUILDER int
spa_pod_builder_raw_padded(struct spa_pod_builder *builder, const void *data, uint32_t size)
{
int r, res = spa_pod_builder_raw(builder, data, size);
@ -155,7 +163,7 @@ spa_pod_builder_raw_padded(struct spa_pod_builder *builder, const void *data, ui
return res;
}
static inline void *spa_pod_builder_pop(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
SPA_API_POD_BUILDER void *spa_pod_builder_pop(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
{
struct spa_pod *pod;
@ -172,7 +180,7 @@ static inline void *spa_pod_builder_pop(struct spa_pod_builder *builder, struct
return pod;
}
static inline int
SPA_API_POD_BUILDER int
spa_pod_builder_primitive(struct spa_pod_builder *builder, const struct spa_pod *p)
{
const void *data;
@ -198,13 +206,13 @@ spa_pod_builder_primitive(struct spa_pod_builder *builder, const struct spa_pod
#define SPA_POD_INIT_None() SPA_POD_INIT(0, SPA_TYPE_None)
static inline int spa_pod_builder_none(struct spa_pod_builder *builder)
SPA_API_POD_BUILDER int spa_pod_builder_none(struct spa_pod_builder *builder)
{
const struct spa_pod p = SPA_POD_INIT_None();
return spa_pod_builder_primitive(builder, &p);
}
static inline int spa_pod_builder_child(struct spa_pod_builder *builder, uint32_t size, uint32_t type)
SPA_API_POD_BUILDER int spa_pod_builder_child(struct spa_pod_builder *builder, uint32_t size, uint32_t type)
{
const struct spa_pod p = SPA_POD_INIT(size,type);
SPA_FLAG_CLEAR(builder->state.flags, SPA_POD_BUILDER_FLAG_FIRST);
@ -213,7 +221,7 @@ static inline int spa_pod_builder_child(struct spa_pod_builder *builder, uint32_
#define SPA_POD_INIT_Bool(val) ((struct spa_pod_bool){ { sizeof(uint32_t), SPA_TYPE_Bool }, (val) ? 1 : 0, 0 })
static inline int spa_pod_builder_bool(struct spa_pod_builder *builder, bool val)
SPA_API_POD_BUILDER int spa_pod_builder_bool(struct spa_pod_builder *builder, bool val)
{
const struct spa_pod_bool p = SPA_POD_INIT_Bool(val);
return spa_pod_builder_primitive(builder, &p.pod);
@ -221,7 +229,7 @@ static inline int spa_pod_builder_bool(struct spa_pod_builder *builder, bool val
#define SPA_POD_INIT_Id(val) ((struct spa_pod_id){ { sizeof(uint32_t), SPA_TYPE_Id }, (val), 0 })
static inline int spa_pod_builder_id(struct spa_pod_builder *builder, uint32_t val)
SPA_API_POD_BUILDER int spa_pod_builder_id(struct spa_pod_builder *builder, uint32_t val)
{
const struct spa_pod_id p = SPA_POD_INIT_Id(val);
return spa_pod_builder_primitive(builder, &p.pod);
@ -229,7 +237,7 @@ static inline int spa_pod_builder_id(struct spa_pod_builder *builder, uint32_t v
#define SPA_POD_INIT_Int(val) ((struct spa_pod_int){ { sizeof(int32_t), SPA_TYPE_Int }, (val), 0 })
static inline int spa_pod_builder_int(struct spa_pod_builder *builder, int32_t val)
SPA_API_POD_BUILDER int spa_pod_builder_int(struct spa_pod_builder *builder, int32_t val)
{
const struct spa_pod_int p = SPA_POD_INIT_Int(val);
return spa_pod_builder_primitive(builder, &p.pod);
@ -237,7 +245,7 @@ static inline int spa_pod_builder_int(struct spa_pod_builder *builder, int32_t v
#define SPA_POD_INIT_Long(val) ((struct spa_pod_long){ { sizeof(int64_t), SPA_TYPE_Long }, (val) })
static inline int spa_pod_builder_long(struct spa_pod_builder *builder, int64_t val)
SPA_API_POD_BUILDER int spa_pod_builder_long(struct spa_pod_builder *builder, int64_t val)
{
const struct spa_pod_long p = SPA_POD_INIT_Long(val);
return spa_pod_builder_primitive(builder, &p.pod);
@ -245,7 +253,7 @@ static inline int spa_pod_builder_long(struct spa_pod_builder *builder, int64_t
#define SPA_POD_INIT_Float(val) ((struct spa_pod_float){ { sizeof(float), SPA_TYPE_Float }, (val), 0 })
static inline int spa_pod_builder_float(struct spa_pod_builder *builder, float val)
SPA_API_POD_BUILDER int spa_pod_builder_float(struct spa_pod_builder *builder, float val)
{
const struct spa_pod_float p = SPA_POD_INIT_Float(val);
return spa_pod_builder_primitive(builder, &p.pod);
@ -253,7 +261,7 @@ static inline int spa_pod_builder_float(struct spa_pod_builder *builder, float v
#define SPA_POD_INIT_Double(val) ((struct spa_pod_double){ { sizeof(double), SPA_TYPE_Double }, (val) })
static inline int spa_pod_builder_double(struct spa_pod_builder *builder, double val)
SPA_API_POD_BUILDER int spa_pod_builder_double(struct spa_pod_builder *builder, double val)
{
const struct spa_pod_double p = SPA_POD_INIT_Double(val);
return spa_pod_builder_primitive(builder, &p.pod);
@ -261,7 +269,7 @@ static inline int spa_pod_builder_double(struct spa_pod_builder *builder, double
#define SPA_POD_INIT_String(len) ((struct spa_pod_string){ { (len), SPA_TYPE_String } })
static inline int
SPA_API_POD_BUILDER int
spa_pod_builder_write_string(struct spa_pod_builder *builder, const char *str, uint32_t len)
{
int r, res;
@ -273,7 +281,7 @@ spa_pod_builder_write_string(struct spa_pod_builder *builder, const char *str, u
return res;
}
static inline int
SPA_API_POD_BUILDER int
spa_pod_builder_string_len(struct spa_pod_builder *builder, const char *str, uint32_t len)
{
const struct spa_pod_string p = SPA_POD_INIT_String(len+1);
@ -283,7 +291,7 @@ spa_pod_builder_string_len(struct spa_pod_builder *builder, const char *str, uin
return res;
}
static inline int spa_pod_builder_string(struct spa_pod_builder *builder, const char *str)
SPA_API_POD_BUILDER int spa_pod_builder_string(struct spa_pod_builder *builder, const char *str)
{
uint32_t len = str ? strlen(str) : 0;
return spa_pod_builder_string_len(builder, str ? str : "", len);
@ -291,7 +299,7 @@ static inline int spa_pod_builder_string(struct spa_pod_builder *builder, const
#define SPA_POD_INIT_Bytes(len) ((struct spa_pod_bytes){ { (len), SPA_TYPE_Bytes } })
static inline int
SPA_API_POD_BUILDER int
spa_pod_builder_bytes(struct spa_pod_builder *builder, const void *bytes, uint32_t len)
{
const struct spa_pod_bytes p = SPA_POD_INIT_Bytes(len);
@ -300,7 +308,7 @@ spa_pod_builder_bytes(struct spa_pod_builder *builder, const void *bytes, uint32
res = r;
return res;
}
static inline void *
SPA_API_POD_BUILDER void *
spa_pod_builder_reserve_bytes(struct spa_pod_builder *builder, uint32_t len)
{
uint32_t offset = builder->state.offset;
@ -311,7 +319,7 @@ spa_pod_builder_reserve_bytes(struct spa_pod_builder *builder, uint32_t len)
#define SPA_POD_INIT_Pointer(type,value) ((struct spa_pod_pointer){ { sizeof(struct spa_pod_pointer_body), SPA_TYPE_Pointer }, { (type), 0, (value) } })
static inline int
SPA_API_POD_BUILDER int
spa_pod_builder_pointer(struct spa_pod_builder *builder, uint32_t type, const void *val)
{
const struct spa_pod_pointer p = SPA_POD_INIT_Pointer(type, val);
@ -320,7 +328,7 @@ spa_pod_builder_pointer(struct spa_pod_builder *builder, uint32_t type, const vo
#define SPA_POD_INIT_Fd(fd) ((struct spa_pod_fd){ { sizeof(int64_t), SPA_TYPE_Fd }, (fd) })
static inline int spa_pod_builder_fd(struct spa_pod_builder *builder, int64_t fd)
SPA_API_POD_BUILDER int spa_pod_builder_fd(struct spa_pod_builder *builder, int64_t fd)
{
const struct spa_pod_fd p = SPA_POD_INIT_Fd(fd);
return spa_pod_builder_primitive(builder, &p.pod);
@ -328,7 +336,7 @@ static inline int spa_pod_builder_fd(struct spa_pod_builder *builder, int64_t fd
#define SPA_POD_INIT_Rectangle(val) ((struct spa_pod_rectangle){ { sizeof(struct spa_rectangle), SPA_TYPE_Rectangle }, (val) })
static inline int
SPA_API_POD_BUILDER int
spa_pod_builder_rectangle(struct spa_pod_builder *builder, uint32_t width, uint32_t height)
{
const struct spa_pod_rectangle p = SPA_POD_INIT_Rectangle(SPA_RECTANGLE(width, height));
@ -337,14 +345,14 @@ spa_pod_builder_rectangle(struct spa_pod_builder *builder, uint32_t width, uint3
#define SPA_POD_INIT_Fraction(val) ((struct spa_pod_fraction){ { sizeof(struct spa_fraction), SPA_TYPE_Fraction }, (val) })
static inline int
SPA_API_POD_BUILDER int
spa_pod_builder_fraction(struct spa_pod_builder *builder, uint32_t num, uint32_t denom)
{
const struct spa_pod_fraction p = SPA_POD_INIT_Fraction(SPA_FRACTION(num, denom));
return spa_pod_builder_primitive(builder, &p.pod);
}
static inline int
SPA_API_POD_BUILDER int
spa_pod_builder_push_array(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
{
const struct spa_pod_array p =
@ -356,7 +364,7 @@ spa_pod_builder_push_array(struct spa_pod_builder *builder, struct spa_pod_frame
return res;
}
static inline int
SPA_API_POD_BUILDER int
spa_pod_builder_array(struct spa_pod_builder *builder,
uint32_t child_size, uint32_t child_type, uint32_t n_elems, const void *elems)
{
@ -378,7 +386,7 @@ spa_pod_builder_array(struct spa_pod_builder *builder,
{ { { (n_vals) * sizeof(ctype) + sizeof(struct spa_pod_choice_body), SPA_TYPE_Choice }, \
{ (type), 0, { sizeof(ctype), (child_type) } } }, { __VA_ARGS__ } })
static inline int
SPA_API_POD_BUILDER int
spa_pod_builder_push_choice(struct spa_pod_builder *builder, struct spa_pod_frame *frame,
uint32_t type, uint32_t flags)
{
@ -393,7 +401,7 @@ spa_pod_builder_push_choice(struct spa_pod_builder *builder, struct spa_pod_fram
#define SPA_POD_INIT_Struct(size) ((struct spa_pod_struct){ { (size), SPA_TYPE_Struct } })
static inline int
SPA_API_POD_BUILDER int
spa_pod_builder_push_struct(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
{
const struct spa_pod_struct p = SPA_POD_INIT_Struct(0);
@ -405,7 +413,7 @@ spa_pod_builder_push_struct(struct spa_pod_builder *builder, struct spa_pod_fram
#define SPA_POD_INIT_Object(size,type,id,...) ((struct spa_pod_object){ { (size), SPA_TYPE_Object }, { (type), (id) }, ##__VA_ARGS__ })
static inline int
SPA_API_POD_BUILDER int
spa_pod_builder_push_object(struct spa_pod_builder *builder, struct spa_pod_frame *frame,
uint32_t type, uint32_t id)
{
@ -420,7 +428,7 @@ spa_pod_builder_push_object(struct spa_pod_builder *builder, struct spa_pod_fram
#define SPA_POD_INIT_Prop(key,flags,size,type) \
((struct spa_pod_prop){ (key), (flags), { (size), (type) } })
static inline int
SPA_API_POD_BUILDER int
spa_pod_builder_prop(struct spa_pod_builder *builder, uint32_t key, uint32_t flags)
{
const struct { uint32_t key; uint32_t flags; } p = { key, flags };
@ -430,7 +438,7 @@ spa_pod_builder_prop(struct spa_pod_builder *builder, uint32_t key, uint32_t fla
#define SPA_POD_INIT_Sequence(size,unit) \
((struct spa_pod_sequence){ { (size), SPA_TYPE_Sequence}, {(unit), 0 } })
static inline int
SPA_API_POD_BUILDER int
spa_pod_builder_push_sequence(struct spa_pod_builder *builder, struct spa_pod_frame *frame, uint32_t unit)
{
const struct spa_pod_sequence p =
@ -441,14 +449,14 @@ spa_pod_builder_push_sequence(struct spa_pod_builder *builder, struct spa_pod_fr
return res;
}
static inline uint32_t
SPA_API_POD_BUILDER int
spa_pod_builder_control(struct spa_pod_builder *builder, uint32_t offset, uint32_t type)
{
const struct { uint32_t offset; uint32_t type; } p = { offset, type };
return spa_pod_builder_raw(builder, &p, sizeof(p));
}
static inline uint32_t spa_choice_from_id(char id)
SPA_API_POD_BUILDER uint32_t spa_choice_from_id(char id)
{
switch (id) {
case 'r':
@ -481,7 +489,7 @@ do { \
spa_pod_builder_long(builder, va_arg(args, int64_t)); \
break; \
case 'f': \
spa_pod_builder_float(builder, va_arg(args, double)); \
spa_pod_builder_float(builder, (float)va_arg(args, double)); \
break; \
case 'd': \
spa_pod_builder_double(builder, va_arg(args, double)); \
@ -560,7 +568,7 @@ do { \
} \
} while(false)
static inline int
SPA_API_POD_BUILDER int
spa_pod_builder_addv(struct spa_pod_builder *builder, va_list args)
{
int res = 0;
@ -618,7 +626,7 @@ spa_pod_builder_addv(struct spa_pod_builder *builder, va_list args)
return res;
}
static inline int spa_pod_builder_add(struct spa_pod_builder *builder, ...)
SPA_API_POD_BUILDER int spa_pod_builder_add(struct spa_pod_builder *builder, ...)
{
int res;
va_list args;
@ -658,7 +666,7 @@ static inline int spa_pod_builder_add(struct spa_pod_builder *builder, ...)
})
/** Copy a pod structure */
static inline struct spa_pod *
SPA_API_POD_BUILDER struct spa_pod *
spa_pod_copy(const struct spa_pod *pod)
{
size_t size;

View File

@ -30,7 +30,7 @@ struct spa_event {
(ev)->body.body.id : SPA_ID_INVALID)
#define SPA_EVENT_INIT_FULL(t,size,type,id,...) ((t) \
{ { (size), SPA_TYPE_OBJECT }, \
{ { (size), SPA_TYPE_Object }, \
{ { (type), (id) }, ##__VA_ARGS__ } }) \
#define SPA_EVENT_INIT(type,id) \

View File

@ -14,6 +14,14 @@ extern "C" {
#include <spa/pod/pod.h>
#ifndef SPA_API_POD_ITER
#ifdef SPA_API_IMPL
#define SPA_API_POD_ITER SPA_API_IMPL
#else
#define SPA_API_POD_ITER static inline
#endif
#endif
/**
* \addtogroup spa_pod
* \{
@ -26,54 +34,60 @@ struct spa_pod_frame {
uint32_t flags;
};
static inline bool spa_pod_is_inside(const void *pod, uint32_t size, const void *iter)
SPA_API_POD_ITER bool spa_pod_is_inside(const void *pod, uint32_t size, const void *iter)
{
return SPA_POD_BODY(iter) <= SPA_PTROFF(pod, size, void) &&
SPA_PTROFF(iter, SPA_POD_SIZE(iter), void) <= SPA_PTROFF(pod, size, void);
size_t remaining;
return spa_ptr_type_inside(pod, size, iter, struct spa_pod, &remaining) &&
remaining >= SPA_POD_BODY_SIZE(iter);
}
static inline void *spa_pod_next(const void *iter)
SPA_API_POD_ITER void *spa_pod_next(const void *iter)
{
return SPA_PTROFF(iter, SPA_ROUND_UP_N(SPA_POD_SIZE(iter), 8), void);
}
static inline struct spa_pod_prop *spa_pod_prop_first(const struct spa_pod_object_body *body)
SPA_API_POD_ITER struct spa_pod_prop *spa_pod_prop_first(const struct spa_pod_object_body *body)
{
return SPA_PTROFF(body, sizeof(struct spa_pod_object_body), struct spa_pod_prop);
}
static inline bool spa_pod_prop_is_inside(const struct spa_pod_object_body *body,
SPA_API_POD_ITER bool spa_pod_prop_is_inside(const struct spa_pod_object_body *body,
uint32_t size, const struct spa_pod_prop *iter)
{
return SPA_POD_CONTENTS(struct spa_pod_prop, iter) <= SPA_PTROFF(body, size, void) &&
SPA_PTROFF(iter, SPA_POD_PROP_SIZE(iter), void) <= SPA_PTROFF(body, size, void);
size_t remaining;
return spa_ptr_type_inside(body, size, iter, struct spa_pod_prop, &remaining) &&
remaining >= iter->value.size;
}
static inline struct spa_pod_prop *spa_pod_prop_next(const struct spa_pod_prop *iter)
SPA_API_POD_ITER struct spa_pod_prop *spa_pod_prop_next(const struct spa_pod_prop *iter)
{
return SPA_PTROFF(iter, SPA_ROUND_UP_N(SPA_POD_PROP_SIZE(iter), 8), struct spa_pod_prop);
}
static inline struct spa_pod_control *spa_pod_control_first(const struct spa_pod_sequence_body *body)
SPA_API_POD_ITER struct spa_pod_control *spa_pod_control_first(const struct spa_pod_sequence_body *body)
{
return SPA_PTROFF(body, sizeof(struct spa_pod_sequence_body), struct spa_pod_control);
}
static inline bool spa_pod_control_is_inside(const struct spa_pod_sequence_body *body,
SPA_API_POD_ITER bool spa_pod_control_is_inside(const struct spa_pod_sequence_body *body,
uint32_t size, const struct spa_pod_control *iter)
{
return SPA_POD_CONTENTS(struct spa_pod_control, iter) <= SPA_PTROFF(body, size, void) &&
SPA_PTROFF(iter, SPA_POD_CONTROL_SIZE(iter), void) <= SPA_PTROFF(body, size, void);
size_t remaining;
return spa_ptr_type_inside(body, size, iter, struct spa_pod_control, &remaining) &&
remaining >= iter->value.size;
}
static inline struct spa_pod_control *spa_pod_control_next(const struct spa_pod_control *iter)
SPA_API_POD_ITER struct spa_pod_control *spa_pod_control_next(const struct spa_pod_control *iter)
{
return SPA_PTROFF(iter, SPA_ROUND_UP_N(SPA_POD_CONTROL_SIZE(iter), 8), struct spa_pod_control);
}
#define SPA_POD_ARRAY_BODY_FOREACH(body, _size, iter) \
for ((iter) = (__typeof__(iter))SPA_PTROFF((body), sizeof(struct spa_pod_array_body), void); \
(iter) < (__typeof__(iter))SPA_PTROFF((body), (_size), void); \
(body)->child.size > 0 && spa_ptrinside(body, _size, iter, (body)->child.size, NULL); \
(iter) = (__typeof__(iter))SPA_PTROFF((iter), (body)->child.size, void))
#define SPA_POD_ARRAY_FOREACH(obj, iter) \
@ -81,7 +95,7 @@ static inline struct spa_pod_control *spa_pod_control_next(const struct spa_pod_
#define SPA_POD_CHOICE_BODY_FOREACH(body, _size, iter) \
for ((iter) = (__typeof__(iter))SPA_PTROFF((body), sizeof(struct spa_pod_choice_body), void); \
(iter) < (__typeof__(iter))SPA_PTROFF((body), (_size), void); \
(body)->child.size > 0 && spa_ptrinside(body, _size, iter, (body)->child.size, NULL); \
(iter) = (__typeof__(iter))SPA_PTROFF((iter), (body)->child.size, void))
#define SPA_POD_CHOICE_FOREACH(obj, iter) \
@ -112,7 +126,7 @@ static inline struct spa_pod_control *spa_pod_control_next(const struct spa_pod_
SPA_POD_SEQUENCE_BODY_FOREACH(&(seq)->body, SPA_POD_BODY_SIZE(seq), iter)
static inline void *spa_pod_from_data(void *data, size_t maxsize, off_t offset, size_t size)
SPA_API_POD_ITER void *spa_pod_from_data(void *data, size_t maxsize, off_t offset, size_t size)
{
void *pod;
if (size < sizeof(struct spa_pod) || offset + size > maxsize)
@ -123,17 +137,17 @@ static inline void *spa_pod_from_data(void *data, size_t maxsize, off_t offset,
return pod;
}
static inline int spa_pod_is_none(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_none(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_None);
}
static inline int spa_pod_is_bool(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_bool(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_Bool && SPA_POD_BODY_SIZE(pod) >= sizeof(int32_t));
}
static inline int spa_pod_get_bool(const struct spa_pod *pod, bool *value)
SPA_API_POD_ITER int spa_pod_get_bool(const struct spa_pod *pod, bool *value)
{
if (!spa_pod_is_bool(pod))
return -EINVAL;
@ -141,12 +155,12 @@ static inline int spa_pod_get_bool(const struct spa_pod *pod, bool *value)
return 0;
}
static inline int spa_pod_is_id(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_id(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_Id && SPA_POD_BODY_SIZE(pod) >= sizeof(uint32_t));
}
static inline int spa_pod_get_id(const struct spa_pod *pod, uint32_t *value)
SPA_API_POD_ITER int spa_pod_get_id(const struct spa_pod *pod, uint32_t *value)
{
if (!spa_pod_is_id(pod))
return -EINVAL;
@ -154,12 +168,12 @@ static inline int spa_pod_get_id(const struct spa_pod *pod, uint32_t *value)
return 0;
}
static inline int spa_pod_is_int(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_int(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_Int && SPA_POD_BODY_SIZE(pod) >= sizeof(int32_t));
}
static inline int spa_pod_get_int(const struct spa_pod *pod, int32_t *value)
SPA_API_POD_ITER int spa_pod_get_int(const struct spa_pod *pod, int32_t *value)
{
if (!spa_pod_is_int(pod))
return -EINVAL;
@ -167,12 +181,12 @@ static inline int spa_pod_get_int(const struct spa_pod *pod, int32_t *value)
return 0;
}
static inline int spa_pod_is_long(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_long(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_Long && SPA_POD_BODY_SIZE(pod) >= sizeof(int64_t));
}
static inline int spa_pod_get_long(const struct spa_pod *pod, int64_t *value)
SPA_API_POD_ITER int spa_pod_get_long(const struct spa_pod *pod, int64_t *value)
{
if (!spa_pod_is_long(pod))
return -EINVAL;
@ -180,12 +194,12 @@ static inline int spa_pod_get_long(const struct spa_pod *pod, int64_t *value)
return 0;
}
static inline int spa_pod_is_float(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_float(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_Float && SPA_POD_BODY_SIZE(pod) >= sizeof(float));
}
static inline int spa_pod_get_float(const struct spa_pod *pod, float *value)
SPA_API_POD_ITER int spa_pod_get_float(const struct spa_pod *pod, float *value)
{
if (!spa_pod_is_float(pod))
return -EINVAL;
@ -193,12 +207,12 @@ static inline int spa_pod_get_float(const struct spa_pod *pod, float *value)
return 0;
}
static inline int spa_pod_is_double(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_double(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_Double && SPA_POD_BODY_SIZE(pod) >= sizeof(double));
}
static inline int spa_pod_get_double(const struct spa_pod *pod, double *value)
SPA_API_POD_ITER int spa_pod_get_double(const struct spa_pod *pod, double *value)
{
if (!spa_pod_is_double(pod))
return -EINVAL;
@ -206,7 +220,7 @@ static inline int spa_pod_get_double(const struct spa_pod *pod, double *value)
return 0;
}
static inline int spa_pod_is_string(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_string(const struct spa_pod *pod)
{
const char *s = (const char *)SPA_POD_CONTENTS(struct spa_pod_string, pod);
return (SPA_POD_TYPE(pod) == SPA_TYPE_String &&
@ -214,7 +228,7 @@ static inline int spa_pod_is_string(const struct spa_pod *pod)
s[SPA_POD_BODY_SIZE(pod)-1] == '\0');
}
static inline int spa_pod_get_string(const struct spa_pod *pod, const char **value)
SPA_API_POD_ITER int spa_pod_get_string(const struct spa_pod *pod, const char **value)
{
if (!spa_pod_is_string(pod))
return -EINVAL;
@ -222,7 +236,7 @@ static inline int spa_pod_get_string(const struct spa_pod *pod, const char **val
return 0;
}
static inline int spa_pod_copy_string(const struct spa_pod *pod, size_t maxlen, char *dest)
SPA_API_POD_ITER int spa_pod_copy_string(const struct spa_pod *pod, size_t maxlen, char *dest)
{
const char *s = (const char *)SPA_POD_CONTENTS(struct spa_pod_string, pod);
if (!spa_pod_is_string(pod) || maxlen < 1)
@ -232,12 +246,12 @@ static inline int spa_pod_copy_string(const struct spa_pod *pod, size_t maxlen,
return 0;
}
static inline int spa_pod_is_bytes(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_bytes(const struct spa_pod *pod)
{
return SPA_POD_TYPE(pod) == SPA_TYPE_Bytes;
}
static inline int spa_pod_get_bytes(const struct spa_pod *pod, const void **value, uint32_t *len)
SPA_API_POD_ITER int spa_pod_get_bytes(const struct spa_pod *pod, const void **value, uint32_t *len)
{
if (!spa_pod_is_bytes(pod))
return -EINVAL;
@ -246,13 +260,13 @@ static inline int spa_pod_get_bytes(const struct spa_pod *pod, const void **valu
return 0;
}
static inline int spa_pod_is_pointer(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_pointer(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_Pointer &&
SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_pointer_body));
}
static inline int spa_pod_get_pointer(const struct spa_pod *pod, uint32_t *type, const void **value)
SPA_API_POD_ITER int spa_pod_get_pointer(const struct spa_pod *pod, uint32_t *type, const void **value)
{
if (!spa_pod_is_pointer(pod))
return -EINVAL;
@ -261,13 +275,13 @@ static inline int spa_pod_get_pointer(const struct spa_pod *pod, uint32_t *type,
return 0;
}
static inline int spa_pod_is_fd(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_fd(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_Fd &&
SPA_POD_BODY_SIZE(pod) >= sizeof(int64_t));
}
static inline int spa_pod_get_fd(const struct spa_pod *pod, int64_t *value)
SPA_API_POD_ITER int spa_pod_get_fd(const struct spa_pod *pod, int64_t *value)
{
if (!spa_pod_is_fd(pod))
return -EINVAL;
@ -275,13 +289,13 @@ static inline int spa_pod_get_fd(const struct spa_pod *pod, int64_t *value)
return 0;
}
static inline int spa_pod_is_rectangle(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_rectangle(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_Rectangle &&
SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_rectangle));
}
static inline int spa_pod_get_rectangle(const struct spa_pod *pod, struct spa_rectangle *value)
SPA_API_POD_ITER int spa_pod_get_rectangle(const struct spa_pod *pod, struct spa_rectangle *value)
{
if (!spa_pod_is_rectangle(pod))
return -EINVAL;
@ -289,39 +303,39 @@ static inline int spa_pod_get_rectangle(const struct spa_pod *pod, struct spa_re
return 0;
}
static inline int spa_pod_is_fraction(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_fraction(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_Fraction &&
SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_fraction));
}
static inline int spa_pod_get_fraction(const struct spa_pod *pod, struct spa_fraction *value)
SPA_API_POD_ITER int spa_pod_get_fraction(const struct spa_pod *pod, struct spa_fraction *value)
{
spa_return_val_if_fail(spa_pod_is_fraction(pod), -EINVAL);
*value = SPA_POD_VALUE(struct spa_pod_fraction, pod);
return 0;
}
static inline int spa_pod_is_bitmap(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_bitmap(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_Bitmap &&
SPA_POD_BODY_SIZE(pod) >= sizeof(uint8_t));
}
static inline int spa_pod_is_array(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_array(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_Array &&
SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_array_body));
}
static inline void *spa_pod_get_array(const struct spa_pod *pod, uint32_t *n_values)
SPA_API_POD_ITER void *spa_pod_get_array(const struct spa_pod *pod, uint32_t *n_values)
{
spa_return_val_if_fail(spa_pod_is_array(pod), NULL);
*n_values = SPA_POD_ARRAY_N_VALUES(pod);
return SPA_POD_ARRAY_VALUES(pod);
}
static inline uint32_t spa_pod_copy_array(const struct spa_pod *pod, uint32_t type,
SPA_API_POD_ITER uint32_t spa_pod_copy_array(const struct spa_pod *pod, uint32_t type,
void *values, uint32_t max_values)
{
uint32_t n_values;
@ -333,13 +347,13 @@ static inline uint32_t spa_pod_copy_array(const struct spa_pod *pod, uint32_t ty
return n_values;
}
static inline int spa_pod_is_choice(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_choice(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_Choice &&
SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_choice_body));
}
static inline struct spa_pod *spa_pod_get_values(const struct spa_pod *pod, uint32_t *n_vals, uint32_t *choice)
SPA_API_POD_ITER struct spa_pod *spa_pod_get_values(const struct spa_pod *pod, uint32_t *n_vals, uint32_t *choice)
{
if (pod->type == SPA_TYPE_Choice) {
*n_vals = SPA_POD_CHOICE_N_VALUES(pod);
@ -353,34 +367,34 @@ static inline struct spa_pod *spa_pod_get_values(const struct spa_pod *pod, uint
}
}
static inline int spa_pod_is_struct(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_struct(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_Struct);
}
static inline int spa_pod_is_object(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_object(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_Object &&
SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_object_body));
}
static inline bool spa_pod_is_object_type(const struct spa_pod *pod, uint32_t type)
SPA_API_POD_ITER bool spa_pod_is_object_type(const struct spa_pod *pod, uint32_t type)
{
return (pod && spa_pod_is_object(pod) && SPA_POD_OBJECT_TYPE(pod) == type);
}
static inline bool spa_pod_is_object_id(const struct spa_pod *pod, uint32_t id)
SPA_API_POD_ITER bool spa_pod_is_object_id(const struct spa_pod *pod, uint32_t id)
{
return (pod && spa_pod_is_object(pod) && SPA_POD_OBJECT_ID(pod) == id);
}
static inline int spa_pod_is_sequence(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_is_sequence(const struct spa_pod *pod)
{
return (SPA_POD_TYPE(pod) == SPA_TYPE_Sequence &&
SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_sequence_body));
}
static inline const struct spa_pod_prop *spa_pod_object_find_prop(const struct spa_pod_object *pod,
SPA_API_POD_ITER const struct spa_pod_prop *spa_pod_object_find_prop(const struct spa_pod_object *pod,
const struct spa_pod_prop *start, uint32_t key)
{
const struct spa_pod_prop *first, *res;
@ -400,7 +414,7 @@ static inline const struct spa_pod_prop *spa_pod_object_find_prop(const struct s
return NULL;
}
static inline const struct spa_pod_prop *spa_pod_find_prop(const struct spa_pod *pod,
SPA_API_POD_ITER const struct spa_pod_prop *spa_pod_find_prop(const struct spa_pod *pod,
const struct spa_pod_prop *start, uint32_t key)
{
if (!spa_pod_is_object(pod))
@ -408,7 +422,7 @@ static inline const struct spa_pod_prop *spa_pod_find_prop(const struct spa_pod
return spa_pod_object_find_prop((const struct spa_pod_object *)pod, start, key);
}
static inline int spa_pod_object_fixate(struct spa_pod_object *pod)
SPA_API_POD_ITER int spa_pod_object_fixate(struct spa_pod_object *pod)
{
struct spa_pod_prop *res;
SPA_POD_OBJECT_FOREACH(pod, res) {
@ -419,14 +433,14 @@ static inline int spa_pod_object_fixate(struct spa_pod_object *pod)
return 0;
}
static inline int spa_pod_fixate(struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_fixate(struct spa_pod *pod)
{
if (!spa_pod_is_object(pod))
return -EINVAL;
return spa_pod_object_fixate((struct spa_pod_object *)pod);
}
static inline int spa_pod_object_is_fixated(const struct spa_pod_object *pod)
SPA_API_POD_ITER int spa_pod_object_is_fixated(const struct spa_pod_object *pod)
{
struct spa_pod_prop *res;
SPA_POD_OBJECT_FOREACH(pod, res) {
@ -437,7 +451,15 @@ static inline int spa_pod_object_is_fixated(const struct spa_pod_object *pod)
return 1;
}
static inline int spa_pod_is_fixated(const struct spa_pod *pod)
SPA_API_POD_ITER int spa_pod_object_has_props(const struct spa_pod_object *pod)
{
struct spa_pod_prop *res;
SPA_POD_OBJECT_FOREACH(pod, res)
return 1;
return 0;
}
SPA_API_POD_ITER int spa_pod_is_fixated(const struct spa_pod *pod)
{
if (!spa_pod_is_object(pod))
return -EINVAL;

View File

@ -15,6 +15,14 @@ extern "C" {
#include <spa/pod/iter.h>
#include <spa/pod/vararg.h>
#ifndef SPA_API_POD_PARSER
#ifdef SPA_API_IMPL
#define SPA_API_POD_PARSER SPA_API_IMPL
#else
#define SPA_API_POD_PARSER static inline
#endif
#endif
/**
* \addtogroup spa_pod
* \{
@ -33,33 +41,33 @@ struct spa_pod_parser {
struct spa_pod_parser_state state;
};
#define SPA_POD_PARSER_INIT(buffer,size) ((struct spa_pod_parser){ (buffer), (size), 0, {} })
#define SPA_POD_PARSER_INIT(buffer,size) ((struct spa_pod_parser){ (buffer), (size), 0, {0,0,NULL}})
static inline void spa_pod_parser_init(struct spa_pod_parser *parser,
SPA_API_POD_PARSER void spa_pod_parser_init(struct spa_pod_parser *parser,
const void *data, uint32_t size)
{
*parser = SPA_POD_PARSER_INIT(data, size);
}
static inline void spa_pod_parser_pod(struct spa_pod_parser *parser,
SPA_API_POD_PARSER void spa_pod_parser_pod(struct spa_pod_parser *parser,
const struct spa_pod *pod)
{
spa_pod_parser_init(parser, pod, SPA_POD_SIZE(pod));
}
static inline void
SPA_API_POD_PARSER void
spa_pod_parser_get_state(struct spa_pod_parser *parser, struct spa_pod_parser_state *state)
{
*state = parser->state;
}
static inline void
SPA_API_POD_PARSER void
spa_pod_parser_reset(struct spa_pod_parser *parser, struct spa_pod_parser_state *state)
{
parser->state = *state;
}
static inline struct spa_pod *
SPA_API_POD_PARSER struct spa_pod *
spa_pod_parser_deref(struct spa_pod_parser *parser, uint32_t offset, uint32_t size)
{
/* Cast to uint64_t to avoid wraparound. Add 8 for the pod itself. */
@ -78,12 +86,12 @@ spa_pod_parser_deref(struct spa_pod_parser *parser, uint32_t offset, uint32_t si
return NULL;
}
static inline struct spa_pod *spa_pod_parser_frame(struct spa_pod_parser *parser, struct spa_pod_frame *frame)
SPA_API_POD_PARSER struct spa_pod *spa_pod_parser_frame(struct spa_pod_parser *parser, struct spa_pod_frame *frame)
{
return SPA_PTROFF(parser->data, frame->offset, struct spa_pod);
}
static inline void spa_pod_parser_push(struct spa_pod_parser *parser,
SPA_API_POD_PARSER void spa_pod_parser_push(struct spa_pod_parser *parser,
struct spa_pod_frame *frame, const struct spa_pod *pod, uint32_t offset)
{
frame->pod = *pod;
@ -93,19 +101,19 @@ static inline void spa_pod_parser_push(struct spa_pod_parser *parser,
parser->state.frame = frame;
}
static inline struct spa_pod *spa_pod_parser_current(struct spa_pod_parser *parser)
SPA_API_POD_PARSER struct spa_pod *spa_pod_parser_current(struct spa_pod_parser *parser)
{
struct spa_pod_frame *f = parser->state.frame;
uint32_t size = f ? f->offset + SPA_POD_SIZE(&f->pod) : parser->size;
return spa_pod_parser_deref(parser, parser->state.offset, size);
}
static inline void spa_pod_parser_advance(struct spa_pod_parser *parser, const struct spa_pod *pod)
SPA_API_POD_PARSER void spa_pod_parser_advance(struct spa_pod_parser *parser, const struct spa_pod *pod)
{
parser->state.offset += SPA_ROUND_UP_N(SPA_POD_SIZE(pod), 8);
}
static inline struct spa_pod *spa_pod_parser_next(struct spa_pod_parser *parser)
SPA_API_POD_PARSER struct spa_pod *spa_pod_parser_next(struct spa_pod_parser *parser)
{
struct spa_pod *pod = spa_pod_parser_current(parser);
if (pod)
@ -113,7 +121,7 @@ static inline struct spa_pod *spa_pod_parser_next(struct spa_pod_parser *parser)
return pod;
}
static inline int spa_pod_parser_pop(struct spa_pod_parser *parser,
SPA_API_POD_PARSER int spa_pod_parser_pop(struct spa_pod_parser *parser,
struct spa_pod_frame *frame)
{
parser->state.frame = frame->parent;
@ -121,7 +129,7 @@ static inline int spa_pod_parser_pop(struct spa_pod_parser *parser,
return 0;
}
static inline int spa_pod_parser_get_bool(struct spa_pod_parser *parser, bool *value)
SPA_API_POD_PARSER int spa_pod_parser_get_bool(struct spa_pod_parser *parser, bool *value)
{
int res = -EPIPE;
const struct spa_pod *pod = spa_pod_parser_current(parser);
@ -130,7 +138,7 @@ static inline int spa_pod_parser_get_bool(struct spa_pod_parser *parser, bool *v
return res;
}
static inline int spa_pod_parser_get_id(struct spa_pod_parser *parser, uint32_t *value)
SPA_API_POD_PARSER int spa_pod_parser_get_id(struct spa_pod_parser *parser, uint32_t *value)
{
int res = -EPIPE;
const struct spa_pod *pod = spa_pod_parser_current(parser);
@ -139,7 +147,7 @@ static inline int spa_pod_parser_get_id(struct spa_pod_parser *parser, uint32_t
return res;
}
static inline int spa_pod_parser_get_int(struct spa_pod_parser *parser, int32_t *value)
SPA_API_POD_PARSER int spa_pod_parser_get_int(struct spa_pod_parser *parser, int32_t *value)
{
int res = -EPIPE;
const struct spa_pod *pod = spa_pod_parser_current(parser);
@ -148,7 +156,7 @@ static inline int spa_pod_parser_get_int(struct spa_pod_parser *parser, int32_t
return res;
}
static inline int spa_pod_parser_get_long(struct spa_pod_parser *parser, int64_t *value)
SPA_API_POD_PARSER int spa_pod_parser_get_long(struct spa_pod_parser *parser, int64_t *value)
{
int res = -EPIPE;
const struct spa_pod *pod = spa_pod_parser_current(parser);
@ -157,7 +165,7 @@ static inline int spa_pod_parser_get_long(struct spa_pod_parser *parser, int64_t
return res;
}
static inline int spa_pod_parser_get_float(struct spa_pod_parser *parser, float *value)
SPA_API_POD_PARSER int spa_pod_parser_get_float(struct spa_pod_parser *parser, float *value)
{
int res = -EPIPE;
const struct spa_pod *pod = spa_pod_parser_current(parser);
@ -166,7 +174,7 @@ static inline int spa_pod_parser_get_float(struct spa_pod_parser *parser, float
return res;
}
static inline int spa_pod_parser_get_double(struct spa_pod_parser *parser, double *value)
SPA_API_POD_PARSER int spa_pod_parser_get_double(struct spa_pod_parser *parser, double *value)
{
int res = -EPIPE;
const struct spa_pod *pod = spa_pod_parser_current(parser);
@ -175,7 +183,7 @@ static inline int spa_pod_parser_get_double(struct spa_pod_parser *parser, doubl
return res;
}
static inline int spa_pod_parser_get_string(struct spa_pod_parser *parser, const char **value)
SPA_API_POD_PARSER int spa_pod_parser_get_string(struct spa_pod_parser *parser, const char **value)
{
int res = -EPIPE;
const struct spa_pod *pod = spa_pod_parser_current(parser);
@ -184,7 +192,7 @@ static inline int spa_pod_parser_get_string(struct spa_pod_parser *parser, const
return res;
}
static inline int spa_pod_parser_get_bytes(struct spa_pod_parser *parser, const void **value, uint32_t *len)
SPA_API_POD_PARSER int spa_pod_parser_get_bytes(struct spa_pod_parser *parser, const void **value, uint32_t *len)
{
int res = -EPIPE;
const struct spa_pod *pod = spa_pod_parser_current(parser);
@ -193,7 +201,7 @@ static inline int spa_pod_parser_get_bytes(struct spa_pod_parser *parser, const
return res;
}
static inline int spa_pod_parser_get_pointer(struct spa_pod_parser *parser, uint32_t *type, const void **value)
SPA_API_POD_PARSER int spa_pod_parser_get_pointer(struct spa_pod_parser *parser, uint32_t *type, const void **value)
{
int res = -EPIPE;
const struct spa_pod *pod = spa_pod_parser_current(parser);
@ -202,7 +210,7 @@ static inline int spa_pod_parser_get_pointer(struct spa_pod_parser *parser, uint
return res;
}
static inline int spa_pod_parser_get_fd(struct spa_pod_parser *parser, int64_t *value)
SPA_API_POD_PARSER int spa_pod_parser_get_fd(struct spa_pod_parser *parser, int64_t *value)
{
int res = -EPIPE;
const struct spa_pod *pod = spa_pod_parser_current(parser);
@ -211,7 +219,7 @@ static inline int spa_pod_parser_get_fd(struct spa_pod_parser *parser, int64_t *
return res;
}
static inline int spa_pod_parser_get_rectangle(struct spa_pod_parser *parser, struct spa_rectangle *value)
SPA_API_POD_PARSER int spa_pod_parser_get_rectangle(struct spa_pod_parser *parser, struct spa_rectangle *value)
{
int res = -EPIPE;
const struct spa_pod *pod = spa_pod_parser_current(parser);
@ -220,7 +228,7 @@ static inline int spa_pod_parser_get_rectangle(struct spa_pod_parser *parser, st
return res;
}
static inline int spa_pod_parser_get_fraction(struct spa_pod_parser *parser, struct spa_fraction *value)
SPA_API_POD_PARSER int spa_pod_parser_get_fraction(struct spa_pod_parser *parser, struct spa_fraction *value)
{
int res = -EPIPE;
const struct spa_pod *pod = spa_pod_parser_current(parser);
@ -229,7 +237,7 @@ static inline int spa_pod_parser_get_fraction(struct spa_pod_parser *parser, str
return res;
}
static inline int spa_pod_parser_get_pod(struct spa_pod_parser *parser, struct spa_pod **value)
SPA_API_POD_PARSER int spa_pod_parser_get_pod(struct spa_pod_parser *parser, struct spa_pod **value)
{
struct spa_pod *pod = spa_pod_parser_current(parser);
if (pod == NULL)
@ -238,7 +246,7 @@ static inline int spa_pod_parser_get_pod(struct spa_pod_parser *parser, struct s
spa_pod_parser_advance(parser, pod);
return 0;
}
static inline int spa_pod_parser_push_struct(struct spa_pod_parser *parser,
SPA_API_POD_PARSER int spa_pod_parser_push_struct(struct spa_pod_parser *parser,
struct spa_pod_frame *frame)
{
const struct spa_pod *pod = spa_pod_parser_current(parser);
@ -251,7 +259,7 @@ static inline int spa_pod_parser_push_struct(struct spa_pod_parser *parser,
return 0;
}
static inline int spa_pod_parser_push_object(struct spa_pod_parser *parser,
SPA_API_POD_PARSER int spa_pod_parser_push_object(struct spa_pod_parser *parser,
struct spa_pod_frame *frame, uint32_t type, uint32_t *id)
{
const struct spa_pod *pod = spa_pod_parser_current(parser);
@ -268,7 +276,7 @@ static inline int spa_pod_parser_push_object(struct spa_pod_parser *parser,
return 0;
}
static inline bool spa_pod_parser_can_collect(const struct spa_pod *pod, char type)
SPA_API_POD_PARSER bool spa_pod_parser_can_collect(const struct spa_pod *pod, char type)
{
if (pod == NULL)
return false;
@ -443,7 +451,7 @@ do { \
} \
} while(false)
static inline int spa_pod_parser_getv(struct spa_pod_parser *parser, va_list args)
SPA_API_POD_PARSER int spa_pod_parser_getv(struct spa_pod_parser *parser, va_list args)
{
struct spa_pod_frame *f = parser->state.frame;
uint32_t ftype = f ? f->pod.type : (uint32_t)SPA_TYPE_Struct;
@ -455,7 +463,7 @@ static inline int spa_pod_parser_getv(struct spa_pod_parser *parser, va_list arg
const struct spa_pod *pod = NULL;
const char *format;
if (ftype == SPA_TYPE_Object) {
if (f && ftype == SPA_TYPE_Object) {
uint32_t key = va_arg(args, uint32_t);
const struct spa_pod_object *object;
@ -496,7 +504,7 @@ static inline int spa_pod_parser_getv(struct spa_pod_parser *parser, va_list arg
return count;
}
static inline int spa_pod_parser_get(struct spa_pod_parser *parser, ...)
SPA_API_POD_PARSER int spa_pod_parser_get(struct spa_pod_parser *parser, ...)
{
int res;
va_list args;

View File

@ -9,10 +9,20 @@
extern "C" {
#endif
#include <errno.h>
#include <spa/utils/defs.h>
#include <spa/utils/hook.h>
#include <spa/support/system.h>
#ifndef SPA_API_LOOP
#ifdef SPA_API_IMPL
#define SPA_API_LOOP SPA_API_IMPL
#else
#define SPA_API_LOOP static inline
#endif
#endif
/** \defgroup spa_loop Loop
* Event loop interface
*/
@ -66,19 +76,56 @@ struct spa_loop_methods {
#define SPA_VERSION_LOOP_METHODS 0
uint32_t version;
/** add a source to the loop */
/** Add a source to the loop. Must be called from the loop's own thread.
*
* \param[in] object The callbacks data.
* \param[in] source The source.
* \return 0 on success, negative errno-style value on failure.
*/
int (*add_source) (void *object,
struct spa_source *source);
/** update the source io mask */
/** Update the source io mask. Must be called from the loop's own thread.
*
* \param[in] object The callbacks data.
* \param[in] source The source.
* \return 0 on success, negative errno-style value on failure.
*/
int (*update_source) (void *object,
struct spa_source *source);
/** remove a source from the loop */
/** Remove a source from the loop. Must be called from the loop's own thread.
*
* \param[in] object The callbacks data.
* \param[in] source The source.
* \return 0 on success, negative errno-style value on failure.
*/
int (*remove_source) (void *object,
struct spa_source *source);
/** invoke a function in the context of this loop */
/** Invoke a function in the context of this loop.
* May be called from any thread and multiple threads at the same time.
* If called from the loop's thread, all callbacks previously queued with
* invoke() will be run synchronously, which might cause unexpected
* reentrancy problems.
*
* \param[in] object The callbacks data.
* \param func The function to be invoked.
* \param seq An opaque sequence number. This will be made
* available to func.
* \param[in] data Data that will be copied into the internal ring buffer and made
* available to func. Because this data is copied, it is okay to
* pass a pointer to a local variable, but do not pass a pointer to
* an object that has identity.
* \param size The size of data to copy.
* \param block If \true, do not return until func has been called. Otherwise,
* returns immediately. Passing \true does not risk a deadlock because
* the data thread is never allowed to wait on any other thread.
* \param user_data An opaque pointer passed to func.
* \return `-EPIPE` if the internal ring buffer filled up,
* if block is \false, 0 if seq was SPA_ID_INVALID or
* seq with the ASYNC flag set
* or the return value of func otherwise. */
int (*invoke) (void *object,
spa_invoke_func_t func,
uint32_t seq,
@ -88,21 +135,29 @@ struct spa_loop_methods {
void *user_data);
};
#define spa_loop_method(o,method,version,...) \
({ \
int _res = -ENOTSUP; \
struct spa_loop *_o = o; \
spa_interface_call_res(&_o->iface, \
struct spa_loop_methods, _res, \
method, version, ##__VA_ARGS__); \
_res; \
})
#define spa_loop_add_source(l,...) spa_loop_method(l,add_source,0,##__VA_ARGS__)
#define spa_loop_update_source(l,...) spa_loop_method(l,update_source,0,##__VA_ARGS__)
#define spa_loop_remove_source(l,...) spa_loop_method(l,remove_source,0,##__VA_ARGS__)
#define spa_loop_invoke(l,...) spa_loop_method(l,invoke,0,##__VA_ARGS__)
SPA_API_LOOP int spa_loop_add_source(struct spa_loop *object, struct spa_source *source)
{
return spa_api_method_r(int, -ENOTSUP,
spa_loop, &object->iface, add_source, 0, source);
}
SPA_API_LOOP int spa_loop_update_source(struct spa_loop *object, struct spa_source *source)
{
return spa_api_method_r(int, -ENOTSUP,
spa_loop, &object->iface, update_source, 0, source);
}
SPA_API_LOOP int spa_loop_remove_source(struct spa_loop *object, struct spa_source *source)
{
return spa_api_method_r(int, -ENOTSUP,
spa_loop, &object->iface, remove_source, 0, source);
}
SPA_API_LOOP int spa_loop_invoke(struct spa_loop *object,
spa_invoke_func_t func, uint32_t seq, const void *data,
size_t size, bool block, void *user_data)
{
return spa_api_method_r(int, -ENOTSUP,
spa_loop, &object->iface, invoke, 0, func, seq, data,
size, block, user_data);
}
/** Control hooks. These hooks can't be removed from their
* callbacks and must be removed from a safe place (when the loop
@ -118,24 +173,42 @@ struct spa_loop_control_hooks {
void (*after) (void *data);
};
#define spa_loop_control_hook_before(l) \
({ \
struct spa_hook_list *_l = l; \
struct spa_hook *_h; \
spa_list_for_each_reverse(_h, &_l->list, link) \
spa_callbacks_call(&_h->cb, struct spa_loop_control_hooks, before, 0); \
})
SPA_API_LOOP void spa_loop_control_hook_before(struct spa_hook_list *l)
{
struct spa_hook *h;
spa_list_for_each_reverse(h, &l->list, link)
spa_callbacks_call_fast(&h->cb, struct spa_loop_control_hooks, before, 0);
}
#define spa_loop_control_hook_after(l) \
({ \
struct spa_hook_list *_l = l; \
struct spa_hook *_h; \
spa_list_for_each(_h, &_l->list, link) \
spa_callbacks_call(&_h->cb, struct spa_loop_control_hooks, after, 0); \
})
SPA_API_LOOP void spa_loop_control_hook_after(struct spa_hook_list *l)
{
struct spa_hook *h;
spa_list_for_each(h, &l->list, link)
spa_callbacks_call_fast(&h->cb, struct spa_loop_control_hooks, after, 0);
}
/**
* Control an event loop
*
* The event loop control function provide API to run the event loop.
*
* The below (pseudo)code is a minimal example outlining the use of the loop
* control:
* \code{.c}
* spa_loop_control_enter(loop);
* while (running) {
* spa_loop_control_iterate(loop, -1);
* }
* spa_loop_control_leave(loop);
* \endcode
*
* It is also possible to add the loop to an existing event loop by using the
* spa_loop_control_get_fd() call. This fd will become readable when activity
* has been detected on the sources in the loop. spa_loop_control_iterate() with
* a 0 timeout should be called to process the pending sources.
*
* spa_loop_control_enter() and spa_loop_control_leave() should be called once
* from the thread that will run the iterate() function.
*/
struct spa_loop_control_methods {
/* the version of this structure. This can be used to expand this
@ -143,10 +216,19 @@ struct spa_loop_control_methods {
#define SPA_VERSION_LOOP_CONTROL_METHODS 1
uint32_t version;
/** get the loop fd
* \param object the control to query
*
* Get the fd of this loop control. This fd will be readable when a
* source in the loop has activity. The user should call iterate()
* with a 0 timeout to schedule one iteration of the loop and dispatch
* the sources.
* \return the fd of the loop
*/
int (*get_fd) (void *object);
/** Add a hook
* \param ctrl the control to change
* \param object the control to change
* \param hooks the hooks to add
*
* Adds hooks to the loop controlled by \a ctrl.
@ -157,18 +239,19 @@ struct spa_loop_control_methods {
void *data);
/** Enter a loop
* \param ctrl the control
* \param object the control
*
* Start an iteration of the loop. This function should be called
* before calling iterate and is typically used to capture the thread
* that this loop will run in.
* This function should be called before calling iterate and is
* typically used to capture the thread that this loop will run in.
* It should ideally be called once from the thread that will run
* the loop.
*/
void (*enter) (void *object);
/** Leave a loop
* \param ctrl the control
* \param object the control
*
* Ends the iteration of a loop. This should be called after calling
* iterate.
* It should ideally be called once after calling iterate when the loop
* will no longer be iterated from the thread that called enter().
*/
void (*leave) (void *object);
@ -194,30 +277,43 @@ struct spa_loop_control_methods {
int (*check) (void *object);
};
#define spa_loop_control_method_v(o,method,version,...) \
({ \
struct spa_loop_control *_o = o; \
spa_interface_call(&_o->iface, \
struct spa_loop_control_methods, \
method, version, ##__VA_ARGS__); \
})
#define spa_loop_control_method_r(o,method,version,...) \
({ \
int _res = -ENOTSUP; \
struct spa_loop_control *_o = o; \
spa_interface_call_res(&_o->iface, \
struct spa_loop_control_methods, _res, \
method, version, ##__VA_ARGS__); \
_res; \
})
#define spa_loop_control_get_fd(l) spa_loop_control_method_r(l,get_fd,0)
#define spa_loop_control_add_hook(l,...) spa_loop_control_method_v(l,add_hook,0,__VA_ARGS__)
#define spa_loop_control_enter(l) spa_loop_control_method_v(l,enter,0)
#define spa_loop_control_leave(l) spa_loop_control_method_v(l,leave,0)
#define spa_loop_control_iterate(l,...) spa_loop_control_method_r(l,iterate,0,__VA_ARGS__)
#define spa_loop_control_check(l) spa_loop_control_method_r(l,check,1)
SPA_API_LOOP int spa_loop_control_get_fd(struct spa_loop_control *object)
{
return spa_api_method_r(int, -ENOTSUP,
spa_loop_control, &object->iface, get_fd, 0);
}
SPA_API_LOOP void spa_loop_control_add_hook(struct spa_loop_control *object,
struct spa_hook *hook, const struct spa_loop_control_hooks *hooks,
void *data)
{
spa_api_method_v(spa_loop_control, &object->iface, add_hook, 0,
hook, hooks, data);
}
SPA_API_LOOP void spa_loop_control_enter(struct spa_loop_control *object)
{
spa_api_method_v(spa_loop_control, &object->iface, enter, 0);
}
SPA_API_LOOP void spa_loop_control_leave(struct spa_loop_control *object)
{
spa_api_method_v(spa_loop_control, &object->iface, leave, 0);
}
SPA_API_LOOP int spa_loop_control_iterate(struct spa_loop_control *object,
int timeout)
{
return spa_api_method_r(int, -ENOTSUP,
spa_loop_control, &object->iface, iterate, 0, timeout);
}
SPA_API_LOOP int spa_loop_control_iterate_fast(struct spa_loop_control *object,
int timeout)
{
return spa_api_method_fast_r(int, -ENOTSUP,
spa_loop_control, &object->iface, iterate, 0, timeout);
}
SPA_API_LOOP int spa_loop_control_check(struct spa_loop_control *object)
{
return spa_api_method_r(int, -ENOTSUP,
spa_loop_control, &object->iface, check, 1);
}
typedef void (*spa_source_io_func_t) (void *data, int fd, uint32_t mask);
typedef void (*spa_source_idle_func_t) (void *data);
@ -268,44 +364,71 @@ struct spa_loop_utils_methods {
void (*destroy_source) (void *object, struct spa_source *source);
};
#define spa_loop_utils_method_v(o,method,version,...) \
({ \
struct spa_loop_utils *_o = o; \
spa_interface_call(&_o->iface, \
struct spa_loop_utils_methods, \
method, version, ##__VA_ARGS__); \
})
#define spa_loop_utils_method_r(o,method,version,...) \
({ \
int _res = -ENOTSUP; \
struct spa_loop_utils *_o = o; \
spa_interface_call_res(&_o->iface, \
struct spa_loop_utils_methods, _res, \
method, version, ##__VA_ARGS__); \
_res; \
})
#define spa_loop_utils_method_s(o,method,version,...) \
({ \
struct spa_source *_res = NULL; \
struct spa_loop_utils *_o = o; \
spa_interface_call_res(&_o->iface, \
struct spa_loop_utils_methods, _res, \
method, version, ##__VA_ARGS__); \
_res; \
})
#define spa_loop_utils_add_io(l,...) spa_loop_utils_method_s(l,add_io,0,__VA_ARGS__)
#define spa_loop_utils_update_io(l,...) spa_loop_utils_method_r(l,update_io,0,__VA_ARGS__)
#define spa_loop_utils_add_idle(l,...) spa_loop_utils_method_s(l,add_idle,0,__VA_ARGS__)
#define spa_loop_utils_enable_idle(l,...) spa_loop_utils_method_r(l,enable_idle,0,__VA_ARGS__)
#define spa_loop_utils_add_event(l,...) spa_loop_utils_method_s(l,add_event,0,__VA_ARGS__)
#define spa_loop_utils_signal_event(l,...) spa_loop_utils_method_r(l,signal_event,0,__VA_ARGS__)
#define spa_loop_utils_add_timer(l,...) spa_loop_utils_method_s(l,add_timer,0,__VA_ARGS__)
#define spa_loop_utils_update_timer(l,...) spa_loop_utils_method_r(l,update_timer,0,__VA_ARGS__)
#define spa_loop_utils_add_signal(l,...) spa_loop_utils_method_s(l,add_signal,0,__VA_ARGS__)
#define spa_loop_utils_destroy_source(l,...) spa_loop_utils_method_v(l,destroy_source,0,__VA_ARGS__)
SPA_API_LOOP struct spa_source *
spa_loop_utils_add_io(struct spa_loop_utils *object, int fd, uint32_t mask,
bool close, spa_source_io_func_t func, void *data)
{
return spa_api_method_r(struct spa_source *, NULL,
spa_loop_utils, &object->iface, add_io, 0, fd, mask, close, func, data);
}
SPA_API_LOOP int spa_loop_utils_update_io(struct spa_loop_utils *object,
struct spa_source *source, uint32_t mask)
{
return spa_api_method_r(int, -ENOTSUP,
spa_loop_utils, &object->iface, update_io, 0, source, mask);
}
SPA_API_LOOP struct spa_source *
spa_loop_utils_add_idle(struct spa_loop_utils *object, bool enabled,
spa_source_idle_func_t func, void *data)
{
return spa_api_method_r(struct spa_source *, NULL,
spa_loop_utils, &object->iface, add_idle, 0, enabled, func, data);
}
SPA_API_LOOP int spa_loop_utils_enable_idle(struct spa_loop_utils *object,
struct spa_source *source, bool enabled)
{
return spa_api_method_r(int, -ENOTSUP,
spa_loop_utils, &object->iface, enable_idle, 0, source, enabled);
}
SPA_API_LOOP struct spa_source *
spa_loop_utils_add_event(struct spa_loop_utils *object, spa_source_event_func_t func, void *data)
{
return spa_api_method_r(struct spa_source *, NULL,
spa_loop_utils, &object->iface, add_event, 0, func, data);
}
SPA_API_LOOP int spa_loop_utils_signal_event(struct spa_loop_utils *object,
struct spa_source *source)
{
return spa_api_method_r(int, -ENOTSUP,
spa_loop_utils, &object->iface, signal_event, 0, source);
}
SPA_API_LOOP struct spa_source *
spa_loop_utils_add_timer(struct spa_loop_utils *object, spa_source_timer_func_t func, void *data)
{
return spa_api_method_r(struct spa_source *, NULL,
spa_loop_utils, &object->iface, add_timer, 0, func, data);
}
SPA_API_LOOP int spa_loop_utils_update_timer(struct spa_loop_utils *object,
struct spa_source *source, struct timespec *value,
struct timespec *interval, bool absolute)
{
return spa_api_method_r(int, -ENOTSUP,
spa_loop_utils, &object->iface, update_timer, 0, source,
value, interval, absolute);
}
SPA_API_LOOP struct spa_source *
spa_loop_utils_add_signal(struct spa_loop_utils *object, int signal_number,
spa_source_signal_func_t func, void *data)
{
return spa_api_method_r(struct spa_source *, NULL,
spa_loop_utils, &object->iface, add_signal, 0,
signal_number, func, data);
}
SPA_API_LOOP void spa_loop_utils_destroy_source(struct spa_loop_utils *object,
struct spa_source *source)
{
spa_api_method_v(spa_loop_utils, &object->iface, destroy_source, 0, source);
}
/**
* \}

View File

@ -12,11 +12,20 @@ extern "C" {
struct itimerspec;
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <spa/utils/defs.h>
#include <spa/utils/hook.h>
#ifndef SPA_API_SYSTEM
#ifdef SPA_API_IMPL
#define SPA_API_SYSTEM SPA_API_IMPL
#else
#define SPA_API_SYSTEM static inline
#endif
#endif
/** \defgroup spa_system System
* I/O, clock, polling, timer, and signal interfaces
*/
@ -97,42 +106,106 @@ struct spa_system_methods {
int (*signalfd_read) (void *object, int fd, int *signal);
};
#define spa_system_method_r(o,method,version,...) \
({ \
volatile int _res = -ENOTSUP; \
struct spa_system *_o = o; \
spa_interface_call_res(&_o->iface, \
struct spa_system_methods, _res, \
method, version, ##__VA_ARGS__); \
_res; \
})
SPA_API_SYSTEM ssize_t spa_system_read(struct spa_system *object, int fd, void *buf, size_t count)
{
return spa_api_method_fast_r(ssize_t, -ENOTSUP, spa_system, &object->iface, read, 0, fd, buf, count);
}
SPA_API_SYSTEM ssize_t spa_system_write(struct spa_system *object, int fd, const void *buf, size_t count)
{
return spa_api_method_fast_r(ssize_t, -ENOTSUP, spa_system, &object->iface, write, 0, fd, buf, count);
}
#define spa_system_ioctl(object,fd,request,...) \
spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, ioctl, 0, fd, request, ##__VA_ARGS__)
SPA_API_SYSTEM int spa_system_close(struct spa_system *object, int fd)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, close, 0, fd);
}
SPA_API_SYSTEM int spa_system_clock_gettime(struct spa_system *object,
int clockid, struct timespec *value)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, clock_gettime, 0, clockid, value);
}
SPA_API_SYSTEM int spa_system_clock_getres(struct spa_system *object,
int clockid, struct timespec *res)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, clock_getres, 0, clockid, res);
}
#define spa_system_read(s,...) spa_system_method_r(s,read,0,__VA_ARGS__)
#define spa_system_write(s,...) spa_system_method_r(s,write,0,__VA_ARGS__)
#define spa_system_ioctl(s,...) spa_system_method_r(s,ioctl,0,__VA_ARGS__)
#define spa_system_close(s,...) spa_system_method_r(s,close,0,__VA_ARGS__)
SPA_API_SYSTEM int spa_system_pollfd_create(struct spa_system *object, int flags)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, pollfd_create, 0, flags);
}
SPA_API_SYSTEM int spa_system_pollfd_add(struct spa_system *object, int pfd, int fd, uint32_t events, void *data)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, pollfd_add, 0, pfd, fd, events, data);
}
SPA_API_SYSTEM int spa_system_pollfd_mod(struct spa_system *object, int pfd, int fd, uint32_t events, void *data)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, pollfd_mod, 0, pfd, fd, events, data);
}
SPA_API_SYSTEM int spa_system_pollfd_del(struct spa_system *object, int pfd, int fd)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, pollfd_del, 0, pfd, fd);
}
SPA_API_SYSTEM int spa_system_pollfd_wait(struct spa_system *object, int pfd,
struct spa_poll_event *ev, int n_ev, int timeout)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, pollfd_wait, 0, pfd, ev, n_ev, timeout);
}
#define spa_system_clock_gettime(s,...) spa_system_method_r(s,clock_gettime,0,__VA_ARGS__)
#define spa_system_clock_getres(s,...) spa_system_method_r(s,clock_getres,0,__VA_ARGS__)
SPA_API_SYSTEM int spa_system_timerfd_create(struct spa_system *object, int clockid, int flags)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, timerfd_create, 0, clockid, flags);
}
#define spa_system_pollfd_create(s,...) spa_system_method_r(s,pollfd_create,0,__VA_ARGS__)
#define spa_system_pollfd_add(s,...) spa_system_method_r(s,pollfd_add,0,__VA_ARGS__)
#define spa_system_pollfd_mod(s,...) spa_system_method_r(s,pollfd_mod,0,__VA_ARGS__)
#define spa_system_pollfd_del(s,...) spa_system_method_r(s,pollfd_del,0,__VA_ARGS__)
#define spa_system_pollfd_wait(s,...) spa_system_method_r(s,pollfd_wait,0,__VA_ARGS__)
SPA_API_SYSTEM int spa_system_timerfd_settime(struct spa_system *object,
int fd, int flags,
const struct itimerspec *new_value,
struct itimerspec *old_value)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, timerfd_settime, 0,
fd, flags, new_value, old_value);
}
#define spa_system_timerfd_create(s,...) spa_system_method_r(s,timerfd_create,0,__VA_ARGS__)
#define spa_system_timerfd_settime(s,...) spa_system_method_r(s,timerfd_settime,0,__VA_ARGS__)
#define spa_system_timerfd_gettime(s,...) spa_system_method_r(s,timerfd_gettime,0,__VA_ARGS__)
#define spa_system_timerfd_read(s,...) spa_system_method_r(s,timerfd_read,0,__VA_ARGS__)
SPA_API_SYSTEM int spa_system_timerfd_gettime(struct spa_system *object,
int fd, struct itimerspec *curr_value)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, timerfd_gettime, 0,
fd, curr_value);
}
SPA_API_SYSTEM int spa_system_timerfd_read(struct spa_system *object, int fd, uint64_t *expirations)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, timerfd_read, 0,
fd, expirations);
}
#define spa_system_eventfd_create(s,...) spa_system_method_r(s,eventfd_create,0,__VA_ARGS__)
#define spa_system_eventfd_write(s,...) spa_system_method_r(s,eventfd_write,0,__VA_ARGS__)
#define spa_system_eventfd_read(s,...) spa_system_method_r(s,eventfd_read,0,__VA_ARGS__)
SPA_API_SYSTEM int spa_system_eventfd_create(struct spa_system *object, int flags)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, eventfd_create, 0, flags);
}
SPA_API_SYSTEM int spa_system_eventfd_write(struct spa_system *object, int fd, uint64_t count)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, eventfd_write, 0,
fd, count);
}
SPA_API_SYSTEM int spa_system_eventfd_read(struct spa_system *object, int fd, uint64_t *count)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, eventfd_read, 0,
fd, count);
}
#define spa_system_signalfd_create(s,...) spa_system_method_r(s,signalfd_create,0,__VA_ARGS__)
#define spa_system_signalfd_read(s,...) spa_system_method_r(s,signalfd_read,0,__VA_ARGS__)
SPA_API_SYSTEM int spa_system_signalfd_create(struct spa_system *object, int signal, int flags)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, signalfd_create, 0,
signal, flags);
}
SPA_API_SYSTEM int spa_system_signalfd_read(struct spa_system *object, int fd, int *signal)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, signalfd_read, 0,
fd, signal);
}
/**
* \}

View File

@ -0,0 +1,124 @@
/* Simple Plugin API */
/* SPDX-FileCopyrightText: Copyright © 2023 PipeWire authors */
/* SPDX-License-Identifier: MIT */
#ifndef SPA_UTILS_CLEANUP_H
#define SPA_UTILS_CLEANUP_H
#define spa_exchange(var, new_value) \
__extension__ ({ \
__typeof__(var) *_ptr_ = &(var); \
__typeof__(var) _old_value_ = *_ptr_; \
*_ptr_ = (new_value); \
_old_value_; \
})
/* ========================================================================== */
#if __GNUC__ >= 10 || defined(__clang__)
#define spa_steal_ptr(ptr) ((__typeof__(*(ptr)) *) spa_exchange((ptr), NULL))
#else
#define spa_steal_ptr(ptr) spa_exchange((ptr), NULL)
#endif
#define spa_clear_ptr(ptr, destructor) \
__extension__ ({ \
__typeof__(ptr) _old_value = spa_steal_ptr(ptr); \
if (_old_value) \
destructor(_old_value); \
(void) 0; \
})
/* ========================================================================== */
#include <errno.h>
#include <unistd.h>
#define spa_steal_fd(fd) spa_exchange((fd), -1)
#define spa_clear_fd(fd) \
__extension__ ({ \
int _old_value = spa_steal_fd(fd), _res = 0; \
if (_old_value >= 0) \
_res = close(_old_value); \
_res; \
})
/* ========================================================================== */
#if defined(__has_attribute) && __has_attribute(__cleanup__)
#define spa_cleanup(func) __attribute__((__cleanup__(func)))
#define SPA_DEFINE_AUTO_CLEANUP(name, type, ...) \
typedef __typeof__(type) _spa_auto_cleanup_type_ ## name; \
static inline void _spa_auto_cleanup_func_ ## name (__typeof__(type) *thing) \
{ \
int _save_errno = errno; \
__VA_ARGS__ \
errno = _save_errno; \
}
#define spa_auto(name) \
spa_cleanup(_spa_auto_cleanup_func_ ## name) \
_spa_auto_cleanup_type_ ## name
#define SPA_DEFINE_AUTOPTR_CLEANUP(name, type, ...) \
typedef __typeof__(type) * _spa_autoptr_cleanup_type_ ## name; \
static inline void _spa_autoptr_cleanup_func_ ## name (__typeof__(type) **thing) \
{ \
int _save_errno = errno; \
__VA_ARGS__ \
errno = _save_errno; \
}
#define spa_autoptr(name) \
spa_cleanup(_spa_autoptr_cleanup_func_ ## name) \
_spa_autoptr_cleanup_type_ ## name
/* ========================================================================== */
#include <stdlib.h>
static inline void _spa_autofree_cleanup_func(void *p)
{
int save_errno = errno;
free(*(void **) p);
errno = save_errno;
}
#define spa_autofree spa_cleanup(_spa_autofree_cleanup_func)
/* ========================================================================== */
static inline void _spa_autoclose_cleanup_func(int *fd)
{
int save_errno = errno;
spa_clear_fd(*fd);
errno = save_errno;
}
#define spa_autoclose spa_cleanup(_spa_autoclose_cleanup_func)
/* ========================================================================== */
#include <stdio.h>
SPA_DEFINE_AUTOPTR_CLEANUP(FILE, FILE, {
spa_clear_ptr(*thing, fclose);
})
/* ========================================================================== */
#include <dirent.h>
SPA_DEFINE_AUTOPTR_CLEANUP(DIR, DIR, {
spa_clear_ptr(*thing, closedir);
})
#else
#define SPA_DEFINE_AUTO_CLEANUP(name, type, ...)
#define SPA_DEFINE_AUTOPTR_CLEANUP(name, type, ...)
#endif
#endif /* SPA_UTILS_CLEANUP_H */

View File

@ -9,20 +9,31 @@
extern "C" {
# if __cplusplus >= 201103L
# define SPA_STATIC_ASSERT_IMPL(expr, msg, ...) static_assert(expr, msg)
# define SPA_ALIGNOF alignof
# endif
#elif __STDC_VERSION__ >= 202311L
# define SPA_STATIC_ASSERT_IMPL(expr, msg, ...) static_assert(expr, msg)
# define SPA_ALIGNOF alignof
#else
# include <stdbool.h>
# if __STDC_VERSION__ >= 201112L
# define SPA_STATIC_ASSERT_IMPL(expr, msg, ...) _Static_assert(expr, msg)
# define SPA_ALIGNOF _Alignof
# endif
#endif
#ifndef SPA_STATIC_ASSERT_IMPL
#define SPA_STATIC_ASSERT_IMPL(expr, ...) \
((void)sizeof(struct { int spa_static_assertion_failed : 2 * !!(expr) - 1; }))
#endif
#ifndef SPA_ALIGNOF
#define SPA_ALIGNOF __alignof__
#endif
#define SPA_STATIC_ASSERT(expr, ...) SPA_STATIC_ASSERT_IMPL(expr, ## __VA_ARGS__, "`" #expr "` evaluated to false")
#define SPA_CONCAT_NOEXPAND(a, b) a ## b
#define SPA_CONCAT(a, b) SPA_CONCAT_NOEXPAND(a, b)
#include <inttypes.h>
#include <signal.h>
#include <stdlib.h>
@ -122,10 +133,10 @@ struct spa_fraction {
* ```
*/
#define SPA_FOR_EACH_ELEMENT(arr, ptr) \
for ((ptr) = arr; (void*)(ptr) < SPA_PTROFF(arr, sizeof(arr), void); (ptr)++)
for ((ptr) = arr; (ptr) < (arr) + SPA_N_ELEMENTS(arr); (ptr)++)
#define SPA_FOR_EACH_ELEMENT_VAR(arr, var) \
for (__typeof__((arr)[0])* var = arr; (void*)(var) < SPA_PTROFF(arr, sizeof(arr), void); (var)++)
for (__typeof__((arr)[0])* var = arr; (var) < (arr) + SPA_N_ELEMENTS(arr); (var)++)
#define SPA_ABS(a) \
({ \
@ -156,6 +167,10 @@ struct spa_fraction {
({ \
fminf(fmaxf(v, low), high); \
})
#define SPA_CLAMPD(v,low,high) \
({ \
fmin(fmax(v, low), high); \
})
#define SPA_SWAP(a,b) \
@ -171,6 +186,16 @@ struct spa_fraction {
x; \
})
/** 3-way comparison. NaN > NaN and NaN > finite numbers */
#define SPA_CMP(a, b) \
({ \
__typeof__(a) _a = (a); \
__typeof__(b) _b = (b); \
(_a > _b) ? 1 : (_a == _b) ? 0 : (_a < _b) ? -1 \
: (_a == _a) ? -1 : (_b == _b) ? 1 \
: 1; \
})
/**
* Return the address (buffer + offset) as pointer of \a type
*/
@ -178,7 +203,6 @@ struct spa_fraction {
#define SPA_PTROFF_ALIGN(ptr_,offset_,alignment_,type_) \
SPA_PTR_ALIGN(SPA_PTROFF(ptr_,offset_,type_),alignment_,type_)
/**
* Deprecated, use SPA_PTROFF and SPA_PTROFF_ALIGN instead
*/
@ -189,9 +213,6 @@ struct spa_fraction {
#define SPA_PTRDIFF(p1,p2) ((intptr_t)(p1) - (intptr_t)(p2))
#define SPA_PTR_TO_INT(p) ((int) ((intptr_t) (p)))
#define SPA_INT_TO_PTR(u) ((void*) ((intptr_t) (u)))
#define SPA_PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p)))
#define SPA_UINT32_TO_PTR(u) ((void*) ((uintptr_t) (u)))
@ -233,6 +254,20 @@ struct spa_fraction {
#define SPA_WARN_UNUSED_RESULT
#endif
#ifndef SPA_API_IMPL
#define SPA_API_PROTO static inline
#define SPA_API_IMPL static inline
#endif
#ifndef SPA_API_UTILS_DEFS
#ifdef SPA_API_IMPL
#define SPA_API_UTILS_DEFS SPA_API_IMPL
#else
#define SPA_API_UTILS_DEFS static inline
#endif
#endif
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define SPA_RESTRICT restrict
#elif defined(__GNUC__) && __GNUC__ >= 4
@ -265,7 +300,7 @@ struct spa_fraction {
})
#define SPA_PTR_ALIGNMENT(p,align) ((intptr_t)(p) & ((align)-1))
#define SPA_PTR_ALIGNMENT(p,align) ((uintptr_t)(p) & ((align)-1))
#define SPA_IS_ALIGNED(p,align) (SPA_PTR_ALIGNMENT(p,align) == 0)
#define SPA_PTR_ALIGN(p,align,type) ((type*)SPA_ROUND_UP_N((intptr_t)(p), (intptr_t)(align)))
@ -279,9 +314,51 @@ struct spa_fraction {
#endif
#endif
SPA_API_UTILS_DEFS bool spa_ptrinside(const void *p1, size_t s1, const void *p2, size_t s2,
size_t *remaining)
{
if (SPA_LIKELY((uintptr_t)p1 <= (uintptr_t)p2 && s2 <= s1 &&
(uintptr_t)p2 - (uintptr_t)p1 <= s1 - s2)) {
if (remaining != NULL)
*remaining = ((uintptr_t)p1 + s1) - ((uintptr_t)p2 + s2);
return true;
} else {
if (remaining != NULL)
*remaining = 0;
return false;
}
}
SPA_API_UTILS_DEFS bool spa_ptr_inside_and_aligned(const void *p1, size_t s1,
const void *p2, size_t s2, size_t align,
size_t *remaining)
{
if (SPA_IS_ALIGNED(p2, align)) {
return spa_ptrinside(p1, s1, p2, s2, remaining);
} else {
if (remaining != NULL)
*remaining = 0;
return false;
}
}
#define spa_ptr_type_inside(p1, s1, p2, type, remaining) \
spa_ptr_inside_and_aligned(p1, s1, p2, sizeof(type), SPA_ALIGNOF(type), remaining)
#define SPA_PTR_TO_INT(p) ((int) ((intptr_t) (p)))
#define SPA_INT_TO_PTR(u) ((void*) ((intptr_t) (u)))
#define SPA_STRINGIFY_1(...) #__VA_ARGS__
#define SPA_STRINGIFY(...) SPA_STRINGIFY_1(__VA_ARGS__)
struct spa_error_location {
int line;
int col;
size_t len;
const char *location;
const char *reason;
};
#define spa_return_if_fail(expr) \
do { \
if (SPA_UNLIKELY(!(expr))) { \

View File

@ -13,6 +13,14 @@ extern "C" {
#include <spa/utils/defs.h>
#ifndef SPA_API_DICT
#ifdef SPA_API_IMPL
#define SPA_API_DICT SPA_API_IMPL
#else
#define SPA_API_DICT static inline
#endif
#endif
/**
* \defgroup spa_dict Dictionary
* Dictionary data structure
@ -28,7 +36,8 @@ struct spa_dict_item {
const char *value;
};
#define SPA_DICT_ITEM_INIT(key,value) ((struct spa_dict_item) { (key), (value) })
#define SPA_DICT_ITEM(key,value) ((struct spa_dict_item) { (key), (value) })
#define SPA_DICT_ITEM_INIT(key,value) SPA_DICT_ITEM(key,value)
struct spa_dict {
#define SPA_DICT_FLAG_SORTED (1<<0) /**< items are sorted */
@ -37,22 +46,26 @@ struct spa_dict {
const struct spa_dict_item *items;
};
#define SPA_DICT_INIT(items,n_items) ((struct spa_dict) { 0, (n_items), (items) })
#define SPA_DICT_INIT_ARRAY(items) ((struct spa_dict) { 0, SPA_N_ELEMENTS(items), (items) })
#define SPA_DICT(items,n_items) ((struct spa_dict) { 0, (n_items), (items) })
#define SPA_DICT_ARRAY(items) SPA_DICT((items),SPA_N_ELEMENTS(items))
#define SPA_DICT_ITEMS(...) SPA_DICT_ARRAY(((struct spa_dict_item[]) { __VA_ARGS__}))
#define SPA_DICT_INIT(items,n_items) SPA_DICT(items,n_items)
#define SPA_DICT_INIT_ARRAY(items) SPA_DICT_ARRAY(items)
#define spa_dict_for_each(item, dict) \
for ((item) = (dict)->items; \
(item) < &(dict)->items[(dict)->n_items]; \
(item)++)
static inline int spa_dict_item_compare(const void *i1, const void *i2)
SPA_API_DICT int spa_dict_item_compare(const void *i1, const void *i2)
{
const struct spa_dict_item *it1 = (const struct spa_dict_item *)i1,
*it2 = (const struct spa_dict_item *)i2;
return strcmp(it1->key, it2->key);
}
static inline void spa_dict_qsort(struct spa_dict *dict)
SPA_API_DICT void spa_dict_qsort(struct spa_dict *dict)
{
if (dict->n_items > 0)
qsort((void*)dict->items, dict->n_items, sizeof(struct spa_dict_item),
@ -60,7 +73,7 @@ static inline void spa_dict_qsort(struct spa_dict *dict)
SPA_FLAG_SET(dict->flags, SPA_DICT_FLAG_SORTED);
}
static inline const struct spa_dict_item *spa_dict_lookup_item(const struct spa_dict *dict,
SPA_API_DICT const struct spa_dict_item *spa_dict_lookup_item(const struct spa_dict *dict,
const char *key)
{
const struct spa_dict_item *item;
@ -83,7 +96,7 @@ static inline const struct spa_dict_item *spa_dict_lookup_item(const struct spa_
return NULL;
}
static inline const char *spa_dict_lookup(const struct spa_dict *dict, const char *key)
SPA_API_DICT const char *spa_dict_lookup(const struct spa_dict *dict, const char *key)
{
const struct spa_dict_item *item = spa_dict_lookup_item(dict, key);
return item ? item->value : NULL;

View File

@ -0,0 +1,26 @@
/* Spa */
/* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#ifndef SPA_ENDIAN_H
#define SPA_ENDIAN_H
#if defined(__FreeBSD__) || defined(__MidnightBSD__)
#include <sys/endian.h>
#define bswap_16 bswap16
#define bswap_32 bswap32
#define bswap_64 bswap64
#elif defined(_MSC_VER) && defined(_WIN32)
#include <stdlib.h>
#define __LITTLE_ENDIAN 1234
#define __BIG_ENDIAN 4321
#define __BYTE_ORDER __LITTLE_ENDIAN
#define bswap_16 _byteswap_ushort
#define bswap_32 _byteswap_ulong
#define bswap_64 _byteswap_uint64
#else
#include <endian.h>
#include <byteswap.h>
#endif
#endif /* SPA_ENDIAN_H */

View File

@ -10,6 +10,12 @@ extern "C" {
#endif
#include <spa/utils/type.h>
#include <spa/pod/pod.h>
/**
* \addtogroup spa_types
* \{
*/
#define SPA_TYPE_INFO_Direction SPA_TYPE_INFO_ENUM_BASE "Direction"
#define SPA_TYPE_INFO_DIRECTION_BASE SPA_TYPE_INFO_Direction ":"
@ -20,8 +26,6 @@ static const struct spa_type_info spa_type_direction[] = {
{ 0, 0, NULL, NULL }
};
#include <spa/pod/pod.h>
#define SPA_TYPE_INFO_Choice SPA_TYPE_INFO_ENUM_BASE "Choice"
#define SPA_TYPE_INFO_CHOICE_BASE SPA_TYPE_INFO_Choice ":"

View File

@ -12,6 +12,14 @@ extern "C" {
#include <spa/utils/defs.h>
#include <spa/utils/list.h>
#ifndef SPA_API_HOOK
#ifdef SPA_API_IMPL
#define SPA_API_HOOK SPA_API_IMPL
#else
#define SPA_API_HOOK static inline
#endif
#endif
/** \defgroup spa_interfaces Interfaces
*
* \brief Generic implementation of implementation-independent interfaces
@ -158,10 +166,18 @@ struct spa_interface {
const type *_f = (const type *) (callbacks)->funcs; \
bool _res = SPA_CALLBACK_CHECK(_f,method,vers); \
if (SPA_LIKELY(_res)) \
_f->method((callbacks)->data, ## __VA_ARGS__); \
(_f->method)((callbacks)->data, ## __VA_ARGS__); \
_res; \
})
#define spa_callbacks_call_fast(callbacks,type,method,vers,...) \
({ \
const type *_f = (const type *) (callbacks)->funcs; \
(_f->method)((callbacks)->data, ## __VA_ARGS__); \
true; \
})
/**
* True if the \a callbacks are of version \a vers, false otherwise
*/
@ -191,9 +207,14 @@ struct spa_interface {
({ \
const type *_f = (const type *) (callbacks)->funcs; \
if (SPA_LIKELY(SPA_CALLBACK_CHECK(_f,method,vers))) \
res = _f->method((callbacks)->data, ## __VA_ARGS__); \
res = (_f->method)((callbacks)->data, ## __VA_ARGS__); \
res; \
})
#define spa_callbacks_call_fast_res(callbacks,type,res,method,vers,...) \
({ \
const type *_f = (const type *) (callbacks)->funcs; \
res = (_f->method)((callbacks)->data, ## __VA_ARGS__); \
})
/**
* True if the \a iface's callbacks are of version \a vers, false otherwise
@ -216,6 +237,9 @@ struct spa_interface {
#define spa_interface_call(iface,method_type,method,vers,...) \
spa_callbacks_call(&(iface)->cb,method_type,method,vers,##__VA_ARGS__)
#define spa_interface_call_fast(iface,method_type,method,vers,...) \
spa_callbacks_call_fast(&(iface)->cb,method_type,method,vers,##__VA_ARGS__)
/**
* Invoke method named \a method in the callbacks on the given interface object.
* The \a method_type defines the type of the method struct, not the interface
@ -226,6 +250,76 @@ struct spa_interface {
#define spa_interface_call_res(iface,method_type,res,method,vers,...) \
spa_callbacks_call_res(&(iface)->cb,method_type,res,method,vers,##__VA_ARGS__)
#define spa_interface_call_fast_res(iface,method_type,res,method,vers,...) \
spa_callbacks_call_fast_res(&(iface)->cb,method_type,res,method,vers,##__VA_ARGS__)
#define spa_api_func_v(o,method,version,...) \
({ \
if (SPA_LIKELY(SPA_CALLBACK_CHECK(o,method,version))) \
((o)->method)(o, ##__VA_ARGS__); \
})
#define spa_api_func_r(rtype,def,o,method,version,...) \
({ \
rtype _res = def; \
if (SPA_LIKELY(SPA_CALLBACK_CHECK(o,method,version))) \
_res = ((o)->method)(o, ##__VA_ARGS__); \
_res; \
})
#define spa_api_func_fast(o,method,...) \
({ \
((o)->method)(o, ##__VA_ARGS__); \
})
#define spa_api_method_v(type,o,method,version,...) \
({ \
struct spa_interface *_i = o; \
spa_interface_call(_i, struct type ##_methods, \
method, version, ##__VA_ARGS__); \
})
#define spa_api_method_r(rtype,def,type,o,method,version,...) \
({ \
rtype _res = def; \
struct spa_interface *_i = o; \
spa_interface_call_res(_i, struct type ##_methods, \
_res, method, version, ##__VA_ARGS__); \
_res; \
})
#define spa_api_method_null_v(type,co,o,method,version,...) \
({ \
struct type *_co = co; \
if (SPA_LIKELY(_co != NULL)) { \
struct spa_interface *_i = o; \
spa_interface_call(_i, struct type ##_methods, \
method, version, ##__VA_ARGS__); \
} \
})
#define spa_api_method_null_r(rtype,def,type,co,o,method,version,...) \
({ \
rtype _res = def; \
struct type *_co = co; \
if (SPA_LIKELY(_co != NULL)) { \
struct spa_interface *_i = o; \
spa_interface_call_res(_i, struct type ##_methods, \
_res, method, version, ##__VA_ARGS__); \
} \
_res; \
})
#define spa_api_method_fast_v(type,o,method,version,...) \
({ \
struct spa_interface *_i = o; \
spa_interface_call_fast(_i, struct type ##_methods, \
method, version, ##__VA_ARGS__); \
})
#define spa_api_method_fast_r(rtype,def,type,o,method,version,...) \
({ \
rtype _res = def; \
struct spa_interface *_i = o; \
spa_interface_call_fast_res(_i, struct type ##_methods, \
_res, method, version, ##__VA_ARGS__); \
_res; \
})
/**
* \}
*/
@ -329,18 +423,18 @@ struct spa_hook {
};
/** Initialize a hook list to the empty list*/
static inline void spa_hook_list_init(struct spa_hook_list *list)
SPA_API_HOOK void spa_hook_list_init(struct spa_hook_list *list)
{
spa_list_init(&list->list);
}
static inline bool spa_hook_list_is_empty(struct spa_hook_list *list)
SPA_API_HOOK bool spa_hook_list_is_empty(struct spa_hook_list *list)
{
return spa_list_is_empty(&list->list);
}
/** Append a hook. */
static inline void spa_hook_list_append(struct spa_hook_list *list,
SPA_API_HOOK void spa_hook_list_append(struct spa_hook_list *list,
struct spa_hook *hook,
const void *funcs, void *data)
{
@ -350,7 +444,7 @@ static inline void spa_hook_list_append(struct spa_hook_list *list,
}
/** Prepend a hook */
static inline void spa_hook_list_prepend(struct spa_hook_list *list,
SPA_API_HOOK void spa_hook_list_prepend(struct spa_hook_list *list,
struct spa_hook *hook,
const void *funcs, void *data)
{
@ -360,7 +454,7 @@ static inline void spa_hook_list_prepend(struct spa_hook_list *list,
}
/** Remove a hook */
static inline void spa_hook_remove(struct spa_hook *hook)
SPA_API_HOOK void spa_hook_remove(struct spa_hook *hook)
{
if (spa_list_is_initialized(&hook->link))
spa_list_remove(&hook->link);
@ -369,14 +463,14 @@ static inline void spa_hook_remove(struct spa_hook *hook)
}
/** Remove all hooks from the list */
static inline void spa_hook_list_clean(struct spa_hook_list *list)
SPA_API_HOOK void spa_hook_list_clean(struct spa_hook_list *list)
{
struct spa_hook *h;
spa_list_consume(h, &list->list, link)
spa_hook_remove(h);
}
static inline void
SPA_API_HOOK void
spa_hook_list_isolate(struct spa_hook_list *list,
struct spa_hook_list *save,
struct spa_hook *hook,
@ -390,7 +484,7 @@ spa_hook_list_isolate(struct spa_hook_list *list,
spa_hook_list_append(list, hook, funcs, data);
}
static inline void
SPA_API_HOOK void
spa_hook_list_join(struct spa_hook_list *list,
struct spa_hook_list *save)
{

View File

@ -9,6 +9,16 @@
extern "C" {
#endif
#include <spa/utils/defs.h>
#ifndef SPA_API_LIST
#ifdef SPA_API_IMPL
#define SPA_API_LIST SPA_API_IMPL
#else
#define SPA_API_LIST static inline
#endif
#endif
/**
* \defgroup spa_list List
* Doubly linked list data structure
@ -26,19 +36,19 @@ struct spa_list {
#define SPA_LIST_INIT(list) ((struct spa_list){ (list), (list) })
static inline void spa_list_init(struct spa_list *list)
SPA_API_LIST void spa_list_init(struct spa_list *list)
{
*list = SPA_LIST_INIT(list);
}
static inline int spa_list_is_initialized(struct spa_list *list)
SPA_API_LIST int spa_list_is_initialized(struct spa_list *list)
{
return !!list->prev;
}
#define spa_list_is_empty(l) ((l)->next == (l))
static inline void spa_list_insert(struct spa_list *list, struct spa_list *elem)
SPA_API_LIST void spa_list_insert(struct spa_list *list, struct spa_list *elem)
{
elem->prev = list;
elem->next = list->next;
@ -46,7 +56,7 @@ static inline void spa_list_insert(struct spa_list *list, struct spa_list *elem)
elem->next->prev = elem;
}
static inline void spa_list_insert_list(struct spa_list *list, struct spa_list *other)
SPA_API_LIST void spa_list_insert_list(struct spa_list *list, struct spa_list *other)
{
if (spa_list_is_empty(other))
return;
@ -56,7 +66,7 @@ static inline void spa_list_insert_list(struct spa_list *list, struct spa_list *
list->next = other->next;
}
static inline void spa_list_remove(struct spa_list *elem)
SPA_API_LIST void spa_list_remove(struct spa_list *elem)
{
elem->prev->next = elem->next;
elem->next->prev = elem->prev;

View File

@ -17,6 +17,14 @@ extern "C" {
#include <spa/utils/defs.h>
#ifndef SPA_API_STRING
#ifdef SPA_API_IMPL
#define SPA_API_STRING SPA_API_IMPL
#else
#define SPA_API_STRING static inline
#endif
#endif
/**
* \defgroup spa_string String handling
* String handling utilities
@ -33,7 +41,7 @@ extern "C" {
* If both \a a and \a b are NULL, the two are considered equal.
*
*/
static inline bool spa_streq(const char *s1, const char *s2)
SPA_API_STRING bool spa_streq(const char *s1, const char *s2)
{
return SPA_LIKELY(s1 && s2) ? strcmp(s1, s2) == 0 : s1 == s2;
}
@ -43,7 +51,7 @@ static inline bool spa_streq(const char *s1, const char *s2)
*
* If both \a a and \a b are NULL, the two are considered equal.
*/
static inline bool spa_strneq(const char *s1, const char *s2, size_t len)
SPA_API_STRING bool spa_strneq(const char *s1, const char *s2, size_t len)
{
return SPA_LIKELY(s1 && s2) ? strncmp(s1, s2, len) == 0 : s1 == s2;
}
@ -54,7 +62,7 @@ static inline bool spa_strneq(const char *s1, const char *s2, size_t len)
* A \a s is NULL, it never starts with the given \a prefix. A \a prefix of
* NULL is a bug in the caller.
*/
static inline bool spa_strstartswith(const char *s, const char *prefix)
SPA_API_STRING bool spa_strstartswith(const char *s, const char *prefix)
{
if (SPA_UNLIKELY(s == NULL))
return false;
@ -70,7 +78,7 @@ static inline bool spa_strstartswith(const char *s, const char *prefix)
* A \a s is NULL, it never ends with the given \a suffix. A \a suffix of
* NULL is a bug in the caller.
*/
static inline bool spa_strendswith(const char *s, const char *suffix)
SPA_API_STRING bool spa_strendswith(const char *s, const char *suffix)
{
size_t l1, l2;
@ -92,7 +100,7 @@ static inline bool spa_strendswith(const char *s, const char *suffix)
*
* \return true on success, false otherwise
*/
static inline bool spa_atoi32(const char *str, int32_t *val, int base)
SPA_API_STRING bool spa_atoi32(const char *str, int32_t *val, int base)
{
char *endptr;
long v;
@ -120,7 +128,7 @@ static inline bool spa_atoi32(const char *str, int32_t *val, int base)
*
* \return true on success, false otherwise
*/
static inline bool spa_atou32(const char *str, uint32_t *val, int base)
SPA_API_STRING bool spa_atou32(const char *str, uint32_t *val, int base)
{
char *endptr;
unsigned long long v;
@ -148,7 +156,7 @@ static inline bool spa_atou32(const char *str, uint32_t *val, int base)
*
* \return true on success, false otherwise
*/
static inline bool spa_atoi64(const char *str, int64_t *val, int base)
SPA_API_STRING bool spa_atoi64(const char *str, int64_t *val, int base)
{
char *endptr;
long long v;
@ -173,7 +181,7 @@ static inline bool spa_atoi64(const char *str, int64_t *val, int base)
*
* \return true on success, false otherwise
*/
static inline bool spa_atou64(const char *str, uint64_t *val, int base)
SPA_API_STRING bool spa_atou64(const char *str, uint64_t *val, int base)
{
char *endptr;
unsigned long long v;
@ -196,7 +204,7 @@ static inline bool spa_atou64(const char *str, uint64_t *val, int base)
*
* \return true on success, false otherwise
*/
static inline bool spa_atob(const char *str)
SPA_API_STRING bool spa_atob(const char *str)
{
return spa_streq(str, "true") || spa_streq(str, "1");
}
@ -210,7 +218,7 @@ static inline bool spa_atob(const char *str)
* number on error.
*/
SPA_PRINTF_FUNC(3, 0)
static inline int spa_vscnprintf(char *buffer, size_t size, const char *format, va_list args)
SPA_API_STRING int spa_vscnprintf(char *buffer, size_t size, const char *format, va_list args)
{
int r;
@ -233,7 +241,7 @@ static inline int spa_vscnprintf(char *buffer, size_t size, const char *format,
* number on error.
*/
SPA_PRINTF_FUNC(3, 4)
static inline int spa_scnprintf(char *buffer, size_t size, const char *format, ...)
SPA_API_STRING int spa_scnprintf(char *buffer, size_t size, const char *format, ...)
{
int r;
va_list args;
@ -253,7 +261,7 @@ static inline int spa_scnprintf(char *buffer, size_t size, const char *format, .
*
* \return the result float.
*/
static inline float spa_strtof(const char *str, char **endptr)
SPA_API_STRING float spa_strtof(const char *str, char **endptr)
{
#ifndef __LOCALE_C_ONLY
static locale_t locale = NULL;
@ -279,7 +287,7 @@ static inline float spa_strtof(const char *str, char **endptr)
*
* \return true on success, false otherwise
*/
static inline bool spa_atof(const char *str, float *val)
SPA_API_STRING bool spa_atof(const char *str, float *val)
{
char *endptr;
float v;
@ -303,7 +311,7 @@ static inline bool spa_atof(const char *str, float *val)
*
* \return the result float.
*/
static inline double spa_strtod(const char *str, char **endptr)
SPA_API_STRING double spa_strtod(const char *str, char **endptr)
{
#ifndef __LOCALE_C_ONLY
static locale_t locale = NULL;
@ -329,7 +337,7 @@ static inline double spa_strtod(const char *str, char **endptr)
*
* \return true on success, false otherwise
*/
static inline bool spa_atod(const char *str, double *val)
SPA_API_STRING bool spa_atod(const char *str, double *val)
{
char *endptr;
double v;
@ -346,7 +354,7 @@ static inline bool spa_atod(const char *str, double *val)
return true;
}
static inline char *spa_dtoa(char *str, size_t size, double val)
SPA_API_STRING char *spa_dtoa(char *str, size_t size, double val)
{
int i, l;
l = spa_scnprintf(str, size, "%f", val);
@ -362,15 +370,17 @@ struct spa_strbuf {
size_t pos;
};
static inline void spa_strbuf_init(struct spa_strbuf *buf, char *buffer, size_t maxsize)
SPA_API_STRING void spa_strbuf_init(struct spa_strbuf *buf, char *buffer, size_t maxsize)
{
buf->buffer = buffer;
buf->maxsize = maxsize;
buf->pos = 0;
if (maxsize > 0)
buf->buffer[0] = '\0';
}
SPA_PRINTF_FUNC(2, 3)
static inline int spa_strbuf_append(struct spa_strbuf *buf, const char *fmt, ...)
SPA_API_STRING int spa_strbuf_append(struct spa_strbuf *buf, const char *fmt, ...)
{
size_t remain = buf->maxsize - buf->pos;
ssize_t written;

View File

@ -20,10 +20,6 @@ extern "C" {
#define SPA_TYPE_ROOT spa_types
#endif
static inline bool spa_type_is_a(const char *type, const char *parent)
{
return type != NULL && parent != NULL && strncmp(type, parent, strlen(parent)) == 0;
}
#include <spa/utils/type.h>
#include <spa/utils/enum-types.h>
@ -83,6 +79,7 @@ static const struct spa_type_info spa_types[] = {
{ SPA_TYPE_OBJECT_Profiler, SPA_TYPE_Object, SPA_TYPE_INFO_Profiler, spa_type_profiler },
{ SPA_TYPE_OBJECT_ParamLatency, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_Latency, spa_type_param_latency },
{ SPA_TYPE_OBJECT_ParamProcessLatency, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_ProcessLatency, spa_type_param_process_latency },
{ SPA_TYPE_OBJECT_ParamTag, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_Tag, spa_type_param_tag },
{ 0, 0, NULL, NULL }
};

View File

@ -10,6 +10,15 @@ extern "C" {
#endif
#include <spa/utils/defs.h>
#include <spa/utils/string.h>
#ifndef SPA_API_TYPE
#ifdef SPA_API_IMPL
#define SPA_API_TYPE SPA_API_IMPL
#else
#define SPA_API_TYPE static inline
#endif
#endif
/** \defgroup spa_types Types
* Data type information enumerations
@ -78,6 +87,7 @@ enum {
SPA_TYPE_OBJECT_Profiler,
SPA_TYPE_OBJECT_ParamLatency,
SPA_TYPE_OBJECT_ParamProcessLatency,
SPA_TYPE_OBJECT_ParamTag,
_SPA_TYPE_OBJECT_LAST, /**< not part of ABI */
/* vendor extensions */
@ -122,6 +132,47 @@ struct spa_type_info {
const struct spa_type_info *values;
};
SPA_API_TYPE bool spa_type_is_a(const char *type, const char *parent)
{
return type != NULL && parent != NULL && strncmp(type, parent, strlen(parent)) == 0;
}
SPA_API_TYPE const char *spa_type_short_name(const char *name)
{
const char *h;
if ((h = strrchr(name, ':')) != NULL)
name = h + 1;
return name;
}
SPA_API_TYPE uint32_t spa_type_from_short_name(const char *name,
const struct spa_type_info *info, uint32_t unknown)
{
int i;
for (i = 0; info[i].name; i++) {
if (spa_streq(name, spa_type_short_name(info[i].name)))
return info[i].type;
}
return unknown;
}
SPA_API_TYPE const char * spa_type_to_name(uint32_t type,
const struct spa_type_info *info, const char *unknown)
{
int i;
for (i = 0; info[i].name; i++) {
if (info[i].type == type)
return info[i].name;
}
return unknown;
}
SPA_API_TYPE const char * spa_type_to_short_name(uint32_t type,
const struct spa_type_info *info, const char *unknown)
{
const char *n = spa_type_to_name(type, info, unknown);
return n ? spa_type_short_name(n) : NULL;
}
/**
* \}
*/