📄 state.c
字号:
/* * Advanced Linux Sound Architecture Control Program * Copyright (c) by Abramo Bagnara <abramo@alsa-project.org> * Jaroslav Kysela <perex@suse.cz> * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include "aconfig.h"#include "version.h"#include <getopt.h>#include <stdarg.h>#include <stdio.h>#include <assert.h>#include <errno.h>#include <alsa/asoundlib.h>#include "alsactl.h"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 snd_config_integer_add(snd_config_t *father, char *id, long integer){ int err; snd_config_t *leaf; err = snd_config_make_integer(&leaf, id); if (err < 0) return err; err = snd_config_add(father, leaf); if (err < 0) { snd_config_delete(leaf); return err; } err = snd_config_set_integer(leaf, integer); if (err < 0) { snd_config_delete(leaf); return err; } return 0;}static int snd_config_integer64_add(snd_config_t *father, char *id, long long integer){ int err; snd_config_t *leaf; err = snd_config_make_integer64(&leaf, id); if (err < 0) return err; err = snd_config_add(father, leaf); if (err < 0) { snd_config_delete(leaf); return err; } err = snd_config_set_integer64(leaf, integer); if (err < 0) { snd_config_delete(leaf); return err; } return 0;}static int snd_config_string_add(snd_config_t *father, const char *id, const char *string){ int err; snd_config_t *leaf; err = snd_config_make_string(&leaf, id); if (err < 0) return err; err = snd_config_add(father, leaf); if (err < 0) { snd_config_delete(leaf); return err; } err = snd_config_set_string(leaf, string); if (err < 0) { snd_config_delete(leaf); return err; } return 0;}static int snd_config_compound_add(snd_config_t *father, const char *id, int join, snd_config_t **node){ int err; snd_config_t *leaf; err = snd_config_make_compound(&leaf, id, join); if (err < 0) return err; err = snd_config_add(father, leaf); if (err < 0) { snd_config_delete(leaf); return err; } *node = leaf; return 0;}#define MAX_USER_TLV_SIZE 64static char *tlv_to_str(unsigned int *tlv){ int i, len = tlv[1] / 4 + 2; char *s, *p; if (len >= MAX_USER_TLV_SIZE) return NULL; s = malloc(len * 8 + 1); if (! s) return NULL; p = s; for (i = 0; i < len; i++) { sprintf(p, "%08x", tlv[i]); p += 8; } return s;}static int hextodigit(int c){ if (c >= '0' && c <= '9') c -= '0'; else if (c >= 'a' && c <= 'f') c = c - 'a' + 10; else if (c >= 'A' && c <= 'F') c = c - 'A' + 10; else return -1; return c;}static unsigned int *str_to_tlv(const char *s){ int i, j, c, len; unsigned int *tlv; len = strlen(s); if (len % 8) /* aligned to 4 bytes (= 8 letters) */ return NULL; len /= 8; if (len > MAX_USER_TLV_SIZE) return NULL; tlv = malloc(sizeof(int) * len); if (! tlv) return NULL; for (i = 0; i < len; i++) { tlv[i] = 0; for (j = 0; j < 8; j++) { if ((c = hextodigit(*s++)) < 0) { free(tlv); return NULL; } tlv[i] = (tlv[i] << 4) | c; } } return tlv;}static int get_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id, snd_config_t *top){ snd_ctl_elem_value_t *ctl; snd_ctl_elem_info_t *info; snd_config_t *control, *comment, *item, *value; 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; } err = snd_config_compound_add(top, num_str(snd_ctl_elem_info_get_numid(info)), 0, &control); if (err < 0) { error("snd_config_compound_add: %s", snd_strerror(err)); return err; } err = snd_config_compound_add(control, "comment", 1, &comment); if (err < 0) { error("snd_config_compound_add: %s", 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"); if (snd_ctl_elem_info_is_user(info)) strcat(buf, " user"); err = snd_config_string_add(comment, "access", buf + 1); if (err < 0) { error("snd_config_string_add: %s", snd_strerror(err)); return err; } 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); err = snd_config_string_add(comment, "type", s); if (err < 0) { error("snd_config_string_add: %s", snd_strerror(err)); return err; } err = snd_config_integer_add(comment, "count", count); if (err < 0) { error("snd_config_integer_add: %s", snd_strerror(err)); return err; } 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) sprintf(buf, "%li - %li (step %li)", min, max, step); else sprintf(buf, "%li - %li", min, max); err = snd_config_string_add(comment, "range", buf); if (err < 0) { error("snd_config_string_add: %s", snd_strerror(err)); return err; } if (snd_ctl_elem_info_is_tlv_readable(info) && snd_ctl_elem_info_is_tlv_writable(info)) { unsigned int tlv[MAX_USER_TLV_SIZE]; err = snd_ctl_elem_tlv_read(handle, id, tlv, sizeof(tlv)); if (err >= 0) { char *s = tlv_to_str(tlv); if (s) { err = snd_config_string_add(comment, "tlv", s); if (err < 0) { error("snd_config_string_add: %s", snd_strerror(err)); return err; } free(s); } } } 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) sprintf(buf, "%Li - %Li (step %Li)", min, max, step); else sprintf(buf, "%Li - %Li", min, max); err = snd_config_string_add(comment, "range", buf); if (err < 0) { error("snd_config_string_add: %s", snd_strerror(err)); return err; } break; } case SND_CTL_ELEM_TYPE_ENUMERATED: { unsigned int items; err = snd_config_compound_add(comment, "item", 1, &item); if (err < 0) { error("snd_config_compound_add: %s", snd_strerror(err)); return err; } 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; } err = snd_config_string_add(item, num_str(idx), snd_ctl_elem_info_get_item_name(info)); if (err < 0) { error("snd_config_string_add: %s", snd_strerror(err)); return err; } } break; } default: break; } s = snd_ctl_elem_iface_name(snd_ctl_elem_info_get_interface(info)); err = snd_config_string_add(control, "iface", s); if (err < 0) { error("snd_config_string_add: %s", snd_strerror(err)); return err; } if (device != 0) { err = snd_config_integer_add(control, "device", device); if (err < 0) { error("snd_config_integer_add: %s", snd_strerror(err)); return err; } } if (subdevice != 0) { err = snd_config_integer_add(control, "subdevice", subdevice); if (err < 0) { error("snd_config_integer_add: %s", snd_strerror(err)); return err; } } err = snd_config_string_add(control, "name", name); if (err < 0) { error("snd_config_string_add: %s", snd_strerror(err)); return err; } if (index != 0) { err = snd_config_integer_add(control, "index", index); if (err < 0) { error("snd_config_integer_add: %s", snd_strerror(err)); return err; } } 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'; err = snd_config_string_add(control, "value", buf); if (err < 0) { error("snd_config_string_add: %s", snd_strerror(err)); return err; } return 0; } default: break; } if (count == 1) { switch (type) { case SND_CTL_ELEM_TYPE_BOOLEAN: err = snd_config_string_add(control, "value", snd_ctl_elem_value_get_boolean(ctl, 0) ? "true" : "false"); if (err < 0) { error("snd_config_string_add: %s", snd_strerror(err)); return err; } return 0; case SND_CTL_ELEM_TYPE_INTEGER: err = snd_config_integer_add(control, "value", snd_ctl_elem_value_get_integer(ctl, 0)); if (err < 0) { error("snd_config_integer_add: %s", snd_strerror(err)); return err; } return 0; case SND_CTL_ELEM_TYPE_INTEGER64: err = snd_config_integer64_add(control, "value", snd_ctl_elem_value_get_integer64(ctl, 0)); if (err < 0) { error("snd_config_integer64_add: %s", snd_strerror(err)); return err; } return 0; case SND_CTL_ELEM_TYPE_ENUMERATED: { unsigned int v = snd_ctl_elem_value_get_enumerated(ctl, 0); 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(control, "value", s); } else { err = snd_config_integer_add(control, "value", v); } if (err < 0) error("snd_config add: %s", snd_strerror(err)); return 0; } default: error("Unknown control type: %d\n", type);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -