RFC: provide a device name list for applications

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

	here is my proposal to provide (a long waited feature) a device 
name list for applications (especially for GUI). The work is not finished, 
but the patch bellow gives already useful hints like (for PCM devices):

hw:CARD=Intel,DEV=0
hw:CARD=Intel,DEV=1
hw:CARD=Intel,DEV=2
hw:CARD=Intel,DEV=6
plughw:CARD=Intel,DEV=0
plughw:CARD=Intel,DEV=1
plughw:CARD=Intel,DEV=2
plughw:CARD=Intel,DEV=6
plug
shm
tee
file
null

	Things to do:

- provide device description behind '|' separator - add this description
  to configuration files
- some virtual devices does not make sense without arguments (like file) -
  add a list off switch 
- gather virtual devices from configuration files probably from
  namehint.pcm tree:

namehint.pcm [
	"file:FILE=/tmp/soundwave.raw|Save sound output to /tmp/soundwave.raw file"
	"plug:front|Do all conversions for front speakers"
]

- sorting / ordering of resulted hints? any hints from you? ;-) maybe add
  a wieght to config files?

						Jaroslav

diff -r cbe0a9529254 include/control.h
--- a/include/control.h	Fri Oct 06 15:22:34 2006 +0200
+++ b/include/control.h	Tue Oct 10 15:34:55 2006 +0200
@@ -213,6 +213,9 @@ int snd_card_get_index(const char *name)
 int snd_card_get_index(const char *name);
 int snd_card_get_name(int card, char **name);
 int snd_card_get_longname(int card, char **name);
+
+int snd_device_name_hint(int card, snd_ctl_elem_iface_t iface, char ***hints);
+int snd_device_name_free_hint(char **hints);
 
 int snd_ctl_open(snd_ctl_t **ctl, const char *name, int mode);
 int snd_ctl_open_lconf(snd_ctl_t **ctl, const char *name, int mode, snd_config_t *lconf);
