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; }
/** * \brief Returns an integer environment value. * \param dst The function puts the handle to the result configuration node * (with type integer) 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 igetenv vars [ MY_DEVICE DEVICE D ] default 0 } \endcode */ int snd_func_igetenv(snd_config_t **dst, snd_config_t *root, snd_config_t *src, snd_config_t *private_data) { snd_config_t *d; const char *str, *id; int err; long v; err = snd_func_getenv(&d, root, src, private_data); if (err < 0) return err; err = snd_config_get_string(d, &str); if (err < 0) { snd_config_delete(d); return err; } err = safe_strtol(str, &v); if (err < 0) { snd_config_delete(d); return err; } snd_config_delete(d); err = snd_config_get_id(src, &id); if (err < 0) return err; err = snd_config_imake_integer(dst, id, v); if (err < 0) return err; return 0; }
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; }
/** * \brief Gets the control interface index from a configuration node. * \param conf Handle to the configuration node to be parsed. * \return The control interface index if successful, otherwise a negative error code. */ int snd_config_get_ctl_iface(const snd_config_t *conf) { long v; const char *str, *id; int err; err = snd_config_get_id(conf, &id); if (err < 0) return err; err = snd_config_get_integer(conf, &v); if (err >= 0) { if (v < 0 || v > SND_CTL_ELEM_IFACE_LAST) { _invalid_value: SNDERR("Invalid value for %s", id); return -EINVAL; } return v; } err = snd_config_get_string(conf, &str); if (err < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; } err = snd_config_get_ctl_iface_ascii(str); if (err < 0) goto _invalid_value; 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 (_snd_conf_generic_id(id)) continue; return -EINVAL; }
int parse_get_safe_id(snd_config_t *n, const char **id) { int err; err = snd_config_get_id(n, id); if (err < 0) return err; return parse_is_name_safe((char *)(*id)); }
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; } }
/* * 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 (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; } }
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; }
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 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; } }
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); } }
/** * \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; }
/* Work around PulseAudio ALSA plugin bug where the PA server forces a higher than requested latency, but the plugin does not update its (and ALSA's) internal state to reflect that, leading to an immediate underrun situation. Inspired by WINE's make_handle_underrun_config. Reference: http://mailman.alsa-project.org/pipermail/alsa-devel/2012-July/05 */ static snd_config_t * init_local_config_with_workaround(char const * pcm_name) { int r; snd_config_t * lconf; snd_config_t * pcm_node; snd_config_t * node; char const * string; char node_name[64]; lconf = NULL; if (snd_config == NULL) { return NULL; } r = snd_config_copy(&lconf, snd_config); if (r < 0) { return NULL; } do { r = snd_config_search_definition(lconf, "pcm", pcm_name, &pcm_node); if (r < 0) { break; } r = snd_config_get_id(pcm_node, &string); if (r < 0) { break; } r = snprintf(node_name, sizeof(node_name), "pcm.%s", string); if (r < 0 || r > (int) sizeof(node_name)) { break; } r = snd_config_search(lconf, node_name, &pcm_node); if (r < 0) { break; } /* If this PCM has a slave, walk the slave configurations until we reach the bottom. */ while ((node = get_slave_pcm_node(lconf, pcm_node)) != NULL) { pcm_node = node; } /* Fetch the PCM node's type, and bail out if it's not the PulseAudio plugin. */ r = snd_config_search(pcm_node, "type", &node); if (r < 0) { break; } r = snd_config_get_string(node, &string); if (r < 0) { break; } if (strcmp(string, "pulse") != 0) { break; } /* Don't clobber an explicit existing handle_underrun value, set it only if it doesn't already exist. */ r = snd_config_search(pcm_node, "handle_underrun", &node); if (r != -ENOENT) { break; } /* Disable pcm_pulse's asynchronous underrun handling. */ r = snd_config_imake_integer(&node, "handle_underrun", 0); if (r < 0) { break; } r = snd_config_add(pcm_node, node); if (r < 0) { break; } return lconf; } while (0); snd_config_delete(lconf); return NULL; }
/** * \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; }
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 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; }
* \return A non-negative value if successful, otherwise a negative error code. * * Example (result is "/usr/share/alsa" using the default paths): \code { @func datadir } \endcode */ int snd_func_datadir(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *src, snd_config_t *private_data ATTRIBUTE_UNUSED) { int err; const char *id; err = snd_config_get_id(src, &id); if (err < 0) return err; return snd_config_imake_string(dst, id, ALSA_CONFIG_DIR); } #ifndef DOC_HIDDEN SND_DLSYM_BUILD_VERSION(snd_func_datadir, SND_CONFIG_DLSYM_VERSION_EVALUATE); #endif static int open_ctl(long card, snd_ctl_t **ctl) { char name[16]; snprintf(name, sizeof(name), "hw:%li", card); name[sizeof(name)-1] = '\0'; return snd_ctl_open(ctl, name, 0); }
/** * \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; }