diff --git a/modules/module-pipewire.c b/modules/module-pipewire.c index ab422cf7..a329fb8b 100644 --- a/modules/module-pipewire.c +++ b/modules/module-pipewire.c @@ -26,12 +26,7 @@ gpointer simple_endpoint_link_factory (WpFactory * factory, GType type, struct module_data { WpModule *module; - - /* Registry */ - struct pw_registry_proxy *registry_proxy; - struct spa_hook registry_listener; - - /* Client nodes info */ + WpRemotePipewire *remote_pipewire; GHashTable *client_nodes_info; }; @@ -39,7 +34,7 @@ struct endpoint_info { gchar *name; gchar *media_class; - const struct pw_proxy *proxy; + struct pw_proxy *proxy; }; struct proxy_info @@ -143,8 +138,8 @@ proxy_port_created(GObject *initable, GAsyncResult *res, gpointer d) { struct proxy_info *pi = d; const struct module_data *data = pi->data; + struct endpoint_info *ei = NULL; WpProxyPort *proxy_port = NULL; - struct pw_proxy *proxy = NULL; /* Get the proxy port */ proxy_port = wp_proxy_port_new_finish(initable, res, NULL); @@ -155,19 +150,21 @@ proxy_port_created(GObject *initable, GAsyncResult *res, gpointer d) pi->proxy_port = proxy_port; /* Get the node proxy */ - proxy = pw_registry_proxy_bind (data->registry_proxy, pi->node_id, - PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, 0); - if (!proxy) + ei = g_hash_table_lookup(data->client_nodes_info, + GINT_TO_POINTER(pi->node_id)); + if (!ei) return; /* Create the proxy node asynchronically */ - wp_proxy_node_new(pi->node_id, proxy, proxy_node_created, pi); + wp_proxy_node_new(pi->node_id, ei->proxy, proxy_node_created, pi); } static void -handle_node (struct module_data *data, uint32_t id, uint32_t parent_id, - const struct spa_dict * props) +handle_node (WpRemotePipewire *rp, guint id, guint parent_id, gconstpointer p, + gpointer d) { + struct module_data *data = d; + const struct spa_dict *props = p; struct endpoint_info *ei = NULL; const gchar *name; const gchar *media_class; @@ -198,9 +195,10 @@ handle_node (struct module_data *data, uint32_t id, uint32_t parent_id, g_debug ("found stream node: id:%u ; name:%s ; media_class:%s", id, name, media_class); - /* Get the proxy */ - proxy = pw_registry_proxy_bind (data->registry_proxy, id, - PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, 0); + /* Bind the proxy */ + proxy = wp_remote_pipewire_proxy_bind(rp, id, PW_TYPE_INTERFACE_Node); + if (!proxy) + return; /* TODO: Assume all clients have this format for now */ format.format = SPA_AUDIO_FORMAT_F32P; @@ -230,9 +228,10 @@ handle_node (struct module_data *data, uint32_t id, uint32_t parent_id, } static void -handle_port(struct module_data *data, uint32_t id, uint32_t parent_id, - const struct spa_dict *props) +handle_port(WpRemotePipewire *rp, guint id, guint parent_id, gconstpointer p, + gpointer d) { + struct module_data *data = d; struct proxy_info *pi = NULL; struct pw_proxy *proxy = NULL; @@ -241,9 +240,8 @@ handle_port(struct module_data *data, uint32_t id, uint32_t parent_id, GINT_TO_POINTER (parent_id))) return; - /* Get the port proxy */ - proxy = pw_registry_proxy_bind (data->registry_proxy, id, - PW_TYPE_INTERFACE_Port, PW_VERSION_PORT, 0); + /* Bind the proxy */ + proxy = wp_remote_pipewire_proxy_bind (rp, id, PW_TYPE_INTERFACE_Port); if (!proxy) return; @@ -257,55 +255,18 @@ handle_port(struct module_data *data, uint32_t id, uint32_t parent_id, wp_proxy_port_new(id, proxy, proxy_port_created, pi); } -static void -registry_global(void *d, uint32_t id, uint32_t parent_id, - uint32_t permissions, uint32_t type, uint32_t version, - const struct spa_dict *props) -{ - struct module_data *data = d; - - switch (type) { - case PW_TYPE_INTERFACE_Node: - handle_node(data, id, parent_id, props); - break; - - case PW_TYPE_INTERFACE_Port: - handle_port(data, id, parent_id, props); - break; - - default: - break; - } -} - -static const struct pw_registry_proxy_events registry_events = { - PW_VERSION_REGISTRY_PROXY_EVENTS, - .global = registry_global, -}; - -static void -on_remote_connected (WpRemote *remote, WpRemoteState state, - struct module_data *data) -{ - struct pw_core_proxy *core_proxy; - struct pw_remote *pw_remote; - - g_object_get (remote, "pw-remote", &pw_remote, NULL); - - core_proxy = pw_remote_get_core_proxy (pw_remote); - data->registry_proxy = pw_core_proxy_get_registry (core_proxy, - PW_TYPE_INTERFACE_Registry, PW_VERSION_REGISTRY, 0); - pw_registry_proxy_add_listener(data->registry_proxy, - &data->registry_listener, ®istry_events, data); -} - static void module_destroy (gpointer d) { struct module_data *data = d; + /* Set to NULL module and remote pipewire as we don't own the reference */ + data->module = NULL; + data->remote_pipewire = NULL; + /* Destroy the hash table */ g_hash_table_unref (data->client_nodes_info); + data->client_nodes_info = NULL; /* Clean up */ g_slice_free (struct module_data, data); @@ -315,12 +276,13 @@ void wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args) { struct module_data *data; - WpRemote *remote; + WpRemotePipewire *rp; struct pw_core *pw_core; struct pw_remote *pw_remote; - remote = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE); - if (!remote) { + /* Make sure the remote pipewire is valid */ + rp = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE); + if (!rp) { g_critical ("module-pipewire cannot be loaded without a registered " "WpRemotePipewire object"); return; @@ -329,20 +291,22 @@ wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args) /* Create the module data */ data = g_slice_new0 (struct module_data); data->module = module; + data->remote_pipewire = rp; data->client_nodes_info = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, endpoint_info_destroy); + /* Set the module destroy callback */ wp_module_set_destroy_callback (module, module_destroy, data); - g_signal_connect (remote, "state-changed::connected", - (GCallback) on_remote_connected, data); + /* Register the global addded callbacks */ + g_signal_connect(rp, "global-added::node", (GCallback)handle_node, data); + g_signal_connect(rp, "global-added::port", (GCallback)handle_port, data); - g_object_get (remote, - "pw-core", &pw_core, - "pw-remote", &pw_remote, - NULL); + /* Init remoted endpoint */ + g_object_get (rp, "pw-core", &pw_core, "pw-remote", &pw_remote, NULL); remote_endpoint_init (core, pw_core, pw_remote); + /* Register simple-endpoint and simple-endpoint-link */ wp_factory_new (core, "pipewire-simple-endpoint", simple_endpoint_factory); wp_factory_new (core, "pipewire-simple-endpoint-link", simple_endpoint_link_factory); diff --git a/modules/module-pw-alsa-udev.c b/modules/module-pw-alsa-udev.c index 0f2c99cc..c98cd76c 100644 --- a/modules/module-pw-alsa-udev.c +++ b/modules/module-pw-alsa-udev.c @@ -18,15 +18,7 @@ struct impl { WpModule *module; - - /* Remote */ - struct spa_hook remote_listener; - - /* Registry */ - struct pw_registry_proxy *registry_proxy; - struct spa_hook registry_listener; - - /* The alsa node proxies */ + WpRemotePipewire *remote_pipewire; GHashTable *alsa_nodes_info; }; @@ -89,8 +81,8 @@ proxy_node_created(GObject *initable, GAsyncResult *res, gpointer data) g_autoptr(WpProxyNode) proxy_node = NULL; struct endpoint_info *ei = NULL; GVariantBuilder b; - g_autoptr(GVariant) endpoint_props = NULL; - g_autoptr(WpEndpoint) endpoint = NULL; + g_autoptr (GVariant) endpoint_props = NULL; + g_autoptr (WpEndpoint) endpoint = NULL; /* Get the proxy */ proxy_node = wp_proxy_node_new_finish(initable, res, NULL); @@ -147,8 +139,8 @@ proxy_port_created(GObject *initable, GAsyncResult *res, gpointer data) pi->proxy_port = proxy_port; /* Get the node proxy */ - proxy = pw_registry_proxy_bind (impl->registry_proxy, pi->node_id, - PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, 0); + proxy = wp_remote_pipewire_proxy_bind (impl->remote_pipewire, pi->node_id, + PW_TYPE_INTERFACE_Node); if (!proxy) return; @@ -157,17 +149,16 @@ proxy_port_created(GObject *initable, GAsyncResult *res, gpointer data) } static void -handle_node(struct impl *impl, uint32_t id, uint32_t parent_id, - const struct spa_dict *props) +handle_node(WpRemotePipewire *rp, guint id, guint parent_id, gconstpointer p, + gpointer d) { + struct impl *impl = d; + const struct spa_dict *props = p; const gchar *media_class = NULL, *name = NULL; struct endpoint_info *ei = NULL; /* Make sure the node has properties */ - if (!props) { - g_warning("node has no properties, skipping..."); - return; - } + g_return_if_fail(props); /* Get the name and media_class */ name = spa_dict_lookup(props, "node.name"); @@ -189,9 +180,10 @@ handle_node(struct impl *impl, uint32_t id, uint32_t parent_id, } static void -handle_port(struct impl *impl, uint32_t id, uint32_t parent_id, - const struct spa_dict *props) +handle_port(WpRemotePipewire *rp, guint id, guint parent_id, gconstpointer p, + gpointer d) { + struct impl *impl = d; struct proxy_info *pi = NULL; struct pw_proxy *proxy = NULL; @@ -199,13 +191,8 @@ handle_port(struct impl *impl, uint32_t id, uint32_t parent_id, if (!g_hash_table_contains(impl->alsa_nodes_info, GINT_TO_POINTER (parent_id))) return; - /* Make sure the port has porperties */ - if (!props) - return; - /* Get the port proxy */ - proxy = pw_registry_proxy_bind (impl->registry_proxy, id, - PW_TYPE_INTERFACE_Port, PW_VERSION_PORT, 0); + proxy = wp_remote_pipewire_proxy_bind (rp, id, PW_TYPE_INTERFACE_Port); if (!proxy) return; @@ -219,90 +206,48 @@ handle_port(struct impl *impl, uint32_t id, uint32_t parent_id, wp_proxy_port_new(id, proxy, proxy_port_created, pi); } -static void -registry_global(void *data, uint32_t id, uint32_t parent_id, - uint32_t permissions, uint32_t type, uint32_t version, - const struct spa_dict *props) -{ - struct impl *impl = data; - - switch (type) { - case PW_TYPE_INTERFACE_Node: - handle_node(impl, id, parent_id, props); - break; - - case PW_TYPE_INTERFACE_Port: - handle_port(impl, id, parent_id, props); - break; - - default: - break; - } -} - -static const struct pw_registry_proxy_events registry_events = { - PW_VERSION_REGISTRY_PROXY_EVENTS, - .global = registry_global, -}; - -static void -on_connected (WpRemote *remote, WpRemoteState state, struct impl *impl) -{ - struct pw_core_proxy *core_proxy = NULL; - struct pw_remote *pw_remote; - - g_object_get (remote, "pw-remote", &pw_remote, NULL); - - core_proxy = pw_remote_get_core_proxy (pw_remote); - impl->registry_proxy = pw_core_proxy_get_registry (core_proxy, - PW_TYPE_INTERFACE_Registry, PW_VERSION_REGISTRY, 0); - pw_registry_proxy_add_listener(impl->registry_proxy, - &impl->registry_listener, ®istry_events, impl); -} - static void module_destroy (gpointer data) { struct impl *impl = data; + /* Set to NULL module and remote pipewire as we don't own the reference */ + impl->module = NULL; + impl->remote_pipewire = NULL; + /* Destroy the hash table */ g_hash_table_unref (impl->alsa_nodes_info); + impl->alsa_nodes_info = NULL; /* Clean up */ g_slice_free (struct impl, impl); } -struct impl * -module_create (WpModule * module, WpCore * core) -{ - struct impl *impl; - WpRemote *remote; - - /* Allocate impl */ - impl = g_new0(struct impl, 1); - - /* Set core */ - impl->module = module; - - /* Set remote */ - remote = wp_core_get_global(core, WP_GLOBAL_REMOTE_PIPEWIRE); - g_signal_connect (remote, "state-changed::connected", - (GCallback) on_connected, impl); - - /* Create the hash table */ - impl->alsa_nodes_info = g_hash_table_new_full (g_direct_hash, - g_direct_equal, NULL, endpoint_info_destroy); - - /* Return the module */ - return impl; -} - void wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args) { - /* Create the impl */ - struct impl *impl = module_create (module, core); + struct impl *impl; + WpRemotePipewire *rp; + + /* Make sure the remote pipewire is valid */ + rp = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE); + if (!rp) { + g_critical ("module-pw-alsa-udev cannot be loaded without a registered " + "WpRemotePipewire object"); + return; + } + + /* Create the module data */ + impl = g_slice_new0(struct impl); + impl->module = module; + impl->remote_pipewire = rp; + impl->alsa_nodes_info = g_hash_table_new_full (g_direct_hash, + g_direct_equal, NULL, endpoint_info_destroy); /* Set destroy callback for impl */ wp_module_set_destroy_callback (module, module_destroy, impl); + + /* Register the global addded callbacks */ + g_signal_connect(rp, "global-added::node", (GCallback)handle_node, impl); + g_signal_connect(rp, "global-added::port", (GCallback)handle_port, impl); } diff --git a/modules/module-pw-audio-softdsp-endpoint.c b/modules/module-pw-audio-softdsp-endpoint.c index 481c3c4b..c728dce5 100644 --- a/modules/module-pw-audio-softdsp-endpoint.c +++ b/modules/module-pw-audio-softdsp-endpoint.c @@ -26,17 +26,13 @@ struct _WpPwAudioSoftdspEndpoint { WpEndpoint parent; + /* The remote pipewire */ + WpRemotePipewire *remote_pipewire; + /* temporary method to select which endpoint * is going to be the default input/output */ gboolean selected; - /* Core */ - struct pw_core_proxy *core_proxy; - - /* Registry */ - struct pw_registry_proxy *registry_proxy; - struct spa_hook registry_listener; - /* Direction */ enum pw_direction direction; @@ -132,8 +128,8 @@ on_dsp_running(WpPwAudioSoftdspEndpoint *self) g_debug ("%p linking DSP to node", self); /* Create the link */ - self->link_proxy = pw_core_proxy_create_object(self->core_proxy, - "link-factory", PW_TYPE_INTERFACE_Link, PW_VERSION_LINK, &props->dict, 0); + self->link_proxy = wp_remote_pipewire_create_object(self->remote_pipewire, + "link-factory", PW_TYPE_INTERFACE_Link, &props->dict); /* Clean up */ pw_properties_free(props); @@ -264,8 +260,8 @@ emit_audio_dsp_node (WpPwAudioSoftdspEndpoint *self) MAX_QUANTUM_SIZE * sizeof(float)); /* Set the DSP proxy and listener */ - self->dsp_proxy = pw_core_proxy_create_object(self->core_proxy, "audio-dsp", - PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, &props->dict, 0); + self->dsp_proxy = wp_remote_pipewire_create_object(self->remote_pipewire, + "audio-dsp", PW_TYPE_INTERFACE_Node, &props->dict); pw_node_proxy_add_listener(self->dsp_proxy, &self->dsp_listener, &dsp_node_events, self); pw_node_proxy_enum_params (self->dsp_proxy, 0, SPA_PARAM_Props, 0, -1, NULL); @@ -284,21 +280,69 @@ emit_audio_dsp_node (WpPwAudioSoftdspEndpoint *self) pw_properties_free(props); } +static void +handle_port(WpRemotePipewire *rp, guint id, guint parent_id, gconstpointer p, + gpointer d) +{ + WpPwAudioSoftdspEndpoint *self = d; + const struct spa_dict *props = p; + const char *direction_prop = NULL; + enum pw_direction direction; + + /* Make sure the dsp port is not already set*/ + if (self->dsp_port_id != 0) + return; + + /* Make sure the port has porperties */ + if (!props) + return; + + /* Only handle ports owned by this endpoint */ + if (!self->dsp_info || self->dsp_info->id != parent_id) + return; + + /* Get the direction property */ + direction_prop = spa_dict_lookup(props, "port.direction"); + if (!direction_prop) + return; + direction = + !strcmp(direction_prop, "out") ? PW_DIRECTION_OUTPUT : PW_DIRECTION_INPUT; + + /* Only handle ports with the oposit direction of the endpoint */ + if (self->direction == direction) + return; + + /* Set the dsp port id */ + self->dsp_port_id = id; +} + static void endpoint_constructed (GObject * object) { WpPwAudioSoftdspEndpoint *self = WP_PW_AUDIO_SOFTDSP_ENDPOINT (object); + g_autoptr (WpCore) core = wp_endpoint_get_core(WP_ENDPOINT(self)); const gchar *media_class = wp_endpoint_get_media_class (WP_ENDPOINT (self)); GVariantDict d; + /* Set Remote Pipewire */ + self->remote_pipewire = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE); + if (!self->remote_pipewire) + g_critical ("failed to get remote pipewire "); + + /* Register the global-added::port callback in remote pipewire */ + g_signal_connect(self->remote_pipewire, "global-added::port", + (GCallback)handle_port, self); + /* Set the direction */ - if (g_str_has_suffix (media_class, "Source")) { + if (g_str_has_suffix (media_class, "Source")) self->direction = PW_DIRECTION_INPUT; - } else if (g_str_has_suffix (media_class, "Sink")) { + else if (g_str_has_suffix (media_class, "Sink")) self->direction = PW_DIRECTION_OUTPUT; - } else { + else g_critical ("failed to parse direction"); - } + + /* Emit the audio DSP node */ + emit_audio_dsp_node(self); g_variant_dict_init (&d, NULL); g_variant_dict_insert (&d, "id", "u", 0); @@ -338,6 +382,9 @@ endpoint_finalize (GObject * object) { WpPwAudioSoftdspEndpoint *self = WP_PW_AUDIO_SOFTDSP_ENDPOINT (object); + /* Set to NULL remote pipewire as we don't own the reference */ + self->remote_pipewire = NULL; + /* Unref the proxy node */ g_clear_object (&self->proxy_node); @@ -500,6 +547,7 @@ endpoint_class_init (WpPwAudioSoftdspEndpointClass * klass) endpoint_class->get_control_value = endpoint_get_control_value; endpoint_class->set_control_value = endpoint_set_control_value; + /* Instal the properties */ g_object_class_install_property (object_class, PROP_NODE_PROXY, g_param_spec_object ("node-proxy", "node-proxy", "Pointer to the node proxy of the device", WP_TYPE_PROXY_NODE, @@ -510,91 +558,22 @@ endpoint_class_init (WpPwAudioSoftdspEndpointClass * klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); } -static void -handle_port(WpPwAudioSoftdspEndpoint *self, uint32_t id, uint32_t parent_id, - const struct spa_dict *props) -{ - const char *direction_prop = NULL; - enum pw_direction direction; - - /* Make sure the dsp port is not already set*/ - if (self->dsp_port_id != 0) - return; - - /* Make sure the port has porperties */ - if (!props) - return; - - /* Only handle ports owned by this endpoint */ - if (!self->dsp_info || self->dsp_info->id != parent_id) - return; - - /* Get the direction property */ - direction_prop = spa_dict_lookup(props, "port.direction"); - if (!direction_prop) - return; - direction = - !strcmp(direction_prop, "out") ? PW_DIRECTION_OUTPUT : PW_DIRECTION_INPUT; - - /* Only handle ports with the oposit direction of the endpoint */ - if (self->direction == direction) - return; - - /* Set the dsp port id */ - self->dsp_port_id = id; -} - -static void -registry_global(void *data, uint32_t id, uint32_t parent_id, - uint32_t permissions, uint32_t type, uint32_t version, - const struct spa_dict *props) -{ - WpPwAudioSoftdspEndpoint *self = data; - - switch (type) { - case PW_TYPE_INTERFACE_Port: - handle_port(self, id, parent_id, props); - break; - - default: - break; - } -} - -static const struct pw_registry_proxy_events registry_events = { - PW_VERSION_REGISTRY_PROXY_EVENTS, - .global = registry_global, -}; - static gpointer endpoint_factory (WpFactory * factory, GType type, GVariant * properties) { - g_autoptr (WpCore) wp_core = NULL; - WpRemote *remote; - struct pw_remote *pw_remote; + g_autoptr (WpCore) core = NULL; const gchar *name = NULL; const gchar *media_class = NULL; guint64 proxy_node, proxy_port; - /* Make sure the type is not the base class type */ - if (type != WP_TYPE_ENDPOINT) - return NULL; + /* Make sure the type is correct */ + g_return_val_if_fail(type == WP_TYPE_ENDPOINT, NULL); - /* Get the WirePlumber core */ - wp_core = wp_factory_get_core(factory); - if (!wp_core) { - g_warning("failed to get wireplumbe core. Skipping..."); - return NULL; - } + /* Get the Core */ + core = wp_factory_get_core(factory); + g_return_val_if_fail (core, NULL); - /* Get the remote */ - remote = wp_core_get_global(wp_core, WP_GLOBAL_REMOTE_PIPEWIRE); - if (!remote) { - g_warning("failed to get core remote. Skipping..."); - return NULL; - } - - /* Get the name and media-class */ + /* Get the properties */ if (!g_variant_lookup (properties, "name", "&s", &name)) return NULL; if (!g_variant_lookup (properties, "media-class", "&s", &media_class)) @@ -604,36 +583,14 @@ endpoint_factory (WpFactory * factory, GType type, GVariant * properties) if (!g_variant_lookup (properties, "proxy-port", "t", &proxy_port)) return NULL; - /* Create the softdsp endpoint object */ - WpPwAudioSoftdspEndpoint *ep = g_object_new (endpoint_get_type (), - "core", wp_core, + /* Create and return the softdsp endpoint object */ + return g_object_new (endpoint_get_type (), + "core", core, "name", name, "media-class", media_class, "node-proxy", (gpointer) proxy_node, "port-proxy", (gpointer) proxy_port, NULL); - if (!ep) - return NULL; - - /* Set the core proxy */ - g_object_get (remote, "pw-remote", &pw_remote, NULL); - ep->core_proxy = pw_remote_get_core_proxy(pw_remote); - if (!ep->core_proxy) { - g_warning("failed to get core proxy. Skipping..."); - return NULL; - } - - /* Add registry listener */ - ep->registry_proxy = pw_core_proxy_get_registry (ep->core_proxy, - PW_TYPE_INTERFACE_Registry, PW_VERSION_REGISTRY, 0); - pw_registry_proxy_add_listener(ep->registry_proxy, &ep->registry_listener, - ®istry_events, ep); - - /* Emit the audio DSP node */ - emit_audio_dsp_node(ep); - - /* Return the object */ - return ep; } void