]> git.alsa-project.org Git - alsa-gobject.git/commitdiff
ctl: add global method to get list of available sound cards
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Mon, 18 Nov 2019 04:22:44 +0000 (13:22 +0900)
committerTakashi Sakamoto <o-takashi@sakamocchi.jp>
Sat, 30 Nov 2019 08:58:41 +0000 (17:58 +0900)
src/ctl/alsactl.map
src/ctl/query.c
src/ctl/query.h

index 4863f838e1a4a210348e0cda22730e28f8c23eec..523c0193b6d498a1803053f6d2aecb4c371cd865 100644 (file)
@@ -5,6 +5,8 @@ ALSA_GOBJECT_0_0_0 {
     "alsactl_elem_access_flag_get_type";
     "alsactl_event_type_get_type";
     "alsactl_event_mask_flag_get_type";
+
+    "alsactl_get_card_id_list";
   local:
     *;
 };
index 5bd80812885882e8db8a0e3b2e82bf2b336bf58f..0a83447139f3bd6224ee17e87f01fb89451a8ebd 100644 (file)
@@ -2,5 +2,170 @@
 #include "query.h"
 #include "privates.h"
 
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <libudev.h>
+
 // For error handling.
 G_DEFINE_QUARK("alsactl-error", alsactl_error)
+
+static void prepare_udev_enum(struct udev_enumerate **enumerator,
+                              GError **error)
+{
+    struct udev *ctx;
+    int err;
+
+    ctx = udev_new();
+    if (ctx == NULL) {
+        generate_error(error, errno);
+        return;
+    }
+
+    *enumerator = udev_enumerate_new(ctx);
+    if (*enumerator == NULL) {
+        generate_error(error, errno);
+        udev_unref(ctx);
+        return;
+    }
+
+    err = udev_enumerate_add_match_subsystem(*enumerator, "sound");
+    if (err < 0) {
+        generate_error(error, -err);
+        udev_enumerate_unref(*enumerator);
+        udev_unref(ctx);
+        return;
+    }
+
+    err = udev_enumerate_scan_devices(*enumerator);
+    if (err < 0) {
+        generate_error(error, -err);
+        udev_enumerate_unref(*enumerator);
+        udev_unref(ctx);
+    }
+}
+
+static struct udev_device *detect_dev(struct udev_enumerate *enumerator,
+                                      struct udev_list_entry *entry,
+                                      const char *prefix)
+{
+    struct udev *ctx = udev_enumerate_get_udev(enumerator);
+    const char *syspath;
+    struct udev_device *dev;
+    const char *sysname;
+
+    syspath = udev_list_entry_get_name(entry);
+    if (syspath == NULL)
+        return NULL;
+
+    dev = udev_device_new_from_syspath(ctx, syspath);
+    if (dev == NULL)
+        return NULL;
+
+    sysname = udev_device_get_sysname(dev);
+    if (sysname == NULL) {
+        udev_device_unref(dev);
+        return NULL;
+    }
+
+    if (strstr(sysname, prefix) != sysname) {
+        udev_device_unref(dev);
+        return NULL;
+    }
+
+    return dev;
+}
+
+static void release_udev_enum(struct udev_enumerate *enumerator)
+{
+    struct udev *ctx = udev_enumerate_get_udev(enumerator);
+
+    udev_enumerate_unref(enumerator);
+    udev_unref(ctx);
+}
+
+static int compare_guint(const void *l, const void *r)
+{
+    const guint *x = l;
+    const guint *y = r;
+
+    return *x > *y;
+}
+
+/**
+ * alsactl_get_card_id_list:
+ * @entries: (array length=entry_count)(out): The list of numerical ID for sound
+ *           cards.
+ * @entry_count: The number of entries.
+ * @error: A #GError.
+ *
+ * Get the list of numerical ID for available sound cards.
+ */
+void alsactl_get_card_id_list(guint **entries, gsize *entry_count,
+                              GError **error)
+{
+    struct udev_enumerate *enumerator;
+    struct udev_list_entry *entry, *entry_list;
+    unsigned int count;
+    unsigned int index;
+
+    if (entries == NULL || entry_count == NULL || error == NULL) {
+        generate_error(error, EINVAL);
+        return;
+    }
+
+    prepare_udev_enum(&enumerator, error);
+    if (enumerator == NULL)
+        return;
+
+    entry_list = udev_enumerate_get_list_entry(enumerator);
+
+    count = 0;
+    udev_list_entry_foreach(entry, entry_list) {
+        struct udev_device *dev = detect_dev(enumerator, entry, "card");
+        if (dev != NULL) {
+            ++count;
+            udev_device_unref(dev);
+        }
+    }
+
+    // Nothing available.
+    if (count == 0)
+        goto end;
+
+    *entries = g_try_malloc0_n(count, sizeof(**entries));
+    if (*entries == NULL) {
+        generate_error(error, ENOMEM);
+        goto end;
+    }
+
+    index = 0;
+    udev_list_entry_foreach(entry, entry_list) {
+        struct udev_device *dev = detect_dev(enumerator, entry, "card");
+        if (dev != NULL) {
+            const char *sysnum = udev_device_get_sysnum(dev);
+            long val;
+            char *endptr;
+
+            errno = 0;
+            val = strtol(sysnum, &endptr, 10);
+            if (errno == 0 && *endptr == '\0' && val >= 0) {
+                (*entries)[index] = (guint)val;
+                ++index;
+            }
+            udev_device_unref(dev);
+        }
+    }
+    if (index != count) {
+        generate_error(error, ENOENT);
+        g_free(*entries);
+        *entries = NULL;
+        goto end;
+    }
+    *entry_count = count;
+
+    qsort(*entries, count, sizeof(guint), compare_guint);
+end:
+    release_udev_enum(enumerator);
+}
index 7e19ef8e3eb831e61bcebdcf0a11a940e106827f..62135ba85565239c6ceb6d4ce6b65569433eb097 100644 (file)
@@ -7,6 +7,9 @@
 
 G_BEGIN_DECLS
 
+void alsactl_get_card_id_list(guint **entries, gsize *entry_count,
+                              GError **error);
+
 G_END_DECLS
 
 #endif