summaryrefslogtreecommitdiffstats
path: root/third_party/pipewire/spa/support
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /third_party/pipewire/spa/support
parentInitial commit. (diff)
downloadfirefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz
firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/pipewire/spa/support')
-rw-r--r--third_party/pipewire/spa/support/cpu.h168
-rw-r--r--third_party/pipewire/spa/support/dbus.h167
-rw-r--r--third_party/pipewire/spa/support/i18n.h107
-rw-r--r--third_party/pipewire/spa/support/log-impl.h143
-rw-r--r--third_party/pipewire/spa/support/log.h314
-rw-r--r--third_party/pipewire/spa/support/loop.h327
-rw-r--r--third_party/pipewire/spa/support/plugin-loader.h101
-rw-r--r--third_party/pipewire/spa/support/plugin.h229
-rw-r--r--third_party/pipewire/spa/support/system.h165
-rw-r--r--third_party/pipewire/spa/support/thread.h149
10 files changed, 1870 insertions, 0 deletions
diff --git a/third_party/pipewire/spa/support/cpu.h b/third_party/pipewire/spa/support/cpu.h
new file mode 100644
index 0000000000..39a82f426e
--- /dev/null
+++ b/third_party/pipewire/spa/support/cpu.h
@@ -0,0 +1,168 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_CPU_H
+#define SPA_CPU_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+
+#include <spa/utils/defs.h>
+#include <spa/utils/hook.h>
+
+/** \defgroup spa_cpu CPU
+ * Querying CPU properties
+ */
+
+/**
+ * \addtogroup spa_cpu
+ * \{
+ */
+
+/**
+ * The CPU features interface
+ */
+#define SPA_TYPE_INTERFACE_CPU SPA_TYPE_INFO_INTERFACE_BASE "CPU"
+
+#define SPA_VERSION_CPU 0
+struct spa_cpu { struct spa_interface iface; };
+
+/* x86 specific */
+#define SPA_CPU_FLAG_MMX (1<<0) /**< standard MMX */
+#define SPA_CPU_FLAG_MMXEXT (1<<1) /**< SSE integer or AMD MMX ext */
+#define SPA_CPU_FLAG_3DNOW (1<<2) /**< AMD 3DNOW */
+#define SPA_CPU_FLAG_SSE (1<<3) /**< SSE */
+#define SPA_CPU_FLAG_SSE2 (1<<4) /**< SSE2 */
+#define SPA_CPU_FLAG_3DNOWEXT (1<<5) /**< AMD 3DNowExt */
+#define SPA_CPU_FLAG_SSE3 (1<<6) /**< Prescott SSE3 */
+#define SPA_CPU_FLAG_SSSE3 (1<<7) /**< Conroe SSSE3 */
+#define SPA_CPU_FLAG_SSE41 (1<<8) /**< Penryn SSE4.1 */
+#define SPA_CPU_FLAG_SSE42 (1<<9) /**< Nehalem SSE4.2 */
+#define SPA_CPU_FLAG_AESNI (1<<10) /**< Advanced Encryption Standard */
+#define SPA_CPU_FLAG_AVX (1<<11) /**< AVX */
+#define SPA_CPU_FLAG_XOP (1<<12) /**< Bulldozer XOP */
+#define SPA_CPU_FLAG_FMA4 (1<<13) /**< Bulldozer FMA4 */
+#define SPA_CPU_FLAG_CMOV (1<<14) /**< supports cmov */
+#define SPA_CPU_FLAG_AVX2 (1<<15) /**< AVX2 */
+#define SPA_CPU_FLAG_FMA3 (1<<16) /**< Haswell FMA3 */
+#define SPA_CPU_FLAG_BMI1 (1<<17) /**< Bit Manipulation Instruction Set 1 */
+#define SPA_CPU_FLAG_BMI2 (1<<18) /**< Bit Manipulation Instruction Set 2 */
+#define SPA_CPU_FLAG_AVX512 (1<<19) /**< AVX-512 */
+#define SPA_CPU_FLAG_SLOW_UNALIGNED (1<<20) /**< unaligned loads/stores are slow */
+
+/* PPC specific */
+#define SPA_CPU_FLAG_ALTIVEC (1<<0) /**< standard */
+#define SPA_CPU_FLAG_VSX (1<<1) /**< ISA 2.06 */
+#define SPA_CPU_FLAG_POWER8 (1<<2) /**< ISA 2.07 */
+
+/* ARM specific */
+#define SPA_CPU_FLAG_ARMV5TE (1 << 0)
+#define SPA_CPU_FLAG_ARMV6 (1 << 1)
+#define SPA_CPU_FLAG_ARMV6T2 (1 << 2)
+#define SPA_CPU_FLAG_VFP (1 << 3)
+#define SPA_CPU_FLAG_VFPV3 (1 << 4)
+#define SPA_CPU_FLAG_NEON (1 << 5)
+#define SPA_CPU_FLAG_ARMV8 (1 << 6)
+
+#define SPA_CPU_FORCE_AUTODETECT ((uint32_t)-1)
+
+#define SPA_CPU_VM_NONE (0)
+#define SPA_CPU_VM_OTHER (1 << 0)
+#define SPA_CPU_VM_KVM (1 << 1)
+#define SPA_CPU_VM_QEMU (1 << 2)
+#define SPA_CPU_VM_BOCHS (1 << 3)
+#define SPA_CPU_VM_XEN (1 << 4)
+#define SPA_CPU_VM_UML (1 << 5)
+#define SPA_CPU_VM_VMWARE (1 << 6)
+#define SPA_CPU_VM_ORACLE (1 << 7)
+#define SPA_CPU_VM_MICROSOFT (1 << 8)
+#define SPA_CPU_VM_ZVM (1 << 9)
+#define SPA_CPU_VM_PARALLELS (1 << 10)
+#define SPA_CPU_VM_BHYVE (1 << 11)
+#define SPA_CPU_VM_QNX (1 << 12)
+#define SPA_CPU_VM_ACRN (1 << 13)
+#define SPA_CPU_VM_POWERVM (1 << 14)
+
+/**
+ * methods
+ */
+struct spa_cpu_methods {
+ /** the version of the methods. This can be used to expand this
+ structure in the future */
+#define SPA_VERSION_CPU_METHODS 2
+ uint32_t version;
+
+ /** get CPU flags */
+ uint32_t (*get_flags) (void *object);
+
+ /** force CPU flags, use SPA_CPU_FORCE_AUTODETECT to autodetect CPU flags */
+ int (*force_flags) (void *object, uint32_t flags);
+
+ /** get number of CPU cores */
+ uint32_t (*get_count) (void *object);
+
+ /** get maximum required alignment of data */
+ uint32_t (*get_max_align) (void *object);
+
+ /* check if running in a VM. Since:1 */
+ uint32_t (*get_vm_type) (void *object);
+
+ /* denormals will be handled as zero, either with FTZ or DAZ.
+ * Since:2 */
+ int (*zero_denormals) (void *object, bool enable);
+};
+
+#define spa_cpu_method(o,method,version,...) \
+({ \
+ int _res = -ENOTSUP; \
+ struct spa_cpu *_c = o; \
+ spa_interface_call_res(&_c->iface, \
+ struct spa_cpu_methods, _res, \
+ method, version, ##__VA_ARGS__); \
+ _res; \
+})
+#define spa_cpu_get_flags(c) spa_cpu_method(c, get_flags, 0)
+#define spa_cpu_force_flags(c,f) spa_cpu_method(c, force_flags, 0, f)
+#define spa_cpu_get_count(c) spa_cpu_method(c, get_count, 0)
+#define spa_cpu_get_max_align(c) spa_cpu_method(c, get_max_align, 0)
+#define spa_cpu_get_vm_type(c) spa_cpu_method(c, get_vm_type, 1)
+#define spa_cpu_zero_denormals(c,e) spa_cpu_method(c, zero_denormals, 2, e)
+
+/** keys can be given when initializing the cpu handle */
+#define SPA_KEY_CPU_FORCE "cpu.force" /**< force cpu flags */
+#define SPA_KEY_CPU_VM_TYPE "cpu.vm.type" /**< force a VM type */
+#define SPA_KEY_CPU_ZERO_DENORMALS "cpu.zero.denormals" /**< zero denormals */
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_CPU_H */
diff --git a/third_party/pipewire/spa/support/dbus.h b/third_party/pipewire/spa/support/dbus.h
new file mode 100644
index 0000000000..9ebb7d8355
--- /dev/null
+++ b/third_party/pipewire/spa/support/dbus.h
@@ -0,0 +1,167 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_DBUS_H
+#define SPA_DBUS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/support/loop.h>
+
+/** \defgroup spa_dbus DBus
+ * DBus communication
+ */
+
+/**
+ * \addtogroup spa_dbus
+ * \{
+ */
+
+#define SPA_TYPE_INTERFACE_DBus SPA_TYPE_INFO_INTERFACE_BASE "DBus"
+
+#define SPA_VERSION_DBUS 0
+struct spa_dbus { struct spa_interface iface; };
+
+enum spa_dbus_type {
+ SPA_DBUS_TYPE_SESSION, /**< The login session bus */
+ SPA_DBUS_TYPE_SYSTEM, /**< The systemwide bus */
+ SPA_DBUS_TYPE_STARTER /**< The bus that started us, if any */
+};
+
+#define SPA_DBUS_CONNECTION_EVENT_DESTROY 0
+#define SPA_DBUS_CONNECTION_EVENT_DISCONNECTED 1
+#define SPA_DBUS_CONNECTION_EVENT_NUM 2
+
+struct spa_dbus_connection_events {
+#define SPA_VERSION_DBUS_CONNECTION_EVENTS 0
+ uint32_t version;
+
+ /* a connection is destroyed */
+ void (*destroy) (void *data);
+
+ /* a connection disconnected */
+ void (*disconnected) (void *data);
+};
+
+struct spa_dbus_connection {
+#define SPA_VERSION_DBUS_CONNECTION 1
+ uint32_t version;
+ /**
+ * Get the DBusConnection from a wrapper
+ *
+ * Note that the returned handle is closed and unref'd by spa_dbus
+ * immediately before emitting the asynchronous "disconnected" event.
+ * The caller must either deal with the invalidation, or keep an extra
+ * ref on the handle returned.
+ *
+ * \param conn the spa_dbus_connection wrapper
+ * \return a pointer of type DBusConnection
+ */
+ void *(*get) (struct spa_dbus_connection *conn);
+ /**
+ * Destroy a dbus connection wrapper
+ *
+ * \param conn the wrapper to destroy
+ */
+ void (*destroy) (struct spa_dbus_connection *conn);
+
+ /**
+ * Add a listener for events
+ *
+ * Since version 1
+ */
+ void (*add_listener) (struct spa_dbus_connection *conn,
+ struct spa_hook *listener,
+ const struct spa_dbus_connection_events *events,
+ void *data);
+};
+
+#define spa_dbus_connection_call(c,method,vers,...) \
+({ \
+ if (SPA_LIKELY(SPA_CALLBACK_CHECK(c,method,vers))) \
+ c->method((c), ## __VA_ARGS__); \
+})
+
+#define spa_dbus_connection_call_vp(c,method,vers,...) \
+({ \
+ void *_res = NULL; \
+ if (SPA_LIKELY(SPA_CALLBACK_CHECK(c,method,vers))) \
+ _res = c->method((c), ## __VA_ARGS__); \
+ _res; \
+})
+
+/** \copydoc spa_dbus_connection.get
+ * \sa spa_dbus_connection.get */
+#define spa_dbus_connection_get(c) spa_dbus_connection_call_vp(c,get,0)
+/** \copydoc spa_dbus_connection.destroy
+ * \sa spa_dbus_connection.destroy */
+#define spa_dbus_connection_destroy(c) spa_dbus_connection_call(c,destroy,0)
+/** \copydoc spa_dbus_connection.add_listener
+ * \sa spa_dbus_connection.add_listener */
+#define spa_dbus_connection_add_listener(c,...) spa_dbus_connection_call(c,add_listener,1,__VA_ARGS__)
+
+struct spa_dbus_methods {
+#define SPA_VERSION_DBUS_METHODS 0
+ uint32_t version;
+
+ /**
+ * Get a new connection wrapper for the given bus type.
+ *
+ * The connection wrapper is completely configured to operate
+ * in the main context of the handle that manages the spa_dbus
+ * interface.
+ *
+ * \param dbus the dbus manager
+ * \param type the bus type to wrap
+ * \param error location for the DBusError
+ * \return a new dbus connection wrapper or NULL on error
+ */
+ struct spa_dbus_connection * (*get_connection) (void *object,
+ enum spa_dbus_type type);
+};
+
+/** \copydoc spa_dbus_methods.get_connection
+ * \sa spa_dbus_methods.get_connection
+ */
+static inline struct spa_dbus_connection *
+spa_dbus_get_connection(struct spa_dbus *dbus, enum spa_dbus_type type)
+{
+ struct spa_dbus_connection *res = NULL;
+ spa_interface_call_res(&dbus->iface,
+ struct spa_dbus_methods, res,
+ get_connection, 0, type);
+ return res;
+}
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_DBUS_H */
diff --git a/third_party/pipewire/spa/support/i18n.h b/third_party/pipewire/spa/support/i18n.h
new file mode 100644
index 0000000000..fc45b0734e
--- /dev/null
+++ b/third_party/pipewire/spa/support/i18n.h
@@ -0,0 +1,107 @@
+/* Simple Plugin API
+ *
+ * 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 SPA_I18N_H
+#define SPA_I18N_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/hook.h>
+#include <spa/utils/defs.h>
+
+/** \defgroup spa_i18n I18N
+ * Gettext interface
+ */
+
+/**
+ * \addtogroup spa_i18n
+ * \{
+ */
+
+#define SPA_TYPE_INTERFACE_I18N SPA_TYPE_INFO_INTERFACE_BASE "I18N"
+
+#define SPA_VERSION_I18N 0
+struct spa_i18n { struct spa_interface iface; };
+
+struct spa_i18n_methods {
+#define SPA_VERSION_I18N_METHODS 0
+ uint32_t version;
+
+ /**
+ * Translate a message
+ *
+ * \param object the i18n interface
+ * \param msgid the message
+ * \return a translated message
+ */
+ const char *(*text) (void *object, const char *msgid);
+
+ /**
+ * Translate a message for a number
+ *
+ * \param object the i18n interface
+ * \param msgid the message to translate
+ * \param msgid_plural the plural form of \a msgid
+ * \param n a number
+ * \return a translated message for the number \a n
+ */
+ const char *(*ntext) (void *object, const char *msgid,
+ const char *msgid_plural, unsigned long int n);
+};
+
+SPA_FORMAT_ARG_FUNC(2)
+static inline const char *
+spa_i18n_text(struct spa_i18n *i18n, const char *msgid)
+{
+ const char *res = msgid;
+ if (SPA_LIKELY(i18n != NULL))
+ spa_interface_call_res(&i18n->iface,
+ struct spa_i18n_methods, res,
+ text, 0, msgid);
+ return res;
+}
+
+static inline const char *
+spa_i18n_ntext(struct spa_i18n *i18n, const char *msgid,
+ const char *msgid_plural, unsigned long int n)
+{
+ const char *res = n == 1 ? msgid : msgid_plural;
+ if (SPA_LIKELY(i18n != NULL))
+ spa_interface_call_res(&i18n->iface,
+ struct spa_i18n_methods, res,
+ ntext, 0, msgid, msgid_plural, n);
+ return res;
+}
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_I18N_H */
diff --git a/third_party/pipewire/spa/support/log-impl.h b/third_party/pipewire/spa/support/log-impl.h
new file mode 100644
index 0000000000..124153d073
--- /dev/null
+++ b/third_party/pipewire/spa/support/log-impl.h
@@ -0,0 +1,143 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_LOG_IMPL_H
+#define SPA_LOG_IMPL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+
+#include <spa/utils/type.h>
+#include <spa/support/log.h>
+
+/**
+ * \addtogroup spa_log
+ * \{
+ */
+
+static inline SPA_PRINTF_FUNC(7, 0) void spa_log_impl_logtv(void *object,
+ 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)
+{
+ static const char * const levels[] = { "-", "E", "W", "I", "D", "T" };
+
+ const char *basename = strrchr(file, '/');
+ char text[512], location[1024];
+ char topicstr[32] = {0};
+
+ if (basename)
+ basename += 1; /* skip '/' */
+ else
+ basename = file; /* use whole string if no '/' is found */
+
+ if (topic && topic->topic)
+ snprintf(topicstr, sizeof(topicstr), " %s ", topic->topic);
+ vsnprintf(text, sizeof(text), fmt, args);
+ snprintf(location, sizeof(location), "[%s]%s[%s:%i %s()] %s\n",
+ levels[level],
+ topicstr,
+ basename, line, func, text);
+ fputs(location, stderr);
+}
+
+static inline SPA_PRINTF_FUNC(7,8) void spa_log_impl_logt(void *object,
+ 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;
+ va_start(args, fmt);
+ spa_log_impl_logtv(object, level, topic, file, line, func, fmt, args);
+ va_end(args);
+}
+
+static inline SPA_PRINTF_FUNC(6, 0) void spa_log_impl_logv(void *object,
+ enum spa_log_level level,
+ const char *file,
+ int line,
+ const char *func,
+ const char *fmt,
+ va_list args)
+{
+
+ spa_log_impl_logtv(object, level, NULL, file, line, func, fmt, args);
+}
+
+static inline SPA_PRINTF_FUNC(6,7) void spa_log_impl_log(void *object,
+ enum spa_log_level level,
+ const char *file,
+ int line,
+ const char *func,
+ const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ spa_log_impl_logv(object, level, file, line, func, fmt, args);
+ va_end(args);
+}
+
+static inline void spa_log_impl_topic_init(void *object, struct spa_log_topic *topic)
+{
+ /* noop */
+}
+
+#define SPA_LOG_IMPL_DEFINE(name) \
+struct { \
+ struct spa_log log; \
+ struct spa_log_methods methods; \
+} name
+
+#define SPA_LOG_IMPL_INIT(name) \
+ { { { SPA_TYPE_INTERFACE_Log, SPA_VERSION_LOG, \
+ SPA_CALLBACKS_INIT(&name.methods, &name) }, \
+ SPA_LOG_LEVEL_INFO, }, \
+ { SPA_VERSION_LOG_METHODS, \
+ spa_log_impl_log, \
+ spa_log_impl_logv, \
+ spa_log_impl_logt, \
+ spa_log_impl_logtv, \
+ } }
+
+#define SPA_LOG_IMPL(name) \
+ SPA_LOG_IMPL_DEFINE(name) = SPA_LOG_IMPL_INIT(name)
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+#endif /* SPA_LOG_IMPL_H */
diff --git a/third_party/pipewire/spa/support/log.h b/third_party/pipewire/spa/support/log.h
new file mode 100644
index 0000000000..e4990d1bb6
--- /dev/null
+++ b/third_party/pipewire/spa/support/log.h
@@ -0,0 +1,314 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_LOG_H
+#define SPA_LOG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+
+#include <spa/utils/type.h>
+#include <spa/utils/defs.h>
+#include <spa/utils/hook.h>
+
+/** \defgroup spa_log Log
+ * Logging interface
+ */
+
+/**
+ * \addtogroup spa_log
+ * \{
+ */
+
+/** The default log topic. Redefine this in your code to
+ * allow for the spa_log_* macros to work correctly, e.g:
+ *
+ * \code{.c}
+ * struct spa_log_topic *mylogger;
+ * #undef SPA_LOG_TOPIC_DEFAULT
+ * #define SPA_LOG_TOPIC_DEFAULT mylogger
+ * \endcode
+ */
+#define SPA_LOG_TOPIC_DEFAULT NULL
+
+enum spa_log_level {
+ SPA_LOG_LEVEL_NONE = 0,
+ SPA_LOG_LEVEL_ERROR,
+ SPA_LOG_LEVEL_WARN,
+ SPA_LOG_LEVEL_INFO,
+ SPA_LOG_LEVEL_DEBUG,
+ SPA_LOG_LEVEL_TRACE,
+};
+
+/**
+ * The Log interface
+ */
+#define SPA_TYPE_INTERFACE_Log SPA_TYPE_INFO_INTERFACE_BASE "Log"
+
+
+struct spa_log {
+ /** the version of this log. This can be used to expand this
+ * structure in the future */
+#define SPA_VERSION_LOG 0
+ struct spa_interface iface;
+ /**
+ * Logging level, everything above this level is not logged
+ */
+ enum spa_log_level level;
+};
+
+/**
+ * \struct spa_log_topic
+ *
+ * Identifier for a topic. Topics are string-based filters that logically
+ * group messages together. An implementation may decide to filter different
+ * topics on different levels, for example the "protocol" topic may require
+ * debug level TRACE while the "core" topic defaults to debug level INFO.
+ *
+ * spa_log_topics require a spa_log_methods version of 1 or higher.
+ */
+struct spa_log_topic {
+#define SPA_VERSION_LOG_TOPIC 0
+ /** the version of this topic. This can be used to expand this
+ * structure in the future */
+ uint32_t version;
+ /** The string identifier for the topic */
+ const char *topic;
+ /** Logging level set for this topic */
+ enum spa_log_level level;
+ /** False if this topic follows the \ref spa_log level */
+ bool has_custom_level;
+};
+
+struct spa_log_methods {
+#define SPA_VERSION_LOG_METHODS 1
+ uint32_t version;
+ /**
+ * Log a message with the given log level.
+ *
+ * \note If compiled with this header, this function is only called
+ * for implementations of version 0. For versions 1 and above, see
+ * logt() instead.
+ *
+ * \param log a spa_log
+ * \param level a spa_log_level
+ * \param file the file name
+ * \param line the line number
+ * \param func the function name
+ * \param fmt printf style format
+ * \param ... format arguments
+ */
+ void (*log) (void *object,
+ enum spa_log_level level,
+ const char *file,
+ int line,
+ const char *func,
+ const char *fmt, ...) SPA_PRINTF_FUNC(6, 7);
+
+ /**
+ * Log a message with the given log level.
+ *
+ * \note If compiled with this header, this function is only called
+ * for implementations of version 0. For versions 1 and above, see
+ * logtv() instead.
+ *
+ * \param log a spa_log
+ * \param level a spa_log_level
+ * \param file the file name
+ * \param line the line number
+ * \param func the function name
+ * \param fmt printf style format
+ * \param args format arguments
+ */
+ void (*logv) (void *object,
+ enum spa_log_level level,
+ const char *file,
+ int line,
+ const char *func,
+ const char *fmt,
+ va_list args) SPA_PRINTF_FUNC(6, 0);
+ /**
+ * Log a message with the given log level for the given topic.
+ *
+ * \note Callers that do not use topic-based logging (version 0), the \a
+ * topic is NULL
+ *
+ * \param log a spa_log
+ * \param level a spa_log_level
+ * \param topic the topic for this message, may be NULL
+ * \param file the file name
+ * \param line the line number
+ * \param func the function name
+ * \param fmt printf style format
+ * \param ... format arguments
+ *
+ * \since 1
+ */
+ void (*logt) (void *object,
+ 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(7, 8);
+
+ /**
+ * Log a message with the given log level for the given topic.
+ *
+ * \note For callers that do not use topic-based logging (version 0),
+ * the \a topic is NULL
+ *
+ * \param log a spa_log
+ * \param level a spa_log_level
+ * \param topic the topic for this message, may be NULL
+ * \param file the file name
+ * \param line the line number
+ * \param func the function name
+ * \param fmt printf style format
+ * \param args format arguments
+ *
+ * \since 1
+ */
+ void (*logtv) (void *object,
+ 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(7, 0);
+
+ /**
+ * Initializes a \ref spa_log_topic to the correct logging level.
+ *
+ * \since 1
+ */
+ void (*topic_init) (void *object, struct spa_log_topic *topic);
+};
+
+
+#define SPA_LOG_TOPIC(v, t) \
+ (struct spa_log_topic){ .version = v, .topic = (t)}
+
+#define spa_log_topic_init(l, topic) \
+do { \
+ struct spa_log *_l = l; \
+ if (SPA_LIKELY(_l)) { \
+ struct spa_interface *_if = &_l->iface; \
+ spa_interface_call(_if, struct spa_log_methods, \
+ topic_init, 1, topic); \
+ } \
+} while(0)
+
+/* Unused, left for backwards compat */
+#define spa_log_level_enabled(l,lev) ((l) && (l)->level >= (lev))
+
+#define spa_log_level_topic_enabled(l,topic,lev) \
+({ \
+ struct spa_log *_log = l; \
+ enum spa_log_level _lev = _log ? _log->level : SPA_LOG_LEVEL_NONE; \
+ struct spa_log_topic *_t = (struct spa_log_topic *)topic; \
+ if (_t && _t->has_custom_level) \
+ _lev = _t->level; \
+ _lev >= lev; \
+})
+
+/* Transparently calls to version 0 log if v1 is not supported */
+#define spa_log_logt(l,lev,topic,...) \
+({ \
+ struct spa_log *_l = l; \
+ struct spa_interface *_if = &_l->iface; \
+ if (SPA_UNLIKELY(spa_log_level_topic_enabled(_l, topic, lev))) { \
+ if (!spa_interface_call(_if, \
+ struct spa_log_methods, logt, 1, \
+ lev, topic, \
+ __VA_ARGS__)) \
+ spa_interface_call(_if, \
+ struct spa_log_methods, log, 0, \
+ lev, __VA_ARGS__); \
+ } \
+})
+
+/* Transparently calls to version 0 logv if v1 is not supported */
+#define spa_log_logtv(l,lev,topic,...) \
+({ \
+ struct spa_log *_l = l; \
+ struct spa_interface *_if = &_l->iface; \
+ if (SPA_UNLIKELY(spa_log_level_topic_enabled(_l, topic, lev))) { \
+ if (!spa_interface_call(_if, \
+ struct spa_log_methods, logtv, 1, \
+ lev, topic, \
+ __VA_ARGS__)) \
+ spa_interface_call(_if, \
+ struct spa_log_methods, logv, 0, \
+ lev, __VA_ARGS__); \
+ } \
+})
+
+#define spa_log_log(l,lev,...) \
+ spa_log_logt(l,lev,SPA_LOG_TOPIC_DEFAULT,__VA_ARGS__)
+
+#define spa_log_logv(l,lev,...) \
+ spa_log_logtv(l,lev,SPA_LOG_TOPIC_DEFAULT,__VA_ARGS__)
+
+#define spa_log_error(l,...) spa_log_log(l,SPA_LOG_LEVEL_ERROR,__FILE__,__LINE__,__func__,__VA_ARGS__)
+#define spa_log_warn(l,...) spa_log_log(l,SPA_LOG_LEVEL_WARN,__FILE__,__LINE__,__func__,__VA_ARGS__)
+#define spa_log_info(l,...) spa_log_log(l,SPA_LOG_LEVEL_INFO,__FILE__,__LINE__,__func__,__VA_ARGS__)
+#define spa_log_debug(l,...) spa_log_log(l,SPA_LOG_LEVEL_DEBUG,__FILE__,__LINE__,__func__,__VA_ARGS__)
+#define spa_log_trace(l,...) spa_log_log(l,SPA_LOG_LEVEL_TRACE,__FILE__,__LINE__,__func__,__VA_ARGS__)
+
+#define spa_logt_error(l,t,...) spa_log_logt(l,SPA_LOG_LEVEL_ERROR,t,__FILE__,__LINE__,__func__,__VA_ARGS__)
+#define spa_logt_warn(l,t,...) spa_log_logt(l,SPA_LOG_LEVEL_WARN,t,__FILE__,__LINE__,__func__,__VA_ARGS__)
+#define spa_logt_info(l,t,...) spa_log_logt(l,SPA_LOG_LEVEL_INFO,t,__FILE__,__LINE__,__func__,__VA_ARGS__)
+#define spa_logt_debug(l,t,...) spa_log_logt(l,SPA_LOG_LEVEL_DEBUG,t,__FILE__,__LINE__,__func__,__VA_ARGS__)
+#define spa_logt_trace(l,t,...) spa_log_logt(l,SPA_LOG_LEVEL_TRACE,t,__FILE__,__LINE__,__func__,__VA_ARGS__)
+
+#ifndef FASTPATH
+#define spa_log_trace_fp(l,...) spa_log_log(l,SPA_LOG_LEVEL_TRACE,__FILE__,__LINE__,__func__,__VA_ARGS__)
+#else
+#define spa_log_trace_fp(l,...)
+#endif
+
+/** \fn spa_log_error */
+
+/** keys can be given when initializing the logger handle */
+#define SPA_KEY_LOG_LEVEL "log.level" /**< the default log level */
+#define SPA_KEY_LOG_COLORS "log.colors" /**< enable colors in the logger */
+#define SPA_KEY_LOG_FILE "log.file" /**< log to the specified file instead of
+ * stderr. */
+#define SPA_KEY_LOG_TIMESTAMP "log.timestamp" /**< log timestamps */
+#define SPA_KEY_LOG_LINE "log.line" /**< log file and line numbers */
+#define SPA_KEY_LOG_PATTERNS "log.patterns" /**< Spa:String:JSON array of [ {"pattern" : level}, ... ] */
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+#endif /* SPA_LOG_H */
diff --git a/third_party/pipewire/spa/support/loop.h b/third_party/pipewire/spa/support/loop.h
new file mode 100644
index 0000000000..3c93573c8f
--- /dev/null
+++ b/third_party/pipewire/spa/support/loop.h
@@ -0,0 +1,327 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_LOOP_H
+#define SPA_LOOP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/defs.h>
+#include <spa/utils/hook.h>
+#include <spa/support/system.h>
+
+/** \defgroup spa_loop Loop
+ * Event loop interface
+ */
+
+/**
+ * \addtogroup spa_loop
+ * \{
+ */
+
+#define SPA_TYPE_INTERFACE_Loop SPA_TYPE_INFO_INTERFACE_BASE "Loop"
+#define SPA_TYPE_INTERFACE_DataLoop SPA_TYPE_INFO_INTERFACE_BASE "DataLoop"
+#define SPA_VERSION_LOOP 0
+struct spa_loop { struct spa_interface iface; };
+
+#define SPA_TYPE_INTERFACE_LoopControl SPA_TYPE_INFO_INTERFACE_BASE "LoopControl"
+#define SPA_VERSION_LOOP_CONTROL 0
+struct spa_loop_control { struct spa_interface iface; };
+
+#define SPA_TYPE_INTERFACE_LoopUtils SPA_TYPE_INFO_INTERFACE_BASE "LoopUtils"
+#define SPA_VERSION_LOOP_UTILS 0
+struct spa_loop_utils { struct spa_interface iface; };
+
+struct spa_source;
+
+typedef void (*spa_source_func_t) (struct spa_source *source);
+
+struct spa_source {
+ struct spa_loop *loop;
+ spa_source_func_t func;
+ void *data;
+ int fd;
+ uint32_t mask;
+ uint32_t rmask;
+ /* private data for the loop implementer */
+ void *priv;
+};
+
+typedef int (*spa_invoke_func_t) (struct spa_loop *loop,
+ bool async,
+ uint32_t seq,
+ const void *data,
+ size_t size,
+ void *user_data);
+
+/**
+ * Register sources and work items to an event loop
+ */
+struct spa_loop_methods {
+ /* the version of this structure. This can be used to expand this
+ * structure in the future */
+#define SPA_VERSION_LOOP_METHODS 0
+ uint32_t version;
+
+ /** add a source to the loop */
+ int (*add_source) (void *object,
+ struct spa_source *source);
+
+ /** update the source io mask */
+ int (*update_source) (void *object,
+ struct spa_source *source);
+
+ /** remove a source from the loop */
+ int (*remove_source) (void *object,
+ struct spa_source *source);
+
+ /** invoke a function in the context of this loop */
+ int (*invoke) (void *object,
+ spa_invoke_func_t func,
+ uint32_t seq,
+ const void *data,
+ size_t size,
+ bool block,
+ void *user_data);
+};
+
+#define spa_loop_method(o,method,version,...) \
+({ \
+ int _res = -ENOTSUP; \
+ struct spa_loop *_o = o; \
+ spa_interface_call_res(&_o->iface, \
+ struct spa_loop_methods, _res, \
+ method, version, ##__VA_ARGS__); \
+ _res; \
+})
+
+#define spa_loop_add_source(l,...) spa_loop_method(l,add_source,0,##__VA_ARGS__)
+#define spa_loop_update_source(l,...) spa_loop_method(l,update_source,0,##__VA_ARGS__)
+#define spa_loop_remove_source(l,...) spa_loop_method(l,remove_source,0,##__VA_ARGS__)
+#define spa_loop_invoke(l,...) spa_loop_method(l,invoke,0,##__VA_ARGS__)
+
+
+/** Control hooks. These hooks can't be removed from their
+ * callbacks and must be removed from a safe place (when the loop
+ * is not running or when it is locked). */
+struct spa_loop_control_hooks {
+#define SPA_VERSION_LOOP_CONTROL_HOOKS 0
+ uint32_t version;
+ /** Executed right before waiting for events. It is typically used to
+ * release locks. */
+ void (*before) (void *data);
+ /** Executed right after waiting for events. It is typically used to
+ * reacquire locks. */
+ void (*after) (void *data);
+};
+
+#define spa_loop_control_hook_before(l) \
+({ \
+ struct spa_hook_list *_l = l; \
+ struct spa_hook *_h; \
+ spa_list_for_each_reverse(_h, &_l->list, link) \
+ spa_callbacks_call(&_h->cb, struct spa_loop_control_hooks, before, 0); \
+})
+
+#define spa_loop_control_hook_after(l) \
+({ \
+ struct spa_hook_list *_l = l; \
+ struct spa_hook *_h; \
+ spa_list_for_each(_h, &_l->list, link) \
+ spa_callbacks_call(&_h->cb, struct spa_loop_control_hooks, after, 0); \
+})
+
+/**
+ * Control an event loop
+ */
+struct spa_loop_control_methods {
+ /* the version of this structure. This can be used to expand this
+ * structure in the future */
+#define SPA_VERSION_LOOP_CONTROL_METHODS 0
+ uint32_t version;
+
+ int (*get_fd) (void *object);
+
+ /** Add a hook
+ * \param ctrl the control to change
+ * \param hooks the hooks to add
+ *
+ * Adds hooks to the loop controlled by \a ctrl.
+ */
+ void (*add_hook) (void *object,
+ struct spa_hook *hook,
+ const struct spa_loop_control_hooks *hooks,
+ void *data);
+
+ /** Enter a loop
+ * \param ctrl the control
+ *
+ * Start an iteration of the loop. This function should be called
+ * before calling iterate and is typically used to capture the thread
+ * that this loop will run in.
+ */
+ void (*enter) (void *object);
+ /** Leave a loop
+ * \param ctrl the control
+ *
+ * Ends the iteration of a loop. This should be called after calling
+ * iterate.
+ */
+ void (*leave) (void *object);
+
+ /** Perform one iteration of the loop.
+ * \param ctrl the control
+ * \param timeout an optional timeout in milliseconds.
+ * 0 for no timeout, -1 for infinite timeout.
+ *
+ * This function will block
+ * up to \a timeout milliseconds and then dispatch the fds with activity.
+ * The number of dispatched fds is returned.
+ */
+ int (*iterate) (void *object, int timeout);
+};
+
+#define spa_loop_control_method_v(o,method,version,...) \
+({ \
+ struct spa_loop_control *_o = o; \
+ spa_interface_call(&_o->iface, \
+ struct spa_loop_control_methods, \
+ method, version, ##__VA_ARGS__); \
+})
+
+#define spa_loop_control_method_r(o,method,version,...) \
+({ \
+ int _res = -ENOTSUP; \
+ struct spa_loop_control *_o = o; \
+ spa_interface_call_res(&_o->iface, \
+ struct spa_loop_control_methods, _res, \
+ method, version, ##__VA_ARGS__); \
+ _res; \
+})
+
+#define spa_loop_control_get_fd(l) spa_loop_control_method_r(l,get_fd,0)
+#define spa_loop_control_add_hook(l,...) spa_loop_control_method_v(l,add_hook,0,__VA_ARGS__)
+#define spa_loop_control_enter(l) spa_loop_control_method_v(l,enter,0)
+#define spa_loop_control_leave(l) spa_loop_control_method_v(l,leave,0)
+#define spa_loop_control_iterate(l,...) spa_loop_control_method_r(l,iterate,0,__VA_ARGS__)
+
+typedef void (*spa_source_io_func_t) (void *data, int fd, uint32_t mask);
+typedef void (*spa_source_idle_func_t) (void *data);
+typedef void (*spa_source_event_func_t) (void *data, uint64_t count);
+typedef void (*spa_source_timer_func_t) (void *data, uint64_t expirations);
+typedef void (*spa_source_signal_func_t) (void *data, int signal_number);
+
+/**
+ * Create sources for an event loop
+ */
+struct spa_loop_utils_methods {
+ /* the version of this structure. This can be used to expand this
+ * structure in the future */
+#define SPA_VERSION_LOOP_UTILS_METHODS 0
+ uint32_t version;
+
+ struct spa_source *(*add_io) (void *object,
+ int fd,
+ uint32_t mask,
+ bool close,
+ spa_source_io_func_t func, void *data);
+
+ int (*update_io) (void *object, struct spa_source *source, uint32_t mask);
+
+ struct spa_source *(*add_idle) (void *object,
+ bool enabled,
+ spa_source_idle_func_t func, void *data);
+ int (*enable_idle) (void *object, struct spa_source *source, bool enabled);
+
+ struct spa_source *(*add_event) (void *object,
+ spa_source_event_func_t func, void *data);
+ int (*signal_event) (void *object, struct spa_source *source);
+
+ struct spa_source *(*add_timer) (void *object,
+ spa_source_timer_func_t func, void *data);
+ int (*update_timer) (void *object,
+ struct spa_source *source,
+ struct timespec *value,
+ struct timespec *interval,
+ bool absolute);
+ struct spa_source *(*add_signal) (void *object,
+ int signal_number,
+ spa_source_signal_func_t func, void *data);
+
+ /** destroy a source allocated with this interface. This function
+ * should only be called when the loop is not running or from the
+ * context of the running loop */
+ void (*destroy_source) (void *object, struct spa_source *source);
+};
+
+#define spa_loop_utils_method_v(o,method,version,...) \
+({ \
+ struct spa_loop_utils *_o = o; \
+ spa_interface_call(&_o->iface, \
+ struct spa_loop_utils_methods, \
+ method, version, ##__VA_ARGS__); \
+})
+
+#define spa_loop_utils_method_r(o,method,version,...) \
+({ \
+ int _res = -ENOTSUP; \
+ struct spa_loop_utils *_o = o; \
+ spa_interface_call_res(&_o->iface, \
+ struct spa_loop_utils_methods, _res, \
+ method, version, ##__VA_ARGS__); \
+ _res; \
+})
+#define spa_loop_utils_method_s(o,method,version,...) \
+({ \
+ struct spa_source *_res = NULL; \
+ struct spa_loop_utils *_o = o; \
+ spa_interface_call_res(&_o->iface, \
+ struct spa_loop_utils_methods, _res, \
+ method, version, ##__VA_ARGS__); \
+ _res; \
+})
+
+
+#define spa_loop_utils_add_io(l,...) spa_loop_utils_method_s(l,add_io,0,__VA_ARGS__)
+#define spa_loop_utils_update_io(l,...) spa_loop_utils_method_r(l,update_io,0,__VA_ARGS__)
+#define spa_loop_utils_add_idle(l,...) spa_loop_utils_method_s(l,add_idle,0,__VA_ARGS__)
+#define spa_loop_utils_enable_idle(l,...) spa_loop_utils_method_r(l,enable_idle,0,__VA_ARGS__)
+#define spa_loop_utils_add_event(l,...) spa_loop_utils_method_s(l,add_event,0,__VA_ARGS__)
+#define spa_loop_utils_signal_event(l,...) spa_loop_utils_method_r(l,signal_event,0,__VA_ARGS__)
+#define spa_loop_utils_add_timer(l,...) spa_loop_utils_method_s(l,add_timer,0,__VA_ARGS__)
+#define spa_loop_utils_update_timer(l,...) spa_loop_utils_method_r(l,update_timer,0,__VA_ARGS__)
+#define spa_loop_utils_add_signal(l,...) spa_loop_utils_method_s(l,add_signal,0,__VA_ARGS__)
+#define spa_loop_utils_destroy_source(l,...) spa_loop_utils_method_v(l,destroy_source,0,__VA_ARGS__)
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_LOOP_H */
diff --git a/third_party/pipewire/spa/support/plugin-loader.h b/third_party/pipewire/spa/support/plugin-loader.h
new file mode 100644
index 0000000000..ced58cbce2
--- /dev/null
+++ b/third_party/pipewire/spa/support/plugin-loader.h
@@ -0,0 +1,101 @@
+/* Simple Plugin API
+ *
+ * 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 SPA_PLUGIN_LOADER_H
+#define SPA_PLUGIN_LOADER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/hook.h>
+#include <spa/utils/dict.h>
+
+/** \defgroup spa_plugin_loader Plugin Loader
+ * SPA plugin loader
+ */
+
+/**
+ * \addtogroup spa_plugin_loader
+ * \{
+ */
+
+#define SPA_TYPE_INTERFACE_PluginLoader SPA_TYPE_INFO_INTERFACE_BASE "PluginLoader"
+
+#define SPA_VERSION_PLUGIN_LOADER 0
+struct spa_plugin_loader { struct spa_interface iface; };
+
+struct spa_plugin_loader_methods {
+#define SPA_VERSION_PLUGIN_LOADER_METHODS 0
+ uint32_t version;
+
+ /**
+ * Load a SPA plugin.
+ *
+ * \param factory_name Plugin factory name
+ * \param info Info dictionary for plugin. NULL if none.
+ * \return plugin handle, or NULL on error
+ */
+ struct spa_handle *(*load) (void *object, const char *factory_name, const struct spa_dict *info);
+
+ /**
+ * Unload a SPA plugin.
+ *
+ * \param handle Plugin handle.
+ * \return 0 on success, < 0 on error
+ */
+ int (*unload)(void *object, struct spa_handle *handle);
+};
+
+static inline struct spa_handle *
+spa_plugin_loader_load(struct spa_plugin_loader *loader, const char *factory_name, const struct spa_dict *info)
+{
+ struct spa_handle *res = NULL;
+ if (SPA_LIKELY(loader != NULL))
+ spa_interface_call_res(&loader->iface,
+ struct spa_plugin_loader_methods, res,
+ load, 0, factory_name, info);
+ return res;
+}
+
+static inline int
+spa_plugin_loader_unload(struct spa_plugin_loader *loader, struct spa_handle *handle)
+{
+ int res = -1;
+ if (SPA_LIKELY(loader != NULL))
+ spa_interface_call_res(&loader->iface,
+ struct spa_plugin_loader_methods, res,
+ unload, 0, handle);
+ return res;
+}
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_PLUGIN_LOADER_H */
diff --git a/third_party/pipewire/spa/support/plugin.h b/third_party/pipewire/spa/support/plugin.h
new file mode 100644
index 0000000000..e66bdc9976
--- /dev/null
+++ b/third_party/pipewire/spa/support/plugin.h
@@ -0,0 +1,229 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_PLUGIN_H
+#define SPA_PLUGIN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/defs.h>
+#include <spa/utils/dict.h>
+
+/**
+ * \defgroup spa_handle Plugin Handle
+ * SPA plugin handle and factory interfaces
+ */
+
+/**
+ * \addtogroup spa_handle
+ * \{
+ */
+
+struct spa_handle {
+ /** Version of this struct */
+#define SPA_VERSION_HANDLE 0
+ uint32_t version;
+
+ /**
+ * Get the interface provided by \a handle with \a type.
+ *
+ * \a interface is always a struct spa_interface but depending on
+ * \a type, the struct might contain other information.
+ *
+ * \param handle a spa_handle
+ * \param type the interface type
+ * \param interface result to hold the interface.
+ * \return 0 on success
+ * -ENOTSUP when there are no interfaces
+ * -EINVAL when handle or info is NULL
+ */
+ int (*get_interface) (struct spa_handle *handle, const char *type, void **interface);
+ /**
+ * Clean up the memory of \a handle. After this, \a handle should not be used
+ * anymore.
+ *
+ * \param handle a pointer to memory
+ * \return 0 on success
+ */
+ int (*clear) (struct spa_handle *handle);
+};
+
+#define spa_handle_get_interface(h,...) (h)->get_interface((h),__VA_ARGS__)
+#define spa_handle_clear(h) (h)->clear((h))
+
+/**
+ * This structure lists the information about available interfaces on
+ * handles.
+ */
+struct spa_interface_info {
+ const char *type; /*< the type of the interface, can be
+ * used to get the interface */
+};
+
+/**
+ * Extra supporting infrastructure passed to the init() function of
+ * a factory. It can be extra information or interfaces such as logging.
+ */
+struct spa_support {
+ const char *type; /*< the type of the support item */
+ void *data; /*< specific data for the item */
+};
+
+/** Find a support item of the given type */
+static inline void *spa_support_find(const struct spa_support *support,
+ uint32_t n_support,
+ const char *type)
+{
+ uint32_t i;
+ for (i = 0; i < n_support; i++) {
+ if (strcmp(support[i].type, type) == 0)
+ return support[i].data;
+ }
+ return NULL;
+}
+
+#define SPA_SUPPORT_INIT(type,data) (struct spa_support) { (type), (data) }
+
+struct spa_handle_factory {
+ /** The version of this structure */
+#define SPA_VERSION_HANDLE_FACTORY 1
+ uint32_t version;
+ /**
+ * The name of the factory contains a logical name that describes
+ * the function of the handle. Other plugins might contain an alternative
+ * implementation with the same name.
+ *
+ * See utils/names.h for the list of standard names.
+ *
+ * Examples include:
+ *
+ * api.alsa.pcm.sink: an object to write PCM samples to an alsa PLAYBACK
+ * device
+ * api.v4l2.source: an object to read from a v4l2 source.
+ */
+ const char *name;
+ /**
+ * Extra information about the handles of this factory.
+ */
+ const struct spa_dict *info;
+ /**
+ * Get the size of handles from this factory.
+ *
+ * \param factory a spa_handle_factory
+ * \param params extra parameters that determine the size of the
+ * handle.
+ */
+ size_t (*get_size) (const struct spa_handle_factory *factory,
+ const struct spa_dict *params);
+
+ /**
+ * Initialize an instance of this factory. The caller should allocate
+ * memory at least size bytes and pass this as \a handle.
+ *
+ * \a support can optionally contain extra interfaces or data items that the
+ * plugin can use such as a logger.
+ *
+ * \param factory a spa_handle_factory
+ * \param handle a pointer to memory
+ * \param info extra handle specific information, usually obtained
+ * from a spa_device. This can be used to configure the handle.
+ * \param support support items
+ * \param n_support number of elements in \a support
+ * \return 0 on success
+ * < 0 errno type error
+ */
+ int (*init) (const struct spa_handle_factory *factory,
+ struct spa_handle *handle,
+ const struct spa_dict *info,
+ const struct spa_support *support,
+ uint32_t n_support);
+
+ /**
+ * spa_handle_factory::enum_interface_info:
+ * \param factory: a #spa_handle_factory
+ * \param info: result to hold spa_interface_info.
+ * \param index: index to keep track of the enumeration, 0 for first item
+ *
+ * Enumerate the interface information for \a factory.
+ *
+ * \return 1 when an item is available
+ * 0 when no more items are available
+ * < 0 errno type error
+ */
+ int (*enum_interface_info) (const struct spa_handle_factory *factory,
+ const struct spa_interface_info **info,
+ uint32_t *index);
+};
+
+#define spa_handle_factory_get_size(h,...) (h)->get_size((h),__VA_ARGS__)
+#define spa_handle_factory_init(h,...) (h)->init((h),__VA_ARGS__)
+#define spa_handle_factory_enum_interface_info(h,...) (h)->enum_interface_info((h),__VA_ARGS__)
+
+/**
+ * The function signature of the entry point in a plugin.
+ *
+ * \param factory a location to hold the factory result
+ * \param index index to keep track of the enumeration
+ * \return 1 on success
+ * 0 when there are no more factories
+ * -EINVAL when factory is NULL
+ */
+typedef int (*spa_handle_factory_enum_func_t) (const struct spa_handle_factory **factory,
+ uint32_t *index);
+
+#define SPA_HANDLE_FACTORY_ENUM_FUNC_NAME "spa_handle_factory_enum"
+
+/**
+ * The entry point in a plugin.
+ *
+ * \param factory a location to hold the factory result
+ * \param index index to keep track of the enumeration
+ * \return 1 on success
+ * 0 when no more items are available
+ * < 0 errno type error
+ */
+int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index);
+
+
+
+#define SPA_KEY_FACTORY_NAME "factory.name" /**< the name of a factory */
+#define SPA_KEY_FACTORY_AUTHOR "factory.author" /**< a comma separated list of factory authors */
+#define SPA_KEY_FACTORY_DESCRIPTION "factory.description" /**< description of a factory */
+#define SPA_KEY_FACTORY_USAGE "factory.usage" /**< usage of a factory */
+
+#define SPA_KEY_LIBRARY_NAME "library.name" /**< the name of a library. This is usually
+ * the filename of the plugin without the
+ * path or the plugin extension. */
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_PLUGIN_H */
diff --git a/third_party/pipewire/spa/support/system.h b/third_party/pipewire/spa/support/system.h
new file mode 100644
index 0000000000..8076ceb4bb
--- /dev/null
+++ b/third_party/pipewire/spa/support/system.h
@@ -0,0 +1,165 @@
+/* Simple Plugin API
+ *
+ * Copyright © 2019 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SPA_SYSTEM_H
+#define SPA_SYSTEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct itimerspec;
+
+#include <time.h>
+#include <sys/types.h>
+
+#include <spa/utils/defs.h>
+#include <spa/utils/hook.h>
+
+/** \defgroup spa_system System
+ * I/O, clock, polling, timer, and signal interfaces
+ */
+
+/**
+ * \addtogroup spa_system
+ * \{
+ */
+
+/**
+ * a collection of core system functions
+ */
+#define SPA_TYPE_INTERFACE_System SPA_TYPE_INFO_INTERFACE_BASE "System"
+#define SPA_TYPE_INTERFACE_DataSystem SPA_TYPE_INFO_INTERFACE_BASE "DataSystem"
+
+#define SPA_VERSION_SYSTEM 0
+struct spa_system { struct spa_interface iface; };
+
+/* IO events */
+#define SPA_IO_IN (1 << 0)
+#define SPA_IO_OUT (1 << 2)
+#define SPA_IO_ERR (1 << 3)
+#define SPA_IO_HUP (1 << 4)
+
+/* flags */
+#define SPA_FD_CLOEXEC (1<<0)
+#define SPA_FD_NONBLOCK (1<<1)
+#define SPA_FD_EVENT_SEMAPHORE (1<<2)
+#define SPA_FD_TIMER_ABSTIME (1<<3)
+#define SPA_FD_TIMER_CANCEL_ON_SET (1<<4)
+
+struct spa_poll_event {
+ uint32_t events;
+ void *data;
+};
+
+struct spa_system_methods {
+#define SPA_VERSION_SYSTEM_METHODS 0
+ uint32_t version;
+
+ /* read/write/ioctl */
+ ssize_t (*read) (void *object, int fd, void *buf, size_t count);
+ ssize_t (*write) (void *object, int fd, const void *buf, size_t count);
+ int (*ioctl) (void *object, int fd, unsigned long request, ...);
+ int (*close) (void *object, int fd);
+
+ /* clock */
+ int (*clock_gettime) (void *object,
+ int clockid, struct timespec *value);
+ int (*clock_getres) (void *object,
+ int clockid, struct timespec *res);
+
+ /* poll */
+ int (*pollfd_create) (void *object, int flags);
+ int (*pollfd_add) (void *object, int pfd, int fd, uint32_t events, void *data);
+ int (*pollfd_mod) (void *object, int pfd, int fd, uint32_t events, void *data);
+ int (*pollfd_del) (void *object, int pfd, int fd);
+ int (*pollfd_wait) (void *object, int pfd,
+ struct spa_poll_event *ev, int n_ev, int timeout);
+
+ /* timers */
+ int (*timerfd_create) (void *object, int clockid, int flags);
+ int (*timerfd_settime) (void *object,
+ int fd, int flags,
+ const struct itimerspec *new_value,
+ struct itimerspec *old_value);
+ int (*timerfd_gettime) (void *object,
+ int fd, struct itimerspec *curr_value);
+ int (*timerfd_read) (void *object, int fd, uint64_t *expirations);
+
+ /* events */
+ int (*eventfd_create) (void *object, int flags);
+ int (*eventfd_write) (void *object, int fd, uint64_t count);
+ int (*eventfd_read) (void *object, int fd, uint64_t *count);
+
+ /* signals */
+ int (*signalfd_create) (void *object, int signal, int flags);
+ int (*signalfd_read) (void *object, int fd, int *signal);
+};
+
+#define spa_system_method_r(o,method,version,...) \
+({ \
+ int _res = -ENOTSUP; \
+ struct spa_system *_o = o; \
+ spa_interface_call_res(&_o->iface, \
+ struct spa_system_methods, _res, \
+ method, version, ##__VA_ARGS__); \
+ _res; \
+})
+
+
+#define spa_system_read(s,...) spa_system_method_r(s,read,0,__VA_ARGS__)
+#define spa_system_write(s,...) spa_system_method_r(s,write,0,__VA_ARGS__)
+#define spa_system_ioctl(s,...) spa_system_method_r(s,ioctl,0,__VA_ARGS__)
+#define spa_system_close(s,...) spa_system_method_r(s,close,0,__VA_ARGS__)
+
+#define spa_system_clock_gettime(s,...) spa_system_method_r(s,clock_gettime,0,__VA_ARGS__)
+#define spa_system_clock_getres(s,...) spa_system_method_r(s,clock_getres,0,__VA_ARGS__)
+
+#define spa_system_pollfd_create(s,...) spa_system_method_r(s,pollfd_create,0,__VA_ARGS__)
+#define spa_system_pollfd_add(s,...) spa_system_method_r(s,pollfd_add,0,__VA_ARGS__)
+#define spa_system_pollfd_mod(s,...) spa_system_method_r(s,pollfd_mod,0,__VA_ARGS__)
+#define spa_system_pollfd_del(s,...) spa_system_method_r(s,pollfd_del,0,__VA_ARGS__)
+#define spa_system_pollfd_wait(s,...) spa_system_method_r(s,pollfd_wait,0,__VA_ARGS__)
+
+#define spa_system_timerfd_create(s,...) spa_system_method_r(s,timerfd_create,0,__VA_ARGS__)
+#define spa_system_timerfd_settime(s,...) spa_system_method_r(s,timerfd_settime,0,__VA_ARGS__)
+#define spa_system_timerfd_gettime(s,...) spa_system_method_r(s,timerfd_gettime,0,__VA_ARGS__)
+#define spa_system_timerfd_read(s,...) spa_system_method_r(s,timerfd_read,0,__VA_ARGS__)
+
+#define spa_system_eventfd_create(s,...) spa_system_method_r(s,eventfd_create,0,__VA_ARGS__)
+#define spa_system_eventfd_write(s,...) spa_system_method_r(s,eventfd_write,0,__VA_ARGS__)
+#define spa_system_eventfd_read(s,...) spa_system_method_r(s,eventfd_read,0,__VA_ARGS__)
+
+#define spa_system_signalfd_create(s,...) spa_system_method_r(s,signalfd_create,0,__VA_ARGS__)
+#define spa_system_signalfd_read(s,...) spa_system_method_r(s,signalfd_read,0,__VA_ARGS__)
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_SYSTEM_H */
diff --git a/third_party/pipewire/spa/support/thread.h b/third_party/pipewire/spa/support/thread.h
new file mode 100644
index 0000000000..ef3866f014
--- /dev/null
+++ b/third_party/pipewire/spa/support/thread.h
@@ -0,0 +1,149 @@
+/* Simple Plugin API
+ *
+ * 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 SPA_THREAD_H
+#define SPA_THREAD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+#include <errno.h>
+
+#include <spa/utils/defs.h>
+#include <spa/utils/hook.h>
+#include <spa/utils/dict.h>
+
+/** \defgroup spa_thread Thread
+ * Threading utility interfaces
+ */
+
+/**
+ * \addtogroup spa_thread
+ * \{
+ */
+
+/** a thread object.
+ * This can be cast to a platform native thread, like pthread on posix systems
+ */
+#define SPA_TYPE_INFO_Thread SPA_TYPE_INFO_POINTER_BASE "Thread"
+struct spa_thread;
+
+#define SPA_TYPE_INTERFACE_ThreadUtils SPA_TYPE_INFO_INTERFACE_BASE "ThreadUtils"
+#define SPA_VERSION_THREAD_UTILS 0
+struct spa_thread_utils { struct spa_interface iface; };
+
+/** thread utils */
+struct spa_thread_utils_methods {
+#define SPA_VERSION_THREAD_UTILS_METHODS 0
+ uint32_t version;
+
+ /** create a new thread that runs \a start with \a arg */
+ struct spa_thread * (*create) (void *object, const struct spa_dict *props,
+ void *(*start)(void*), void *arg);
+ /** stop and join a thread */
+ int (*join)(void *object, struct spa_thread *thread, void **retval);
+
+ /** get realtime priority range for threads created with \a props */
+ int (*get_rt_range) (void *object, const struct spa_dict *props, int *min, int *max);
+ /** acquire realtime priority, a priority of -1 refers to the priority
+ * configured in the realtime module
+ */
+ int (*acquire_rt) (void *object, struct spa_thread *thread, int priority);
+ /** drop realtime priority */
+ int (*drop_rt) (void *object, struct spa_thread *thread);
+};
+
+/** \copydoc spa_thread_utils_methods.create
+ * \sa spa_thread_utils_methods.create */
+static inline struct spa_thread *spa_thread_utils_create(struct spa_thread_utils *o,
+ const struct spa_dict *props, void *(*start_routine)(void*), void *arg)
+{
+ struct spa_thread *res = NULL;
+ spa_interface_call_res(&o->iface,
+ struct spa_thread_utils_methods, res, create, 0,
+ props, start_routine, arg);
+ return res;
+}
+
+/** \copydoc spa_thread_utils_methods.join
+ * \sa spa_thread_utils_methods.join */
+static inline int spa_thread_utils_join(struct spa_thread_utils *o,
+ struct spa_thread *thread, void **retval)
+{
+ int res = -ENOTSUP;
+ spa_interface_call_res(&o->iface,
+ struct spa_thread_utils_methods, res, join, 0,
+ thread, retval);
+ return res;
+}
+
+/** \copydoc spa_thread_utils_methods.get_rt_range
+ * \sa spa_thread_utils_methods.get_rt_range */
+static inline int spa_thread_utils_get_rt_range(struct spa_thread_utils *o,
+ const struct spa_dict *props, int *min, int *max)
+{
+ int res = -ENOTSUP;
+ spa_interface_call_res(&o->iface,
+ struct spa_thread_utils_methods, res, get_rt_range, 0,
+ props, min, max);
+ return res;
+}
+
+/** \copydoc spa_thread_utils_methods.acquire_rt
+ * \sa spa_thread_utils_methods.acquire_rt */
+static inline int spa_thread_utils_acquire_rt(struct spa_thread_utils *o,
+ struct spa_thread *thread, int priority)
+{
+ int res = -ENOTSUP;
+ spa_interface_call_res(&o->iface,
+ struct spa_thread_utils_methods, res, acquire_rt, 0,
+ thread, priority);
+ return res;
+}
+
+/** \copydoc spa_thread_utils_methods.drop_rt
+ * \sa spa_thread_utils_methods.drop_rt */
+static inline int spa_thread_utils_drop_rt(struct spa_thread_utils *o,
+ struct spa_thread *thread)
+{
+ int res = -ENOTSUP;
+ spa_interface_call_res(&o->iface,
+ struct spa_thread_utils_methods, res, drop_rt, 0, thread);
+ return res;
+}
+
+#define SPA_KEY_THREAD_NAME "thread.name" /* the thread name */
+#define SPA_KEY_THREAD_STACK_SIZE "thread.stack-size" /* the stack size of the thread */
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SPA_THREAD_H */