Beispiel #1
0
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;
}
Beispiel #2
0
/**
 * \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;
}
Beispiel #3
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;
 }
Beispiel #4
0
/**
 * \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;
}
Beispiel #5
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 (_snd_conf_generic_id(id))
			continue;
		return -EINVAL;
	}
Beispiel #6
0
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));
}
Beispiel #7
0
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;
			}
		}
Beispiel #8
0
/*
 * 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);
	}
Beispiel #9
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;
		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;
		}
	}
Beispiel #11
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 (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;
	}
Beispiel #16
0
/* 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;
}
Beispiel #17
0
/**
 * \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;
}
Beispiel #18
0
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));

			}
		}
Beispiel #19
0
/**
 * \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;
}
Beispiel #20
0
 * \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;
	}
Beispiel #22
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;
	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;
	}