/* PipeWire */ /* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */ /* SPDX-License-Identifier: MIT */ #ifndef PIPEWIRE_CORE_H #define PIPEWIRE_CORE_H #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** \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_CORE_PERM_MASK PW_PERM_R|PW_PERM_X|PW_PERM_M #define PW_VERSION_CORE 4 struct pw_core; #define PW_VERSION_REGISTRY 3 struct pw_registry; #ifndef PW_API_CORE_IMPL #define PW_API_CORE_IMPL static inline #endif #ifndef PW_API_REGISTRY_IMPL #define PW_API_REGISTRY_IMPL static inline #endif /** The default remote name to connect to */ #define PW_DEFAULT_REMOTE "pipewire-0" /** 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 #include #include /** Update an existing \ref pw_core_info with \a update with reset. When info is NULL, * a new one will be allocated. Returns NULL on failure. */ struct pw_core_info * pw_core_info_update(struct pw_core_info *info, const struct pw_core_info *update); /** Update an existing \ref pw_core_info with \a update. When info is NULL, a new one * will be allocated. Returns NULL on failure */ struct pw_core_info * pw_core_info_merge(struct pw_core_info *info, const struct pw_core_info *update, bool reset); /** 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_BOUND_PROPS 8 #define PW_CORE_EVENT_NUM 9 /** \struct pw_core_events * \brief Core events */ struct pw_core_events { #define PW_VERSION_CORE_EVENTS 1 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. * * The bound_props event is an enhanced version of this event that * also contains the extra global properties. * * \param id bound object ID * \param global_id the global id bound to */ 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); /** * Notify an object binding * * This event is emitted when a local object ID is bound to a * global ID. It is emitted before the global becomes visible in the * registry. * * This is an enhanced version of the bound_id event. * * \param id bound object ID * \param global_id the global id bound to * \param props The properties of the new global object. * * Since version 4:1 */ void (*bound_props) (void *data, uint32_t id, uint32_t global_id, const struct spa_dict *props); }; #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). * * This requires X permissions on the core. */ 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 * * This requires X permissions on the core. */ 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 * * This requires X permissions on the core. */ 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 resource id where the error occurred * \param res error code * \param message error description * * This requires X permissions on the core. */ int (*error) (void *object, uint32_t id, int seq, int res, const char *message); /** * 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 * * This requires X permissions on the core. */ 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 * * This requires X permissions on the core. */ 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 * * This requires X permissions on the core. */ int (*destroy) (void *object, void *proxy); }; /** \copydoc pw_core_methods.add_listener * \sa pw_core_methods.add_listener */ PW_API_CORE_IMPL int pw_core_add_listener(struct pw_core *object, struct spa_hook *listener, const struct pw_core_events *events, void *data) { return spa_api_method_r(int, -ENOTSUP, pw_core, (struct spa_interface*)object, add_listener, 0, listener, events, data); } /** \copydoc pw_core_methods.hello * \sa pw_core_methods.hello */ PW_API_CORE_IMPL int pw_core_hello(struct pw_core *object, uint32_t version) { return spa_api_method_r(int, -ENOTSUP, pw_core, (struct spa_interface*)object, hello, 0, version); } /** \copydoc pw_core_methods.sync * \sa pw_core_methods.sync */ PW_API_CORE_IMPL int pw_core_sync(struct pw_core *object, uint32_t id, int seq) { return spa_api_method_r(int, -ENOTSUP, pw_core, (struct spa_interface*)object, sync, 0, id, seq); } /** \copydoc pw_core_methods.pong * \sa pw_core_methods.pong */ PW_API_CORE_IMPL int pw_core_pong(struct pw_core *object, uint32_t id, int seq) { return spa_api_method_r(int, -ENOTSUP, pw_core, (struct spa_interface*)object, pong, 0, id, seq); } /** \copydoc pw_core_methods.error * \sa pw_core_methods.error */ PW_API_CORE_IMPL int pw_core_error(struct pw_core *object, uint32_t id, int seq, int res, const char *message) { return spa_api_method_r(int, -ENOTSUP, pw_core, (struct spa_interface*)object, error, 0, id, seq, res, message); } PW_API_CORE_IMPL SPA_PRINTF_FUNC(5, 0) int pw_core_errorv(struct pw_core *core, uint32_t id, int seq, int res, const char *message, va_list args) { char buffer[1024]; vsnprintf(buffer, sizeof(buffer), message, args); buffer[1023] = '\0'; return pw_core_error(core, id, seq, res, buffer); } PW_API_CORE_IMPL SPA_PRINTF_FUNC(5, 6) int pw_core_errorf(struct pw_core *core, uint32_t id, int seq, int res, const char *message, ...) { va_list args; int r; va_start(args, message); r = pw_core_errorv(core, id, seq, res, message, args); va_end(args); return r; } /** \copydoc pw_core_methods.get_registry * \sa pw_core_methods.get_registry */ PW_API_CORE_IMPL struct pw_registry * pw_core_get_registry(struct pw_core *core, uint32_t version, size_t user_data_size) { return spa_api_method_r(struct pw_registry*, NULL, pw_core, (struct spa_interface*)core, get_registry, 0, version, user_data_size); } /** \copydoc pw_core_methods.create_object * \sa pw_core_methods.create_object */ PW_API_CORE_IMPL void * pw_core_create_object(struct pw_core *core, const char *factory_name, const char *type, uint32_t version, const struct spa_dict *props, size_t user_data_size) { return spa_api_method_r(void*, NULL, pw_core, (struct spa_interface*)core, create_object, 0, factory_name, type, version, props, user_data_size); } /** \copydoc pw_core_methods.destroy * \sa pw_core_methods.destroy */ PW_API_CORE_IMPL void pw_core_destroy(struct pw_core *core, void *proxy) { spa_api_method_v(pw_core, (struct spa_interface*)core, destroy, 0, proxy); } /** * \} */ /** \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. The client needs X permissions * on the global. */ int (*destroy) (void *object, uint32_t id); }; /** Registry */ /** \copydoc pw_registry_methods.add_listener * \sa pw_registry_methods.add_listener */ PW_API_REGISTRY_IMPL int pw_registry_add_listener(struct pw_registry *registry, struct spa_hook *listener, const struct pw_registry_events *events, void *data) { return spa_api_method_r(int, -ENOTSUP, pw_registry, (struct spa_interface*)registry, add_listener, 0, listener, events, data); } /** \copydoc pw_registry_methods.bind * \sa pw_registry_methods.bind */ PW_API_REGISTRY_IMPL void * pw_registry_bind(struct pw_registry *registry, uint32_t id, const char *type, uint32_t version, size_t user_data_size) { return spa_api_method_r(void*, NULL, pw_registry, (struct spa_interface*)registry, bind, 0, id, type, version, user_data_size); } /** \copydoc pw_registry_methods.destroy * \sa pw_registry_methods.destroy */ PW_API_REGISTRY_IMPL int pw_registry_destroy(struct pw_registry *registry, uint32_t id) { return spa_api_method_r(int, -ENOTSUP, pw_registry, (struct spa_interface*)registry, destroy, 0, id); } /** * \} */ /** * \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 */