]> git.alsa-project.org Git - alsa-gobject.git/commitdiff
hwdep: add global method to get list of hwdep devices in sound card
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Wed, 27 Nov 2019 06:23:04 +0000 (15:23 +0900)
committer坂本 貴史 <o-takashi@sakamocchi.jp>
Wed, 8 Apr 2020 01:40:25 +0000 (10:40 +0900)
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
src/hwdep/alsahwdep.map
src/hwdep/query.c
src/hwdep/query.h

index a1e36915c28062a83edcb3a6a345e4a0b30f5333..779c754e20541bf816589e029e7ec49f056bef27 100644 (file)
@@ -1,6 +1,8 @@
 ALSA_GOBJECT_0_0_0 {
   global:
     "alsahwdep_iface_type_get_type";
+
+    "alsahwdep_get_device_id_list";
   local:
     *;
 };
index 7b968fcc5e81f090f116b9e871c1a75cfc1e52d0..93357e43c7a55b6372fcbbef1bddd26ba7de54dc 100644 (file)
@@ -1,5 +1,201 @@
 // SPDX-License-Identifier: LGPL-3.0-or-later
 #include "query.h"
+#include "privates.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <libudev.h>
 
 // For error handling.
 G_DEFINE_QUARK("alsahwdep-error", alsahwdep_error)
+
+// 'C' is required apart from emulation of Open Sound System.
+#define PREFIX_SYSNAME_TEMPLATE     "hwC%u"
+
+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;
+}
+
+static unsigned int calculate_digits(unsigned int number)
+{
+    unsigned int digits;
+
+    while (true) {
+        number /= 10;
+        ++digits;
+        if (number == 0)
+            break;
+    }
+
+    return digits;
+}
+
+/**
+ * alsahwdep_get_device_id_list:
+ * @card_id: The numerical ID of sound card.
+ * @entries: (array length=entry_count)(out): The list of numerical ID for
+ *           hwdep device.
+ * @entry_count: The number of entries.
+ * @error: A #GError.
+ *
+ * Get the list of numerical ID for available hwdep devices of sound card.
+ */
+void alsahwdep_get_device_id_list(guint card_id, guint **entries,
+                                  gsize *entry_count, GError **error)
+{
+    struct udev_enumerate *enumerator;
+    unsigned int length;
+    char *prefix;
+    struct udev_list_entry *entry, *entry_list;
+    unsigned int count;
+    unsigned int index;
+
+    g_return_if_fail(entries != NULL);
+    g_return_if_fail(entry_count != NULL);
+
+    prepare_udev_enum(&enumerator, error);
+    if (*error != NULL)
+        goto end;
+
+    length = strlen(PREFIX_SYSNAME_TEMPLATE) + calculate_digits(card_id) + 1;
+    prefix = g_try_malloc0(length);
+    if (prefix == NULL) {
+        generate_error(error, ENOMEM);
+        goto end;
+    }
+    snprintf(prefix, length, PREFIX_SYSNAME_TEMPLATE, card_id);
+
+    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, prefix);
+        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, prefix);
+        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:
+    g_free(prefix);
+    release_udev_enum(enumerator);
+}
index 03876a1353bca93265e9d80c8fb229580ff5a832..4cee162a9af6e078befcc07304ec3926b4b9692b 100644 (file)
@@ -7,6 +7,9 @@
 
 G_BEGIN_DECLS
 
+void alsahwdep_get_device_id_list(guint card_id, guint **entries,
+                                  gsize *entry_count, GError **error);
+
 G_END_DECLS
 
 #endif