rendered paste body#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <alsa/asoundlib.h>
#define error(a, b...) do{ \
char __tmp__[255]; \
snprintf(__tmp__, 255, a, ##b); \
fprintf(stderr, "%s:%s:%i ERROR: %s\n", __FILE__, __FUNCTION__, __LINE__, __tmp__); \
fflush(stderr); \
}while(0)
#define debug(a, b...) do{ \
char __tmp__[255]; \
snprintf(__tmp__, 255, a, ##b); \
printf("%s\n", __tmp__); \
}while(0)
char *id_str(snd_ctl_elem_id_t *id)
{
static char str[128];
assert(id);
sprintf(str, "%i,%i,%i,%s,%i",
snd_ctl_elem_id_get_interface(id),
snd_ctl_elem_id_get_device(id),
snd_ctl_elem_id_get_subdevice(id),
snd_ctl_elem_id_get_name(id),
snd_ctl_elem_id_get_index(id));
return str;
}
char *num_str(long n)
{
static char str[32];
sprintf(str, "%ld", n);
return str;
}
static int get_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id)
{
snd_ctl_elem_value_t *ctl;
snd_ctl_elem_info_t *info;
const char *s;
char buf[256];
unsigned int idx;
int err;
unsigned int device, subdevice, index;
const char *name;
snd_ctl_elem_type_t type;
unsigned int count;
snd_ctl_elem_value_alloca(&ctl);
snd_ctl_elem_info_alloca(&info);
snd_ctl_elem_info_set_id(info, id);
err = snd_ctl_elem_info(handle, info);
if (err < 0) {
error("Cannot read control info '%s': %s", id_str(id), snd_strerror(err));
return err;
}
if (!snd_ctl_elem_info_is_readable(info))
return 0;
snd_ctl_elem_value_set_id(ctl, id);
err = snd_ctl_elem_read(handle, ctl);
if (err < 0) {
error("Cannot read control '%s': %s", id_str(id), snd_strerror(err));
return err;
}
buf[0] = '\0';
buf[1] = '\0';
if (snd_ctl_elem_info_is_readable(info))
strcat(buf, " read");
if (snd_ctl_elem_info_is_writable(info))
strcat(buf, " write");
if (snd_ctl_elem_info_is_inactive(info))
strcat(buf, " inactive");
if (snd_ctl_elem_info_is_volatile(info))
strcat(buf, " volatile");
if (snd_ctl_elem_info_is_locked(info))
strcat(buf, " locked");
type = snd_ctl_elem_info_get_type(info);
device = snd_ctl_elem_info_get_device(info);
subdevice = snd_ctl_elem_info_get_subdevice(info);
index = snd_ctl_elem_info_get_index(info);
name = snd_ctl_elem_info_get_name(info);
count = snd_ctl_elem_info_get_count(info);
s = snd_ctl_elem_type_name(type);
s = snd_ctl_elem_iface_name(snd_ctl_elem_info_get_interface(info));
debug("iface: %s", s);
if (device != 0) {
debug("device: %i", device);
}
if (subdevice != 0) {
debug("subdevice: %i", subdevice);
}
debug("name: %s", name);
if (index != 0) {
debug("index: %i", index);
}
switch (type) {
case SND_CTL_ELEM_TYPE_BOOLEAN:
break;
case SND_CTL_ELEM_TYPE_INTEGER: {
long min = snd_ctl_elem_info_get_min(info);
long max = snd_ctl_elem_info_get_max(info);
long step = snd_ctl_elem_info_get_step(info);
if (step)
debug("%li - %li (step %li)", min, max, step);
else
debug("%li - %li", min, max);
break;
}
case SND_CTL_ELEM_TYPE_INTEGER64: {
long long min = snd_ctl_elem_info_get_min64(info);
long long max = snd_ctl_elem_info_get_max64(info);
long long step = snd_ctl_elem_info_get_step64(info);
if (step)
debug("%Li - %Li (step %Li)", min, max, step);
else
debug("%Li - %Li", min, max);
break;
}
case SND_CTL_ELEM_TYPE_ENUMERATED: {
unsigned int items;
char tmp[256];
items = snd_ctl_elem_info_get_items(info);
for (idx = 0; idx < items; idx++) {
snd_ctl_elem_info_set_item(info, idx);
err = snd_ctl_elem_info(handle, info);
if (err < 0) {
error("snd_ctl_card_info: %s", snd_strerror(err));
return err;
}
debug("\t%s, %s", num_str(idx), snd_ctl_elem_info_get_item_name(info));
}
break;
}
default:
break;
}
switch (type) {
case SND_CTL_ELEM_TYPE_BYTES:
case SND_CTL_ELEM_TYPE_IEC958: {
size_t size = type == SND_CTL_ELEM_TYPE_BYTES ? count : sizeof(snd_aes_iec958_t);
char buf[size * 2 + 1];
char *p = buf;
char *hex = "0123456789abcdef";
const unsigned char *bytes = (const unsigned char *)snd_ctl_elem_value_get_bytes(ctl);
for (idx = 0; idx < size; idx++) {
int v = bytes[idx];
*p++ = hex[v >> 4];
*p++ = hex[v & 0x0f];
}
*p = '\0';
debug("value: %u", buf);
return 0;
}
default:
break;
}
if (count == 1) {
switch (type) {
case SND_CTL_ELEM_TYPE_BOOLEAN:
debug("value: %s", snd_ctl_elem_value_get_boolean(ctl, 0) ? "true" : "false");
return 0;
case SND_CTL_ELEM_TYPE_INTEGER:
debug("value: %i", snd_ctl_elem_value_get_integer(ctl, 0));
return 0;
case SND_CTL_ELEM_TYPE_INTEGER64:
debug("value: %lli", snd_ctl_elem_value_get_integer64(ctl, 0));
return 0;
case SND_CTL_ELEM_TYPE_ENUMERATED: {
unsigned int v = snd_ctl_elem_value_get_enumerated(ctl, 0);
debug("(enum) value: %i", v);
return 0;
}
default:
error("Unknown control type: %d\n", type);
return -EINVAL;
}
}
/* err = snd_config_compound_add(control, "value", 1, &value);
if (err < 0) {
error("snd_config_compound_add: %s", snd_strerror(err));
return err;
}
switch (type) {
case SND_CTL_ELEM_TYPE_BOOLEAN:
for (idx = 0; idx < count; idx++) {
err = snd_config_string_add(value, num_str(idx), snd_ctl_elem_value_get_boolean(ctl, idx) ? "true" : "false");
if (err < 0) {
error("snd_config_string_add: %s", snd_strerror(err));
return err;
}
}
break;
case SND_CTL_ELEM_TYPE_INTEGER:
for (idx = 0; idx < count; idx++) {
err = snd_config_integer_add(value, num_str(idx), snd_ctl_elem_value_get_integer(ctl, idx));
if (err < 0) {
error("snd_config_integer_add: %s", snd_strerror(err));
return err;
}
}
break;
case SND_CTL_ELEM_TYPE_INTEGER64:
for (idx = 0; idx < count; idx++) {
err = snd_config_integer64_add(value, num_str(idx), snd_ctl_elem_value_get_integer64(ctl, idx));
if (err < 0) {
error("snd_config_integer64_add: %s", snd_strerror(err));
return err;
}
}
break;
case SND_CTL_ELEM_TYPE_ENUMERATED:
for (idx = 0; idx < count; idx++) {
unsigned int v = snd_ctl_elem_value_get_enumerated(ctl, idx);
snd_config_t *c;
err = snd_config_search(item, num_str(v), &c);
if (err == 0) {
err = snd_config_get_string(c, &s);
assert(err == 0);
err = snd_config_string_add(value, num_str(idx), s);
} else {
err = snd_config_integer_add(value, num_str(idx), v);
}
if (err < 0) {
error("snd_config add: %s", snd_strerror(err));
return err;
}
}
break;
default:
error("Unknown control type: %d\n", type);
return -EINVAL;
}*/
return 0;
}
static int get_controls(int cardno)
{
snd_ctl_t *handle;
snd_ctl_card_info_t *info;
snd_ctl_elem_list_t *list;
unsigned int idx;
int err;
char name[32];
unsigned int count;
const char *id;
snd_ctl_card_info_alloca(&info);
snd_ctl_elem_list_alloca(&list);
sprintf(name, "hw:%d", cardno);
err = snd_ctl_open(&handle, name, SND_CTL_READONLY);
if (err < 0) {
error("snd_ctl_open error: %s", snd_strerror(err));
return err;
}
err = snd_ctl_card_info(handle, info);
if (err < 0) {
error("snd_ctl_card_info error: %s", snd_strerror(err));
goto _close;
}
err = snd_ctl_elem_list(handle, list);
if (err < 0) {
error("Cannot determine controls: %s", snd_strerror(err));
goto _close;
}
count = snd_ctl_elem_list_get_count(list);
if (count < 0) {
err = 0;
goto _close;
}
if (count == 0) {
err = 0;
goto _close;
}
snd_ctl_elem_list_set_offset(list, 0);
if (snd_ctl_elem_list_alloc_space(list, count) < 0) {
error("No enough memory...");
goto _close;
}
if ((err = snd_ctl_elem_list(handle, list)) < 0) {
error("Cannot determine controls (2): %s", snd_strerror(err));
goto _free;
}
for (idx = 0; idx < count; ++idx) {
snd_ctl_elem_id_t *id;
snd_ctl_elem_id_alloca(&id);
snd_ctl_elem_list_get_id(list, idx, id);
err = get_control(handle, id);
if (err < 0)
goto _free;
}
err = 0;
_free:
snd_ctl_elem_list_free_space(list);
_close:
snd_ctl_close(handle);
return err;
}
int main(int argc, char **argv)
{
int card = 0;
char *string = NULL;
while(card > -1) {
snd_card_get_name(card, &string);
printf("Card name: \"%s\"\n", string);
get_controls(card);
snd_card_next(&card);
}
}