@@ -256,6 +259,7 @@ snd_ctl_type_t snd_ctl_type(snd_ctl_t *c
 
 const char *snd_ctl_elem_type_name(snd_ctl_elem_type_t type);
 const char *snd_ctl_elem_iface_name(snd_ctl_elem_iface_t iface);
+const char *snd_ctl_iface_conf_name(snd_ctl_elem_iface_t iface);
 const char *snd_ctl_event_type_name(snd_ctl_event_type_t type);
 
 unsigned int snd_ctl_event_elem_get_mask(const snd_ctl_event_t *obj);
diff -r cbe0a9529254 include/local.h
--- a/include/local.h	Fri Oct 06 15:22:34 2006 +0200
+++ b/include/local.h	Tue Oct 10 15:34:55 2006 +0200
@@ -259,4 +259,8 @@ int snd_config_check_hop(snd_config_t *c
 int snd_config_check_hop(snd_config_t *conf);
 #define SND_CONF_MAX_HOPS	64
 
-#endif
+int snd_config_search_alias_hooks(snd_config_t *config,
+                                  const char *base, const char *key,
+				  snd_config_t **result);
+
+#endif
diff -r cbe0a9529254 src/Versions
--- a/src/Versions	Fri Oct 06 15:22:34 2006 +0200
+++ b/src/Versions	Tue Oct 10 15:34:55 2006 +0200
@@ -288,3 +288,11 @@ ALSA_1.0.12 {
     snd_hctl_elem_tlv_write;
     snd_hctl_elem_tlv_command;
 } ALSA_1.0.11;
+
+ALSA_1.0.14 {
+  global:
+
+    snd_device_name_hint;
+    snd_device_name_free_hint;
+    snd_ctl_iface_conf_name;
+} ALSA_1.0.12;
diff -r cbe0a9529254 src/conf.c
--- a/src/conf.c	Fri Oct 06 15:22:34 2006 +0200
+++ b/src/conf.c	Tue Oct 10 15:34:55 2006 +0200
@@ -3935,6 +3935,10 @@ int snd_config_expand(snd_config_t *conf
 	snd_config_t *defs, *subs = NULL, *res;
 	err = snd_config_search(config, "@args", &defs);
 	if (err < 0) {
+		if (args != NULL) {
+			SNDERR("Unknown parameters %s", args);
+			return -EINVAL;
+		}
 		err = snd_config_copy(&res, config);
 		if (err < 0)
 			return err;
diff -r cbe0a9529254 src/control/Makefile.am
--- a/src/control/Makefile.am	Fri Oct 06 15:22:34 2006 +0200
+++ b/src/control/Makefile.am	Tue Oct 10 15:34:55 2006 +0200
@@ -1,6 +1,6 @@ EXTRA_LTLIBRARIES = libcontrol.la
 EXTRA_LTLIBRARIES = libcontrol.la
 
-libcontrol_la_SOURCES = cards.c hcontrol.c \
+libcontrol_la_SOURCES = cards.c namehint.c hcontrol.c \
                         control.c control_hw.c control_shm.c \
 			control_ext.c setup.c control_symbols.c
 
diff -r cbe0a9529254 src/control/control.c
--- a/src/control/control.c	Fri Oct 06 15:22:34 2006 +0200
+++ b/src/control/control.c	Tue Oct 10 15:34:55 2006 +0200
@@ -950,6 +950,7 @@ int snd_ctl_open_lconf(snd_ctl_t **ctlp,
 #ifndef DOC_HIDDEN
 #define TYPE(v) [SND_CTL_ELEM_TYPE_##v] = #v
 #define IFACE(v) [SND_CTL_ELEM_IFACE_##v] = #v
+#define IFACE1(v, n) [SND_CTL_ELEM_IFACE_##v] = #n
 #define EVENT(v) [SND_CTL_EVENT_##v] = #v
 
 static const char *snd_ctl_elem_type_names[] = {
@@ -972,6 +973,16 @@ static const char *snd_ctl_elem_iface_na
 	IFACE(SEQUENCER),
 };
 
+static const char *snd_ctl_iface_conf_names[] = {
+	IFACE1(CARD, card),
+	IFACE1(HWDEP, hwdep),
+	IFACE1(MIXER, mixer),
+	IFACE1(PCM, pcm),
+	IFACE1(RAWMIDI, rawmidi),
+	IFACE1(TIMER, timer),
+	IFACE1(SEQUENCER, seq),
+};
+
 static const char *snd_ctl_event_type_names[] = {
 	EVENT(ELEM),
 };
@@ -997,6 +1008,17 @@ const char *snd_ctl_elem_iface_name(snd_
 {
 	assert(iface <= SND_CTL_ELEM_IFACE_LAST);
 	return snd_ctl_elem_iface_names[iface];
+}
+
+/**
+ * \brief get configuration name of related interface
+ * \param iface ala CTL interface identification
+ * \return ascii name of configuration interface
+ */
+const char *snd_ctl_iface_conf_name(snd_ctl_elem_iface_t iface)
+{
+	assert(iface <= SND_CTL_ELEM_IFACE_LAST);
+	return snd_ctl_iface_conf_names[iface];
 }
 
 /**
diff -r cbe0a9529254 test/Makefile.am
--- a/test/Makefile.am	Fri Oct 06 15:22:34 2006 +0200
+++ b/test/Makefile.am	Tue Oct 10 15:34:55 2006 +0200
@@ -1,6 +1,6 @@ check_PROGRAMS=control pcm pcm_min laten
 check_PROGRAMS=control pcm pcm_min latency seq \
 	       playmidi1 timer rawmidi midiloop \
-	       oldapi queue_timer
+	       oldapi queue_timer namehint
 
 control_LDADD=../src/libasound.la
 pcm_LDADD=../src/libasound.la
@@ -13,6 +13,7 @@ midiloop_LDADD=../src/libasound.la
 midiloop_LDADD=../src/libasound.la
 oldapi_LDADD=../src/libasound.la
 queue_timer_LDADD=../src/libasound.la
+namehint_LDADD=../src/libasound.la
 code_CFLAGS=-Wall -pipe -g -O2
 
 INCLUDES=-I$(top_srcdir)/include
diff -r cbe0a9529254 src/control/namehint.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/control/namehint.c	Tue Oct 10 15:34:55 2006 +0200
@@ -0,0 +1,264 @@
+/**
+ * \file control/namehint.c
+ * \brief Give device name hints
+ * \author Jaroslav Kysela <perex@xxxxxxx>
+ * \date 2006
+ */
+/*
+ *  Give device name hints  - main file
+ *  Copyright (c) 2006 by Jaroslav Kysela <perex@xxxxxxx>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as
+ *   published by the Free Software Foundation; either version 2.1 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include "local.h"
+
+struct hint_list {
+	char **list;
+	unsigned int count;
+	unsigned int allocated;
+};
+
+static int hint_list_add(struct hint_list *list,
+			 const char *name,
+			 const char *description)
+{
+	char *x;
+
+	if (list->count == list->allocated) {
+		char **n = realloc(list->list, (list->allocated + 10) * sizeof(char *));
+		if (n == NULL)
+			return -ENOMEM;
+		list->allocated += 10;
+		list->list = n;
+	}
+	if (name == NULL) {
+		x = NULL;
+	} else {
+		x = malloc(strlen(name) + (description != NULL ? (strlen(description) + 1) : 0) + 1);
+		if (x == NULL)
+			return -ENOMEM;
+		strcpy(x, name);
+		if (description != NULL) {
+			strcat(x, "|");
+			strcat(x, description);
+		}
+	}
+	list->list[list->count++] = x;
+	return 0;
+}
+
+static void zero_handler(const char *file ATTRIBUTE_UNUSED,
+			 int line ATTRIBUTE_UNUSED,
+			 const char *function ATTRIBUTE_UNUSED,
+			 int err ATTRIBUTE_UNUSED,
+			 const char *fmt ATTRIBUTE_UNUSED, ...)
+{
+}
+
+static int try_config(struct hint_list *list,
+		      const char *base,
+		      const char *fmt, ...)
+{
+	va_list arg;
+	snd_lib_error_handler_t eh;
+	snd_config_t *res;
+	char *buf = malloc(512);
+	int err;
+
+	if (buf == NULL)
+		return -ENOMEM;
+	va_start(arg, fmt);
+	vsnprintf(buf, 512, fmt, arg);
+	buf[512-1] = '\0';
+	va_end(arg);
+	eh = snd_lib_error;
+	snd_lib_error_set_handler(&zero_handler);		
+	err = snd_config_search_definition(snd_config, base, buf, &res);
+	snd_lib_error_set_handler(eh);
+	if (err < 0)
+		return err;
+	err = -EINVAL;
+	if (snd_config_get_type(res) != SND_CONFIG_TYPE_COMPOUND)
+		goto __cleanup;
+	if (snd_config_search(res, "type", NULL) < 0)
+		goto __cleanup;
+	err = 0;
+#if 0	/* for debug purposes */
+		{
+			snd_output_t *out;
+			printf("********* PCM '%s':\n", buf);
+			snd_output_stdio_attach(&out, stderr, 0);
+			snd_config_save(res, out);
+			snd_output_close(out);
+			printf("\n");
+		}
+#endif
+      __cleanup:
+      	snd_config_delete(res);
+      	if (err >= 0)
+	      	err = hint_list_add(list, buf, NULL);
+      	free(buf);
+	return err;
+}
+
+#ifndef DOC_HIDDEN
+#define IFACE(v, fcn) [SND_CTL_ELEM_IFACE_##v] = (next_devices_t)fcn
+
+typedef int (*next_devices_t)(snd_ctl_t *, int *);
+
+static next_devices_t next_devices[] = {
+	IFACE(CARD, NULL),
+	IFACE(HWDEP, snd_ctl_hwdep_next_device),
+	IFACE(MIXER, NULL),
+	IFACE(PCM, snd_ctl_pcm_next_device),
+	IFACE(RAWMIDI, snd_ctl_rawmidi_next_device),
+	IFACE(TIMER, NULL),
+	IFACE(SEQUENCER, NULL)
+};
+#endif
+
+static int add_card(struct hint_list *list, int card, snd_ctl_elem_iface_t iface)
+{
+	int err, first, ok;
+	snd_config_t *conf, *n;
+	snd_config_iterator_t i, next;
+	const char *str, *base;
+	snd_ctl_t *ctl;
+	char ctl_name[16];
+	snd_ctl_card_info_t *info;
+	
+	snd_ctl_card_info_alloca(&info);
+	if (iface > SND_CTL_ELEM_IFACE_LAST)
+		return -EINVAL;
+	if (snd_card_get_name(card, (char **)&str) < 0)
+		return 0;
+	base = snd_ctl_iface_conf_name(iface);
+	err = snd_config_search(snd_config, base, &conf);
+	if (err < 0)
+		return err;
+	sprintf(ctl_name, "hw:%i", card);
+	err = snd_ctl_open(&ctl, ctl_name, 0);
+	if (err < 0)
+		return err;
+	err = snd_ctl_card_info(ctl, info);
+	if (err < 0)
+		goto __error;
+	snd_config_for_each(i, next, conf) {
+		n = snd_config_iterator_entry(i);
+		if (snd_config_get_id(n, &str) < 0)
+			continue;
+		if (next_devices[iface] != NULL) {
+			first = -1;
+			err = next_devices[iface](ctl, &first);
+			if (first < 0)
+				err = -EINVAL;
+			ok = 0;
+			while (err >= 0 && first >= 0) {
+				err = try_config(list, base, "%s:CARD=%s,DEV=%i", str, snd_ctl_card_info_get_id(info), first);
+				if (err < 0)
+					break;
+				err = next_devices[iface](ctl, &first);
+				ok++;
+			}
+			if (ok)
+				continue;
+		} else {
+			err = -EINVAL;
+		}
+		if (err < 0)
+			err = try_config(list, base, "%s:CARD=%s", str, snd_ctl_card_info_get_id(info));
+		if (err < 0)
+			err = try_config(list, base, str);
+		if (err == -ENOMEM)
+			goto __error;
+	}
+	err = 0;
+      __error:
+      	if (err < 0)
+      		snd_ctl_close(ctl);
+	return err;
+}
+
+/**
+ * \brief Return string list with device name hints.
+ * \param card Card number or -1 (means all cards)
+ * \param iface Interface identification
+ * \param hints Result - array of string with device name hints
+ * \result zero if success, otherwise a negative error code
+ *
+ * Note: The device description is separated with '|' char.
+ */
+int snd_device_name_hint(int card, snd_ctl_elem_iface_t iface, char ***hints)
+{
+	struct hint_list list;
+	int err;
+
+	if (hints == NULL)
+		return -EINVAL;
+	err = snd_config_update();
+	if (err < 0)
+		return err;
+	list.list = NULL;
+	list.count = list.allocated = 0;
+	if (card >= 0) {
+		err = add_card(&list, card, iface);
+	} else {
+		err = snd_card_next(&card);
+		if (err < 0)
+			goto __error;
+		while (card >= 0) {
+			err = add_card(&list, card, iface);
+			if (err < 0)
+				goto __error;
+			err = snd_card_next(&card);
+			if (err < 0)
+				goto __error;
+		}
+	}
+      __error:
+      	if (err < 0) {
+      		snd_device_name_free_hint(list.list);
+      		return err;
+      	} else {
+      		err = hint_list_add(&list, NULL, NULL);
+      		if (err < 0)
+      			goto __error;
+      		*hints = list.list;
+	}
+      	return 0;
+}
+
+/**
+ * \brief Free a string list with device name hints.
+ * \param name Result - card long name corresponding to card number
+ * \result zero if success, otherwise a negative error code
+ */
+int snd_device_name_free_hint(char **hints)
+{
+	char **h;
+
+	if (hints == NULL)
+		return 0;
+	h = hints;
+	while (*h) {
+		free(*h);
+		h++;
+	}
+	free(hints);
+	return 0;
+}
diff -r cbe0a9529254 test/namehint.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/namehint.c	Tue Oct 10 15:34:55 2006 +0200
@@ -0,0 +1,28 @@
+#include "../include/asoundlib.h"
+#include <err.h>
+
+int main(int argc, char *argv[])
+{
+	const char *iface = "pcm";
+	snd_ctl_elem_iface_t niface;
+	char **hints, **n;
+	int err;
+
+	if (argc > 1)
+		iface = argv[1];
+	for (niface = 0; niface < SND_CTL_ELEM_IFACE_LAST; niface++)
+		if (strcmp(snd_ctl_iface_conf_name(niface), iface) == 0)
+			break;
+	if (niface > SND_CTL_ELEM_IFACE_LAST)
+		errx(1, "interface %s dnoes not exist", iface);
+	err = snd_device_name_hint(-1, niface, &hints);
+	if (err < 0)
+		errx(1, "snd_device_name_hint error: %s", snd_strerror(err));
+	n = hints;
+	while (*n != NULL) {
+		printf("%s\n", *n);
+		n++;
+	}
+	snd_device_name_free_hint(hints);
+	return 0;
+}

-----
Jaroslav Kysela <perex@xxxxxxx>
Linux Kernel Sound Maintainer
ALSA Project, SUSE Labs

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/alsa-devel

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux