static int snd_func_iops(snd_config_t **dst, snd_config_t *root, snd_config_t *src, snd_config_t *private_data, int op) { snd_config_t *n; snd_config_iterator_t i, next; const char *id; char *res = NULL; long result = 0, val; int idx = 0, err, hit; err = snd_config_search(src, "integers", &n); if (err < 0) { SNDERR("field integers not found"); goto __error; } err = snd_config_evaluate(n, root, private_data, NULL); if (err < 0) { SNDERR("error evaluating integers"); goto __error; } do { hit = 0; snd_config_for_each(i, next, n) { snd_config_t *n = snd_config_iterator_entry(i); const char *id; long i; if (snd_config_get_id(n, &id) < 0) continue; err = safe_strtol(id, &i); if (err < 0) { SNDERR("id of field %s is not an integer", id); err = -EINVAL; goto __error; } if (i == idx) { idx++; err = snd_config_get_integer(n, &val); if (err < 0) { SNDERR("invalid integer for id %s", id); err = -EINVAL; goto __error; } switch (op) { case 0: result += val; break; case 1: result *= val; break; } hit = 1; } } } while (hit); err = snd_config_get_id(src, &id); if (err >= 0) err = snd_config_imake_integer(dst, id, result); free(res); __error: return err; }
static int parse_text_values(snd_config_t *cfg, struct tplg_elem *elem) { struct tplg_texts *texts = elem->texts; snd_config_iterator_t i, next; snd_config_t *n; const char *value = NULL; int j = 0; tplg_dbg(" Text Values: %s\n", elem->id); snd_config_for_each(i, next, cfg) { n = snd_config_iterator_entry(i); if (j == SND_SOC_TPLG_NUM_TEXTS) { tplg_dbg("error: text string number exceeds %d\n", j); return -ENOMEM; } /* get value */ if (snd_config_get_string(n, &value) < 0) continue; elem_copy_text(&texts->items[j][0], value, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); tplg_dbg("\t%s\n", &texts->items[j][0]); j++; }
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, "comment") == 0) continue; if (strcmp(id, "type") == 0) continue; if (strcmp(id, "card") == 0) { err = snd_config_get_integer(n, &card); if (err < 0) { err = snd_config_get_string(n, &str); if (err < 0) return -EINVAL; card = snd_card_get_index(str); if (card < 0) return card; } continue; } if (strcmp(id, "device") == 0) { err = snd_config_get_integer(n, &device); if (err < 0) return err; continue; } SNDERR("Unexpected field %s", id); return -EINVAL; }
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; }
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 (_snd_conf_generic_id(id)) continue; return -EINVAL; }
static int names_parse(snd_config_t *top, const char *iface, snd_devname_t **list) { snd_config_iterator_t i, next; snd_config_iterator_t j, jnext; char *name, *comment; const char *id; snd_devname_t *dn, *last = NULL; int err; err = snd_config_search(top, iface, &top); if (err < 0) return err; snd_config_for_each(i, next, top) { snd_config_t *n = snd_config_iterator_entry(i); if (snd_config_get_id(n, &id) < 0) continue; name = comment = NULL; snd_config_for_each(j, jnext, n) { snd_config_t *m = snd_config_iterator_entry(j); if (snd_config_get_id(m, &id) < 0) continue; if (strcmp(id, "name") == 0) { err = snd_config_get_string(m, (const char **)&name); if (err < 0) continue; name = strdup(name); if (name == NULL) { err = -ENOMEM; goto _err; } continue; } if (strcmp(id, "comment") == 0) { err = snd_config_get_string(m, (const char **)&comment); if (err < 0) continue; comment = strdup(comment); if (name == NULL) { err = -ENOMEM; goto _err; } continue; } }
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; }
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, "comment") == 0) continue; if (strcmp(id, "type") == 0) continue; return -EINVAL; }
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; } }
static int tplg_parse_dapm_mixers(snd_config_t *cfg, struct tplg_elem *elem) { snd_config_iterator_t i, next; snd_config_t *n; const char *value = NULL; tplg_dbg(" DAPM Mixer Controls: %s\n", elem->id); snd_config_for_each(i, next, cfg) { n = snd_config_iterator_entry(i); /* get value */ if (snd_config_get_string(n, &value) < 0) continue; tplg_ref_add(elem, SND_TPLG_TYPE_MIXER, value); tplg_dbg("\t\t %s\n", value); }
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 (snd_rawmidi_conf_generic_id(id)) continue; if (strcmp(id, "slave") == 0) { err = snd_config_get_string(n, &slave_str); if (err < 0) return err; continue; } if (strcmp(id, "merge") == 0) { merge = snd_config_get_bool(n); continue; } return -EINVAL; }
/* * Parse transition */ static int parse_transition(snd_use_case_mgr_t *uc_mgr, struct list_head *tlist, snd_config_t *cfg) { struct transition_sequence *tseq; const char *id; snd_config_iterator_t i, next; snd_config_t *n; int err; if (snd_config_get_id(cfg, &id) < 0) return -EINVAL; if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { uc_error("compound type expected for %s", id); return -EINVAL; } snd_config_for_each(i, next, cfg) { n = snd_config_iterator_entry(i); if (snd_config_get_id(n, &id) < 0) return -EINVAL; tseq = calloc(1, sizeof(*tseq)); if (tseq == NULL) return -ENOMEM; INIT_LIST_HEAD(&tseq->transition_list); tseq->name = strdup(id); if (tseq->name == NULL) { free(tseq); return -ENOMEM; } err = parse_sequence(uc_mgr, &tseq->transition_list, n); if (err < 0) { uc_mgr_free_transition_element(tseq); return err; } list_add(&tseq->list, tlist); }
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 (snd_pcm_conf_generic_id(id)) continue; if (strcmp(id, "playback") == 0) { if (stream == SND_PCM_STREAM_PLAYBACK) slave = n; continue; } if (strcmp(id, "capture") == 0) { if (stream == SND_PCM_STREAM_CAPTURE) slave = n; continue; } SNDERR("Unknown field %s", id); return -EINVAL; }
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; }
/*---------------------------------------------------------------------------- ** ALSA_CheckEnvironment ** ** Given an Alsa style configuration node, scan its subitems ** for environment variable names, and use them to find an override, ** if appropriate. ** This is essentially a long and convoluted way of doing: ** getenv("ALSA_CARD") ** getenv("ALSA_CTL_CARD") ** getenv("ALSA_PCM_CARD") ** getenv("ALSA_PCM_DEVICE") ** ** The output value is set with the atoi() of the first environment ** variable found to be set, if any; otherwise, it is left alone */ static void ALSA_CheckEnvironment(snd_config_t *node, int *outvalue) { snd_config_iterator_t iter; for (iter = snd_config_iterator_first(node); iter != snd_config_iterator_end(node); iter = snd_config_iterator_next(iter)) { snd_config_t *leaf = snd_config_iterator_entry(iter); if (snd_config_get_type(leaf) == SND_CONFIG_TYPE_STRING) { const char *value; if (snd_config_get_string(leaf, &value) >= 0) { char *p = getenv(value); if (p) { *outvalue = atoi(p); return; } } } } }
void AlsaBackend::UpdateDevicesList() { Log("AlsaBackend::UpdateDeviceList\n"); DeviceInfo info; void **hints, **n; char *name, *descr, *desc; unsigned devices = 0; InitDevicesList(); info.SetDevice(devices++, "default", "Default device", "default"); info.type = DeviceInfo::TYPE_PLUG; info.direction = 0; PcmPreProbe(info, OUTPUT); PcmPreProbe(info, INPUT); devicesList.push_back(info); // Start with safe alsa detection, list the devices from software config. snd_config_update(); if (snd_device_name_hint(-1, "pcm", &hints) < 0) return; n = hints; while (*n != NULL) { name = snd_device_name_get_hint(*n, "NAME"); descr = snd_device_name_get_hint(*n, "DESC"); if (!descr) desc = (char*)""; else { desc = descr; for (int i = strlen(desc); i > 0; i--) if (desc[i-1] == '\n') desc[i-1] = ' '; } if (IgnorePlugin(name)) { Log("Ignoring ALSA device %s", name); } else { info.SetDevice(devices++, name, desc, name); info.type = DeviceInfo::TYPE_PLUG; info.probed = false; info.direction = 0; PcmPreProbe(info, OUTPUT); PcmPreProbe(info, INPUT); if (info.direction != 0) devicesList.push_back(info); } if (name != NULL) free(name); if (descr != NULL) free(descr); n++; } snd_device_name_free_hint(hints); // Continue with new detection, this is a more thorough test with probing device characteristics enum { IDLEN = 12 }; char hwdev[IDLEN+1]; int card, err, dev; snd_ctl_t* handle = NULL; snd_ctl_card_info_t* cardinfo; snd_pcm_info_t* pcminfo; snd_ctl_card_info_alloca(&cardinfo); snd_pcm_info_alloca(&pcminfo); card = -1; while (snd_card_next(&card) == 0 && card >= 0) { snprintf(hwdev, IDLEN, "hw:%d", card); err = snd_ctl_open(&handle, hwdev, 0); if (sc_errcheck(err, "opening control interface", card, -1)) continue; err = snd_ctl_card_info(handle, cardinfo); if (sc_errcheck(err, "obtaining card info", card, -1)) { snd_ctl_close(handle); continue; } Log("Card %d, ID '%s', name '%s'", card, snd_ctl_card_info_get_id(cardinfo), snd_ctl_card_info_get_name(cardinfo)); dev = -1; if (snd_ctl_pcm_next_device(handle, &dev) < 0) { snd_ctl_close(handle); continue; } while (dev >= 0) { if (!DevProbe(handle, pcminfo, card, dev, OUTPUT) && !DevProbe(handle, pcminfo, card, dev, INPUT)) { if (snd_ctl_pcm_next_device(handle, &dev) < 0) break; } snprintf(hwdev, IDLEN, "hw:%d,%d", card, dev); char strbuf[DEVICE_NAME_MAXLEN]; snprintf(strbuf, DEVICE_NAME_MAXLEN, "%s, %s", snd_ctl_card_info_get_name(cardinfo), snd_pcm_info_get_name(pcminfo)); info.SetDevice(devices++, hwdev, strbuf, hwdev); info.type = DeviceInfo::TYPE_HW; info.probed = false; info.direction = 0; PcmPreProbe(info, OUTPUT); PcmPreProbe(info, INPUT); Log("**********\n%s :: %s\n**********\n", info.guid, info.displayName); devicesList.push_back(info); if (snd_ctl_pcm_next_device(handle, &dev) < 0) break; } snd_ctl_close(handle); } // And complement with chewing a bit on user-defined entries, too. // from PortAudio /* Iterate over plugin devices */ snd_config_t *topNode = NULL; assert(snd_config); if ((err = snd_config_search(snd_config, "pcm", &topNode)) >= 0) { snd_config_iterator_t i, next; snd_config_for_each(i, next, topNode) { const char *tpStr = "unknown", *idStr = NULL; int err = 0; snd_config_t *n = snd_config_iterator_entry(i), *tp = NULL; if ((err = snd_config_search(n, "type", &tp)) < 0) { if (-ENOENT != err) { Log("plugin list error: %s", snd_strerror(err)); } } else { snd_config_get_string(tp, &tpStr); } snd_config_get_id(n, &idStr); if (IgnorePlugin(idStr)) { Log("Ignoring ALSA plugin device %s of type %s", idStr, tpStr); continue; } Log("Found plugin %s of type %s", idStr, tpStr); info.SetDevice(devices++, idStr, idStr, tpStr); info.probed = false; info.direction = 0; if (strncmp(tpStr, "bluetooth", 9)==0) info.type = DeviceInfo::TYPE_BLUETOOTH; else if(strncmp(tpStr, "null", 4) == 0) { info.type = DeviceInfo::TYPE_NULL; // Never need to probe the null device. info.probed = true; } else if(strncmp(tpStr, "unknown", 4) == 0) info.type = DeviceInfo::TYPE_UNKNOWN; else { info.type = DeviceInfo::TYPE_PLUG; // No need to preprobe bluetooth, null and unknown(?) types. PcmPreProbe(info, OUTPUT); PcmPreProbe(info, INPUT); } devicesList.push_back(info); } }
static int snd_rawmidi_open_conf(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, const char *name, snd_config_t *rawmidi_root, snd_config_t *rawmidi_conf, int mode) { const char *str; char buf[256]; int err; snd_config_t *conf, *type_conf = NULL; snd_config_iterator_t i, next; snd_rawmidi_params_t params; const char *id; const char *lib = NULL, *open_name = NULL; int (*open_func)(snd_rawmidi_t **, snd_rawmidi_t **, const char *, snd_config_t *, snd_config_t *, int) = NULL; #ifndef PIC extern void *snd_rawmidi_open_symbols(void); #endif void *h = NULL; if (snd_config_get_type(rawmidi_conf) != SND_CONFIG_TYPE_COMPOUND) { if (name) SNDERR("Invalid type for RAWMIDI %s definition", name); else SNDERR("Invalid type for RAWMIDI definition"); return -EINVAL; } err = snd_config_search(rawmidi_conf, "type", &conf); if (err < 0) { SNDERR("type is not defined"); return err; } err = snd_config_get_id(conf, &id); if (err < 0) { SNDERR("unable to get id"); return err; } err = snd_config_get_string(conf, &str); if (err < 0) { SNDERR("Invalid type for %s", id); return err; } err = snd_config_search_definition(rawmidi_root, "rawmidi_type", str, &type_conf); if (err >= 0) { if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) { SNDERR("Invalid type for RAWMIDI type %s definition", str); goto _err; } snd_config_for_each(i, next, type_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, "comment") == 0) continue; if (strcmp(id, "lib") == 0) { err = snd_config_get_string(n, &lib); if (err < 0) { SNDERR("Invalid type for %s", id); goto _err; } continue; } if (strcmp(id, "open") == 0) { err = snd_config_get_string(n, &open_name); if (err < 0) { SNDERR("Invalid type for %s", id); goto _err; } continue; } SNDERR("Unknown field %s", id); err = -EINVAL; goto _err; } }
std::vector<ALSAInput::Source> ALSAInput::GetSourceList() { std::vector<Source> list; /* This code is based on the ALSA device detection code used in PortAudio. I just ported it to C++ and improved it a bit. All credit goes to the PortAudio devs, they saved me a lot of time :). */ // these ALSA plugins are blacklisted because they are always defined but rarely useful // 'pulse' is also blacklisted because the native PulseAudio backend is more reliable std::vector<std::string> plugin_blacklist = { "cards", "default", "sysdefault", "hw", "plughw", "plug", "dmix", "dsnoop", "shm", "tee", "file", "null", "front", "rear", "center_lfe", "side", "surround40", "surround41", "surround50", "surround51", "surround71", "iec958", "spdif", "hdmi", "modem", "phoneline", "pulse", }; std::sort(plugin_blacklist.begin(), plugin_blacklist.end()); // the 'default' PCM must be first, so add it explicitly list.push_back(Source("default", "Default source")); Logger::LogInfo("[ALSAInput::GetSourceList] " + Logger::tr("Generating source list ...")); snd_ctl_card_info_t *alsa_card_info = NULL; snd_pcm_info_t *alsa_pcm_info = NULL; snd_ctl_t *alsa_ctl = NULL; try { // allocate card and PCM info structure if(snd_ctl_card_info_malloc(&alsa_card_info) < 0) { throw std::bad_alloc(); } if(snd_pcm_info_malloc(&alsa_pcm_info) < 0) { throw std::bad_alloc(); } // update the ALSA configuration snd_config_update_free_global(); if(snd_config_update() < 0) { Logger::LogError("[ALSAInput::GetSourceList] " + Logger::tr("Error: Could not update ALSA configuration!")); throw ALSAException(); } // find all PCM plugins (by parsing the config file) snd_config_t *alsa_config_pcms = NULL; if(snd_config_search(snd_config, "pcm", &alsa_config_pcms) == 0) { snd_config_iterator_t i, next; snd_config_for_each(i, next, alsa_config_pcms) { snd_config_t *alsa_config_pcm = snd_config_iterator_entry(i); // get the name const char *id = NULL; if(snd_config_get_id(alsa_config_pcm, &id) < 0 || id == NULL) continue; std::string plugin_name = id; // ignore the plugin if it is blacklisted if(std::binary_search(plugin_blacklist.begin(), plugin_blacklist.end(), plugin_name)) continue; // try to get the description std::string plugin_description; snd_config_t *alsa_config_description = NULL; if(snd_config_search(alsa_config_pcm, "hint.description", &alsa_config_description) == 0) { const char *str = NULL; if(snd_config_get_string(alsa_config_description, &str) >= 0 && str != NULL) { plugin_description = str; } } // if there is no description, ignore it, because it's probably not meant to be used if(plugin_description.empty()) continue; // if there is no description, use the type instead /*if(plugin_description.empty()) { snd_config_t *alsa_config_type = NULL; if(snd_config_search(alsa_config_pcm, "type", &alsa_config_type) >= 0) { const char *str = NULL; if(snd_config_get_string(alsa_config_type, &str) >= 0 && str != NULL) { plugin_description = std::string(str) + " plugin"; } } }*/ // add to list Logger::LogInfo("[ALSAInput::GetSourceList] " + Logger::tr("Found plugin: [%1] %2").arg(QString::fromStdString(plugin_name)).arg(QString::fromStdString(plugin_description))); list.push_back(Source(plugin_name, plugin_description)); } }
/** * \brief Parse control element id from the config * \param conf the config tree to parse * \param ctl_id the pointer to store the resultant control element id * \param cardp the pointer to store the card index * \param cchannelsp the pointer to store the number of channels (optional) * \param hwctlp the pointer to store the h/w control flag (optional) * \return 0 if successful, or a negative error code * * This function parses the given config tree to retrieve the control element id * and the card index. It's used by softvol. External PCM plugins can use this * function for creating or assigining their controls. * * cchannelsp and hwctlp arguments are optional. Set NULL if not necessary. */ int snd_pcm_parse_control_id(snd_config_t *conf, snd_ctl_elem_id_t *ctl_id, int *cardp, int *cchannelsp, int *hwctlp) { snd_config_iterator_t i, next; int iface = SND_CTL_ELEM_IFACE_MIXER; const char *name = NULL; long index = 0; long device = -1; long subdevice = -1; int err; assert(ctl_id && cardp); *cardp = -1; if (cchannelsp) *cchannelsp = 2; 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, "comment") == 0) continue; if (strcmp(id, "card") == 0) { const char *str; long v; if ((err = snd_config_get_integer(n, &v)) < 0) { if ((err = snd_config_get_string(n, &str)) < 0) { SNDERR("Invalid field %s", id); goto _err; } *cardp = snd_card_get_index(str); if (*cardp < 0) { SNDERR("Cannot get index for %s", str); err = *cardp; goto _err; } } else *cardp = v; continue; } if (strcmp(id, "iface") == 0 || strcmp(id, "interface") == 0) { const char *ptr; if ((err = snd_config_get_string(n, &ptr)) < 0) { SNDERR("field %s is not a string", id); goto _err; } if ((err = snd_config_get_ctl_iface_ascii(ptr)) < 0) { SNDERR("Invalid value for '%s'", id); goto _err; } iface = err; continue; } if (strcmp(id, "name") == 0) { if ((err = snd_config_get_string(n, &name)) < 0) { SNDERR("field %s is not a string", id); goto _err; } continue; } if (strcmp(id, "index") == 0) { if ((err = snd_config_get_integer(n, &index)) < 0) { SNDERR("field %s is not an integer", id); goto _err; } continue; } if (strcmp(id, "device") == 0) { if ((err = snd_config_get_integer(n, &device)) < 0) { SNDERR("field %s is not an integer", id); goto _err; } continue; } if (strcmp(id, "subdevice") == 0) { if ((err = snd_config_get_integer(n, &subdevice)) < 0) { SNDERR("field %s is not an integer", id); goto _err; } continue; } if (cchannelsp && strcmp(id, "count") == 0) { long v; if ((err = snd_config_get_integer(n, &v)) < 0) { SNDERR("field %s is not an integer", id); goto _err; } if (v < 1 || v > 2) { SNDERR("Invalid count %ld", v); goto _err; } *cchannelsp = v; continue; } if (hwctlp && strcmp(id, "hwctl") == 0) { if ((err = snd_config_get_bool(n)) < 0) { SNDERR("The field %s must be a boolean type", id); return err; } *hwctlp = err; continue; } SNDERR("Unknown field %s", id); return -EINVAL; }
/** * \brief Returns an environment value. * \param dst The function puts the handle to the result configuration node * (with type string) at the address specified by \p dst. * \param root Handle to the root source node. * \param src Handle to the source node, with definitions for \c vars and * \c default. * \param private_data Handle to the \c private_data node. * \return Zero if successful, otherwise a negative error code. * * Example: \code { @func getenv vars [ MY_CARD CARD C ] default 0 } \endcode */ int snd_func_getenv(snd_config_t **dst, snd_config_t *root, snd_config_t *src, snd_config_t *private_data) { snd_config_t *n, *d; snd_config_iterator_t i, next; const char *res, *id; char *def = NULL; int idx = 0, err, hit; err = snd_config_search(src, "vars", &n); if (err < 0) { SNDERR("field vars not found"); goto __error; } err = snd_config_evaluate(n, root, private_data, NULL); if (err < 0) { SNDERR("error evaluating vars"); goto __error; } err = snd_config_search(src, "default", &d); if (err < 0) { SNDERR("field default not found"); goto __error; } err = snd_config_evaluate(d, root, private_data, NULL); if (err < 0) { SNDERR("error evaluating default"); goto __error; } err = snd_config_get_ascii(d, &def); if (err < 0) { SNDERR("error getting field default"); goto __error; } do { hit = 0; snd_config_for_each(i, next, n) { snd_config_t *n = snd_config_iterator_entry(i); const char *ptr; long i; if (snd_config_get_id(n, &id) < 0) continue; if (snd_config_get_type(n) != SND_CONFIG_TYPE_STRING) { SNDERR("field %s is not a string", id); err = -EINVAL; goto __error; } err = safe_strtol(id, &i); if (err < 0) { SNDERR("id of field %s is not an integer", id); err = -EINVAL; goto __error; } if (i == idx) { idx++; err = snd_config_get_string(n, &ptr); if (err < 0) { SNDERR("invalid string for id %s", id); err = -EINVAL; goto __error; } res = getenv(ptr); if (res != NULL && *res != '\0') goto __ok; hit = 1; } } } while (hit); res = def; __ok: err = snd_config_get_id(src, &id); if (err >= 0) err = snd_config_imake_string(dst, id, res); __error: free(def); return err; }
/** * \brief Merges the given strings. * \param dst The function puts the handle to the result configuration node * (with type string) at the address specified by \p dst. * \param root Handle to the root source node. * \param src Handle to the source node, with a definition for \c strings. * \param private_data Handle to the \c private_data node. * \return A non-negative value if successful, otherwise a negative error code. * * Example (result is "a1b2c3"): \code { @func concat strings [ "a1" "b2" "c3" ] } \endcode */ int snd_func_concat(snd_config_t **dst, snd_config_t *root, snd_config_t *src, snd_config_t *private_data) { snd_config_t *n; snd_config_iterator_t i, next; const char *id; char *res = NULL, *tmp; int idx = 0, len = 0, len1, err, hit; err = snd_config_search(src, "strings", &n); if (err < 0) { SNDERR("field strings not found"); goto __error; } err = snd_config_evaluate(n, root, private_data, NULL); if (err < 0) { SNDERR("error evaluating strings"); goto __error; } do { hit = 0; snd_config_for_each(i, next, n) { snd_config_t *n = snd_config_iterator_entry(i); char *ptr; const char *id; long i; if (snd_config_get_id(n, &id) < 0) continue; err = safe_strtol(id, &i); if (err < 0) { SNDERR("id of field %s is not an integer", id); err = -EINVAL; goto __error; } if (i == idx) { idx++; err = snd_config_get_ascii(n, &ptr); if (err < 0) { SNDERR("invalid ascii string for id %s", id); err = -EINVAL; goto __error; } len1 = strlen(ptr); tmp = realloc(res, len + len1 + 1); if (tmp == NULL) { free(ptr); free(res); err = -ENOMEM; goto __error; } memcpy(tmp + len, ptr, len1); free(ptr); len += len1; tmp[len] = '\0'; res = tmp; hit = 1; } } } while (hit); if (res == NULL) { SNDERR("empty string is not accepted"); err = -EINVAL; goto __error; } err = snd_config_get_id(src, &id); if (err >= 0) err = snd_config_imake_string(dst, id, res); free(res); __error: return err; }
/** * \brief Creates a new File PCM * \param pcmp Returns created PCM handle * \param name Name of PCM * \param root Root configuration node * \param conf Configuration node with File PCM description * \param stream Stream type * \param mode Stream mode * \retval zero on success otherwise a negative error code * \warning Using of this function might be dangerous in the sense * of compatibility reasons. The prototype might be freely * changed in future. */ int _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, snd_config_t *root, snd_config_t *conf, snd_pcm_stream_t stream, int mode) { snd_config_iterator_t i, next; int err; snd_pcm_t *spcm; snd_config_t *slave = NULL, *sconf; const char *fname = NULL, *ifname = NULL; const char *format = NULL; long fd = -1, ifd = -1, trunc = 1; long perm = 0600; 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 (snd_pcm_conf_generic_id(id)) continue; if (strcmp(id, "slave") == 0) { slave = n; continue; } if (strcmp(id, "format") == 0) { err = snd_config_get_string(n, &format); if (err < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; } continue; } if (strcmp(id, "file") == 0) { err = snd_config_get_string(n, &fname); if (err < 0) { err = snd_config_get_integer(n, &fd); if (err < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; } } continue; } if (strcmp(id, "infile") == 0) { err = snd_config_get_string(n, &ifname); if (err < 0) { err = snd_config_get_integer(n, &ifd); if (err < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; } } continue; } if (strcmp(id, "perm") == 0) { err = snd_config_get_integer(n, &perm); if (err < 0) { SNDERR("Invalid type for %s", id); return err; } if ((perm & ~0777) != 0) { SNDERR("The field perm must be a valid file permission"); return -EINVAL; } continue; } if (strcmp(id, "truncate") == 0) { err = snd_config_get_bool(n); if (err < 0) return -EINVAL; trunc = err; continue; } SNDERR("Unknown field %s", id); return -EINVAL; }
/** * \brief Creates a new File PCM * \param pcmp Returns created PCM handle * \param name Name of PCM * \param root Root configuration node * \param conf Configuration node with File PCM description * \param stream Stream type * \param mode Stream mode * \retval zero on success otherwise a negative error code * \warning Using of this function might be dangerous in the sense * of compatibility reasons. The prototype might be freely * changed in future. */ int _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, snd_config_t *root, snd_config_t *conf, snd_pcm_stream_t stream, int mode) { snd_config_iterator_t i, next; int err; snd_pcm_t *spcm; snd_config_t *slave = NULL, *sconf; const char *fname = NULL, *ifname = NULL; const char *format = NULL; long fd = -1, ifd = -1; int perm = 0600; 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 (snd_pcm_conf_generic_id(id)) continue; if (strcmp(id, "slave") == 0) { slave = n; continue; } if (strcmp(id, "format") == 0) { err = snd_config_get_string(n, &format); if (err < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; } continue; } if (strcmp(id, "file") == 0) { err = snd_config_get_string(n, &fname); if (err < 0) { err = snd_config_get_integer(n, &fd); if (err < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; } } continue; } if (strcmp(id, "infile") == 0) { err = snd_config_get_string(n, &ifname); if (err < 0) { err = snd_config_get_integer(n, &ifd); if (err < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; } } continue; } if (strcmp(id, "perm") == 0) { char *str; char *endp; err = snd_config_get_ascii(n, &str); if (err < 0) { SNDERR("The field perm must be a valid file permission"); return err; } if (isdigit(*str) == 0) { SNDERR("The field perm must be a valid file permission"); free(str); return -EINVAL; } perm = strtol(str, &endp, 8); free(str); continue; } SNDERR("Unknown field %s", id); return -EINVAL; }