diff --git a/lib/wp/factory.c b/lib/wp/factory.c index f8c71d468731d90d94b05d57375954943b99b05b..7292166379d3fad564ce2e40752851e0ad193f07 100644 --- a/lib/wp/factory.c +++ b/lib/wp/factory.c @@ -46,7 +46,7 @@ wp_factory_class_init (WpFactoryClass * klass) WpFactory * wp_factory_new (WpCore * core, const gchar * name, WpFactoryFunc func) { - g_autoptr (WpFactory) f = NULL; + WpFactory *f = NULL; g_return_val_if_fail (name != NULL && *name != '\0', NULL); g_return_val_if_fail (func != NULL, NULL); diff --git a/modules/module-pipewire/simple-endpoint-link.c b/modules/module-pipewire/simple-endpoint-link.c index 93dc160a79a4841aaf35ece03fb6048268b2c3c6..2b9d075846feebee84b3617ff39ec7bd43edb523 100644 --- a/modules/module-pipewire/simple-endpoint-link.c +++ b/modules/module-pipewire/simple-endpoint-link.c @@ -44,6 +44,8 @@ simple_endpoint_link_create (WpEndpointLink * self, GVariant * src_data, GVariant * sink_data, GError ** error) { /* TODO create pw_links based on the nodes & ports described in src/sink_data */ + + return TRUE; } static void diff --git a/modules/module-pipewire/simple-endpoint.c b/modules/module-pipewire/simple-endpoint.c index 61439cdbc6d92c59b75a8624f4d2a0fbe67d0eae..52ce5d4c0a482a365a3271692939a596937ed919 100644 --- a/modules/module-pipewire/simple-endpoint.c +++ b/modules/module-pipewire/simple-endpoint.c @@ -95,6 +95,8 @@ simple_endpoint_prepare_link (WpEndpoint * self, guint32 stream_id, { /* TODO: verify that the remote end supports the same media type */ /* TODO: fill @properties with (node id, array(port ids)) */ + + return TRUE; } static void diff --git a/modules/module-pw-alsa-udev.c b/modules/module-pw-alsa-udev.c index 156882d5f5e8aae681f1102344ad36299534696e..6875a8237d1d1d4ada5cc9af62844771bc4ec7bb 100644 --- a/modules/module-pw-alsa-udev.c +++ b/modules/module-pw-alsa-udev.c @@ -14,7 +14,143 @@ #include <wp/wp.h> #include <pipewire/pipewire.h> +#define NAME "module-pw-alsa-udev" + +struct impl { + WpCore *wp_core; + + struct pw_remote *remote; + struct spa_hook remote_listener; + + struct pw_registry_proxy *registry_proxy; + struct spa_hook registry_listener; +}; + +static void +handle_node(struct impl *impl, uint32_t id, uint32_t parent_id, + const struct spa_dict *props) +{ + const gchar *media_class = NULL, *node_name = NULL; + struct spa_proxy *proxy = NULL; + GVariantBuilder b; + g_autoptr(GVariant) endpoint_props = NULL; + + /* Make sure the node has properties */ + if (!props) { + g_warning(NAME" %p: node has no properties, skipping...", impl); + return; + } + + /* Make sure the media class is audio */ + /* FIXME: need to handle only alsa nodes */ + media_class = spa_dict_lookup(props, "media.class"); + if (!g_str_has_prefix (media_class, "Audio/")) + return; + + /* Get the device name */ + node_name = spa_dict_lookup(props, "node.name"); + + /* Get the proxy */ + proxy = pw_registry_proxy_bind (impl->registry_proxy, id, + PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, 0); + + /* Build the GVariant properties for the endpoint */ + g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&b, "{sv}", "name", + g_variant_new_take_string (g_strdup_printf ("Endpoint %u: %s", id, node_name))); + g_variant_builder_add (&b, "{sv}", + "media-class", g_variant_new_string (media_class)); + g_variant_builder_add (&b, "{sv}", + "node-proxy", g_variant_new_uint64 ((guint64) proxy)); + endpoint_props = g_variant_builder_end (&b); + + /* Create the endpoint */ + wp_factory_make (impl->wp_core, "pw-audio-softdsp-endpoint", WP_TYPE_ENDPOINT, + endpoint_props); +} + +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; + + /* Only handle nodes */ + switch (type) { + case PW_TYPE_INTERFACE_Node: + handle_node(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_state_changed(void *_data, enum pw_remote_state old, + enum pw_remote_state state, const char *error) +{ + struct impl *impl = _data; + struct pw_core_proxy *core_proxy; + + switch (state) { + case PW_REMOTE_STATE_CONNECTED: + core_proxy = pw_remote_get_core_proxy (impl->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); + break; + + case PW_REMOTE_STATE_ERROR: + /* TODO quit wireplumber */ + break; + + case PW_REMOTE_STATE_UNCONNECTED: + /* TODO quit wireplumber */ + break; + + default: + break; + } +} + +static const struct pw_remote_events remote_events = { + PW_VERSION_REMOTE_EVENTS, + .state_changed = on_state_changed, +}; + +static void +module_destroy (gpointer data) +{ + struct impl *impl = data; + + g_debug ("module-pipewire destroy"); + + g_slice_free (struct impl, impl); +} + void wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args) { + /* This needs to create the alsa sink and alsa source nodes, but since + * this is already implemented in the alsa-module of pipewire, for now + * we just listen for the alsa nodes created by pipewire. We eventually + * need to move all the node creation logic here */ + + /* Create the impl */ + struct impl *impl = g_new0(struct impl, 1); + impl->wp_core = core; + impl->remote = wp_core_get_global(core, WP_GLOBAL_PW_REMOTE); + + /* Set destroy callback for impl */ + wp_module_set_destroy_callback (module, module_destroy, impl); + + /* Add a state changed listener */ + pw_remote_add_listener(impl->remote, &impl->remote_listener, &remote_events, impl); } diff --git a/modules/module-pw-audio-softdsp-endpoint.c b/modules/module-pw-audio-softdsp-endpoint.c index b2534c0a7c60ab2ec0cc38dbfe6c4267a95e3ebf..802b7a5d601a689034e54e7b15ecdf0160b1eab7 100644 --- a/modules/module-pw-audio-softdsp-endpoint.c +++ b/modules/module-pw-audio-softdsp-endpoint.c @@ -35,6 +35,7 @@ static gboolean endpoint_prepare_link (WpEndpoint * self, guint32 stream_id, WpEndpointLink * link, GVariant ** properties, GError ** error) { + return TRUE; } static void @@ -48,13 +49,22 @@ endpoint_class_init (WpPwAudioSoftdspEndpointClass * klass) static gpointer endpoint_factory (WpFactory * factory, GType type, GVariant * properties) { + const gchar *name = NULL; + const gchar *media_class = NULL; + if (type != WP_TYPE_ENDPOINT) return NULL; - /* TODO: retrieve pw_node* from @properties and keep it - * TODO: populate media_class and name on the endpoint - */ - return g_object_new (endpoint_get_type (), NULL); + /* Get the name and media-class */ + if (!g_variant_lookup (properties, "name", "&s", &name)) + return NULL; + if (!g_variant_lookup (properties, "media-class", "&s", &media_class)) + return NULL; + + return g_object_new (endpoint_get_type (), + "name", name, + "media-class", media_class, + NULL); } void