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; }
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 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 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; }
/*---------------------------------------------------------------------------- ** ALSA_DefaultDevices ** ** Jump through Alsa style hoops to (hopefully) properly determine ** Alsa defaults for CTL Card #, as well as for PCM Card + Device #. ** We'll also find out if the user has set any of the environment ** variables that specify we're to use a specific card or device. ** ** Parameters: ** directhw Whether to use a direct hardware device or not; ** essentially switches the pcm device name from ** one of 'default:X' or 'plughw:X' to "hw:X" ** defctlcard If !NULL, will hold the ctl card number given ** by the ALSA config as the default ** defpcmcard If !NULL, default pcm card # ** defpcmdev If !NULL, default pcm device # ** fixedctlcard If !NULL, and the user set the appropriate ** environment variable, we'll set to the ** card the user specified. ** fixedpcmcard If !NULL, and the user set the appropriate ** environment variable, we'll set to the ** card the user specified. ** fixedpcmdev If !NULL, and the user set the appropriate ** environment variable, we'll set to the ** device the user specified. ** ** Returns: 0 on success, < 0 on failure */ static int ALSA_DefaultDevices(int directhw, long *defctlcard, long *defpcmcard, long *defpcmdev, int *fixedctlcard, int *fixedpcmcard, int *fixedpcmdev) { snd_config_t *configp; char pcmsearch[256]; ALSA_RETURN_ONFAIL(snd_config_update()); if (defctlcard) if (snd_config_search(snd_config, "defaults.ctl.card", &configp) >= 0) snd_config_get_integer(configp, defctlcard); if (defpcmcard) if (snd_config_search(snd_config, "defaults.pcm.card", &configp) >= 0) snd_config_get_integer(configp, defpcmcard); if (defpcmdev) if (snd_config_search(snd_config, "defaults.pcm.device", &configp) >= 0) snd_config_get_integer(configp, defpcmdev); if (fixedctlcard) { if (snd_config_search(snd_config, "*****@*****.**", &configp) >= 0) ALSA_CheckEnvironment(configp, fixedctlcard); } if (fixedpcmcard) { sprintf(pcmsearch, "*****@*****.**", directhw ? "hw" : "plughw"); if (snd_config_search(snd_config, pcmsearch, &configp) >= 0) ALSA_CheckEnvironment(configp, fixedpcmcard); } if (fixedpcmdev) { sprintf(pcmsearch, "*****@*****.**", directhw ? "hw" : "plughw"); if (snd_config_search(snd_config, pcmsearch, &configp) >= 0) ALSA_CheckEnvironment(configp, fixedpcmdev); } return 0; }
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_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; }
/** * \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; }
bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device) { m_initDevice = device; m_initFormat = format; /* if we are raw, correct the data format */ if (AE_IS_RAW(format.m_dataFormat)) { m_channelLayout = GetChannelLayout(format); format.m_dataFormat = AE_FMT_S16NE; m_passthrough = true; } else { m_channelLayout = GetChannelLayout(format); m_passthrough = false; } if (m_channelLayout.Count() == 0) { CLog::Log(LOGERROR, "CAESinkALSA::Initialize - Unable to open the requested channel layout"); return false; } format.m_channelLayout = m_channelLayout; AEDeviceType devType = AEDeviceTypeFromName(device); std::string AESParams; /* digital interfaces should have AESx set, though in practice most * receivers don't care */ if (m_passthrough || devType == AE_DEVTYPE_HDMI || devType == AE_DEVTYPE_IEC958) GetAESParams(format, AESParams); CLog::Log(LOGINFO, "CAESinkALSA::Initialize - Attempting to open device \"%s\"", device.c_str()); /* get the sound config */ snd_config_t *config; snd_config_copy(&config, snd_config); snd_config_t *dmixRateConf; long dmixRate; if (snd_config_search(config, "defaults.pcm.dmix.rate", &dmixRateConf) < 0 || snd_config_get_integer(dmixRateConf, &dmixRate) < 0) dmixRate = 48000; /* assume default */ /* Prefer dmix for non-passthrough stereo when sample rate matches */ if (!OpenPCMDevice(device, AESParams, m_channelLayout.Count(), &m_pcm, config, format.m_sampleRate == dmixRate && !m_passthrough)) { CLog::Log(LOGERROR, "CAESinkALSA::Initialize - failed to initialize device \"%s\"", device.c_str()); snd_config_delete(config); return false; } /* get the actual device name that was used */ device = snd_pcm_name(m_pcm); m_device = device; CLog::Log(LOGINFO, "CAESinkALSA::Initialize - Opened device \"%s\"", device.c_str()); /* free the sound config */ snd_config_delete(config); if (!InitializeHW(format) || !InitializeSW(format)) return false; snd_pcm_nonblock(m_pcm, 1); snd_pcm_prepare (m_pcm); m_format = format; m_formatSampleRateMul = 1.0 / (double)m_format.m_sampleRate; return true; }
/** * \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 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; }