From 23cc1edc283d051350732ed788733b4755550f02 Mon Sep 17 00:00:00 2001 From: Julian Bouzas <julian.bouzas@collabora.com> Date: Wed, 28 Aug 2019 11:04:14 -0400 Subject: [PATCH] alsa-udev: cleaned module and set media class to Alsa/<direction> --- modules/module-pw-alsa-udev.c | 155 +++++++++++++++++++++++---------- modules/module-simple-policy.c | 10 +-- 2 files changed, 116 insertions(+), 49 deletions(-) diff --git a/modules/module-pw-alsa-udev.c b/modules/module-pw-alsa-udev.c index 48cd8d25..6c499495 100644 --- a/modules/module-pw-alsa-udev.c +++ b/modules/module-pw-alsa-udev.c @@ -11,6 +11,7 @@ * and automatically creates endpoints for all alsa device nodes that appear */ +#include <spa/utils/keys.h> #include <spa/utils/names.h> #include <spa/monitor/monitor.h> #include <pipewire/pipewire.h> @@ -57,7 +58,6 @@ struct node { struct pw_properties *props; struct pw_proxy *proxy; - struct spa_node *node; }; static void @@ -89,6 +89,89 @@ on_endpoint_created(GObject *initable, GAsyncResult *res, gpointer d) endpoint); } +static gboolean +parse_alsa_properties (const struct spa_dict *props, const gchar **name, + const gchar **media_class, enum pw_direction *direction) +{ + const char *local_name = NULL; + const char *local_media_class = NULL; + enum pw_direction local_direction; + + /* Get the name */ + local_name = spa_dict_lookup (props, "node.name"); + if (!local_name) + return FALSE; + + /* Get the media class */ + local_media_class = spa_dict_lookup(props, SPA_KEY_MEDIA_CLASS); + if (!local_media_class) + return FALSE; + + /* Get the direction */ + if (g_str_has_prefix (local_media_class, "Audio/Sink")) + local_direction = PW_DIRECTION_INPUT; + else if (g_str_has_prefix (local_media_class, "Audio/Source")) + local_direction = PW_DIRECTION_OUTPUT; + else + return FALSE; + + /* Set the name */ + if (name) + *name = local_name; + + /* Set the media class */ + if (media_class) { + switch (local_direction) { + case PW_DIRECTION_INPUT: + *media_class = "Alsa/Sink"; + break; + case PW_DIRECTION_OUTPUT: + *media_class = "Alsa/Source"; + break; + default: + break; + } + } + + /* Set the direction */ + if (direction) + *direction = local_direction; + + return TRUE; +} + +/* TODO: we need to find a better way to do this */ +static gboolean +is_alsa_device (const struct spa_dict *props) +{ + const gchar *name = NULL; + const gchar *media_class = NULL; + + /* Get the name */ + name = spa_dict_lookup (props, "node.name"); + if (!name) + return FALSE; + + /* Get the media class */ + media_class = spa_dict_lookup(props, SPA_KEY_MEDIA_CLASS); + if (!media_class) + return FALSE; + + /* Check if it is an audio device */ + if (!g_str_has_prefix (media_class, "Audio/")) + return FALSE; + + /* Check it is not a convert */ + if (g_str_has_prefix (media_class, "Audio/Convert")) + return FALSE; + + /* Check if it is not a bluez device */ + if (g_str_has_prefix (name, "api.bluez5")) + return FALSE; + + return TRUE; +} + static void on_node_added(WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d) { @@ -100,41 +183,22 @@ on_node_added(WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d) GVariantBuilder b; g_autoptr (GVariant) endpoint_props = NULL; - /* Make sure the node has properties */ + /* Only handle alsa nodes */ g_return_if_fail(props); - - /* Get the media_class */ - media_class = spa_dict_lookup(props, "media.class"); - - /* Make sure the media class is non-convert audio */ - if (!g_str_has_prefix (media_class, "Audio/")) - return; - if (g_str_has_prefix (media_class, "Audio/Convert")) - return; - - /* Get the name */ - name = spa_dict_lookup (props, "media.name"); - if (!name) - name = spa_dict_lookup (props, "node.name"); - - /* Don't handle bluetooth nodes */ - if (g_str_has_prefix (name, "api.bluez5")) + if (!is_alsa_device (props)) 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"); + /* Parse the alsa properties */ + if (!parse_alsa_properties (props, &name, &media_class, &direction)) { + g_critical ("failed to parse alsa properties"); 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)); + "name", g_variant_new_take_string ( + g_strdup_printf ("Alsa %u (%s)", id, name))); g_variant_builder_add (&b, "{sv}", "media-class", g_variant_new_string (media_class)); g_variant_builder_add (&b, "{sv}", @@ -172,36 +236,39 @@ create_node(struct impl *impl, struct device *dev, uint32_t id, const struct spa_device_object_info *info) { struct node *node; - const char *str; + const char *name; + struct pw_properties *props = NULL; /* Check if the type is a node */ if (info->type != SPA_TYPE_INTERFACE_Node) return NULL; + /* Get the alsa name */ + name = pw_properties_get(dev->props, SPA_KEY_DEVICE_NICK); + if (name == NULL) + name = pw_properties_get(dev->props, SPA_KEY_DEVICE_NAME); + if (name == NULL) + name = pw_properties_get(dev->props, SPA_KEY_DEVICE_ALIAS); + if (name == NULL) + name = "alsa-device"; + + /* Create the properties */ + props = pw_properties_new_dict(&dev->props->dict); + pw_properties_update(props, info->props); + pw_properties_set(props, PW_KEY_NODE_NAME, name); + pw_properties_set(props, PW_KEY_FACTORY_NAME, info->factory_name); + pw_properties_set(props, "merger.monitor", "1"); + /* Create the node */ node = g_slice_new0(struct node); - - /* Set the node properties */ - node->props = pw_properties_copy(dev->props); - pw_properties_update(node->props, info->props); - str = pw_properties_get(dev->props, SPA_KEY_DEVICE_NICK); - if (str == NULL) - str = pw_properties_get(dev->props, SPA_KEY_DEVICE_NAME); - if (str == NULL) - str = pw_properties_get(dev->props, SPA_KEY_DEVICE_ALIAS); - if (str == NULL) - str = "alsa-device"; - pw_properties_set(node->props, PW_KEY_NODE_NAME, str); - pw_properties_set(node->props, "factory.name", info->factory_name); - pw_properties_set(node->props, "merger.monitor", "1"); - - /* Set the node info */ node->impl = impl; node->device = dev; node->id = id; + node->props = props; node->proxy = wp_remote_pipewire_create_object(impl->remote_pipewire, "adapter", PW_TYPE_INTERFACE_Node, &node->props->dict); if (!node->proxy) { + pw_properties_free(props); g_slice_free (struct node, node); return NULL; } diff --git a/modules/module-simple-policy.c b/modules/module-simple-policy.c index a11ffca9..86f26e67 100644 --- a/modules/module-simple-policy.c +++ b/modules/module-simple-policy.c @@ -136,10 +136,10 @@ select_new_endpoint (WpSimplePolicy *self) if (!self->selected[DIRECTION_SINK]) { direction = DIRECTION_SINK; - media_class = "Audio/Sink"; + media_class = "Alsa/Sink"; } else if (!self->selected[DIRECTION_SOURCE]) { direction = DIRECTION_SOURCE; - media_class = "Audio/Source"; + media_class = "Alsa/Source"; } else return G_SOURCE_REMOVE; @@ -172,8 +172,8 @@ simple_policy_endpoint_added (WpPolicy *policy, WpEndpoint *ep) guint32 control_id; gint direction; - /* we only care about audio device endpoints here */ - if (!g_str_has_prefix (media_class, "Audio/")) + /* we only care about alsa device endpoints here */ + if (!g_str_has_prefix (media_class, "Alsa/")) return; /* verify it has the "selected" control available */ @@ -282,7 +282,7 @@ handle_client (WpPolicy *policy, WpEndpoint *ep) g_variant_dict_init (&d, NULL); g_variant_dict_insert (&d, "action", "s", "link"); g_variant_dict_insert (&d, "media.class", "s", - is_capture ? "Audio/Source" : "Audio/Sink"); + is_capture ? "Alsa/Source" : "Alsa/Sink"); g_object_get (ep, "role", &role, NULL); if (role) -- GitLab