diff options
Diffstat (limited to 'third_party/pipewire/pipewire')
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 */ |