]> git.alsa-project.org Git - alsa-gobject.git/commitdiff
rawmidi; add global method to get list of rawmidi device for sound card
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Mon, 18 Nov 2019 04:22:44 +0000 (13:22 +0900)
committer坂本 貴史 <o-takashi@sakamocchi.jp>
Sun, 12 Apr 2020 05:30:33 +0000 (14:30 +0900)
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
src/rawmidi/alsarawmidi.map
src/rawmidi/query.c
src/rawmidi/query.h

index 21014afb22d77c256c9877a42992e317b0f27fc1..589359aa82dee3f50f8e027a453aabcb9a7c2bd0 100644 (file)
@@ -2,6 +2,8 @@ ALSA_GOBJECT_0_0_0 {
   global:
     "alsarawmidi_stream_direction_get_type";
     "alsarawmidi_stream_pair_info_flag_get_type";
+
+    "alsarawmidi_get_device_id_list";
   local:
     *;
 };
index 82457b4486443a802bd1cb71fe0eb28c494a7779..1f1371a2ef0d64e3d42e0151f5cc729c211bfc82 100644 (file)
@@ -1,5 +1,197 @@
 // SPDX-License-Identifier: LGPL-3.0-or-later
+#include "query.h"
 #include "privates.h"
 
+#include <stdio.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <libudev.h>
+
 // For error reporting.
 G_DEFINE_QUARK("alsarawmidi-error", alsarawmidi_error)
+
+// 'C' is required apart from emulation of Open Sound System.
+#define PREFIX_SYSNAME_TEMPLATE     "midiC%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;
+}
+
+/**
+ * alsarawmidi_get_device_id_list:
+ * @card_id: The numerical ID of sound card.
+ * @entries: (array length=entry_count)(out): The list of numerical ID for
+ *           rawmidi device.
+ * @entry_count: The number of entries.
+ * @error: A #GError.
+ *
+ * Get the list of numerical ID for available rawmidi devices of sound card.
+ */
+void alsarawmidi_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 fc26827c9b73f3b2c32d8e27e68463fc72ee06e8..bb7e5b2f62a1e5e521881532915df1d838e285a3 100644 (file)
@@ -7,6 +7,10 @@
 
 G_BEGIN_DECLS
 
+void alsarawmidi_get_device_id_list(guint card_id,
+                                    guint **entries, gsize *entry_count,
+                                    GError **error);
+
 G_END_DECLS
 
 #endif