summaryrefslogtreecommitdiffstats
path: root/third_party/pipewire/pipewire
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/pipewire/pipewire')
-rw-r--r--third_party/pipewire/pipewire/array.h176
-rw-r--r--third_party/pipewire/pipewire/buffers.h74
-rw-r--r--third_party/pipewire/pipewire/client.h186
-rw-r--r--third_party/pipewire/pipewire/conf.h43
-rw-r--r--third_party/pipewire/pipewire/context.h192
-rw-r--r--third_party/pipewire/pipewire/control.h82
-rw-r--r--third_party/pipewire/pipewire/core.h629
-rw-r--r--third_party/pipewire/pipewire/data-loop.h113
-rw-r--r--third_party/pipewire/pipewire/device.h178
-rw-r--r--third_party/pipewire/pipewire/factory.h123
-rw-r--r--third_party/pipewire/pipewire/filter.h250
-rw-r--r--third_party/pipewire/pipewire/global.h165
-rw-r--r--third_party/pipewire/pipewire/i18n.h56
-rw-r--r--third_party/pipewire/pipewire/impl-client.h185
-rw-r--r--third_party/pipewire/pipewire/impl-core.h104
-rw-r--r--third_party/pipewire/pipewire/impl-device.h116
-rw-r--r--third_party/pipewire/pipewire/impl-factory.h131
-rw-r--r--third_party/pipewire/pipewire/impl-link.h126
-rw-r--r--third_party/pipewire/pipewire/impl-metadata.h114
-rw-r--r--third_party/pipewire/pipewire/impl-module.h117
-rw-r--r--third_party/pipewire/pipewire/impl-node.h186
-rw-r--r--third_party/pipewire/pipewire/impl-port.h144
-rw-r--r--third_party/pipewire/pipewire/impl.h62
-rw-r--r--third_party/pipewire/pipewire/keys.h344
-rw-r--r--third_party/pipewire/pipewire/link.h148
-rw-r--r--third_party/pipewire/pipewire/log.h182
-rw-r--r--third_party/pipewire/pipewire/loop.h90
-rw-r--r--third_party/pipewire/pipewire/main-loop.h86
-rw-r--r--third_party/pipewire/pipewire/map.h252
-rw-r--r--third_party/pipewire/pipewire/mem.h212
-rw-r--r--third_party/pipewire/pipewire/module.h121
-rw-r--r--third_party/pipewire/pipewire/node.h216
-rw-r--r--third_party/pipewire/pipewire/permission.h86
-rw-r--r--third_party/pipewire/pipewire/pipewire.h122
-rw-r--r--third_party/pipewire/pipewire/port.h179
-rw-r--r--third_party/pipewire/pipewire/private.h1308
-rw-r--r--third_party/pipewire/pipewire/properties.h199
-rw-r--r--third_party/pipewire/pipewire/protocol.h162
-rw-r--r--third_party/pipewire/pipewire/proxy.h219
-rw-r--r--third_party/pipewire/pipewire/resource.h174
-rw-r--r--third_party/pipewire/pipewire/stream.h521
-rw-r--r--third_party/pipewire/pipewire/thread-loop.h175
-rw-r--r--third_party/pipewire/pipewire/thread.h65
-rw-r--r--third_party/pipewire/pipewire/type.h65
-rw-r--r--third_party/pipewire/pipewire/utils.h101
-rw-r--r--third_party/pipewire/pipewire/version.h68
-rw-r--r--third_party/pipewire/pipewire/work-queue.h71
47 files changed, 8718 insertions, 0 deletions
diff --git a/third_party/pipewire/pipewire/array.h b/third_party/pipewire/pipewire/array.h
new file mode 100644
index 0000000000..4e2dd72ebb
--- /dev/null
+++ b/third_party/pipewire/pipewire/array.h
@@ -0,0 +1,176 @@
+/* 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_ARRAY_H
+#define PIPEWIRE_ARRAY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <errno.h>
+
+#include <spa/utils/defs.h>
+
+/** \defgroup pw_array Array
+ *
+ * \brief An array object
+ *
+ * The array is a dynamically resizable data structure that can
+ * hold items of the same size.
+ */
+
+/**
+ * \addtogroup pw_array
+ * \{
+ */
+struct pw_array {
+ void *data; /**< pointer to array data */
+ size_t size; /**< length of array in bytes */
+ size_t alloc; /**< number of allocated memory in \a data */
+ size_t extend; /**< number of bytes to extend with */
+};
+
+#define PW_ARRAY_INIT(extend) (struct pw_array) { NULL, 0, 0, extend }
+
+#define pw_array_get_len_s(a,s) ((a)->size / (s))
+#define pw_array_get_unchecked_s(a,idx,s,t) SPA_PTROFF((a)->data,(idx)*(s),t)
+#define pw_array_check_index_s(a,idx,s) ((idx) < pw_array_get_len_s(a,s))
+
+/** Get the number of items of type \a t in array */
+#define pw_array_get_len(a,t) pw_array_get_len_s(a,sizeof(t))
+/** Get the item with index \a idx and type \a t from array */
+#define pw_array_get_unchecked(a,idx,t) pw_array_get_unchecked_s(a,idx,sizeof(t),t)
+/** Check if an item with index \a idx and type \a t exist in array */
+#define pw_array_check_index(a,idx,t) pw_array_check_index_s(a,idx,sizeof(t))
+
+#define pw_array_first(a) ((a)->data)
+#define pw_array_end(a) SPA_PTROFF((a)->data, (a)->size, void)
+#define pw_array_check(a,p) (SPA_PTROFF(p,sizeof(*p),void) <= pw_array_end(a))
+
+#define pw_array_for_each(pos, array) \
+ for (pos = (__typeof__(pos)) pw_array_first(array); \
+ pw_array_check(array, pos); \
+ (pos)++)
+
+#define pw_array_consume(pos, array) \
+ for (pos = (__typeof__(pos)) pw_array_first(array); \
+ pw_array_check(array, pos); \
+ pos = (__typeof__(pos)) pw_array_first(array))
+
+#define pw_array_remove(a,p) \
+({ \
+ (a)->size -= sizeof(*(p)); \
+ memmove(p, SPA_PTROFF((p), sizeof(*(p)), void), \
+ SPA_PTRDIFF(pw_array_end(a),(p))); \
+})
+
+/** Initialize the array with given extend */
+static inline void pw_array_init(struct pw_array *arr, size_t extend)
+{
+ arr->data = NULL;
+ arr->size = arr->alloc = 0;
+ arr->extend = extend;
+}
+
+/** Clear the array */
+static inline void pw_array_clear(struct pw_array *arr)
+{
+ free(arr->data);
+ pw_array_init(arr, arr->extend);
+}
+
+/** Reset the array */
+static inline void pw_array_reset(struct pw_array *arr)
+{
+ arr->size = 0;
+}
+
+/** Make sure \a size bytes can be added to the array */
+static inline int pw_array_ensure_size(struct pw_array *arr, size_t size)
+{
+ size_t alloc, need;
+
+ alloc = arr->alloc;
+ need = arr->size + size;
+
+ if (SPA_UNLIKELY(alloc < need)) {
+ void *data;
+ alloc = SPA_MAX(alloc, arr->extend);
+ spa_assert(alloc != 0); /* forgot pw_array_init */
+ while (alloc < need)
+ alloc *= 2;
+ if (SPA_UNLIKELY((data = realloc(arr->data, alloc)) == NULL))
+ return -errno;
+ arr->data = data;
+ arr->alloc = alloc;
+ }
+ return 0;
+}
+
+/** Add \a ref size bytes to \a arr. A pointer to memory that can
+ * hold at least \a size bytes is returned */
+static inline void *pw_array_add(struct pw_array *arr, size_t size)
+{
+ void *p;
+
+ if (pw_array_ensure_size(arr, size) < 0)
+ return NULL;
+
+ p = SPA_PTROFF(arr->data, arr->size, void);
+ arr->size += size;
+
+ return p;
+}
+
+/** Add \a ref size bytes to \a arr. When there is not enough memory to
+ * hold \a size bytes, NULL is returned */
+static inline void *pw_array_add_fixed(struct pw_array *arr, size_t size)
+{
+ void *p;
+
+ if (SPA_UNLIKELY(arr->alloc < arr->size + size)) {
+ errno = ENOSPC;
+ return NULL;
+ }
+
+ p = SPA_PTROFF(arr->data, arr->size, void);
+ arr->size += size;
+
+ return p;
+}
+
+/** Add a pointer to array */
+#define pw_array_add_ptr(a,p) \
+ *((void**) pw_array_add(a, sizeof(void*))) = (p)
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PIPEWIRE_ARRAY_H */
diff --git a/third_party/pipewire/pipewire/buffers.h b/third_party/pipewire/pipewire/buffers.h
new file mode 100644
index 0000000000..df72bf3f8e
--- /dev/null
+++ b/third_party/pipewire/pipewire/buffers.h
@@ -0,0 +1,74 @@
+/* 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_BUFFERS_H
+#define PIPEWIRE_BUFFERS_H
+
+#include <spa/node/node.h>
+
+#include <pipewire/context.h>
+#include <pipewire/mem.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup pw_buffers Buffers
+ * Buffer handling
+ */
+
+/**
+ * \addtogroup pw_buffers
+ * \{
+ */
+
+#define PW_BUFFERS_FLAG_NONE 0
+#define PW_BUFFERS_FLAG_NO_MEM (1<<0) /**< don't allocate buffer memory */
+#define PW_BUFFERS_FLAG_SHARED (1<<1) /**< buffers can be shared */
+#define PW_BUFFERS_FLAG_DYNAMIC (1<<2) /**< buffers have dynamic data */
+#define PW_BUFFERS_FLAG_SHARED_MEM (1<<3) /**< buffers need shared memory */
+
+struct pw_buffers {
+ struct pw_memblock *mem; /**< allocated buffer memory */
+ struct spa_buffer **buffers; /**< port buffers */
+ uint32_t n_buffers; /**< number of port buffers */
+ uint32_t flags; /**< flags */
+};
+
+int pw_buffers_negotiate(struct pw_context *context, uint32_t flags,
+ struct spa_node *outnode, uint32_t out_port_id,
+ struct spa_node *innode, uint32_t in_port_id,
+ struct pw_buffers *result);
+
+void pw_buffers_clear(struct pw_buffers *buffers);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_BUFFERS_H */
diff --git a/third_party/pipewire/pipewire/client.h b/third_party/pipewire/pipewire/client.h
new file mode 100644
index 0000000000..2ed4c5b7bf
--- /dev/null
+++ b/third_party/pipewire/pipewire/client.h
@@ -0,0 +1,186 @@
+/* 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_CLIENT_H
+#define PIPEWIRE_CLIENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/defs.h>
+#include <spa/param/param.h>
+
+#include <pipewire/proxy.h>
+#include <pipewire/permission.h>
+
+/** \defgroup pw_client Client
+ * Client interface
+ */
+
+/**
+ * \addtogroup pw_client
+ * \{
+ */
+#define PW_TYPE_INTERFACE_Client PW_TYPE_INFO_INTERFACE_BASE "Client"
+
+#define PW_VERSION_CLIENT 3
+struct pw_client;
+
+/* default ID of the current client after connect */
+#define PW_ID_CLIENT 1
+
+/** The client information. Extra information can be added in later versions */
+struct pw_client_info {
+ uint32_t id; /**< id of the global */
+#define PW_CLIENT_CHANGE_MASK_PROPS (1 << 0)
+#define PW_CLIENT_CHANGE_MASK_ALL ((1 << 1)-1)
+ uint64_t change_mask; /**< bitfield of changed fields since last call */
+ struct spa_dict *props; /**< extra properties */
+};
+
+/** Update an existing \ref pw_client_info with \a update with reset */
+struct pw_client_info *
+pw_client_info_update(struct pw_client_info *info,
+ const struct pw_client_info *update);
+/** Merge an existing \ref pw_client_info with \a update */
+struct pw_client_info *
+pw_client_info_merge(struct pw_client_info *info,
+ const struct pw_client_info *update, bool reset);
+/** Free a \ref pw_client_info */
+void pw_client_info_free(struct pw_client_info *info);
+
+
+#define PW_CLIENT_EVENT_INFO 0
+#define PW_CLIENT_EVENT_PERMISSIONS 1
+#define PW_CLIENT_EVENT_NUM 2
+
+/** Client events */
+struct pw_client_events {
+#define PW_VERSION_CLIENT_EVENTS 0
+ uint32_t version;
+ /**
+ * Notify client info
+ *
+ * \param info info about the client
+ */
+ void (*info) (void *data, const struct pw_client_info *info);
+ /**
+ * Notify a client permission
+ *
+ * Event emitted as a result of the get_permissions method.
+ *
+ * \param default_permissions the default permissions
+ * \param index the index of the first permission entry
+ * \param n_permissions the number of permissions
+ * \param permissions the permissions
+ */
+ void (*permissions) (void *data,
+ uint32_t index,
+ uint32_t n_permissions,
+ const struct pw_permission *permissions);
+};
+
+
+#define PW_CLIENT_METHOD_ADD_LISTENER 0
+#define PW_CLIENT_METHOD_ERROR 1
+#define PW_CLIENT_METHOD_UPDATE_PROPERTIES 2
+#define PW_CLIENT_METHOD_GET_PERMISSIONS 3
+#define PW_CLIENT_METHOD_UPDATE_PERMISSIONS 4
+#define PW_CLIENT_METHOD_NUM 5
+
+/** Client methods */
+struct pw_client_methods {
+#define PW_VERSION_CLIENT_METHODS 0
+ uint32_t version;
+
+ int (*add_listener) (void *object,
+ struct spa_hook *listener,
+ const struct pw_client_events *events,
+ void *data);
+ /**
+ * Send an error to a client
+ *
+ * \param id the global id to report the error on
+ * \param res an errno style error code
+ * \param message an error string
+ */
+ int (*error) (void *object, uint32_t id, int res, const char *message);
+ /**
+ * Update client properties
+ *
+ * \param props new properties
+ */
+ int (*update_properties) (void *object, const struct spa_dict *props);
+
+ /**
+ * Get client permissions
+ *
+ * A permissions event will be emitted with the permissions.
+ *
+ * \param index the first index to query, 0 for first
+ * \param num the maximum number of items to get
+ */
+ int (*get_permissions) (void *object, uint32_t index, uint32_t num);
+ /**
+ * Manage the permissions of the global objects for this
+ * client
+ *
+ * Update the permissions of the global objects using the
+ * provided array with permissions
+ *
+ * Globals can use the default permissions or can have specific
+ * permissions assigned to them.
+ *
+ * \param n_permissions number of permissions
+ * \param permissions array of permissions
+ */
+ int (*update_permissions) (void *object, uint32_t n_permissions,
+ const struct pw_permission *permissions);
+};
+
+#define pw_client_method(o,method,version,...) \
+({ \
+ int _res = -ENOTSUP; \
+ spa_interface_call_res((struct spa_interface*)o, \
+ struct pw_client_methods, _res, \
+ method, version, ##__VA_ARGS__); \
+ _res; \
+})
+
+#define pw_client_add_listener(c,...) pw_client_method(c,add_listener,0,__VA_ARGS__)
+#define pw_client_error(c,...) pw_client_method(c,error,0,__VA_ARGS__)
+#define pw_client_update_properties(c,...) pw_client_method(c,update_properties,0,__VA_ARGS__)
+#define pw_client_get_permissions(c,...) pw_client_method(c,get_permissions,0,__VA_ARGS__)
+#define pw_client_update_permissions(c,...) pw_client_method(c,update_permissions,0,__VA_ARGS__)
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PIPEWIRE_CLIENT_H */
diff --git a/third_party/pipewire/pipewire/conf.h b/third_party/pipewire/pipewire/conf.h
new file mode 100644
index 0000000000..459b3b6a85
--- /dev/null
+++ b/third_party/pipewire/pipewire/conf.h
@@ -0,0 +1,43 @@
+/* PipeWire
+ *
+ * Copyright © 2021 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.
+ */
+
+#include <pipewire/context.h>
+
+/** \defgroup pw_conf Configuration
+ * Loading/saving properties from/to configuration files.
+ */
+
+/**
+ * \addtogroup pw_conf
+ * \{
+ */
+
+int pw_conf_load_conf(const char *prefix, const char *name, struct pw_properties *conf);
+int pw_conf_load_state(const char *prefix, const char *name, struct pw_properties *conf);
+int pw_conf_save_state(const char *prefix, const char *name, const struct pw_properties *conf);
+
+
+/**
+ * \}
+ */
diff --git a/third_party/pipewire/pipewire/context.h b/third_party/pipewire/pipewire/context.h
new file mode 100644
index 0000000000..31292c4635
--- /dev/null
+++ b/third_party/pipewire/pipewire/context.h
@@ -0,0 +1,192 @@
+/* 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>
+
+/** \defgroup pw_context Context
+ *
+ * \brief The PipeWire 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 \ref page_core_api).
+ *
+ * - Export a local implementation of an object to another
+ * instance.
+ */
+
+/**
+ * \addtogroup pw_context
+ * @{
+ */
+struct pw_context;
+
+struct pw_global;
+struct pw_impl_client;
+
+#include <pipewire/core.h>
+#include <pipewire/loop.h>
+#include <pipewire/properties.h>
+
+/** 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, deprecated,
+ * use pw_context_conf_section_for_each(). */
+const char *pw_context_get_conf_section(struct pw_context *context, const char *section);
+/** Parse a standard config section for this context. Since 0.3.22 */
+int pw_context_parse_conf_section(struct pw_context *context,
+ struct pw_properties *conf, const char *section);
+
+/** update properties from a section into props. Since 0.3.45 */
+int pw_context_conf_update_props(struct pw_context *context, const char *section,
+ struct pw_properties *props);
+/** emit callback for all config sections. Since 0.3.45 */
+int pw_context_conf_section_for_each(struct pw_context *context, const char *section,
+ int (*callback) (void *data, const char *location, const char *section,
+ const char *str, size_t len),
+ void *data);
+/** emit callback for all matched properties. Since 0.3.46 */
+int pw_context_conf_section_match_rules(struct pw_context *context, const char *section,
+ const struct spa_dict *props,
+ int (*callback) (void *data, const char *location, const char *action,
+ const char *str, size_t len),
+ void *data);
+
+/** 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,
+ 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/third_party/pipewire/pipewire/control.h b/third_party/pipewire/pipewire/control.h
new file mode 100644
index 0000000000..92d89a1538
--- /dev/null
+++ b/third_party/pipewire/pipewire/control.h
@@ -0,0 +1,82 @@
+/* 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_CONTROL_H
+#define PIPEWIRE_CONTROL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/hook.h>
+
+/** \defgroup pw_control Control
+ *
+ * \brief A control can be used to control a port property.
+ */
+
+/**
+ * \addtogroup pw_control
+ * \{
+ */
+struct pw_control;
+
+#include <pipewire/impl.h>
+
+/** Port events, use \ref pw_control_add_listener */
+struct pw_control_events {
+#define PW_VERSION_CONTROL_EVENTS 0
+ uint32_t version;
+
+ /** The control is destroyed */
+ void (*destroy) (void *data);
+
+ /** The control is freed */
+ void (*free) (void *data);
+
+ /** control is linked to another control */
+ void (*linked) (void *data, struct pw_control *other);
+ /** control is unlinked from another control */
+ void (*unlinked) (void *data, struct pw_control *other);
+
+};
+
+/** Get the control parent port or NULL when not set */
+struct pw_impl_port *pw_control_get_port(struct pw_control *control);
+
+/** Add an event listener on the control */
+void pw_control_add_listener(struct pw_control *control,
+ struct spa_hook *listener,
+ const struct pw_control_events *events,
+ void *data);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_CONTROL_H */
diff --git a/third_party/pipewire/pipewire/core.h b/third_party/pipewire/pipewire/core.h
new file mode 100644
index 0000000000..604e7ccdfc
--- /dev/null
+++ b/third_party/pipewire/pipewire/core.h
@@ -0,0 +1,629 @@
+/* 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>
+
+/** \defgroup pw_core Core
+ *
+ * \brief The core global object.
+ *
+ * This is a special singleton object. It is used for internal PipeWire
+ * protocol features. Connecting to a PipeWire instance returns one core
+ * object, the caller should then register event listeners
+ * using \ref pw_core_add_listener.
+ *
+ * Updates to the core object are then provided through the \ref
+ * pw_core_events interface. See \ref page_tutorial2 for an example.
+ */
+
+/**
+ * \addtogroup pw_core
+ * \{
+ */
+#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 may be added in later versions,
+ * clients must not assume a constant struct size */
+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 an existing \ref pw_core_info with \a update with reset */
+struct pw_core_info *
+pw_core_info_update(struct pw_core_info *info,
+ const struct pw_core_info *update);
+/** Update an existing \ref pw_core_info with \a update */
+struct pw_core_info *
+pw_core_info_merge(struct pw_core_info *info,
+ const struct pw_core_info *update, bool reset);
+/** Free a \ref pw_core_info */
+void pw_core_info_free(struct pw_core_info *info);
+
+/** 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
+ */
+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 *data, 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 *data, 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 *data, 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 *data, 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 *data, uint32_t id);
+
+ /**
+ * Notify an object binding
+ *
+ * This event is emitted when a local object ID is bound to a
+ * global ID. It is emitted before the global becomes visible in the
+ * registry.
+ *
+ * \param id bound object ID
+ * \param global_id the global id bound to
+ */
+ void (*bound_id) (void *data, 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 *data, 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 *data, 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__)
+
+/**
+ * \}
+ */
+
+/** \defgroup pw_registry Registry
+ *
+ * The registry object is a singleton object that keeps track of
+ * global objects on the PipeWire instance. See also \ref pw_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.
+ */
+
+/**
+ * \addtogroup pw_registry
+ * \{
+ */
+
+#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 *data, 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 *data, 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__)
+
+/**
+ * \}
+ */
+
+/**
+ * \addtogroup pw_core
+ * \{
+ */
+
+/** Connect to a PipeWire instance
+ *
+ * \param context a \ref pw_context
+ * \param properties optional properties, ownership of the properties is
+ * taken.
+ * \param user_data_size extra user data size
+ *
+ * \return a \ref pw_core on success or NULL with errno set on error. The core
+ * will have an id of \ref PW_ID_CORE (0)
+ */
+struct pw_core *
+pw_context_connect(struct pw_context *context,
+ struct pw_properties *properties,
+ size_t user_data_size);
+
+/** Connect to a PipeWire instance on the given socket
+ *
+ * \param context a \ref pw_context
+ * \param fd the connected socket to use, the socket will be closed
+ * automatically on disconnect or error.
+ * \param properties optional properties, ownership of the properties is
+ * taken.
+ * \param user_data_size extra user data size
+ *
+ * \return a \ref pw_core on success or NULL with errno set on error */
+struct pw_core *
+pw_context_connect_fd(struct pw_context *context,
+ int fd,
+ struct pw_properties *properties,
+ size_t user_data_size);
+
+/** Connect to a given PipeWire instance
+ *
+ * \param context a \ref pw_context to connect to
+ * \param properties optional properties, ownership of the properties is
+ * taken.
+ * \param user_data_size extra user data size
+ *
+ * \return a \ref pw_core on success or NULL with errno set on error */
+struct pw_core *
+pw_context_connect_self(struct pw_context *context,
+ struct pw_properties *properties,
+ size_t 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/third_party/pipewire/pipewire/data-loop.h b/third_party/pipewire/pipewire/data-loop.h
new file mode 100644
index 0000000000..a459c19e54
--- /dev/null
+++ b/third_party/pipewire/pipewire/data-loop.h
@@ -0,0 +1,113 @@
+/* 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_DATA_LOOP_H
+#define PIPEWIRE_DATA_LOOP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/hook.h>
+#include <spa/support/thread.h>
+
+/** \defgroup pw_data_loop Data Loop
+ *
+ * \brief PipeWire rt-loop object
+ *
+ * This loop starts a new real-time thread that
+ * is designed to run the processing graph.
+ */
+
+/**
+ * \addtogroup pw_data_loop
+ * \{
+ */
+struct pw_data_loop;
+
+#include <pipewire/loop.h>
+#include <pipewire/properties.h>
+
+/** Loop events, use \ref pw_data_loop_add_listener to add a listener */
+struct pw_data_loop_events {
+#define PW_VERSION_DATA_LOOP_EVENTS 0
+ uint32_t version;
+ /** The loop is destroyed */
+ void (*destroy) (void *data);
+};
+
+/** Make a new loop. */
+struct pw_data_loop *
+pw_data_loop_new(const struct spa_dict *props);
+
+/** Add an event listener to loop */
+void pw_data_loop_add_listener(struct pw_data_loop *loop,
+ struct spa_hook *listener,
+ const struct pw_data_loop_events *events,
+ void *data);
+
+/** wait for activity on the loop up to \a timeout milliseconds.
+ * Should be called from the loop function */
+int pw_data_loop_wait(struct pw_data_loop *loop, int timeout);
+
+/** make sure the thread will exit. Can be called from a loop callback */
+void pw_data_loop_exit(struct pw_data_loop *loop);
+
+/** Get the loop implementation of this data loop */
+struct pw_loop *
+pw_data_loop_get_loop(struct pw_data_loop *loop);
+
+/** Destroy the loop */
+void pw_data_loop_destroy(struct pw_data_loop *loop);
+
+/** Start the processing thread */
+int pw_data_loop_start(struct pw_data_loop *loop);
+
+/** Stop the processing thread */
+int pw_data_loop_stop(struct pw_data_loop *loop);
+
+/** Check if the current thread is the processing thread */
+bool pw_data_loop_in_thread(struct pw_data_loop *loop);
+/** Get the thread object */
+struct spa_thread *pw_data_loop_get_thread(struct pw_data_loop *loop);
+
+/** invoke func in the context of the thread or in the caller thread when
+ * the loop is not running. Since 0.3.3 */
+int pw_data_loop_invoke(struct pw_data_loop *loop,
+ spa_invoke_func_t func, uint32_t seq, const void *data, size_t size,
+ bool block, void *user_data);
+
+/** Set a custom spa_thread_utils for this loop. Setting NULL restores the
+ * system default implementation. Since 0.3.50 */
+void pw_data_loop_set_thread_utils(struct pw_data_loop *loop,
+ struct spa_thread_utils *impl);
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_DATA_LOOP_H */
diff --git a/third_party/pipewire/pipewire/device.h b/third_party/pipewire/pipewire/device.h
new file mode 100644
index 0000000000..5bcaf80822
--- /dev/null
+++ b/third_party/pipewire/pipewire/device.h
@@ -0,0 +1,178 @@
+/* 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_DEVICE_H
+#define PIPEWIRE_DEVICE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/defs.h>
+#include <spa/utils/hook.h>
+
+#include <pipewire/proxy.h>
+
+/** \defgroup pw_device Device
+ * Device interface
+ */
+
+/**
+ * \addtogroup pw_device
+ * \{
+ */
+
+#define PW_TYPE_INTERFACE_Device PW_TYPE_INFO_INTERFACE_BASE "Device"
+
+#define PW_VERSION_DEVICE 3
+struct pw_device;
+
+/** The device information. Extra information can be added in later versions */
+struct pw_device_info {
+ uint32_t id; /**< id of the global */
+#define PW_DEVICE_CHANGE_MASK_PROPS (1 << 0)
+#define PW_DEVICE_CHANGE_MASK_PARAMS (1 << 1)
+#define PW_DEVICE_CHANGE_MASK_ALL ((1 << 2)-1)
+ uint64_t change_mask; /**< bitfield of changed fields since last call */
+ struct spa_dict *props; /**< extra properties */
+ struct spa_param_info *params; /**< parameters */
+ uint32_t n_params; /**< number of items in \a params */
+};
+
+/** Update and existing \ref pw_device_info with \a update and reset */
+struct pw_device_info *
+pw_device_info_update(struct pw_device_info *info,
+ const struct pw_device_info *update);
+/** Merge and existing \ref pw_device_info with \a update */
+struct pw_device_info *
+pw_device_info_merge(struct pw_device_info *info,
+ const struct pw_device_info *update, bool reset);
+/** Free a \ref pw_device_info */
+void pw_device_info_free(struct pw_device_info *info);
+
+#define PW_DEVICE_EVENT_INFO 0
+#define PW_DEVICE_EVENT_PARAM 1
+#define PW_DEVICE_EVENT_NUM 2
+
+/** Device events */
+struct pw_device_events {
+#define PW_VERSION_DEVICE_EVENTS 0
+ uint32_t version;
+ /**
+ * Notify device info
+ *
+ * \param info info about the device
+ */
+ void (*info) (void *data, const struct pw_device_info *info);
+ /**
+ * Notify a device 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 *data, int seq,
+ uint32_t id, uint32_t index, uint32_t next,
+ const struct spa_pod *param);
+};
+
+
+#define PW_DEVICE_METHOD_ADD_LISTENER 0
+#define PW_DEVICE_METHOD_SUBSCRIBE_PARAMS 1
+#define PW_DEVICE_METHOD_ENUM_PARAMS 2
+#define PW_DEVICE_METHOD_SET_PARAM 3
+#define PW_DEVICE_METHOD_NUM 4
+
+/** Device methods */
+struct pw_device_methods {
+#define PW_VERSION_DEVICE_METHODS 0
+ uint32_t version;
+
+ int (*add_listener) (void *object,
+ struct spa_hook *listener,
+ const struct pw_device_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 device parameters
+ *
+ * Start enumeration of device parameters. For each param, a
+ * param event will be emitted.
+ *
+ * \param seq a sequence number to place in the reply
+ * \param id the parameter id to enum or PW_ID_ANY for all
+ * \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);
+ /**
+ * Set a parameter on the device
+ *
+ * \param id the parameter id to set
+ * \param flags extra parameter flags
+ * \param param the parameter to set
+ */
+ int (*set_param) (void *object, uint32_t id, uint32_t flags,
+ const struct spa_pod *param);
+};
+
+#define pw_device_method(o,method,version,...) \
+({ \
+ int _res = -ENOTSUP; \
+ spa_interface_call_res((struct spa_interface*)o, \
+ struct pw_device_methods, _res, \
+ method, version, ##__VA_ARGS__); \
+ _res; \
+})
+
+#define pw_device_add_listener(c,...) pw_device_method(c,add_listener,0,__VA_ARGS__)
+#define pw_device_subscribe_params(c,...) pw_device_method(c,subscribe_params,0,__VA_ARGS__)
+#define pw_device_enum_params(c,...) pw_device_method(c,enum_params,0,__VA_ARGS__)
+#define pw_device_set_param(c,...) pw_device_method(c,set_param,0,__VA_ARGS__)
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PIPEWIRE_DEVICE_H */
diff --git a/third_party/pipewire/pipewire/factory.h b/third_party/pipewire/pipewire/factory.h
new file mode 100644
index 0000000000..c747dd965d
--- /dev/null
+++ b/third_party/pipewire/pipewire/factory.h
@@ -0,0 +1,123 @@
+/* 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_FACTORY_H
+#define PIPEWIRE_FACTORY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+#include <errno.h>
+
+#include <spa/utils/defs.h>
+#include <spa/utils/hook.h>
+
+#include <pipewire/proxy.h>
+
+/** \defgroup pw_factory Factory
+ * Factory interface
+ */
+
+/**
+ * \addtogroup pw_factory
+ * \{
+ */
+#define PW_TYPE_INTERFACE_Factory PW_TYPE_INFO_INTERFACE_BASE "Factory"
+
+#define PW_VERSION_FACTORY 3
+struct pw_factory;
+
+/** The factory information. Extra information can be added in later versions */
+struct pw_factory_info {
+ uint32_t id; /**< id of the global */
+ const char *name; /**< name the factory */
+ const char *type; /**< type of the objects created by this factory */
+ uint32_t version; /**< version of the objects */
+#define PW_FACTORY_CHANGE_MASK_PROPS (1 << 0)
+#define PW_FACTORY_CHANGE_MASK_ALL ((1 << 1)-1)
+ uint64_t change_mask; /**< bitfield of changed fields since last call */
+ struct spa_dict *props; /**< the properties of the factory */
+};
+
+struct pw_factory_info *
+pw_factory_info_update(struct pw_factory_info *info,
+ const struct pw_factory_info *update);
+struct pw_factory_info *
+pw_factory_info_merge(struct pw_factory_info *info,
+ const struct pw_factory_info *update, bool reset);
+void
+pw_factory_info_free(struct pw_factory_info *info);
+
+
+#define PW_FACTORY_EVENT_INFO 0
+#define PW_FACTORY_EVENT_NUM 1
+
+/** Factory events */
+struct pw_factory_events {
+#define PW_VERSION_FACTORY_EVENTS 0
+ uint32_t version;
+ /**
+ * Notify factory info
+ *
+ * \param info info about the factory
+ */
+ void (*info) (void *data, const struct pw_factory_info *info);
+};
+
+#define PW_FACTORY_METHOD_ADD_LISTENER 0
+#define PW_FACTORY_METHOD_NUM 1
+
+/** Factory methods */
+struct pw_factory_methods {
+#define PW_VERSION_FACTORY_METHODS 0
+ uint32_t version;
+
+ int (*add_listener) (void *object,
+ struct spa_hook *listener,
+ const struct pw_factory_events *events,
+ void *data);
+};
+
+#define pw_factory_method(o,method,version,...) \
+({ \
+ int _res = -ENOTSUP; \
+ spa_interface_call_res((struct spa_interface*)o, \
+ struct pw_factory_methods, _res, \
+ method, version, ##__VA_ARGS__); \
+ _res; \
+})
+
+#define pw_factory_add_listener(c,...) pw_factory_method(c,add_listener,0,__VA_ARGS__)
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PIPEWIRE_FACTORY_H */
diff --git a/third_party/pipewire/pipewire/filter.h b/third_party/pipewire/pipewire/filter.h
new file mode 100644
index 0000000000..255608ab81
--- /dev/null
+++ b/third_party/pipewire/pipewire/filter.h
@@ -0,0 +1,250 @@
+/* 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_FILTER_H
+#define PIPEWIRE_FILTER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup pw_filter Filter
+ *
+ * \brief PipeWire filter object class
+ *
+ * The filter object provides a convenient way to implement
+ * processing filters.
+ *
+ * See also \ref api_pw_core
+ */
+
+/**
+ * \addtogroup pw_filter
+ * \{
+ */
+struct pw_filter;
+
+#include <spa/buffer/buffer.h>
+#include <spa/node/io.h>
+#include <spa/param/param.h>
+#include <spa/pod/command.h>
+
+#include <pipewire/core.h>
+#include <pipewire/stream.h>
+
+/** \enum pw_filter_state The state of a filter */
+enum pw_filter_state {
+ PW_FILTER_STATE_ERROR = -1, /**< the stream is in error */
+ PW_FILTER_STATE_UNCONNECTED = 0, /**< unconnected */
+ PW_FILTER_STATE_CONNECTING = 1, /**< connection is in progress */
+ PW_FILTER_STATE_PAUSED = 2, /**< filter is connected and paused */
+ PW_FILTER_STATE_STREAMING = 3 /**< filter is streaming */
+};
+
+#if 0
+struct pw_buffer {
+ struct spa_buffer *buffer; /**< the spa buffer */
+ void *user_data; /**< user data attached to the buffer */
+ uint64_t size; /**< For input ports, this field is set by pw_filter
+ * with the duration of the buffer in ticks.
+ * For output ports, this field is set by the user.
+ * This field is added for all queued buffers and
+ * returned in the time info. */
+};
+#endif
+
+/** Events for a filter. These events are always called from the mainloop
+ * unless explicitly documented otherwise. */
+struct pw_filter_events {
+#define PW_VERSION_FILTER_EVENTS 1
+ uint32_t version;
+
+ void (*destroy) (void *data);
+ /** when the filter state changes */
+ void (*state_changed) (void *data, enum pw_filter_state old,
+ enum pw_filter_state state, const char *error);
+
+ /** when io changed on a port of the filter (when port_data is NULL). */
+ void (*io_changed) (void *data, void *port_data,
+ uint32_t id, void *area, uint32_t size);
+ /** when a parameter changed on a port of the filter (when port_data is NULL). */
+ void (*param_changed) (void *data, void *port_data,
+ uint32_t id, const struct spa_pod *param);
+
+ /** when a new buffer was created for a port */
+ void (*add_buffer) (void *data, void *port_data, struct pw_buffer *buffer);
+ /** when a buffer was destroyed for a port */
+ void (*remove_buffer) (void *data, void *port_data, struct pw_buffer *buffer);
+
+ /** do processing. 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, struct spa_io_position *position);
+
+ /** The filter is drained */
+ void (*drained) (void *data);
+
+ /** A command notify, Since 0.3.39:1 */
+ void (*command) (void *data, const struct spa_command *command);
+};
+
+/** Convert a filter state to a readable string */
+const char * pw_filter_state_as_string(enum pw_filter_state state);
+
+/** \enum pw_filter_flags Extra flags that can be used in \ref pw_filter_connect() */
+enum pw_filter_flags {
+ PW_FILTER_FLAG_NONE = 0, /**< no flags */
+ PW_FILTER_FLAG_INACTIVE = (1 << 0), /**< start the filter inactive,
+ * pw_filter_set_active() needs to be
+ * called explicitly */
+ PW_FILTER_FLAG_DRIVER = (1 << 1), /**< be a driver */
+ PW_FILTER_FLAG_RT_PROCESS = (1 << 2), /**< call process from the realtime
+ * thread */
+ PW_FILTER_FLAG_CUSTOM_LATENCY = (1 << 3), /**< don't call the default latency algorithm
+ * but emit the param_changed event for the
+ * ports when Latency params are received. */
+};
+
+enum pw_filter_port_flags {
+ PW_FILTER_PORT_FLAG_NONE = 0, /**< no flags */
+ PW_FILTER_PORT_FLAG_MAP_BUFFERS = (1 << 0), /**< mmap the buffers except DmaBuf */
+ PW_FILTER_PORT_FLAG_ALLOC_BUFFERS = (1 << 1), /**< 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_filter
+ * \return a newly allocated \ref pw_filter */
+struct pw_filter *
+pw_filter_new(struct pw_core *core, /**< a \ref pw_core */
+ const char *name, /**< a filter media name */
+ struct pw_properties *props /**< filter properties, ownership is taken */);
+
+struct pw_filter *
+pw_filter_new_simple(struct pw_loop *loop, /**< a \ref pw_loop to use */
+ const char *name, /**< a filter media name */
+ struct pw_properties *props, /**< filter properties, ownership is taken */
+ const struct pw_filter_events *events, /**< filter events */
+ void *data /**< data passed to events */);
+
+/** Destroy a filter */
+void pw_filter_destroy(struct pw_filter *filter);
+
+void pw_filter_add_listener(struct pw_filter *filter,
+ struct spa_hook *listener,
+ const struct pw_filter_events *events,
+ void *data);
+
+enum pw_filter_state pw_filter_get_state(struct pw_filter *filter, const char **error);
+
+const char *pw_filter_get_name(struct pw_filter *filter);
+
+struct pw_core *pw_filter_get_core(struct pw_filter *filter);
+
+/** Connect a filter for processing.
+ * \return 0 on success < 0 on error.
+ *
+ * You should connect to the process event and use pw_filter_dequeue_buffer()
+ * to get the latest metadata and data. */
+int
+pw_filter_connect(struct pw_filter *filter, /**< a \ref pw_filter */
+ enum pw_filter_flags flags, /**< filter flags */
+ const struct spa_pod **params, /**< an array with params. */
+ uint32_t n_params /**< number of items in \a params */);
+
+/** Get the node ID of the filter.
+ * \return node ID. */
+uint32_t
+pw_filter_get_node_id(struct pw_filter *filter);
+
+/** Disconnect \a filter */
+int pw_filter_disconnect(struct pw_filter *filter);
+
+/** add a port to the filter, returns user data of port_data_size. */
+void *pw_filter_add_port(struct pw_filter *filter, /**< a \ref pw_filter */
+ enum pw_direction direction, /**< port direction */
+ enum pw_filter_port_flags flags, /**< port flags */
+ size_t port_data_size, /**< allocated and given to the user as port_data */
+ struct pw_properties *props, /**< port properties, ownership is taken */
+ const struct spa_pod **params, /**< an array of params. The params should
+ * ideally contain the supported formats */
+ uint32_t n_params /**< number of elements in \a params */);
+
+/** remove a port from the filter */
+int pw_filter_remove_port(void *port_data /**< data associated with port */);
+
+/** get properties, port_data of NULL will give global properties */
+const struct pw_properties *pw_filter_get_properties(struct pw_filter *filter,
+ void *port_data);
+
+/** Update properties, use NULL port_data for global filter properties */
+int pw_filter_update_properties(struct pw_filter *filter,
+ void *port_data, const struct spa_dict *dict);
+
+/** Set the filter in error state */
+int pw_filter_set_error(struct pw_filter *filter, /**< a \ref pw_filter */
+ int res, /**< a result code */
+ const char *error, /**< an error message */
+ ...
+ ) SPA_PRINTF_FUNC(3, 4);
+
+/** Update params, use NULL port_data for global filter params */
+int
+pw_filter_update_params(struct pw_filter *filter, /**< a \ref pw_filter */
+ void *port_data, /**< data associated with port */
+ const struct spa_pod **params, /**< an array of params. */
+ uint32_t n_params /**< number of elements in \a params */);
+
+
+/** Query the time on the filter, deprecated, use the spa_io_position in the
+ * process() method for timing information. */
+SPA_DEPRECATED
+int pw_filter_get_time(struct pw_filter *filter, struct pw_time *time);
+
+/** Get a buffer that can be filled for output ports or consumed
+ * for input ports. */
+struct pw_buffer *pw_filter_dequeue_buffer(void *port_data);
+
+/** Submit a buffer for playback or recycle a buffer for capture. */
+int pw_filter_queue_buffer(void *port_data, struct pw_buffer *buffer);
+
+/** Get a data pointer to the buffer data */
+void *pw_filter_get_dsp_buffer(void *port_data, uint32_t n_samples);
+
+/** Activate or deactivate the filter */
+int pw_filter_set_active(struct pw_filter *filter, bool active);
+
+/** Flush a filter. When \a drain is true, the drained callback will
+ * be called when all data is played or recorded */
+int pw_filter_flush(struct pw_filter *filter, bool drain);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_FILTER_H */
diff --git a/third_party/pipewire/pipewire/global.h b/third_party/pipewire/pipewire/global.h
new file mode 100644
index 0000000000..0cf2a7c5d6
--- /dev/null
+++ b/third_party/pipewire/pipewire/global.h
@@ -0,0 +1,165 @@
+/* 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_GLOBAL_H
+#define PIPEWIRE_GLOBAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup pw_global Global
+ *
+ * \brief A global object visible to remote clients
+ *
+ * A global object is visible to remote clients and represents a resource
+ * that can be used or inspected.
+ *
+ * Global objects represent resources that are available on the PipeWire
+ * context and are accessible to remote clients.
+ * Globals come and go when devices or other resources become available for
+ * clients.
+ *
+ * Remote clients receives a list of globals when it binds to the registry
+ * object. See \ref pw_registry.
+ *
+ * A client can bind to a global to send methods or receive events from
+ * the global.
+ *
+ * See \ref page_proxy
+ */
+
+/**
+ * \addtogroup pw_global
+ * \{
+ */
+struct pw_global;
+
+#include <pipewire/impl.h>
+
+typedef int (*pw_global_bind_func_t) (void *object, /**< global object, see \ref pw_global_new */
+ struct pw_impl_client *client, /**< client that binds */
+ uint32_t permissions, /**< permissions for the bind */
+ uint32_t version, /**< client interface version */
+ uint32_t id /**< client proxy id */);
+
+/** Global events, use \ref pw_global_add_listener */
+struct pw_global_events {
+#define PW_VERSION_GLOBAL_EVENTS 0
+ uint32_t version;
+
+ /** The global is destroyed */
+ void (*destroy) (void *data);
+ /** The global is freed */
+ void (*free) (void *data);
+ /** The permissions changed for a client */
+ void (*permissions_changed) (void *data,
+ struct pw_impl_client *client,
+ uint32_t old_permissions,
+ uint32_t new_permissions);
+};
+
+/** Create a new global object */
+struct pw_global *
+pw_global_new(struct pw_context *context, /**< the context */
+ const char *type, /**< the interface type of the global */
+ uint32_t version, /**< the interface version of the global */
+ struct pw_properties *properties, /**< extra properties */
+ pw_global_bind_func_t func, /**< function to bind */
+ void *object /**< global object */);
+
+/** Register a global object to the context registry */
+int pw_global_register(struct pw_global *global);
+
+/** Add an event listener on the global */
+void pw_global_add_listener(struct pw_global *global,
+ struct spa_hook *listener,
+ const struct pw_global_events *events,
+ void *data);
+
+/** Get the permissions of the global for a given client */
+uint32_t pw_global_get_permissions(struct pw_global *global, struct pw_impl_client *client);
+
+/** Get the context object of this global */
+struct pw_context *pw_global_get_context(struct pw_global *global);
+
+/** Get the global type */
+const char *pw_global_get_type(struct pw_global *global);
+
+/** Check a global type */
+bool pw_global_is_type(struct pw_global *global, const char *type);
+
+/** Get the global version */
+uint32_t pw_global_get_version(struct pw_global *global);
+
+/** Get the global properties */
+const struct pw_properties *pw_global_get_properties(struct pw_global *global);
+
+/** Update the global properties, must be done when unregistered */
+int pw_global_update_keys(struct pw_global *global,
+ const struct spa_dict *dict, const char * const keys[]);
+
+/** Get the object associated with the global. This depends on the type of the
+ * global */
+void *pw_global_get_object(struct pw_global *global);
+
+/** Get the unique id of the global */
+uint32_t pw_global_get_id(struct pw_global *global);
+
+/** Get the serial number of the global */
+uint64_t pw_global_get_serial(struct pw_global *global);
+
+/** Add a resource to a global */
+int pw_global_add_resource(struct pw_global *global, struct pw_resource *resource);
+
+/** Iterate all resources added to the global 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
+ * items are iterated. */
+int pw_global_for_each_resource(struct pw_global *global,
+ int (*callback) (void *data, struct pw_resource *resource),
+ void *data);
+
+/** Let a client bind to a global */
+int pw_global_bind(struct pw_global *global,
+ struct pw_impl_client *client,
+ uint32_t permissions,
+ uint32_t version,
+ uint32_t id);
+
+int pw_global_update_permissions(struct pw_global *global, struct pw_impl_client *client,
+ uint32_t old_permissions, uint32_t new_permissions);
+
+/** Destroy a global */
+void pw_global_destroy(struct pw_global *global);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_GLOBAL_H */
diff --git a/third_party/pipewire/pipewire/i18n.h b/third_party/pipewire/pipewire/i18n.h
new file mode 100644
index 0000000000..aa7b0b3101
--- /dev/null
+++ b/third_party/pipewire/pipewire/i18n.h
@@ -0,0 +1,56 @@
+/* PipeWire
+ *
+ * Copyright © 2021 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_I18N_H
+#define PIPEWIRE_I18N_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup pw_gettext Internationalization
+ * Gettext interface
+ */
+
+/**
+ * \addtogroup pw_gettext
+ * \{
+ */
+#include <spa/support/i18n.h>
+
+SPA_FORMAT_ARG_FUNC(1) const char *pw_gettext(const char *msgid);
+SPA_FORMAT_ARG_FUNC(1) const char *pw_ngettext(const char *msgid, const char *msgid_plural, unsigned long int n);
+
+#define _(String) (pw_gettext(String))
+#define N_(String) (String)
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_I18N_H */
diff --git a/third_party/pipewire/pipewire/impl-client.h b/third_party/pipewire/pipewire/impl-client.h
new file mode 100644
index 0000000000..3d20ae610d
--- /dev/null
+++ b/third_party/pipewire/pipewire/impl-client.h
@@ -0,0 +1,185 @@
+/* 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_IMPL_CLIENT_H
+#define PIPEWIRE_IMPL_CLIENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/hook.h>
+
+/** \page page_client_impl Client Implementation
+ *
+ * \section sec_page_client_impl_overview Overview
+ *
+ * The \ref pw_impl_client object is created by a protocol implementation when
+ * a new client connects.
+ *
+ * The client is used to keep track of all resources belonging to one
+ * connection with the PipeWire server.
+ *
+ * \section sec_page_client_impl_credentials Credentials
+ *
+ * The client object will have its credentials filled in by the protocol.
+ * This information is used to check if a resource or action is available
+ * for this client.
+ *
+ * \section sec_page_client_impl_types Types
+ *
+ * The client and server maintain a mapping between the client and server
+ * types. All type ids that are in messages exchanged between the client
+ * and server will automatically be remapped.
+ *
+ * \section sec_page_client_impl_resources Resources
+ *
+ * When a client binds to context global object, a resource is made for this
+ * binding and a unique id is assigned to the resources. The client and
+ * server will use this id as the destination when exchanging messages.
+ * See also \ref pw_resource
+ */
+
+/** \defgroup pw_impl_client Client Impl
+ *
+ * \brief PipeWire client object class
+ *
+ * The client object represents a client connection with the PipeWire
+ * server.
+ *
+ * Each client has its own list of resources it is bound to along with
+ * a mapping between the client types and server types.
+ *
+ * See: \ref page_client_impl
+ */
+
+/**
+ * \addtogroup pw_impl_client
+ * \{
+ */
+struct pw_impl_client;
+
+#include <pipewire/context.h>
+#include <pipewire/global.h>
+#include <pipewire/properties.h>
+#include <pipewire/resource.h>
+#include <pipewire/permission.h>
+
+/** The events that a client can emit */
+struct pw_impl_client_events {
+#define PW_VERSION_IMPL_CLIENT_EVENTS 0
+ uint32_t version;
+
+ /** emitted when the client is destroyed */
+ void (*destroy) (void *data);
+
+ /** emitted right before the client is freed */
+ void (*free) (void *data);
+
+ /** the client is initialized */
+ void (*initialized) (void *data);
+
+ /** emitted when the client info changed */
+ void (*info_changed) (void *data, const struct pw_client_info *info);
+
+ /** emitted when a new resource is added for client */
+ void (*resource_added) (void *data, struct pw_resource *resource);
+
+ /** emitted when a resource is removed */
+ void (*resource_removed) (void *data, struct pw_resource *resource);
+
+ /** emitted when the client becomes busy processing an asynchronous
+ * message. In the busy state no messages should be processed.
+ * Processing should resume when the client becomes not busy */
+ void (*busy_changed) (void *data, bool busy);
+};
+
+/** Create a new client. This is mainly used by protocols. */
+struct pw_impl_client *
+pw_context_create_client(struct pw_impl_core *core, /**< the core object */
+ struct pw_protocol *protocol, /**< the client protocol */
+ struct pw_properties *properties, /**< client properties */
+ size_t user_data_size /**< extra user data size */);
+
+/** Destroy a previously created client */
+void pw_impl_client_destroy(struct pw_impl_client *client);
+
+/** Finish configuration and register a client */
+int pw_impl_client_register(struct pw_impl_client *client, /**< the client to register */
+ struct pw_properties *properties/**< extra properties */);
+
+/** Get the client user data */
+void *pw_impl_client_get_user_data(struct pw_impl_client *client);
+
+/** Get the client information */
+const struct pw_client_info *pw_impl_client_get_info(struct pw_impl_client *client);
+
+/** Update the client properties */
+int pw_impl_client_update_properties(struct pw_impl_client *client, const struct spa_dict *dict);
+
+/** Update the client permissions */
+int pw_impl_client_update_permissions(struct pw_impl_client *client, uint32_t n_permissions,
+ const struct pw_permission *permissions);
+
+/** check if a client has permissions for global_id, Since 0.3.9 */
+int pw_impl_client_check_permissions(struct pw_impl_client *client,
+ uint32_t global_id, uint32_t permissions);
+
+/** Get the client properties */
+const struct pw_properties *pw_impl_client_get_properties(struct pw_impl_client *client);
+
+/** Get the context used to create this client */
+struct pw_context *pw_impl_client_get_context(struct pw_impl_client *client);
+/** Get the protocol used to create this client */
+struct pw_protocol *pw_impl_client_get_protocol(struct pw_impl_client *client);
+
+/** Get the client core resource */
+struct pw_resource *pw_impl_client_get_core_resource(struct pw_impl_client *client);
+
+/** Get a resource with the given id */
+struct pw_resource *pw_impl_client_find_resource(struct pw_impl_client *client, uint32_t id);
+
+/** Get the global associated with this client */
+struct pw_global *pw_impl_client_get_global(struct pw_impl_client *client);
+
+/** listen to events from this client */
+void pw_impl_client_add_listener(struct pw_impl_client *client,
+ struct spa_hook *listener,
+ const struct pw_impl_client_events *events,
+ void *data);
+
+
+/** Mark the client busy. This can be used when an asynchronous operation is
+ * started and no further processing is allowed to happen for the client */
+void pw_impl_client_set_busy(struct pw_impl_client *client, bool busy);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_IMPL_CLIENT_H */
diff --git a/third_party/pipewire/pipewire/impl-core.h b/third_party/pipewire/pipewire/impl-core.h
new file mode 100644
index 0000000000..ec4107e4f7
--- /dev/null
+++ b/third_party/pipewire/pipewire/impl-core.h
@@ -0,0 +1,104 @@
+/* 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_IMPL_CORE_H
+#define PIPEWIRE_IMPL_CORE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup pw_impl_core Core Impl
+ *
+ * \brief PipeWire core interface.
+ *
+ * The core is used to make objects on demand.
+ */
+
+/**
+ * \addtogroup pw_impl_core
+ * \{
+ */
+
+struct pw_impl_core;
+
+#include <pipewire/context.h>
+#include <pipewire/global.h>
+#include <pipewire/properties.h>
+#include <pipewire/resource.h>
+
+/** Factory events, listen to them with \ref pw_impl_core_add_listener */
+struct pw_impl_core_events {
+#define PW_VERSION_IMPL_CORE_EVENTS 0
+ uint32_t version;
+
+ /** the core is destroyed */
+ void (*destroy) (void *data);
+ /** the core is freed */
+ void (*free) (void *data);
+ /** the core is initialized */
+ void (*initialized) (void *data);
+};
+
+struct pw_impl_core *pw_context_create_core(struct pw_context *context,
+ struct pw_properties *properties,
+ size_t user_data_size);
+
+/* get the default core in a context */
+struct pw_impl_core *pw_context_get_default_core(struct pw_context *context);
+
+/** Get the core properties */
+const struct pw_properties *pw_impl_core_get_properties(struct pw_impl_core *core);
+
+/** Get the core information */
+const struct pw_core_info *pw_impl_core_get_info(struct pw_impl_core *core);
+
+/** Update the core properties */
+int pw_impl_core_update_properties(struct pw_impl_core *core, const struct spa_dict *dict);
+
+int pw_impl_core_register(struct pw_impl_core *core,
+ struct pw_properties *properties);
+
+void pw_impl_core_destroy(struct pw_impl_core *core);
+
+void *pw_impl_core_get_user_data(struct pw_impl_core *core);
+
+/** Get the global of this core */
+struct pw_global *pw_impl_core_get_global(struct pw_impl_core *core);
+
+/** Add an event listener */
+void pw_impl_core_add_listener(struct pw_impl_core *core,
+ struct spa_hook *listener,
+ const struct pw_impl_core_events *events,
+ void *data);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_IMPL_CORE_H */
diff --git a/third_party/pipewire/pipewire/impl-device.h b/third_party/pipewire/pipewire/impl-device.h
new file mode 100644
index 0000000000..016d6dc469
--- /dev/null
+++ b/third_party/pipewire/pipewire/impl-device.h
@@ -0,0 +1,116 @@
+/* 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_IMPL_DEVICE_H
+#define PIPEWIRE_IMPL_DEVICE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup pw_impl_device Device Impl
+ *
+ * The device is an object that manages nodes. It typically
+ * corresponds to a physical hardware device but it does not
+ * have to be.
+ *
+ * The purpose of the device is to provide an interface to
+ * dynamically create/remove/configure the nodes it manages.
+ */
+
+/**
+ * \addtogroup pw_impl_device
+ * \{
+ */
+struct pw_impl_device;
+
+#include <spa/monitor/device.h>
+
+#include <pipewire/context.h>
+#include <pipewire/global.h>
+#include <pipewire/properties.h>
+#include <pipewire/resource.h>
+
+/** Device events, listen to them with \ref pw_impl_device_add_listener */
+struct pw_impl_device_events {
+#define PW_VERSION_IMPL_DEVICE_EVENTS 0
+ uint32_t version;
+
+ /** the device is destroyed */
+ void (*destroy) (void *data);
+ /** the device is freed */
+ void (*free) (void *data);
+ /** the device is initialized */
+ void (*initialized) (void *data);
+
+ /** the device info changed */
+ void (*info_changed) (void *data, const struct pw_device_info *info);
+};
+
+struct pw_impl_device *pw_context_create_device(struct pw_context *context,
+ struct pw_properties *properties,
+ size_t user_data_size);
+
+int pw_impl_device_register(struct pw_impl_device *device,
+ struct pw_properties *properties);
+
+void pw_impl_device_destroy(struct pw_impl_device *device);
+
+void *pw_impl_device_get_user_data(struct pw_impl_device *device);
+
+/** Set the device implementation */
+int pw_impl_device_set_implementation(struct pw_impl_device *device, struct spa_device *spa_device);
+/** Get the device implementation */
+struct spa_device *pw_impl_device_get_implementation(struct pw_impl_device *device);
+
+/** Get the global of this device */
+struct pw_global *pw_impl_device_get_global(struct pw_impl_device *device);
+
+/** Add an event listener */
+void pw_impl_device_add_listener(struct pw_impl_device *device,
+ struct spa_hook *listener,
+ const struct pw_impl_device_events *events,
+ void *data);
+
+int pw_impl_device_update_properties(struct pw_impl_device *device, const struct spa_dict *dict);
+
+const struct pw_properties *pw_impl_device_get_properties(struct pw_impl_device *device);
+
+int pw_impl_device_for_each_param(struct pw_impl_device *device,
+ int seq, uint32_t param_id,
+ uint32_t index, uint32_t max,
+ const struct spa_pod *filter,
+ int (*callback) (void *data, int seq,
+ uint32_t id, uint32_t index, uint32_t next,
+ struct spa_pod *param),
+ void *data);
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_IMPL_DEVICE_H */
diff --git a/third_party/pipewire/pipewire/impl-factory.h b/third_party/pipewire/pipewire/impl-factory.h
new file mode 100644
index 0000000000..f3cc54669f
--- /dev/null
+++ b/third_party/pipewire/pipewire/impl-factory.h
@@ -0,0 +1,131 @@
+/* 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_IMPL_FACTORY_H
+#define PIPEWIRE_IMPL_FACTORY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup pw_impl_factory Factory Impl
+ *
+ * The factory is used to make objects on demand.
+ */
+
+/**
+ * \addtogroup pw_impl_factory
+ * \{
+ */
+struct pw_impl_factory;
+
+#include <pipewire/context.h>
+#include <pipewire/impl-client.h>
+#include <pipewire/global.h>
+#include <pipewire/properties.h>
+#include <pipewire/resource.h>
+
+/** Factory events, listen to them with \ref pw_impl_factory_add_listener */
+struct pw_impl_factory_events {
+#define PW_VERSION_IMPL_FACTORY_EVENTS 0
+ uint32_t version;
+
+ /** the factory is destroyed */
+ void (*destroy) (void *data);
+ /** the factory is freed */
+ void (*free) (void *data);
+ /** the factory is initialized */
+ void (*initialized) (void *data);
+};
+
+struct pw_impl_factory_implementation {
+#define PW_VERSION_IMPL_FACTORY_IMPLEMENTATION 0
+ uint32_t version;
+
+ /** The function to create an object from this factory */
+ void *(*create_object) (void *data,
+ struct pw_resource *resource,
+ const char *type,
+ uint32_t version,
+ struct pw_properties *properties,
+ uint32_t new_id);
+};
+
+struct pw_impl_factory *pw_context_create_factory(struct pw_context *context,
+ const char *name,
+ const char *type,
+ uint32_t version,
+ struct pw_properties *properties,
+ size_t user_data_size);
+
+/** Get the factory properties */
+const struct pw_properties *pw_impl_factory_get_properties(struct pw_impl_factory *factory);
+
+/** Get the factory info */
+const struct pw_factory_info *pw_impl_factory_get_info(struct pw_impl_factory *factory);
+
+/** Update the factory properties */
+int pw_impl_factory_update_properties(struct pw_impl_factory *factory, const struct spa_dict *dict);
+
+int pw_impl_factory_register(struct pw_impl_factory *factory,
+ struct pw_properties *properties);
+
+void pw_impl_factory_destroy(struct pw_impl_factory *factory);
+
+void *pw_impl_factory_get_user_data(struct pw_impl_factory *factory);
+
+/** Get the global of this factory */
+struct pw_global *pw_impl_factory_get_global(struct pw_impl_factory *factory);
+
+/** Add an event listener */
+void pw_impl_factory_add_listener(struct pw_impl_factory *factory,
+ struct spa_hook *listener,
+ const struct pw_impl_factory_events *events,
+ void *data);
+
+void pw_impl_factory_set_implementation(struct pw_impl_factory *factory,
+ const struct pw_impl_factory_implementation *implementation,
+ void *data);
+
+void *pw_impl_factory_create_object(struct pw_impl_factory *factory,
+ struct pw_resource *resource,
+ const char *type,
+ uint32_t version,
+ struct pw_properties *properties,
+ uint32_t new_id);
+
+/** Find a factory by name */
+struct pw_impl_factory *
+pw_context_find_factory(struct pw_context *context /**< the context */,
+ const char *name /**< the factory name */);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_IMPL_FACTORY_H */
diff --git a/third_party/pipewire/pipewire/impl-link.h b/third_party/pipewire/pipewire/impl-link.h
new file mode 100644
index 0000000000..5a3b73f52f
--- /dev/null
+++ b/third_party/pipewire/pipewire/impl-link.h
@@ -0,0 +1,126 @@
+/* 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_IMPL_LINK_H
+#define PIPEWIRE_IMPL_LINK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup pw_impl_link Link Impl
+ *
+ * \brief PipeWire link object.
+ */
+
+/**
+ * \addtogroup pw_impl_link
+ * \{
+ */
+struct pw_impl_link;
+struct pw_impl_port;
+
+#include <pipewire/impl.h>
+
+/** link events added with \ref pw_impl_link_add_listener */
+struct pw_impl_link_events {
+#define PW_VERSION_IMPL_LINK_EVENTS 0
+ uint32_t version;
+
+ /** A link is destroyed */
+ void (*destroy) (void *data);
+
+ /** A link is freed */
+ void (*free) (void *data);
+
+ /** a Link is initialized */
+ void (*initialized) (void *data);
+
+ /** The info changed on a link */
+ void (*info_changed) (void *data, const struct pw_link_info *info);
+
+ /** The link state changed, \a error is only valid when the state is
+ * in error. */
+ void (*state_changed) (void *data, enum pw_link_state old,
+ enum pw_link_state state, const char *error);
+
+ /** A port is unlinked */
+ void (*port_unlinked) (void *data, struct pw_impl_port *port);
+};
+
+
+/** Make a new link between two ports
+ * \return a newly allocated link */
+struct pw_impl_link *
+pw_context_create_link(struct pw_context *context, /**< the context object */
+ struct pw_impl_port *output, /**< an output port */
+ struct pw_impl_port *input, /**< an input port */
+ struct spa_pod *format_filter, /**< an optional format filter */
+ struct pw_properties *properties /**< extra properties */,
+ size_t user_data_size /**< extra user data size */);
+
+/** Destroy a link */
+void pw_impl_link_destroy(struct pw_impl_link *link);
+
+/** Add an event listener to \a link */
+void pw_impl_link_add_listener(struct pw_impl_link *link,
+ struct spa_hook *listener,
+ const struct pw_impl_link_events *events,
+ void *data);
+
+/** Finish link configuration and register */
+int pw_impl_link_register(struct pw_impl_link *link, /**< the link to register */
+ struct pw_properties *properties /**< extra properties */);
+
+/** Get the context of a link */
+struct pw_context *pw_impl_link_get_context(struct pw_impl_link *link);
+
+/** Get the user_data of a link, the size of the memory is given when
+ * constructing the link */
+void *pw_impl_link_get_user_data(struct pw_impl_link *link);
+
+/** Get the link info */
+const struct pw_link_info *pw_impl_link_get_info(struct pw_impl_link *link);
+
+/** Get the global of the link */
+struct pw_global *pw_impl_link_get_global(struct pw_impl_link *link);
+
+/** Get the output port of the link */
+struct pw_impl_port *pw_impl_link_get_output(struct pw_impl_link *link);
+
+/** Get the input port of the link */
+struct pw_impl_port *pw_impl_link_get_input(struct pw_impl_link *link);
+
+/** Find the link between 2 ports */
+struct pw_impl_link *pw_impl_link_find(struct pw_impl_port *output, struct pw_impl_port *input);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_IMPL_LINK_H */
diff --git a/third_party/pipewire/pipewire/impl-metadata.h b/third_party/pipewire/pipewire/impl-metadata.h
new file mode 100644
index 0000000000..4b81cac293
--- /dev/null
+++ b/third_party/pipewire/pipewire/impl-metadata.h
@@ -0,0 +1,114 @@
+/* PipeWire
+ *
+ * Copyright © 2021 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_IMPL_METADATA_H
+#define PIPEWIRE_IMPL_METADATA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup pw_impl_metadata Metadata Impl
+ *
+ * The metadata is used to store key/type/value pairs per object id.
+ */
+
+/**
+ * \addtogroup pw_impl_metadata
+ * \{
+ */
+struct pw_impl_metadata;
+
+#include <pipewire/context.h>
+#include <pipewire/impl-client.h>
+#include <pipewire/global.h>
+#include <pipewire/properties.h>
+#include <pipewire/resource.h>
+
+#include "pipewire/extensions/metadata.h"
+
+/** Metadata events, listen to them with \ref pw_impl_metadata_add_listener */
+struct pw_impl_metadata_events {
+#define PW_VERSION_IMPL_METADATA_EVENTS 0
+ uint32_t version;
+
+ /** the metadata is destroyed */
+ void (*destroy) (void *data);
+ /** the metadata is freed */
+ void (*free) (void *data);
+
+ /** a property changed */
+ int (*property) (void *data,
+ uint32_t subject,
+ const char *key,
+ const char *type,
+ const char *value);
+};
+
+struct pw_impl_metadata *pw_context_create_metadata(struct pw_context *context,
+ const char *name, struct pw_properties *properties,
+ size_t user_data_size);
+
+/** Get the metadata properties */
+const struct pw_properties *pw_impl_metadata_get_properties(struct pw_impl_metadata *metadata);
+
+int pw_impl_metadata_register(struct pw_impl_metadata *metadata,
+ struct pw_properties *properties);
+
+void pw_impl_metadata_destroy(struct pw_impl_metadata *metadata);
+
+void *pw_impl_metadata_get_user_data(struct pw_impl_metadata *metadata);
+
+int pw_impl_metadata_set_implementation(struct pw_impl_metadata *metadata,
+ struct pw_metadata *impl);
+
+struct pw_metadata *pw_impl_metadata_get_implementation(struct pw_impl_metadata *metadata);
+
+/** Get the global of this metadata */
+struct pw_global *pw_impl_metadata_get_global(struct pw_impl_metadata *metadata);
+
+/** Add an event listener */
+void pw_impl_metadata_add_listener(struct pw_impl_metadata *metadata,
+ struct spa_hook *listener,
+ const struct pw_impl_metadata_events *events,
+ void *data);
+
+/** Set a property */
+int pw_impl_metadata_set_property(struct pw_impl_metadata *metadata,
+ uint32_t subject, const char *key, const char *type,
+ const char *value);
+
+int pw_impl_metadata_set_propertyf(struct pw_impl_metadata *metadata,
+ uint32_t subject, const char *key, const char *type,
+ const char *fmt, ...) SPA_PRINTF_FUNC(5,6);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_IMPL_METADATA_H */
diff --git a/third_party/pipewire/pipewire/impl-module.h b/third_party/pipewire/pipewire/impl-module.h
new file mode 100644
index 0000000000..281cd2a521
--- /dev/null
+++ b/third_party/pipewire/pipewire/impl-module.h
@@ -0,0 +1,117 @@
+/* PipeWire
+ * Copyright © 2016 Axis Communications <dev-gstreamer@axis.com>
+ * @author Linus Svensson <linus.svensson@axis.com>
+ * 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_IMPL_MODULE_H
+#define PIPEWIRE_IMPL_MODULE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/hook.h>
+
+#include <pipewire/context.h>
+
+#define PIPEWIRE_SYMBOL_MODULE_INIT "pipewire__module_init"
+#define PIPEWIRE_MODULE_PREFIX "libpipewire-"
+
+/** \defgroup pw_impl_module Module Impl
+ *
+ * A dynamically loadable module
+ */
+
+/**
+ * \addtogroup pw_impl_module
+ * \{
+ */
+struct pw_impl_module;
+
+/** Module init function signature
+ *
+ * \param module A \ref pw_impl_module
+ * \param args Arguments to the module
+ * \return 0 on success, < 0 otherwise with an errno style error
+ *
+ * A module should provide an init function with this signature. This function
+ * will be called when a module is loaded.
+ */
+typedef int (*pw_impl_module_init_func_t) (struct pw_impl_module *module, const char *args);
+
+/** Module events added with \ref pw_impl_module_add_listener */
+struct pw_impl_module_events {
+#define PW_VERSION_IMPL_MODULE_EVENTS 0
+ uint32_t version;
+
+ /** The module is destroyed */
+ void (*destroy) (void *data);
+ /** The module is freed */
+ void (*free) (void *data);
+ /** The module is initialized */
+ void (*initialized) (void *data);
+
+ /** The module is registered. This is a good time to register
+ * objects created from the module. */
+ void (*registered) (void *data);
+};
+
+struct pw_impl_module *
+pw_context_load_module(struct pw_context *context,
+ const char *name,
+ const char *args,
+ struct pw_properties *properties);
+
+/** Get the context of a module */
+struct pw_context * pw_impl_module_get_context(struct pw_impl_module *module);
+
+/** Get the global of a module */
+struct pw_global * pw_impl_module_get_global(struct pw_impl_module *module);
+
+/** Get the module properties */
+const struct pw_properties *pw_impl_module_get_properties(struct pw_impl_module *module);
+
+/** Update the module properties */
+int pw_impl_module_update_properties(struct pw_impl_module *module, const struct spa_dict *dict);
+
+/** Get the module info */
+const struct pw_module_info *pw_impl_module_get_info(struct pw_impl_module *module);
+
+/** Add an event listener to a module */
+void pw_impl_module_add_listener(struct pw_impl_module *module,
+ struct spa_hook *listener,
+ const struct pw_impl_module_events *events,
+ void *data);
+
+/** Destroy a module */
+void pw_impl_module_destroy(struct pw_impl_module *module);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_IMPL_MODULE_H */
diff --git a/third_party/pipewire/pipewire/impl-node.h b/third_party/pipewire/pipewire/impl-node.h
new file mode 100644
index 0000000000..7ef741f0f3
--- /dev/null
+++ b/third_party/pipewire/pipewire/impl-node.h
@@ -0,0 +1,186 @@
+/* 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_IMPL_NODE_H
+#define PIPEWIRE_IMPL_NODE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup pw_impl_node Node Impl
+ *
+ * The node object processes data. The node has a list of
+ * input and output ports (\ref pw_impl_port) on which it
+ * will receive and send out buffers respectively.
+ */
+/**
+ * \addtogroup pw_impl_node
+ * \{
+ */
+struct pw_impl_node;
+struct pw_impl_port;
+
+#include <spa/node/node.h>
+#include <spa/node/event.h>
+
+#include <pipewire/impl.h>
+
+/** Node events, listen to them with \ref pw_impl_node_add_listener */
+struct pw_impl_node_events {
+#define PW_VERSION_IMPL_NODE_EVENTS 0
+ uint32_t version;
+
+ /** the node is destroyed */
+ void (*destroy) (void *data);
+ /** the node is about to be freed */
+ void (*free) (void *data);
+ /** the node is initialized */
+ void (*initialized) (void *data);
+
+ /** a port is being initialized on the node */
+ void (*port_init) (void *data, struct pw_impl_port *port);
+ /** a port was added */
+ void (*port_added) (void *data, struct pw_impl_port *port);
+ /** a port was removed */
+ void (*port_removed) (void *data, struct pw_impl_port *port);
+
+ /** the node info changed */
+ void (*info_changed) (void *data, const struct pw_node_info *info);
+ /** a port on the node changed info */
+ void (*port_info_changed) (void *data, struct pw_impl_port *port,
+ const struct pw_port_info *info);
+ /** the node active state changed */
+ void (*active_changed) (void *data, bool active);
+
+ /** a new state is requested on the node */
+ void (*state_request) (void *data, enum pw_node_state state);
+ /** the state of the node changed */
+ void (*state_changed) (void *data, enum pw_node_state old,
+ enum pw_node_state state, const char *error);
+
+ /** a result was received */
+ void (*result) (void *data, int seq, int res, uint32_t type, const void *result);
+
+ /** an event is emitted */
+ void (*event) (void *data, const struct spa_event *event);
+
+ /** the driver of the node changed */
+ void (*driver_changed) (void *data, struct pw_impl_node *old, struct pw_impl_node *driver);
+
+ /** a peer was added */
+ void (*peer_added) (void *data, struct pw_impl_node *peer);
+ /** a peer was removed */
+ void (*peer_removed) (void *data, struct pw_impl_node *peer);
+};
+
+/** Create a new node */
+struct pw_impl_node *
+pw_context_create_node(struct pw_context *context, /**< the context */
+ struct pw_properties *properties, /**< extra properties */
+ size_t user_data_size /**< user data size */);
+
+/** Complete initialization of the node and register */
+int pw_impl_node_register(struct pw_impl_node *node, /**< node to register */
+ struct pw_properties *properties /**< extra properties */);
+
+/** Destroy a node */
+void pw_impl_node_destroy(struct pw_impl_node *node);
+
+/** Get the node info */
+const struct pw_node_info *pw_impl_node_get_info(struct pw_impl_node *node);
+
+/** Get node user_data. The size of the memory was given in \ref pw_context_create_node */
+void * pw_impl_node_get_user_data(struct pw_impl_node *node);
+
+/** Get the context of this node */
+struct pw_context *pw_impl_node_get_context(struct pw_impl_node *node);
+
+/** Get the global of this node */
+struct pw_global *pw_impl_node_get_global(struct pw_impl_node *node);
+
+/** Get the node properties */
+const struct pw_properties *pw_impl_node_get_properties(struct pw_impl_node *node);
+
+/** Update the node properties */
+int pw_impl_node_update_properties(struct pw_impl_node *node, const struct spa_dict *dict);
+
+/** Set the node implementation */
+int pw_impl_node_set_implementation(struct pw_impl_node *node, struct spa_node *spa_node);
+
+/** Get the node implementation */
+struct spa_node *pw_impl_node_get_implementation(struct pw_impl_node *node);
+
+/** Add an event listener */
+void pw_impl_node_add_listener(struct pw_impl_node *node,
+ struct spa_hook *listener,
+ const struct pw_impl_node_events *events,
+ void *data);
+
+/** Iterate the ports in the given direction. 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
+ * items are iterated. */
+int pw_impl_node_for_each_port(struct pw_impl_node *node,
+ enum pw_direction direction,
+ int (*callback) (void *data, struct pw_impl_port *port),
+ void *data);
+
+int pw_impl_node_for_each_param(struct pw_impl_node *node,
+ int seq, uint32_t param_id,
+ uint32_t index, uint32_t max,
+ const struct spa_pod *filter,
+ int (*callback) (void *data, int seq,
+ uint32_t id, uint32_t index, uint32_t next,
+ struct spa_pod *param),
+ void *data);
+
+/** Find the port with direction and port_id or NULL when not found. Passing
+ * PW_ID_ANY for port_id will return any port, preferably an unlinked one. */
+struct pw_impl_port *
+pw_impl_node_find_port(struct pw_impl_node *node, enum pw_direction direction, uint32_t port_id);
+
+/** Get a free unused port_id from the node */
+uint32_t pw_impl_node_get_free_port_id(struct pw_impl_node *node, enum pw_direction direction);
+
+int pw_impl_node_initialized(struct pw_impl_node *node);
+
+/** Set a node active. This will start negotiation with all linked active
+ * nodes and start data transport */
+int pw_impl_node_set_active(struct pw_impl_node *node, bool active);
+
+/** Check if a node is active */
+bool pw_impl_node_is_active(struct pw_impl_node *node);
+
+/** Check if a node is active, Since 0.3.39 */
+int pw_impl_node_send_command(struct pw_impl_node *node, const struct spa_command *command);
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_IMPL_NODE_H */
diff --git a/third_party/pipewire/pipewire/impl-port.h b/third_party/pipewire/pipewire/impl-port.h
new file mode 100644
index 0000000000..c275104457
--- /dev/null
+++ b/third_party/pipewire/pipewire/impl-port.h
@@ -0,0 +1,144 @@
+/* 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_IMPL_PORT_H
+#define PIPEWIRE_IMPL_PORT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/hook.h>
+
+/** \defgroup pw_impl_port Port Impl
+ *
+ * \brief A port can be used to link two nodes.
+ */
+
+/**
+ * \addtogroup pw_impl_port
+ * \{
+ */
+struct pw_impl_port;
+struct pw_impl_link;
+struct pw_control;
+
+#include <pipewire/impl.h>
+
+enum pw_impl_port_state {
+ PW_IMPL_PORT_STATE_ERROR = -1, /**< the port is in error */
+ PW_IMPL_PORT_STATE_INIT = 0, /**< the port is being created */
+ PW_IMPL_PORT_STATE_CONFIGURE = 1, /**< the port is ready for format negotiation */
+ PW_IMPL_PORT_STATE_READY = 2, /**< the port is ready for buffer allocation */
+ PW_IMPL_PORT_STATE_PAUSED = 3, /**< the port is paused */
+};
+
+/** Port events, use \ref pw_impl_port_add_listener */
+struct pw_impl_port_events {
+#define PW_VERSION_IMPL_PORT_EVENTS 2
+ uint32_t version;
+
+ /** The port is destroyed */
+ void (*destroy) (void *data);
+
+ /** The port is freed */
+ void (*free) (void *data);
+
+ /** The port is initialized */
+ void (*initialized) (void *data);
+
+ /** the port info changed */
+ void (*info_changed) (void *data, const struct pw_port_info *info);
+
+ /** a new link is added on this port */
+ void (*link_added) (void *data, struct pw_impl_link *link);
+
+ /** a link is removed from this port */
+ void (*link_removed) (void *data, struct pw_impl_link *link);
+
+ /** the state of the port changed */
+ void (*state_changed) (void *data, enum pw_impl_port_state old,
+ enum pw_impl_port_state state, const char *error);
+
+ /** a control was added to the port */
+ void (*control_added) (void *data, struct pw_control *control);
+
+ /** a control was removed from the port */
+ void (*control_removed) (void *data, struct pw_control *control);
+
+ /** a parameter changed, since version 1 */
+ void (*param_changed) (void *data, uint32_t id);
+
+ /** latency changed. Since version 2 */
+ void (*latency_changed) (void *data);
+};
+
+/** Create a new port
+ * \return a newly allocated port */
+struct pw_impl_port *
+pw_context_create_port(struct pw_context *context,
+ enum pw_direction direction,
+ uint32_t port_id,
+ const struct spa_port_info *info,
+ size_t user_data_size);
+
+/** Get the port direction */
+enum pw_direction pw_impl_port_get_direction(struct pw_impl_port *port);
+
+/** Get the port properties */
+const struct pw_properties *pw_impl_port_get_properties(struct pw_impl_port *port);
+
+/** Update the port properties */
+int pw_impl_port_update_properties(struct pw_impl_port *port, const struct spa_dict *dict);
+
+/** Get the port info */
+const struct pw_port_info *pw_impl_port_get_info(struct pw_impl_port *port);
+
+/** Get the port id */
+uint32_t pw_impl_port_get_id(struct pw_impl_port *port);
+
+/** Get the port parent node or NULL when not yet set */
+struct pw_impl_node *pw_impl_port_get_node(struct pw_impl_port *port);
+
+/** check is a port has links, return 0 if not, 1 if it is linked */
+int pw_impl_port_is_linked(struct pw_impl_port *port);
+
+/** Add a port to a node */
+int pw_impl_port_add(struct pw_impl_port *port, struct pw_impl_node *node);
+
+/** Add an event listener on the port */
+void pw_impl_port_add_listener(struct pw_impl_port *port,
+ struct spa_hook *listener,
+ const struct pw_impl_port_events *events,
+ void *data);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_IMPL_PORT_H */
diff --git a/third_party/pipewire/pipewire/impl.h b/third_party/pipewire/pipewire/impl.h
new file mode 100644
index 0000000000..8caa673fe7
--- /dev/null
+++ b/third_party/pipewire/pipewire/impl.h
@@ -0,0 +1,62 @@
+/* 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_IMPL_H
+#define PIPEWIRE_IMPL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \addtogroup api_pw_impl
+ */
+
+struct pw_impl_client;
+struct pw_impl_module;
+struct pw_global;
+struct pw_node;
+struct pw_impl_port;
+struct pw_resource;
+
+#include <pipewire/pipewire.h>
+#include <pipewire/control.h>
+#include <pipewire/impl-core.h>
+#include <pipewire/impl-client.h>
+#include <pipewire/impl-device.h>
+#include <pipewire/impl-factory.h>
+#include <pipewire/global.h>
+#include <pipewire/impl-link.h>
+#include <pipewire/impl-metadata.h>
+#include <pipewire/impl-module.h>
+#include <pipewire/impl-node.h>
+#include <pipewire/impl-port.h>
+#include <pipewire/resource.h>
+#include <pipewire/work-queue.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_IMPL_H */
diff --git a/third_party/pipewire/pipewire/keys.h b/third_party/pipewire/pipewire/keys.h
new file mode 100644
index 0000000000..55c37b0f12
--- /dev/null
+++ b/third_party/pipewire/pipewire/keys.h
@@ -0,0 +1,344 @@
+/* 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
+
+/**
+ * \defgroup pw_keys Key Names
+ *
+ * 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.
+ *
+ * \addtogroup pw_keys
+ * \{
+ */
+#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 */
+
+/** object properties */
+#define PW_KEY_OBJECT_PATH "object.path" /**< unique path to construct the object */
+#define PW_KEY_OBJECT_ID "object.id" /**< a global object id */
+#define PW_KEY_OBJECT_SERIAL "object.serial" /**< a 64 bit object serial number. This is a number
+ * incremented for each object that is created.
+ * The lower 32 bits are guaranteed to never be
+ * SPA_ID_INVALID. */
+#define PW_KEY_OBJECT_LINGER "object.linger" /**< the object lives on even after the client
+ * that created it has been destroyed */
+#define PW_KEY_OBJECT_REGISTER "object.register" /**< If the object should be registered. */
+
+
+/* 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-<username>-<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_LOCK_QUANTUM "node.lock-quantum" /**< don't change quantum when this node
+ * is active */
+#define PW_KEY_NODE_FORCE_QUANTUM "node.force-quantum" /**< force a quantum while the node is
+ * active */
+#define PW_KEY_NODE_RATE "node.rate" /**< the requested rate of the graph as
+ * a fraction. Ex: 1/48000 */
+#define PW_KEY_NODE_LOCK_RATE "node.lock-rate" /**< don't change rate when this node
+ * is active */
+#define PW_KEY_NODE_FORCE_RATE "node.force-rate" /**< force a rate while the node is
+ * active */
+
+#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_WANT_DRIVER "node.want-driver" /**< the node wants to be grouped with a driver
+ * node in order to schedule the graph. */
+#define PW_KEY_NODE_PAUSE_ON_IDLE "node.pause-on-idle" /**< pause the node when idle */
+#define PW_KEY_NODE_SUSPEND_ON_IDLE "node.suspend-on-idle" /**< suspend the node when idle */
+#define PW_KEY_NODE_CACHE_PARAMS "node.cache-params" /**< cache the node params */
+#define PW_KEY_NODE_TRANSPORT_SYNC "node.transport.sync" /**< the node handles transport sync */
+#define PW_KEY_NODE_DRIVER "node.driver" /**< node can drive the graph */
+#define PW_KEY_NODE_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 */
+#define PW_KEY_NODE_LINK_GROUP "node.link-group" /**< the node is internally linked to
+ * nodes with the same link-group */
+#define PW_KEY_NODE_NETWORK "node.network" /**< the node is on a network */
+#define PW_KEY_NODE_TRIGGER "node.trigger" /**< the node is not scheduled automatically
+ * based on the dependencies in the graph
+ * but it will be triggered explicitly. */
+
+/** 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 */
+
+/** 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.rate" /**< 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" */
+#define PW_KEY_AUDIO_ALLOWED_RATES "audio.allowed-rates" /**< a list of allowed samplerates
+ * ex. "[ 44100 48000 ]" */
+
+/** 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 */
+
+#define PW_KEY_TARGET_OBJECT "target.object" /**< a target object to link to */
+
+/** \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_KEYS_H */
diff --git a/third_party/pipewire/pipewire/link.h b/third_party/pipewire/pipewire/link.h
new file mode 100644
index 0000000000..8130f4b5ed
--- /dev/null
+++ b/third_party/pipewire/pipewire/link.h
@@ -0,0 +1,148 @@
+/* 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_LINK_H
+#define PIPEWIRE_LINK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/defs.h>
+#include <spa/utils/hook.h>
+
+#include <pipewire/proxy.h>
+
+/** \defgroup pw_link Link
+ *
+ * A link is the connection between 2 nodes (\ref pw_node). Nodes are
+ * linked together on ports.
+ *
+ * The link is responsible for negotiating the format and buffers for
+ * the nodes.
+ *
+ */
+
+/**
+ * \addtogroup pw_link
+ * \{
+ */
+
+#define PW_TYPE_INTERFACE_Link PW_TYPE_INFO_INTERFACE_BASE "Link"
+
+#define PW_VERSION_LINK 3
+struct pw_link;
+
+/** \enum pw_link_state The different link states */
+enum pw_link_state {
+ PW_LINK_STATE_ERROR = -2, /**< the link is in error */
+ PW_LINK_STATE_UNLINKED = -1, /**< the link is unlinked */
+ PW_LINK_STATE_INIT = 0, /**< the link is initialized */
+ PW_LINK_STATE_NEGOTIATING = 1, /**< the link is negotiating formats */
+ PW_LINK_STATE_ALLOCATING = 2, /**< the link is allocating buffers */
+ PW_LINK_STATE_PAUSED = 3, /**< the link is paused */
+ PW_LINK_STATE_ACTIVE = 4, /**< the link is active */
+};
+
+/** Convert a \ref pw_link_state to a readable string */
+const char * pw_link_state_as_string(enum pw_link_state state);
+/** The link information. Extra information can be added in later versions */
+struct pw_link_info {
+ uint32_t id; /**< id of the global */
+ uint32_t output_node_id; /**< server side output node id */
+ uint32_t output_port_id; /**< output port id */
+ uint32_t input_node_id; /**< server side input node id */
+ uint32_t input_port_id; /**< input port id */
+#define PW_LINK_CHANGE_MASK_STATE (1 << 0)
+#define PW_LINK_CHANGE_MASK_FORMAT (1 << 1)
+#define PW_LINK_CHANGE_MASK_PROPS (1 << 2)
+#define PW_LINK_CHANGE_MASK_ALL ((1 << 3)-1)
+ uint64_t change_mask; /**< bitfield of changed fields since last call */
+ enum pw_link_state state; /**< the current state of the link */
+ const char *error; /**< an error reason if \a state is error */
+ struct spa_pod *format; /**< format over link */
+ struct spa_dict *props; /**< the properties of the link */
+};
+
+struct pw_link_info *
+pw_link_info_update(struct pw_link_info *info,
+ const struct pw_link_info *update);
+
+struct pw_link_info *
+pw_link_info_merge(struct pw_link_info *info,
+ const struct pw_link_info *update, bool reset);
+
+void
+pw_link_info_free(struct pw_link_info *info);
+
+
+#define PW_LINK_EVENT_INFO 0
+#define PW_LINK_EVENT_NUM 1
+
+/** Link events */
+struct pw_link_events {
+#define PW_VERSION_LINK_EVENTS 0
+ uint32_t version;
+ /**
+ * Notify link info
+ *
+ * \param info info about the link
+ */
+ void (*info) (void *data, const struct pw_link_info *info);
+};
+
+#define PW_LINK_METHOD_ADD_LISTENER 0
+#define PW_LINK_METHOD_NUM 1
+
+/** Link methods */
+struct pw_link_methods {
+#define PW_VERSION_LINK_METHODS 0
+ uint32_t version;
+
+ int (*add_listener) (void *object,
+ struct spa_hook *listener,
+ const struct pw_link_events *events,
+ void *data);
+};
+
+#define pw_link_method(o,method,version,...) \
+({ \
+ int _res = -ENOTSUP; \
+ spa_interface_call_res((struct spa_interface*)o, \
+ struct pw_link_methods, _res, \
+ method, version, ##__VA_ARGS__); \
+ _res; \
+})
+
+#define pw_link_add_listener(c,...) pw_link_method(c,add_listener,0,__VA_ARGS__)
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PIPEWIRE_LINK_H */
diff --git a/third_party/pipewire/pipewire/log.h b/third_party/pipewire/pipewire/log.h
new file mode 100644
index 0000000000..26ffc20f9a
--- /dev/null
+++ b/third_party/pipewire/pipewire/log.h
@@ -0,0 +1,182 @@
+/* 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_LOG_H
+#define PIPEWIRE_LOG_H
+
+#include <spa/support/log.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup pw_log Logging
+ *
+ * \brief Logging functions of PipeWire
+ *
+ * Logging is performed to stdout and stderr. Trace logging is performed
+ * in a lockfree ringbuffer and written out from the main thread as to not
+ * block the realtime threads.
+ */
+
+/**
+ * \addtogroup pw_log
+ * \{
+ */
+/** The global log level */
+extern enum spa_log_level pw_log_level;
+
+extern struct spa_log_topic *PW_LOG_TOPIC_DEFAULT;
+
+/** Configure a logging module. This is usually done automatically
+ * in pw_init() but you can install a custom logger before calling
+ * pw_init(). */
+void pw_log_set(struct spa_log *log);
+
+/** Get the log interface */
+struct spa_log *pw_log_get(void);
+
+/** Configure the logging level */
+void pw_log_set_level(enum spa_log_level level);
+
+/** Log a message for a topic */
+void
+pw_log_logt(enum spa_log_level level,
+ const struct spa_log_topic *topic,
+ const char *file,
+ int line, const char *func,
+ const char *fmt, ...) SPA_PRINTF_FUNC(6, 7);
+
+/** Log a message for a topic */
+void
+pw_log_logtv(enum spa_log_level level,
+ const struct spa_log_topic *topic,
+ const char *file,
+ int line, const char *func,
+ const char *fmt, va_list args) SPA_PRINTF_FUNC(6, 0);
+
+
+
+/** Log a message for the default topic */
+void
+pw_log_log(enum spa_log_level level,
+ const char *file,
+ int line, const char *func,
+ const char *fmt, ...) SPA_PRINTF_FUNC(5, 6);
+
+/** Log a message for the default topic */
+void
+pw_log_logv(enum spa_log_level level,
+ const char *file,
+ int line, const char *func,
+ const char *fmt, va_list args) SPA_PRINTF_FUNC(5, 0);
+
+/** Initialize the log topic. The returned topic is owned by the pipewire
+ * context and the topic must not be modified or freed.
+ * Do not use this function directly, use one of PW_LOG_TOPIC_* instead.
+ *
+ * \see PW_LOG_TOPIC_STATIC
+ * \see PW_LOG_TOPIC_EXTERN
+ * \see PW_LOG_TOPIC
+ */
+void
+_pw_log_topic_new(struct spa_log_topic *topic);
+
+/**
+ * Declare a static log topic named \a var. The usual usage is:
+ * \code
+ * PW_LOG_TOPIC_STATIC(my_topic);
+ * #define PW_LOG_TOPIC_DEFAULT my_topic
+ *
+ * void foo() {
+ * pw_log_debug("bar");
+ * }
+ * \endcode
+ */
+#define PW_LOG_TOPIC_STATIC(var, topic) \
+ static struct spa_log_topic var##__LINE__ = SPA_LOG_TOPIC(0, topic); \
+ static struct spa_log_topic *var = &(var##__LINE__)
+
+/**
+ * Declare a static log topic named \a var.
+ * See \ref PW_LOG_TOPIC_STATIC for an example usage.
+ */
+#define PW_LOG_TOPIC_EXTERN(var) \
+ extern struct spa_log_topic *var
+
+/**
+ * Declare a static log topic named \a var.
+ * See \ref PW_LOG_TOPIC_STATIC for an example usage.
+ */
+#define PW_LOG_TOPIC(var, topic) \
+ struct spa_log_topic var##__LINE__ = SPA_LOG_TOPIC(0, topic); \
+ struct spa_log_topic *var = &(var##__LINE__)
+
+#define PW_LOG_TOPIC_INIT(var) \
+ spa_log_topic_init(pw_log_get(), var);
+
+/** Check if a loglevel is enabled */
+#define pw_log_level_enabled(lev) (pw_log_level >= (lev))
+#define pw_log_topic_enabled(lev,t) ((t) && (t)->has_custom_level ? (t)->level >= (lev) : pw_log_level_enabled((lev)))
+
+#define pw_logtv(lev,topic,fmt,ap) \
+({ \
+ if (SPA_UNLIKELY(pw_log_topic_enabled(lev,topic))) \
+ pw_log_logtv(lev,topic,__FILE__,__LINE__,__func__,fmt,ap); \
+})
+
+#define pw_logt(lev,topic,...) \
+({ \
+ if (SPA_UNLIKELY(pw_log_topic_enabled(lev,topic))) \
+ pw_log_logt(lev,topic,__FILE__,__LINE__,__func__,__VA_ARGS__); \
+})
+
+#define pw_log(lev,...) pw_logt(lev,PW_LOG_TOPIC_DEFAULT,__VA_ARGS__)
+
+#define pw_log_error(...) pw_log(SPA_LOG_LEVEL_ERROR,__VA_ARGS__)
+#define pw_log_warn(...) pw_log(SPA_LOG_LEVEL_WARN,__VA_ARGS__)
+#define pw_log_info(...) pw_log(SPA_LOG_LEVEL_INFO,__VA_ARGS__)
+#define pw_log_debug(...) pw_log(SPA_LOG_LEVEL_DEBUG,__VA_ARGS__)
+#define pw_log_trace(...) pw_log(SPA_LOG_LEVEL_TRACE,__VA_ARGS__)
+
+#define pw_logt_error(t,...) pw_logt(SPA_LOG_LEVEL_ERROR,t,__VA_ARGS__)
+#define pw_logt_warn(t,...) pw_logt(SPA_LOG_LEVEL_WARN,t,__VA_ARGS__)
+#define pw_logt_info(t,...) pw_logt(SPA_LOG_LEVEL_INFO,t,__VA_ARGS__)
+#define pw_logt_debug(t,...) pw_logt(SPA_LOG_LEVEL_DEBUG,t,__VA_ARGS__)
+#define pw_logt_trace(t,...) pw_logt(SPA_LOG_LEVEL_TRACE,t,__VA_ARGS__)
+
+#ifndef FASTPATH
+#define pw_log_trace_fp(...) pw_log(SPA_LOG_LEVEL_TRACE,__VA_ARGS__)
+#else
+#define pw_log_trace_fp(...)
+#endif
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* PIPEWIRE_LOG_H */
diff --git a/third_party/pipewire/pipewire/loop.h b/third_party/pipewire/pipewire/loop.h
new file mode 100644
index 0000000000..42a630d9f1
--- /dev/null
+++ b/third_party/pipewire/pipewire/loop.h
@@ -0,0 +1,90 @@
+/* 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>
+
+/** \defgroup pw_loop Loop
+ *
+ * PipeWire loop object provides an implementation of
+ * the spa loop interfaces. It can be used to implement various
+ * event loops.
+ */
+
+/**
+ * \addtogroup pw_loop
+ * \{
+ */
+
+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/third_party/pipewire/pipewire/main-loop.h b/third_party/pipewire/pipewire/main-loop.h
new file mode 100644
index 0000000000..2225beee53
--- /dev/null
+++ b/third_party/pipewire/pipewire/main-loop.h
@@ -0,0 +1,86 @@
+/* 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_MAIN_LOOP_H
+#define PIPEWIRE_MAIN_LOOP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup pw_main_loop Main Loop
+ *
+ * A main loop object
+ */
+
+/**
+ * \addtogroup pw_main_loop
+ * \{
+ */
+
+/** A main loop object */
+struct pw_main_loop;
+
+#include <pipewire/loop.h>
+
+/** Events of the main loop */
+struct pw_main_loop_events {
+#define PW_VERSION_MAIN_LOOP_EVENTS 0
+ uint32_t version;
+
+ /** Emitted when the main loop is destroyed */
+ void (*destroy) (void *data);
+};
+
+/** Create a new main loop. */
+struct pw_main_loop *
+pw_main_loop_new(const struct spa_dict *props);
+
+/** Add an event listener */
+void pw_main_loop_add_listener(struct pw_main_loop *loop,
+ struct spa_hook *listener,
+ const struct pw_main_loop_events *events,
+ void *data);
+
+/** Get the loop implementation */
+struct pw_loop * pw_main_loop_get_loop(struct pw_main_loop *loop);
+
+/** Destroy a loop */
+void pw_main_loop_destroy(struct pw_main_loop *loop);
+
+/** Run a main loop. This blocks until \ref pw_main_loop_quit is called */
+int pw_main_loop_run(struct pw_main_loop *loop);
+
+/** Quit a main loop */
+int pw_main_loop_quit(struct pw_main_loop *loop);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_MAIN_LOOP_H */
diff --git a/third_party/pipewire/pipewire/map.h b/third_party/pipewire/pipewire/map.h
new file mode 100644
index 0000000000..f2b54fc7cf
--- /dev/null
+++ b/third_party/pipewire/pipewire/map.h
@@ -0,0 +1,252 @@
+/* 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_MAP_H
+#define PIPEWIRE_MAP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+#include <errno.h>
+
+#include <spa/utils/defs.h>
+#include <pipewire/array.h>
+
+/** \defgroup pw_map Map
+ *
+ * \brief A map that holds pointers to objects indexed by id
+ *
+ * The map is a sparse version of the \ref pw_array "pw_array" that manages the
+ * indices of elements for the caller. Adding items with
+ * pw_map_insert_new() returns the assigned index for that item; if items
+ * are removed the map re-uses indices to keep the array at the minimum
+ * required size.
+ *
+ * \code{.c}
+ * struct pw_map map = PW_MAP_INIT(4);
+ *
+ * idx1 = pw_map_insert_new(&map, ptr1);
+ * idx2 = pw_map_insert_new(&map, ptr2);
+ * // the map is now [ptr1, ptr2], size 2
+ * pw_map_remove(&map, idx1);
+ * // the map is now [<unused>, ptr2], size 2
+ * pw_map_insert_new(&map, ptr3);
+ * // the map is now [ptr3, ptr2], size 2
+ * \endcode
+ */
+
+/**
+ * \addtogroup pw_map
+ * \{
+ */
+
+/** \private
+ * An entry in the map. This is used internally only. Each element in the
+ * backing pw_array is a union pw_map_item. For real items, the data pointer
+ * points to the item. If an element has been removed, pw_map->free_list
+ * is the index of the most recently removed item. That item contains
+ * the index of the next removed item until item->next is SPA_ID_INVALID.
+ *
+ * The free list is prepended only, the last item to be removed will be the
+ * first item to get re-used on the next insert.
+ */
+union pw_map_item {
+ uintptr_t next; /* next free index */
+ void *data; /* data of this item, must be an even address */
+};
+
+/** A map. This struct should be treated as opaque by the caller. */
+struct pw_map {
+ struct pw_array items; /* an array with the map items */
+ uint32_t free_list; /* first free index */
+};
+
+/** \param extend the amount of bytes to grow the map with when needed */
+#define PW_MAP_INIT(extend) (struct pw_map) { PW_ARRAY_INIT(extend), SPA_ID_INVALID }
+
+/**
+ * Get the number of currently allocated elements in the map.
+ * \note pw_map_get_size() returns the currently allocated number of
+ * elements in the map, not the number of actually set elements.
+ * \return the number of available elements before the map needs to grow
+ */
+#define pw_map_get_size(m) pw_array_get_len(&(m)->items, union pw_map_item)
+#define pw_map_get_item(m,id) pw_array_get_unchecked(&(m)->items,id,union pw_map_item)
+#define pw_map_item_is_free(item) ((item)->next & 0x1)
+#define pw_map_id_is_free(m,id) (pw_map_item_is_free(pw_map_get_item(m,id)))
+/** \return true if the id fits within the current map size */
+#define pw_map_check_id(m,id) ((id) < pw_map_get_size(m))
+/** \return true if there is a valid item at \a id */
+#define pw_map_has_item(m,id) (pw_map_check_id(m,id) && !pw_map_id_is_free(m, id))
+#define pw_map_lookup_unchecked(m,id) pw_map_get_item(m,id)->data
+
+/** Convert an id to a pointer that can be inserted into the map */
+#define PW_MAP_ID_TO_PTR(id) (SPA_UINT32_TO_PTR((id)<<1))
+/** Convert a pointer to an id that can be retrieved from the map */
+#define PW_MAP_PTR_TO_ID(p) (SPA_PTR_TO_UINT32(p)>>1)
+
+/** Initialize a map
+ * \param map the map to initialize
+ * \param size the initial size of the map
+ * \param extend the amount to bytes to grow the map with when needed
+ */
+static inline void pw_map_init(struct pw_map *map, size_t size, size_t extend)
+{
+ pw_array_init(&map->items, extend * sizeof(union pw_map_item));
+ pw_array_ensure_size(&map->items, size * sizeof(union pw_map_item));
+ map->free_list = SPA_ID_INVALID;
+}
+
+/** Clear a map and free the data storage. All previously returned ids
+ * must be treated as invalid.
+ */
+static inline void pw_map_clear(struct pw_map *map)
+{
+ pw_array_clear(&map->items);
+}
+
+/** Reset a map but keep previously allocated storage. All previously
+ * returned ids must be treated as invalid.
+ */
+static inline void pw_map_reset(struct pw_map *map)
+{
+ pw_array_reset(&map->items);
+ map->free_list = SPA_ID_INVALID;
+}
+
+/** Insert data in the map. This function causes the map to grow if required.
+ * \param map the map to insert into
+ * \param data the item to add
+ * \return the id where the item was inserted or SPA_ID_INVALID when the
+ * item can not be inserted.
+ */
+static inline uint32_t pw_map_insert_new(struct pw_map *map, void *data)
+{
+ union pw_map_item *start, *item;
+ uint32_t id;
+
+ if (map->free_list != SPA_ID_INVALID) {
+ start = (union pw_map_item *) map->items.data;
+ item = &start[map->free_list >> 1]; /* lsb always 1, see pw_map_remove */
+ map->free_list = item->next;
+ } else {
+ item = (union pw_map_item *) pw_array_add(&map->items, sizeof(union pw_map_item));
+ if (item == NULL)
+ return SPA_ID_INVALID;
+ start = (union pw_map_item *) map->items.data;
+ }
+ item->data = data;
+ id = (item - start);
+ return id;
+}
+
+/** Replace the data in the map at an index.
+ *
+ * \param map the map to insert into
+ * \param id the index to insert at, must be less or equal to pw_map_get_size()
+ * \param data the data to insert
+ * \return 0 on success, -ENOSPC value when the index is invalid or a negative errno
+ */
+static inline int pw_map_insert_at(struct pw_map *map, uint32_t id, void *data)
+{
+ size_t size = pw_map_get_size(map);
+ union pw_map_item *item;
+
+ if (id > size)
+ return -ENOSPC;
+ else if (id == size) {
+ item = (union pw_map_item *) pw_array_add(&map->items, sizeof(union pw_map_item));
+ if (item == NULL)
+ return -errno;
+ } else {
+ item = pw_map_get_item(map, id);
+ if (pw_map_item_is_free(item))
+ return -EINVAL;
+ }
+ item->data = data;
+ return 0;
+}
+
+/** Remove an item at index. The id may get re-used in the future.
+ *
+ * \param map the map to remove from
+ * \param id the index to remove
+ */
+static inline void pw_map_remove(struct pw_map *map, uint32_t id)
+{
+ if (pw_map_id_is_free(map, id))
+ return;
+
+ pw_map_get_item(map, id)->next = map->free_list;
+ map->free_list = (id << 1) | 1;
+}
+
+/** Find an item in the map
+ * \param map the map to use
+ * \param id the index to look at
+ * \return the item at \a id or NULL when no such item exists
+ */
+static inline void *pw_map_lookup(struct pw_map *map, uint32_t id)
+{
+ if (SPA_LIKELY(pw_map_check_id(map, id))) {
+ union pw_map_item *item = pw_map_get_item(map, id);
+ if (!pw_map_item_is_free(item))
+ return item->data;
+ }
+ return NULL;
+}
+
+/** Iterate all map items
+ * \param map the map to iterate
+ * \param func the function to call for each item, the item data and \a data is
+ * passed to the function. When \a func returns a non-zero result,
+ * iteration ends and the result is returned.
+ * \param data data to pass to \a func
+ * \return the result of the last call to \a func or 0 when all callbacks returned 0.
+ */
+static inline int pw_map_for_each(struct pw_map *map,
+ int (*func) (void *item_data, void *data), void *data)
+{
+ union pw_map_item *item;
+ int res = 0;
+
+ pw_array_for_each(item, &map->items) {
+ if (!pw_map_item_is_free(item))
+ if ((res = func(item->data, data)) != 0)
+ break;
+ }
+ return res;
+}
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PIPEWIRE_MAP_H */
diff --git a/third_party/pipewire/pipewire/mem.h b/third_party/pipewire/pipewire/mem.h
new file mode 100644
index 0000000000..4edfab6696
--- /dev/null
+++ b/third_party/pipewire/pipewire/mem.h
@@ -0,0 +1,212 @@
+/* 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_MEM_H
+#define PIPEWIRE_MEM_H
+
+#include <pipewire/properties.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup pw_memblock Memory Blocks
+ * Memory allocation and pools.
+ */
+
+/**
+ * \addtogroup pw_memblock
+ * \{
+ */
+
+/** Flags passed to \ref pw_mempool_alloc() */
+enum pw_memblock_flags {
+ PW_MEMBLOCK_FLAG_NONE = 0,
+ PW_MEMBLOCK_FLAG_READABLE = (1 << 0), /**< memory is readable */
+ PW_MEMBLOCK_FLAG_WRITABLE = (1 << 1), /**< memory is writable */
+ PW_MEMBLOCK_FLAG_SEAL = (1 << 2), /**< seal the fd */
+ PW_MEMBLOCK_FLAG_MAP = (1 << 3), /**< mmap the fd */
+ PW_MEMBLOCK_FLAG_DONT_CLOSE = (1 << 4), /**< don't close fd */
+ PW_MEMBLOCK_FLAG_DONT_NOTIFY = (1 << 5), /**< don't notify events */
+
+ PW_MEMBLOCK_FLAG_READWRITE = PW_MEMBLOCK_FLAG_READABLE | PW_MEMBLOCK_FLAG_WRITABLE,
+};
+
+enum pw_memmap_flags {
+ PW_MEMMAP_FLAG_NONE = 0,
+ PW_MEMMAP_FLAG_READ = (1 << 0), /**< map in read mode */
+ PW_MEMMAP_FLAG_WRITE = (1 << 1), /**< map in write mode */
+ PW_MEMMAP_FLAG_TWICE = (1 << 2), /**< map the same area twice after each other,
+ * creating a circular ringbuffer */
+ PW_MEMMAP_FLAG_PRIVATE = (1 << 3), /**< writes will be private */
+ PW_MEMMAP_FLAG_LOCKED = (1 << 4), /**< lock the memory into RAM */
+ PW_MEMMAP_FLAG_READWRITE = PW_MEMMAP_FLAG_READ | PW_MEMMAP_FLAG_WRITE,
+};
+
+struct pw_memchunk;
+
+/**
+ *
+ * A memory pool is a collection of pw_memblocks */
+struct pw_mempool {
+ struct pw_properties *props;
+};
+
+/**
+ * Memory block structure */
+struct pw_memblock {
+ struct pw_mempool *pool; /**< owner pool */
+ uint32_t id; /**< unique id */
+ int ref; /**< refcount */
+ uint32_t flags; /**< flags for the memory block on of enum pw_memblock_flags */
+ uint32_t type; /**< type of the fd, one of enum spa_data_type */
+ int fd; /**< fd */
+ uint32_t size; /**< size of memory */
+ struct pw_memmap *map; /**< optional map when PW_MEMBLOCK_FLAG_MAP was given */
+};
+
+/** a mapped region of a pw_memblock */
+struct pw_memmap {
+ struct pw_memblock *block; /**< owner memblock */
+ void *ptr; /**< mapped pointer */
+ uint32_t flags; /**< flags for the mapping on of enum pw_memmap_flags */
+ uint32_t offset; /**< offset in memblock */
+ uint32_t size; /**< size in memblock */
+ uint32_t tag[5]; /**< user tag */
+};
+
+struct pw_mempool_events {
+#define PW_VERSION_MEMPOOL_EVENTS 0
+ uint32_t version;
+
+ /** the pool is destroyed */
+ void (*destroy) (void *data);
+
+ /** a new memory block is added to the pool */
+ void (*added) (void *data, struct pw_memblock *block);
+
+ /** a memory block is removed from the pool */
+ void (*removed) (void *data, struct pw_memblock *block);
+};
+
+/** Create a new memory pool */
+struct pw_mempool *pw_mempool_new(struct pw_properties *props);
+
+/** Listen for events */
+void pw_mempool_add_listener(struct pw_mempool *pool,
+ struct spa_hook *listener,
+ const struct pw_mempool_events *events,
+ void *data);
+
+/** Clear a pool */
+void pw_mempool_clear(struct pw_mempool *pool);
+
+/** Clear and destroy a pool */
+void pw_mempool_destroy(struct pw_mempool *pool);
+
+
+/** Allocate a memory block from the pool */
+struct pw_memblock * pw_mempool_alloc(struct pw_mempool *pool,
+ enum pw_memblock_flags flags, uint32_t type, size_t size);
+
+/** Import a block from another pool */
+struct pw_memblock * pw_mempool_import_block(struct pw_mempool *pool,
+ struct pw_memblock *mem);
+
+/** Import an fd into the pool */
+struct pw_memblock * pw_mempool_import(struct pw_mempool *pool,
+ enum pw_memblock_flags flags, uint32_t type, int fd);
+
+/** Free a memblock regardless of the refcount and destroy all mappings */
+void pw_memblock_free(struct pw_memblock *mem);
+
+/** Unref a memblock */
+static inline void pw_memblock_unref(struct pw_memblock *mem)
+{
+ if (--mem->ref == 0)
+ pw_memblock_free(mem);
+}
+
+/** Remove a memblock for given \a id */
+int pw_mempool_remove_id(struct pw_mempool *pool, uint32_t id);
+
+/** Find memblock for given \a ptr */
+struct pw_memblock * pw_mempool_find_ptr(struct pw_mempool *pool, const void *ptr);
+
+/** Find memblock for given \a id */
+struct pw_memblock * pw_mempool_find_id(struct pw_mempool *pool, uint32_t id);
+
+/** Find memblock for given \a fd */
+struct pw_memblock * pw_mempool_find_fd(struct pw_mempool *pool, int fd);
+
+
+/** Map a region of a memory block */
+struct pw_memmap * pw_memblock_map(struct pw_memblock *block,
+ enum pw_memmap_flags flags, uint32_t offset, uint32_t size,
+ uint32_t tag[5]);
+
+/** Map a region of a memory block with \a id */
+struct pw_memmap * pw_mempool_map_id(struct pw_mempool *pool, uint32_t id,
+ enum pw_memmap_flags flags, uint32_t offset, uint32_t size,
+ uint32_t tag[5]);
+
+struct pw_memmap * pw_mempool_import_map(struct pw_mempool *pool,
+ struct pw_mempool *other, void *data, uint32_t size, uint32_t tag[5]);
+
+/** find a map with the given tag */
+struct pw_memmap * pw_mempool_find_tag(struct pw_mempool *pool, uint32_t tag[5], size_t size);
+
+/** Unmap a region */
+int pw_memmap_free(struct pw_memmap *map);
+
+
+/** parameters to map a memory range */
+struct pw_map_range {
+ uint32_t start; /** offset in first page with start of data */
+ uint32_t offset; /** page aligned offset to map */
+ uint32_t size; /** size to map */
+};
+
+#define PW_MAP_RANGE_INIT (struct pw_map_range){ 0, }
+
+/** Calculate parameters to mmap() memory into \a range so that
+ * \a size bytes at \a offset can be mapped with mmap(). */
+static inline void pw_map_range_init(struct pw_map_range *range,
+ uint32_t offset, uint32_t size,
+ uint32_t page_size)
+{
+ range->offset = SPA_ROUND_DOWN_N(offset, page_size);
+ range->start = offset - range->offset;
+ range->size = SPA_ROUND_UP_N(range->start + size, page_size);
+}
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_MEM_H */
diff --git a/third_party/pipewire/pipewire/module.h b/third_party/pipewire/pipewire/module.h
new file mode 100644
index 0000000000..aba6de8b5d
--- /dev/null
+++ b/third_party/pipewire/pipewire/module.h
@@ -0,0 +1,121 @@
+/* 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_MODULE_H
+#define PIPEWIRE_MODULE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/defs.h>
+#include <spa/utils/hook.h>
+
+#include <pipewire/proxy.h>
+
+/** \defgroup pw_module Module
+ * Module interface
+ */
+
+/**
+ * \addtogroup pw_module
+ * \{
+ */
+#define PW_TYPE_INTERFACE_Module PW_TYPE_INFO_INTERFACE_BASE "Module"
+
+#define PW_VERSION_MODULE 3
+struct pw_module;
+
+/** The module information. Extra information can be added in later versions */
+struct pw_module_info {
+ uint32_t id; /**< id of the global */
+ const char *name; /**< name of the module */
+ const char *filename; /**< filename of the module */
+ const char *args; /**< arguments passed to the module */
+#define PW_MODULE_CHANGE_MASK_PROPS (1 << 0)
+#define PW_MODULE_CHANGE_MASK_ALL ((1 << 1)-1)
+ uint64_t change_mask; /**< bitfield of changed fields since last call */
+ struct spa_dict *props; /**< extra properties */
+};
+
+/** Update and existing \ref pw_module_info with \a update with reset */
+struct pw_module_info *
+pw_module_info_update(struct pw_module_info *info,
+ const struct pw_module_info *update);
+/** Merge and existing \ref pw_module_info with \a update */
+struct pw_module_info *
+pw_module_info_merge(struct pw_module_info *info,
+ const struct pw_module_info *update, bool reset);
+/** Free a \ref pw_module_info */
+void pw_module_info_free(struct pw_module_info *info);
+
+#define PW_MODULE_EVENT_INFO 0
+#define PW_MODULE_EVENT_NUM 1
+
+/** Module events */
+struct pw_module_events {
+#define PW_VERSION_MODULE_EVENTS 0
+ uint32_t version;
+ /**
+ * Notify module info
+ *
+ * \param info info about the module
+ */
+ void (*info) (void *data, const struct pw_module_info *info);
+};
+
+#define PW_MODULE_METHOD_ADD_LISTENER 0
+#define PW_MODULE_METHOD_NUM 1
+
+/** Module methods */
+struct pw_module_methods {
+#define PW_VERSION_MODULE_METHODS 0
+ uint32_t version;
+
+ int (*add_listener) (void *object,
+ struct spa_hook *listener,
+ const struct pw_module_events *events,
+ void *data);
+};
+
+#define pw_module_method(o,method,version,...) \
+({ \
+ int _res = -ENOTSUP; \
+ spa_interface_call_res((struct spa_interface*)o, \
+ struct pw_module_methods, _res, \
+ method, version, ##__VA_ARGS__); \
+ _res; \
+})
+
+#define pw_module_add_listener(c,...) pw_module_method(c,add_listener,0,__VA_ARGS__)
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PIPEWIRE_MODULE_H */
diff --git a/third_party/pipewire/pipewire/node.h b/third_party/pipewire/pipewire/node.h
new file mode 100644
index 0000000000..e5b8995252
--- /dev/null
+++ b/third_party/pipewire/pipewire/node.h
@@ -0,0 +1,216 @@
+/* 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_NODE_H
+#define PIPEWIRE_NODE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+#include <errno.h>
+
+#include <spa/utils/defs.h>
+#include <spa/utils/hook.h>
+#include <spa/node/command.h>
+#include <spa/param/param.h>
+
+#include <pipewire/proxy.h>
+
+/** \defgroup pw_node Node
+ * Node interface
+ */
+
+/**
+ * \addtogroup pw_node
+ * \{
+ */
+#define PW_TYPE_INTERFACE_Node PW_TYPE_INFO_INTERFACE_BASE "Node"
+
+#define PW_VERSION_NODE 3
+struct pw_node;
+
+/** \enum pw_node_state The different node states */
+enum pw_node_state {
+ PW_NODE_STATE_ERROR = -1, /**< error state */
+ PW_NODE_STATE_CREATING = 0, /**< the node is being created */
+ PW_NODE_STATE_SUSPENDED = 1, /**< the node is suspended, the device might
+ * be closed */
+ PW_NODE_STATE_IDLE = 2, /**< the node is running but there is no active
+ * port */
+ PW_NODE_STATE_RUNNING = 3, /**< the node is running */
+};
+
+/** Convert a \ref pw_node_state to a readable string */
+const char * pw_node_state_as_string(enum pw_node_state state);
+
+/** The node information. Extra information can be added in later versions */
+struct pw_node_info {
+ uint32_t id; /**< id of the global */
+ uint32_t max_input_ports; /**< maximum number of inputs */
+ uint32_t max_output_ports; /**< maximum number of outputs */
+#define PW_NODE_CHANGE_MASK_INPUT_PORTS (1 << 0)
+#define PW_NODE_CHANGE_MASK_OUTPUT_PORTS (1 << 1)
+#define PW_NODE_CHANGE_MASK_STATE (1 << 2)
+#define PW_NODE_CHANGE_MASK_PROPS (1 << 3)
+#define PW_NODE_CHANGE_MASK_PARAMS (1 << 4)
+#define PW_NODE_CHANGE_MASK_ALL ((1 << 5)-1)
+ uint64_t change_mask; /**< bitfield of changed fields since last call */
+ uint32_t n_input_ports; /**< number of inputs */
+ uint32_t n_output_ports; /**< number of outputs */
+ enum pw_node_state state; /**< the current state of the node */
+ const char *error; /**< an error reason if \a state is error */
+ struct spa_dict *props; /**< the properties of the node */
+ struct spa_param_info *params; /**< parameters */
+ uint32_t n_params; /**< number of items in \a params */
+};
+
+struct pw_node_info *
+pw_node_info_update(struct pw_node_info *info,
+ const struct pw_node_info *update);
+
+struct pw_node_info *
+pw_node_info_merge(struct pw_node_info *info,
+ const struct pw_node_info *update, bool reset);
+
+void
+pw_node_info_free(struct pw_node_info *info);
+
+#define PW_NODE_EVENT_INFO 0
+#define PW_NODE_EVENT_PARAM 1
+#define PW_NODE_EVENT_NUM 2
+
+/** Node events */
+struct pw_node_events {
+#define PW_VERSION_NODE_EVENTS 0
+ uint32_t version;
+ /**
+ * Notify node info
+ *
+ * \param info info about the node
+ */
+ void (*info) (void *data, const struct pw_node_info *info);
+ /**
+ * Notify a node 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 *data, int seq,
+ uint32_t id, uint32_t index, uint32_t next,
+ const struct spa_pod *param);
+};
+
+#define PW_NODE_METHOD_ADD_LISTENER 0
+#define PW_NODE_METHOD_SUBSCRIBE_PARAMS 1
+#define PW_NODE_METHOD_ENUM_PARAMS 2
+#define PW_NODE_METHOD_SET_PARAM 3
+#define PW_NODE_METHOD_SEND_COMMAND 4
+#define PW_NODE_METHOD_NUM 5
+
+/** Node methods */
+struct pw_node_methods {
+#define PW_VERSION_NODE_METHODS 0
+ uint32_t version;
+
+ int (*add_listener) (void *object,
+ struct spa_hook *listener,
+ const struct pw_node_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 node parameters
+ *
+ * Start enumeration of node parameters. For each param, a
+ * param event will be emitted.
+ *
+ * \param seq a sequence number to place in the reply
+ * \param id the parameter id to enum or PW_ID_ANY for all
+ * \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);
+
+ /**
+ * Set a parameter on the node
+ *
+ * \param id the parameter id to set
+ * \param flags extra parameter flags
+ * \param param the parameter to set
+ */
+ int (*set_param) (void *object, uint32_t id, uint32_t flags,
+ const struct spa_pod *param);
+
+ /**
+ * Send a command to the node
+ *
+ * \param command the command to send
+ */
+ int (*send_command) (void *object, const struct spa_command *command);
+};
+
+#define pw_node_method(o,method,version,...) \
+({ \
+ int _res = -ENOTSUP; \
+ spa_interface_call_res((struct spa_interface*)o, \
+ struct pw_node_methods, _res, \
+ method, version, ##__VA_ARGS__); \
+ _res; \
+})
+
+/** Node */
+#define pw_node_add_listener(c,...) pw_node_method(c,add_listener,0,__VA_ARGS__)
+#define pw_node_subscribe_params(c,...) pw_node_method(c,subscribe_params,0,__VA_ARGS__)
+#define pw_node_enum_params(c,...) pw_node_method(c,enum_params,0,__VA_ARGS__)
+#define pw_node_set_param(c,...) pw_node_method(c,set_param,0,__VA_ARGS__)
+#define pw_node_send_command(c,...) pw_node_method(c,send_command,0,__VA_ARGS__)
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PIPEWIRE_NODE_H */
diff --git a/third_party/pipewire/pipewire/permission.h b/third_party/pipewire/pipewire/permission.h
new file mode 100644
index 0000000000..e0274ddcbb
--- /dev/null
+++ b/third_party/pipewire/pipewire/permission.h
@@ -0,0 +1,86 @@
+/* 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_PERMISSION_H
+#define PIPEWIRE_PERMISSION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/defs.h>
+
+/** \defgroup pw_permission Permission
+ *
+ * Permissions are kept for a client and describe what the client is
+ * allowed to do with an object.
+ *
+ * See \ref page_core_api
+ */
+
+/**
+ * \addtogroup pw_permission
+ * \{
+ */
+
+#define PW_PERM_R 0400 /**< object can be seen and events can be received */
+#define PW_PERM_W 0200 /**< methods can be called that modify the object */
+#define PW_PERM_X 0100 /**< methods can be called on the object. The W flag must be
+ * present in order to call methods that modify the object. */
+#define PW_PERM_M 0010 /**< metadata can be set on object, Since 0.3.9 */
+
+#define PW_PERM_RWX (PW_PERM_R|PW_PERM_W|PW_PERM_X)
+#define PW_PERM_RWXM (PW_PERM_RWX|PW_PERM_M)
+
+#define PW_PERM_IS_R(p) (((p)&PW_PERM_R) == PW_PERM_R)
+#define PW_PERM_IS_W(p) (((p)&PW_PERM_W) == PW_PERM_W)
+#define PW_PERM_IS_X(p) (((p)&PW_PERM_X) == PW_PERM_X)
+#define PW_PERM_IS_M(p) (((p)&PW_PERM_M) == PW_PERM_M)
+
+#define PW_PERM_ALL PW_PERM_RWXM
+#define PW_PERM_INVALID (uint32_t)(0xffffffff)
+
+struct pw_permission {
+ uint32_t id; /**< id of object, PW_ID_ANY for default permission */
+ uint32_t permissions; /**< bitmask of above permissions */
+};
+
+#define PW_PERMISSION_INIT(id,p) (struct pw_permission){ (id), (p) }
+
+#define PW_PERMISSION_FORMAT "%c%c%c%c"
+#define PW_PERMISSION_ARGS(permission) \
+ (permission) & PW_PERM_R ? 'r' : '-', \
+ (permission) & PW_PERM_W ? 'w' : '-', \
+ (permission) & PW_PERM_X ? 'x' : '-', \
+ (permission) & PW_PERM_M ? 'm' : '-'
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_PERMISSION_H */
diff --git a/third_party/pipewire/pipewire/pipewire.h b/third_party/pipewire/pipewire/pipewire.h
new file mode 100644
index 0000000000..b932103f46
--- /dev/null
+++ b/third_party/pipewire/pipewire/pipewire.h
@@ -0,0 +1,122 @@
+/* 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_H
+#define PIPEWIRE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/support/plugin.h>
+
+#include <pipewire/array.h>
+#include <pipewire/client.h>
+#include <pipewire/context.h>
+#include <pipewire/device.h>
+#include <pipewire/buffers.h>
+#include <pipewire/core.h>
+#include <pipewire/factory.h>
+#include <pipewire/keys.h>
+#include <pipewire/log.h>
+#include <pipewire/loop.h>
+#include <pipewire/link.h>
+#include <pipewire/main-loop.h>
+#include <pipewire/map.h>
+#include <pipewire/mem.h>
+#include <pipewire/module.h>
+#include <pipewire/node.h>
+#include <pipewire/properties.h>
+#include <pipewire/proxy.h>
+#include <pipewire/permission.h>
+#include <pipewire/protocol.h>
+#include <pipewire/port.h>
+#include <pipewire/stream.h>
+#include <pipewire/filter.h>
+#include <pipewire/thread-loop.h>
+#include <pipewire/data-loop.h>
+#include <pipewire/type.h>
+#include <pipewire/utils.h>
+#include <pipewire/version.h>
+
+/** \defgroup pw_pipewire Initialization
+ * Initializing PipeWire and loading SPA modules.
+ */
+
+/**
+ * \addtogroup pw_pipewire
+ * \{
+ */
+void
+pw_init(int *argc, char **argv[]);
+
+void pw_deinit(void);
+
+bool
+pw_debug_is_category_enabled(const char *name);
+
+const char *
+pw_get_application_name(void);
+
+const char *
+pw_get_prgname(void);
+
+const char *
+pw_get_user_name(void);
+
+const char *
+pw_get_host_name(void);
+
+const char *
+pw_get_client_name(void);
+
+bool pw_in_valgrind(void);
+
+bool pw_check_option(const char *option, const char *value);
+
+enum pw_direction
+pw_direction_reverse(enum pw_direction direction);
+
+int pw_set_domain(const char *domain);
+const char *pw_get_domain(void);
+
+uint32_t pw_get_support(struct spa_support *support, uint32_t max_support);
+
+struct spa_handle *pw_load_spa_handle(const char *lib,
+ const char *factory_name,
+ const struct spa_dict *info,
+ uint32_t n_support,
+ const struct spa_support support[]);
+
+int pw_unload_spa_handle(struct spa_handle *handle);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_H */
diff --git a/third_party/pipewire/pipewire/port.h b/third_party/pipewire/pipewire/port.h
new file mode 100644
index 0000000000..463af23dbb
--- /dev/null
+++ b/third_party/pipewire/pipewire/port.h
@@ -0,0 +1,179 @@
+/* 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>
+
+/** \defgroup pw_port Port
+ * Port interface
+ */
+
+/**
+ * \addtogroup pw_port
+ * \{
+ */
+
+#define PW_TYPE_INTERFACE_Port PW_TYPE_INFO_INTERFACE_BASE "Port"
+
+#define PW_VERSION_PORT 3
+struct pw_port;
+
+/** The direction of a port */
+#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 */
+const char * pw_direction_as_string(enum pw_direction direction);
+
+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);
+
+struct pw_port_info *
+pw_port_info_merge(struct pw_port_info *info,
+ const struct pw_port_info *update, bool reset);
+
+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 *data, 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 *data, 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/third_party/pipewire/pipewire/private.h b/third_party/pipewire/pipewire/private.h
new file mode 100644
index 0000000000..b892074a6b
--- /dev/null
+++ b/third_party/pipewire/pipewire/private.h
@@ -0,0 +1,1308 @@
+/* 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_PRIVATE_H
+#define PIPEWIRE_PRIVATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/socket.h>
+#include <sys/types.h> /* for pthread_t */
+
+#include "pipewire/impl.h"
+
+#include <spa/support/plugin.h>
+#include <spa/pod/builder.h>
+#include <spa/param/latency-utils.h>
+#include <spa/utils/result.h>
+#include <spa/utils/type-info.h>
+
+#if defined(__FreeBSD__) || defined(__MidnightBSD__)
+struct ucred {
+};
+#endif
+
+#ifndef spa_debug
+#define spa_debug(...) pw_log_trace(__VA_ARGS__)
+#endif
+
+#define MAX_RATES 16u
+#define CLOCK_MIN_QUANTUM 4u
+#define CLOCK_MAX_QUANTUM 65536u
+
+struct settings {
+ uint32_t log_level;
+ uint32_t clock_rate; /* default clock rate */
+ uint32_t clock_rates[MAX_RATES]; /* allowed clock rates */
+ uint32_t n_clock_rates; /* number of alternative clock rates */
+ uint32_t clock_quantum; /* default quantum */
+ uint32_t clock_min_quantum; /* min quantum */
+ uint32_t clock_max_quantum; /* max quantum */
+ uint32_t clock_quantum_limit; /* quantum limit */
+ struct spa_rectangle video_size;
+ struct spa_fraction video_rate;
+ uint32_t link_max_buffers;
+ unsigned int mem_warn_mlock:1;
+ unsigned int mem_allow_mlock:1;
+ unsigned int clock_power_of_two_quantum:1;
+ unsigned int check_quantum:1;
+ unsigned int check_rate:1;
+#define CLOCK_RATE_UPDATE_MODE_HARD 0
+#define CLOCK_RATE_UPDATE_MODE_SOFT 1
+ int clock_rate_update_mode;
+ uint32_t clock_force_rate; /* force a clock rate */
+ uint32_t clock_force_quantum; /* force a quantum */
+};
+
+struct ratelimit {
+ uint64_t interval;
+ uint64_t begin;
+ unsigned burst;
+ unsigned n_printed, n_missed;
+};
+
+static inline bool ratelimit_test(struct ratelimit *r, uint64_t now, enum spa_log_level level)
+{
+ if (r->begin + r->interval < now) {
+ if (r->n_missed)
+ pw_log(level, "%u events suppressed", r->n_missed);
+ r->begin = now;
+ r->n_printed = 0;
+ r->n_missed = 0;
+ } else if (r->n_printed >= r->burst) {
+ r->n_missed++;
+ return false;
+ }
+ r->n_printed++;
+ return true;
+}
+
+#define MAX_PARAMS 32
+
+struct pw_param {
+ uint32_t id;
+ struct spa_list link;
+ struct spa_pod *param;
+};
+
+static inline uint32_t pw_param_clear(struct spa_list *param_list, uint32_t id)
+{
+ struct pw_param *p, *t;
+ uint32_t count = 0;
+
+ spa_list_for_each_safe(p, t, param_list, link) {
+ if (id == SPA_ID_INVALID || p->id == id) {
+ spa_list_remove(&p->link);
+ free(p);
+ count++;
+ }
+ }
+ return count;
+}
+
+static inline struct pw_param *pw_param_add(struct spa_list *params,
+ uint32_t id, const struct spa_pod *param)
+{
+ struct pw_param *p;
+
+ if (id == SPA_ID_INVALID) {
+ if (param == NULL || !spa_pod_is_object(param)) {
+ errno = EINVAL;
+ return NULL;
+ }
+ id = SPA_POD_OBJECT_ID(param);
+ }
+
+ if ((p = malloc(sizeof(*p) + (param != NULL ? SPA_POD_SIZE(param) : 0))) == NULL)
+ return NULL;
+
+ p->id = id;
+ if (param != NULL) {
+ p->param = SPA_PTROFF(p, sizeof(*p), struct spa_pod);
+ memcpy(p->param, param, SPA_POD_SIZE(param));
+ } else {
+ pw_param_clear(params, id);
+ p->param = NULL;
+ }
+ spa_list_append(params, &p->link);
+ return p;
+}
+
+static inline void pw_param_update(struct spa_list *param_list, struct spa_list *pending_list)
+{
+ struct pw_param *p;
+
+ spa_list_consume(p, pending_list, link) {
+ spa_list_remove(&p->link);
+ if (p->param == NULL) {
+ pw_param_clear(param_list, p->id);
+ free(p);
+ } else {
+ spa_list_append(param_list, &p->link);
+ }
+ }
+}
+
+static inline struct spa_param_info *pw_param_info_find(struct spa_param_info info[],
+ uint32_t n_info, uint32_t id)
+{
+ uint32_t i;
+ for (i = 0; i < n_info; i++) {
+ if (info[i].id == id)
+ return &info[i];
+ }
+ return NULL;
+}
+
+#define pw_protocol_emit_destroy(p) spa_hook_list_call(&p->listener_list, struct pw_protocol_events, destroy, 0)
+
+struct pw_protocol {
+ struct spa_list link; /**< link in context protocol_list */
+ struct pw_context *context; /**< context for this protocol */
+
+ char *name; /**< type name of the protocol */
+
+ struct spa_list marshal_list; /**< list of marshallers for supported interfaces */
+ struct spa_list client_list; /**< list of current clients */
+ struct spa_list server_list; /**< list of current servers */
+ struct spa_hook_list listener_list; /**< event listeners */
+
+ const struct pw_protocol_implementation *implementation; /**< implementation of the protocol */
+
+ const void *extension; /**< extension API */
+
+ void *user_data; /**< user data for the implementation */
+};
+
+/** the permission function. It returns the allowed access permissions for \a global
+ * for \a client */
+typedef uint32_t (*pw_permission_func_t) (struct pw_global *global,
+ struct pw_impl_client *client, void *data);
+
+#define pw_impl_client_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_impl_client_events, m, v, ##__VA_ARGS__)
+
+#define pw_impl_client_emit_destroy(o) pw_impl_client_emit(o, destroy, 0)
+#define pw_impl_client_emit_free(o) pw_impl_client_emit(o, free, 0)
+#define pw_impl_client_emit_initialized(o) pw_impl_client_emit(o, initialized, 0)
+#define pw_impl_client_emit_info_changed(o,i) pw_impl_client_emit(o, info_changed, 0, i)
+#define pw_impl_client_emit_resource_added(o,r) pw_impl_client_emit(o, resource_added, 0, r)
+#define pw_impl_client_emit_resource_impl(o,r) pw_impl_client_emit(o, resource_impl, 0, r)
+#define pw_impl_client_emit_resource_removed(o,r) pw_impl_client_emit(o, resource_removed, 0, r)
+#define pw_impl_client_emit_busy_changed(o,b) pw_impl_client_emit(o, busy_changed, 0, b)
+
+enum spa_node0_event {
+ SPA_NODE0_EVENT_START = SPA_TYPE_VENDOR_PipeWire,
+ SPA_NODE0_EVENT_RequestClockUpdate,
+};
+
+enum spa_node0_command {
+ SPA_NODE0_COMMAND_START = SPA_TYPE_VENDOR_PipeWire,
+ SPA_NODE0_COMMAND_ClockUpdate,
+};
+
+struct protocol_compat_v2 {
+ /* v2 typemap */
+ struct pw_map types;
+ unsigned int send_types:1;
+};
+
+#define pw_impl_core_emit(s,m,v,...) spa_hook_list_call(&s->listener_list, struct pw_impl_core_events, m, v, ##__VA_ARGS__)
+
+#define pw_impl_core_emit_destroy(s) pw_impl_core_emit(s, destroy, 0)
+#define pw_impl_core_emit_free(s) pw_impl_core_emit(s, free, 0)
+#define pw_impl_core_emit_initialized(s) pw_impl_core_emit(s, initialized, 0)
+
+struct pw_impl_core {
+ struct pw_context *context;
+ struct spa_list link; /**< link in context object core_impl list */
+ struct pw_global *global; /**< global object created for this core */
+ struct spa_hook global_listener;
+
+ struct pw_properties *properties; /**< core properties */
+ struct pw_core_info info; /**< core info */
+
+ struct spa_hook_list listener_list;
+ void *user_data; /**< extra user data */
+
+ unsigned int registered:1;
+};
+
+#define pw_impl_metadata_emit(s,m,v,...) spa_hook_list_call(&s->listener_list, struct pw_impl_metadata_events, m, v, ##__VA_ARGS__)
+
+#define pw_impl_metadata_emit_destroy(s) pw_impl_metadata_emit(s, destroy, 0)
+#define pw_impl_metadata_emit_free(s) pw_impl_metadata_emit(s, free, 0)
+#define pw_impl_metadata_emit_property(s, ...) pw_impl_metadata_emit(s, property, 0, __VA_ARGS__)
+
+struct pw_impl_metadata {
+ struct pw_context *context; /**< the context */
+ struct spa_list link; /**< link in context metadata_list */
+ struct pw_global *global; /**< global for this metadata */
+ struct spa_hook global_listener;
+
+ struct pw_properties *properties; /**< properties of the metadata */
+
+ struct pw_metadata *metadata;
+ struct spa_hook metadata_listener;
+
+ struct spa_hook_list listener_list; /**< event listeners */
+ void *user_data;
+
+ unsigned int registered:1;
+};
+
+struct pw_impl_client {
+ struct pw_impl_core *core; /**< core object */
+ struct pw_context *context; /**< context object */
+
+ struct spa_list link; /**< link in context object client list */
+ struct pw_global *global; /**< global object created for this client */
+ struct spa_hook global_listener;
+
+ pw_permission_func_t permission_func; /**< get permissions of an object */
+ void *permission_data; /**< data passed to permission function */
+
+ struct pw_properties *properties; /**< Client properties */
+
+ struct pw_client_info info; /**< client info */
+
+ struct pw_mempool *pool; /**< client mempool */
+ struct pw_resource *core_resource; /**< core resource object */
+ struct pw_resource *client_resource; /**< client resource object */
+
+ struct pw_map objects; /**< list of resource objects */
+
+ struct spa_hook_list listener_list;
+
+ struct pw_protocol *protocol; /**< protocol in use */
+ int recv_seq; /**< last received sequence number */
+ int send_seq; /**< last sender sequence number */
+ uint64_t recv_generation; /**< last received registry generation */
+ uint64_t sent_generation; /**< last sent registry generation */
+
+ void *user_data; /**< extra user data */
+
+ struct ucred ucred; /**< ucred information */
+ unsigned int registered:1;
+ unsigned int ucred_valid:1; /**< if the ucred member is valid */
+ unsigned int busy:1;
+ unsigned int destroyed:1;
+
+ int refcount;
+
+ /* v2 compatibility data */
+ void *compat_v2;
+};
+
+#define pw_global_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_global_events, m, v, ##__VA_ARGS__)
+
+#define pw_global_emit_registering(g) pw_global_emit(g, registering, 0)
+#define pw_global_emit_destroy(g) pw_global_emit(g, destroy, 0)
+#define pw_global_emit_free(g) pw_global_emit(g, free, 0)
+#define pw_global_emit_permissions_changed(g,...) pw_global_emit(g, permissions_changed, 0, __VA_ARGS__)
+
+struct pw_global {
+ struct pw_context *context; /**< the context */
+
+ struct spa_list link; /**< link in context list of globals */
+ uint32_t id; /**< server id of the object */
+
+ struct pw_properties *properties; /**< properties of the global */
+
+ struct spa_hook_list listener_list;
+
+ const char *type; /**< type of interface */
+ uint32_t version; /**< version of interface */
+
+ pw_global_bind_func_t func; /**< bind function */
+ void *object; /**< object associated with the interface */
+ uint64_t serial; /**< increasing serial number */
+ uint64_t generation; /**< registry generation number */
+
+ struct spa_list resource_list; /**< The list of resources of this global */
+
+ unsigned int registered:1;
+ unsigned int destroyed:1;
+};
+
+#define pw_core_resource(r,m,v,...) pw_resource_call(r, struct pw_core_events, m, v, ##__VA_ARGS__)
+#define pw_core_resource_info(r,...) pw_core_resource(r,info,0,__VA_ARGS__)
+#define pw_core_resource_done(r,...) pw_core_resource(r,done,0,__VA_ARGS__)
+#define pw_core_resource_ping(r,...) pw_core_resource(r,ping,0,__VA_ARGS__)
+#define pw_core_resource_error(r,...) pw_core_resource(r,error,0,__VA_ARGS__)
+#define pw_core_resource_remove_id(r,...) pw_core_resource(r,remove_id,0,__VA_ARGS__)
+#define pw_core_resource_bound_id(r,...) pw_core_resource(r,bound_id,0,__VA_ARGS__)
+#define pw_core_resource_add_mem(r,...) pw_core_resource(r,add_mem,0,__VA_ARGS__)
+#define pw_core_resource_remove_mem(r,...) pw_core_resource(r,remove_mem,0,__VA_ARGS__)
+
+static inline SPA_PRINTF_FUNC(5,0) void
+pw_core_resource_errorv(struct pw_resource *resource, 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';
+ pw_log_debug("resource %p: id:%d seq:%d res:%d (%s) msg:\"%s\"",
+ resource, id, seq, res, spa_strerror(res), buffer);
+ if (resource)
+ pw_core_resource_error(resource, id, seq, res, buffer);
+ else
+ pw_log_error("id:%d seq:%d res:%d (%s) msg:\"%s\"",
+ id, seq, res, spa_strerror(res), buffer);
+}
+
+static inline SPA_PRINTF_FUNC(5,6) void
+pw_core_resource_errorf(struct pw_resource *resource, uint32_t id, int seq,
+ int res, const char *message, ...)
+{
+ va_list args;
+ va_start(args, message);
+ pw_core_resource_errorv(resource, id, seq, res, message, args);
+ va_end(args);
+}
+
+#define pw_context_driver_emit(c,m,v,...) spa_hook_list_call_simple(&c->driver_listener_list, struct pw_context_driver_events, m, v, ##__VA_ARGS__)
+#define pw_context_driver_emit_start(c,n) pw_context_driver_emit(c, start, 0, n)
+#define pw_context_driver_emit_xrun(c,n) pw_context_driver_emit(c, xrun, 0, n)
+#define pw_context_driver_emit_incomplete(c,n) pw_context_driver_emit(c, incomplete, 0, n)
+#define pw_context_driver_emit_timeout(c,n) pw_context_driver_emit(c, timeout, 0, n)
+#define pw_context_driver_emit_drained(c,n) pw_context_driver_emit(c, drained, 0, n)
+#define pw_context_driver_emit_complete(c,n) pw_context_driver_emit(c, complete, 0, n)
+
+struct pw_context_driver_events {
+#define PW_VERSION_CONTEXT_DRIVER_EVENTS 0
+ uint32_t version;
+
+ /** The driver graph is started */
+ void (*start) (void *data, struct pw_impl_node *node);
+ /** The driver under/overruns */
+ void (*xrun) (void *data, struct pw_impl_node *node);
+ /** The driver could not complete the graph */
+ void (*incomplete) (void *data, struct pw_impl_node *node);
+ /** The driver got a sync timeout */
+ void (*timeout) (void *data, struct pw_impl_node *node);
+ /** a node drained */
+ void (*drained) (void *data, struct pw_impl_node *node);
+ /** The driver completed the graph */
+ void (*complete) (void *data, struct pw_impl_node *node);
+};
+
+#define pw_registry_resource(r,m,v,...) pw_resource_call(r, struct pw_registry_events,m,v,##__VA_ARGS__)
+#define pw_registry_resource_global(r,...) pw_registry_resource(r,global,0,__VA_ARGS__)
+#define pw_registry_resource_global_remove(r,...) pw_registry_resource(r,global_remove,0,__VA_ARGS__)
+
+#define pw_context_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_context_events, m, v, ##__VA_ARGS__)
+#define pw_context_emit_destroy(c) pw_context_emit(c, destroy, 0)
+#define pw_context_emit_free(c) pw_context_emit(c, free, 0)
+#define pw_context_emit_info_changed(c,i) pw_context_emit(c, info_changed, 0, i)
+#define pw_context_emit_check_access(c,cl) pw_context_emit(c, check_access, 0, cl)
+#define pw_context_emit_global_added(c,g) pw_context_emit(c, global_added, 0, g)
+#define pw_context_emit_global_removed(c,g) pw_context_emit(c, global_removed, 0, g)
+
+struct pw_context {
+ struct pw_impl_core *core; /**< core object */
+
+ struct pw_properties *conf; /**< configuration of the context */
+ struct pw_properties *properties; /**< properties of the context */
+
+ struct settings defaults; /**< default parameters */
+ struct settings settings; /**< current parameters */
+
+ void *settings_impl; /**< settings metadata */
+
+ struct pw_mempool *pool; /**< global memory pool */
+
+ uint64_t stamp;
+ uint64_t serial;
+ uint64_t generation; /**< registry generation number */
+ struct pw_map globals; /**< map of globals */
+
+ struct spa_list core_impl_list; /**< list of core_imp */
+ struct spa_list protocol_list; /**< list of protocols */
+ struct spa_list core_list; /**< list of core connections */
+ struct spa_list registry_resource_list; /**< list of registry resources */
+ struct spa_list module_list; /**< list of modules */
+ struct spa_list device_list; /**< list of devices */
+ struct spa_list global_list; /**< list of globals */
+ struct spa_list client_list; /**< list of clients */
+ struct spa_list node_list; /**< list of nodes */
+ struct spa_list factory_list; /**< list of factories */
+ struct spa_list metadata_list; /**< list of metadata */
+ struct spa_list link_list; /**< list of links */
+ struct spa_list control_list[2]; /**< list of controls, indexed by direction */
+ struct spa_list export_list; /**< list of export types */
+ struct spa_list driver_list; /**< list of driver nodes */
+
+ struct spa_hook_list driver_listener_list;
+ struct spa_hook_list listener_list;
+
+ struct spa_thread_utils *thread_utils;
+ struct pw_loop *main_loop; /**< main loop for control */
+ struct pw_loop *data_loop; /**< data loop for data passing */
+ struct pw_data_loop *data_loop_impl;
+ struct spa_system *data_system; /**< data system for data passing */
+ struct pw_work_queue *work_queue; /**< work queue */
+
+ struct spa_support support[16]; /**< support for spa plugins */
+ uint32_t n_support; /**< number of support items */
+ struct pw_array factory_lib; /**< mapping of factory_name regexp to library */
+
+ struct pw_array objects; /**< objects */
+
+ struct pw_impl_client *current_client; /**< client currently executing code in mainloop */
+
+ long sc_pagesize;
+ unsigned int freewheeling:1;
+
+ void *user_data; /**< extra user data */
+};
+
+#define pw_data_loop_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_data_loop_events, m, v, ##__VA_ARGS__)
+#define pw_data_loop_emit_destroy(o) pw_data_loop_emit(o, destroy, 0)
+
+struct pw_data_loop {
+ struct pw_loop *loop;
+
+ struct spa_hook_list listener_list;
+
+ struct spa_thread_utils *thread_utils;
+
+ pthread_t thread;
+ unsigned int cancel:1;
+ unsigned int created:1;
+ unsigned int running:1;
+};
+
+#define pw_main_loop_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_main_loop_events, m, v, ##__VA_ARGS__)
+#define pw_main_loop_emit_destroy(o) pw_main_loop_emit(o, destroy, 0)
+
+struct pw_main_loop {
+ struct pw_loop *loop;
+
+ struct spa_hook_list listener_list;
+
+ unsigned int created:1;
+ unsigned int running:1;
+};
+
+#define pw_impl_device_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_impl_device_events, m, v, ##__VA_ARGS__)
+#define pw_impl_device_emit_destroy(m) pw_impl_device_emit(m, destroy, 0)
+#define pw_impl_device_emit_free(m) pw_impl_device_emit(m, free, 0)
+#define pw_impl_device_emit_initialized(m) pw_impl_device_emit(m, initialized, 0)
+#define pw_impl_device_emit_info_changed(n,i) pw_impl_device_emit(n, info_changed, 0, i)
+
+struct pw_impl_device {
+ struct pw_context *context; /**< the context object */
+ struct spa_list link; /**< link in the context device_list */
+ struct pw_global *global; /**< global object for this device */
+ struct spa_hook global_listener;
+
+ struct pw_properties *properties; /**< properties of the device */
+ struct pw_device_info info; /**< introspectable device info */
+ struct spa_param_info params[MAX_PARAMS];
+
+ char *name; /**< device name for debug */
+
+ struct spa_device *device; /**< device implementation */
+ struct spa_hook listener;
+ struct spa_hook_list listener_list;
+
+ struct spa_list object_list;
+
+ void *user_data; /**< device user_data */
+
+ unsigned int registered:1;
+};
+
+#define pw_impl_module_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_impl_module_events, m, v, ##__VA_ARGS__)
+#define pw_impl_module_emit_destroy(m) pw_impl_module_emit(m, destroy, 0)
+#define pw_impl_module_emit_free(m) pw_impl_module_emit(m, free, 0)
+#define pw_impl_module_emit_initialized(m) pw_impl_module_emit(m, initialized, 0)
+#define pw_impl_module_emit_registered(m) pw_impl_module_emit(m, registered, 0)
+
+struct pw_impl_module {
+ struct pw_context *context; /**< the context object */
+ struct spa_list link; /**< link in the context module_list */
+ struct pw_global *global; /**< global object for this module */
+ struct spa_hook global_listener;
+
+ struct pw_properties *properties; /**< properties of the module */
+ struct pw_module_info info; /**< introspectable module info */
+
+ struct spa_hook_list listener_list;
+
+ void *user_data; /**< module user_data */
+};
+
+struct pw_node_activation_state {
+ int status; /**< current status, the result of spa_node_process() */
+ int32_t required; /**< required number of signals */
+ int32_t pending; /**< number of pending signals */
+};
+
+static inline void pw_node_activation_state_reset(struct pw_node_activation_state *state)
+{
+ state->pending = state->required;
+}
+
+#define pw_node_activation_state_dec(s,c) (__atomic_sub_fetch(&(s)->pending, c, __ATOMIC_SEQ_CST) == 0)
+
+struct pw_node_target {
+ struct spa_list link;
+ struct pw_impl_node *node;
+ struct pw_node_activation *activation;
+ int (*signal) (void *data);
+ void *data;
+ unsigned int active:1;
+};
+
+struct pw_node_activation {
+#define PW_NODE_ACTIVATION_NOT_TRIGGERED 0
+#define PW_NODE_ACTIVATION_TRIGGERED 1
+#define PW_NODE_ACTIVATION_AWAKE 2
+#define PW_NODE_ACTIVATION_FINISHED 3
+ uint32_t status;
+
+ unsigned int version:1;
+ unsigned int pending_sync:1; /* a sync is pending */
+ unsigned int pending_new_pos:1; /* a new position is pending */
+
+ struct pw_node_activation_state state[2]; /* one current state and one next state,
+ * as version flag */
+ uint64_t signal_time;
+ uint64_t awake_time;
+ uint64_t finish_time;
+ uint64_t prev_signal_time;
+
+ /* updates */
+ struct spa_io_segment reposition; /* reposition info, used when driver reposition_owner
+ * has this node id */
+ struct spa_io_segment segment; /* update for the extra segment info fields.
+ * used when driver segment_owner has this node id */
+
+ /* for drivers, shared with all nodes */
+ uint32_t segment_owner[32]; /* id of owners for each segment info struct.
+ * nodes that want to update segment info need to
+ * CAS their node id in this array. */
+ struct spa_io_position position; /* contains current position and segment info.
+ * extra info is updated by nodes that have set
+ * themselves as owner in the segment structs */
+
+ uint64_t sync_timeout; /* sync timeout in nanoseconds
+ * position goes to RUNNING without waiting any
+ * longer for sync clients. */
+ uint64_t sync_left; /* number of cycles before timeout */
+
+
+ float cpu_load[3]; /* averaged over short, medium, long time */
+ uint32_t xrun_count; /* number of xruns */
+ uint64_t xrun_time; /* time of last xrun in microseconds */
+ uint64_t xrun_delay; /* delay of last xrun in microseconds */
+ uint64_t max_delay; /* max of all xruns in microseconds */
+
+#define PW_NODE_ACTIVATION_COMMAND_NONE 0
+#define PW_NODE_ACTIVATION_COMMAND_START 1
+#define PW_NODE_ACTIVATION_COMMAND_STOP 2
+ uint32_t command; /* next command */
+ uint32_t reposition_owner; /* owner id with new reposition info, last one
+ * to update wins */
+};
+
+#define ATOMIC_CAS(v,ov,nv) \
+({ \
+ __typeof__(v) __ov = (ov); \
+ __atomic_compare_exchange_n(&(v), &__ov, (nv), \
+ 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); \
+})
+
+#define ATOMIC_DEC(s) __atomic_sub_fetch(&(s), 1, __ATOMIC_SEQ_CST)
+#define ATOMIC_INC(s) __atomic_add_fetch(&(s), 1, __ATOMIC_SEQ_CST)
+#define ATOMIC_LOAD(s) __atomic_load_n(&(s), __ATOMIC_SEQ_CST)
+#define ATOMIC_STORE(s,v) __atomic_store_n(&(s), (v), __ATOMIC_SEQ_CST)
+#define ATOMIC_XCHG(s,v) __atomic_exchange_n(&(s), (v), __ATOMIC_SEQ_CST)
+
+#define SEQ_WRITE(s) ATOMIC_INC(s)
+#define SEQ_WRITE_SUCCESS(s1,s2) ((s1) + 1 == (s2) && ((s2) & 1) == 0)
+
+#define SEQ_READ(s) ATOMIC_LOAD(s)
+#define SEQ_READ_SUCCESS(s1,s2) ((s1) == (s2) && ((s2) & 1) == 0)
+
+#define pw_impl_node_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_impl_node_events, m, v, ##__VA_ARGS__)
+#define pw_impl_node_emit_destroy(n) pw_impl_node_emit(n, destroy, 0)
+#define pw_impl_node_emit_free(n) pw_impl_node_emit(n, free, 0)
+#define pw_impl_node_emit_initialized(n) pw_impl_node_emit(n, initialized, 0)
+#define pw_impl_node_emit_port_init(n,p) pw_impl_node_emit(n, port_init, 0, p)
+#define pw_impl_node_emit_port_added(n,p) pw_impl_node_emit(n, port_added, 0, p)
+#define pw_impl_node_emit_port_removed(n,p) pw_impl_node_emit(n, port_removed, 0, p)
+#define pw_impl_node_emit_info_changed(n,i) pw_impl_node_emit(n, info_changed, 0, i)
+#define pw_impl_node_emit_port_info_changed(n,p,i) pw_impl_node_emit(n, port_info_changed, 0, p, i)
+#define pw_impl_node_emit_active_changed(n,a) pw_impl_node_emit(n, active_changed, 0, a)
+#define pw_impl_node_emit_state_request(n,s) pw_impl_node_emit(n, state_request, 0, s)
+#define pw_impl_node_emit_state_changed(n,o,s,e) pw_impl_node_emit(n, state_changed, 0, o, s, e)
+#define pw_impl_node_emit_async_complete(n,s,r) pw_impl_node_emit(n, async_complete, 0, s, r)
+#define pw_impl_node_emit_result(n,s,r,t,result) pw_impl_node_emit(n, result, 0, s, r, t, result)
+#define pw_impl_node_emit_event(n,e) pw_impl_node_emit(n, event, 0, e)
+#define pw_impl_node_emit_driver_changed(n,o,d) pw_impl_node_emit(n, driver_changed, 0, o, d)
+#define pw_impl_node_emit_peer_added(n,p) pw_impl_node_emit(n, peer_added, 0, p)
+#define pw_impl_node_emit_peer_removed(n,p) pw_impl_node_emit(n, peer_removed, 0, p)
+
+struct pw_impl_node {
+ struct pw_context *context; /**< context object */
+ struct spa_list link; /**< link in context node_list */
+ struct pw_global *global; /**< global for this node */
+ struct spa_hook global_listener;
+
+ struct pw_properties *properties; /**< properties of the node */
+
+ struct pw_node_info info; /**< introspectable node info */
+ struct spa_param_info params[MAX_PARAMS];
+
+ char *name; /** for debug */
+
+ uint32_t priority_driver; /** priority for being driver */
+ char group[128]; /** group to schedule this node in */
+ uint64_t spa_flags;
+
+ unsigned int registered:1;
+ unsigned int active:1; /**< if the node is active */
+ unsigned int live:1; /**< if the node is live */
+ unsigned int driver:1; /**< if the node can drive the graph */
+ unsigned int exported:1; /**< if the node is exported */
+ unsigned int remote:1; /**< if the node is implemented remotely */
+ unsigned int driving:1; /**< a driving node is one of the driver nodes that
+ * is selected to drive the graph */
+ unsigned int visited:1; /**< for sorting */
+ unsigned int want_driver:1; /**< this node wants to be assigned to a driver */
+ unsigned int passive:1; /**< driver graph only has passive links */
+ unsigned int freewheel:1; /**< if this is the freewheel driver */
+ unsigned int loopchecked:1; /**< for feedback loop checking */
+ unsigned int always_process:1; /**< this node wants to always be processing, even when idle */
+ unsigned int lock_quantum:1; /**< don't change graph quantum */
+ unsigned int lock_rate:1; /**< don't change graph rate */
+ unsigned int transport_sync:1; /**< supports transport sync */
+ unsigned int current_pending:1; /**< a quantum/rate update is pending */
+ unsigned int moved:1; /**< the node was moved drivers */
+
+ uint32_t port_user_data_size; /**< extra size for port user data */
+
+ struct spa_list driver_link;
+ struct pw_impl_node *driver_node;
+ struct spa_list follower_list;
+ struct spa_list follower_link;
+
+ struct spa_list sort_link; /**< link used to sort nodes */
+
+ struct spa_node *node; /**< SPA node implementation */
+ struct spa_hook listener;
+
+ struct spa_list input_ports; /**< list of input ports */
+ struct pw_map input_port_map; /**< map from port_id to port */
+ struct spa_list output_ports; /**< list of output ports */
+ struct pw_map output_port_map; /**< map from port_id to port */
+
+ struct spa_hook_list listener_list;
+
+ struct pw_loop *data_loop; /**< the data loop for this node */
+
+ struct spa_fraction latency; /**< requested latency */
+ struct spa_fraction max_latency; /**< maximum latency */
+ struct spa_fraction rate; /**< requested rate */
+ uint32_t force_quantum; /**< forced quantum */
+ uint32_t force_rate; /**< forced rate */
+ uint32_t stamp; /**< stamp of last update */
+ struct spa_source source; /**< source to remotely trigger this node */
+ struct pw_memblock *activation;
+ struct {
+ struct spa_io_clock *clock; /**< io area of the clock or NULL */
+ struct spa_io_position *position;
+ struct pw_node_activation *activation;
+
+ struct spa_list target_list; /* list of targets to signal after
+ * this node */
+ struct pw_node_target driver_target; /* driver target that we signal */
+ struct spa_list input_mix; /* our input ports (and mixers) */
+ struct spa_list output_mix; /* output ports (and mixers) */
+
+ struct pw_node_target target; /* our target that is signaled by the
+ driver */
+ struct spa_list driver_link; /* our link in driver */
+
+ struct ratelimit rate_limit;
+ } rt;
+ struct spa_fraction current_rate;
+ uint64_t current_quantum;
+
+ void *user_data; /**< extra user data */
+};
+
+struct pw_impl_port_mix {
+ struct spa_list link;
+ struct spa_list rt_link;
+ struct pw_impl_port *p;
+ struct {
+ enum spa_direction direction;
+ uint32_t port_id;
+ } port;
+ struct spa_io_buffers *io;
+ uint32_t id;
+ uint32_t peer_id;
+ unsigned int have_buffers:1;
+};
+
+struct pw_impl_port_implementation {
+#define PW_VERSION_PORT_IMPLEMENTATION 0
+ uint32_t version;
+
+ int (*init_mix) (void *data, struct pw_impl_port_mix *mix);
+ int (*release_mix) (void *data, struct pw_impl_port_mix *mix);
+};
+
+#define pw_impl_port_call(p,m,v,...) \
+({ \
+ int _res = 0; \
+ spa_callbacks_call_res(&(p)->impl, \
+ struct pw_impl_port_implementation, \
+ _res, m, v, ## __VA_ARGS__); \
+ _res; \
+})
+
+#define pw_impl_port_call_init_mix(p,m) pw_impl_port_call(p,init_mix,0,m)
+#define pw_impl_port_call_release_mix(p,m) pw_impl_port_call(p,release_mix,0,m)
+
+#define pw_impl_port_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_impl_port_events, m, v, ##__VA_ARGS__)
+#define pw_impl_port_emit_destroy(p) pw_impl_port_emit(p, destroy, 0)
+#define pw_impl_port_emit_free(p) pw_impl_port_emit(p, free, 0)
+#define pw_impl_port_emit_initialized(p) pw_impl_port_emit(p, initialized, 0)
+#define pw_impl_port_emit_info_changed(p,i) pw_impl_port_emit(p, info_changed, 0, i)
+#define pw_impl_port_emit_link_added(p,l) pw_impl_port_emit(p, link_added, 0, l)
+#define pw_impl_port_emit_link_removed(p,l) pw_impl_port_emit(p, link_removed, 0, l)
+#define pw_impl_port_emit_state_changed(p,o,s,e) pw_impl_port_emit(p, state_changed, 0, o, s, e)
+#define pw_impl_port_emit_control_added(p,c) pw_impl_port_emit(p, control_added, 0, c)
+#define pw_impl_port_emit_control_removed(p,c) pw_impl_port_emit(p, control_removed, 0, c)
+#define pw_impl_port_emit_param_changed(p,i) pw_impl_port_emit(p, param_changed, 1, i)
+#define pw_impl_port_emit_latency_changed(p) pw_impl_port_emit(p, latency_changed, 2)
+
+#define PW_IMPL_PORT_IS_CONTROL(port) SPA_FLAG_MASK(port->flags, \
+ PW_IMPL_PORT_FLAG_BUFFERS|PW_IMPL_PORT_FLAG_CONTROL,\
+ PW_IMPL_PORT_FLAG_CONTROL)
+struct pw_impl_port {
+ struct spa_list link; /**< link in node port_list */
+
+ struct pw_impl_node *node; /**< owner node */
+ struct pw_global *global; /**< global for this port */
+ struct spa_hook global_listener;
+
+#define PW_IMPL_PORT_FLAG_TO_REMOVE (1<<0) /**< if the port should be removed from the
+ * implementation when destroyed */
+#define PW_IMPL_PORT_FLAG_BUFFERS (1<<1) /**< port has data */
+#define PW_IMPL_PORT_FLAG_CONTROL (1<<2) /**< port has control */
+#define PW_IMPL_PORT_FLAG_NO_MIXER (1<<3) /**< don't try to add mixer to port */
+ uint32_t flags;
+ uint64_t spa_flags;
+
+ enum pw_direction direction; /**< port direction */
+ uint32_t port_id; /**< port id */
+
+ enum pw_impl_port_state state; /**< state of the port */
+ const char *error; /**< error state */
+
+ struct pw_properties *properties; /**< properties of the port */
+ struct pw_port_info info;
+ struct spa_param_info params[MAX_PARAMS];
+
+ struct pw_buffers buffers; /**< buffers managed by this port, only on
+ * output ports, shared with all links */
+
+ struct spa_list links; /**< list of \ref pw_impl_link */
+
+ struct spa_list control_list[2];/**< list of \ref pw_control indexed by direction */
+
+ struct spa_hook_list listener_list;
+
+ struct spa_callbacks impl;
+
+ struct spa_node *mix; /**< port buffer mix/split */
+#define PW_IMPL_PORT_MIX_FLAG_MULTI (1<<0) /**< multi input or output */
+#define PW_IMPL_PORT_MIX_FLAG_MIX_ONLY (1<<1) /**< only negotiate mix ports */
+#define PW_IMPL_PORT_MIX_FLAG_NEGOTIATE (1<<2) /**< negotiate buffers */
+ uint32_t mix_flags; /**< flags for the mixing */
+ struct spa_handle *mix_handle; /**< mix plugin handle */
+ struct pw_buffers mix_buffers; /**< buffers between mixer and node */
+
+ struct spa_list mix_list; /**< list of \ref pw_impl_port_mix */
+ struct pw_map mix_port_map; /**< map from port_id from mixer */
+ uint32_t n_mix;
+
+ struct {
+ struct spa_io_buffers io; /**< io area of the port */
+ struct spa_io_clock clock; /**< io area of the clock */
+ struct spa_list mix_list;
+ struct spa_list node_link;
+ } rt; /**< data only accessed from the data thread */
+ unsigned int added:1;
+ unsigned int destroying:1;
+ int busy_count;
+
+ struct spa_latency_info latency[2]; /**< latencies */
+ unsigned int have_latency_param:1;
+
+ void *owner_data; /**< extra owner data */
+ void *user_data; /**< extra user data */
+};
+
+struct pw_control_link {
+ struct spa_list out_link;
+ struct spa_list in_link;
+ struct pw_control *output;
+ struct pw_control *input;
+ uint32_t out_port;
+ uint32_t in_port;
+ unsigned int valid:1;
+};
+
+#define pw_impl_link_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_impl_link_events, m, v, ##__VA_ARGS__)
+#define pw_impl_link_emit_destroy(l) pw_impl_link_emit(l, destroy, 0)
+#define pw_impl_link_emit_free(l) pw_impl_link_emit(l, free, 0)
+#define pw_impl_link_emit_initialized(l) pw_impl_link_emit(l, initialized, 0)
+#define pw_impl_link_emit_info_changed(l,i) pw_impl_link_emit(l, info_changed, 0, i)
+#define pw_impl_link_emit_state_changed(l,...) pw_impl_link_emit(l, state_changed, 0, __VA_ARGS__)
+#define pw_impl_link_emit_port_unlinked(l,p) pw_impl_link_emit(l, port_unlinked, 0, p)
+
+struct pw_impl_link {
+ struct pw_context *context; /**< context object */
+ struct spa_list link; /**< link in context link_list */
+ struct pw_global *global; /**< global for this link */
+ struct spa_hook global_listener;
+
+ char *name;
+
+ struct pw_link_info info; /**< introspectable link info */
+ struct pw_properties *properties; /**< extra link properties */
+
+ struct spa_io_buffers *io; /**< link io area */
+
+ struct pw_impl_port *output; /**< output port */
+ struct spa_list output_link; /**< link in output port links */
+ struct pw_impl_port *input; /**< input port */
+ struct spa_list input_link; /**< link in input port links */
+
+ struct spa_hook_list listener_list;
+
+ struct pw_control_link control;
+ struct pw_control_link notify;
+
+ struct {
+ struct pw_impl_port_mix out_mix; /**< port added to the output mixer */
+ struct pw_impl_port_mix in_mix; /**< port added to the input mixer */
+ struct pw_node_target target; /**< target to trigger the input node */
+ } rt;
+
+ void *user_data;
+
+ unsigned int registered:1;
+ unsigned int feedback:1;
+ unsigned int preparing:1;
+ unsigned int prepared:1;
+ unsigned int passive:1;
+};
+
+#define pw_resource_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_resource_events, m, v, ##__VA_ARGS__)
+
+#define pw_resource_emit_destroy(o) pw_resource_emit(o, destroy, 0)
+#define pw_resource_emit_pong(o,s) pw_resource_emit(o, pong, 0, s)
+#define pw_resource_emit_error(o,s,r,m) pw_resource_emit(o, error, 0, s, r, m)
+
+struct pw_resource {
+ struct spa_interface impl; /**< object implementation */
+
+ struct pw_context *context; /**< the context object */
+ struct pw_global *global; /**< global of resource */
+ struct spa_list link; /**< link in global resource_list */
+
+ struct pw_impl_client *client; /**< owner client */
+
+ uint32_t id; /**< per client unique id, index in client objects */
+ uint32_t permissions; /**< resource permissions */
+ const char *type; /**< type of the client interface */
+ uint32_t version; /**< version of the client interface */
+ uint32_t bound_id; /**< global id we are bound to */
+ int refcount;
+
+ unsigned int removed:1; /**< resource was removed from server */
+ unsigned int destroyed:1; /**< resource was destroyed */
+
+ struct spa_hook_list listener_list;
+ struct spa_hook_list object_listener_list;
+
+ const struct pw_protocol_marshal *marshal;
+
+ void *user_data; /**< extra user data */
+};
+
+#define pw_proxy_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_proxy_events, m, v, ##__VA_ARGS__)
+#define pw_proxy_emit_destroy(p) pw_proxy_emit(p, destroy, 0)
+#define pw_proxy_emit_bound(p,g) pw_proxy_emit(p, bound, 0, g)
+#define pw_proxy_emit_removed(p) pw_proxy_emit(p, removed, 0)
+#define pw_proxy_emit_done(p,s) pw_proxy_emit(p, done, 0, s)
+#define pw_proxy_emit_error(p,s,r,m) pw_proxy_emit(p, error, 0, s, r, m)
+
+struct pw_proxy {
+ struct spa_interface impl; /**< object implementation */
+
+ struct pw_core *core; /**< the owner core of this proxy */
+
+ uint32_t id; /**< client side id */
+ const char *type; /**< type of the interface */
+ uint32_t version; /**< client side version */
+ uint32_t bound_id; /**< global id we are bound to */
+ int refcount;
+ unsigned int zombie:1; /**< proxy is removed locally and waiting to
+ * be removed from server */
+ unsigned int removed:1; /**< proxy was removed from server */
+ unsigned int destroyed:1; /**< proxy was destroyed by client */
+ unsigned int in_map:1; /**< proxy is in core object map */
+
+ struct spa_hook_list listener_list;
+ struct spa_hook_list object_listener_list;
+
+ const struct pw_protocol_marshal *marshal; /**< protocol specific marshal functions */
+
+ void *user_data; /**< extra user data */
+};
+
+struct pw_core {
+ struct pw_proxy proxy;
+
+ struct pw_context *context; /**< context */
+ struct spa_list link; /**< link in context core_list */
+ struct pw_properties *properties; /**< extra properties */
+
+ struct pw_mempool *pool; /**< memory pool */
+ struct pw_core *core; /**< proxy for the core object */
+ struct spa_hook core_listener;
+ struct spa_hook proxy_core_listener;
+
+ struct pw_map objects; /**< map of client side proxy objects
+ * indexed with the client id */
+ struct pw_client *client; /**< proxy for the client object */
+
+ struct spa_list stream_list; /**< list of \ref pw_stream objects */
+ struct spa_list filter_list; /**< list of \ref pw_stream objects */
+
+ struct pw_protocol_client *conn; /**< the protocol client connection */
+ int recv_seq; /**< last received sequence number */
+ int send_seq; /**< last protocol result code */
+ uint64_t recv_generation; /**< last received registry generation */
+
+ unsigned int removed:1;
+ unsigned int destroyed:1;
+
+ void *user_data; /**< extra user data */
+};
+
+#define pw_stream_emit(s,m,v,...) spa_hook_list_call(&s->listener_list, struct pw_stream_events, m, v, ##__VA_ARGS__)
+#define pw_stream_emit_destroy(s) pw_stream_emit(s, destroy, 0)
+#define pw_stream_emit_state_changed(s,o,n,e) pw_stream_emit(s, state_changed,0,o,n,e)
+#define pw_stream_emit_io_changed(s,i,a,t) pw_stream_emit(s, io_changed,0,i,a,t)
+#define pw_stream_emit_param_changed(s,i,p) pw_stream_emit(s, param_changed,0,i,p)
+#define pw_stream_emit_add_buffer(s,b) pw_stream_emit(s, add_buffer, 0, b)
+#define pw_stream_emit_remove_buffer(s,b) pw_stream_emit(s, remove_buffer, 0, b)
+#define pw_stream_emit_process(s) pw_stream_emit(s, process, 0)
+#define pw_stream_emit_drained(s) pw_stream_emit(s, drained,0)
+#define pw_stream_emit_control_info(s,i,c) pw_stream_emit(s, control_info, 0, i, c)
+#define pw_stream_emit_command(s,c) pw_stream_emit(s, command,1,c)
+#define pw_stream_emit_trigger_done(s) pw_stream_emit(s, trigger_done,2)
+
+
+struct pw_stream {
+ struct pw_core *core; /**< the owner core */
+ struct spa_hook core_listener;
+
+ struct spa_list link; /**< link in the core */
+
+ char *name; /**< the name of the stream */
+ struct pw_properties *properties; /**< properties of the stream */
+
+ uint32_t node_id; /**< node id for remote node, available from
+ * CONFIGURE state and higher */
+ enum pw_stream_state state; /**< stream state */
+ char *error; /**< error reason when state is in error */
+
+ struct spa_hook_list listener_list;
+
+ struct pw_proxy *proxy;
+ struct spa_hook proxy_listener;
+
+ struct spa_hook node_listener;
+
+ struct spa_list controls;
+};
+
+#define pw_filter_emit(s,m,v,...) spa_hook_list_call(&(s)->listener_list, struct pw_filter_events, m, v, ##__VA_ARGS__)
+#define pw_filter_emit_destroy(s) pw_filter_emit(s, destroy, 0)
+#define pw_filter_emit_state_changed(s,o,n,e) pw_filter_emit(s, state_changed,0,o,n,e)
+#define pw_filter_emit_io_changed(s,p,i,d,t) pw_filter_emit(s, io_changed,0,p,i,d,t)
+#define pw_filter_emit_param_changed(s,p,i,f) pw_filter_emit(s, param_changed,0,p,i,f)
+#define pw_filter_emit_add_buffer(s,p,b) pw_filter_emit(s, add_buffer, 0, p, b)
+#define pw_filter_emit_remove_buffer(s,p,b) pw_filter_emit(s, remove_buffer, 0, p, b)
+#define pw_filter_emit_process(s,p) pw_filter_emit(s, process, 0, p)
+#define pw_filter_emit_drained(s) pw_filter_emit(s, drained, 0)
+#define pw_filter_emit_command(s,c) pw_filter_emit(s, command, 1, c)
+
+
+struct pw_filter {
+ struct pw_core *core; /**< the owner core proxy */
+ struct spa_hook core_listener;
+
+ struct spa_list link; /**< link in the core proxy */
+
+ char *name; /**< the name of the filter */
+ struct pw_properties *properties; /**< properties of the filter */
+
+ uint32_t node_id; /**< node id for remote node, available from
+ * CONFIGURE state and higher */
+ enum pw_filter_state state; /**< filter state */
+ char *error; /**< error reason when state is in error */
+
+ struct spa_hook_list listener_list;
+
+ struct pw_proxy *proxy;
+ struct spa_hook proxy_listener;
+
+ struct spa_list controls;
+};
+
+#define pw_impl_factory_emit(s,m,v,...) spa_hook_list_call(&s->listener_list, struct pw_impl_factory_events, m, v, ##__VA_ARGS__)
+
+#define pw_impl_factory_emit_destroy(s) pw_impl_factory_emit(s, destroy, 0)
+#define pw_impl_factory_emit_free(s) pw_impl_factory_emit(s, free, 0)
+#define pw_impl_factory_emit_initialized(s) pw_impl_factory_emit(s, initialized, 0)
+
+struct pw_impl_factory {
+ struct pw_context *context; /**< the context */
+ struct spa_list link; /**< link in context factory_list */
+ struct pw_global *global; /**< global for this factory */
+ struct spa_hook global_listener;
+
+ struct pw_factory_info info; /**< introspectable factory info */
+ struct pw_properties *properties; /**< properties of the factory */
+
+ struct spa_hook_list listener_list; /**< event listeners */
+
+ struct spa_callbacks impl;
+
+ void *user_data;
+
+ unsigned int registered:1;
+};
+
+#define pw_control_emit(c,m,v,...) spa_hook_list_call(&c->listener_list, struct pw_control_events, m, v, ##__VA_ARGS__)
+#define pw_control_emit_destroy(c) pw_control_emit(c, destroy, 0)
+#define pw_control_emit_free(c) pw_control_emit(c, free, 0)
+#define pw_control_emit_linked(c,o) pw_control_emit(c, linked, 0, o)
+#define pw_control_emit_unlinked(c,o) pw_control_emit(c, unlinked, 0, o)
+
+struct pw_control {
+ struct spa_list link; /**< link in context control_list */
+ struct pw_context *context; /**< the context */
+
+ struct pw_impl_port *port; /**< owner port or NULL */
+ struct spa_list port_link; /**< link in port control_list */
+
+ enum spa_direction direction; /**< the direction */
+ struct spa_list links; /**< list of pw_control_link */
+
+ uint32_t id;
+ int32_t size;
+
+ struct spa_hook_list listener_list;
+
+ void *user_data;
+};
+
+/** Find a good format between 2 ports */
+int pw_context_find_format(struct pw_context *context,
+ struct pw_impl_port *output,
+ struct pw_impl_port *input,
+ struct pw_properties *props,
+ uint32_t n_format_filters,
+ struct spa_pod **format_filters,
+ struct spa_pod **format,
+ struct spa_pod_builder *builder,
+ char **error);
+
+/** Find a ports compatible with \a other_port and the format filters */
+struct pw_impl_port *
+pw_context_find_port(struct pw_context *context,
+ struct pw_impl_port *other_port,
+ uint32_t id,
+ struct pw_properties *props,
+ uint32_t n_format_filters,
+ struct spa_pod **format_filters,
+ char **error);
+
+int pw_context_debug_port_params(struct pw_context *context,
+ struct spa_node *node, enum spa_direction direction,
+ uint32_t port_id, uint32_t id, int err, const char *debug, ...);
+
+const struct pw_export_type *pw_context_find_export_type(struct pw_context *context, const char *type);
+
+int pw_proxy_init(struct pw_proxy *proxy, const char *type, uint32_t version);
+
+void pw_proxy_remove(struct pw_proxy *proxy);
+
+int pw_context_recalc_graph(struct pw_context *context, const char *reason);
+
+void pw_impl_port_update_info(struct pw_impl_port *port, const struct spa_port_info *info);
+
+int pw_impl_port_register(struct pw_impl_port *port,
+ struct pw_properties *properties);
+
+/** Get the user data of a port, the size of the memory was given \ref in pw_context_create_port */
+void * pw_impl_port_get_user_data(struct pw_impl_port *port);
+
+int pw_impl_port_set_mix(struct pw_impl_port *port, struct spa_node *node, uint32_t flags);
+
+int pw_impl_port_init_mix(struct pw_impl_port *port, struct pw_impl_port_mix *mix);
+int pw_impl_port_release_mix(struct pw_impl_port *port, struct pw_impl_port_mix *mix);
+
+void pw_impl_port_update_state(struct pw_impl_port *port, enum pw_impl_port_state state, int res, char *error);
+
+/** Unlink a port */
+void pw_impl_port_unlink(struct pw_impl_port *port);
+
+/** Destroy a port */
+void pw_impl_port_destroy(struct pw_impl_port *port);
+
+/** Iterate the params of the given port. The callback should return
+ * 1 to fetch the next item, 0 to stop iteration or <0 on error.
+ * The function returns 0 on success or the error returned by the callback. */
+int pw_impl_port_for_each_param(struct pw_impl_port *port,
+ int seq, uint32_t param_id,
+ uint32_t index, uint32_t max,
+ const struct spa_pod *filter,
+ int (*callback) (void *data, int seq,
+ uint32_t id, uint32_t index, uint32_t next,
+ struct spa_pod *param),
+ void *data);
+
+int pw_impl_port_for_each_filtered_param(struct pw_impl_port *in_port,
+ struct pw_impl_port *out_port,
+ int seq,
+ uint32_t in_param_id,
+ uint32_t out_param_id,
+ const struct spa_pod *filter,
+ int (*callback) (void *data, int seq,
+ uint32_t id, uint32_t index, uint32_t next,
+ struct spa_pod *param),
+ void *data);
+
+/** Iterate the links of the port. 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
+ * items are iterated. */
+int pw_impl_port_for_each_link(struct pw_impl_port *port,
+ int (*callback) (void *data, struct pw_impl_link *link),
+ void *data);
+
+/** Set a param on a port, use SPA_ID_INVALID for mix_id to set
+ * the param on all mix ports */
+int pw_impl_port_set_param(struct pw_impl_port *port,
+ uint32_t id, uint32_t flags, const struct spa_pod *param);
+
+/** Use buffers on a port */
+int pw_impl_port_use_buffers(struct pw_impl_port *port, struct pw_impl_port_mix *mix, uint32_t flags,
+ struct spa_buffer **buffers, uint32_t n_buffers);
+
+int pw_impl_port_recalc_latency(struct pw_impl_port *port);
+
+/** Change the state of the node */
+int pw_impl_node_set_state(struct pw_impl_node *node, enum pw_node_state state);
+
+int pw_impl_node_set_param(struct pw_impl_node *node,
+ uint32_t id, uint32_t flags, const struct spa_pod *param);
+
+int pw_impl_node_update_ports(struct pw_impl_node *node);
+
+int pw_impl_node_set_driver(struct pw_impl_node *node, struct pw_impl_node *driver);
+
+/** Prepare a link
+ * Starts the negotiation of formats and buffers on \a link */
+int pw_impl_link_prepare(struct pw_impl_link *link);
+/** starts streaming on a link */
+int pw_impl_link_activate(struct pw_impl_link *link);
+
+/** Deactivate a link */
+int pw_impl_link_deactivate(struct pw_impl_link *link);
+
+struct pw_control *
+pw_control_new(struct pw_context *context,
+ struct pw_impl_port *owner, /**< can be NULL */
+ uint32_t id, uint32_t size,
+ size_t user_data_size /**< extra user data */);
+
+int pw_control_add_link(struct pw_control *control, uint32_t cmix,
+ struct pw_control *other, uint32_t omix,
+ struct pw_control_link *link);
+
+int pw_control_remove_link(struct pw_control_link *link);
+
+void pw_control_destroy(struct pw_control *control);
+
+void pw_impl_client_unref(struct pw_impl_client *client);
+
+#define PW_LOG_OBJECT_POD (1<<0)
+void pw_log_log_object(enum spa_log_level level, const char *file, int line,
+ const char *func, uint32_t flags, const void *object);
+
+#define pw_log_object(lev,fl,obj) \
+({ \
+ if (SPA_UNLIKELY(pw_log_level_enabled (lev))) \
+ pw_log_log_object(lev,__FILE__,__LINE__,__func__,(fl),(obj)); \
+})
+
+#define pw_log_pod(lev,pod) pw_log_object(lev,PW_LOG_OBJECT_POD,pod)
+#define pw_log_format(lev,pod) pw_log_object(lev,PW_LOG_OBJECT_POD,pod)
+
+bool pw_log_is_default(void);
+
+void pw_log_init(void);
+void pw_log_deinit(void);
+
+void pw_settings_init(struct pw_context *context);
+int pw_settings_expose(struct pw_context *context);
+void pw_settings_clean(struct pw_context *context);
+
+void pw_impl_module_schedule_destroy(struct pw_impl_module *module);
+
+pthread_attr_t *pw_thread_fill_attr(const struct spa_dict *props, pthread_attr_t *attr);
+
+/** \endcond */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_PRIVATE_H */
diff --git a/third_party/pipewire/pipewire/properties.h b/third_party/pipewire/pipewire/properties.h
new file mode 100644
index 0000000000..e91fee5217
--- /dev/null
+++ b/third_party/pipewire/pipewire/properties.h
@@ -0,0 +1,199 @@
+/* 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>
+#include <spa/utils/string.h>
+
+/** \defgroup pw_properties Properties
+ *
+ * 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.
+ */
+
+/**
+ * \addtogroup pw_properties
+ * \{
+ */
+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 * const keys[]);
+int pw_properties_update_ignore(struct pw_properties *props,
+ const struct spa_dict *dict, const char * const ignore[]);
+
+/* Update props with all key/value pairs from dict */
+int pw_properties_update(struct pw_properties *props,
+ const struct spa_dict *dict);
+/* Update props with all key/value pairs from str */
+int pw_properties_update_string(struct pw_properties *props,
+ const char *str, size_t size);
+
+int pw_properties_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 * const 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);
+
+int
+pw_properties_fetch_uint32(const struct pw_properties *properties, const char *key, uint32_t *value);
+
+int
+pw_properties_fetch_int32(const struct pw_properties *properties, const char *key, int32_t *value);
+
+int
+pw_properties_fetch_uint64(const struct pw_properties *properties, const char *key, uint64_t *value);
+
+int
+pw_properties_fetch_int64(const struct pw_properties *properties, const char *key, int64_t *value);
+
+int
+pw_properties_fetch_bool(const struct pw_properties *properties, const char *key, bool *value);
+
+static inline uint32_t
+pw_properties_get_uint32(const struct pw_properties *properties, const char *key, uint32_t deflt)
+{
+ uint32_t val = deflt;
+ pw_properties_fetch_uint32(properties, key, &val);
+ return val;
+}
+
+static inline int32_t
+pw_properties_get_int32(const struct pw_properties *properties, const char *key, int32_t deflt)
+{
+ int32_t val = deflt;
+ pw_properties_fetch_int32(properties, key, &val);
+ return val;
+}
+
+static inline uint64_t
+pw_properties_get_uint64(const struct pw_properties *properties, const char *key, uint64_t deflt)
+{
+ uint64_t val = deflt;
+ pw_properties_fetch_uint64(properties, key, &val);
+ return val;
+}
+
+static inline int64_t
+pw_properties_get_int64(const struct pw_properties *properties, const char *key, int64_t deflt)
+{
+ int64_t val = deflt;
+ pw_properties_fetch_int64(properties, key, &val);
+ return val;
+}
+
+
+static inline bool
+pw_properties_get_bool(const struct pw_properties *properties, const char *key, bool deflt)
+{
+ bool val = deflt;
+ pw_properties_fetch_bool(properties, key, &val);
+ return val;
+}
+
+const char *
+pw_properties_iterate(const struct pw_properties *properties, void **state);
+
+#define PW_PROPERTIES_FLAG_NL (1<<0)
+int pw_properties_serialize_dict(FILE *f, const struct spa_dict *dict, uint32_t flags);
+
+static inline bool pw_properties_parse_bool(const char *value) {
+ return spa_atob(value);
+}
+
+static inline int pw_properties_parse_int(const char *value) {
+ int v;
+ return spa_atoi32(value, &v, 0) ? v: 0;
+}
+
+static inline int64_t pw_properties_parse_int64(const char *value) {
+ int64_t v;
+ return spa_atoi64(value, &v, 0) ? v : 0;
+}
+
+static inline uint64_t pw_properties_parse_uint64(const char *value) {
+ uint64_t v;
+ return spa_atou64(value, &v, 0) ? v : 0;
+}
+
+static inline float pw_properties_parse_float(const char *value) {
+ float v;
+ return spa_atof(value, &v) ? v : 0.0f;
+}
+
+static inline double pw_properties_parse_double(const char *value) {
+ double v;
+ return spa_atod(value, &v) ? v : 0.0;
+}
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_PROPERTIES_H */
diff --git a/third_party/pipewire/pipewire/protocol.h b/third_party/pipewire/pipewire/protocol.h
new file mode 100644
index 0000000000..bb97273065
--- /dev/null
+++ b/third_party/pipewire/pipewire/protocol.h
@@ -0,0 +1,162 @@
+/* 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>
+
+/** \defgroup pw_protocol Protocol
+ *
+ * \brief Manages protocols and their implementation
+ */
+
+/**
+ * \addtogroup pw_protocol
+ * \{
+ */
+
+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);
+
+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/third_party/pipewire/pipewire/proxy.h b/third_party/pipewire/pipewire/proxy.h
new file mode 100644
index 0000000000..1e15dcccef
--- /dev/null
+++ b/third_party/pipewire/pipewire/proxy.h
@@ -0,0 +1,219 @@
+/* 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_context_connect.
+ * See \ref pw_proxy
+ *
+ * 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.
+ */
+
+/** \defgroup pw_proxy 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
+ */
+
+/**
+ * \addtogroup pw_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,
+ 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);
+
+void pw_proxy_ref(struct pw_proxy *proxy);
+void pw_proxy_unref(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/third_party/pipewire/pipewire/resource.h b/third_party/pipewire/pipewire/resource.h
new file mode 100644
index 0000000000..24d458cb00
--- /dev/null
+++ b/third_party/pipewire/pipewire/resource.h
@@ -0,0 +1,174 @@
+/* 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_RESOURCE_H
+#define PIPEWIRE_RESOURCE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/hook.h>
+
+/** \defgroup pw_resource Resource
+ *
+ * \brief Client owned objects
+ *
+ * Resources represent objects owned by a \ref pw_impl_client. They are
+ * the result of binding to a global resource or by calling API that
+ * creates client owned objects.
+ *
+ * The client usually has a proxy object associated with the resource
+ * that it can use to communicate with the resource. See \ref page_proxy.
+ *
+ * Resources are destroyed when the client or the bound object is
+ * destroyed.
+ *
+ */
+
+
+/**
+ * \addtogroup pw_resource
+ * \{
+ */
+struct pw_resource;
+
+#include <pipewire/impl-client.h>
+
+/** Resource events */
+struct pw_resource_events {
+#define PW_VERSION_RESOURCE_EVENTS 0
+ uint32_t version;
+
+ /** The resource is destroyed */
+ void (*destroy) (void *data);
+
+ /** a reply to a ping event completed */
+ void (*pong) (void *data, int seq);
+
+ /** an error occurred on the resource */
+ void (*error) (void *data, int seq, int res, const char *message);
+};
+
+/** Make a new resource for client */
+struct pw_resource *
+pw_resource_new(struct pw_impl_client *client, /**< the client owning the resource */
+ uint32_t id, /**< the remote per client id */
+ uint32_t permissions, /**< permissions on this resource */
+ const char *type, /**< interface of the resource */
+ uint32_t version, /**< requested interface version */
+ size_t user_data_size /**< extra user data size */);
+
+/** Destroy a resource */
+void pw_resource_destroy(struct pw_resource *resource);
+
+/** Remove a resource, like pw_resource_destroy but without sending a
+ * remove_id message to the client */
+void pw_resource_remove(struct pw_resource *resource);
+
+/** Get the client owning this resource */
+struct pw_impl_client *pw_resource_get_client(struct pw_resource *resource);
+
+/** Get the unique id of this resource */
+uint32_t pw_resource_get_id(struct pw_resource *resource);
+
+/** Get the permissions of this resource */
+uint32_t pw_resource_get_permissions(struct pw_resource *resource);
+
+/** Get the type and optionally the version of this resource */
+const char *pw_resource_get_type(struct pw_resource *resource, uint32_t *version);
+
+/** Get the protocol used for this resource */
+struct pw_protocol *pw_resource_get_protocol(struct pw_resource *resource);
+
+/** Get the user data for the resource, the size was given in \ref pw_resource_new */
+void *pw_resource_get_user_data(struct pw_resource *resource);
+
+/** Add an event listener */
+void pw_resource_add_listener(struct pw_resource *resource,
+ struct spa_hook *listener,
+ const struct pw_resource_events *events,
+ void *data);
+
+/** Set the resource implementation. */
+void pw_resource_add_object_listener(struct pw_resource *resource,
+ struct spa_hook *listener,
+ const void *funcs,
+ void *data);
+
+/** Generate an ping event for a resource. This will generate a pong event
+ * with the same \a sequence number in the return value. */
+int pw_resource_ping(struct pw_resource *resource, int seq);
+
+/** ref/unref a resource, Since 0.3.52 */
+void pw_resource_ref(struct pw_resource *resource);
+void pw_resource_unref(struct pw_resource *resource);
+
+/** Notify global id this resource is bound to */
+int pw_resource_set_bound_id(struct pw_resource *resource, uint32_t global_id);
+
+/** Get the global id this resource is bound to or SPA_ID_INVALID when not bound */
+uint32_t pw_resource_get_bound_id(struct pw_resource *resource);
+
+/** Generate an error for a resource */
+void pw_resource_error(struct pw_resource *resource, int res, const char *error);
+void pw_resource_errorf(struct pw_resource *resource, int res, const char *error, ...) SPA_PRINTF_FUNC(3, 4);
+void pw_resource_errorf_id(struct pw_resource *resource, uint32_t id, int res, const char *error, ...) SPA_PRINTF_FUNC(4, 5);
+
+/** Get the list of object listeners from a resource */
+struct spa_hook_list *pw_resource_get_object_listeners(struct pw_resource *resource);
+
+/** Get the marshal functions for the resource */
+const struct pw_protocol_marshal *pw_resource_get_marshal(struct pw_resource *resource);
+
+/** install a marshal function on a resource */
+int pw_resource_install_marshal(struct pw_resource *resource, bool implementor);
+
+#define pw_resource_notify(r,type,event,version,...) \
+ spa_hook_list_call(pw_resource_get_object_listeners(r), \
+ type, event, version, ## __VA_ARGS__)
+
+#define pw_resource_call(r,type,method,version,...) \
+ spa_interface_call((struct spa_interface*)r, \
+ type, method, version, ##__VA_ARGS__)
+
+#define pw_resource_call_res(r,type,method,version,...) \
+({ \
+ int _res = -ENOTSUP; \
+ spa_interface_call_res((struct spa_interface*)r, \
+ type, _res, method, version, ##__VA_ARGS__); \
+ _res; \
+})
+
+
+/**
+ * \}
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_RESOURCE_H */
diff --git a/third_party/pipewire/pipewire/stream.h b/third_party/pipewire/pipewire/stream.h
new file mode 100644
index 0000000000..e61213dd0d
--- /dev/null
+++ b/third_party/pipewire/pipewire/stream.h
@@ -0,0 +1,521 @@
+/* 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 Streams
+ *
+ * \section sec_overview Overview
+ *
+ * \ref pw_stream "Streams" are used to exchange data with the
+ * PipeWire server. A stream is a wrapper around a proxy for a 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.
+ *
+ * Streams can also be used to:
+ *
+ * \li Implement a Sink in PipeWire. This is a PW_DIRECTION_INPUT stream.
+ * \li Implement a Source in PipeWire. This is a PW_DIRECTION_OUTPUT stream
+ *
+ * In this case, the PW_KEY_MEDIA_CLASS property needs to be set to
+ * "Audio/Sink" or "Audio/Source" respectively.
+ *
+ * \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. The basic set of properties
+ * each stream must provide is filled in automatically.
+ *
+ * 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.
+ *
+ * The direction is:
+
+ * \li PW_DIRECTION_INPUT for a stream that *consumes* data. This can be a
+ * stream that captures from a Source or a when the stream is used to
+ * implement a Sink.
+ *
+ * \li PW_DIRECTION_OUTPUT for a stream that *produces* data. This can be a
+ * stream that plays to a Sink or when the stream is used to implement
+ * a Source.
+ *
+ * \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. The buffers can only be used with the stream that emitted
+ * the add_buffer event.
+ *
+ * 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.
+ *
+ * The buffer is owned by the stream and stays alive until the
+ * remove_buffer event is emitted or the stream is destroyed.
+ *
+ * When the buffer has been processed, 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.
+ *
+ * The buffer is owned by the stream and stays alive until the
+ * remove_buffer event is emitted or the stream is destroyed.
+ *
+ * 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.
+ *
+ * \section sec_stream_configuration Configuration
+ *
+ * \subsection ssec_config_properties Stream Properties
+ *
+ * \subsection ssec_config_rules Stream Rules
+ *
+ * \section sec_stream_environment Environment Variables
+ *
+ */
+/** \defgroup pw_stream Stream
+ *
+ * \brief PipeWire stream objects
+ *
+ * The stream object provides a convenient way to send and
+ * receive data streams from/to PipeWire.
+ *
+ * See also \ref page_streams and \ref api_pw_core
+ */
+
+/**
+ * \addtogroup pw_stream
+ * \{
+ */
+struct pw_stream;
+
+#include <spa/buffer/buffer.h>
+#include <spa/param/param.h>
+#include <spa/pod/command.h>
+
+/** \enum pw_stream_state The state of a 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 */
+};
+
+/** a buffer structure obtained from pw_stream_dequeue_buffer(). The size of this
+ * structure can grow as more field are added in the future */
+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.
+ * For audio, it is advised to use the number of
+ * samples in the buffer for this field. */
+ uint64_t requested; /**< For playback streams, this field contains the
+ * suggested amount of data to provide. For audio
+ * streams this will be the amount of samples
+ * required by the resampler. This field is 0
+ * when no suggestion is provided. Since 0.3.49 */
+};
+
+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.
+ *
+ * Use pw_stream_get_time_n() to get an updated time snapshot of the stream.
+ * The time snapshot can give information about the time in the driver of the
+ * graph, the delay to the edge of the graph and the internal queuing in the
+ * stream.
+ *
+ * pw_time.ticks gives a monotonic increasing counter of the time in the graph
+ * driver. I can be used to generate a timetime to schedule samples as well
+ * as detect discontinuities in the timeline caused by xruns.
+ *
+ * pw_time.delay is expressed as pw_time.rate, the time domain of the graph. This
+ * value, and pw_time.ticks, were captured at pw_time.now and can be extrapolated
+ * to the current time like this:
+ *
+ * struct timespec ts;
+ * clock_gettime(CLOCK_MONOTONIC, &ts);
+ * int64_t diff = SPA_TIMESPEC_TO_NSEC(&ts) - pw_time.now;
+ * int64_t elapsed = (pw_time.rate.denom * diff) / (pw_time.rate.num * SPA_NSEC_PER_SEC);
+ *
+ * pw_time.delay contains the total delay that a signal will travel through the
+ * graph. This includes the delay caused by filters in the graph as well as delays
+ * caused by the hardware. The delay is usually quite stable and should only change when
+ * the topology, quantum or samplerate of the graph changes.
+ *
+ * pw_time.queued and pw_time.buffered is expressed in the time domain of the stream,
+ * or the format that is used for the buffers of this stream.
+ *
+ * pw_time.queued is the sum of all the pw_buffer.size fields of the buffers that are
+ * currently queued in the stream but not yet processed. The application can choose
+ * the units of this value, for example, time, samples or bytes (below expressed
+ * as app.rate).
+ *
+ * pw_time.buffered is format dependent, for audio/raw it contains the number of samples
+ * that are buffered inside the resampler/converter.
+ *
+ * The total delay of data in a stream is the sum of the queued and buffered data
+ * (not yet processed data) and the delay to the edge of the graph, usually a
+ * playback or capture device.
+ *
+ * For an audio playback stream, if you were to queue a buffer, the total delay
+ * in milliseconds for the first sample in the newly queued buffer to be played
+ * by the hardware can be calculated as:
+ *
+ * (pw_time.buffered * 1000 / stream.samplerate) +
+ * (pw_time.queued * 1000 / app.rate) +
+ * ((pw_time.delay - elapsed) * 1000 * pw_time.rate.num / pw_time.rate.denom)
+ *
+ * The current extrapolated time (in ms) in the source or sink can be calculated as:
+ *
+ * (pw_time.ticks + elapsed) * 1000 * pw_time.rate.num / pw_time.rate.denom
+ *
+ *
+ * stream time domain graph time domain
+ * /-----------------------\/-----------------------------\
+ *
+ * queue +-+ +-+ +-----------+ +--------+
+ * ----> | | | |->| converter | -> graph -> | kernel | -> speaker
+ * <---- +-+ +-+ +-----------+ +--------+
+ * dequeue buffers \-------------------/\--------/
+ * graph internal
+ * latency latency
+ * \--------/\-------------/\-----------------------------/
+ * queued buffered delay
+ */
+struct pw_time {
+ int64_t now; /**< the monotonic time in nanoseconds. This is the time
+ * when this time report was updated. It is usually
+ * updated every graph cycle. You can use the current
+ * monotonic time to calculate the elapsed time between
+ * this report and the current state and calculate
+ * updated ticks and delay values. */
+ struct spa_fraction rate; /**< the rate of \a ticks and delay. This is usually
+ * expressed in 1/<samplerate>. */
+ uint64_t ticks; /**< the ticks at \a now. This is the current time that
+ * the remote end is reading/writing. This is monotonicaly
+ * increasing. */
+ int64_t delay; /**< delay to device. This is the time it will take for
+ * the next output sample of the stream to be presented by
+ * the playback device or the time a sample traveled
+ * from the capture device. This delay includes the
+ * delay introduced by all filters on the path between
+ * the stream and the device. The delay is normally
+ * constant in a graph and can change when the topology
+ * of the graph or the quantum changes. This delay does
+ * not include the delay caused by queued buffers. */
+ uint64_t queued; /**< data queued in the stream, this is the sum
+ * of the size fields in the pw_buffer that are
+ * currently queued */
+ uint64_t buffered; /**< for audio/raw streams, this contains the extra
+ * number of samples buffered in the resampler.
+ * Since 0.3.50. */
+ uint32_t queued_buffers; /**< The number of buffers that are queued. Since 0.3.50 */
+ uint32_t avail_buffers; /**< The number of buffers that can be dequeued. Since 0.3.50 */
+};
+
+#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 2
+ 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);
+
+ /** A command notify, Since 0.3.39:1 */
+ void (*command) (void *data, const struct spa_command *command);
+
+ /** a trigger_process completed. Since version 0.3.40:2 */
+ void (*trigger_done) (void *data);
+};
+
+/** Convert a stream state to a readable string */
+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() */
+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 */
+ PW_STREAM_FLAG_TRIGGER = (1 << 9), /**< the output stream will not be scheduled
+ * automatically but _trigger_process()
+ * needs to be called. This can be used
+ * when the output of the stream depends
+ * on input from other streams. */
+};
+
+/** Create a new unconneced \ref 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 */
+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.
+ * \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.
+ * \return node ID. */
+uint32_t
+pw_stream_get_node_id(struct pw_stream *stream);
+
+/** Disconnect \a 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
+ *
+ * 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 */);
+
+/** Get control values */
+const struct pw_stream_control *pw_stream_get_control(struct pw_stream *stream, uint32_t id);
+
+/** Set control values */
+int pw_stream_set_control(struct pw_stream *stream, uint32_t id, uint32_t n_values, float *values, ...);
+
+/** Query the time on the stream */
+int pw_stream_get_time_n(struct pw_stream *stream, struct pw_time *time, size_t size);
+
+/** Query the time on the stream, deprecated since 0.3.50,
+ * use pw_stream_get_time_n() to get the fields added since 0.3.50. */
+SPA_DEPRECATED
+int pw_stream_get_time(struct pw_stream *stream, struct pw_time *time);
+
+/** Get a buffer that can be filled for playback streams or consumed
+ * for capture streams. */
+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 */
+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);
+
+/** Check if the stream is driving. The stream needs to have the
+ * PW_STREAM_FLAG_DRIVER set. When the stream is driving,
+ * pw_stream_trigger_process() needs to be called when data is
+ * available (output) or needed (input). Since 0.3.34 */
+bool pw_stream_is_driving(struct pw_stream *stream);
+
+/** Trigger a push/pull on the stream. One iteration of the graph will
+ * scheduled and process() will be called. Since 0.3.34 */
+int pw_stream_trigger_process(struct pw_stream *stream);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_STREAM_H */
diff --git a/third_party/pipewire/pipewire/thread-loop.h b/third_party/pipewire/pipewire/thread-loop.h
new file mode 100644
index 0000000000..13e8532ca2
--- /dev/null
+++ b/third_party/pipewire/pipewire/thread-loop.h
@@ -0,0 +1,175 @@
+/* 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_THREAD_LOOP_H
+#define PIPEWIRE_THREAD_LOOP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <pipewire/loop.h>
+
+/** \page page_thread_loop Thread Loop
+ *
+ * \section sec_thread_loop_overview Overview
+ *
+ * The threaded loop implementation is a special wrapper around the
+ * regular \ref pw_loop implementation.
+ *
+ * The added feature in the threaded loop is that it spawns a new thread
+ * that runs the wrapped loop. This allows a synchronous application to use
+ * the asynchronous API without risking to stall the PipeWire library.
+ *
+ * \section sec_thread_loop_create Creation
+ *
+ * A \ref pw_thread_loop object is created using pw_thread_loop_new().
+ * The \ref pw_loop to wrap must be given as an argument along with the name
+ * for the thread that will be spawned.
+ *
+ * After allocating the object, the thread must be started with
+ * pw_thread_loop_start()
+ *
+ * \section sec_thread_loop_destruction Destruction
+ *
+ * When the PipeWire connection has been terminated, the thread must be
+ * stopped and the resources freed. Stopping the thread is done using
+ * pw_thread_loop_stop(), which must be called without the lock (see
+ * below) held. When that function returns, the thread is stopped and the
+ * \ref pw_thread_loop object can be freed using pw_thread_loop_destroy().
+ *
+ * \section sec_thread_loop_locking Locking
+ *
+ * Since the PipeWire API doesn't allow concurrent accesses to objects,
+ * a locking scheme must be used to guarantee safe usage. The threaded
+ * loop API provides such a scheme through the functions
+ * pw_thread_loop_lock() and pw_thread_loop_unlock().
+ *
+ * The lock is recursive, so it's safe to use it multiple times from the same
+ * thread. Just make sure you call pw_thread_loop_unlock() the same
+ * number of times you called pw_thread_loop_lock().
+ *
+ * The lock needs to be held whenever you call any PipeWire function that
+ * uses an object associated with this loop. Make sure you do not hold
+ * on to the lock more than necessary though, as the threaded loop stops
+ * while the lock is held.
+ *
+ * \section sec_thread_loop_events Events and Callbacks
+ *
+ * All events and callbacks are called with the thread lock held.
+ *
+ */
+/** \defgroup pw_thread_loop Thread Loop
+ *
+ * The threaded loop object runs a \ref pw_loop in a separate thread
+ * and ensures proper locking is done.
+ *
+ * All of the loop callbacks will be executed with the loop
+ * lock held.
+ *
+ * See also \ref page_thread_loop
+ */
+
+/**
+ * \addtogroup pw_thread_loop
+ * \{
+ */
+struct pw_thread_loop;
+
+/** Thread loop events */
+struct pw_thread_loop_events {
+#define PW_VERSION_THREAD_LOOP_EVENTS 0
+ uint32_t version;
+
+ /** the loop is destroyed */
+ void (*destroy) (void *data);
+};
+
+/** Make a new thread loop with the given name and optional properties. */
+struct pw_thread_loop *
+pw_thread_loop_new(const char *name, const struct spa_dict *props);
+
+/** Make a new thread loop with the given loop, name and optional properties.
+ * When \a loop is NULL, a new loop will be created. */
+struct pw_thread_loop *
+pw_thread_loop_new_full(struct pw_loop *loop, const char *name, const struct spa_dict *props);
+
+/** Destroy a thread loop */
+void pw_thread_loop_destroy(struct pw_thread_loop *loop);
+
+/** Add an event listener */
+void pw_thread_loop_add_listener(struct pw_thread_loop *loop,
+ struct spa_hook *listener,
+ const struct pw_thread_loop_events *events,
+ void *data);
+
+/** Get the loop implementation of the thread loop */
+struct pw_loop * pw_thread_loop_get_loop(struct pw_thread_loop *loop);
+
+/** Start the thread loop */
+int pw_thread_loop_start(struct pw_thread_loop *loop);
+
+/** Stop the thread loop */
+void pw_thread_loop_stop(struct pw_thread_loop *loop);
+
+/** Lock the loop. This ensures exclusive ownership of the loop */
+void pw_thread_loop_lock(struct pw_thread_loop *loop);
+
+/** Unlock the loop */
+void pw_thread_loop_unlock(struct pw_thread_loop *loop);
+
+/** Release the lock and wait until some thread calls \ref pw_thread_loop_signal */
+void pw_thread_loop_wait(struct pw_thread_loop *loop);
+
+/** Release the lock and wait a maximum of 'wait_max_sec' seconds
+ * until some thread calls \ref pw_thread_loop_signal or time out */
+int pw_thread_loop_timed_wait(struct pw_thread_loop *loop, int wait_max_sec);
+
+/** Get a struct timespec suitable for \ref pw_thread_loop_timed_wait_full.
+ * Since: 0.3.7 */
+int pw_thread_loop_get_time(struct pw_thread_loop *loop, struct timespec *abstime, int64_t timeout);
+
+/** Release the lock and wait up to \a abstime until some thread calls
+ * \ref pw_thread_loop_signal. Use \ref pw_thread_loop_get_time to make a timeout.
+ * Since: 0.3.7 */
+int pw_thread_loop_timed_wait_full(struct pw_thread_loop *loop, struct timespec *abstime);
+
+/** Signal all threads waiting with \ref pw_thread_loop_wait */
+void pw_thread_loop_signal(struct pw_thread_loop *loop, bool wait_for_accept);
+
+/** Signal all threads executing \ref pw_thread_loop_signal with wait_for_accept */
+void pw_thread_loop_accept(struct pw_thread_loop *loop);
+
+/** Check if inside the thread */
+bool pw_thread_loop_in_thread(struct pw_thread_loop *loop);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_THREAD_LOOP_H */
diff --git a/third_party/pipewire/pipewire/thread.h b/third_party/pipewire/pipewire/thread.h
new file mode 100644
index 0000000000..ba84a5dd95
--- /dev/null
+++ b/third_party/pipewire/pipewire/thread.h
@@ -0,0 +1,65 @@
+/* PipeWire
+ *
+ * Copyright © 2021 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_THREAD_H
+#define PIPEWIRE_THREAD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+#include <errno.h>
+
+#include <spa/support/thread.h>
+
+/** \defgroup pw_thread Thread
+ *
+ * \brief functions to manipulate threads
+ */
+
+/**
+ * \addtogroup pw_thread
+ * \{
+ */
+
+SPA_DEPRECATED
+void pw_thread_utils_set(struct spa_thread_utils *impl);
+struct spa_thread_utils *pw_thread_utils_get(void);
+
+#define pw_thread_utils_create(...) spa_thread_utils_create(pw_thread_utils_get(), ##__VA_ARGS__)
+#define pw_thread_utils_join(...) spa_thread_utils_join(pw_thread_utils_get(), ##__VA_ARGS__)
+#define pw_thread_utils_get_rt_range(...) spa_thread_utils_get_rt_range(pw_thread_utils_get(), ##__VA_ARGS__)
+#define pw_thread_utils_acquire_rt(...) spa_thread_utils_acquire_rt(pw_thread_utils_get(), ##__VA_ARGS__)
+#define pw_thread_utils_drop_rt(...) spa_thread_utils_drop_rt(pw_thread_utils_get(), ##__VA_ARGS__)
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PIPEWIRE_THREAD_H */
diff --git a/third_party/pipewire/pipewire/type.h b/third_party/pipewire/pipewire/type.h
new file mode 100644
index 0000000000..3572531ad6
--- /dev/null
+++ b/third_party/pipewire/pipewire/type.h
@@ -0,0 +1,65 @@
+/* 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_TYPE_H
+#define PIPEWIRE_TYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/type.h>
+
+/** \defgroup pw_type Type info
+ * Type information
+ */
+
+/**
+ * \addtogroup pw_type
+ * \{
+ */
+
+enum {
+ PW_TYPE_FIRST = SPA_TYPE_VENDOR_PipeWire,
+};
+
+#define PW_TYPE_INFO_BASE "PipeWire:"
+
+#define PW_TYPE_INFO_Object PW_TYPE_INFO_BASE "Object"
+#define PW_TYPE_INFO_OBJECT_BASE PW_TYPE_INFO_Object ":"
+
+#define PW_TYPE_INFO_Interface PW_TYPE_INFO_BASE "Interface"
+#define PW_TYPE_INFO_INTERFACE_BASE PW_TYPE_INFO_Interface ":"
+
+const struct spa_type_info * pw_type_info(void);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_TYPE_H */
diff --git a/third_party/pipewire/pipewire/utils.h b/third_party/pipewire/pipewire/utils.h
new file mode 100644
index 0000000000..b320db22f9
--- /dev/null
+++ b/third_party/pipewire/pipewire/utils.h
@@ -0,0 +1,101 @@
+/* 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 <stdlib.h>
+#include <string.h>
+#include <sys/un.h>
+#ifndef _POSIX_C_SOURCE
+# include <sys/mount.h>
+#endif
+
+#include <spa/utils/defs.h>
+#include <spa/pod/pod.h>
+
+/** \defgroup pw_utils Utilities
+ *
+ * Various utility functions
+ */
+
+/**
+ * \addtogroup pw_utils
+ * \{
+ */
+
+/** a function to destroy an item */
+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
+
+#if !defined(strdupa)
+# define strdupa(s) \
+ ({ \
+ const char *__old = (s); \
+ size_t __len = strlen(__old) + 1; \
+ char *__new = (char *) alloca(__len); \
+ (char *) memcpy(__new, __old, __len); \
+ })
+#endif
+
+ssize_t pw_getrandom(void *buf, size_t buflen, unsigned int flags);
+
+void* pw_reallocarray(void *ptr, size_t nmemb, size_t size);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PIPEWIRE_UTILS_H */
diff --git a/third_party/pipewire/pipewire/version.h b/third_party/pipewire/pipewire/version.h
new file mode 100644
index 0000000000..3d31e46112
--- /dev/null
+++ b/third_party/pipewire/pipewire/version.h
@@ -0,0 +1,68 @@
+/* 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_VERSION_H
+#define PIPEWIRE_VERSION_H
+
+/* WARNING: Make sure to edit the real source file version.h.in! */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Return the version of the header files. Keep in mind that this is
+a macro and not a function, so it is impossible to get the pointer of
+it. */
+#define pw_get_headers_version() ("0.3.52")
+
+/** Return the version of the library the current application is
+ * linked to. */
+const char* pw_get_library_version(void);
+
+/** The current API version. Versions prior to 0.2.0 have
+ * PW_API_VERSION undefined. Please note that this is only ever
+ * increased on incompatible API changes! */
+#define PW_API_VERSION "0.3"
+
+/** The major version of PipeWire. \since 0.2.0 */
+#define PW_MAJOR 0
+
+/** The minor version of PipeWire. \since 0.2.0 */
+#define PW_MINOR 3
+
+/** The micro version of PipeWire. \since 0.2.0 */
+#define PW_MICRO 52
+
+/** Evaluates to TRUE if the PipeWire library version is equal or
+ * newer than the specified. \since 0.2.0 */
+#define PW_CHECK_VERSION(major,minor,micro) \
+ ((PW_MAJOR > (major)) || \
+ (PW_MAJOR == (major) && PW_MINOR > (minor)) || \
+ (PW_MAJOR == (major) && PW_MINOR == (minor) && PW_MICRO >= (micro)))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_VERSION_H */
diff --git a/third_party/pipewire/pipewire/work-queue.h b/third_party/pipewire/pipewire/work-queue.h
new file mode 100644
index 0000000000..299f8f1f85
--- /dev/null
+++ b/third_party/pipewire/pipewire/work-queue.h
@@ -0,0 +1,71 @@
+/* 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_WORK_QUEUE_H
+#define PIPEWIRE_WORK_QUEUE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup pw_work_queue Work Queue
+ * Queued processing of work items.
+ */
+
+/**
+ * \addtogroup pw_work_queue
+ * \{
+ */
+struct pw_work_queue;
+
+#include <pipewire/loop.h>
+
+typedef void (*pw_work_func_t) (void *obj, void *data, int res, uint32_t id);
+
+struct pw_work_queue *
+pw_work_queue_new(struct pw_loop *loop);
+
+void
+pw_work_queue_destroy(struct pw_work_queue *queue);
+
+uint32_t
+pw_work_queue_add(struct pw_work_queue *queue,
+ void *obj, int res,
+ pw_work_func_t func, void *data);
+
+int
+pw_work_queue_cancel(struct pw_work_queue *queue, void *obj, uint32_t id);
+
+int
+pw_work_queue_complete(struct pw_work_queue *queue, void *obj, uint32_t seq, int res);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_WORK_QUEUE_H */