Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mumble-voip/mumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavide Beatrici <git@davidebeatrici.dev>2021-05-13 22:09:35 +0300
committerDavide Beatrici <git@davidebeatrici.dev>2021-05-13 22:09:35 +0300
commit0a31cd1c63ff42d61470ac006a60f96051c279ec (patch)
tree8f8d532e1e18064787e8c075d162dc3c48a3c39d /3rdparty
parent9e8a197f5cfc6689d1f4e5f5599087f9802b4ec4 (diff)
FEAT(client): Implement native support for PipeWire
Tested with PipeWire 0.3.26. The implementation is quite basic and simple, yet it surpasses the JACK one in terms of features. For example, support for the most common surround mappings is provided. As opposed to JACK, an option to disable the auto endpoint connection is not provided. However, it's something that can be easily implemented if needed. Support for echo cancellation will definitely be added in future.
Diffstat (limited to '3rdparty')
-rw-r--r--3rdparty/pipewire/pipewire/context.h194
-rw-r--r--3rdparty/pipewire/pipewire/core.h584
-rw-r--r--3rdparty/pipewire/pipewire/keys.h306
-rw-r--r--3rdparty/pipewire/pipewire/loop.h80
-rw-r--r--3rdparty/pipewire/pipewire/port.h169
-rw-r--r--3rdparty/pipewire/pipewire/properties.h125
-rw-r--r--3rdparty/pipewire/pipewire/protocol.h152
-rw-r--r--3rdparty/pipewire/pipewire/proxy.h207
-rw-r--r--3rdparty/pipewire/pipewire/stream.h358
-rw-r--r--3rdparty/pipewire/pipewire/utils.h73
-rw-r--r--3rdparty/pipewire/spa/buffer/buffer.h119
-rw-r--r--3rdparty/pipewire/spa/buffer/meta.h158
-rw-r--r--3rdparty/pipewire/spa/param/audio/format-utils.h113
-rw-r--r--3rdparty/pipewire/spa/param/audio/format.h48
-rw-r--r--3rdparty/pipewire/spa/param/audio/raw.h242
-rw-r--r--3rdparty/pipewire/spa/param/format-utils.h49
-rw-r--r--3rdparty/pipewire/spa/param/format.h147
-rw-r--r--3rdparty/pipewire/spa/param/param.h171
-rw-r--r--3rdparty/pipewire/spa/pod/builder.h683
-rw-r--r--3rdparty/pipewire/spa/pod/iter.h447
-rw-r--r--3rdparty/pipewire/spa/pod/parser.h573
-rw-r--r--3rdparty/pipewire/spa/pod/pod.h236
-rw-r--r--3rdparty/pipewire/spa/pod/vararg.h104
-rw-r--r--3rdparty/pipewire/spa/support/loop.h312
-rw-r--r--3rdparty/pipewire/spa/support/system.h152
-rw-r--r--3rdparty/pipewire/spa/utils/defs.h300
-rw-r--r--3rdparty/pipewire/spa/utils/dict.h104
-rw-r--r--3rdparty/pipewire/spa/utils/hook.h208
-rw-r--r--3rdparty/pipewire/spa/utils/list.h147
-rw-r--r--3rdparty/pipewire/spa/utils/type.h138
30 files changed, 6699 insertions, 0 deletions
diff --git a/3rdparty/pipewire/pipewire/context.h b/3rdparty/pipewire/pipewire/context.h
new file mode 100644
index 000000000..88c1ac1eb
--- /dev/null
+++ b/3rdparty/pipewire/pipewire/context.h
@@ -0,0 +1,194 @@
+/* PipeWire
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef PIPEWIRE_CONTEXT_H
+#define PIPEWIRE_CONTEXT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/defs.h>
+#include <spa/utils/hook.h>
+
+/** \class pw_context
+ *
+ * \brief the PipeWire context
+ *
+ * The context object manages all locally available resources. It
+ * is used by both clients and servers.
+ *
+ * The context is used to:
+ *
+ * - Load modules and extend the functionality. This includes
+ * extending the protocol with new object types or creating
+ * any of the available objects.
+ *
+ * - Create implementations of various objects like nodes,
+ * devices, factories, modules, etc.. This will usually also
+ * create pw_global objects that can then be shared with
+ * clients.
+ *
+ * - Connect to another PipeWire instance (the main daemon, for
+ * example) and interact with it (See \subpage page_core_api).
+ *
+ * - Export a local implementation of an object to another
+ * instance.
+ */
+struct pw_context;
+
+struct pw_global;
+struct pw_impl_client;
+
+#include <pipewire/core.h>
+#include <pipewire/loop.h>
+#include <pipewire/properties.h>
+
+/** \page page_context_api Core API
+ *
+ * \section page_context_overview Overview
+ *
+ * \subpage page_context
+ *
+ * \subpage page_global
+ *
+ * \subpage page_client
+ *
+ * \subpage page_resource
+ *
+ * \subpage page_node
+ *
+ * \subpage page_port
+ *
+ * \subpage page_link
+ */
+
+/** \page page_context Context
+ *
+ * \section page_context_overview Overview
+ *
+ * The context object is an object that manages the state and
+ * resources of a PipeWire instance.
+ */
+
+/** context events emitted by the context object added with \ref pw_context_add_listener */
+struct pw_context_events {
+#define PW_VERSION_CONTEXT_EVENTS 0
+ uint32_t version;
+
+ /** The context is being destroyed */
+ void (*destroy) (void *data);
+ /** The context is being freed */
+ void (*free) (void *data);
+ /** a new client object is added */
+ void (*check_access) (void *data, struct pw_impl_client *client);
+ /** a new global object was added */
+ void (*global_added) (void *data, struct pw_global *global);
+ /** a global object was removed */
+ void (*global_removed) (void *data, struct pw_global *global);
+};
+
+/** 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 */);
+
+/** destroy a context object, all resources except the main_loop will be destroyed */
+void pw_context_destroy(struct pw_context *context);
+
+/** Get the context user data */
+void *pw_context_get_user_data(struct pw_context *context);
+
+/** Add a new event listener to a context */
+void pw_context_add_listener(struct pw_context *context,
+ struct spa_hook *listener,
+ const struct pw_context_events *events,
+ void *data);
+
+/** Get the context properties */
+const struct pw_properties *pw_context_get_properties(struct pw_context *context);
+
+/** Update the context properties */
+int pw_context_update_properties(struct pw_context *context, const struct spa_dict *dict);
+
+/** Get a config section for this context. Since 0.3.22 */
+const char *pw_context_get_conf_section(struct pw_context *context, const char *section);
+
+/** 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 */
+struct pw_loop *pw_context_get_main_loop(struct pw_context *context);
+
+/** Get the work queue from the context: Since 0.3.26 */
+struct pw_work_queue *pw_context_get_work_queue(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
+ * globals are iterated. */
+int pw_context_for_each_global(struct pw_context *context, /**< the context */
+ int (*callback) (void *data, struct pw_global *global),
+ void *data);
+
+/** Find a context global by id */
+struct pw_global *pw_context_find_global(struct pw_context *context, /**< the context */
+ uint32_t id /**< the global id */);
+
+/** add a spa library for the given factory_name regex */
+int pw_context_add_spa_lib(struct pw_context *context, const char *factory_regex, const char *lib);
+
+/** find the library name for a spa factory */
+const char * pw_context_find_spa_lib(struct pw_context *context, const char *factory_name);
+
+struct spa_handle *pw_context_load_spa_handle(struct pw_context *context,
+ const char *factory_name,
+ const struct spa_dict *info);
+
+
+/** data for registering export functions */
+struct pw_export_type {
+ struct spa_list link;
+ const char *type;
+ struct pw_proxy * (*func) (struct pw_core *core,
+ const char *type, const struct spa_dict *props, void *object,
+ size_t user_data_size);
+};
+
+/** register a type that can be exported on a context_proxy. This is usually used by
+ * extension modules */
+int pw_context_register_export_type(struct pw_context *context, struct pw_export_type *type);
+/** 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 */
+int pw_context_set_object(struct pw_context *context, const char *type, void *value);
+/** get an object from the context */
+void *pw_context_get_object(struct pw_context *context, const char *type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_CONTEXT_H */
diff --git a/3rdparty/pipewire/pipewire/core.h b/3rdparty/pipewire/pipewire/core.h
new file mode 100644
index 000000000..1fbaa02bf
--- /dev/null
+++ b/3rdparty/pipewire/pipewire/core.h
@@ -0,0 +1,584 @@
+/* PipeWire
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef PIPEWIRE_CORE_H
+#define PIPEWIRE_CORE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+#include <errno.h>
+
+#include <spa/utils/hook.h>
+
+#define PW_TYPE_INTERFACE_Core PW_TYPE_INFO_INTERFACE_BASE "Core"
+#define PW_TYPE_INTERFACE_Registry PW_TYPE_INFO_INTERFACE_BASE "Registry"
+
+#define PW_VERSION_CORE 3
+struct pw_core;
+#define PW_VERSION_REGISTRY 3
+struct pw_registry;
+
+/* the default remote name to connect to */
+#define PW_DEFAULT_REMOTE "pipewire-0"
+
+/* default ID for the core object after connect */
+#define PW_ID_CORE 0
+
+/* invalid ID that matches any object when used for permissions */
+#define PW_ID_ANY (uint32_t)(0xffffffff)
+
+/** The core information. Extra information can be added in later versions \memberof pw_introspect */
+struct pw_core_info {
+ uint32_t id; /**< id of the global */
+ uint32_t cookie; /**< a random cookie for identifying this instance of PipeWire */
+ const char *user_name; /**< name of the user that started the core */
+ const char *host_name; /**< name of the machine the core is running on */
+ const char *version; /**< version of the core */
+ const char *name; /**< name of the core */
+#define PW_CORE_CHANGE_MASK_PROPS (1 << 0)
+#define PW_CORE_CHANGE_MASK_ALL ((1 << 1)-1)
+ uint64_t change_mask; /**< bitfield of changed fields since last call */
+ struct spa_dict *props; /**< extra properties */
+};
+
+#include <pipewire/context.h>
+#include <pipewire/properties.h>
+#include <pipewire/proxy.h>
+
+/** Update and existing \ref pw_core_info with \a update \memberof pw_introspect */
+struct pw_core_info *
+pw_core_info_update(struct pw_core_info *info,
+ const struct pw_core_info *update);
+
+/** Free a \ref pw_core_info \memberof pw_introspect */
+void pw_core_info_free(struct pw_core_info *info);
+
+/**
+ * \page page_iface_pw_core pw_core
+ * \section page_iface_pw_core_desc Description
+ *
+ * The core global object. This is a special singleton object. It
+ * is used for internal PipeWire protocol features.
+ * \section page_iface_pw_core API
+ */
+
+/** Core */
+
+#define PW_CORE_EVENT_INFO 0
+#define PW_CORE_EVENT_DONE 1
+#define PW_CORE_EVENT_PING 2
+#define PW_CORE_EVENT_ERROR 3
+#define PW_CORE_EVENT_REMOVE_ID 4
+#define PW_CORE_EVENT_BOUND_ID 5
+#define PW_CORE_EVENT_ADD_MEM 6
+#define PW_CORE_EVENT_REMOVE_MEM 7
+#define PW_CORE_EVENT_NUM 8
+
+/** \struct pw_core_events
+ * \brief Core events
+ * \ingroup pw_core_interface The pw_core interface
+ */
+struct pw_core_events {
+#define PW_VERSION_CORE_EVENTS 0
+ uint32_t version;
+
+ /**
+ * Notify new core info
+ *
+ * This event is emitted when first bound to the core or when the
+ * hello method is called.
+ *
+ * \param info new core info
+ */
+ void (*info) (void *object, const struct pw_core_info *info);
+ /**
+ * Emit a done event
+ *
+ * The done event is emitted as a result of a sync method with the
+ * same seq number.
+ *
+ * \param seq the seq number passed to the sync method call
+ */
+ void (*done) (void *object, uint32_t id, int seq);
+
+ /** Emit a ping event
+ *
+ * The client should reply with a pong reply with the same seq
+ * number.
+ */
+ void (*ping) (void *object, uint32_t id, int seq);
+
+ /**
+ * Fatal error event
+ *
+ * The error event is sent out when a fatal (non-recoverable)
+ * error has occurred. The id argument is the proxy object where
+ * the error occurred, most often in response to a request to that
+ * object. The message is a brief description of the error,
+ * for (debugging) convenience.
+ *
+ * This event is usually also emitted on the proxy object with
+ * \a id.
+ *
+ * \param id object where the error occurred
+ * \param seq the sequence number that generated the error
+ * \param res error code
+ * \param message error description
+ */
+ void (*error) (void *object, uint32_t id, int seq, int res, const char *message);
+ /**
+ * Remove an object ID
+ *
+ * This event is used internally by the object ID management
+ * logic. When a client deletes an object, the server will send
+ * this event to acknowledge that it has seen the delete request.
+ * When the client receives this event, it will know that it can
+ * safely reuse the object ID.
+ *
+ * \param id deleted object ID
+ */
+ void (*remove_id) (void *object, 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.
+ *
+ * \param id bound object ID
+ * \param global_id the global id bound to
+ */
+ void (*bound_id) (void *object, uint32_t id, uint32_t global_id);
+
+ /**
+ * Add memory for a client
+ *
+ * Memory is given to a client as \a fd of a certain
+ * memory \a type.
+ *
+ * Further references to this fd will be made with the per memory
+ * unique identifier \a id.
+ *
+ * \param id the unique id of the memory
+ * \param type the memory type, one of enum spa_data_type
+ * \param fd the file descriptor
+ * \param flags extra flags
+ */
+ void (*add_mem) (void *object, uint32_t id, uint32_t type, int fd, uint32_t flags);
+
+ /**
+ * Remove memory for a client
+ *
+ * \param id the memory id to remove
+ */
+ void (*remove_mem) (void *object, uint32_t id);
+};
+
+#define PW_CORE_METHOD_ADD_LISTENER 0
+#define PW_CORE_METHOD_HELLO 1
+#define PW_CORE_METHOD_SYNC 2
+#define PW_CORE_METHOD_PONG 3
+#define PW_CORE_METHOD_ERROR 4
+#define PW_CORE_METHOD_GET_REGISTRY 5
+#define PW_CORE_METHOD_CREATE_OBJECT 6
+#define PW_CORE_METHOD_DESTROY 7
+#define PW_CORE_METHOD_NUM 8
+
+/**
+ * \struct pw_core_methods
+ * \brief Core methods
+ *
+ * The core global object. This is a singleton object used for
+ * creating new objects in the remote PipeWire instance. It is
+ * also used for internal features.
+ */
+struct pw_core_methods {
+#define PW_VERSION_CORE_METHODS 0
+ uint32_t version;
+
+ int (*add_listener) (void *object,
+ struct spa_hook *listener,
+ const struct pw_core_events *events,
+ void *data);
+ /**
+ * 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).
+ */
+ int (*hello) (void *object, uint32_t version);
+ /**
+ * Do server roundtrip
+ *
+ * Ask the server to emit the 'done' event with \a seq.
+ *
+ * Since methods are handled in-order and events are delivered
+ * in-order, this can be used as a barrier to ensure all previous
+ * methods and the resulting events have been handled.
+ *
+ * \param seq the seq number passed to the done event
+ */
+ int (*sync) (void *object, uint32_t id, int seq);
+ /**
+ * Reply to a server ping event.
+ *
+ * Reply to the server ping event with the same seq.
+ *
+ * \param seq the seq number received in the ping event
+ */
+ int (*pong) (void *object, uint32_t id, int seq);
+ /**
+ * Fatal error event
+ *
+ * The error method is sent out when a fatal (non-recoverable)
+ * error has occurred. The id argument is the proxy object where
+ * the error occurred, most often in response to an event on that
+ * object. The message is a brief description of the error,
+ * for (debugging) convenience.
+ *
+ * This method is usually also emitted on the resource object with
+ * \a id.
+ *
+ * \param id object where the error occurred
+ * \param res error code
+ * \param message error description
+ */
+ int (*error) (void *object, uint32_t id, int seq, int res, const char *message);
+ /**
+ * Get the registry object
+ *
+ * Create a registry object that allows the client to list and bind
+ * the global objects available from the PipeWire server
+ * \param version the client version
+ * \param user_data_size extra size
+ */
+ struct pw_registry * (*get_registry) (void *object, uint32_t version,
+ size_t user_data_size);
+
+ /**
+ * Create a new object on the PipeWire server from a factory.
+ *
+ * \param factory_name the factory name to use
+ * \param type the interface to bind to
+ * \param version the version of the interface
+ * \param props extra properties
+ * \param user_data_size extra size
+ */
+ void * (*create_object) (void *object,
+ const char *factory_name,
+ const char *type,
+ uint32_t version,
+ const struct spa_dict *props,
+ size_t user_data_size);
+ /**
+ * Destroy an resource
+ *
+ * Destroy the server resource for the given proxy.
+ *
+ * \param obj the proxy to destroy
+ */
+ 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
+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)
+{
+ char buffer[1024];
+ vsnprintf(buffer, sizeof(buffer), message, args);
+ buffer[1023] = '\0';
+ return pw_core_error(core, id, seq, res, buffer);
+}
+
+static inline
+SPA_PRINTF_FUNC(5, 6) int
+pw_core_errorf(struct pw_core *core, uint32_t id, int seq,
+ int res, const char *message, ...)
+{
+ va_list args;
+ int r;
+ va_start(args, message);
+ r = pw_core_errorv(core, id, seq, res, message, args);
+ va_end(args);
+ return r;
+}
+
+static inline 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;
+}
+
+static inline void *
+pw_core_create_object(struct pw_core *core,
+ const char *factory_name,
+ const char *type,
+ uint32_t version,
+ 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;
+}
+
+#define pw_core_destroy(c,...) pw_core_method(c,destroy,0,__VA_ARGS__)
+
+/** \page page_registry Registry
+ *
+ * \section page_registry_overview Overview
+ *
+ * The registry object is a singleton object that keeps track of
+ * global objects on the PipeWire instance. See also \ref page_global.
+ *
+ * Global objects typically represent an actual object in PipeWire
+ * (for example, a module or node) or they are singleton
+ * objects such as the core.
+ *
+ * When a client creates a registry object, the registry object
+ * will emit a global event for each global currently in the
+ * registry. Globals come and go as a result of device hotplugs or
+ * reconfiguration or other events, and the registry will send out
+ * global and global_remove events to keep the client up to date
+ * with the changes. To mark the end of the initial burst of
+ * events, the client can use the pw_core.sync methosd immediately
+ * after calling pw_core.get_registry.
+ *
+ * A client can bind to a global object by using the bind
+ * request. This creates a client-side proxy that lets the object
+ * emit events to the client and lets the client invoke methods on
+ * the object. See \ref page_proxy
+ *
+ * Clients can also change the permissions of the global objects that
+ * it can see. This is interesting when you want to configure a
+ * pipewire session before handing it to another application. You
+ * can, for example, hide certain existing or new objects or limit
+ * the access permissions on an object.
+ */
+
+#define PW_REGISTRY_EVENT_GLOBAL 0
+#define PW_REGISTRY_EVENT_GLOBAL_REMOVE 1
+#define PW_REGISTRY_EVENT_NUM 2
+
+/** Registry events */
+struct pw_registry_events {
+#define PW_VERSION_REGISTRY_EVENTS 0
+ uint32_t version;
+ /**
+ * Notify of a new global object
+ *
+ * The registry emits this event when a new global object is
+ * available.
+ *
+ * \param id the global object id
+ * \param permissions the permissions of the object
+ * \param type the type of the interface
+ * \param version the version of the interface
+ * \param props extra properties of the global
+ */
+ void (*global) (void *object, uint32_t id,
+ uint32_t permissions, const char *type, uint32_t version,
+ const struct spa_dict *props);
+ /**
+ * Notify of a global object removal
+ *
+ * Emitted when a global object was removed from the registry.
+ * If the client has any bindings to the global, it should destroy
+ * those.
+ *
+ * \param id the id of the global that was removed
+ */
+ void (*global_remove) (void *object, uint32_t id);
+};
+
+#define PW_REGISTRY_METHOD_ADD_LISTENER 0
+#define PW_REGISTRY_METHOD_BIND 1
+#define PW_REGISTRY_METHOD_DESTROY 2
+#define PW_REGISTRY_METHOD_NUM 3
+
+/** Registry methods */
+struct pw_registry_methods {
+#define PW_VERSION_REGISTRY_METHODS 0
+ uint32_t version;
+
+ int (*add_listener) (void *object,
+ struct spa_hook *listener,
+ const struct pw_registry_events *events,
+ void *data);
+ /**
+ * Bind to a global object
+ *
+ * Bind to the global object with \a id and use the client proxy
+ * with new_id as the proxy. After this call, methods can be
+ * send to the remote global object and events can be received
+ *
+ * \param id the global id to bind to
+ * \param type the interface type to bind to
+ * \param version the interface version to use
+ * \returns the new object
+ */
+ void * (*bind) (void *object, uint32_t id, const char *type, uint32_t version,
+ size_t use_data_size);
+
+ /**
+ * Attempt to destroy a global object
+ *
+ * Try to destroy the global object.
+ *
+ * \param id the global id to destroy
+ */
+ 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 *
+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;
+}
+
+#define pw_registry_destroy(p,...) pw_registry_method(p,destroy,0,__VA_ARGS__)
+
+
+/** Connect to a PipeWire instance \memberof pw_core
+ * \return a pw_core on success or NULL with errno set on error. The core
+ * will have an id of PW_ID_CORE (0) */
+struct pw_core *
+pw_context_connect(struct pw_context *context, /**< a \ref pw_context */
+ struct pw_properties *properties, /**< optional properties, ownership of
+ * the properties is taken.*/
+ size_t user_data_size /**< extra user data size */);
+
+/** Connect to a PipeWire instance on the given socket \memberof pw_core
+ * \param fd the connected socket to use, the socket will be closed
+ * automatically on disconnect or error.
+ * \return a pw_core on success or NULL with errno set on error */
+struct pw_core *
+pw_context_connect_fd(struct pw_context *context, /**< a \ref pw_context */
+ int fd, /**< an fd */
+ struct pw_properties *properties, /**< optional properties, ownership of
+ * the properties is taken.*/
+ size_t user_data_size /**< extra user data size */);
+
+/** Connect to a given PipeWire instance \memberof pw_core
+ * \return a pw_core on success or NULL with errno set on error */
+struct pw_core *
+pw_context_connect_self(struct pw_context *context, /**< a \ref pw_context to connect to */
+ struct pw_properties *properties, /**< optional properties, ownership of
+ * the properties is taken.*/
+ size_t user_data_size /**< extra user data size */);
+
+/** Steal the fd of the core connection or < 0 on error. The core
+ * will be disconnected after this call. */
+int pw_core_steal_fd(struct pw_core *core);
+
+/** Pause or resume the core. When the core is paused, no new events
+ * will be dispatched until the core is resumed again. */
+int pw_core_set_paused(struct pw_core *core, bool paused);
+
+/** disconnect and destroy a core */
+int pw_core_disconnect(struct pw_core *core);
+
+/** Get the user_data. It is of the size specified when this object was
+ * constructed */
+void *pw_core_get_user_data(struct pw_core *core);
+
+/** Get the client proxy of the connected core. This will have the id
+ * of PW_ID_CLIENT (1) */
+struct pw_client * pw_core_get_client(struct pw_core *core);
+
+/** Get the context object used to created this core */
+struct pw_context * pw_core_get_context(struct pw_core *core);
+
+/** Get properties from the core */
+const struct pw_properties *pw_core_get_properties(struct pw_core *core);
+
+/** Update the core properties. This updates the properties
+ * of the associated client.
+ * \return the number of properties that were updated */
+int pw_core_update_properties(struct pw_core *core, const struct spa_dict *dict);
+
+/** Get the core mempool object */
+struct pw_mempool * pw_core_get_mempool(struct pw_core *core);
+
+/** Get the proxy with the given id */
+struct pw_proxy *pw_core_find_proxy(struct pw_core *core, uint32_t id);
+
+/** Export an object into the PipeWire instance associated with core */
+struct pw_proxy *pw_core_export(struct pw_core *core, /**< the core */
+ const char *type, /**< the type of object */
+ const struct spa_dict *props, /**< extra properties */
+ void *object, /**< object to export */
+ size_t user_data_size /**< extra user data */);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_CORE_H */
diff --git a/3rdparty/pipewire/pipewire/keys.h b/3rdparty/pipewire/pipewire/keys.h
new file mode 100644
index 000000000..5326ca78f
--- /dev/null
+++ b/3rdparty/pipewire/pipewire/keys.h
@@ -0,0 +1,306 @@
+/* PipeWire
+ *
+ * Copyright © 2019 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef PIPEWIRE_KEYS_H
+#define PIPEWIRE_KEYS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A collection of keys that are used to add extra information on objects.
+ *
+ * Keys that start with "pipewire." are in general set-once and then
+ * read-only. They are usually used for security sensitive information that
+ * needs to be fixed.
+ *
+ * Properties from other objects can also appear. This usually suggests some
+ * sort of parent/child or owner/owned relationship.
+ */
+#define PW_KEY_PROTOCOL "pipewire.protocol" /**< protocol used for connection */
+#define PW_KEY_ACCESS "pipewire.access" /**< how the client access is controlled */
+#define PW_KEY_CLIENT_ACCESS "pipewire.client.access"/**< how the client wants to be access
+ * controlled */
+
+/** Various keys related to the identity of a client process and its security.
+ * Must be obtained from trusted sources by the protocol and placed as
+ * read-only properties. */
+#define PW_KEY_SEC_PID "pipewire.sec.pid" /**< Client pid, set by protocol */
+#define PW_KEY_SEC_UID "pipewire.sec.uid" /**< Client uid, set by protocol*/
+#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_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 */
+
+#define PW_KEY_OBJECT_PATH "object.path" /**< unique path to construct the object */
+#define PW_KEY_OBJECT_ID "object.id" /**< a global object id */
+
+/* config */
+#define PW_KEY_CONFIG_PREFIX "config.prefix" /**< a config prefix directory */
+#define PW_KEY_CONFIG_NAME "config.name" /**< a config file name */
+
+/* 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 */
+#define PW_KEY_HOST_NAME "context.host-name" /**< The host name of the machine */
+
+/* core */
+#define PW_KEY_CORE_NAME "core.name" /**< The name of the core. Default is
+ * pipewire-<user-name>-<pid>, overwritten
+ * by env(PIPEWIRE_CORE) */
+#define PW_KEY_CORE_VERSION "core.version" /**< The version of the core. */
+#define PW_KEY_CORE_DAEMON "core.daemon" /**< If the core is listening for connections. */
+
+#define PW_KEY_CORE_ID "core.id" /**< the core id */
+#define PW_KEY_CORE_MONITORS "core.monitors" /**< the apis monitored by core. */
+
+/* cpu */
+#define PW_KEY_CPU_MAX_ALIGN "cpu.max-align" /**< maximum alignment needed to support
+ * all CPU optimizations */
+#define PW_KEY_CPU_CORES "cpu.cores" /**< number of cores */
+
+/* priorities */
+#define PW_KEY_PRIORITY_SESSION "priority.session" /**< priority in session manager */
+#define PW_KEY_PRIORITY_DRIVER "priority.driver" /**< priority to be a driver */
+
+/* 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) */
+#define PW_KEY_REMOTE_INTENTION "remote.intention" /**< The intention of the remote connection,
+ * "generic", "screencast" */
+
+/** application keys */
+#define PW_KEY_APP_NAME "application.name" /**< application name. Ex: "Totem Music Player" */
+#define PW_KEY_APP_ID "application.id" /**< a textual id for identifying an
+ * application logically. Ex: "org.gnome.Totem" */
+#define PW_KEY_APP_VERSION "application.version" /**< application version. Ex: "1.2.0" */
+#define PW_KEY_APP_ICON "application.icon" /**< aa base64 blob with PNG image data */
+#define PW_KEY_APP_ICON_NAME "application.icon-name" /**< an XDG icon name for the application.
+ * Ex: "totem" */
+#define PW_KEY_APP_LANGUAGE "application.language" /**< application language if applicable, in
+ * standard POSIX format. Ex: "en_GB" */
+
+#define PW_KEY_APP_PROCESS_ID "application.process.id" /**< process id (pid)*/
+#define PW_KEY_APP_PROCESS_BINARY "application.process.binary" /**< binary name */
+#define PW_KEY_APP_PROCESS_USER "application.process.user" /**< user name */
+#define PW_KEY_APP_PROCESS_HOST "application.process.host" /**< host name */
+#define PW_KEY_APP_PROCESS_MACHINE_ID "application.process.machine-id" /**< the D-Bus host id the
+ * application runs on */
+#define PW_KEY_APP_PROCESS_SESSION_ID "application.process.session-id" /**< login session of the
+ * application, on Unix the
+ * value of $XDG_SESSION_ID. */
+/** window system */
+#define PW_KEY_WINDOW_X11_DISPLAY "window.x11.display" /**< the X11 display string. Ex. ":0.0" */
+
+/** Client properties */
+#define PW_KEY_CLIENT_ID "client.id" /**< a client id */
+#define PW_KEY_CLIENT_NAME "client.name" /**< the client name */
+#define PW_KEY_CLIENT_API "client.api" /**< the client api used to access
+ * PipeWire */
+
+/** Node keys */
+#define PW_KEY_NODE_ID "node.id" /**< node id */
+#define PW_KEY_NODE_NAME "node.name" /**< node name */
+#define PW_KEY_NODE_NICK "node.nick" /**< short node name */
+#define PW_KEY_NODE_DESCRIPTION "node.description" /**< localized human readable node one-line
+ * description. Ex. "Foobar USB Headset" */
+#define PW_KEY_NODE_PLUGGED "node.plugged" /**< when the node was created. As a uint64 in
+ * nanoseconds. */
+
+#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. */
+#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 */
+#define PW_KEY_NODE_TARGET "node.target" /**< node wants to be connected to the target
+ * node/session */
+#define PW_KEY_NODE_LATENCY "node.latency" /**< the requested latency of the node as
+ * a fraction. Ex: 128/48000 */
+#define PW_KEY_NODE_MAX_LATENCY "node.max-latency" /**< the maximum supported latency of the
+ * node as a fraction. Ex: 1024/48000 */
+#define PW_KEY_NODE_DONT_RECONNECT "node.dont-reconnect" /**< don't reconnect this node */
+#define PW_KEY_NODE_ALWAYS_PROCESS "node.always-process" /**< process even when unlinked */
+#define PW_KEY_NODE_PAUSE_ON_IDLE "node.pause-on-idle" /**< pause the node when idle */
+#define PW_KEY_NODE_CACHE_PARAMS "node.cache-params" /**< cache the node params */
+#define PW_KEY_NODE_DRIVER "node.driver" /**< node can drive the graph */
+#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
+ * object */
+#define PW_KEY_NODE_PASSIVE "node.passive" /**< indicate that a node wants passive links
+ * on output/input/all ports when the value is
+ * "out"/"in"/"true" respectively */
+
+/** Port keys */
+#define PW_KEY_PORT_ID "port.id" /**< port id */
+#define PW_KEY_PORT_NAME "port.name" /**< port name */
+#define PW_KEY_PORT_DIRECTION "port.direction" /**< the port direction, one of "in" or "out"
+ * or "control" and "notify" for control ports */
+#define PW_KEY_PORT_ALIAS "port.alias" /**< port alias */
+#define PW_KEY_PORT_PHYSICAL "port.physical" /**< if this is a physical port */
+#define PW_KEY_PORT_TERMINAL "port.terminal" /**< if this port consumes the data */
+#define PW_KEY_PORT_CONTROL "port.control" /**< if this port is a control port */
+#define PW_KEY_PORT_MONITOR "port.monitor" /**< if this port is a monitor port */
+#define PW_KEY_PORT_CACHE_PARAMS "port.cache-params" /**< cache the node port params */
+#define PW_KEY_PORT_EXTRA "port.extra" /**< api specific extra port info, API name
+ * should be prefixed. "jack:flags:56" */
+
+/** link properties */
+#define PW_KEY_LINK_ID "link.id" /**< a link id */
+#define PW_KEY_LINK_INPUT_NODE "link.input.node" /**< input node id of a link */
+#define PW_KEY_LINK_INPUT_PORT "link.input.port" /**< input port id of a link */
+#define PW_KEY_LINK_OUTPUT_NODE "link.output.node" /**< output node id of a link */
+#define PW_KEY_LINK_OUTPUT_PORT "link.output.port" /**< output port id of a link */
+#define PW_KEY_LINK_PASSIVE "link.passive" /**< indicate that a link is passive and
+ * does not cause the graph to be
+ * runnable. */
+#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 */
+
+/** device properties */
+#define PW_KEY_DEVICE_ID "device.id" /**< device id */
+#define PW_KEY_DEVICE_NAME "device.name" /**< device name */
+#define PW_KEY_DEVICE_PLUGGED "device.plugged" /**< when the device was created. As a uint64 in
+ * nanoseconds. */
+#define PW_KEY_DEVICE_NICK "device.nick" /**< a short device nickname */
+#define PW_KEY_DEVICE_STRING "device.string" /**< device string in the underlying layer's
+ * format. Ex. "surround51:0" */
+#define PW_KEY_DEVICE_API "device.api" /**< API this device is accessed with.
+ * Ex. "alsa", "v4l2" */
+#define PW_KEY_DEVICE_DESCRIPTION "device.description" /**< localized human readable device one-line
+ * description. Ex. "Foobar USB Headset" */
+#define PW_KEY_DEVICE_BUS_PATH "device.bus-path" /**< bus path to the device in the OS'
+ * format. Ex. "pci-0000:00:14.0-usb-0:3.2:1.0" */
+#define PW_KEY_DEVICE_SERIAL "device.serial" /**< Serial number if applicable */
+#define PW_KEY_DEVICE_VENDOR_ID "device.vendor.id" /**< vendor ID if applicable */
+#define PW_KEY_DEVICE_VENDOR_NAME "device.vendor.name" /**< vendor name if applicable */
+#define PW_KEY_DEVICE_PRODUCT_ID "device.product.id" /**< product ID if applicable */
+#define PW_KEY_DEVICE_PRODUCT_NAME "device.product.name" /**< product name if applicable */
+#define PW_KEY_DEVICE_CLASS "device.class" /**< device class */
+#define PW_KEY_DEVICE_FORM_FACTOR "device.form-factor" /**< form factor if applicable. One of
+ * "internal", "speaker", "handset", "tv",
+ * "webcam", "microphone", "headset",
+ * "headphone", "hands-free", "car", "hifi",
+ * "computer", "portable" */
+#define PW_KEY_DEVICE_BUS "device.bus" /**< bus of the device if applicable. One of
+ * "isa", "pci", "usb", "firewire",
+ * "bluetooth" */
+#define PW_KEY_DEVICE_SUBSYSTEM "device.subsystem" /**< device subsystem */
+#define PW_KEY_DEVICE_ICON "device.icon" /**< icon for the device. A base64 blob
+ * containing PNG image data */
+#define PW_KEY_DEVICE_ICON_NAME "device.icon-name" /**< an XDG icon name for the device.
+ * Ex. "sound-card-speakers-usb" */
+#define PW_KEY_DEVICE_INTENDED_ROLES "device.intended-roles" /**< intended use. A space separated list of
+ * roles (see PW_KEY_MEDIA_ROLE) this device
+ * is particularly well suited for, due to
+ * latency, quality or form factor. */
+#define PW_KEY_DEVICE_CACHE_PARAMS "device.cache-params" /**< cache the device spa params */
+
+/** module properties */
+#define PW_KEY_MODULE_ID "module.id" /**< the module id */
+#define PW_KEY_MODULE_NAME "module.name" /**< the name of the module */
+#define PW_KEY_MODULE_AUTHOR "module.author" /**< the author's name */
+#define PW_KEY_MODULE_DESCRIPTION "module.description" /**< a human readable one-line description
+ * of the module's purpose.*/
+#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. */
+
+/** Factory properties */
+#define PW_KEY_FACTORY_ID "factory.id" /**< the factory id */
+#define PW_KEY_FACTORY_NAME "factory.name" /**< the name of the factory */
+#define PW_KEY_FACTORY_USAGE "factory.usage" /**< the usage of the factory */
+#define PW_KEY_FACTORY_TYPE_NAME "factory.type.name" /**< the name of the type created by a factory */
+#define PW_KEY_FACTORY_TYPE_VERSION "factory.type.version" /**< the version of the type created by a factory */
+
+/** Stream properties */
+#define PW_KEY_STREAM_IS_LIVE "stream.is-live" /**< Indicates that the stream is live. */
+#define PW_KEY_STREAM_LATENCY_MIN "stream.latency.min" /**< The minimum latency of the stream. */
+#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. */
+#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 */
+
+/** object properties */
+#define PW_KEY_OBJECT_LINGER "object.linger" /**< the object lives on even after the client
+ * that created it has been destroyed */
+
+/** Media */
+#define PW_KEY_MEDIA_TYPE "media.type" /**< Media type, one of
+ * Audio, Video, Midi */
+#define PW_KEY_MEDIA_CATEGORY "media.category" /**< Media Category:
+ * Playback, Capture, Duplex, Monitor, Manager */
+#define PW_KEY_MEDIA_ROLE "media.role" /**< Role: Movie, Music, Camera,
+ * Screen, Communication, Game,
+ * Notification, DSP, Production,
+ * Accessibility, Test */
+#define PW_KEY_MEDIA_CLASS "media.class" /**< class Ex: "Video/Source" */
+#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_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 */
+#define PW_KEY_MEDIA_FILENAME "media.filename" /**< filename */
+#define PW_KEY_MEDIA_ICON "media.icon" /**< icon for the media, a base64 blob with
+ * PNG image data */
+#define PW_KEY_MEDIA_ICON_NAME "media.icon-name" /**< an XDG icon name for the media.
+ * Ex: "audio-x-mp3" */
+#define PW_KEY_MEDIA_COMMENT "media.comment" /**< extra comment */
+#define PW_KEY_MEDIA_DATE "media.date" /**< date of the media */
+#define PW_KEY_MEDIA_FORMAT "media.format" /**< format of the media */
+
+/** format related properties */
+#define PW_KEY_FORMAT_DSP "format.dsp" /**< a dsp format.
+ * Ex: "32 bit float mono audio" */
+/** audio related properties */
+#define PW_KEY_AUDIO_CHANNEL "audio.channel" /**< an audio channel. Ex: "FL" */
+#define PW_KEY_AUDIO_RATE "audio.samplerate" /**< an audio samplerate */
+#define PW_KEY_AUDIO_CHANNELS "audio.channels" /**< number of audio channels */
+#define PW_KEY_AUDIO_FORMAT "audio.format" /**< an audio format. Ex: "S16LE" */
+
+/** video related properties */
+#define PW_KEY_VIDEO_RATE "video.framerate" /**< a video framerate */
+#define PW_KEY_VIDEO_FORMAT "video.format" /**< a video format */
+#define PW_KEY_VIDEO_SIZE "video.size" /**< a video size as "<width>x<height" */
+
+#ifdef PW_ENABLE_DEPRECATED
+#define PW_KEY_PRIORITY_MASTER "priority.master" /**< deprecated */
+#endif /* PW_ENABLE_DEPRECATED */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_KEYS_H */
diff --git a/3rdparty/pipewire/pipewire/loop.h b/3rdparty/pipewire/pipewire/loop.h
new file mode 100644
index 000000000..bb642c466
--- /dev/null
+++ b/3rdparty/pipewire/pipewire/loop.h
@@ -0,0 +1,80 @@
+/* PipeWire
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef PIPEWIRE_LOOP_H
+#define PIPEWIRE_LOOP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/support/loop.h>
+#include <spa/utils/dict.h>
+
+/** \class pw_loop
+ *
+ * PipeWire loop object provides an implementation of
+ * the spa loop interfaces. It can be used to implement various
+ * event loops.
+ */
+struct pw_loop {
+ struct spa_system *system; /**< system utils */
+ struct spa_loop *loop; /**< wrapped loop */
+ struct spa_loop_control *control; /**< loop control */
+ struct spa_loop_utils *utils; /**< loop utils */
+};
+
+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__)
+
+#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)
+
+#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__)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_LOOP_H */
diff --git a/3rdparty/pipewire/pipewire/port.h b/3rdparty/pipewire/pipewire/port.h
new file mode 100644
index 000000000..03b1386b3
--- /dev/null
+++ b/3rdparty/pipewire/pipewire/port.h
@@ -0,0 +1,169 @@
+/* PipeWire
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef PIPEWIRE_PORT_H
+#define PIPEWIRE_PORT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+#include <errno.h>
+
+#include <spa/utils/defs.h>
+#include <spa/utils/hook.h>
+#include <spa/param/param.h>
+
+#include <pipewire/proxy.h>
+
+#define PW_TYPE_INTERFACE_Port PW_TYPE_INFO_INTERFACE_BASE "Port"
+
+#define PW_VERSION_PORT 3
+struct pw_port;
+
+/** \enum pw_direction The direction of a port \memberof pw_introspect */
+#define pw_direction spa_direction
+#define PW_DIRECTION_INPUT SPA_DIRECTION_INPUT
+#define PW_DIRECTION_OUTPUT SPA_DIRECTION_OUTPUT
+
+/** Convert a \ref pw_direction to a readable string \memberof pw_introspect */
+const char * pw_direction_as_string(enum pw_direction direction);
+
+
+/** \class pw_introspect
+ *
+ * The introspection methods and structures are used to get information
+ * about the object in the PipeWire server
+ */
+
+struct pw_port_info {
+ uint32_t id; /**< id of the global */
+ enum pw_direction direction; /**< port direction */
+#define PW_PORT_CHANGE_MASK_PROPS (1 << 0)
+#define PW_PORT_CHANGE_MASK_PARAMS (1 << 1)
+#define PW_PORT_CHANGE_MASK_ALL ((1 << 2)-1)
+ uint64_t change_mask; /**< bitfield of changed fields since last call */
+ struct spa_dict *props; /**< the properties of the port */
+ struct spa_param_info *params; /**< parameters */
+ uint32_t n_params; /**< number of items in \a params */
+};
+
+struct pw_port_info *
+pw_port_info_update(struct pw_port_info *info,
+ const struct pw_port_info *update);
+
+void
+pw_port_info_free(struct pw_port_info *info);
+
+#define PW_PORT_EVENT_INFO 0
+#define PW_PORT_EVENT_PARAM 1
+#define PW_PORT_EVENT_NUM 2
+
+/** Port events */
+struct pw_port_events {
+#define PW_VERSION_PORT_EVENTS 0
+ uint32_t version;
+ /**
+ * Notify port info
+ *
+ * \param info info about the port
+ */
+ void (*info) (void *object, const struct pw_port_info *info);
+ /**
+ * Notify a port param
+ *
+ * Event emitted as a result of the enum_params method.
+ *
+ * \param seq the sequence number of the request
+ * \param id the param id
+ * \param index the param index
+ * \param next the param index of the next param
+ * \param param the parameter
+ */
+ void (*param) (void *object, int seq,
+ uint32_t id, uint32_t index, uint32_t next,
+ const struct spa_pod *param);
+};
+
+#define PW_PORT_METHOD_ADD_LISTENER 0
+#define PW_PORT_METHOD_SUBSCRIBE_PARAMS 1
+#define PW_PORT_METHOD_ENUM_PARAMS 2
+#define PW_PORT_METHOD_NUM 3
+
+/** Port methods */
+struct pw_port_methods {
+#define PW_VERSION_PORT_METHODS 0
+ uint32_t version;
+
+ int (*add_listener) (void *object,
+ struct spa_hook *listener,
+ const struct pw_port_events *events,
+ void *data);
+ /**
+ * Subscribe to parameter changes
+ *
+ * Automatically emit param events for the given ids when
+ * they are changed.
+ *
+ * \param ids an array of param ids
+ * \param n_ids the number of ids in \a ids
+ */
+ int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
+
+ /**
+ * Enumerate port parameters
+ *
+ * Start enumeration of port parameters. For each param, a
+ * param event will be emitted.
+ *
+ * \param seq a sequence number returned in the reply
+ * \param id the parameter id to enumerate
+ * \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
+ */
+ 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__)
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PIPEWIRE_PORT_H */
diff --git a/3rdparty/pipewire/pipewire/properties.h b/3rdparty/pipewire/pipewire/properties.h
new file mode 100644
index 000000000..1784d0c0c
--- /dev/null
+++ b/3rdparty/pipewire/pipewire/properties.h
@@ -0,0 +1,125 @@
+/* PipeWire
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef PIPEWIRE_PROPERTIES_H
+#define PIPEWIRE_PROPERTIES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+
+#include <spa/utils/dict.h>
+
+/** \class pw_properties
+ *
+ * \brief A collection of key/value pairs
+ *
+ * Properties are used to pass around arbitrary key/value pairs.
+ * Both keys and values are strings which keeps things simple.
+ * Encoding of arbitrary values should be done by using a string
+ * serialization such as base64 for binary blobs.
+ */
+struct pw_properties {
+ struct spa_dict dict; /**< dictionary of key/values */
+ uint32_t flags; /**< extra flags */
+};
+
+struct pw_properties *
+pw_properties_new(const char *key, ...) SPA_SENTINEL;
+
+struct pw_properties *
+pw_properties_new_dict(const struct spa_dict *dict);
+
+struct pw_properties *
+pw_properties_new_string(const char *args);
+
+struct pw_properties *
+pw_properties_copy(const struct pw_properties *properties);
+
+int pw_properties_update_keys(struct pw_properties *props,
+ const struct spa_dict *dict, const char *keys[]);
+int pw_properties_update_ignore(struct pw_properties *props,
+ const struct spa_dict *dict, const char *ignore[]);
+
+int pw_properties_update(struct pw_properties *oldprops,
+ const struct spa_dict *dict);
+int pw_properties_update_string(struct pw_properties *props,
+ const char *str, size_t size);
+
+int pw_properties_add(struct pw_properties *oldprops,
+ const struct spa_dict *dict);
+int pw_properties_add_keys(struct pw_properties *oldprops,
+ const struct spa_dict *dict, const char *keys[]);
+
+void pw_properties_clear(struct pw_properties *properties);
+
+void
+pw_properties_free(struct pw_properties *properties);
+
+int
+pw_properties_set(struct pw_properties *properties, const char *key, const char *value);
+
+int
+pw_properties_setf(struct pw_properties *properties,
+ const char *key, const char *format, ...) SPA_PRINTF_FUNC(3, 4);
+int
+pw_properties_setva(struct pw_properties *properties,
+ const char *key, const char *format, va_list args) SPA_PRINTF_FUNC(3,0);
+const char *
+pw_properties_get(const struct pw_properties *properties, const char *key);
+
+const char *
+pw_properties_iterate(const struct pw_properties *properties, void **state);
+
+static inline bool pw_properties_parse_bool(const char *value) {
+ return (strcmp(value, "true") == 0 || atoi(value) == 1);
+}
+
+static inline int pw_properties_parse_int(const char *value) {
+ return strtol(value, NULL, 0);
+}
+
+static inline int64_t pw_properties_parse_int64(const char *value) {
+ return strtoll(value, NULL, 0);
+}
+
+static inline uint64_t pw_properties_parse_uint64(const char *value) {
+ return strtoull(value, NULL, 0);
+}
+
+static inline float pw_properties_parse_float(const char *value) {
+ return strtof(value, NULL);
+}
+
+static inline double pw_properties_parse_double(const char *value) {
+ return strtod(value, NULL);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_PROPERTIES_H */
diff --git a/3rdparty/pipewire/pipewire/protocol.h b/3rdparty/pipewire/pipewire/protocol.h
new file mode 100644
index 000000000..2a1d8a83e
--- /dev/null
+++ b/3rdparty/pipewire/pipewire/protocol.h
@@ -0,0 +1,152 @@
+/* PipeWire
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef PIPEWIRE_PROTOCOL_H
+#define PIPEWIRE_PROTOCOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/list.h>
+
+struct pw_protocol;
+
+#include <pipewire/context.h>
+#include <pipewire/properties.h>
+#include <pipewire/utils.h>
+
+#define PW_TYPE_INFO_Protocol "PipeWire:Protocol"
+#define PW_TYPE_INFO_PROTOCOL_BASE PW_TYPE_INFO_Protocol ":"
+
+struct pw_protocol_client {
+ struct spa_list link; /**< link in protocol client_list */
+ struct pw_protocol *protocol; /**< the owner protocol */
+
+ struct pw_core *core;
+
+ int (*connect) (struct pw_protocol_client *client,
+ const struct spa_dict *props,
+ void (*done_callback) (void *data, int result),
+ void *data);
+ int (*connect_fd) (struct pw_protocol_client *client, int fd, bool close);
+ int (*steal_fd) (struct pw_protocol_client *client);
+ void (*disconnect) (struct pw_protocol_client *client);
+ void (*destroy) (struct pw_protocol_client *client);
+ int (*set_paused) (struct pw_protocol_client *client, bool paused);
+};
+
+#define pw_protocol_client_connect(c,p,cb,d) ((c)->connect(c,p,cb,d))
+#define pw_protocol_client_connect_fd(c,fd,cl) ((c)->connect_fd(c,fd,cl))
+#define pw_protocol_client_steal_fd(c) ((c)->steal_fd(c))
+#define pw_protocol_client_disconnect(c) ((c)->disconnect(c))
+#define pw_protocol_client_destroy(c) ((c)->destroy(c))
+#define pw_protocol_client_set_paused(c,p) ((c)->set_paused(c,p))
+
+struct pw_protocol_server {
+ struct spa_list link; /**< link in protocol server_list */
+ struct pw_protocol *protocol; /**< the owner protocol */
+
+ struct pw_impl_core *core;
+
+ struct spa_list client_list; /**< list of clients of this protocol */
+
+ void (*destroy) (struct pw_protocol_server *listen);
+};
+
+#define pw_protocol_server_destroy(l) ((l)->destroy(l))
+
+struct pw_protocol_marshal {
+ const char *type; /**< interface type */
+ uint32_t version; /**< version */
+#define PW_PROTOCOL_MARSHAL_FLAG_IMPL (1 << 0) /**< marshal for implementations */
+ uint32_t flags; /**< version */
+ uint32_t n_client_methods; /**< number of client methods */
+ uint32_t n_server_methods; /**< number of server methods */
+ const void *client_marshal;
+ const void *server_demarshal;
+ const void *server_marshal;
+ const void *client_demarshal;
+};
+
+struct pw_protocol_implementation {
+#define PW_VERSION_PROTOCOL_IMPLEMENTATION 0
+ uint32_t version;
+
+ struct pw_protocol_client * (*new_client) (struct pw_protocol *protocol,
+ struct pw_core *core,
+ const struct spa_dict *props);
+ struct pw_protocol_server * (*add_server) (struct pw_protocol *protocol,
+ struct pw_impl_core *core,
+ const struct spa_dict *props);
+};
+
+struct pw_protocol_events {
+#define PW_VERSION_PROTOCOL_EVENTS 0
+ uint32_t version;
+
+ void (*destroy) (void *data);
+};
+
+#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_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);
+
+void pw_protocol_destroy(struct pw_protocol *protocol);
+
+struct pw_context *pw_protocol_get_context(struct pw_protocol *protocol);
+
+void *pw_protocol_get_user_data(struct pw_protocol *protocol);
+
+const struct pw_protocol_implementation *
+pw_protocol_get_implementation(struct pw_protocol *protocol);
+
+const void *
+pw_protocol_get_extension(struct pw_protocol *protocol);
+
+
+void pw_protocol_add_listener(struct pw_protocol *protocol,
+ struct spa_hook *listener,
+ const struct pw_protocol_events *events,
+ void *data);
+
+/** \class pw_protocol
+ *
+ * \brief Manages protocols and their implementation
+ */
+int pw_protocol_add_marshal(struct pw_protocol *protocol,
+ const struct pw_protocol_marshal *marshal);
+
+const struct pw_protocol_marshal *
+pw_protocol_get_marshal(struct pw_protocol *protocol, const char *type, uint32_t version, uint32_t flags);
+
+struct pw_protocol * pw_context_find_protocol(struct pw_context *context, const char *name);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PIPEWIRE_PROTOCOL_H */
diff --git a/3rdparty/pipewire/pipewire/proxy.h b/3rdparty/pipewire/pipewire/proxy.h
new file mode 100644
index 000000000..c21ea4e71
--- /dev/null
+++ b/3rdparty/pipewire/pipewire/proxy.h
@@ -0,0 +1,207 @@
+/* PipeWire
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef PIPEWIRE_PROXY_H
+#define PIPEWIRE_PROXY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/hook.h>
+
+/** \page page_proxy Proxy
+ *
+ * \section sec_page_proxy_overview Overview
+ *
+ * The proxy object is a client side representation of a resource
+ * that lives on a remote PipeWire instance.
+ *
+ * It is used to communicate with the remote object.
+ *
+ * \section sec_page_proxy_core Core proxy
+ *
+ * A proxy for a remote core object can be obtained by making
+ * a remote connection with \ref pw_core_connect.
+ * See \ref pw_page_remote_api
+ *
+ * Some methods on proxy object allow creation of more proxy objects or
+ * create a binding between a local proxy and global resource.
+ *
+ * \section sec_page_proxy_create Create
+ *
+ * A client first creates a new proxy object with pw_proxy_new(). A
+ * type must be provided for this object.
+ *
+ * The protocol of the context will usually install an interface to
+ * translate method calls and events to the wire format.
+ *
+ * The creator of the proxy will usually also install an event
+ * implementation of the particular object type.
+ *
+ * \section sec_page_proxy_bind Bind
+ *
+ * To actually use the proxy object, one needs to create a server
+ * side resource for it. This can be done by, for example, binding
+ * to a global object or by calling a method that creates and binds
+ * to a new remote object. In all cases, the local id is passed to
+ * the server and is used to create a resource with the same id.
+ *
+ * \section sec_page_proxy_methods Methods
+ *
+ * To call a method on the proxy use the interface methods. Calling
+ * any interface method will result in a request to the server to
+ * perform the requested action on the corresponding resource.
+ *
+ * \section sec_page_proxy_events Events
+ *
+ * Events send from the server to the proxy will be demarshalled by
+ * the protocol and will then result in a call to the installed
+ * implementation of the proxy.
+ *
+ * \section sec_page_proxy_destroy Destroy
+ *
+ * Use pw_proxy_destroy() to destroy the client side object. This
+ * is usually done automatically when the server removes the resource
+ * associated to the proxy.
+ */
+
+/** \class pw_proxy
+ *
+ * \brief Represents an object on the client side.
+ *
+ * A pw_proxy acts as a client side proxy to an object existing in a remote
+ * pipewire instance. The proxy is responsible for converting interface functions
+ * invoked by the client to PipeWire messages. Events will call the handlers
+ * set in listener.
+ *
+ * See \ref page_proxy
+ */
+struct pw_proxy;
+
+#include <pipewire/protocol.h>
+
+/** Proxy events, use \ref pw_proxy_add_listener */
+struct pw_proxy_events {
+#define PW_VERSION_PROXY_EVENTS 0
+ uint32_t version;
+
+ /** The proxy is destroyed */
+ void (*destroy) (void *data);
+
+ /** a proxy is bound to a global id */
+ void (*bound) (void *data, uint32_t global_id);
+
+ /** a proxy is removed from the server. Use pw_proxy_destroy to
+ * free the proxy. */
+ void (*removed) (void *data);
+
+ /** a reply to a sync method completed */
+ void (*done) (void *data, int seq);
+
+ /** an error occurred on the proxy */
+ void (*error) (void *data, int seq, int res, const char *message);
+};
+
+/** Make a new proxy object. The id can be used to bind to a remote object and
+ * can be retrieved with \ref pw_proxy_get_id . */
+struct pw_proxy *
+pw_proxy_new(struct pw_proxy *factory, /**< factory */
+ const char *type, /**< interface type */
+ uint32_t version, /**< interface version */
+ size_t user_data_size /**< size of user data */);
+
+/** Add an event listener to proxy */
+void pw_proxy_add_listener(struct pw_proxy *proxy,
+ struct spa_hook *listener,
+ const struct pw_proxy_events *events,
+ void *data);
+
+/** Add a listener for the events received from the remote object. The
+ * events depend on the type of the remote object type. */
+void pw_proxy_add_object_listener(struct pw_proxy *proxy, /**< the proxy */
+ struct spa_hook *listener, /**< listener */
+ const void *funcs, /**< proxied functions */
+ void *data /**< data passed to events */);
+
+/** destroy a proxy */
+void pw_proxy_destroy(struct pw_proxy *proxy);
+
+/** Get the user_data. The size was given in \ref pw_proxy_new */
+void *pw_proxy_get_user_data(struct pw_proxy *proxy);
+
+/** Get the local id of the proxy */
+uint32_t pw_proxy_get_id(struct pw_proxy *proxy);
+
+/** Get the type and version of the proxy */
+const char *pw_proxy_get_type(struct pw_proxy *proxy, uint32_t *version);
+
+/** Get the protocol used for the proxy */
+struct pw_protocol *pw_proxy_get_protocol(struct pw_proxy *proxy);
+
+/** Generate an sync method for a proxy. This will generate a done event
+ * with the same seq number of the reply. */
+int pw_proxy_sync(struct pw_proxy *proxy, int seq);
+
+/** Set the global id this proxy is bound to. This is usually used internally
+ * and will also emit the bound event */
+int pw_proxy_set_bound_id(struct pw_proxy *proxy, uint32_t global_id);
+/** Get the global id bound to this proxy of SPA_ID_INVALID when not bound
+ * to a global */
+uint32_t pw_proxy_get_bound_id(struct pw_proxy *proxy);
+
+/** Generate an error for a proxy */
+int pw_proxy_error(struct pw_proxy *proxy, int res, const char *error);
+int pw_proxy_errorf(struct pw_proxy *proxy, int res, const char *error, ...) SPA_PRINTF_FUNC(3, 4);
+
+/** Get the listener of proxy */
+struct spa_hook_list *pw_proxy_get_object_listeners(struct pw_proxy *proxy);
+
+/** Get the marshal functions for the proxy */
+const struct pw_protocol_marshal *pw_proxy_get_marshal(struct pw_proxy *proxy);
+
+/** Install a marshal function on a proxy */
+int pw_proxy_install_marshal(struct pw_proxy *proxy, bool implementor);
+
+#define pw_proxy_notify(p,type,event,version,...) \
+ spa_hook_list_call(pw_proxy_get_object_listeners(p), \
+ type, event, version, ## __VA_ARGS__)
+
+#define pw_proxy_call(p,type,method,version,...) \
+ spa_interface_call((struct spa_interface*)p, \
+ type, method, version, ##__VA_ARGS__)
+
+#define pw_proxy_call_res(p,type,method,version,...) \
+({ \
+ int _res = -ENOTSUP; \
+ spa_interface_call_res((struct spa_interface*)p, \
+ type, _res, method, version, ##__VA_ARGS__); \
+ _res; \
+})
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_PROXY_H */
diff --git a/3rdparty/pipewire/pipewire/stream.h b/3rdparty/pipewire/pipewire/stream.h
new file mode 100644
index 000000000..205531a24
--- /dev/null
+++ b/3rdparty/pipewire/pipewire/stream.h
@@ -0,0 +1,358 @@
+/* PipeWire
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef PIPEWIRE_STREAM_H
+#define PIPEWIRE_STREAM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \page page_streams Media Streams
+ *
+ * \section sec_overview Overview
+ *
+ * Media streams are used to exchange data with the PipeWire server. A
+ * stream is a wrapper around a proxy for a \ref pw_client_node with
+ * an adapter. This means the stream will automatically do conversion
+ * to the type required by the server.
+ *
+ * Streams can be used to:
+ *
+ * \li Consume a stream from PipeWire. This is a PW_DIRECTION_INPUT stream.
+ * \li Produce a stream to PipeWire. This is a PW_DIRECTION_OUTPUT stream
+ *
+ * You can connect the stream port to a specific server port or let PipeWire
+ * choose a port for you.
+ *
+ * For more complicated nodes such as filters or ports with multiple
+ * inputs and/or outputs you will need to use the pw_filter or make
+ * a pw_node yourself and export it with \ref pw_core_export.
+ *
+ * \section sec_create Create
+ *
+ * Make a new stream with \ref pw_stream_new(). You will need to specify
+ * a name for the stream and extra properties. You can use \ref
+ * pw_fill_stream_properties() to get a basic set of properties for the
+ * stream.
+ *
+ * Once the stream is created, the state_changed event should be used to
+ * track the state of the stream.
+ *
+ * \section sec_connect Connect
+ *
+ * The stream is initially unconnected. To connect the stream, use
+ * \ref pw_stream_connect(). Pass the desired direction as an argument.
+ *
+ * \subsection ssec_stream_target Stream target
+ *
+ * To make the newly connected stream automatically connect to an existing
+ * PipeWire node, use the \ref PW_STREAM_FLAG_AUTOCONNECT and the port_path
+ * argument while connecting.
+ *
+ * \subsection ssec_stream_formats Stream formats
+ *
+ * An array of possible formats that this stream can consume or provide
+ * must be specified.
+ *
+ * \section sec_format Format negotiation
+ *
+ * After connecting the stream, the server will want to configure some
+ * parameters on the stream. You will be notified of these changes
+ * with the param_changed event.
+ *
+ * When a format param change is emitted, the client should now prepare
+ * itself to deal with the format and complete the negotiation procedure
+ * with a call to \ref pw_stream_update_params().
+ *
+ * As arguments to \ref pw_stream_update_params() an array of spa_param
+ * structures must be given. They contain parameters such as buffer size,
+ * number of buffers, required metadata and other parameters for the
+ * media buffers.
+ *
+ * \section sec_buffers Buffer negotiation
+ *
+ * After completing the format negotiation, PipeWire will allocate and
+ * notify the stream of the buffers that will be used to exchange data
+ * between client and server.
+ *
+ * With the add_buffer event, a stream will be notified of a new buffer
+ * that can be used for data transport. You can attach user_data to these
+ * buffers.
+ *
+ * After the buffers are negotiated, the stream will transition to the
+ * \ref PW_STREAM_STATE_PAUSED state.
+ *
+ * \section sec_streaming Streaming
+ *
+ * From the \ref PW_STREAM_STATE_PAUSED state, the stream can be set to
+ * the \ref PW_STREAM_STATE_STREAMING state by the PipeWire server when
+ * data transport is started.
+ *
+ * Depending on how the stream was connected it will need to Produce or
+ * Consume data for/from PipeWire as explained in the following
+ * subsections.
+ *
+ * \subsection ssec_consume Consume data
+ *
+ * The process event is emitted for each new buffer that can be
+ * consumed.
+ *
+ * \ref pw_stream_dequeue_buffer() should be used to get the data and
+ * metadata of the buffer.
+ *
+ * When the buffer is no longer in use, call \ref pw_stream_queue_buffer()
+ * to let PipeWire reuse the buffer.
+ *
+ * \subsection ssec_produce Produce data
+ *
+ * \ref pw_stream_dequeue_buffer() gives an empty buffer that can be filled.
+ *
+ * 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.
+ *
+ * \section sec_stream_disconnect Disconnect
+ *
+ * Use \ref pw_stream_disconnect() to disconnect a stream after use.
+ */
+/** \class pw_stream
+ *
+ * \brief PipeWire stream object class
+ *
+ * The stream object provides a convenient way to send and
+ * receive data streams from/to PipeWire.
+ *
+ * See also \ref page_streams and \ref page_context_api
+ */
+struct pw_stream;
+
+#include <spa/buffer/buffer.h>
+#include <spa/param/param.h>
+
+/** \enum pw_stream_state The state of a stream \memberof pw_stream */
+enum pw_stream_state {
+ PW_STREAM_STATE_ERROR = -1, /**< the stream is in error */
+ PW_STREAM_STATE_UNCONNECTED = 0, /**< unconnected */
+ PW_STREAM_STATE_CONNECTING = 1, /**< connection is in progress */
+ PW_STREAM_STATE_PAUSED = 2, /**< paused */
+ PW_STREAM_STATE_STREAMING = 3 /**< streaming */
+};
+
+struct pw_buffer {
+ struct spa_buffer *buffer; /**< the spa buffer */
+ void *user_data; /**< user data attached to the buffer */
+ uint64_t size; /**< This field is set by the user and the sum of
+ * all queued buffer is returned in the time info */
+};
+
+struct pw_stream_control {
+ const char *name; /**< name of the control */
+ uint32_t flags; /**< extra flags (unused) */
+ float def; /**< default value */
+ float min; /**< min value */
+ float max; /**< max value */
+ float *values; /**< array of values */
+ uint32_t n_values; /**< number of values in array */
+ uint32_t max_values; /**< max values that can be set on this control */
+};
+
+/** A time structure \memberof pw_stream */
+struct pw_time {
+ int64_t now; /**< the monotonic time in nanoseconds */
+ struct spa_fraction rate; /**< the rate of \a ticks and delay */
+ uint64_t ticks; /**< the ticks at \a now. This is the current time that
+ * the remote end is reading/writing. */
+ int64_t delay; /**< delay to device, add to ticks to get the time of the
+ * device. Positive for INPUT streams and
+ * negative for OUTPUT streams. */
+ uint64_t queued; /**< data queued in the stream, this is the sum
+ * of the size fields in the pw_buffer that are
+ * currently queued */
+};
+
+#include <pipewire/port.h>
+
+/** Events for a stream. These events are always called from the mainloop
+ * unless explicitly documented otherwise. */
+struct pw_stream_events {
+#define PW_VERSION_STREAM_EVENTS 0
+ uint32_t version;
+
+ void (*destroy) (void *data);
+ /** when the stream state changes */
+ void (*state_changed) (void *data, enum pw_stream_state old,
+ enum pw_stream_state state, const char *error);
+
+ /** Notify information about a control. */
+ void (*control_info) (void *data, uint32_t id, const struct pw_stream_control *control);
+
+ /** when io changed on the stream. */
+ void (*io_changed) (void *data, uint32_t id, void *area, uint32_t size);
+ /** when a parameter changed */
+ void (*param_changed) (void *data, uint32_t id, const struct spa_pod *param);
+
+ /** when a new buffer was created for this stream */
+ void (*add_buffer) (void *data, struct pw_buffer *buffer);
+ /** when a buffer was destroyed for this stream */
+ void (*remove_buffer) (void *data, struct pw_buffer *buffer);
+
+ /** when a buffer can be queued (for playback streams) or
+ * dequeued (for capture streams). This is normally called from the
+ * mainloop but can also be called directly from the realtime data
+ * thread if the user is prepared to deal with this. */
+ void (*process) (void *data);
+
+ /** The stream is drained */
+ void (*drained) (void *data);
+
+};
+
+/** Convert a stream state to a readable string \memberof pw_stream */
+const char * pw_stream_state_as_string(enum pw_stream_state state);
+
+/** \enum pw_stream_flags Extra flags that can be used in \ref pw_stream_connect() \memberof pw_stream */
+enum pw_stream_flags {
+ PW_STREAM_FLAG_NONE = 0, /**< no flags */
+ PW_STREAM_FLAG_AUTOCONNECT = (1 << 0), /**< try to automatically connect
+ * this stream */
+ 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_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
+ * in the process callback. */
+ PW_STREAM_FLAG_NO_CONVERT = (1 << 5), /**< don't convert format */
+ PW_STREAM_FLAG_EXCLUSIVE = (1 << 6), /**< require exclusive access to the
+ * device */
+ PW_STREAM_FLAG_DONT_RECONNECT = (1 << 7), /**< don't try to reconnect this stream
+ * when the sink/source is removed */
+ PW_STREAM_FLAG_ALLOC_BUFFERS = (1 << 8), /**< the application will allocate buffer
+ * memory. In the add_buffer event, the
+ * data of the buffer should be set */
+};
+
+/** Create a new unconneced \ref pw_stream \memberof pw_stream
+ * \return a newly allocated \ref pw_stream */
+struct pw_stream *
+pw_stream_new(struct pw_core *core, /**< a \ref pw_core */
+ const char *name, /**< a stream media name */
+ 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 */
+ const char *name, /**< a stream media name */
+ struct pw_properties *props,/**< stream properties, ownership is taken */
+ const struct pw_stream_events *events, /**< stream events */
+ void *data /**< data passed to events */);
+
+/** Destroy a stream \memberof pw_stream */
+void pw_stream_destroy(struct pw_stream *stream);
+
+void pw_stream_add_listener(struct pw_stream *stream,
+ struct spa_hook *listener,
+ const struct pw_stream_events *events,
+ void *data);
+
+enum pw_stream_state pw_stream_get_state(struct pw_stream *stream, const char **error);
+
+const char *pw_stream_get_name(struct pw_stream *stream);
+
+struct pw_core *pw_stream_get_core(struct pw_stream *stream);
+
+const struct pw_properties *pw_stream_get_properties(struct pw_stream *stream);
+
+int pw_stream_update_properties(struct pw_stream *stream, const struct spa_dict *dict);
+
+/** Connect a stream for input or output on \a port_path. \memberof pw_stream
+ * \return 0 on success < 0 on error.
+ *
+ * You should connect to the process event and use pw_stream_dequeue_buffer()
+ * to get the latest metadata and data. */
+int
+pw_stream_connect(struct pw_stream *stream, /**< a \ref pw_stream */
+ enum pw_direction direction, /**< the stream direction */
+ uint32_t target_id, /**< the target object id to connect to or
+ * PW_ID_ANY to let the manager
+ * select a target. */
+ enum pw_stream_flags flags, /**< stream flags */
+ const struct spa_pod **params, /**< an array with params. The params
+ * should ideally contain supported
+ * formats. */
+ uint32_t n_params /**< number of items in \a params */);
+
+/** Get the node ID of the stream. \memberof pw_stream
+ * \return node ID. */
+uint32_t
+pw_stream_get_node_id(struct pw_stream *stream);
+
+/** Disconnect \a stream \memberof pw_stream */
+int pw_stream_disconnect(struct pw_stream *stream);
+
+/** Set the stream in error state */
+int pw_stream_set_error(struct pw_stream *stream, /**< a \ref pw_stream */
+ int res, /**< a result code */
+ const char *error, ... /**< an error message */) SPA_PRINTF_FUNC(3, 4);
+
+/** Complete the negotiation process with result code \a res \memberof pw_stream
+ *
+ * This function should be called after notification of the format.
+
+ * When \a res indicates success, \a params contain the parameters for the
+ * allocation state. */
+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. */
+ uint32_t n_params /**< number of elements in \a params */);
+
+/** 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 \memberof pw_stream */
+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. */
+struct pw_buffer *pw_stream_dequeue_buffer(struct pw_stream *stream);
+
+/** Submit a buffer for playback or recycle a buffer for capture. */
+int pw_stream_queue_buffer(struct pw_stream *stream, struct pw_buffer *buffer);
+
+/** Activate or deactivate the stream \memberof pw_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 */
+int pw_stream_flush(struct pw_stream *stream, bool drain);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_STREAM_H */
diff --git a/3rdparty/pipewire/pipewire/utils.h b/3rdparty/pipewire/pipewire/utils.h
new file mode 100644
index 000000000..317ee92d2
--- /dev/null
+++ b/3rdparty/pipewire/pipewire/utils.h
@@ -0,0 +1,73 @@
+/* PipeWire
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef PIPEWIRE_UTILS_H
+#define PIPEWIRE_UTILS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+
+#include <spa/utils/defs.h>
+#include <spa/pod/pod.h>
+
+/** \class pw_utils
+ *
+ * Various utility functions
+ */
+
+/** a function to destroy an item \memberof pw_utils */
+typedef void (*pw_destroy_t) (void *object);
+
+const char *
+pw_split_walk(const char *str, const char *delimiter, size_t *len, const char **state);
+
+char **
+pw_split_strv(const char *str, const char *delimiter, int max_tokens, int *n_tokens);
+
+void
+pw_free_strv(char **str);
+
+char *
+pw_strip(char *str, const char *whitespace);
+
+#if !defined(strndupa)
+# define strndupa(s, n) \
+ ({ \
+ const char *__old = (s); \
+ size_t __len = strnlen(__old, (n)); \
+ char *__new = (char *) __builtin_alloca(__len + 1); \
+ memcpy(__new, __old, __len); \
+ __new[__len] = '\0'; \
+ __new; \
+ })
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PIPEWIRE_UTILS_H */
diff --git a/3rdparty/pipewire/spa/buffer/buffer.h b/3rdparty/pipewire/spa/buffer/buffer.h
new file mode 100644
index 000000000..2e4a6d510
--- /dev/null
+++ b/3rdparty/pipewire/spa/buffer/buffer.h
@@ -0,0 +1,119 @@
+/* Simple Plugin API
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_BUFFER_H
+#define SPA_BUFFER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/defs.h>
+#include <spa/buffer/meta.h>
+
+/** \page page_buffer Buffers
+ *
+ * Buffers describe the data and metadata that is exchanged between
+ * ports of a node.
+ */
+
+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_LAST, /**< not part of ABI */
+};
+
+/** Chunk of memory, can change for each buffer */
+struct spa_chunk {
+ uint32_t offset; /**< offset of valid data. Should be taken
+ * modulo the data maxsize to get the offset
+ * in the data memory. */
+ uint32_t size; /**< size of valid data. Should be clamped to
+ * maxsize. */
+ int32_t stride; /**< stride of valid data */
+#define SPA_CHUNK_FLAG_NONE 0
+#define SPA_CHUNK_FLAG_CORRUPTED (1u<<0) /**< chunk data is corrupted in some way */
+ int32_t flags; /**< chunk flags */
+};
+
+/** Data for a buffer this stays constant for a buffer */
+struct spa_data {
+ uint32_t type; /**< memory type, one of enum spa_data_type, when
+ * allocating memory, the type contains a bitmask
+ * of allowed types. SPA_ID_INVALID is a special
+ * value for the allocator to indicate that the
+ * other side did not explicitly specify any
+ * supported data types. It should probably use
+ * a memory type that does not require special
+ * handling in addition to simple mmap/munmap. */
+#define SPA_DATA_FLAG_NONE 0
+#define SPA_DATA_FLAG_READABLE (1u<<0) /**< data is readable */
+#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)
+ uint32_t flags; /**< data flags */
+ int64_t fd; /**< optional fd for data */
+ uint32_t mapoffset; /**< offset to map fd at */
+ uint32_t maxsize; /**< max size of data */
+ void *data; /**< optional data pointer */
+ struct spa_chunk *chunk; /**< valid chunk of memory */
+};
+
+/** A Buffer */
+struct spa_buffer {
+ uint32_t n_metas; /**< number of metadata */
+ uint32_t n_datas; /**< number of data members */
+ struct spa_meta *metas; /**< array of metadata */
+ struct spa_data *datas; /**< array of data members */
+};
+
+/** Find metadata in a buffer */
+static inline struct spa_meta *spa_buffer_find_meta(const struct spa_buffer *b, uint32_t type)
+{
+ uint32_t i;
+
+ for (i = 0; i < b->n_metas; i++)
+ if (b->metas[i].type == type)
+ return &b->metas[i];
+
+ return NULL;
+}
+
+static inline 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)
+ return m->data;
+ return NULL;
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_BUFFER_H */
diff --git a/3rdparty/pipewire/spa/buffer/meta.h b/3rdparty/pipewire/spa/buffer/meta.h
new file mode 100644
index 000000000..6f12d7883
--- /dev/null
+++ b/3rdparty/pipewire/spa/buffer/meta.h
@@ -0,0 +1,158 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_META_H
+#define SPA_META_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/defs.h>
+#include <spa/pod/pod.h>
+
+/** \page page_meta Metadata
+ *
+ * Metadata contains extra information on a buffer.
+ */
+enum spa_meta_type {
+ SPA_META_Invalid,
+ SPA_META_Header, /**< struct spa_meta_header */
+ SPA_META_VideoCrop, /**< struct spa_meta_region with cropping data */
+ SPA_META_VideoDamage, /**< array of struct spa_meta_region with damage */
+ SPA_META_Bitmap, /**< struct spa_meta_bitmap */
+ SPA_META_Cursor, /**< struct spa_meta_cursor */
+ SPA_META_Control, /**< metadata contains a spa_meta_control
+ * associated with the data */
+ SPA_META_Busy, /**< don't write to buffer when count > 0 */
+
+ SPA_META_LAST, /**< not part of ABI/API */
+};
+
+/**
+ * A metadata element.
+ *
+ * This structure is available on the buffer structure and contains
+ * the type of the metadata and a pointer/size to the actual metadata
+ * itself.
+ */
+struct spa_meta {
+ uint32_t type; /**< metadata type, one of enum spa_meta_type */
+ uint32_t size; /**< size of metadata */
+ void *data; /**< pointer to metadata */
+};
+
+#define spa_meta_first(m) ((m)->data)
+#define spa_meta_end(m) SPA_PTROFF((m)->data,(m)->size,void)
+#define spa_meta_check(p,m) (SPA_PTROFF(p,sizeof(*p),void) <= spa_meta_end(m))
+
+/**
+ * Describes essential buffer header metadata such as flags and
+ * timestamps.
+ */
+struct spa_meta_header {
+#define SPA_META_HEADER_FLAG_DISCONT (1 << 0) /**< data is not continuous with previous buffer */
+#define SPA_META_HEADER_FLAG_CORRUPTED (1 << 1) /**< data might be corrupted */
+#define SPA_META_HEADER_FLAG_MARKER (1 << 2) /**< media specific marker */
+#define SPA_META_HEADER_FLAG_HEADER (1 << 3) /**< data contains a codec specific header */
+#define SPA_META_HEADER_FLAG_GAP (1 << 4) /**< data contains media neutral data */
+#define SPA_META_HEADER_FLAG_DELTA_UNIT (1 << 5) /**< cannot be decoded independently */
+ uint32_t flags; /**< flags */
+ uint32_t offset; /**< offset in current cycle */
+ int64_t pts; /**< presentation timestamp */
+ int64_t dts_offset; /**< decoding timestamp as a difference with pts */
+ uint64_t seq; /**< sequence number, increments with a
+ * media specific frequency */
+};
+
+/** metadata structure for Region or an array of these for RegionArray */
+struct spa_meta_region {
+ struct spa_region region;
+};
+
+#define spa_meta_region_is_valid(m) ((m)->region.size.width != 0 && (m)->region.size.height != 0)
+
+/** iterate all the items in a metadata */
+#define spa_meta_for_each(pos,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
+ *
+ * This metadata contains a bitmap image in the given format and size.
+ * It is typically used for cursor images or other small images that are
+ * better transferred inline.
+ */
+struct spa_meta_bitmap {
+ uint32_t format; /**< bitmap video format, one of enum spa_video_format. 0 is
+ * and invalid format and should be handled as if there is
+ * no new bitmap information. */
+ struct spa_rectangle size; /**< width and height of bitmap */
+ int32_t stride; /**< stride of bitmap data */
+ uint32_t offset; /**< offset of bitmap data in this structure. An offset of
+ * 0 means no image data (invisible), an offset >=
+ * sizeof(struct spa_meta_bitmap) contains valid bitmap
+ * info. */
+};
+
+#define spa_meta_cursor_is_valid(m) ((m)->id != 0)
+
+/**
+ * Cursor information
+ *
+ * Metadata to describe the position and appearance of a pointing device.
+ */
+struct spa_meta_cursor {
+ uint32_t id; /**< cursor id. an id of 0 is an invalid id and means that
+ * there is no new cursor data */
+ uint32_t flags; /**< extra flags */
+ struct spa_point position; /**< position on screen */
+ struct spa_point hotspot; /**< offsets for hotspot in bitmap, this field has no meaning
+ * when there is no valid bitmap (see below) */
+ uint32_t bitmap_offset; /**< offset of bitmap meta in this structure. When the offset
+ * is 0, there is no new bitmap information. When the offset is
+ * >= sizeof(struct spa_meta_cursor) there is a
+ * struct spa_meta_bitmap at the offset. */
+};
+
+/** a timed set of events associated with the buffer */
+struct spa_meta_control {
+ struct spa_pod_sequence sequence;
+};
+
+/** a busy counter for the buffer */
+struct spa_meta_busy {
+ uint32_t flags;
+ uint32_t count; /**< number of users busy with the buffer */
+};
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_META_H */
diff --git a/3rdparty/pipewire/spa/param/audio/format-utils.h b/3rdparty/pipewire/spa/param/audio/format-utils.h
new file mode 100644
index 000000000..dc7a2b9f5
--- /dev/null
+++ b/3rdparty/pipewire/spa/param/audio/format-utils.h
@@ -0,0 +1,113 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_PARAM_AUDIO_FORMAT_UTILS_H
+#define SPA_PARAM_AUDIO_FORMAT_UTILS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include <spa/pod/parser.h>
+#include <spa/pod/builder.h>
+#include <spa/param/audio/format.h>
+#include <spa/param/format-utils.h>
+
+static inline int
+spa_format_audio_raw_parse(const struct spa_pod *format, struct spa_audio_info_raw *info)
+{
+ struct spa_pod *position = NULL;
+ int res;
+ info->flags = 0;
+ res = spa_pod_parse_object(format,
+ SPA_TYPE_OBJECT_Format, NULL,
+ SPA_FORMAT_AUDIO_format, SPA_POD_Id(&info->format),
+ SPA_FORMAT_AUDIO_rate, SPA_POD_Int(&info->rate),
+ SPA_FORMAT_AUDIO_channels, SPA_POD_Int(&info->channels),
+ SPA_FORMAT_AUDIO_position, SPA_POD_OPT_Pod(&position));
+ if (position == NULL ||
+ !spa_pod_copy_array(position, SPA_TYPE_Id, info->position, SPA_AUDIO_MAX_CHANNELS))
+ SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);
+
+ return res;
+}
+
+static inline int
+spa_format_audio_dsp_parse(const struct spa_pod *format, struct spa_audio_info_dsp *info)
+{
+ int res;
+ res = spa_pod_parse_object(format,
+ SPA_TYPE_OBJECT_Format, NULL,
+ SPA_FORMAT_AUDIO_format, SPA_POD_Id(&info->format));
+ return res;
+}
+
+static inline struct spa_pod *
+spa_format_audio_raw_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_raw *info)
+{
+ struct spa_pod_frame f;
+ spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
+ spa_pod_builder_add(builder,
+ SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
+ SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
+ 0);
+ if (info->format != SPA_AUDIO_FORMAT_UNKNOWN)
+ spa_pod_builder_add(builder,
+ SPA_FORMAT_AUDIO_format, SPA_POD_Id(info->format), 0);
+ if (info->rate != 0)
+ spa_pod_builder_add(builder,
+ SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate), 0);
+ if (info->channels != 0) {
+ spa_pod_builder_add(builder,
+ SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info->channels), 0);
+ if (!SPA_FLAG_IS_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED)) {
+ spa_pod_builder_add(builder, SPA_FORMAT_AUDIO_position,
+ SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id,
+ info->channels, info->position), 0);
+ }
+ }
+ return (struct spa_pod*)spa_pod_builder_pop(builder, &f);
+}
+
+static inline struct spa_pod *
+spa_format_audio_dsp_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_dsp *info)
+{
+ struct spa_pod_frame f;
+ spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
+ spa_pod_builder_add(builder,
+ SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
+ SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsp),
+ 0);
+ if (info->format != SPA_AUDIO_FORMAT_UNKNOWN)
+ spa_pod_builder_add(builder,
+ SPA_FORMAT_AUDIO_format, SPA_POD_Id(info->format), 0);
+ return (struct spa_pod*)spa_pod_builder_pop(builder, &f);
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_PARAM_AUDIO_FORMAT_UTILS_H */
diff --git a/3rdparty/pipewire/spa/param/audio/format.h b/3rdparty/pipewire/spa/param/audio/format.h
new file mode 100644
index 000000000..507a7453d
--- /dev/null
+++ b/3rdparty/pipewire/spa/param/audio/format.h
@@ -0,0 +1,48 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_PARAM_AUDIO_FORMAT_H
+#define SPA_PARAM_AUDIO_FORMAT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/param/format.h>
+#include <spa/param/audio/raw.h>
+
+struct spa_audio_info {
+ uint32_t media_type;
+ uint32_t media_subtype;
+ union {
+ struct spa_audio_info_raw raw;
+ struct spa_audio_info_dsp dsp;
+ } info;
+};
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_PARAM_AUDIO_FORMAT_H */
diff --git a/3rdparty/pipewire/spa/param/audio/raw.h b/3rdparty/pipewire/spa/param/audio/raw.h
new file mode 100644
index 000000000..7689811ae
--- /dev/null
+++ b/3rdparty/pipewire/spa/param/audio/raw.h
@@ -0,0 +1,242 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_AUDIO_RAW_H
+#define SPA_AUDIO_RAW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#ifndef __FreeBSD__
+#include <endian.h>
+#endif
+
+#define SPA_AUDIO_MAX_CHANNELS 64u
+
+enum spa_audio_format {
+ SPA_AUDIO_FORMAT_UNKNOWN,
+ SPA_AUDIO_FORMAT_ENCODED,
+
+ /* interleaved formats */
+ SPA_AUDIO_FORMAT_START_Interleaved = 0x100,
+ SPA_AUDIO_FORMAT_S8,
+ SPA_AUDIO_FORMAT_U8,
+ SPA_AUDIO_FORMAT_S16_LE,
+ SPA_AUDIO_FORMAT_S16_BE,
+ SPA_AUDIO_FORMAT_U16_LE,
+ SPA_AUDIO_FORMAT_U16_BE,
+ SPA_AUDIO_FORMAT_S24_32_LE,
+ SPA_AUDIO_FORMAT_S24_32_BE,
+ SPA_AUDIO_FORMAT_U24_32_LE,
+ SPA_AUDIO_FORMAT_U24_32_BE,
+ SPA_AUDIO_FORMAT_S32_LE,
+ SPA_AUDIO_FORMAT_S32_BE,
+ SPA_AUDIO_FORMAT_U32_LE,
+ SPA_AUDIO_FORMAT_U32_BE,
+ SPA_AUDIO_FORMAT_S24_LE,
+ SPA_AUDIO_FORMAT_S24_BE,
+ SPA_AUDIO_FORMAT_U24_LE,
+ SPA_AUDIO_FORMAT_U24_BE,
+ SPA_AUDIO_FORMAT_S20_LE,
+ SPA_AUDIO_FORMAT_S20_BE,
+ SPA_AUDIO_FORMAT_U20_LE,
+ SPA_AUDIO_FORMAT_U20_BE,
+ SPA_AUDIO_FORMAT_S18_LE,
+ SPA_AUDIO_FORMAT_S18_BE,
+ SPA_AUDIO_FORMAT_U18_LE,
+ SPA_AUDIO_FORMAT_U18_BE,
+ SPA_AUDIO_FORMAT_F32_LE,
+ SPA_AUDIO_FORMAT_F32_BE,
+ SPA_AUDIO_FORMAT_F64_LE,
+ SPA_AUDIO_FORMAT_F64_BE,
+
+ /* planar formats */
+ SPA_AUDIO_FORMAT_START_Planar = 0x200,
+ SPA_AUDIO_FORMAT_U8P,
+ SPA_AUDIO_FORMAT_S16P,
+ SPA_AUDIO_FORMAT_S24_32P,
+ SPA_AUDIO_FORMAT_S32P,
+ SPA_AUDIO_FORMAT_S24P,
+ SPA_AUDIO_FORMAT_F32P,
+ SPA_AUDIO_FORMAT_F64P,
+ SPA_AUDIO_FORMAT_S8P,
+
+ /* other formats start here */
+ SPA_AUDIO_FORMAT_START_Other = 0x400,
+
+ /* Aliases */
+
+ /* DSP formats */
+ SPA_AUDIO_FORMAT_DSP_S32 = SPA_AUDIO_FORMAT_S24_32P,
+ SPA_AUDIO_FORMAT_DSP_F32 = SPA_AUDIO_FORMAT_F32P,
+ SPA_AUDIO_FORMAT_DSP_F64 = SPA_AUDIO_FORMAT_F64P,
+
+ /* native endian */
+#if __BYTE_ORDER == __BIG_ENDIAN
+ SPA_AUDIO_FORMAT_S16 = SPA_AUDIO_FORMAT_S16_BE,
+ SPA_AUDIO_FORMAT_U16 = SPA_AUDIO_FORMAT_U16_BE,
+ SPA_AUDIO_FORMAT_S24_32 = SPA_AUDIO_FORMAT_S24_32_BE,
+ SPA_AUDIO_FORMAT_U24_32 = SPA_AUDIO_FORMAT_U24_32_BE,
+ SPA_AUDIO_FORMAT_S32 = SPA_AUDIO_FORMAT_S32_BE,
+ SPA_AUDIO_FORMAT_U32 = SPA_AUDIO_FORMAT_U32_BE,
+ SPA_AUDIO_FORMAT_S24 = SPA_AUDIO_FORMAT_S24_BE,
+ SPA_AUDIO_FORMAT_U24 = SPA_AUDIO_FORMAT_U24_BE,
+ SPA_AUDIO_FORMAT_S20 = SPA_AUDIO_FORMAT_S20_BE,
+ SPA_AUDIO_FORMAT_U20 = SPA_AUDIO_FORMAT_U20_BE,
+ SPA_AUDIO_FORMAT_S18 = SPA_AUDIO_FORMAT_S18_BE,
+ SPA_AUDIO_FORMAT_U18 = SPA_AUDIO_FORMAT_U18_BE,
+ SPA_AUDIO_FORMAT_F32 = SPA_AUDIO_FORMAT_F32_BE,
+ SPA_AUDIO_FORMAT_F64 = SPA_AUDIO_FORMAT_F64_BE,
+ SPA_AUDIO_FORMAT_S16_OE = SPA_AUDIO_FORMAT_S16_LE,
+ SPA_AUDIO_FORMAT_U16_OE = SPA_AUDIO_FORMAT_U16_LE,
+ SPA_AUDIO_FORMAT_S24_32_OE = SPA_AUDIO_FORMAT_S24_32_LE,
+ SPA_AUDIO_FORMAT_U24_32_OE = SPA_AUDIO_FORMAT_U24_32_LE,
+ SPA_AUDIO_FORMAT_S32_OE = SPA_AUDIO_FORMAT_S32_LE,
+ SPA_AUDIO_FORMAT_U32_OE = SPA_AUDIO_FORMAT_U32_LE,
+ SPA_AUDIO_FORMAT_S24_OE = SPA_AUDIO_FORMAT_S24_LE,
+ SPA_AUDIO_FORMAT_U24_OE = SPA_AUDIO_FORMAT_U24_LE,
+ SPA_AUDIO_FORMAT_S20_OE = SPA_AUDIO_FORMAT_S20_LE,
+ SPA_AUDIO_FORMAT_U20_OE = SPA_AUDIO_FORMAT_U20_LE,
+ SPA_AUDIO_FORMAT_S18_OE = SPA_AUDIO_FORMAT_S18_LE,
+ SPA_AUDIO_FORMAT_U18_OE = SPA_AUDIO_FORMAT_U18_LE,
+ SPA_AUDIO_FORMAT_F32_OE = SPA_AUDIO_FORMAT_F32_LE,
+ SPA_AUDIO_FORMAT_F64_OE = SPA_AUDIO_FORMAT_F64_LE,
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ SPA_AUDIO_FORMAT_S16 = SPA_AUDIO_FORMAT_S16_LE,
+ SPA_AUDIO_FORMAT_U16 = SPA_AUDIO_FORMAT_U16_LE,
+ SPA_AUDIO_FORMAT_S24_32 = SPA_AUDIO_FORMAT_S24_32_LE,
+ SPA_AUDIO_FORMAT_U24_32 = SPA_AUDIO_FORMAT_U24_32_LE,
+ SPA_AUDIO_FORMAT_S32 = SPA_AUDIO_FORMAT_S32_LE,
+ SPA_AUDIO_FORMAT_U32 = SPA_AUDIO_FORMAT_U32_LE,
+ SPA_AUDIO_FORMAT_S24 = SPA_AUDIO_FORMAT_S24_LE,
+ SPA_AUDIO_FORMAT_U24 = SPA_AUDIO_FORMAT_U24_LE,
+ SPA_AUDIO_FORMAT_S20 = SPA_AUDIO_FORMAT_S20_LE,
+ SPA_AUDIO_FORMAT_U20 = SPA_AUDIO_FORMAT_U20_LE,
+ SPA_AUDIO_FORMAT_S18 = SPA_AUDIO_FORMAT_S18_LE,
+ SPA_AUDIO_FORMAT_U18 = SPA_AUDIO_FORMAT_U18_LE,
+ SPA_AUDIO_FORMAT_F32 = SPA_AUDIO_FORMAT_F32_LE,
+ SPA_AUDIO_FORMAT_F64 = SPA_AUDIO_FORMAT_F64_LE,
+ SPA_AUDIO_FORMAT_S16_OE = SPA_AUDIO_FORMAT_S16_BE,
+ SPA_AUDIO_FORMAT_U16_OE = SPA_AUDIO_FORMAT_U16_BE,
+ SPA_AUDIO_FORMAT_S24_32_OE = SPA_AUDIO_FORMAT_S24_32_BE,
+ SPA_AUDIO_FORMAT_U24_32_OE = SPA_AUDIO_FORMAT_U24_32_BE,
+ SPA_AUDIO_FORMAT_S32_OE = SPA_AUDIO_FORMAT_S32_BE,
+ SPA_AUDIO_FORMAT_U32_OE = SPA_AUDIO_FORMAT_U32_BE,
+ SPA_AUDIO_FORMAT_S24_OE = SPA_AUDIO_FORMAT_S24_BE,
+ SPA_AUDIO_FORMAT_U24_OE = SPA_AUDIO_FORMAT_U24_BE,
+ SPA_AUDIO_FORMAT_S20_OE = SPA_AUDIO_FORMAT_S20_BE,
+ SPA_AUDIO_FORMAT_U20_OE = SPA_AUDIO_FORMAT_U20_BE,
+ SPA_AUDIO_FORMAT_S18_OE = SPA_AUDIO_FORMAT_S18_BE,
+ SPA_AUDIO_FORMAT_U18_OE = SPA_AUDIO_FORMAT_U18_BE,
+ SPA_AUDIO_FORMAT_F32_OE = SPA_AUDIO_FORMAT_F32_BE,
+ SPA_AUDIO_FORMAT_F64_OE = SPA_AUDIO_FORMAT_F64_BE,
+#endif
+};
+
+#define SPA_AUDIO_FORMAT_IS_INTERLEAVED(fmt) ((fmt) > SPA_AUDIO_FORMAT_START_Interleaved && (fmt) < SPA_AUDIO_FORMAT_START_Planar)
+#define SPA_AUDIO_FORMAT_IS_PLANAR(fmt) ((fmt) > SPA_AUDIO_FORMAT_START_Planar && (fmt) < SPA_AUDIO_FORMAT_START_Other)
+
+enum spa_audio_channel {
+ SPA_AUDIO_CHANNEL_UNKNOWN, /**< unspecified */
+ SPA_AUDIO_CHANNEL_NA, /**< N/A, silent */
+
+ SPA_AUDIO_CHANNEL_MONO, /**< mono stream */
+
+ SPA_AUDIO_CHANNEL_FL, /**< front left */
+ SPA_AUDIO_CHANNEL_FR, /**< front right */
+ SPA_AUDIO_CHANNEL_FC, /**< front center */
+ SPA_AUDIO_CHANNEL_LFE, /**< LFE */
+ SPA_AUDIO_CHANNEL_SL, /**< side left */
+ SPA_AUDIO_CHANNEL_SR, /**< side right */
+ SPA_AUDIO_CHANNEL_FLC, /**< front left center */
+ SPA_AUDIO_CHANNEL_FRC, /**< front right center */
+ SPA_AUDIO_CHANNEL_RC, /**< rear center */
+ SPA_AUDIO_CHANNEL_RL, /**< rear left */
+ SPA_AUDIO_CHANNEL_RR, /**< rear right */
+ SPA_AUDIO_CHANNEL_TC, /**< top center */
+ SPA_AUDIO_CHANNEL_TFL, /**< top front left */
+ SPA_AUDIO_CHANNEL_TFC, /**< top front center */
+ SPA_AUDIO_CHANNEL_TFR, /**< top front right */
+ SPA_AUDIO_CHANNEL_TRL, /**< top rear left */
+ SPA_AUDIO_CHANNEL_TRC, /**< top rear center */
+ SPA_AUDIO_CHANNEL_TRR, /**< top rear right */
+ SPA_AUDIO_CHANNEL_RLC, /**< rear left center */
+ SPA_AUDIO_CHANNEL_RRC, /**< rear right center */
+ SPA_AUDIO_CHANNEL_FLW, /**< front left wide */
+ SPA_AUDIO_CHANNEL_FRW, /**< front right wide */
+ SPA_AUDIO_CHANNEL_LFE2, /**< LFE 2 */
+ SPA_AUDIO_CHANNEL_FLH, /**< front left high */
+ SPA_AUDIO_CHANNEL_FCH, /**< front center high */
+ SPA_AUDIO_CHANNEL_FRH, /**< front right high */
+ SPA_AUDIO_CHANNEL_TFLC, /**< top front left center */
+ SPA_AUDIO_CHANNEL_TFRC, /**< top front right center */
+ SPA_AUDIO_CHANNEL_TSL, /**< top side left */
+ SPA_AUDIO_CHANNEL_TSR, /**< top side right */
+ SPA_AUDIO_CHANNEL_LLFE, /**< left LFE */
+ SPA_AUDIO_CHANNEL_RLFE, /**< right LFE */
+ SPA_AUDIO_CHANNEL_BC, /**< bottom center */
+ SPA_AUDIO_CHANNEL_BLC, /**< bottom left center */
+ SPA_AUDIO_CHANNEL_BRC, /**< bottom right center */
+
+ SPA_AUDIO_CHANNEL_CUSTOM_START = 0x10000,
+};
+
+/** Extra audio flags */
+#define SPA_AUDIO_FLAG_NONE (0) /*< no valid flag */
+#define SPA_AUDIO_FLAG_UNPOSITIONED (1 << 0) /*< the position array explicitly
+ * contains unpositioned channels. */
+/** Audio information description */
+struct spa_audio_info_raw {
+ enum spa_audio_format format; /*< format, one of enum spa_audio_format */
+ uint32_t flags; /*< extra flags */
+ uint32_t rate; /*< sample rate */
+ uint32_t channels; /*< number of channels */
+ uint32_t position[SPA_AUDIO_MAX_CHANNELS]; /*< channel position from enum spa_audio_channel */
+};
+
+#define SPA_AUDIO_INFO_RAW_INIT(...) (struct spa_audio_info_raw) { __VA_ARGS__ }
+
+#define SPA_KEY_AUDIO_FORMAT "audio.format" /**< an audio format as string,
+ * Ex. "S16LE" */
+#define SPA_KEY_AUDIO_CHANNEL "audio.channel" /**< an audio channel as string,
+ * Ex. "FL" */
+#define SPA_KEY_AUDIO_CHANNELS "audio.channels" /**< an audio channel count as int */
+#define SPA_KEY_AUDIO_RATE "audio.rate" /**< an audio sample rate as int */
+#define SPA_KEY_AUDIO_POSITION "audio.position" /**< channel positions as comma separated list
+ * of channels ex. "FL,FR" */
+
+struct spa_audio_info_dsp {
+ enum spa_audio_format format; /*< format, one of the DSP formats in enum spa_audio_format_dsp */
+};
+
+#define SPA_AUDIO_INFO_DSP_INIT(...) (struct spa_audio_info_dsp) { __VA_ARGS__ }
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_AUDIO_RAW_H */
diff --git a/3rdparty/pipewire/spa/param/format-utils.h b/3rdparty/pipewire/spa/param/format-utils.h
new file mode 100644
index 000000000..8e11bab50
--- /dev/null
+++ b/3rdparty/pipewire/spa/param/format-utils.h
@@ -0,0 +1,49 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_PARAM_FORMAT_UTILS_H
+#define SPA_PARAM_FORMAT_UTILS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include <spa/pod/parser.h>
+#include <spa/param/format.h>
+
+static inline int
+spa_format_parse(const struct spa_pod *format, uint32_t *media_type, uint32_t *media_subtype)
+{
+ return spa_pod_parse_object(format,
+ SPA_TYPE_OBJECT_Format, NULL,
+ SPA_FORMAT_mediaType, SPA_POD_Id(media_type),
+ SPA_FORMAT_mediaSubtype, SPA_POD_Id(media_subtype));
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_PARAM_FORMAT_UTILS_H */
diff --git a/3rdparty/pipewire/spa/param/format.h b/3rdparty/pipewire/spa/param/format.h
new file mode 100644
index 000000000..1550cc1a0
--- /dev/null
+++ b/3rdparty/pipewire/spa/param/format.h
@@ -0,0 +1,147 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_PARAM_FORMAT_H
+#define SPA_PARAM_FORMAT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/param/param.h>
+
+/** media type for SPA_TYPE_OBJECT_Format */
+enum spa_media_type {
+ SPA_MEDIA_TYPE_unknown,
+ SPA_MEDIA_TYPE_audio,
+ SPA_MEDIA_TYPE_video,
+ SPA_MEDIA_TYPE_image,
+ SPA_MEDIA_TYPE_binary,
+ SPA_MEDIA_TYPE_stream,
+ SPA_MEDIA_TYPE_application,
+};
+
+/** media subtype for SPA_TYPE_OBJECT_Format */
+enum spa_media_subtype {
+ SPA_MEDIA_SUBTYPE_unknown,
+ SPA_MEDIA_SUBTYPE_raw,
+ SPA_MEDIA_SUBTYPE_dsp,
+
+ SPA_MEDIA_SUBTYPE_START_Audio = 0x10000,
+ SPA_MEDIA_SUBTYPE_mp3,
+ SPA_MEDIA_SUBTYPE_aac,
+ SPA_MEDIA_SUBTYPE_vorbis,
+ SPA_MEDIA_SUBTYPE_wma,
+ SPA_MEDIA_SUBTYPE_ra,
+ SPA_MEDIA_SUBTYPE_sbc,
+ SPA_MEDIA_SUBTYPE_adpcm,
+ SPA_MEDIA_SUBTYPE_g723,
+ SPA_MEDIA_SUBTYPE_g726,
+ SPA_MEDIA_SUBTYPE_g729,
+ SPA_MEDIA_SUBTYPE_amr,
+ SPA_MEDIA_SUBTYPE_gsm,
+
+ SPA_MEDIA_SUBTYPE_START_Video = 0x20000,
+ SPA_MEDIA_SUBTYPE_h264,
+ SPA_MEDIA_SUBTYPE_mjpg,
+ SPA_MEDIA_SUBTYPE_dv,
+ SPA_MEDIA_SUBTYPE_mpegts,
+ SPA_MEDIA_SUBTYPE_h263,
+ SPA_MEDIA_SUBTYPE_mpeg1,
+ SPA_MEDIA_SUBTYPE_mpeg2,
+ SPA_MEDIA_SUBTYPE_mpeg4,
+ SPA_MEDIA_SUBTYPE_xvid,
+ SPA_MEDIA_SUBTYPE_vc1,
+ SPA_MEDIA_SUBTYPE_vp8,
+ SPA_MEDIA_SUBTYPE_vp9,
+ SPA_MEDIA_SUBTYPE_bayer,
+
+ SPA_MEDIA_SUBTYPE_START_Image = 0x30000,
+ SPA_MEDIA_SUBTYPE_jpeg,
+
+ SPA_MEDIA_SUBTYPE_START_Binary = 0x40000,
+
+ SPA_MEDIA_SUBTYPE_START_Stream = 0x50000,
+ SPA_MEDIA_SUBTYPE_midi,
+
+ SPA_MEDIA_SUBTYPE_START_Application = 0x60000,
+ SPA_MEDIA_SUBTYPE_control, /**< control stream, data contains
+ * spa_pod_sequence with control info. */
+};
+
+/** properties for audio SPA_TYPE_OBJECT_Format */
+enum spa_format {
+ SPA_FORMAT_START,
+
+ SPA_FORMAT_mediaType, /**< media type (Id enum spa_media_type) */
+ SPA_FORMAT_mediaSubtype, /**< media subtype (Id enum spa_media_subtype) */
+
+ /* Audio format keys */
+ SPA_FORMAT_START_Audio = 0x10000,
+ SPA_FORMAT_AUDIO_format, /**< audio format, (Id enum spa_audio_format) */
+ SPA_FORMAT_AUDIO_flags, /**< optional flags (Int) */
+ SPA_FORMAT_AUDIO_rate, /**< sample rate (Int) */
+ SPA_FORMAT_AUDIO_channels, /**< number of audio channels (Int) */
+ SPA_FORMAT_AUDIO_position, /**< channel positions (Id enum spa_audio_position) */
+
+ /* Video Format keys */
+ SPA_FORMAT_START_Video = 0x20000,
+ SPA_FORMAT_VIDEO_format, /**< video format (Id enum spa_video_format) */
+ SPA_FORMAT_VIDEO_modifier, /**< format modifier (Long) */
+ SPA_FORMAT_VIDEO_size, /**< size (Rectangle) */
+ SPA_FORMAT_VIDEO_framerate, /**< frame rate (Fraction) */
+ SPA_FORMAT_VIDEO_maxFramerate, /**< maximum frame rate (Fraction) */
+ SPA_FORMAT_VIDEO_views, /**< number of views (Int) */
+ SPA_FORMAT_VIDEO_interlaceMode, /**< (Id enum spa_video_interlace_mode) */
+ SPA_FORMAT_VIDEO_pixelAspectRatio, /**< (Rectangle) */
+ SPA_FORMAT_VIDEO_multiviewMode, /**< (Id enum spa_video_multiview_mode) */
+ SPA_FORMAT_VIDEO_multiviewFlags, /**< (Id enum spa_video_multiview_flags) */
+ SPA_FORMAT_VIDEO_chromaSite, /**< /Id enum spa_video_chroma_site) */
+ SPA_FORMAT_VIDEO_colorRange, /**< /Id enum spa_video_color_range) */
+ SPA_FORMAT_VIDEO_colorMatrix, /**< /Id enum spa_video_color_matrix) */
+ SPA_FORMAT_VIDEO_transferFunction, /**< /Id enum spa_video_transfer_function) */
+ SPA_FORMAT_VIDEO_colorPrimaries, /**< /Id enum spa_video_color_primaries) */
+ SPA_FORMAT_VIDEO_profile, /**< (Int) */
+ SPA_FORMAT_VIDEO_level, /**< (Int) */
+ SPA_FORMAT_VIDEO_H264_streamFormat, /**< (Id enum spa_h264_stream_format) */
+ SPA_FORMAT_VIDEO_H264_alignment, /**< (Id enum spa_h264_alignment) */
+
+ /* Image Format keys */
+ SPA_FORMAT_START_Image = 0x30000,
+ /* Binary Format keys */
+ SPA_FORMAT_START_Binary = 0x40000,
+ /* Stream Format keys */
+ SPA_FORMAT_START_Stream = 0x50000,
+ /* Application Format keys */
+ SPA_FORMAT_START_Application = 0x60000,
+};
+
+#define SPA_KEY_FORMAT_DSP "format.dsp" /**< a predefined DSP format,
+ * Ex. "32 bit float mono audio" */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_PARAM_FORMAT_H */
diff --git a/3rdparty/pipewire/spa/param/param.h b/3rdparty/pipewire/spa/param/param.h
new file mode 100644
index 000000000..79093224d
--- /dev/null
+++ b/3rdparty/pipewire/spa/param/param.h
@@ -0,0 +1,171 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_PARAM_H
+#define SPA_PARAM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/defs.h>
+
+/** different parameter types that can be queried */
+enum spa_param_type {
+ SPA_PARAM_Invalid, /**< invalid */
+ SPA_PARAM_PropInfo, /**< property information as SPA_TYPE_OBJECT_PropInfo */
+ SPA_PARAM_Props, /**< properties as SPA_TYPE_OBJECT_Props */
+ SPA_PARAM_EnumFormat, /**< available formats as SPA_TYPE_OBJECT_Format */
+ SPA_PARAM_Format, /**< configured format as SPA_TYPE_OBJECT_Format */
+ SPA_PARAM_Buffers, /**< buffer configurations as SPA_TYPE_OBJECT_ParamBuffers*/
+ SPA_PARAM_Meta, /**< allowed metadata for buffers as SPA_TYPE_OBJECT_ParamMeta*/
+ SPA_PARAM_IO, /**< configurable IO areas as SPA_TYPE_OBJECT_ParamIO */
+ SPA_PARAM_EnumProfile, /**< profile enumeration as SPA_TYPE_OBJECT_ParamProfile */
+ SPA_PARAM_Profile, /**< profile configuration as SPA_TYPE_OBJECT_ParamProfile */
+ SPA_PARAM_EnumPortConfig, /**< port configuration enumeration as SPA_TYPE_OBJECT_ParamPortConfig */
+ SPA_PARAM_PortConfig, /**< port configuration as SPA_TYPE_OBJECT_ParamPortConfig */
+ SPA_PARAM_EnumRoute, /**< routing enumeration as SPA_TYPE_OBJECT_ParamRoute */
+ SPA_PARAM_Route, /**< routing configuration as SPA_TYPE_OBJECT_ParamRoute */
+ SPA_PARAM_Control, /**< Control parameter, a SPA_TYPE_Sequence */
+};
+
+/** information about a parameter */
+struct spa_param_info {
+ uint32_t id; /**< enum spa_param_type */
+#define SPA_PARAM_INFO_SERIAL (1<<0) /**< bit to signal update even when the
+ * read/write flags don't change */
+#define SPA_PARAM_INFO_READ (1<<1)
+#define SPA_PARAM_INFO_WRITE (1<<2)
+#define SPA_PARAM_INFO_READWRITE (SPA_PARAM_INFO_WRITE|SPA_PARAM_INFO_READ)
+ uint32_t flags;
+ uint32_t user; /**< private user field. You can use this to keep
+ * state. */
+ uint32_t padding[5];
+};
+
+#define SPA_PARAM_INFO(id,flags) (struct spa_param_info){ (id), (flags) }
+
+/** properties for SPA_TYPE_OBJECT_ParamBuffers */
+enum spa_param_buffers {
+ SPA_PARAM_BUFFERS_START,
+ SPA_PARAM_BUFFERS_buffers, /**< number of buffers (Int) */
+ SPA_PARAM_BUFFERS_blocks, /**< number of data blocks per buffer (Int) */
+ 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) */
+};
+
+/** 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) */
+};
+
+/** properties for SPA_TYPE_OBJECT_ParamIO */
+enum spa_param_io {
+ SPA_PARAM_IO_START,
+ SPA_PARAM_IO_id, /**< type ID, uniquely identifies the io area (Id enum spa_io_type) */
+ SPA_PARAM_IO_size, /**< size of the io area (Int) */
+};
+
+enum spa_param_availability {
+ SPA_PARAM_AVAILABILITY_unknown, /**< unknown availability */
+ SPA_PARAM_AVAILABILITY_no, /**< not available */
+ SPA_PARAM_AVAILABILITY_yes, /**< available */
+};
+
+/** properties for SPA_TYPE_OBJECT_ParamProfile */
+enum spa_param_profile {
+ SPA_PARAM_PROFILE_START,
+ SPA_PARAM_PROFILE_index, /**< profile index (Int) */
+ SPA_PARAM_PROFILE_name, /**< profile name (String) */
+ SPA_PARAM_PROFILE_description, /**< profile description (String) */
+ SPA_PARAM_PROFILE_priority, /**< profile priority (Int) */
+ SPA_PARAM_PROFILE_available, /**< availability of the profile
+ * (Id enum spa_param_availability) */
+ SPA_PARAM_PROFILE_info, /**< info (Struct(
+ * Int : n_items,
+ * (String : key,
+ * String : value)*)) */
+ SPA_PARAM_PROFILE_classes, /**< node classes provided by this profile
+ * (Struct(
+ * Int : number of items following
+ * Struct(
+ * String : class name (eg. "Audio/Source"),
+ * Int : number of nodes
+ * String : property (eg. "card.profile.devices"),
+ * Array of Int: device indexes
+ * )*)) */
+ SPA_PARAM_PROFILE_save, /**< If profile should be saved (Bool) */
+};
+
+enum spa_param_port_config_mode {
+ SPA_PARAM_PORT_CONFIG_MODE_none, /**< no configuration */
+ SPA_PARAM_PORT_CONFIG_MODE_passthrough, /**< passthrough configuration */
+ SPA_PARAM_PORT_CONFIG_MODE_convert, /**< convert configuration */
+ SPA_PARAM_PORT_CONFIG_MODE_dsp, /**< dsp configuration, depending on the external
+ * format. For audio, ports will be configured for
+ * the given number of channels with F32 format. */
+};
+
+/** properties for SPA_TYPE_OBJECT_ParamPortConfig */
+enum spa_param_port_config {
+ SPA_PARAM_PORT_CONFIG_START,
+ SPA_PARAM_PORT_CONFIG_direction, /**< direction, input/output (Id enum spa_direction) */
+ SPA_PARAM_PORT_CONFIG_mode, /**< (Id enum spa_param_port_config_mode) mode */
+ SPA_PARAM_PORT_CONFIG_monitor, /**< (Bool) enable monitor output ports on input ports */
+ SPA_PARAM_PORT_CONFIG_control, /**< (Bool) enable control ports */
+ SPA_PARAM_PORT_CONFIG_format, /**< (Object) format filter */
+};
+
+/** properties for SPA_TYPE_OBJECT_ParamRoute */
+enum spa_param_route {
+ SPA_PARAM_ROUTE_START,
+ SPA_PARAM_ROUTE_index, /**< index of the routing destination (Int) */
+ SPA_PARAM_ROUTE_direction, /**< direction, input/output (Id enum spa_direction) */
+ SPA_PARAM_ROUTE_device, /**< device id (Int) */
+ SPA_PARAM_ROUTE_name, /**< name of the routing destination (String) */
+ SPA_PARAM_ROUTE_description, /**< description of the destination (String) */
+ SPA_PARAM_ROUTE_priority, /**< priority of the destination (Int) */
+ SPA_PARAM_ROUTE_available, /**< availability of the destination
+ * (Id enum spa_param_availability) */
+ SPA_PARAM_ROUTE_info, /**< info (Struct(
+ * Int : n_items,
+ * (String : key,
+ * String : value)*)) */
+ SPA_PARAM_ROUTE_profiles, /**< associated profile indexes (Array of Int) */
+ SPA_PARAM_ROUTE_props, /**< properties SPA_TYPE_OBJECT_Props */
+ SPA_PARAM_ROUTE_devices, /**< associated device indexes (Array of Int) */
+ SPA_PARAM_ROUTE_profile, /**< profile id (Int) */
+ SPA_PARAM_ROUTE_save, /**< If route should be saved (Bool) */
+};
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_PARAM_H */
diff --git a/3rdparty/pipewire/spa/pod/builder.h b/3rdparty/pipewire/spa/pod/builder.h
new file mode 100644
index 000000000..807eddab3
--- /dev/null
+++ b/3rdparty/pipewire/spa/pod/builder.h
@@ -0,0 +1,683 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_POD_BUILDER_H
+#define SPA_POD_BUILDER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+
+#include <spa/utils/hook.h>
+#include <spa/pod/iter.h>
+#include <spa/pod/vararg.h>
+
+struct spa_pod_builder_state {
+ uint32_t offset;
+#define SPA_POD_BUILDER_FLAG_BODY (1<<0)
+#define SPA_POD_BUILDER_FLAG_FIRST (1<<1)
+ uint32_t flags;
+ struct spa_pod_frame *frame;
+};
+
+struct spa_pod_builder;
+
+struct spa_pod_builder_callbacks {
+#define SPA_VERSION_POD_BUILDER_CALLBACKS 0
+ uint32_t version;
+
+ int (*overflow) (void *data, uint32_t size);
+};
+
+struct spa_pod_builder {
+ void *data;
+ uint32_t size;
+ uint32_t _padding;
+ struct spa_pod_builder_state state;
+ struct spa_callbacks callbacks;
+};
+
+#define SPA_POD_BUILDER_INIT(buffer,size) (struct spa_pod_builder){ buffer, size, 0, {}, {} }
+
+static inline void
+spa_pod_builder_get_state(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
+{
+ *state = builder->state;
+}
+
+static inline 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_pod_builder_reset(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
+{
+ struct spa_pod_frame *f;
+ uint32_t size = builder->state.offset - state->offset;
+ builder->state = *state;
+ for (f = builder->state.frame; f ; f = f->parent)
+ f->pod.size -= size;
+}
+
+static inline 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_pod_builder_deref(struct spa_pod_builder *builder, uint32_t offset)
+{
+ uint32_t size = builder->size;
+ if (offset + 8 <= size) {
+ struct spa_pod *pod = SPA_PTROFF(builder->data, offset, struct spa_pod);
+ if (offset + SPA_POD_SIZE(pod) <= size)
+ return pod;
+ }
+ return NULL;
+}
+
+static inline 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)
+ return SPA_PTROFF(builder->data, frame->offset, struct spa_pod);
+ return NULL;
+}
+
+static inline void
+spa_pod_builder_push(struct spa_pod_builder *builder,
+ struct spa_pod_frame *frame,
+ const struct spa_pod *pod,
+ uint32_t offset)
+{
+ frame->pod = *pod;
+ frame->offset = offset;
+ frame->parent = builder->state.frame;
+ frame->flags = builder->state.flags;
+ builder->state.frame = frame;
+
+ if (frame->pod.type == SPA_TYPE_Array || frame->pod.type == SPA_TYPE_Choice)
+ 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)
+{
+ int res = 0;
+ struct spa_pod_frame *f;
+ uint32_t offset = builder->state.offset;
+
+ if (offset + size > builder->size) {
+ res = -ENOSPC;
+ spa_callbacks_call_res(&builder->callbacks, struct spa_pod_builder_callbacks, res,
+ overflow, 0, offset + size);
+ }
+ if (res == 0 && data)
+ memcpy(SPA_PTROFF(builder->data, offset, void), data, size);
+
+ builder->state.offset += size;
+
+ for (f = builder->state.frame; f ; f = f->parent)
+ f->pod.size += size;
+
+ return res;
+}
+
+static inline 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_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);
+ if ((r = spa_pod_builder_pad(builder, size)) < 0)
+ res = r;
+ return res;
+}
+
+static inline void *spa_pod_builder_pop(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
+{
+ struct spa_pod *pod;
+
+ if (SPA_FLAG_IS_SET(builder->state.flags, SPA_POD_BUILDER_FLAG_FIRST)) {
+ const struct spa_pod p = { 0, SPA_TYPE_None };
+ spa_pod_builder_raw(builder, &p, sizeof(p));
+ }
+ if ((pod = (struct spa_pod*)spa_pod_builder_frame(builder, frame)) != NULL)
+ *pod = frame->pod;
+
+ builder->state.frame = frame->parent;
+ builder->state.flags = frame->flags;
+ spa_pod_builder_pad(builder, builder->state.offset);
+ return pod;
+}
+
+static inline int
+spa_pod_builder_primitive(struct spa_pod_builder *builder, const struct spa_pod *p)
+{
+ const void *data;
+ uint32_t size;
+ int r, res;
+
+ if (builder->state.flags == SPA_POD_BUILDER_FLAG_BODY) {
+ data = SPA_POD_BODY_CONST(p);
+ size = SPA_POD_BODY_SIZE(p);
+ } else {
+ data = p;
+ size = SPA_POD_SIZE(p);
+ SPA_FLAG_CLEAR(builder->state.flags, SPA_POD_BUILDER_FLAG_FIRST);
+ }
+ res = spa_pod_builder_raw(builder, data, size);
+ if (builder->state.flags != SPA_POD_BUILDER_FLAG_BODY)
+ if ((r = spa_pod_builder_pad(builder, size)) < 0)
+ res = r;
+ return res;
+}
+
+#define SPA_POD_INIT(size,type) (struct spa_pod) { size, type }
+
+#define SPA_POD_INIT_None() SPA_POD_INIT(0, SPA_TYPE_None)
+
+static inline 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)
+{
+ const struct spa_pod p = SPA_POD_INIT(size,type);
+ SPA_FLAG_CLEAR(builder->state.flags, SPA_POD_BUILDER_FLAG_FIRST);
+ return spa_pod_builder_raw(builder, &p, sizeof(p));
+}
+
+#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)
+{
+ const struct spa_pod_bool p = SPA_POD_INIT_Bool(val);
+ return spa_pod_builder_primitive(builder, &p.pod);
+}
+
+#define SPA_POD_INIT_Id(val) (struct spa_pod_id){ { sizeof(uint32_t), SPA_TYPE_Id }, (uint32_t)val, 0 }
+
+static inline 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);
+}
+
+#define SPA_POD_INIT_Int(val) (struct spa_pod_int){ { sizeof(int32_t), SPA_TYPE_Int }, (int32_t)val, 0 }
+
+static inline 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);
+}
+
+#define SPA_POD_INIT_Long(val) (struct spa_pod_long){ { sizeof(int64_t), SPA_TYPE_Long }, (int64_t)val }
+
+static inline 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);
+}
+
+#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)
+{
+ const struct spa_pod_float p = SPA_POD_INIT_Float(val);
+ return spa_pod_builder_primitive(builder, &p.pod);
+}
+
+#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)
+{
+ const struct spa_pod_double p = SPA_POD_INIT_Double(val);
+ return spa_pod_builder_primitive(builder, &p.pod);
+}
+
+#define SPA_POD_INIT_String(len) (struct spa_pod_string){ { len, SPA_TYPE_String } }
+
+static inline int
+spa_pod_builder_write_string(struct spa_pod_builder *builder, const char *str, uint32_t len)
+{
+ int r, res;
+ res = spa_pod_builder_raw(builder, str, len);
+ if ((r = spa_pod_builder_raw(builder, "", 1)) < 0)
+ res = r;
+ if ((r = spa_pod_builder_pad(builder, builder->state.offset)) < 0)
+ res = r;
+ return res;
+}
+
+static inline 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);
+ int r, res = spa_pod_builder_raw(builder, &p, sizeof(p));
+ if ((r = spa_pod_builder_write_string(builder, str, len)) < 0)
+ res = r;
+ return res;
+}
+
+static inline 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);
+}
+
+#define SPA_POD_INIT_Bytes(len) (struct spa_pod_bytes){ { len, SPA_TYPE_Bytes } }
+
+static inline 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);
+ int r, res = spa_pod_builder_raw(builder, &p, sizeof(p));
+ if ((r = spa_pod_builder_raw_padded(builder, bytes, len)) < 0)
+ res = r;
+ return res;
+}
+static inline void *
+spa_pod_builder_reserve_bytes(struct spa_pod_builder *builder, uint32_t len)
+{
+ uint32_t offset = builder->state.offset;
+ if (spa_pod_builder_bytes(builder, NULL, len) < 0)
+ return NULL;
+ return SPA_POD_BODY(spa_pod_builder_deref(builder, offset));
+}
+
+#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_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);
+ return spa_pod_builder_primitive(builder, &p.pod);
+}
+
+#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)
+{
+ const struct spa_pod_fd p = SPA_POD_INIT_Fd(fd);
+ return spa_pod_builder_primitive(builder, &p.pod);
+}
+
+#define SPA_POD_INIT_Rectangle(val) (struct spa_pod_rectangle){ { sizeof(struct spa_rectangle), SPA_TYPE_Rectangle }, val }
+
+static inline 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));
+ return spa_pod_builder_primitive(builder, &p.pod);
+}
+
+#define SPA_POD_INIT_Fraction(val) (struct spa_pod_fraction){ { sizeof(struct spa_fraction), SPA_TYPE_Fraction }, val }
+
+static inline 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_pod_builder_push_array(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
+{
+ const struct spa_pod_array p =
+ { {sizeof(struct spa_pod_array_body) - sizeof(struct spa_pod), SPA_TYPE_Array},
+ {{0, 0}} };
+ uint32_t offset = builder->state.offset;
+ int res = spa_pod_builder_raw(builder, &p, sizeof(p) - sizeof(struct spa_pod));
+ spa_pod_builder_push(builder, frame, &p.pod, offset);
+ return res;
+}
+
+static inline 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)
+{
+ const struct spa_pod_array p = {
+ {(uint32_t)(sizeof(struct spa_pod_array_body) + n_elems * child_size), SPA_TYPE_Array},
+ {{child_size, child_type}}
+ };
+ int r, res = spa_pod_builder_raw(builder, &p, sizeof(p));
+ if ((r = spa_pod_builder_raw_padded(builder, elems, child_size * n_elems)) < 0)
+ res = r;
+ return res;
+}
+
+#define SPA_POD_INIT_CHOICE_BODY(type, flags, child_size, child_type) \
+ (struct spa_pod_choice_body) { type, flags, { child_size, child_type }}
+
+#define SPA_POD_INIT_Choice(type, ctype, child_type, n_vals, ...) \
+ (struct { struct spa_pod_choice choice; ctype vals[n_vals];}) \
+ { { { 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_pod_builder_push_choice(struct spa_pod_builder *builder, struct spa_pod_frame *frame,
+ uint32_t type, uint32_t flags)
+{
+ const struct spa_pod_choice p =
+ { {sizeof(struct spa_pod_choice_body) - sizeof(struct spa_pod), SPA_TYPE_Choice},
+ { type, flags, {0, 0}} };
+ uint32_t offset = builder->state.offset;
+ int res = spa_pod_builder_raw(builder, &p, sizeof(p) - sizeof(struct spa_pod));
+ spa_pod_builder_push(builder, frame, &p.pod, offset);
+ return res;
+}
+
+#define SPA_POD_INIT_Struct(size) (struct spa_pod_struct){ { size, SPA_TYPE_Struct } }
+
+static inline 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);
+ uint32_t offset = builder->state.offset;
+ int res = spa_pod_builder_raw(builder, &p, sizeof(p));
+ spa_pod_builder_push(builder, frame, &p.pod, offset);
+ return res;
+}
+
+#define SPA_POD_INIT_Object(size,type,id,...) (struct spa_pod_object){ { size, SPA_TYPE_Object }, { type, id }, ##__VA_ARGS__ }
+
+static inline int
+spa_pod_builder_push_object(struct spa_pod_builder *builder, struct spa_pod_frame *frame,
+ uint32_t type, uint32_t id)
+{
+ const struct spa_pod_object p =
+ SPA_POD_INIT_Object(sizeof(struct spa_pod_object_body), type, id);
+ uint32_t offset = builder->state.offset;
+ int res = spa_pod_builder_raw(builder, &p, sizeof(p));
+ spa_pod_builder_push(builder, frame, &p.pod, offset);
+ return res;
+}
+
+#define SPA_POD_INIT_Prop(key,flags,size,type) \
+ (struct spa_pod_prop){ key, flags, { size, type } }
+
+static inline 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 };
+ return spa_pod_builder_raw(builder, &p, sizeof(p));
+}
+
+#define SPA_POD_INIT_Sequence(size,unit) \
+ (struct spa_pod_sequence){ { size, SPA_TYPE_Sequence}, {unit, 0 } }
+
+static inline 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 =
+ SPA_POD_INIT_Sequence(sizeof(struct spa_pod_sequence_body), unit);
+ uint32_t offset = builder->state.offset;
+ int res = spa_pod_builder_raw(builder, &p, sizeof(p));
+ spa_pod_builder_push(builder, frame, &p.pod, offset);
+ return res;
+}
+
+static inline uint32_t
+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)
+{
+ switch (id) {
+ case 'r':
+ return SPA_CHOICE_Range;
+ case 's':
+ return SPA_CHOICE_Step;
+ case 'e':
+ return SPA_CHOICE_Enum;
+ case 'f':
+ return SPA_CHOICE_Flags;
+ case 'n':
+ default:
+ return SPA_CHOICE_None;
+ }
+}
+
+#define SPA_POD_BUILDER_COLLECT(builder,type,args) \
+do { \
+ switch (type) { \
+ case 'b': \
+ spa_pod_builder_bool(builder, !!va_arg(args, int)); \
+ break; \
+ case 'I': \
+ spa_pod_builder_id(builder, va_arg(args, uint32_t)); \
+ break; \
+ case 'i': \
+ spa_pod_builder_int(builder, va_arg(args, int)); \
+ break; \
+ case 'l': \
+ spa_pod_builder_long(builder, va_arg(args, int64_t)); \
+ break; \
+ case 'f': \
+ spa_pod_builder_float(builder, va_arg(args, double)); \
+ break; \
+ case 'd': \
+ spa_pod_builder_double(builder, va_arg(args, double)); \
+ break; \
+ case 's': \
+ { \
+ char *strval = va_arg(args, char *); \
+ if (strval != NULL) { \
+ size_t len = strlen(strval); \
+ spa_pod_builder_string_len(builder, strval, len); \
+ } \
+ else \
+ spa_pod_builder_none(builder); \
+ break; \
+ } \
+ case 'S': \
+ { \
+ char *strval = va_arg(args, char *); \
+ size_t len = va_arg(args, int); \
+ spa_pod_builder_string_len(builder, strval, len); \
+ break; \
+ } \
+ case 'y': \
+ { \
+ void *ptr = va_arg(args, void *); \
+ int len = va_arg(args, int); \
+ spa_pod_builder_bytes(builder, ptr, len); \
+ break; \
+ } \
+ case 'R': \
+ { \
+ struct spa_rectangle *rectval = \
+ va_arg(args, struct spa_rectangle *); \
+ spa_pod_builder_rectangle(builder, \
+ rectval->width, rectval->height); \
+ break; \
+ } \
+ case 'F': \
+ { \
+ struct spa_fraction *fracval = \
+ va_arg(args, struct spa_fraction *); \
+ spa_pod_builder_fraction(builder, fracval->num, fracval->denom);\
+ break; \
+ } \
+ case 'a': \
+ { \
+ int child_size = va_arg(args, int); \
+ int child_type = va_arg(args, int); \
+ int n_elems = va_arg(args, int); \
+ void *elems = va_arg(args, void *); \
+ spa_pod_builder_array(builder, child_size, \
+ child_type, n_elems, elems); \
+ break; \
+ } \
+ case 'p': \
+ { \
+ int t = va_arg(args, uint32_t); \
+ spa_pod_builder_pointer(builder, t, va_arg(args, void *)); \
+ break; \
+ } \
+ case 'h': \
+ spa_pod_builder_fd(builder, va_arg(args, int)); \
+ break; \
+ case 'P': \
+ case 'O': \
+ case 'T': \
+ case 'V': \
+ { \
+ struct spa_pod *pod = va_arg(args, struct spa_pod *); \
+ if (pod == NULL) \
+ spa_pod_builder_none(builder); \
+ else \
+ spa_pod_builder_primitive(builder, pod); \
+ break; \
+ } \
+ } \
+} while(false)
+
+static inline int
+spa_pod_builder_addv(struct spa_pod_builder *builder, va_list args)
+{
+ int res = 0;
+ struct spa_pod_frame *frame = builder->state.frame;
+ uint32_t ftype = frame ? frame->pod.type : (uint32_t)SPA_TYPE_None;
+
+ do {
+ const char *format;
+ int n_values = 1;
+ struct spa_pod_frame f;
+ bool choice;
+
+ switch (ftype) {
+ case SPA_TYPE_Object:
+ {
+ uint32_t key = va_arg(args, uint32_t);
+ if (key == 0)
+ goto exit;
+ spa_pod_builder_prop(builder, key, 0);
+ break;
+ }
+ case SPA_TYPE_Sequence:
+ {
+ uint32_t offset = va_arg(args, uint32_t);
+ uint32_t type = va_arg(args, uint32_t);
+ if (type == 0)
+ goto exit;
+ spa_pod_builder_control(builder, offset, type);
+ SPA_FALLTHROUGH
+ }
+ default:
+ break;
+ }
+ if ((format = va_arg(args, const char *)) == NULL)
+ break;
+
+ choice = *format == '?';
+ if (choice) {
+ uint32_t type = spa_choice_from_id(*++format);
+ if (*format != '\0')
+ format++;
+
+ spa_pod_builder_push_choice(builder, &f, type, 0);
+
+ n_values = va_arg(args, int);
+ }
+ while (n_values-- > 0)
+ SPA_POD_BUILDER_COLLECT(builder, *format, args);
+
+ if (choice)
+ spa_pod_builder_pop(builder, &f);
+ } while (true);
+
+ exit:
+ return res;
+}
+
+static inline int spa_pod_builder_add(struct spa_pod_builder *builder, ...)
+{
+ int res;
+ va_list args;
+
+ va_start(args, builder);
+ res = spa_pod_builder_addv(builder, args);
+ va_end(args);
+
+ return res;
+}
+
+#define spa_pod_builder_add_object(b,type,id,...) \
+({ \
+ struct spa_pod_frame _f; \
+ spa_pod_builder_push_object(b, &_f, type, id); \
+ spa_pod_builder_add(b, ##__VA_ARGS__, 0); \
+ spa_pod_builder_pop(b, &_f); \
+})
+
+#define spa_pod_builder_add_struct(b,...) \
+({ \
+ struct spa_pod_frame _f; \
+ spa_pod_builder_push_struct(b, &_f); \
+ spa_pod_builder_add(b, ##__VA_ARGS__, NULL); \
+ spa_pod_builder_pop(b, &_f); \
+})
+
+#define spa_pod_builder_add_sequence(b,unit,...) \
+({ \
+ struct spa_pod_frame _f; \
+ spa_pod_builder_push_sequence(b, &_f, unit); \
+ spa_pod_builder_add(b, ##__VA_ARGS__, 0, 0); \
+ spa_pod_builder_pop(b, &_f); \
+})
+
+/** Copy a pod structure */
+static inline struct spa_pod *
+spa_pod_copy(const struct spa_pod *pod)
+{
+ size_t size;
+ struct spa_pod *c;
+
+ size = SPA_POD_SIZE(pod);
+ if ((c = (struct spa_pod *) malloc(size)) == NULL)
+ return NULL;
+ return (struct spa_pod *) memcpy(c, pod, size);
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_POD_BUILDER_H */
diff --git a/3rdparty/pipewire/spa/pod/iter.h b/3rdparty/pipewire/spa/pod/iter.h
new file mode 100644
index 000000000..4334522c7
--- /dev/null
+++ b/3rdparty/pipewire/spa/pod/iter.h
@@ -0,0 +1,447 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_POD_ITER_H
+#define SPA_POD_ITER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <errno.h>
+#include <sys/types.h>
+
+#include <spa/pod/pod.h>
+
+struct spa_pod_frame {
+ struct spa_pod pod;
+ struct spa_pod_frame *parent;
+ uint32_t offset;
+ uint32_t flags;
+};
+
+static inline 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);
+}
+
+static inline 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)
+{
+ 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,
+ 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);
+}
+
+static inline 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)
+{
+ 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,
+ 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);
+}
+
+static inline 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); \
+ (iter) = (__typeof__(iter))SPA_PTROFF((iter), (body)->child.size, void))
+
+#define SPA_POD_ARRAY_FOREACH(obj, iter) \
+ SPA_POD_ARRAY_BODY_FOREACH(&(obj)->body, SPA_POD_BODY_SIZE(obj), iter)
+
+#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); \
+ (iter) = (__typeof__(iter))SPA_PTROFF((iter), (body)->child.size, void))
+
+#define SPA_POD_CHOICE_FOREACH(obj, iter) \
+ SPA_POD_CHOICE_BODY_FOREACH(&(obj)->body, SPA_POD_BODY_SIZE(obj), iter)
+
+#define SPA_POD_FOREACH(pod, size, iter) \
+ for ((iter) = (pod); \
+ spa_pod_is_inside(pod, size, iter); \
+ (iter) = (__typeof__(iter))spa_pod_next(iter))
+
+#define SPA_POD_STRUCT_FOREACH(obj, iter) \
+ SPA_POD_FOREACH(SPA_POD_BODY(obj), SPA_POD_BODY_SIZE(obj), iter)
+
+#define SPA_POD_OBJECT_BODY_FOREACH(body, size, iter) \
+ for ((iter) = spa_pod_prop_first(body); \
+ spa_pod_prop_is_inside(body, size, iter); \
+ (iter) = spa_pod_prop_next(iter))
+
+#define SPA_POD_OBJECT_FOREACH(obj, iter) \
+ SPA_POD_OBJECT_BODY_FOREACH(&(obj)->body, SPA_POD_BODY_SIZE(obj), iter)
+
+#define SPA_POD_SEQUENCE_BODY_FOREACH(body, size, iter) \
+ for ((iter) = spa_pod_control_first(body); \
+ spa_pod_control_is_inside(body, size, iter); \
+ (iter) = spa_pod_control_next(iter))
+
+#define SPA_POD_SEQUENCE_FOREACH(seq, iter) \
+ 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)
+{
+ void *pod;
+ if (size < sizeof(struct spa_pod) || offset + size > maxsize)
+ return NULL;
+ pod = SPA_PTROFF(data, offset, void);
+ if (SPA_POD_SIZE(pod) > size)
+ return NULL;
+ return pod;
+}
+
+static inline 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)
+{
+ 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)
+{
+ if (!spa_pod_is_bool(pod))
+ return -EINVAL;
+ *value = !!SPA_POD_VALUE(struct spa_pod_bool, pod);
+ return 0;
+}
+
+static inline 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)
+{
+ if (!spa_pod_is_id(pod))
+ return -EINVAL;
+ *value = SPA_POD_VALUE(struct spa_pod_id, pod);
+ return 0;
+}
+
+static inline 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)
+{
+ if (!spa_pod_is_int(pod))
+ return -EINVAL;
+ *value = SPA_POD_VALUE(struct spa_pod_int, pod);
+ return 0;
+}
+
+static inline 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)
+{
+ if (!spa_pod_is_long(pod))
+ return -EINVAL;
+ *value = SPA_POD_VALUE(struct spa_pod_long, pod);
+ return 0;
+}
+
+static inline 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)
+{
+ if (!spa_pod_is_float(pod))
+ return -EINVAL;
+ *value = SPA_POD_VALUE(struct spa_pod_float, pod);
+ return 0;
+}
+
+static inline 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)
+{
+ if (!spa_pod_is_double(pod))
+ return -EINVAL;
+ *value = SPA_POD_VALUE(struct spa_pod_double, pod);
+ return 0;
+}
+
+static inline 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 &&
+ SPA_POD_BODY_SIZE(pod) > 0 &&
+ s[SPA_POD_BODY_SIZE(pod)-1] == '\0');
+}
+
+static inline int spa_pod_get_string(const struct spa_pod *pod, const char **value)
+{
+ if (!spa_pod_is_string(pod))
+ return -EINVAL;
+ *value = (const char *)SPA_POD_CONTENTS(struct spa_pod_string, pod);
+ return 0;
+}
+
+static inline 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)
+ return -EINVAL;
+ strncpy(dest, s, maxlen-1);
+ dest[maxlen-1]= '\0';
+ return 0;
+}
+
+static inline 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)
+{
+ if (!spa_pod_is_bytes(pod))
+ return -EINVAL;
+ *value = (const void *)SPA_POD_CONTENTS(struct spa_pod_bytes, pod);
+ *len = SPA_POD_BODY_SIZE(pod);
+ return 0;
+}
+
+static inline 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)
+{
+ if (!spa_pod_is_pointer(pod))
+ return -EINVAL;
+ *type = ((struct spa_pod_pointer*)pod)->body.type;
+ *value = ((struct spa_pod_pointer*)pod)->body.value;
+ return 0;
+}
+
+static inline 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)
+{
+ if (!spa_pod_is_fd(pod))
+ return -EINVAL;
+ *value = SPA_POD_VALUE(struct spa_pod_fd, pod);
+ return 0;
+}
+
+static inline 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)
+{
+ if (!spa_pod_is_rectangle(pod))
+ return -EINVAL;
+ *value = SPA_POD_VALUE(struct spa_pod_rectangle, pod);
+ return 0;
+}
+
+static inline 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_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)
+{
+ 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)
+{
+ 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_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,
+ void *values, uint32_t max_values)
+{
+ uint32_t n_values;
+ void *v = spa_pod_get_array(pod, &n_values);
+ if (v == NULL || max_values == 0 || SPA_POD_ARRAY_VALUE_TYPE(pod) != type)
+ return 0;
+ n_values = SPA_MIN(n_values, max_values);
+ memcpy(values, v, SPA_POD_ARRAY_VALUE_SIZE(pod) * n_values);
+ return n_values;
+}
+
+static inline 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)
+{
+ if (pod->type == SPA_TYPE_Choice) {
+ *n_vals = SPA_POD_CHOICE_N_VALUES(pod);
+ if ((*choice = SPA_POD_CHOICE_TYPE(pod)) == SPA_CHOICE_None)
+ *n_vals = SPA_MIN(1u, SPA_POD_CHOICE_N_VALUES(pod));
+ return (struct spa_pod*)SPA_POD_CHOICE_CHILD(pod);
+ } else {
+ *n_vals = 1;
+ *choice = SPA_CHOICE_None;
+ return (struct spa_pod*)pod;
+ }
+}
+
+static inline 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)
+{
+ 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)
+{
+ 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)
+{
+ 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)
+{
+ 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,
+ const struct spa_pod_prop *start, uint32_t key)
+{
+ const struct spa_pod_prop *first, *res;
+
+ first = spa_pod_prop_first(&pod->body);
+ start = start ? spa_pod_prop_next(start) : first;
+
+ for (res = start; spa_pod_prop_is_inside(&pod->body, pod->pod.size, res);
+ res = spa_pod_prop_next(res)) {
+ if (res->key == key)
+ return res;
+ }
+ for (res = first; res != start; res = spa_pod_prop_next(res)) {
+ if (res->key == key)
+ return res;
+ }
+ return NULL;
+}
+
+static inline 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))
+ return NULL;
+ 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)
+{
+ struct spa_pod_prop *res;
+ SPA_POD_OBJECT_FOREACH(pod, res) {
+ if (res->value.type == SPA_TYPE_Choice)
+ ((struct spa_pod_choice*)&res->value)->body.type = SPA_CHOICE_None;
+ }
+ return 0;
+}
+
+static inline 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);
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_POD_H */
diff --git a/3rdparty/pipewire/spa/pod/parser.h b/3rdparty/pipewire/spa/pod/parser.h
new file mode 100644
index 000000000..dd7ac7018
--- /dev/null
+++ b/3rdparty/pipewire/spa/pod/parser.h
@@ -0,0 +1,573 @@
+/* Spa
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_POD_PARSER_H
+#define SPA_POD_PARSER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <errno.h>
+#include <stdarg.h>
+
+#include <spa/pod/iter.h>
+#include <spa/pod/vararg.h>
+
+struct spa_pod_parser_state {
+ uint32_t offset;
+ uint32_t flags;
+ struct spa_pod_frame *frame;
+};
+
+struct spa_pod_parser {
+ const void *data;
+ uint32_t size;
+ uint32_t _padding;
+ struct spa_pod_parser_state state;
+};
+
+#define SPA_POD_PARSER_INIT(buffer,size) (struct spa_pod_parser){ buffer, size, 0, {} }
+
+static inline 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,
+ const struct spa_pod *pod)
+{
+ spa_pod_parser_init(parser, pod, SPA_POD_SIZE(pod));
+}
+
+static inline void
+spa_pod_parser_get_state(struct spa_pod_parser *parser, struct spa_pod_parser_state *state)
+{
+ *state = parser->state;
+}
+
+static inline 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_pod_parser_deref(struct spa_pod_parser *parser, uint32_t offset, uint32_t size)
+{
+ if (offset + 8 <= size) {
+ struct spa_pod *pod = SPA_PTROFF(parser->data, offset, struct spa_pod);
+ if (offset + SPA_POD_SIZE(pod) <= size)
+ return pod;
+ }
+ return NULL;
+}
+
+static inline 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,
+ struct spa_pod_frame *frame, const struct spa_pod *pod, uint32_t offset)
+{
+ frame->pod = *pod;
+ frame->offset = offset;
+ frame->parent = parser->state.frame;
+ frame->flags = parser->state.flags;
+ parser->state.frame = frame;
+}
+
+static inline 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)
+{
+ 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)
+{
+ struct spa_pod *pod = spa_pod_parser_current(parser);
+ if (pod)
+ spa_pod_parser_advance(parser, pod);
+ return pod;
+}
+
+static inline int spa_pod_parser_pop(struct spa_pod_parser *parser,
+ struct spa_pod_frame *frame)
+{
+ parser->state.frame = frame->parent;
+ parser->state.offset = frame->offset + SPA_ROUND_UP_N(SPA_POD_SIZE(&frame->pod), 8);
+ return 0;
+}
+
+static inline 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);
+ if (pod != NULL && (res = spa_pod_get_bool(pod, value)) >= 0)
+ spa_pod_parser_advance(parser, pod);
+ return res;
+}
+
+static inline 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);
+ if (pod != NULL && (res = spa_pod_get_id(pod, value)) >= 0)
+ spa_pod_parser_advance(parser, pod);
+ return res;
+}
+
+static inline 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);
+ if (pod != NULL && (res = spa_pod_get_int(pod, value)) >= 0)
+ spa_pod_parser_advance(parser, pod);
+ return res;
+}
+
+static inline 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);
+ if (pod != NULL && (res = spa_pod_get_long(pod, value)) >= 0)
+ spa_pod_parser_advance(parser, pod);
+ return res;
+}
+
+static inline 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);
+ if (pod != NULL && (res = spa_pod_get_float(pod, value)) >= 0)
+ spa_pod_parser_advance(parser, pod);
+ return res;
+}
+
+static inline 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);
+ if (pod != NULL && (res = spa_pod_get_double(pod, value)) >= 0)
+ spa_pod_parser_advance(parser, pod);
+ return res;
+}
+
+static inline 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);
+ if (pod != NULL && (res = spa_pod_get_string(pod, value)) >= 0)
+ spa_pod_parser_advance(parser, pod);
+ return res;
+}
+
+static inline 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);
+ if (pod != NULL && (res = spa_pod_get_bytes(pod, value, len)) >= 0)
+ spa_pod_parser_advance(parser, pod);
+ return res;
+}
+
+static inline 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);
+ if (pod != NULL && (res = spa_pod_get_pointer(pod, type, value)) >= 0)
+ spa_pod_parser_advance(parser, pod);
+ return res;
+}
+
+static inline 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);
+ if (pod != NULL && (res = spa_pod_get_fd(pod, value)) >= 0)
+ spa_pod_parser_advance(parser, pod);
+ return res;
+}
+
+static inline 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);
+ if (pod != NULL && (res = spa_pod_get_rectangle(pod, value)) >= 0)
+ spa_pod_parser_advance(parser, pod);
+ return res;
+}
+
+static inline 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);
+ if (pod != NULL && (res = spa_pod_get_fraction(pod, value)) >= 0)
+ spa_pod_parser_advance(parser, pod);
+ return res;
+}
+
+static inline 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)
+ return -EPIPE;
+ *value = pod;
+ spa_pod_parser_advance(parser, pod);
+ return 0;
+}
+static inline 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);
+ if (pod == NULL)
+ return -EPIPE;
+ if (!spa_pod_is_struct(pod))
+ return -EINVAL;
+ spa_pod_parser_push(parser, frame, pod, parser->state.offset);
+ parser->state.offset += sizeof(struct spa_pod_struct);
+ return 0;
+}
+
+static inline 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);
+ if (pod == NULL)
+ return -EPIPE;
+ if (!spa_pod_is_object(pod))
+ return -EINVAL;
+ if (type != SPA_POD_OBJECT_TYPE(pod))
+ return -EPROTO;
+ if (id != NULL)
+ *id = SPA_POD_OBJECT_ID(pod);
+ spa_pod_parser_push(parser, frame, pod, parser->state.offset);
+ parser->state.offset = parser->size;
+ return 0;
+}
+
+static inline bool spa_pod_parser_can_collect(const struct spa_pod *pod, char type)
+{
+ if (pod == NULL)
+ return false;
+
+ if (spa_pod_is_choice(pod) &&
+ SPA_POD_CHOICE_TYPE(pod) == SPA_CHOICE_None &&
+ spa_pod_parser_can_collect(SPA_POD_CHOICE_CHILD(pod), type))
+ return true;
+
+ switch (type) {
+ case 'P':
+ return true;
+ case 'b':
+ return spa_pod_is_bool(pod);
+ case 'I':
+ return spa_pod_is_id(pod);
+ case 'i':
+ return spa_pod_is_int(pod);
+ case 'l':
+ return spa_pod_is_long(pod);
+ case 'f':
+ return spa_pod_is_float(pod);
+ case 'd':
+ return spa_pod_is_double(pod);
+ case 's':
+ return spa_pod_is_string(pod) || spa_pod_is_none(pod);
+ case 'S':
+ return spa_pod_is_string(pod);
+ case 'y':
+ return spa_pod_is_bytes(pod);
+ case 'R':
+ return spa_pod_is_rectangle(pod);
+ case 'F':
+ return spa_pod_is_fraction(pod);
+ case 'B':
+ return spa_pod_is_bitmap(pod);
+ case 'a':
+ return spa_pod_is_array(pod);
+ case 'p':
+ return spa_pod_is_pointer(pod);
+ case 'h':
+ return spa_pod_is_fd(pod);
+ case 'T':
+ return spa_pod_is_struct(pod) || spa_pod_is_none(pod);
+ case 'O':
+ return spa_pod_is_object(pod) || spa_pod_is_none(pod);
+ case 'V':
+ return spa_pod_is_choice(pod);
+ default:
+ return false;
+ }
+}
+
+#define SPA_POD_PARSER_COLLECT(pod,_type,args) \
+do { \
+ switch (_type) { \
+ case 'b': \
+ *va_arg(args, bool*) = SPA_POD_VALUE(struct spa_pod_bool, pod); \
+ break; \
+ case 'I': \
+ case 'i': \
+ *va_arg(args, int32_t*) = SPA_POD_VALUE(struct spa_pod_int, pod); \
+ break; \
+ case 'l': \
+ *va_arg(args, int64_t*) = SPA_POD_VALUE(struct spa_pod_long, pod); \
+ break; \
+ case 'f': \
+ *va_arg(args, float*) = SPA_POD_VALUE(struct spa_pod_float, pod); \
+ break; \
+ case 'd': \
+ *va_arg(args, double*) = SPA_POD_VALUE(struct spa_pod_double, pod); \
+ break; \
+ case 's': \
+ *va_arg(args, char**) = \
+ (pod == NULL || (SPA_POD_TYPE(pod) == SPA_TYPE_None) \
+ ? NULL \
+ : (char *)SPA_POD_CONTENTS(struct spa_pod_string, pod)); \
+ break; \
+ case 'S': \
+ { \
+ char *dest = va_arg(args, char*); \
+ uint32_t maxlen = va_arg(args, uint32_t); \
+ strncpy(dest, (char *)SPA_POD_CONTENTS(struct spa_pod_string, pod), maxlen-1); \
+ break; \
+ } \
+ case 'y': \
+ *(va_arg(args, void **)) = SPA_POD_CONTENTS(struct spa_pod_bytes, pod); \
+ *(va_arg(args, uint32_t *)) = SPA_POD_BODY_SIZE(pod); \
+ break; \
+ case 'R': \
+ *va_arg(args, struct spa_rectangle*) = \
+ SPA_POD_VALUE(struct spa_pod_rectangle, pod); \
+ break; \
+ case 'F': \
+ *va_arg(args, struct spa_fraction*) = \
+ SPA_POD_VALUE(struct spa_pod_fraction, pod); \
+ break; \
+ case 'B': \
+ *va_arg(args, uint32_t **) = \
+ (uint32_t *) SPA_POD_CONTENTS(struct spa_pod_bitmap, pod); \
+ break; \
+ case 'a': \
+ *va_arg(args, uint32_t*) = SPA_POD_ARRAY_VALUE_SIZE(pod); \
+ *va_arg(args, uint32_t*) = SPA_POD_ARRAY_VALUE_TYPE(pod); \
+ *va_arg(args, uint32_t*) = SPA_POD_ARRAY_N_VALUES(pod); \
+ *va_arg(args, void**) = SPA_POD_ARRAY_VALUES(pod); \
+ break; \
+ case 'p': \
+ { \
+ struct spa_pod_pointer_body *b = \
+ (struct spa_pod_pointer_body *) SPA_POD_BODY(pod); \
+ *(va_arg(args, uint32_t *)) = b->type; \
+ *(va_arg(args, const void **)) = b->value; \
+ break; \
+ } \
+ case 'h': \
+ *va_arg(args, int64_t*) = SPA_POD_VALUE(struct spa_pod_fd, pod); \
+ break; \
+ case 'P': \
+ case 'T': \
+ case 'O': \
+ case 'V': \
+ { \
+ const struct spa_pod **d = va_arg(args, const struct spa_pod**); \
+ if (d) \
+ *d = (pod == NULL || (SPA_POD_TYPE(pod) == SPA_TYPE_None) \
+ ? NULL : pod); \
+ break; \
+ } \
+ default: \
+ break; \
+ } \
+} while(false)
+
+#define SPA_POD_PARSER_SKIP(_type,args) \
+do { \
+ switch (_type) { \
+ case 'S': \
+ va_arg(args, char*); \
+ va_arg(args, uint32_t); \
+ break; \
+ case 'a': \
+ va_arg(args, void*); \
+ va_arg(args, void*); \
+ SPA_FALLTHROUGH \
+ case 'p': \
+ case 'y': \
+ va_arg(args, void*); \
+ SPA_FALLTHROUGH \
+ case 'b': \
+ case 'I': \
+ case 'i': \
+ case 'l': \
+ case 'f': \
+ case 'd': \
+ case 's': \
+ case 'R': \
+ case 'F': \
+ case 'B': \
+ case 'h': \
+ case 'V': \
+ case 'P': \
+ case 'T': \
+ case 'O': \
+ va_arg(args, void*); \
+ break; \
+ } \
+} while(false)
+
+static inline 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;
+ const struct spa_pod_prop *prop = NULL;
+ int count = 0;
+
+ do {
+ bool optional;
+ const struct spa_pod *pod = NULL;
+ const char *format;
+
+ if (ftype == SPA_TYPE_Object) {
+ uint32_t key = va_arg(args, uint32_t);
+ const struct spa_pod_object *object;
+
+ if (key == 0)
+ break;
+
+ object = (const struct spa_pod_object *)spa_pod_parser_frame(parser, f);
+ prop = spa_pod_object_find_prop(object, prop, key);
+ pod = prop ? &prop->value : NULL;
+ }
+
+ if ((format = va_arg(args, char *)) == NULL)
+ break;
+
+ if (ftype == SPA_TYPE_Struct)
+ pod = spa_pod_parser_next(parser);
+
+ if ((optional = (*format == '?')))
+ format++;
+
+ if (!spa_pod_parser_can_collect(pod, *format)) {
+ if (!optional) {
+ if (pod == NULL)
+ return -ESRCH;
+ else
+ return -EPROTO;
+ }
+ SPA_POD_PARSER_SKIP(*format, args);
+ } else {
+ if (pod->type == SPA_TYPE_Choice && *format != 'V' &&
+ SPA_POD_CHOICE_TYPE(pod) == SPA_CHOICE_None)
+ pod = SPA_POD_CHOICE_CHILD(pod);
+
+ SPA_POD_PARSER_COLLECT(pod, *format, args);
+ count++;
+ }
+ } while (true);
+
+ return count;
+}
+
+static inline int spa_pod_parser_get(struct spa_pod_parser *parser, ...)
+{
+ int res;
+ va_list args;
+
+ va_start(args, parser);
+ res = spa_pod_parser_getv(parser, args);
+ va_end(args);
+
+ return res;
+}
+
+#define SPA_POD_OPT_Bool(val) "?" SPA_POD_Bool(val)
+#define SPA_POD_OPT_Id(val) "?" SPA_POD_Id(val)
+#define SPA_POD_OPT_Int(val) "?" SPA_POD_Int(val)
+#define SPA_POD_OPT_Long(val) "?" SPA_POD_Long(val)
+#define SPA_POD_OPT_Float(val) "?" SPA_POD_Float(val)
+#define SPA_POD_OPT_Double(val) "?" SPA_POD_Double(val)
+#define SPA_POD_OPT_String(val) "?" SPA_POD_String(val)
+#define SPA_POD_OPT_Stringn(val,len) "?" SPA_POD_Stringn(val,len)
+#define SPA_POD_OPT_Bytes(val,len) "?" SPA_POD_Bytes(val,len)
+#define SPA_POD_OPT_Rectangle(val) "?" SPA_POD_Rectangle(val)
+#define SPA_POD_OPT_Fraction(val) "?" SPA_POD_Fraction(val)
+#define SPA_POD_OPT_Array(csize,ctype,n_vals,vals) "?" SPA_POD_Array(csize,ctype,n_vals,vals)
+#define SPA_POD_OPT_Pointer(type,val) "?" SPA_POD_Pointer(type,val)
+#define SPA_POD_OPT_Fd(val) "?" SPA_POD_Fd(val)
+#define SPA_POD_OPT_Pod(val) "?" SPA_POD_Pod(val)
+#define SPA_POD_OPT_PodObject(val) "?" SPA_POD_PodObject(val)
+#define SPA_POD_OPT_PodStruct(val) "?" SPA_POD_PodStruct(val)
+#define SPA_POD_OPT_PodChoice(val) "?" SPA_POD_PodChoice(val)
+
+#define spa_pod_parser_get_object(p,type,id,...) \
+({ \
+ struct spa_pod_frame _f; \
+ int _res; \
+ if ((_res = spa_pod_parser_push_object(p, &_f, type, id)) == 0) { \
+ _res = spa_pod_parser_get(p,##__VA_ARGS__, 0); \
+ spa_pod_parser_pop(p, &_f); \
+ } \
+ _res; \
+})
+
+#define spa_pod_parser_get_struct(p,...) \
+({ \
+ struct spa_pod_frame _f; \
+ int _res; \
+ if ((_res = spa_pod_parser_push_struct(p, &_f)) == 0) { \
+ _res = spa_pod_parser_get(p,##__VA_ARGS__, NULL); \
+ spa_pod_parser_pop(p, &_f); \
+ } \
+ _res; \
+})
+
+#define spa_pod_parse_object(pod,type,id,...) \
+({ \
+ struct spa_pod_parser _p; \
+ spa_pod_parser_pod(&_p, pod); \
+ spa_pod_parser_get_object(&_p,type,id,##__VA_ARGS__); \
+})
+
+#define spa_pod_parse_struct(pod,...) \
+({ \
+ struct spa_pod_parser _p; \
+ spa_pod_parser_pod(&_p, pod); \
+ spa_pod_parser_get_struct(&_p,##__VA_ARGS__); \
+})
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_POD_PARSER_H */
diff --git a/3rdparty/pipewire/spa/pod/pod.h b/3rdparty/pipewire/spa/pod/pod.h
new file mode 100644
index 000000000..963e1db2a
--- /dev/null
+++ b/3rdparty/pipewire/spa/pod/pod.h
@@ -0,0 +1,236 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_POD_H
+#define SPA_POD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/defs.h>
+#include <spa/utils/type.h>
+
+#define SPA_POD_BODY_SIZE(pod) (((struct spa_pod*)(pod))->size)
+#define SPA_POD_TYPE(pod) (((struct spa_pod*)(pod))->type)
+#define SPA_POD_SIZE(pod) (sizeof(struct spa_pod) + SPA_POD_BODY_SIZE(pod))
+#define SPA_POD_CONTENTS_SIZE(type,pod) (SPA_POD_SIZE(pod)-sizeof(type))
+
+#define SPA_POD_CONTENTS(type,pod) SPA_PTROFF((pod),sizeof(type),void)
+#define SPA_POD_CONTENTS_CONST(type,pod) SPA_PTROFF((pod),sizeof(type),const void)
+#define SPA_POD_BODY(pod) SPA_PTROFF((pod),sizeof(struct spa_pod),void)
+#define SPA_POD_BODY_CONST(pod) SPA_PTROFF((pod),sizeof(struct spa_pod),const void)
+
+struct spa_pod {
+ uint32_t size; /* size of the body */
+ uint32_t type; /* a basic id of enum spa_type */
+};
+
+#define SPA_POD_VALUE(type,pod) (((type*)pod)->value)
+
+struct spa_pod_bool {
+ struct spa_pod pod;
+ int32_t value;
+ int32_t _padding;
+};
+
+struct spa_pod_id {
+ struct spa_pod pod;
+ uint32_t value;
+ int32_t _padding;
+};
+
+struct spa_pod_int {
+ struct spa_pod pod;
+ int32_t value;
+ int32_t _padding;
+};
+
+struct spa_pod_long {
+ struct spa_pod pod;
+ int64_t value;
+};
+
+struct spa_pod_float {
+ struct spa_pod pod;
+ float value;
+ int32_t _padding;
+};
+
+struct spa_pod_double {
+ struct spa_pod pod;
+ double value;
+};
+
+struct spa_pod_string {
+ struct spa_pod pod;
+ /* value here */
+};
+
+struct spa_pod_bytes {
+ struct spa_pod pod;
+ /* value here */
+};
+
+struct spa_pod_rectangle {
+ struct spa_pod pod;
+ struct spa_rectangle value;
+};
+
+struct spa_pod_fraction {
+ struct spa_pod pod;
+ struct spa_fraction value;
+};
+
+struct spa_pod_bitmap {
+ struct spa_pod pod;
+ /* array of uint8_t follows with the bitmap */
+};
+
+#define SPA_POD_ARRAY_CHILD(arr) (&((struct spa_pod_array*)(arr))->body.child)
+#define SPA_POD_ARRAY_VALUE_TYPE(arr) (SPA_POD_TYPE(SPA_POD_ARRAY_CHILD(arr)))
+#define SPA_POD_ARRAY_VALUE_SIZE(arr) (SPA_POD_BODY_SIZE(SPA_POD_ARRAY_CHILD(arr)))
+#define SPA_POD_ARRAY_N_VALUES(arr) (SPA_POD_ARRAY_VALUE_SIZE(arr) ? ((SPA_POD_BODY_SIZE(arr) - sizeof(struct spa_pod_array_body)) / SPA_POD_ARRAY_VALUE_SIZE(arr)) : 0)
+#define SPA_POD_ARRAY_VALUES(arr) SPA_POD_CONTENTS(struct spa_pod_array, arr)
+
+struct spa_pod_array_body {
+ struct spa_pod child;
+ /* array with elements of child.size follows */
+};
+
+struct spa_pod_array {
+ struct spa_pod pod;
+ struct spa_pod_array_body body;
+};
+
+#define SPA_POD_CHOICE_CHILD(choice) (&((struct spa_pod_choice*)(choice))->body.child)
+#define SPA_POD_CHOICE_TYPE(choice) (((struct spa_pod_choice*)(choice))->body.type)
+#define SPA_POD_CHOICE_FLAGS(choice) (((struct spa_pod_choice*)(choice))->body.flags)
+#define SPA_POD_CHOICE_VALUE_TYPE(choice) (SPA_POD_TYPE(SPA_POD_CHOICE_CHILD(choice)))
+#define SPA_POD_CHOICE_VALUE_SIZE(choice) (SPA_POD_BODY_SIZE(SPA_POD_CHOICE_CHILD(choice)))
+#define SPA_POD_CHOICE_N_VALUES(choice) (SPA_POD_CHOICE_VALUE_SIZE(choice) ? ((SPA_POD_BODY_SIZE(choice) - sizeof(struct spa_pod_choice_body)) / SPA_POD_CHOICE_VALUE_SIZE(choice)) : 0)
+#define SPA_POD_CHOICE_VALUES(choice) (SPA_POD_CONTENTS(struct spa_pod_choice, choice))
+
+enum spa_choice_type {
+ SPA_CHOICE_None, /**< no choice, first value is current */
+ SPA_CHOICE_Range, /**< range: default, min, max */
+ SPA_CHOICE_Step, /**< range with step: default, min, max, step */
+ SPA_CHOICE_Enum, /**< list: default, alternative,... */
+ SPA_CHOICE_Flags, /**< flags: default, possible flags,... */
+};
+
+struct spa_pod_choice_body {
+ uint32_t type; /**< type of choice, one of enum spa_choice_type */
+ uint32_t flags; /**< extra flags */
+ struct spa_pod child;
+ /* array with elements of child.size follows. Note that there might be more
+ * elements than required by \a type, which should be ignored. */
+};
+
+struct spa_pod_choice {
+ struct spa_pod pod;
+ struct spa_pod_choice_body body;
+};
+
+struct spa_pod_struct {
+ struct spa_pod pod;
+ /* one or more spa_pod follow */
+};
+
+#define SPA_POD_OBJECT_TYPE(obj) (((struct spa_pod_object*)(obj))->body.type)
+#define SPA_POD_OBJECT_ID(obj) (((struct spa_pod_object*)(obj))->body.id)
+
+struct spa_pod_object_body {
+ uint32_t type; /**< one of enum spa_type */
+ uint32_t id; /**< id of the object, depends on the object type */
+ /* contents follow, series of spa_pod_prop */
+};
+
+struct spa_pod_object {
+ struct spa_pod pod;
+ struct spa_pod_object_body body;
+};
+
+struct spa_pod_pointer_body {
+ uint32_t type; /**< pointer id, one of enum spa_type */
+ uint32_t _padding;
+ const void *value;
+};
+
+struct spa_pod_pointer {
+ struct spa_pod pod;
+ struct spa_pod_pointer_body body;
+};
+
+struct spa_pod_fd {
+ struct spa_pod pod;
+ int64_t value;
+};
+
+#define SPA_POD_PROP_SIZE(prop) (sizeof(struct spa_pod_prop) + (prop)->value.size)
+
+/* props can be inside an object */
+struct spa_pod_prop {
+ uint32_t key; /**< key of property, list of valid keys depends on the
+ * object type */
+#define SPA_POD_PROP_FLAG_READONLY (1u<<0) /**< is read-only */
+#define SPA_POD_PROP_FLAG_HARDWARE (1u<<1) /**< some sort of hardware parameter */
+#define SPA_POD_PROP_FLAG_HINT_DICT (1u<<2) /**< contains a dictionary struct as
+ * (Struct(
+ * Int : n_items,
+ * (String : key,
+ * String : value)*)) */
+ uint32_t flags; /**< flags for property */
+ struct spa_pod value;
+ /* value follows */
+};
+
+#define SPA_POD_CONTROL_SIZE(ev) (sizeof(struct spa_pod_control) + (ev)->value.size)
+
+/* controls can be inside a sequence and mark timed values */
+struct spa_pod_control {
+ uint32_t offset; /**< media offset */
+ uint32_t type; /**< type of control, enum spa_control_type */
+ struct spa_pod value; /**< control value, depends on type */
+ /* value contents follow */
+};
+
+struct spa_pod_sequence_body {
+ uint32_t unit;
+ uint32_t pad;
+ /* series of struct spa_pod_control follows */
+};
+
+/** a sequence of timed controls */
+struct spa_pod_sequence {
+ struct spa_pod pod;
+ struct spa_pod_sequence_body body;
+};
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_POD_H */
diff --git a/3rdparty/pipewire/spa/pod/vararg.h b/3rdparty/pipewire/spa/pod/vararg.h
new file mode 100644
index 000000000..b6dcdc7b7
--- /dev/null
+++ b/3rdparty/pipewire/spa/pod/vararg.h
@@ -0,0 +1,104 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2019 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_POD_VARARG_H
+#define SPA_POD_VARARG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+
+#include <spa/pod/pod.h>
+
+#define SPA_POD_Prop(key,...) \
+ key, ##__VA_ARGS__
+
+#define SPA_POD_Control(offset,type,...) \
+ offset, type, ##__VA_ARGS__
+
+#define SPA_CHOICE_RANGE(def,min,max) 3,(def),(min),(max)
+#define SPA_CHOICE_STEP(def,min,max,step) 4,(def),(min),(max),(step)
+#define SPA_CHOICE_ENUM(n_vals,...) (n_vals),##__VA_ARGS__
+#define SPA_CHOICE_FLAGS(flags) 1, (flags)
+#define SPA_CHOICE_BOOL(def) 3,(def),(def),!(def)
+
+#define SPA_POD_Bool(val) "b", val
+#define SPA_POD_CHOICE_Bool(def) "?eb", SPA_CHOICE_BOOL(def)
+
+#define SPA_POD_Id(val) "I", val
+#define SPA_POD_CHOICE_ENUM_Id(n_vals,...) "?eI", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
+
+#define SPA_POD_Int(val) "i", val
+#define SPA_POD_CHOICE_ENUM_Int(n_vals,...) "?ei", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
+#define SPA_POD_CHOICE_RANGE_Int(def,min,max) "?ri", SPA_CHOICE_RANGE(def, min, max)
+#define SPA_POD_CHOICE_STEP_Int(def,min,max,step) "?si", SPA_CHOICE_STEP(def, min, max, step)
+#define SPA_POD_CHOICE_FLAGS_Int(flags) "?fi", SPA_CHOICE_FLAGS(flags)
+
+#define SPA_POD_Long(val) "l", val
+#define SPA_POD_CHOICE_ENUM_Long(n_vals,...) "?el", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
+#define SPA_POD_CHOICE_RANGE_Long(def,min,max) "?rl", SPA_CHOICE_RANGE(def, min, max)
+#define SPA_POD_CHOICE_STEP_Long(def,min,max,step) "?sl", SPA_CHOICE_STEP(def, min, max, step)
+#define SPA_POD_CHOICE_FLAGS_Long(flags) "?fl", SPA_CHOICE_FLAGS(flags)
+
+#define SPA_POD_Float(val) "f", val
+#define SPA_POD_CHOICE_ENUM_Float(n_vals,...) "?ef", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
+#define SPA_POD_CHOICE_RANGE_Float(def,min,max) "?rf", SPA_CHOICE_RANGE(def, min, max)
+#define SPA_POD_CHOICE_STEP_Float(def,min,max,step) "?sf", SPA_CHOICE_STEP(def, min, max, step)
+
+#define SPA_POD_Double(val) "d", val
+#define SPA_POD_CHOICE_ENUM_Double(n_vals,...) "?ed", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
+#define SPA_POD_CHOICE_RANGE_Double(def,min,max) "?rd", SPA_CHOICE_RANGE(def, min, max)
+#define SPA_POD_CHOICE_STEP_Double(def,min,max,step) "?sd", SPA_CHOICE_STEP(def, min, max, step)
+
+#define SPA_POD_String(val) "s",val
+#define SPA_POD_Stringn(val,len) "S",val,len
+
+#define SPA_POD_Bytes(val,len) "y",val,len
+
+#define SPA_POD_Rectangle(val) "R",val
+#define SPA_POD_CHOICE_ENUM_Rectangle(n_vals,...) "?eR", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
+#define SPA_POD_CHOICE_RANGE_Rectangle(def,min,max) "?rR", SPA_CHOICE_RANGE((def),(min),(max))
+#define SPA_POD_CHOICE_STEP_Rectangle(def,min,max,step) "?sR", SPA_CHOICE_STEP((def),(min),(max),(step))
+
+#define SPA_POD_Fraction(val) "F",val
+#define SPA_POD_CHOICE_ENUM_Fraction(n_vals,...) "?eF", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
+#define SPA_POD_CHOICE_RANGE_Fraction(def,min,max) "?rF", SPA_CHOICE_RANGE((def),(min),(max))
+#define SPA_POD_CHOICE_STEP_Fraction(def,min,max,step) "?sF", SPA_CHOICE_STEP(def, min, max, step)
+
+#define SPA_POD_Array(csize,ctype,n_vals,vals) "a", csize,ctype,n_vals,vals
+#define SPA_POD_Pointer(type,val) "p", type,val
+#define SPA_POD_Fd(val) "h", val
+#define SPA_POD_None() "P", NULL
+#define SPA_POD_Pod(val) "P", val
+#define SPA_POD_PodObject(val) "O", val
+#define SPA_POD_PodStruct(val) "T", val
+#define SPA_POD_PodChoice(val) "V", val
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_POD_VARARG_H */
diff --git a/3rdparty/pipewire/spa/support/loop.h b/3rdparty/pipewire/spa/support/loop.h
new file mode 100644
index 000000000..34ddaa89e
--- /dev/null
+++ b/3rdparty/pipewire/spa/support/loop.h
@@ -0,0 +1,312 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_LOOP_H
+#define SPA_LOOP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/defs.h>
+#include <spa/utils/hook.h>
+#include <spa/support/system.h>
+
+#define SPA_TYPE_INTERFACE_Loop SPA_TYPE_INFO_INTERFACE_BASE "Loop"
+#define SPA_TYPE_INTERFACE_DataLoop SPA_TYPE_INFO_INTERFACE_BASE "DataLoop"
+#define SPA_VERSION_LOOP 0
+struct spa_loop { struct spa_interface iface; };
+
+#define SPA_TYPE_INTERFACE_LoopControl SPA_TYPE_INFO_INTERFACE_BASE "LoopControl"
+#define SPA_VERSION_LOOP_CONTROL 0
+struct spa_loop_control { struct spa_interface iface; };
+
+#define SPA_TYPE_INTERFACE_LoopUtils SPA_TYPE_INFO_INTERFACE_BASE "LoopUtils"
+#define SPA_VERSION_LOOP_UTILS 0
+struct spa_loop_utils { struct spa_interface iface; };
+
+struct spa_source;
+
+typedef void (*spa_source_func_t) (struct spa_source *source);
+
+struct spa_source {
+ struct spa_loop *loop;
+ spa_source_func_t func;
+ void *data;
+ int fd;
+ uint32_t mask;
+ uint32_t rmask;
+};
+
+typedef int (*spa_invoke_func_t) (struct spa_loop *loop,
+ bool async,
+ uint32_t seq,
+ const void *data,
+ size_t size,
+ void *user_data);
+
+/**
+ * Register sources and work items to an event loop
+ */
+struct spa_loop_methods {
+ /* the version of this structure. This can be used to expand this
+ * structure in the future */
+#define SPA_VERSION_LOOP_METHODS 0
+ uint32_t version;
+
+ /** add a source to the loop */
+ int (*add_source) (void *object,
+ struct spa_source *source);
+
+ /** update the source io mask */
+ int (*update_source) (void *object,
+ struct spa_source *source);
+
+ /** remove a source from the loop */
+ int (*remove_source) (void *object,
+ struct spa_source *source);
+
+ /** invoke a function in the context of this loop */
+ int (*invoke) (void *object,
+ spa_invoke_func_t func,
+ uint32_t seq,
+ const void *data,
+ size_t size,
+ bool block,
+ 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__)
+
+
+/** Control hooks. These hooks can't be removed from their
+ * callbacks and must be removed from a safe place (when the loop
+ * is not running or when it is locked). */
+struct spa_loop_control_hooks {
+#define SPA_VERSION_LOOP_CONTROL_HOOKS 0
+ uint32_t version;
+ /** Executed right before waiting for events. It is typically used to
+ * release locks. */
+ void (*before) (void *data);
+ /** Executed right after waiting for events. It is typically used to
+ * reacquire locks. */
+ 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); \
+})
+
+#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); \
+})
+
+/**
+ * Control an event loop
+ */
+struct spa_loop_control_methods {
+ /* the version of this structure. This can be used to expand this
+ * structure in the future */
+#define SPA_VERSION_LOOP_CONTROL_METHODS 0
+ uint32_t version;
+
+ int (*get_fd) (void *object);
+
+ /** Add a hook
+ * \param ctrl the control to change
+ * \param hooks the hooks to add
+ *
+ * Adds hooks to the loop controlled by \a ctrl.
+ */
+ void (*add_hook) (void *object,
+ struct spa_hook *hook,
+ const struct spa_loop_control_hooks *hooks,
+ void *data);
+
+ /** Enter a loop
+ * \param ctrl 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.
+ */
+ void (*enter) (void *object);
+ /** Leave a loop
+ * \param ctrl the control
+ *
+ * Ends the iteration of a loop. This should be called after calling
+ * iterate.
+ */
+ void (*leave) (void *object);
+
+ /** Perform one iteration of the loop.
+ * \param ctrl the control
+ * \param timeout an optional timeout in milliseconds.
+ * 0 for no timeout, -1 for infinite timeout.
+ *
+ * This function will block
+ * up to \a timeout milliseconds and then dispatch the fds with activity.
+ * The number of dispatched fds is returned.
+ */
+ int (*iterate) (void *object, int timeout);
+};
+
+#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__)
+
+typedef void (*spa_source_io_func_t) (void *data, int fd, uint32_t mask);
+typedef void (*spa_source_idle_func_t) (void *data);
+typedef void (*spa_source_event_func_t) (void *data, uint64_t count);
+typedef void (*spa_source_timer_func_t) (void *data, uint64_t expirations);
+typedef void (*spa_source_signal_func_t) (void *data, int signal_number);
+
+/**
+ * Create sources for an event loop
+ */
+struct spa_loop_utils_methods {
+ /* the version of this structure. This can be used to expand this
+ * structure in the future */
+#define SPA_VERSION_LOOP_UTILS_METHODS 0
+ uint32_t version;
+
+ struct spa_source *(*add_io) (void *object,
+ int fd,
+ uint32_t mask,
+ bool close,
+ spa_source_io_func_t func, void *data);
+
+ int (*update_io) (void *object, struct spa_source *source, uint32_t mask);
+
+ struct spa_source *(*add_idle) (void *object,
+ bool enabled,
+ spa_source_idle_func_t func, void *data);
+ int (*enable_idle) (void *object, struct spa_source *source, bool enabled);
+
+ struct spa_source *(*add_event) (void *object,
+ spa_source_event_func_t func, void *data);
+ int (*signal_event) (void *object, struct spa_source *source);
+
+ struct spa_source *(*add_timer) (void *object,
+ spa_source_timer_func_t func, void *data);
+ int (*update_timer) (void *object,
+ struct spa_source *source,
+ struct timespec *value,
+ struct timespec *interval,
+ bool absolute);
+ struct spa_source *(*add_signal) (void *object,
+ int signal_number,
+ spa_source_signal_func_t func, void *data);
+
+ /** destroy a source allocated with this interface. This function
+ * should only be called when the loop is not running or from the
+ * context of the running loop */
+ 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__)
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_LOOP_H */
diff --git a/3rdparty/pipewire/spa/support/system.h b/3rdparty/pipewire/spa/support/system.h
new file mode 100644
index 000000000..fb867dc5f
--- /dev/null
+++ b/3rdparty/pipewire/spa/support/system.h
@@ -0,0 +1,152 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2019 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_SYSTEM_H
+#define SPA_SYSTEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct itimerspec;
+
+#include <time.h>
+#include <sys/types.h>
+
+#include <spa/utils/defs.h>
+#include <spa/utils/hook.h>
+
+/**
+ * a collection of core system functions
+ */
+#define SPA_TYPE_INTERFACE_System SPA_TYPE_INFO_INTERFACE_BASE "System"
+#define SPA_TYPE_INTERFACE_DataSystem SPA_TYPE_INFO_INTERFACE_BASE "DataSystem"
+
+#define SPA_VERSION_SYSTEM 0
+struct spa_system { struct spa_interface iface; };
+
+/* IO events */
+#define SPA_IO_IN (1 << 0)
+#define SPA_IO_OUT (1 << 2)
+#define SPA_IO_ERR (1 << 3)
+#define SPA_IO_HUP (1 << 4)
+
+/* flags */
+#define SPA_FD_CLOEXEC (1<<0)
+#define SPA_FD_NONBLOCK (1<<1)
+#define SPA_FD_EVENT_SEMAPHORE (1<<2)
+#define SPA_FD_TIMER_ABSTIME (1<<3)
+#define SPA_FD_TIMER_CANCEL_ON_SET (1<<4)
+
+struct spa_poll_event {
+ uint32_t events;
+ void *data;
+};
+
+struct spa_system_methods {
+#define SPA_VERSION_SYSTEM_METHODS 0
+ uint32_t version;
+
+ /* read/write/ioctl */
+ ssize_t (*read) (void *object, int fd, void *buf, size_t count);
+ ssize_t (*write) (void *object, int fd, const void *buf, size_t count);
+ int (*ioctl) (void *object, int fd, unsigned long request, ...);
+ int (*close) (void *object, int fd);
+
+ /* clock */
+ int (*clock_gettime) (void *object,
+ int clockid, struct timespec *value);
+ int (*clock_getres) (void *object,
+ int clockid, struct timespec *res);
+
+ /* poll */
+ int (*pollfd_create) (void *object, int flags);
+ int (*pollfd_add) (void *object, int pfd, int fd, uint32_t events, void *data);
+ int (*pollfd_mod) (void *object, int pfd, int fd, uint32_t events, void *data);
+ int (*pollfd_del) (void *object, int pfd, int fd);
+ int (*pollfd_wait) (void *object, int pfd,
+ struct spa_poll_event *ev, int n_ev, int timeout);
+
+ /* timers */
+ int (*timerfd_create) (void *object, int clockid, int flags);
+ int (*timerfd_settime) (void *object,
+ int fd, int flags,
+ const struct itimerspec *new_value,
+ struct itimerspec *old_value);
+ int (*timerfd_gettime) (void *object,
+ int fd, struct itimerspec *curr_value);
+ int (*timerfd_read) (void *object, int fd, uint64_t *expirations);
+
+ /* events */
+ int (*eventfd_create) (void *object, int flags);
+ int (*eventfd_write) (void *object, int fd, uint64_t count);
+ int (*eventfd_read) (void *object, int fd, uint64_t *count);
+
+ /* signals */
+ int (*signalfd_create) (void *object, int signal, int flags);
+ int (*signalfd_read) (void *object, int fd, int *signal);
+};
+
+#define spa_system_method_r(o,method,version,...) \
+({ \
+ int _res = -ENOTSUP; \
+ struct spa_system *_o = o; \
+ spa_interface_call_res(&_o->iface, \
+ struct spa_system_methods, _res, \
+ method, version, ##__VA_ARGS__); \
+ _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__)
+
+#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__)
+
+#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__)
+
+#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__)
+
+#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__)
+
+#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__)
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_SYSTEM_H */
diff --git a/3rdparty/pipewire/spa/utils/defs.h b/3rdparty/pipewire/spa/utils/defs.h
new file mode 100644
index 000000000..e2ae57640
--- /dev/null
+++ b/3rdparty/pipewire/spa/utils/defs.h
@@ -0,0 +1,300 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_UTILS_DEFS_H
+#define SPA_UTILS_DEFS_H
+
+#ifdef __cplusplus
+extern "C" {
+#else
+#include <stdbool.h>
+#endif
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdio.h>
+
+/**
+ * SPA_FALLTHROUGH is an annotation to suppress compiler warnings about switch
+ * cases that fall through without a break or return statement. SPA_FALLTHROUGH
+ * is only needed on cases that have code:
+ *
+ * switch (foo) {
+ * case 1: // These cases have no code. No fallthrough annotations are needed.
+ * case 2:
+ * case 3:
+ * foo = 4; // This case has code, so a fallthrough annotation is needed:
+ * SPA_FALLTHROUGH;
+ * default:
+ * return foo;
+ * }
+ */
+#if defined(__clang__) && __cplusplus >= 201103L
+ /* clang's fallthrough annotations are only available starting in C++11. */
+# define SPA_FALLTHROUGH [[clang::fallthrough]];
+#elif __GNUC__ >= 7 || __clang_major__ >= 10
+# define SPA_FALLTHROUGH __attribute__ ((fallthrough));
+#else
+# define SPA_FALLTHROUGH /* FALLTHROUGH */
+#endif
+
+#define SPA_FLAG_MASK(field,mask,flag) (((field) & (mask)) == (flag))
+#define SPA_FLAG_IS_SET(field,flag) SPA_FLAG_MASK(field,flag,flag)
+#define SPA_FLAG_SET(field,flag) ((field) |= (flag))
+#define SPA_FLAG_CLEAR(field,flag) ((field) &= ~(flag))
+#define SPA_FLAG_UPDATE(field,flag,val) ((val) ? SPA_FLAG_SET(field,flag) : SPA_FLAG_CLEAR(field,flag))
+
+enum spa_direction {
+ SPA_DIRECTION_INPUT = 0,
+ SPA_DIRECTION_OUTPUT = 1,
+};
+
+#define SPA_DIRECTION_REVERSE(d) ((d) ^ 1)
+
+#define SPA_RECTANGLE(width,height) (struct spa_rectangle){ width, height }
+struct spa_rectangle {
+ uint32_t width;
+ uint32_t height;
+};
+
+#define SPA_POINT(x,y) (struct spa_point){ x, y }
+struct spa_point {
+ int32_t x;
+ int32_t y;
+};
+
+#define SPA_REGION(x,y,width,height) (struct spa_region){ SPA_POINT(x,y), SPA_RECTANGLE(width,height) }
+struct spa_region {
+ struct spa_point position;
+ struct spa_rectangle size;
+};
+
+#define SPA_FRACTION(num,denom) (struct spa_fraction){ num, denom }
+struct spa_fraction {
+ uint32_t num;
+ uint32_t denom;
+};
+
+#define SPA_N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+#define SPA_MIN(a,b) \
+({ \
+ __typeof__(a) _min_a = (a); \
+ __typeof__(b) _min_b = (b); \
+ SPA_LIKELY(_min_a < _min_b) ? _min_a : _min_b; \
+})
+#define SPA_MAX(a,b) \
+({ \
+ __typeof__(a) _max_a = (a); \
+ __typeof__(b) _max_b = (b); \
+ SPA_LIKELY(_max_a > _max_b) ? _max_a : _max_b; \
+})
+#define SPA_CLAMP(v,low,high) \
+({ \
+ __typeof__(v) _v = (v); \
+ __typeof__(low) _low = (low); \
+ __typeof__(high) _high = (high); \
+ SPA_MIN(SPA_MAX(_v, _low), _high); \
+})
+
+#define SPA_SWAP(a,b) \
+({ \
+ __typeof__(a) _t = (a); \
+ a = b; b = _t; \
+})
+
+#define SPA_TYPECHECK(type,x) \
+({ type _dummy; \
+ typeof(x) _dummy2; \
+ (void)(&_dummy == &_dummy2); \
+ x; \
+})
+
+/**
+ * Return the address (buffer + offset) as pointer of \a type
+ */
+#define SPA_PTROFF(ptr_,offset_,type_) ((type_*)((uint8_t*)(ptr_) + (int)(offset_)))
+#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
+ */
+#define SPA_MEMBER(b,o,t) SPA_PTROFF(b,o,t)
+#define SPA_MEMBER_ALIGN(b,o,a,t) SPA_PTROFF_ALIGN(b,o,a,t)
+
+#define SPA_CONTAINER_OF(p,t,m) (t*)((uint8_t*)p - offsetof (t,m))
+
+#define SPA_PTRDIFF(p1,p2) ((uint8_t*)(p1) - (uint8_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)))
+
+#define SPA_TIME_INVALID ((int64_t)INT64_MIN)
+#define SPA_IDX_INVALID ((unsigned int)-1)
+#define SPA_ID_INVALID ((uint32_t)0xffffffff)
+
+#define SPA_NSEC_PER_SEC (1000000000ll)
+#define SPA_NSEC_PER_MSEC (1000000ll)
+#define SPA_NSEC_PER_USEC (1000ll)
+#define SPA_USEC_PER_SEC (1000000ll)
+#define SPA_USEC_PER_MSEC (1000ll)
+#define SPA_MSEC_PER_SEC (1000ll)
+
+#define SPA_TIMESPEC_TO_NSEC(ts) ((ts)->tv_sec * SPA_NSEC_PER_SEC + (ts)->tv_nsec)
+#define SPA_TIMESPEC_TO_USEC(ts) ((ts)->tv_sec * SPA_USEC_PER_SEC + (ts)->tv_nsec / SPA_NSEC_PER_USEC)
+#define SPA_TIMEVAL_TO_NSEC(tv) ((tv)->tv_sec * SPA_NSEC_PER_SEC + (tv)->tv_usec * SPA_NSEC_PER_USEC)
+#define SPA_TIMEVAL_TO_USEC(tv) ((tv)->tv_sec * SPA_USEC_PER_SEC + (tv)->tv_usec)
+
+#ifdef __GNUC__
+#define SPA_PRINTF_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1)))
+#define SPA_ALIGNED(align) __attribute__((aligned(align)))
+#define SPA_DEPRECATED __attribute__ ((deprecated))
+#define SPA_EXPORT __attribute__((visibility("default")))
+#define SPA_SENTINEL __attribute__((__sentinel__))
+#define SPA_UNUSED __attribute__ ((unused))
+#else
+#define SPA_PRINTF_FUNC(fmt, arg1)
+#define SPA_ALIGNED(align)
+#define SPA_DEPRECATED
+#define SPA_EXPORT
+#define SPA_SENTINEL
+#define SPA_UNUSED
+#endif
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define SPA_RESTRICT restrict
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define SPA_RESTRICT __restrict__
+#else
+#define SPA_RESTRICT
+#endif
+
+#define SPA_ROUND_DOWN_N(num,align) ((num) & ~((align) - 1))
+#define SPA_ROUND_UP_N(num,align) SPA_ROUND_DOWN_N((num) + ((align) - 1),align)
+
+#define SPA_PTR_ALIGNMENT(p,align) ((intptr_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))
+
+#ifndef SPA_LIKELY
+#ifdef __GNUC__
+#define SPA_LIKELY(x) (__builtin_expect(!!(x),1))
+#define SPA_UNLIKELY(x) (__builtin_expect(!!(x),0))
+#else
+#define SPA_LIKELY(x) (x)
+#define SPA_UNLIKELY(x) (x)
+#endif
+#endif
+
+#define SPA_STRINGIFY_1(...) #__VA_ARGS__
+#define SPA_STRINGIFY(...) SPA_STRINGIFY_1(__VA_ARGS__)
+
+#define spa_return_if_fail(expr) \
+ do { \
+ if (SPA_UNLIKELY(!(expr))) { \
+ fprintf(stderr, "'%s' failed at %s:%u %s()\n", \
+ #expr , __FILE__, __LINE__, __func__); \
+ return; \
+ } \
+ } while(false)
+
+#define spa_return_val_if_fail(expr, val) \
+ do { \
+ if (SPA_UNLIKELY(!(expr))) { \
+ fprintf(stderr, "'%s' failed at %s:%u %s()\n", \
+ #expr , __FILE__, __LINE__, __func__); \
+ return (val); \
+ } \
+ } while(false)
+
+/* spa_assert_se() is an assert which guarantees side effects of x,
+ * i.e. is never optimized away, regardless of NDEBUG or FASTPATH. */
+#define spa_assert_se(expr) \
+ do { \
+ if (SPA_UNLIKELY(!(expr))) { \
+ fprintf(stderr, "'%s' failed at %s:%u %s()\n", \
+ #expr , __FILE__, __LINE__, __func__); \
+ abort(); \
+ } \
+ } while (false)
+
+#define spa_assert(expr) \
+ do { \
+ if (SPA_UNLIKELY(!(expr))) { \
+ fprintf(stderr, "'%s' failed at %s:%u %s()\n", \
+ #expr , __FILE__, __LINE__, __func__); \
+ abort(); \
+ } \
+ } while (false)
+
+#define spa_assert_not_reached() \
+ do { \
+ fprintf(stderr, "Code should not be reached at %s:%u %s()\n", \
+ __FILE__, __LINE__, __func__); \
+ abort(); \
+ } while (false)
+
+/* Does exactly nothing */
+#define spa_nop() do {} while (false)
+
+#define spa_memzero(x,l) (memset((x), 0, (l)))
+#define spa_zero(x) (spa_memzero(&(x), sizeof(x)))
+
+#ifdef SPA_DEBUG_MEMCPY
+#define spa_memcpy(d,s,n) \
+({ \
+ fprintf(stderr, "%s:%u %s() memcpy(%p, %p, %zd)\n", \
+ __FILE__, __LINE__, __func__, (d), (s), (size_t)(n)); \
+ memcpy(d,s,n); \
+})
+#define spa_memmove(d,s,n) \
+({ \
+ fprintf(stderr, "%s:%u %s() memmove(%p, %p, %zd)\n", \
+ __FILE__, __LINE__, __func__, (d), (s), (size_t)(n)); \
+ memmove(d,s,n); \
+})
+#else
+#define spa_memcpy(d,s,n) memcpy(d,s,n)
+#define spa_memmove(d,s,n) memmove(d,s,n)
+#endif
+
+#define spa_aprintf(_fmt, ...) \
+({ \
+ char *_strp; \
+ if (asprintf(&(_strp), (_fmt), ## __VA_ARGS__ ) == -1) \
+ _strp = NULL; \
+ _strp; \
+})
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_UTILS_DEFS_H */
diff --git a/3rdparty/pipewire/spa/utils/dict.h b/3rdparty/pipewire/spa/utils/dict.h
new file mode 100644
index 000000000..272420ec3
--- /dev/null
+++ b/3rdparty/pipewire/spa/utils/dict.h
@@ -0,0 +1,104 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_DICT_H
+#define SPA_DICT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+
+#include <spa/utils/defs.h>
+
+struct spa_dict_item {
+ const char *key;
+ const char *value;
+};
+
+#define SPA_DICT_ITEM_INIT(key,value) (struct spa_dict_item) { key, value }
+
+struct spa_dict {
+#define SPA_DICT_FLAG_SORTED (1<<0) /**< items are sorted */
+ uint32_t flags;
+ uint32_t n_items;
+ 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_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)
+{
+ 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)
+{
+ qsort((void*)dict->items, dict->n_items, sizeof(struct spa_dict_item),
+ spa_dict_item_compare);
+ 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,
+ const char *key)
+{
+ const struct spa_dict_item *item;
+
+ if (SPA_FLAG_IS_SET(dict->flags, SPA_DICT_FLAG_SORTED)) {
+ struct spa_dict_item k = SPA_DICT_ITEM_INIT(key, NULL);
+ item = (const struct spa_dict_item *)bsearch(&k,
+ (const void *) dict->items, dict->n_items,
+ sizeof(struct spa_dict_item),
+ spa_dict_item_compare);
+ if (item != NULL)
+ return item;
+ } else {
+ spa_dict_for_each(item, dict) {
+ if (!strcmp(item->key, key))
+ return item;
+ }
+ }
+ return NULL;
+}
+
+static inline 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;
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_DICT_H */
diff --git a/3rdparty/pipewire/spa/utils/hook.h b/3rdparty/pipewire/spa/utils/hook.h
new file mode 100644
index 000000000..f1ca66dc8
--- /dev/null
+++ b/3rdparty/pipewire/spa/utils/hook.h
@@ -0,0 +1,208 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_HOOK_H
+#define SPA_HOOK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/defs.h>
+#include <spa/utils/list.h>
+
+/** \class spa_hook
+ *
+ * \brief a list of hooks
+ *
+ * The hook list provides a way to keep track of hooks.
+ */
+/** A list of hooks */
+struct spa_hook_list {
+ struct spa_list list;
+};
+
+/** Callbacks, contains the structure with functions and the data passed
+ * to the functions. The structure should also contain a version field that
+ * is checked. */
+struct spa_callbacks {
+ const void *funcs;
+ void *data;
+};
+
+/** Check if a callback \c has method \m of version \v */
+#define SPA_CALLBACK_CHECK(c,m,v) ((c) && ((v) == 0 || (c)->version > (v)-1) && (c)->m)
+
+#define SPA_CALLBACKS_INIT(_funcs,_data) (struct spa_callbacks){ _funcs, _data, }
+
+struct spa_interface {
+ const char *type;
+ uint32_t version;
+ struct spa_callbacks cb;
+};
+
+#define SPA_INTERFACE_INIT(_type,_version,_funcs,_data) \
+ (struct spa_interface){ _type, _version, SPA_CALLBACKS_INIT(_funcs,_data), }
+
+/** A hook, contains the structure with functions and the data passed
+ * to the functions. */
+struct spa_hook {
+ struct spa_list link;
+ struct spa_callbacks cb;
+ /** callback and data for the hook list, private to the
+ * hook_list implementor */
+ void (*removed) (struct spa_hook *hook);
+ void *priv;
+};
+
+/** Initialize a hook list */
+static inline 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)
+{
+ return spa_list_is_empty(&list->list);
+}
+
+/** Append a hook \memberof spa_hook. */
+static inline void spa_hook_list_append(struct spa_hook_list *list,
+ struct spa_hook *hook,
+ const void *funcs, void *data)
+{
+ spa_zero(*hook);
+ hook->cb = SPA_CALLBACKS_INIT(funcs, data);
+ spa_list_append(&list->list, &hook->link);
+}
+
+/** Prepend a hook \memberof spa_hook */
+static inline void spa_hook_list_prepend(struct spa_hook_list *list,
+ struct spa_hook *hook,
+ const void *funcs, void *data)
+{
+ spa_zero(*hook);
+ hook->cb = SPA_CALLBACKS_INIT(funcs, data);
+ spa_list_prepend(&list->list, &hook->link);
+}
+
+/** Remove a hook \memberof spa_hook */
+static inline void spa_hook_remove(struct spa_hook *hook)
+{
+ spa_list_remove(&hook->link);
+ if (hook->removed)
+ hook->removed(hook);
+}
+
+static inline 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_hook_list_isolate(struct spa_hook_list *list,
+ struct spa_hook_list *save,
+ struct spa_hook *hook,
+ const void *funcs, void *data)
+{
+ /* init save list and move hooks to it */
+ spa_hook_list_init(save);
+ spa_list_insert_list(&save->list, &list->list);
+ /* init hooks and add single hook */
+ spa_hook_list_init(list);
+ spa_hook_list_append(list, hook, funcs, data);
+}
+
+static inline void
+spa_hook_list_join(struct spa_hook_list *list,
+ struct spa_hook_list *save)
+{
+ spa_list_insert_list(&list->list, &save->list);
+}
+
+#define spa_callbacks_call(callbacks,type,method,vers,...) \
+({ \
+ const type *_f = (const type *) (callbacks)->funcs; \
+ if (SPA_LIKELY(SPA_CALLBACK_CHECK(_f,method,vers))) \
+ _f->method((callbacks)->data, ## __VA_ARGS__); \
+})
+
+#define spa_callbacks_call_res(callbacks,type,res,method,vers,...) \
+({ \
+ const type *_f = (const type *) (callbacks)->funcs; \
+ if (SPA_LIKELY(SPA_CALLBACK_CHECK(_f,method,vers))) \
+ res = _f->method((callbacks)->data, ## __VA_ARGS__); \
+ res; \
+})
+
+#define spa_interface_call(iface,type,method,vers,...) \
+ spa_callbacks_call(&(iface)->cb,type,method,vers,##__VA_ARGS__)
+
+#define spa_interface_call_res(iface,type,res,method,vers,...) \
+ spa_callbacks_call_res(&(iface)->cb,type,res,method,vers,##__VA_ARGS__)
+
+#define spa_hook_list_call_simple(l,type,method,vers,...) \
+({ \
+ struct spa_hook_list *_l = l; \
+ struct spa_hook *_h, *_t; \
+ spa_list_for_each_safe(_h, _t, &_l->list, link) \
+ spa_callbacks_call(&_h->cb,type,method,vers, ## __VA_ARGS__); \
+})
+
+/** Call all hooks in a list, starting from the given one and optionally stopping
+ * after calling the first non-NULL function, returns the number of methods
+ * called */
+#define spa_hook_list_do_call(l,start,type,method,vers,once,...) \
+({ \
+ struct spa_hook_list *list = l; \
+ struct spa_list *s = start ? (struct spa_list *)start : &list->list; \
+ struct spa_hook cursor = { 0 }, *ci; \
+ int count = 0; \
+ spa_list_cursor_start(cursor, s, link); \
+ spa_list_for_each_cursor(ci, cursor, &list->list, link) { \
+ const type *_f = (const type *)ci->cb.funcs; \
+ if (SPA_LIKELY(SPA_CALLBACK_CHECK(_f,method,vers))) { \
+ _f->method(ci->cb.data, ## __VA_ARGS__); \
+ count++; \
+ if (once) \
+ break; \
+ } \
+ } \
+ spa_list_cursor_end(cursor, link); \
+ count; \
+})
+
+#define spa_hook_list_call(l,t,m,v,...) spa_hook_list_do_call(l,NULL,t,m,v,false,##__VA_ARGS__)
+#define spa_hook_list_call_once(l,t,m,v,...) spa_hook_list_do_call(l,NULL,t,m,v,true,##__VA_ARGS__)
+
+#define spa_hook_list_call_start(l,s,t,m,v,...) spa_hook_list_do_call(l,s,t,m,v,false,##__VA_ARGS__)
+#define spa_hook_list_call_once_start(l,s,t,m,v,...) spa_hook_list_do_call(l,s,t,m,v,true,##__VA_ARGS__)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPA_HOOK_H */
diff --git a/3rdparty/pipewire/spa/utils/list.h b/3rdparty/pipewire/spa/utils/list.h
new file mode 100644
index 000000000..f9dd37ccb
--- /dev/null
+++ b/3rdparty/pipewire/spa/utils/list.h
@@ -0,0 +1,147 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_LIST_H
+#define SPA_LIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct spa_list {
+ struct spa_list *next;
+ struct spa_list *prev;
+};
+
+#define SPA_LIST_INIT(list) (struct spa_list){ list, list };
+
+static inline void spa_list_init(struct spa_list *list)
+{
+ *list = SPA_LIST_INIT(list);
+}
+
+#define spa_list_is_empty(l) ((l)->next == (l))
+
+static inline void spa_list_insert(struct spa_list *list, struct spa_list *elem)
+{
+ elem->prev = list;
+ elem->next = list->next;
+ list->next = elem;
+ elem->next->prev = elem;
+}
+
+static inline void spa_list_insert_list(struct spa_list *list, struct spa_list *other)
+{
+ if (spa_list_is_empty(other))
+ return;
+ other->next->prev = list;
+ other->prev->next = list->next;
+ list->next->prev = other->prev;
+ list->next = other->next;
+}
+
+static inline void spa_list_remove(struct spa_list *elem)
+{
+ elem->prev->next = elem->next;
+ elem->next->prev = elem->prev;
+}
+
+#define spa_list_first(head, type, member) \
+ SPA_CONTAINER_OF((head)->next, type, member)
+
+#define spa_list_last(head, type, member) \
+ SPA_CONTAINER_OF((head)->prev, type, member)
+
+#define spa_list_append(list, item) \
+ spa_list_insert((list)->prev, item)
+
+#define spa_list_prepend(list, item) \
+ spa_list_insert(list, item)
+
+#define spa_list_is_end(pos, head, member) \
+ (&(pos)->member == (head))
+
+#define spa_list_next(pos, member) \
+ SPA_CONTAINER_OF((pos)->member.next, __typeof__(*pos), member)
+
+#define spa_list_prev(pos, member) \
+ SPA_CONTAINER_OF((pos)->member.prev, __typeof__(*pos), member)
+
+#define spa_list_consume(pos, head, member) \
+ for (pos = spa_list_first(head, __typeof__(*pos), member); \
+ !spa_list_is_empty(head); \
+ pos = spa_list_first(head, __typeof__(*pos), member))
+
+#define spa_list_for_each_next(pos, head, curr, member) \
+ for (pos = spa_list_first(curr, __typeof__(*pos), member); \
+ !spa_list_is_end(pos, head, member); \
+ pos = spa_list_next(pos, member))
+
+#define spa_list_for_each_prev(pos, head, curr, member) \
+ for (pos = spa_list_last(curr, __typeof__(*pos), member); \
+ !spa_list_is_end(pos, head, member); \
+ pos = spa_list_prev(pos, member))
+
+#define spa_list_for_each(pos, head, member) \
+ spa_list_for_each_next(pos, head, head, member)
+
+#define spa_list_for_each_reverse(pos, head, member) \
+ spa_list_for_each_prev(pos, head, head, member)
+
+#define spa_list_for_each_safe_next(pos, tmp, head, curr, member) \
+ for (pos = spa_list_first(curr, __typeof__(*pos), member); \
+ tmp = spa_list_next(pos, member), \
+ !spa_list_is_end(pos, head, member); \
+ pos = tmp)
+
+#define spa_list_for_each_safe_prev(pos, tmp, head, curr, member) \
+ for (pos = spa_list_last(curr, __typeof__(*pos), member); \
+ tmp = spa_list_prev(pos, member), \
+ !spa_list_is_end(pos, head, member); \
+ pos = tmp)
+
+#define spa_list_for_each_safe(pos, tmp, head, member) \
+ spa_list_for_each_safe_next(pos, tmp, head, head, member)
+
+#define spa_list_for_each_safe_reverse(pos, tmp, head, member) \
+ spa_list_for_each_safe_prev(pos, tmp, head, head, member)
+
+#define spa_list_cursor_start(cursor, head, member) \
+ spa_list_prepend(head, &(cursor).member)
+
+#define spa_list_for_each_cursor(pos, cursor, head, member) \
+ for(pos = spa_list_first(&(cursor).member, __typeof__(*(pos)), member); \
+ spa_list_remove(&(pos)->member), \
+ spa_list_append(&(cursor).member, &(pos)->member), \
+ !spa_list_is_end(pos, head, member); \
+ pos = spa_list_next(&cursor, member))
+
+#define spa_list_cursor_end(cursor, member) \
+ spa_list_remove(&(cursor).member)
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_LIST_H */
diff --git a/3rdparty/pipewire/spa/utils/type.h b/3rdparty/pipewire/spa/utils/type.h
new file mode 100644
index 000000000..fb295653f
--- /dev/null
+++ b/3rdparty/pipewire/spa/utils/type.h
@@ -0,0 +1,138 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_TYPE_H
+#define SPA_TYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/defs.h>
+
+enum {
+ /* Basic types */
+ SPA_TYPE_START = 0x00000,
+ SPA_TYPE_None,
+ SPA_TYPE_Bool,
+ SPA_TYPE_Id,
+ SPA_TYPE_Int,
+ SPA_TYPE_Long,
+ SPA_TYPE_Float,
+ SPA_TYPE_Double,
+ SPA_TYPE_String,
+ SPA_TYPE_Bytes,
+ SPA_TYPE_Rectangle,
+ SPA_TYPE_Fraction,
+ SPA_TYPE_Bitmap,
+ SPA_TYPE_Array,
+ SPA_TYPE_Struct,
+ SPA_TYPE_Object,
+ SPA_TYPE_Sequence,
+ SPA_TYPE_Pointer,
+ SPA_TYPE_Fd,
+ SPA_TYPE_Choice,
+ SPA_TYPE_Pod,
+ SPA_TYPE_LAST, /**< not part of ABI */
+
+ /* Pointers */
+ SPA_TYPE_POINTER_START = 0x10000,
+ SPA_TYPE_POINTER_Buffer,
+ SPA_TYPE_POINTER_Meta,
+ SPA_TYPE_POINTER_Dict,
+ SPA_TYPE_POINTER_LAST, /**< not part of ABI */
+
+ /* Events */
+ SPA_TYPE_EVENT_START = 0x20000,
+ SPA_TYPE_EVENT_Device,
+ SPA_TYPE_EVENT_Node,
+ SPA_TYPE_EVENT_LAST, /**< not part of ABI */
+
+ /* Commands */
+ SPA_TYPE_COMMAND_START = 0x30000,
+ SPA_TYPE_COMMAND_Device,
+ SPA_TYPE_COMMAND_Node,
+ SPA_TYPE_COMMAND_LAST, /**< not part of ABI */
+
+ /* Objects */
+ SPA_TYPE_OBJECT_START = 0x40000,
+ SPA_TYPE_OBJECT_PropInfo,
+ SPA_TYPE_OBJECT_Props,
+ SPA_TYPE_OBJECT_Format,
+ SPA_TYPE_OBJECT_ParamBuffers,
+ SPA_TYPE_OBJECT_ParamMeta,
+ SPA_TYPE_OBJECT_ParamIO,
+ SPA_TYPE_OBJECT_ParamProfile,
+ SPA_TYPE_OBJECT_ParamPortConfig,
+ SPA_TYPE_OBJECT_ParamRoute,
+ SPA_TYPE_OBJECT_Profiler,
+ SPA_TYPE_OBJECT_LAST, /**< not part of ABI */
+
+ /* vendor extensions */
+ SPA_TYPE_VENDOR_PipeWire = 0x02000000,
+
+ SPA_TYPE_VENDOR_Other = 0x7f000000,
+};
+
+#define SPA_TYPE_INFO_BASE "Spa:"
+
+#define SPA_TYPE_INFO_Flags SPA_TYPE_INFO_BASE "Flags"
+#define SPA_TYPE_INFO_FLAGS_BASE SPA_TYPE_INFO_Flags ":"
+
+#define SPA_TYPE_INFO_Enum SPA_TYPE_INFO_BASE "Enum"
+#define SPA_TYPE_INFO_ENUM_BASE SPA_TYPE_INFO_Enum ":"
+
+#define SPA_TYPE_INFO_Pod SPA_TYPE_INFO_BASE "Pod"
+#define SPA_TYPE_INFO_POD_BASE SPA_TYPE_INFO_Pod ":"
+
+#define SPA_TYPE_INFO_Struct SPA_TYPE_INFO_POD_BASE "Struct"
+#define SPA_TYPE_INFO_STRUCT_BASE SPA_TYPE_INFO_Struct ":"
+
+#define SPA_TYPE_INFO_Object SPA_TYPE_INFO_POD_BASE "Object"
+#define SPA_TYPE_INFO_OBJECT_BASE SPA_TYPE_INFO_Object ":"
+
+#define SPA_TYPE_INFO_Pointer SPA_TYPE_INFO_BASE "Pointer"
+#define SPA_TYPE_INFO_POINTER_BASE SPA_TYPE_INFO_Pointer ":"
+
+#define SPA_TYPE_INFO_Interface SPA_TYPE_INFO_POINTER_BASE "Interface"
+#define SPA_TYPE_INFO_INTERFACE_BASE SPA_TYPE_INFO_Interface ":"
+
+#define SPA_TYPE_INFO_Event SPA_TYPE_INFO_OBJECT_BASE "Event"
+#define SPA_TYPE_INFO_EVENT_BASE SPA_TYPE_INFO_Event ":"
+
+#define SPA_TYPE_INFO_Command SPA_TYPE_INFO_OBJECT_BASE "Command"
+#define SPA_TYPE_INFO_COMMAND_BASE SPA_TYPE_INFO_Command ":"
+
+struct spa_type_info {
+ uint32_t type;
+ uint32_t parent;
+ const char *name;
+ const struct spa_type_info *values;
+};
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_TYPE_H */