From: Takashi Sakamoto Date: Mon, 18 Nov 2019 04:22:44 +0000 (+0900) Subject: ctl: add global method to get list of available sound cards X-Git-Tag: v0.1.0~428 X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=d1936fbbe7e296aa249b886428dcb45951342a1e;p=alsa-gobject.git ctl: add global method to get list of available sound cards --- diff --git a/src/ctl/alsactl.map b/src/ctl/alsactl.map index 4863f83..523c019 100644 --- a/src/ctl/alsactl.map +++ b/src/ctl/alsactl.map @@ -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: *; }; diff --git a/src/ctl/query.c b/src/ctl/query.c index 5bd8081..0a83447 100644 --- a/src/ctl/query.c +++ b/src/ctl/query.c @@ -2,5 +2,170 @@ #include "query.h" #include "privates.h" +#include +#include +#include + +#include + // 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); +} diff --git a/src/ctl/query.h b/src/ctl/query.h index 7e19ef8..62135ba 100644 --- a/src/ctl/query.h +++ b/src/ctl/query.h @@ -7,6 +7,9 @@ G_BEGIN_DECLS +void alsactl_get_card_id_list(guint **entries, gsize *entry_count, + GError **error); + G_END_DECLS #endif