📄 state.c
字号:
return err; } err = snd_ctl_card_info(handle, info); if (err < 0) { error("snd_ctl_card_info error: %s", snd_strerror(err)); goto _close; } id = snd_ctl_card_info_get_id(info); err = snd_config_search(top, "state", &state); if (err == 0 && snd_config_get_type(state) != SND_CONFIG_TYPE_COMPOUND) { error("config state node is not a compound"); err = -EINVAL; goto _close; } if (err < 0) { err = snd_config_compound_add(top, "state", 1, &state); if (err < 0) { error("snd_config_compound_add: %s", snd_strerror(err)); goto _close; } } err = snd_config_search(state, id, &card); if (err == 0 && snd_config_get_type(card) != SND_CONFIG_TYPE_COMPOUND) { error("config state.%s node is not a compound", id); err = -EINVAL; goto _close; } if (err < 0) { err = snd_config_compound_add(state, id, 0, &card); if (err < 0) { error("snd_config_compound_add: %s", snd_strerror(err)); goto _close; } } err = snd_config_search(card, "control", &control); if (err == 0) { err = snd_config_delete(control); if (err < 0) { error("snd_config_delete: %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); err = snd_config_compound_add(card, "control", count > 0, &control); if (err < 0) { error("snd_config_compound_add: %s", snd_strerror(err)); 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, control); if (err < 0) goto _free; } err = 0; _free: snd_ctl_elem_list_free_space(list); _close: snd_ctl_close(handle); return err;}static long config_iface(snd_config_t *n){ long i; long long li; snd_ctl_elem_iface_t idx; const char *str; switch (snd_config_get_type(n)) { case SND_CONFIG_TYPE_INTEGER: snd_config_get_integer(n, &i); return i; case SND_CONFIG_TYPE_INTEGER64: snd_config_get_integer64(n, &li); return li; case SND_CONFIG_TYPE_STRING: snd_config_get_string(n, &str); break; default: return -1; } for (idx = 0; idx <= SND_CTL_ELEM_IFACE_LAST; idx++) { if (strcasecmp(snd_ctl_elem_iface_name(idx), str) == 0) return idx; } return -1;}static int config_bool(snd_config_t *n, int doit){ const char *str; long val; long long lval; switch (snd_config_get_type(n)) { case SND_CONFIG_TYPE_INTEGER: snd_config_get_integer(n, &val); if (val < 0 || val > 1) return -1; return val; case SND_CONFIG_TYPE_INTEGER64: snd_config_get_integer64(n, &lval); if (lval < 0 || lval > 1) return -1; return (int) lval; case SND_CONFIG_TYPE_STRING: snd_config_get_string(n, &str); break; case SND_CONFIG_TYPE_COMPOUND: if (!force_restore || !doit) return -1; n = snd_config_iterator_entry(snd_config_iterator_first(n)); return config_bool(n, doit); default: return -1; } if (strcmp(str, "on") == 0 || strcmp(str, "true") == 0) return 1; if (strcmp(str, "off") == 0 || strcmp(str, "false") == 0) return 0; return -1;}static int config_enumerated(snd_config_t *n, snd_ctl_t *handle, snd_ctl_elem_info_t *info, int doit){ const char *str; long val; long long lval; unsigned int idx, items; switch (snd_config_get_type(n)) { case SND_CONFIG_TYPE_INTEGER: snd_config_get_integer(n, &val); return val; case SND_CONFIG_TYPE_INTEGER64: snd_config_get_integer64(n, &lval); return (int) lval; case SND_CONFIG_TYPE_STRING: snd_config_get_string(n, &str); break; case SND_CONFIG_TYPE_COMPOUND: if (!force_restore || !doit) return -1; n = snd_config_iterator_entry(snd_config_iterator_first(n)); return config_enumerated(n, handle, info, doit); default: return -1; } items = snd_ctl_elem_info_get_items(info); for (idx = 0; idx < items; idx++) { int err; snd_ctl_elem_info_set_item(info, idx); err = snd_ctl_elem_info(handle, info); if (err < 0) { error("snd_ctl_elem_info: %s", snd_strerror(err)); return err; } if (strcmp(str, snd_ctl_elem_info_get_item_name(info)) == 0) return idx; } return -1;}static int config_integer(snd_config_t *n, long *val, int doit){ int err = snd_config_get_integer(n, val); if (err < 0 && force_restore && doit) { if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) return err; n = snd_config_iterator_entry(snd_config_iterator_first(n)); return config_integer(n, val, doit); } return err;}static int config_integer64(snd_config_t *n, long long *val, int doit){ int err = snd_config_get_integer64(n, val); if (err < 0 && force_restore && doit) { if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) return err; n = snd_config_iterator_entry(snd_config_iterator_first(n)); return config_integer64(n, val, doit); } return err;}static int is_user_control(snd_config_t *conf){ snd_config_iterator_t i, next; snd_config_for_each(i, next, conf) { snd_config_t *n = snd_config_iterator_entry(i); const char *id, *s; if (snd_config_get_id(n, &id) < 0) continue; if (strcmp(id, "access") == 0) { if (snd_config_get_string(n, &s) < 0) return 0; if (strstr(s, "user")) return 1; } } return 0;}/* * get the item type from the given comment config */static int get_comment_type(snd_config_t *n){ static const snd_ctl_elem_type_t types[] = { SND_CTL_ELEM_TYPE_BOOLEAN, SND_CTL_ELEM_TYPE_INTEGER, SND_CTL_ELEM_TYPE_ENUMERATED, SND_CTL_ELEM_TYPE_BYTES, SND_CTL_ELEM_TYPE_IEC958, SND_CTL_ELEM_TYPE_INTEGER64, }; const char *type; unsigned int i; if (snd_config_get_string(n, &type) < 0) return -EINVAL; for (i = 0; i < ARRAY_SIZE(types); ++i) if (strcmp(type, snd_ctl_elem_type_name(types[i])) == 0) return types[i]; return -EINVAL;}/* * get the value range from the given comment config */static int get_comment_range(snd_config_t *n, int ctype, long *imin, long *imax, long *istep){ const char *s; int err; if (snd_config_get_string(n, &s) < 0) return -EINVAL; switch (ctype) { case SND_CTL_ELEM_TYPE_INTEGER: err = sscanf(s, "%li - %li (step %li)", imin, imax, istep); if (err != 3) { istep = 0; err = sscanf(s, "%li - %li", imin, imax); if (err != 2) return -EINVAL; } break; default: return -EINVAL; } return 0;}static int add_user_control(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_config_t *conf){ snd_ctl_elem_id_t *id; snd_config_iterator_t i, next; long imin, imax, istep; snd_ctl_elem_type_t ctype; unsigned int count; int err; unsigned int *tlv; imin = imax = istep = 0; count = 0; ctype = SND_CTL_ELEM_TYPE_NONE; tlv = NULL; snd_config_for_each(i, next, conf) { snd_config_t *n = snd_config_iterator_entry(i); const char *id; if (snd_config_get_id(n, &id) < 0) continue; if (strcmp(id, "type") == 0) { err = get_comment_type(n); if (err < 0) return err; ctype = err; continue; } if (strcmp(id, "range") == 0) { err = get_comment_range(n, ctype, &imin, &imax, &istep); if (err < 0) return err; continue; } if (strcmp(id, "count") == 0) { long v; if ((err = snd_config_get_integer(n, &v)) < 0) return err; count = v; continue; } if (strcmp(id, "tlv") == 0) { const char *s; if ((err = snd_config_get_string(n, &s)) < 0) return -EINVAL; if (tlv) free(tlv); if ((tlv = str_to_tlv(s)) == NULL) return -EINVAL; continue; } } snd_ctl_elem_id_alloca(&id); snd_ctl_elem_info_get_id(info, id); if (count <= 0) count = 1; switch (ctype) { case SND_CTL_ELEM_TYPE_INTEGER: if (imin > imax || istep > imax - imin) return -EINVAL; err = snd_ctl_elem_add_integer(handle, id, count, imin, imax, istep); if (err < 0) goto error; if (tlv) snd_ctl_elem_tlv_write(handle, id, tlv); break; case SND_CTL_ELEM_TYPE_BOOLEAN: err = snd_ctl_elem_add_boolean(handle, id, count); break; case SND_CTL_ELEM_TYPE_IEC958: err = snd_ctl_elem_add_iec958(handle, id); break; default: err = -EINVAL; break; } error: free(tlv); if (err < 0) return err; return snd_ctl_elem_info(handle, info);}/* * look for a config node with the given item name */static snd_config_t *search_comment_item(snd_config_t *conf, const char *name){ snd_config_iterator_t i, next; snd_config_for_each(i, next, conf) { snd_config_t *n = snd_config_iterator_entry(i); const char *id; if (snd_config_get_id(n, &id) < 0) continue; if (strcmp(id, name) == 0) return n; } return NULL;}/* * check whether the config item has the same of compatible type */static int check_comment_type(snd_config_t *conf, int type){ snd_config_t *n = search_comment_item(conf, "type"); int ctype; if (!n) return 0; /* not defined */ ctype = get_comment_type(n); if (ctype == type) return 0; if ((ctype == SND_CTL_ELEM_TYPE_BOOLEAN || ctype == SND_CTL_ELEM_TYPE_INTEGER || ctype == SND_CTL_ELEM_TYPE_INTEGER64 || ctype == SND_CTL_ELEM_TYPE_ENUMERATED) && (type == SND_CTL_ELEM_TYPE_BOOLEAN || type == SND_CTL_ELEM_TYPE_INTEGER || type == SND_CTL_ELEM_TYPE_INTEGER64 || type == SND_CTL_ELEM_TYPE_ENUMERATED)) return 0; /* OK, compatible */ return -EINVAL;}/* * convert from an old value to a new value with the same dB level */static int convert_to_new_db(snd_config_t *value, long omin, long omax, long nmin, long nmax, long odbmin, long odbmax, long ndbmin, long ndbmax, int doit){ long val; if (config_integer(value, &val, doit) < 0) return -EINVAL; if (val < omin || val > omax) return -EINVAL; val = ((val - omin) * (odbmax - odbmin)) / (omax - omin) + odbmin; if (val < ndbmin) val = ndbmin; else if (val > ndbmax) val = ndbmax; val = ((val - ndbmin) * (nmax - nmin)) / (ndbmax - ndbmin) + nmin; return snd_config_set_integer(value, val);}/* * compare the current value range with the old range in comments. * also, if dB information is available, try to compare them. * if any change occurs, try to keep the same dB level. */static int check_comment_range(snd_ctl_t *handle, snd_config_t *conf, snd_ctl_elem_info_t *info, snd_config_t *value, int doit){ snd_config_t *n; long omin, omax, ostep; long nmin, nmax; long odbmin, odbmax; long ndbmin, ndbmax; snd_ctl_elem_id_t *id; n = search_comment_item(conf, "range"); if (!n) return 0; if (get_comment_range(n, SND_CTL_ELEM_TYPE_INTEGER, &omin, &omax, &ostep) < 0) return 0; nmin = snd_ctl_elem_info_get_min(info); nmax = snd_ctl_elem_info_get_max(info); if (omin != nmin && omax != nmax) { /* Hey, the range mismatches */ if (!force_restore || !doit) return -EINVAL; } if (omin >= omax || nmin >= nmax) return 0; /* invalid values */ n = search_comment_item(conf, "dbmin"); if (!n) return 0; if (config_integer(n, &odbmin, doit) < 0) return 0; n = search_comment_item(conf, "dbmax"); if (!n) return 0; if (config_integer(n, &odbmax, doit) < 0) return 0; if (odbmin >= odbmax) return 0; /* invalid values */ snd_ctl_elem_id_alloca(&id); snd_ctl_elem_info_get_id(info, id); if (snd_ctl_get_dB_range(handle, id, &ndbmin, &ndbmax) < 0) return 0; if (ndbmin >= ndbmax) return 0; /* invalid values */ if (omin == nmin && omax == nmax && odbmin == ndbmin && odbmax == ndbmax) return 0; /* OK, identical one */ /* Let's guess the current value from dB range */ if (snd_config_get_type(value) == SND_CONFIG_TYPE_COMPOUND) { snd_config_iterator_t i, next; snd_config_for_each(i, next, value) { snd_config_t *n = snd_config_iterator_entry(i); convert_to_new_db(n, omin, omax, nmin, nmax, odbmin, odbmax, ndbmin, ndbmax, doit); } } else convert_to_new_db(value, omin, omax, nmin, nmax, odbmin, odbmax, ndbmin, ndbmax, doit); return 0;}static int restore_config_value(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_ctl_elem_iface_t type, snd_config_t *value, snd_ctl_elem_value_t *ctl, int idx, int doit){ long val; long long lval; int err; switch (type) { case SND_CTL_ELEM_TYPE_BOOLEAN: val = config_bool(value, doit); if (val >= 0) { snd_ctl_elem_value_set_boolean(ctl, idx, val); return 1; } break; case SND_CTL_ELEM_TYPE_INTEGER: err = config_integer(value, &val, doit); if (err == 0) { snd_ctl_elem_value_set_integer(ctl, idx, val); return 1; } break; case SND_CTL_ELEM_TYPE_INTEGER64: err = config_integer64(value, &lval, doit); if (err == 0) { snd_ctl_elem_value_set_integer64(ctl, idx, lval); return 1; } break; case SND_CTL_ELEM_TYPE_ENUMERATED: val = config_enumerated(value, handle, info, doit); if (val >= 0) { snd_ctl_elem_value_set_enumerated(ctl, idx, val); return 1; } break; case SND_CTL_ELEM_TYPE_BYTES: case SND_CTL_ELEM_TYPE_IEC958: break; default: cerror(doit, "Unknow control type: %d", type); return -EINVAL; } return 0;}static int restore_config_value2(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_ctl_elem_iface_t type, snd_config_t *value, snd_ctl_elem_value_t *ctl, int idx, unsigned int numid, int doit){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -