diff --git a/lib/wp/proxy-node.c b/lib/wp/proxy-node.c index 9b518365..e39801a6 100644 --- a/lib/wp/proxy-node.c +++ b/lib/wp/proxy-node.c @@ -47,9 +47,6 @@ wp_proxy_node_finalize (GObject * object) { WpProxyNode *self = WP_PROXY_NODE(object); - /* Remove the listener */ - spa_hook_remove (&self->listener); - /* Clear the info */ if (self->info) { pw_node_info_free(self->info); diff --git a/lib/wp/proxy-port.c b/lib/wp/proxy-port.c index 07ab144c..f916a03e 100644 --- a/lib/wp/proxy-port.c +++ b/lib/wp/proxy-port.c @@ -77,9 +77,6 @@ wp_proxy_port_finalize (GObject * object) { WpProxyPort *self = WP_PROXY_PORT(object); - /* Remove the listener */ - spa_hook_remove (&self->listener); - /* Clear the indo */ if (self->info) { pw_port_info_free(self->info); diff --git a/lib/wp/proxy.c b/lib/wp/proxy.c index c5082f15..8d9917b4 100644 --- a/lib/wp/proxy.c +++ b/lib/wp/proxy.c @@ -35,6 +35,7 @@ enum { enum { SIGNAL_DESTROYED, + SIGNAL_DONE, LAST_SIGNAL, }; @@ -63,6 +64,9 @@ proxy_event_done (void *data, int seq) { WpProxyPrivate *self = wp_proxy_get_instance_private (WP_PROXY(data)); + /* Emit the done signal */ + g_signal_emit (data, wp_proxy_signals[SIGNAL_DONE], 0); + /* Make sure the task is valid */ if (!self->done_task) return; @@ -89,9 +93,6 @@ wp_proxy_finalize (GObject * object) g_debug ("%s:%p destroyed (pw proxy %p)", G_OBJECT_TYPE_NAME (object), object, self->proxy); - /* Remove the listener */ - spa_hook_remove (&self->listener); - /* Destroy the proxy */ if (self->proxy) { pw_proxy_destroy (self->proxy); @@ -152,7 +153,7 @@ wp_proxy_init_async (GAsyncInitable *initable, int io_priority, pw_proxy_add_listener (self->proxy, &self->listener, &proxy_events, initable); /* Trigger the done callback */ - pw_proxy_sync(self->proxy, 0); + wp_proxy_sync(WP_PROXY(initable)); } static gboolean @@ -199,8 +200,11 @@ wp_proxy_class_init (WpProxyClass * klass) /* Signals */ wp_proxy_signals[SIGNAL_DESTROYED] = g_signal_new ("destroyed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (WpProxyClass, destroyed), NULL, NULL, - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + G_STRUCT_OFFSET (WpProxyClass, destroyed), NULL, NULL, NULL, G_TYPE_NONE, + 0); + wp_proxy_signals[SIGNAL_DONE] = + g_signal_new ("done", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (WpProxyClass, done), NULL, NULL, NULL, G_TYPE_NONE, 0); } guint @@ -224,3 +228,15 @@ wp_proxy_get_pw_proxy (WpProxy * self) priv = wp_proxy_get_instance_private (self); return priv->proxy; } + +void wp_proxy_sync (WpProxy * self) +{ + WpProxyPrivate *priv; + + g_return_if_fail (WP_IS_PROXY (self)); + + priv = wp_proxy_get_instance_private (self); + + /* Trigger the done callback */ + pw_proxy_sync(priv->proxy, 0); +} diff --git a/lib/wp/proxy.h b/lib/wp/proxy.h index 456b29b4..be3570b4 100644 --- a/lib/wp/proxy.h +++ b/lib/wp/proxy.h @@ -24,11 +24,13 @@ struct _WpProxyClass GObjectClass parent_class; /* Signals */ - void (*destroyed)(WpProxy *wp_proxy); + void (*destroyed)(WpProxy *wp_proxy, gpointer data); + void (*done)(WpProxy *wp_proxy, gpointer data); }; guint wp_proxy_get_global_id (WpProxy * self); gpointer wp_proxy_get_pw_proxy (WpProxy * self); +void wp_proxy_sync (WpProxy * self); G_END_DECLS diff --git a/lib/wp/remote-pipewire.c b/lib/wp/remote-pipewire.c index ecdd3ca2..15659bf4 100644 --- a/lib/wp/remote-pipewire.c +++ b/lib/wp/remote-pipewire.c @@ -15,6 +15,9 @@ #define WP_LOOP_SOURCE(x) ((WpLoopSource *) x) +G_DEFINE_QUARK (node, signal_detail_node) +G_DEFINE_QUARK (port, signal_detail_port) + typedef struct _WpLoopSource WpLoopSource; struct _WpLoopSource { @@ -74,6 +77,11 @@ struct _WpRemotePipewire struct pw_core *core; struct pw_remote *remote; struct spa_hook remote_listener; + struct pw_core_proxy *core_proxy; + + /* Registry */ + struct pw_registry_proxy *registry_proxy; + struct spa_hook registry_listener; GMainContext *context; }; @@ -87,8 +95,61 @@ enum { PROP_CONTEXT, }; +enum +{ + SIGNAL_GLOBAL_ADDED, + SIGNAL_GLOBAL_REMOVED, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + G_DEFINE_TYPE (WpRemotePipewire, wp_remote_pipewire, WP_TYPE_REMOTE) +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) +{ + switch (type) { + case PW_TYPE_INTERFACE_Node: + g_signal_emit (data, signals[SIGNAL_GLOBAL_ADDED], + signal_detail_node_quark (), id, parent_id, props); + break; + case PW_TYPE_INTERFACE_Port: + g_signal_emit (data, signals[SIGNAL_GLOBAL_ADDED], + signal_detail_port_quark (), id, parent_id, props); + break; + default: + break; + } +} + +static void +registry_global_remove (void *data, uint32_t id) +{ + g_signal_emit (data, signals[SIGNAL_GLOBAL_REMOVED], 0, id); +} + +static const struct pw_registry_proxy_events registry_proxy_events = { + PW_VERSION_REGISTRY_PROXY_EVENTS, + .global = registry_global, + .global_remove = registry_global_remove, +}; + +static void +registry_init (WpRemotePipewire *self) +{ + /* Get the core proxy */ + self->core_proxy = pw_remote_get_core_proxy (self->remote); + + /* Registry */ + self->registry_proxy = pw_core_proxy_get_registry (self->core_proxy, + PW_TYPE_INTERFACE_Registry, PW_VERSION_REGISTRY, 0); + pw_registry_proxy_add_listener(self->registry_proxy, &self->registry_listener, + ®istry_proxy_events, self); +} + static void on_remote_state_changed (void *d, enum pw_remote_state old_state, enum pw_remote_state new_state, const char *error) @@ -99,6 +160,10 @@ on_remote_state_changed (void *d, enum pw_remote_state old_state, pw_remote_state_as_string (old_state), pw_remote_state_as_string (new_state)); + /* Init the registry when connected */ + if (!self->registry_proxy && new_state == PW_REMOTE_STATE_CONNECTED) + registry_init (self); + g_object_notify (G_OBJECT (self), "state"); } @@ -138,6 +203,8 @@ wp_remote_pipewire_finalize (GObject *object) pw_remote_destroy (self->remote); pw_core_destroy (self->core); g_clear_pointer (&self->context, g_main_context_unref); + self->core_proxy= NULL; + self->registry_proxy = NULL; G_OBJECT_CLASS (wp_remote_pipewire_parent_class)->finalize (object); } @@ -242,6 +309,15 @@ wp_remote_pipewire_class_init (WpRemotePipewireClass *klass) g_object_class_install_property (object_class, PROP_PW_REMOTE, g_param_spec_pointer ("pw-remote", "pw-remote", "The pipewire remote", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + /* Signals */ + signals[SIGNAL_GLOBAL_ADDED] = g_signal_new ("global-added", + G_TYPE_FROM_CLASS (klass), G_SIGNAL_DETAILED | G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, + G_TYPE_POINTER); + signals[SIGNAL_GLOBAL_REMOVED] = g_signal_new ("global-removed", + G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT); } WpRemote * @@ -260,3 +336,25 @@ wp_remote_pipewire_new (WpCore *core, GMainContext *context) return remote; } + +gpointer +wp_remote_pipewire_proxy_bind (WpRemotePipewire *self, guint global_id, + guint global_type) +{ + g_return_val_if_fail (WP_IS_REMOTE_PIPEWIRE(self), NULL); + g_return_val_if_fail (self->registry_proxy, NULL); + + return pw_registry_proxy_bind (self->registry_proxy, global_id, global_type, + 0, 0); +} + +gpointer +wp_remote_pipewire_create_object (WpRemotePipewire *self, + const char *factory_name, guint global_type, gconstpointer props) +{ + g_return_val_if_fail (WP_IS_REMOTE_PIPEWIRE(self), NULL); + g_return_val_if_fail (self->core_proxy, NULL); + + return pw_core_proxy_create_object(self->core_proxy, factory_name, + global_type, 0, props, 0); +} diff --git a/lib/wp/remote-pipewire.h b/lib/wp/remote-pipewire.h index d7da043d..347ffae0 100644 --- a/lib/wp/remote-pipewire.h +++ b/lib/wp/remote-pipewire.h @@ -19,6 +19,11 @@ G_DECLARE_FINAL_TYPE (WpRemotePipewire, wp_remote_pipewire, WpRemote *wp_remote_pipewire_new (WpCore *core, GMainContext *context); +gpointer wp_remote_pipewire_proxy_bind (WpRemotePipewire *self, guint global_id, + guint global_type); +gpointer wp_remote_pipewire_create_object (WpRemotePipewire *self, + const char *factory_name, guint global_type, gconstpointer props); + G_END_DECLS #endif 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