diff --git a/lib/wp/endpoint.c b/lib/wp/endpoint.c index 3816763f3a8c9d768619049fce77010e27e859d8..0c6cce7cfc30297473f0b622e281778df858a9d6 100644 --- a/lib/wp/endpoint.c +++ b/lib/wp/endpoint.c @@ -93,6 +93,7 @@ struct _WpEndpointPrivate { gchar *name; gchar media_class[40]; + guint direction; GPtrArray *streams; GPtrArray *controls; GPtrArray *links; @@ -104,6 +105,7 @@ enum { PROP_CORE, PROP_NAME, PROP_MEDIA_CLASS, + PROP_DIRECTION, }; enum { @@ -211,6 +213,9 @@ wp_endpoint_set_property (GObject * object, guint property_id, strncpy (priv->media_class, g_value_get_string (value), sizeof (priv->media_class) - 1); break; + case PROP_DIRECTION: + priv->direction = g_value_get_uint(value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -234,6 +239,9 @@ wp_endpoint_get_property (GObject * object, guint property_id, GValue * value, case PROP_MEDIA_CLASS: g_value_set_string (value, priv->media_class); break; + case PROP_DIRECTION: + g_value_set_uint (value, priv->direction); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -281,6 +289,15 @@ wp_endpoint_class_init (WpEndpointClass * klass) signals[SIGNAL_NOTIFY_CONTROL_VALUE] = g_signal_new ("notify-control-value", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT); + + /** + * WpEndpoint::direction: + * The direction of the endpoint: input = 0, output = 1. + */ + g_object_class_install_property (object_class, PROP_DIRECTION, + g_param_spec_uint ("direction", "direction", + "The direction of the endpoint", 0, 1, 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); } /** @@ -465,6 +482,17 @@ wp_endpoint_get_media_class (WpEndpoint * self) return priv->media_class; } +guint +wp_endpoint_get_direction (WpEndpoint * self) +{ + WpEndpointPrivate *priv; + + g_return_val_if_fail (WP_IS_ENDPOINT (self), -1); + + priv = wp_endpoint_get_instance_private (self); + return priv->direction; +} + /** * wp_endpoint_register_stream: * @self: the endpoint diff --git a/lib/wp/endpoint.h b/lib/wp/endpoint.h index 2ef688b65ffc55e1c5b7163f8cc97eb519b62c63..b41cc33f72f08afeda3bd0302122c152ab80ff7b 100644 --- a/lib/wp/endpoint.h +++ b/lib/wp/endpoint.h @@ -48,6 +48,7 @@ GPtrArray * wp_endpoint_find (WpCore * core, const gchar * media_class_lookup); WpCore *wp_endpoint_get_core (WpEndpoint * self); const gchar * wp_endpoint_get_name (WpEndpoint * self); const gchar * wp_endpoint_get_media_class (WpEndpoint * self); +guint wp_endpoint_get_direction (WpEndpoint * self); void wp_endpoint_register_stream (WpEndpoint * self, GVariant * stream); GVariant * wp_endpoint_get_stream (WpEndpoint * self, guint32 stream_id); diff --git a/modules/module-pipewire/simple-endpoint.c b/modules/module-pipewire/simple-endpoint.c index e3e825765eddba35031edde2182f1b7bbe17a592..c50a512319ac1cc13795c4ae0cf5d68f9b2118bd 100644 --- a/modules/module-pipewire/simple-endpoint.c +++ b/modules/module-pipewire/simple-endpoint.c @@ -42,9 +42,6 @@ struct _WpPipewireSimpleEndpoint /* Handler */ gulong proxy_node_done_handler_id; - /* Direction */ - enum pw_direction direction; - /* Proxies */ WpProxyNode *proxy_node; struct spa_hook node_proxy_listener; @@ -230,6 +227,7 @@ on_port_added(WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d) static void emit_endpoint_ports(WpPipewireSimpleEndpoint *self) { + enum pw_direction direction = wp_endpoint_get_direction (WP_ENDPOINT (self)); struct pw_node_proxy* node_proxy = NULL; struct spa_audio_info_raw format = { 0, }; struct spa_pod *param; @@ -252,7 +250,7 @@ emit_endpoint_ports(WpPipewireSimpleEndpoint *self) param = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &format); param = spa_pod_builder_add_object(&pod_builder, SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig, - SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(self->direction), + SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction), SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp), SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param)); @@ -323,7 +321,6 @@ wp_simple_endpoint_init_async (GAsyncInitable *initable, int io_priority, { WpPipewireSimpleEndpoint *self = WP_PIPEWIRE_SIMPLE_ENDPOINT (initable); g_autoptr (WpCore) core = wp_endpoint_get_core(WP_ENDPOINT(self)); - const gchar *media_class = wp_endpoint_get_media_class (WP_ENDPOINT (self)); struct pw_node_proxy *node_proxy = NULL; /* Create the async task */ @@ -332,14 +329,6 @@ wp_simple_endpoint_init_async (GAsyncInitable *initable, int io_priority, /* Init the proxies_port array */ self->proxies_port = g_ptr_array_new_full(2, (GDestroyNotify)g_object_unref); - /* Set the direction */ - if (g_str_has_prefix (media_class, "Stream/Input")) - self->direction = PW_DIRECTION_INPUT; - else if (g_str_has_prefix (media_class, "Stream/Output")) - self->direction = PW_DIRECTION_OUTPUT; - else - g_critical ("failed to parse direction"); - /* Register a port_added callback */ self->remote_pipewire = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE); g_return_if_fail(self->remote_pipewire); @@ -579,6 +568,7 @@ simple_endpoint_factory (WpFactory * factory, GType type, { g_autoptr (WpCore) core = NULL; const gchar *name, *media_class; + guint direction; guint global_id; /* Make sure the type is correct */ @@ -593,6 +583,8 @@ simple_endpoint_factory (WpFactory * factory, GType type, return; if (!g_variant_lookup (properties, "media-class", "&s", &media_class)) return; + if (!g_variant_lookup (properties, "direction", "u", &direction)) + return; if (!g_variant_lookup (properties, "global-id", "u", &global_id)) return; @@ -601,6 +593,7 @@ simple_endpoint_factory (WpFactory * factory, GType type, "core", core, "name", name, "media-class", media_class, + "direction", direction, "global-id", global_id, NULL); } diff --git a/modules/module-pw-alsa-udev.c b/modules/module-pw-alsa-udev.c index af474eae4d167c4f37e3cd68a1fcd5e4421959e2..48cd8d25d217ffd9fa46bff549805cfc9bd85b2c 100644 --- a/modules/module-pw-alsa-udev.c +++ b/modules/module-pw-alsa-udev.c @@ -96,6 +96,7 @@ on_node_added(WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d) const struct spa_dict *props = p; g_autoptr (WpCore) core = wp_module_get_core (impl->module); const gchar *media_class, *name; + enum pw_direction direction; GVariantBuilder b; g_autoptr (GVariant) endpoint_props = NULL; @@ -116,12 +117,28 @@ on_node_added(WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d) if (!name) name = spa_dict_lookup (props, "node.name"); + /* Don't handle bluetooth nodes */ + if (g_str_has_prefix (name, "api.bluez5")) + return; + + /* Get the direction */ + if (g_str_has_prefix (media_class, "Audio/Sink")) { + direction = PW_DIRECTION_INPUT; + } else if (g_str_has_prefix (media_class, "Audio/Source")) { + direction = PW_DIRECTION_OUTPUT; + } else { + g_critical ("failed to parse direction"); + return; + } + /* Set the properties */ g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT); g_variant_builder_add (&b, "{sv}", "name", g_variant_new_string (name)); g_variant_builder_add (&b, "{sv}", "media-class", g_variant_new_string (media_class)); + g_variant_builder_add (&b, "{sv}", + "direction", g_variant_new_uint32 (direction)); g_variant_builder_add (&b, "{sv}", "global-id", g_variant_new_uint32 (id)); g_variant_builder_add (&b, "{sv}", diff --git a/modules/module-pw-audio-client.c b/modules/module-pw-audio-client.c index a0dd61fe415d9cf378414f756d9df741e7f5e944..379fe04adddf46b4cc77ee3c44099fea7007ac38 100644 --- a/modules/module-pw-audio-client.c +++ b/modules/module-pw-audio-client.c @@ -57,6 +57,7 @@ on_node_added (WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d) const struct spa_dict *props = p; g_autoptr (WpCore) core = wp_module_get_core (data->module); const gchar *name, *media_class; + enum pw_direction direction; GVariantBuilder b; g_autoptr (GVariant) endpoint_props = NULL; @@ -70,6 +71,16 @@ on_node_added (WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d) if (!g_str_has_prefix (media_class, "Stream/")) return; + /* Get the direction */ + if (g_str_has_prefix (media_class, "Stream/Input")) { + direction = PW_DIRECTION_INPUT; + } else if (g_str_has_prefix (media_class, "Stream/Output")) { + direction = PW_DIRECTION_OUTPUT; + } else { + g_critical ("failed to parse direction"); + return; + } + /* Get the name */ name = spa_dict_lookup (props, "media.name"); if (!name) @@ -83,6 +94,8 @@ on_node_added (WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d) g_variant_new_take_string (g_strdup_printf ("Stream %u", id))); g_variant_builder_add (&b, "{sv}", "media-class", g_variant_new_string (media_class)); + g_variant_builder_add (&b, "{sv}", + "direction", g_variant_new_uint32 (direction)); g_variant_builder_add (&b, "{sv}", "global-id", g_variant_new_uint32 (id)); endpoint_props = g_variant_builder_end (&b); diff --git a/modules/module-pw-audio-softdsp-endpoint.c b/modules/module-pw-audio-softdsp-endpoint.c index 263962a2ae1739912b78db8c9459ba7b2a02b1b9..2d8f1c89d6b5d9bd96d6d8bc745c877168fbd8d1 100644 --- a/modules/module-pw-audio-softdsp-endpoint.c +++ b/modules/module-pw-audio-softdsp-endpoint.c @@ -42,9 +42,6 @@ struct _WpPwAudioSoftdspEndpoint GTask *init_task; gboolean init_abort; - /* Direction */ - enum pw_direction direction; - /* Audio Streams */ WpAudioStream *adapter; GPtrArray *converters; @@ -162,6 +159,7 @@ on_audio_adapter_created(GObject *initable, GAsyncResult *res, gpointer data) { WpPwAudioSoftdspEndpoint *self = data; + enum pw_direction direction = wp_endpoint_get_direction(WP_ENDPOINT(self)); g_autoptr (WpCore) core = wp_endpoint_get_core(WP_ENDPOINT(self)); g_autofree gchar *name = NULL; const struct pw_node_info *adapter_info = NULL; @@ -193,8 +191,8 @@ on_audio_adapter_created(GObject *initable, GAsyncResult *res, /* Create the audio converters */ g_variant_iter_init (&iter, self->streams); for (i = 0; g_variant_iter_next (&iter, "&s", &stream); i++) { - wp_audio_convert_new (WP_ENDPOINT(self), i, stream, self->direction, - adapter_info, on_audio_convert_created, self); + wp_audio_convert_new (WP_ENDPOINT(self), i, stream, direction, adapter_info, + on_audio_convert_created, self); /* Register the stream */ g_variant_dict_init (&d, NULL); @@ -316,24 +314,16 @@ wp_endpoint_init_async (GAsyncInitable *initable, int io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data) { WpPwAudioSoftdspEndpoint *self = WP_PW_AUDIO_SOFTDSP_ENDPOINT (initable); + enum pw_direction direction = wp_endpoint_get_direction(WP_ENDPOINT(self)); 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; /* Create the async task */ self->init_task = g_task_new (initable, cancellable, callback, data); - /* Set the direction */ - if (g_str_has_suffix (media_class, "Source")) - self->direction = PW_DIRECTION_OUTPUT; - else if (g_str_has_suffix (media_class, "Sink")) - self->direction = PW_DIRECTION_INPUT; - else - g_critical ("failed to parse direction"); - /* Create the adapter proxy */ wp_audio_adapter_new (WP_ENDPOINT(self), WP_STREAM_ID_NONE, "master", - self->direction, self->global_id, FALSE, on_audio_adapter_created, self); + direction, self->global_id, FALSE, on_audio_adapter_created, self); /* Register the selected control */ self->selected = FALSE; @@ -401,6 +391,7 @@ endpoint_factory (WpFactory * factory, GType type, GVariant * properties, { g_autoptr (WpCore) core = NULL; const gchar *name, *media_class; + guint direction; guint global_id; g_autoptr (GVariant) streams = NULL; @@ -416,6 +407,8 @@ endpoint_factory (WpFactory * factory, GType type, GVariant * properties, return; if (!g_variant_lookup (properties, "media-class", "&s", &media_class)) return; + if (!g_variant_lookup (properties, "direction", "u", &direction)) + return; if (!g_variant_lookup (properties, "global-id", "u", &global_id)) return; if (!(streams = g_variant_lookup_value (properties, "streams", @@ -428,6 +421,7 @@ endpoint_factory (WpFactory * factory, GType type, GVariant * properties, "core", core, "name", name, "media-class", media_class, + "direction", direction, "global-id", global_id, "streams", streams, NULL); diff --git a/modules/module-pw-audio-softdsp-endpoint/adapter.c b/modules/module-pw-audio-softdsp-endpoint/adapter.c index 14aee5c0e9d9d734989b87ad3700c53f17ff239a..efb8ed6e884d7a5f4f65b584ebf5fa6dd9a98f24 100644 --- a/modules/module-pw-audio-softdsp-endpoint/adapter.c +++ b/modules/module-pw-audio-softdsp-endpoint/adapter.c @@ -26,6 +26,7 @@ struct _WpAudioAdapter /* The task to signal the proxy is initialized */ GTask *init_task; gboolean init_abort; + gboolean ports_done; /* Props */ guint adapter_id; @@ -79,9 +80,45 @@ on_audio_adapter_done(WpProxy *proxy, gpointer data) { WpAudioAdapter *self = data; + /* Emit the ports if not done and sync again */ + if (!self->ports_done) { + enum pw_direction direction = + wp_audio_stream_get_direction ( WP_AUDIO_STREAM (self)); + struct pw_node_proxy *pw_proxy = NULL; + uint8_t buf[1024]; + struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); + struct spa_pod *param; + + /* Emit the props param */ + pw_proxy = wp_proxy_get_pw_proxy(WP_PROXY(self->proxy)); + pw_node_proxy_enum_params (pw_proxy, 0, SPA_PARAM_Props, 0, -1, NULL); + + /* Emit the ports */ + if (self->convert) { + param = spa_pod_builder_add_object(&pod_builder, + SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig, + SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction), + SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_convert)); + } else { + struct spa_audio_info_raw format = *wp_proxy_node_get_format (self->proxy); + param = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &format); + param = spa_pod_builder_add_object(&pod_builder, + SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig, + SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction), + SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp), + SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param)); + } + pw_node_proxy_set_param(pw_proxy, SPA_PARAM_PortConfig, 0, param); + + /* Sync */ + self->ports_done = TRUE; + wp_proxy_sync (WP_PROXY(self->proxy)); + return; + } + /* Don't do anything if the audio adapter has already been initialized */ if (!self->init_task) - return; + return; /* Finish the creation of the audio adapter */ g_task_return_boolean (self->init_task, TRUE); @@ -93,12 +130,6 @@ on_audio_adapter_proxy_created(GObject *initable, GAsyncResult *res, gpointer data) { WpAudioAdapter *self = data; - enum pw_direction direction = - wp_audio_stream_get_direction ( WP_AUDIO_STREAM (self)); - struct pw_node_proxy *pw_proxy = NULL; - uint8_t buf[1024]; - struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); - struct spa_pod *param; /* Get the adapter proxy */ self->proxy = WP_PROXY_NODE (object_safe_new_finish (self, initable, @@ -106,39 +137,10 @@ on_audio_adapter_proxy_created(GObject *initable, GAsyncResult *res, if (!self->proxy) return; - /* Get the pipewire proxy */ - pw_proxy = wp_proxy_get_pw_proxy(WP_PROXY(self->proxy)); - g_return_if_fail (pw_proxy); - - /* Emit the props param */ - pw_node_proxy_enum_params (pw_proxy, 0, SPA_PARAM_Props, 0, -1, NULL); - - /* Emit the ports */ - if (self->convert) { - param = spa_pod_builder_add_object(&pod_builder, - SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig, - SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction), - SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_convert)); - pw_node_proxy_set_param(pw_proxy, SPA_PARAM_PortConfig, 0, param); - } else { - struct spa_audio_info_raw format; - spa_zero(format); - format.format = SPA_AUDIO_FORMAT_F32P; - format.flags = 1; - format.rate = 48000; - format.channels = 2; - format.position[0] = SPA_AUDIO_CHANNEL_FL; - format.position[1] = SPA_AUDIO_CHANNEL_FR; - param = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &format); - param = spa_pod_builder_add_object(&pod_builder, - SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig, - SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction), - SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp), - SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param)); - pw_node_proxy_set_param(pw_proxy, SPA_PARAM_PortConfig, 0, param); - } + /* Emit the EnumFormat param */ + wp_proxy_node_enum_params (self->proxy, 0, SPA_PARAM_EnumFormat, 0, -1, NULL); - /* Register a callback to know when all the adapter ports have been emitted */ + /* Register the done callback */ g_signal_connect_object(self->proxy, "done", (GCallback)on_audio_adapter_done, self, 0); wp_proxy_sync (WP_PROXY(self->proxy)); @@ -248,6 +250,7 @@ static void wp_audio_adapter_init (WpAudioAdapter * self) { self->init_abort = FALSE; + self->ports_done = FALSE; } static void diff --git a/modules/module-pw-bluez.c b/modules/module-pw-bluez.c index 5bca9697b08e0ecc1a795eb9c4d3fd3d6f9ff033..6b3bf526a7775aec038dc048590dfa93e34894a7 100644 --- a/modules/module-pw-bluez.c +++ b/modules/module-pw-bluez.c @@ -25,6 +25,7 @@ struct monitor { struct impl { WpModule *module; WpRemotePipewire *remote_pipewire; + GHashTable *registered_endpoints; /* The bluez monitor */ struct monitor monitor; @@ -57,6 +58,107 @@ struct node { struct pw_proxy *proxy; }; +static void +on_endpoint_created(GObject *initable, GAsyncResult *res, gpointer d) +{ + struct impl *data = d; + WpEndpoint *endpoint = NULL; + guint global_id = 0; + GError *error = NULL; + + /* Get the endpoint */ + endpoint = wp_endpoint_new_finish(initable, res, NULL); + g_return_if_fail (endpoint); + + /* Check for error */ + if (error) { + g_clear_object (&endpoint); + g_warning ("Failed to create client endpoint: %s", error->message); + return; + } + + /* Get the endpoint global id */ + g_object_get (endpoint, "global-id", &global_id, NULL); + g_debug ("Created bluetooth endpoint for global id %d", global_id); + + /* Register the endpoint and add it to the table */ + wp_endpoint_register (endpoint); + g_hash_table_insert (data->registered_endpoints, GUINT_TO_POINTER(global_id), + endpoint); +} + +static void +on_node_added (WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d) +{ + struct impl *data = d; + const struct spa_dict *props = p; + g_autoptr (WpCore) core = wp_module_get_core (data->module); + const gchar *name, *media_class; + enum pw_direction direction; + GVariantBuilder b; + g_autoptr (GVariant) endpoint_props = NULL; + + /* Make sure the node has properties */ + g_return_if_fail(props); + + /* Get the media_class */ + media_class = spa_dict_lookup(props, "media.class"); + + /* Get the name */ + name = spa_dict_lookup (props, "media.name"); + if (!name) + name = spa_dict_lookup (props, "node.name"); + + /* Only handle bluetooth nodes */ + if (!g_str_has_prefix (name, "api.bluez5")) + return; + + /* Get the direction */ + if (g_str_has_prefix (media_class, "Audio/Sink")) { + direction = PW_DIRECTION_INPUT; + } else if (g_str_has_prefix (media_class, "Audio/Source")) { + direction = PW_DIRECTION_OUTPUT; + } else { + g_critical ("failed to parse direction"); + return; + } + + /* Set the properties */ + g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&b, "{sv}", + "name", name ? + g_variant_new_take_string (g_strdup_printf ("Stream %u (%s)", id, name)) : + g_variant_new_take_string (g_strdup_printf ("Stream %u", id))); + g_variant_builder_add (&b, "{sv}", + "media-class", g_variant_new_string (media_class)); + g_variant_builder_add (&b, "{sv}", + "direction", g_variant_new_uint32 (direction)); + g_variant_builder_add (&b, "{sv}", + "global-id", g_variant_new_uint32 (id)); + endpoint_props = g_variant_builder_end (&b); + + /* Create the endpoint async */ + wp_factory_make (core, "pipewire-simple-endpoint", WP_TYPE_ENDPOINT, + endpoint_props, on_endpoint_created, data); +} + +static void +on_global_removed (WpRemotePipewire *rp, guint id, gpointer d) +{ + struct impl *data = d; + WpEndpoint *endpoint = NULL; + + /* Get the endpoint */ + endpoint = g_hash_table_lookup (data->registered_endpoints, + GUINT_TO_POINTER(id)); + if (!endpoint) + return; + + /* Unregister the endpoint and remove it from the table */ + wp_endpoint_unregister (endpoint); + g_hash_table_remove (data->registered_endpoints, GUINT_TO_POINTER(id)); +} + static struct node * create_node(struct impl *impl, struct device *dev, uint32_t id, const struct spa_device_object_info *info) @@ -343,6 +445,10 @@ module_destroy (gpointer data) impl->module = NULL; impl->remote_pipewire = NULL; + /* Destroy the registered endpoints table */ + g_hash_table_unref(impl->registered_endpoints); + impl->registered_endpoints = NULL; + /* Clean up */ g_slice_free (struct impl, impl); } @@ -365,6 +471,8 @@ wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args) impl = g_slice_new0(struct impl); impl->module = module; impl->remote_pipewire = rp; + impl->registered_endpoints = g_hash_table_new_full (g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify)g_object_unref); /* Set destroy callback for impl */ wp_module_set_destroy_callback (module, module_destroy, impl); @@ -374,4 +482,8 @@ wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args) /* Start the monitor when the connected callback is triggered */ g_signal_connect(rp, "state-changed::connected", (GCallback)start_monitor, impl); + + /* Register the global added/removed callbacks */ + g_signal_connect(rp, "global-added::node", (GCallback)on_node_added, impl); + g_signal_connect(rp, "global-removed", (GCallback)on_global_removed, impl); }