/* 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 #include #include /** \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 #include #include /** 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 */