From: Takashi Sakamoto Date: Mon, 18 Nov 2019 04:22:44 +0000 (+0900) Subject: rawmidi; add global method to get list of rawmidi device for sound card X-Git-Tag: v0.1.0~191 X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=cb128c5b59e0e0e1b82ca6b740eb6ddbbf152b9a;p=alsa-gobject.git rawmidi; add global method to get list of rawmidi device for sound card Signed-off-by: Takashi Sakamoto --- diff --git a/src/rawmidi/alsarawmidi.map b/src/rawmidi/alsarawmidi.map index 21014af..589359a 100644 --- a/src/rawmidi/alsarawmidi.map +++ b/src/rawmidi/alsarawmidi.map @@ -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: *; }; diff --git a/src/rawmidi/query.c b/src/rawmidi/query.c index 82457b4..1f1371a 100644 --- a/src/rawmidi/query.c +++ b/src/rawmidi/query.c @@ -1,5 +1,197 @@ // SPDX-License-Identifier: LGPL-3.0-or-later +#include "query.h" #include "privates.h" +#include +#include +#include + +#include + // 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); +} diff --git a/src/rawmidi/query.h b/src/rawmidi/query.h index fc26827..bb7e5b2 100644 --- a/src/rawmidi/query.h +++ b/src/rawmidi/query.h @@ -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