All of lore.kernel.org
 help / color / mirror / Atom feed
* Allow alsa configuration to be loaded from a alsa.conf.d folder
@ 2011-09-11 12:40 gmane
  2011-09-11 12:40 ` [PATCH] conf: Allow for a directory to be given as a config file gmane
  2011-09-13 21:03 ` Allow alsa configuration to be loaded from a alsa.conf.d folder v2 gmane
  0 siblings, 2 replies; 12+ messages in thread
From: gmane @ 2011-09-11 12:40 UTC (permalink / raw)
  To: alsa-devel

Hi,

This is a small patch for alsa-lib that supports the common ".d" folder
configs.

The idea here is to make it easier for packagers and distros to supply
plugin configuration without having to patch alsa-lib to do so (or
by managing a /etc/asound.conf file which may want to be tweaked by multiple
files)

If this patch is accepted, I'll modify alsa-plugins to inlcude a
pulseaudio.conf file in /usr/share/alsa/alsa.conf.d/ which defines
a pcm.pulse anc ctl.pulse. If distros want to default to PA, they should
include their own file in there that defines pcm|ctl.!default appropriately.

Similar configuration could be added for third party alsa plugins such as
the DTS encoder plugin being developed by Alexander Patrikov which are
shipped outside of alsa.

I don't think there is anything too controversial in here, so hopefully it'll
be accepted.

Cheers

Col

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH] conf: Allow for a directory to be given as a config file.
  2011-09-11 12:40 Allow alsa configuration to be loaded from a alsa.conf.d folder gmane
@ 2011-09-11 12:40 ` gmane
  2011-09-12  6:57   ` Jaroslav Kysela
  2011-09-13 21:03 ` Allow alsa configuration to be loaded from a alsa.conf.d folder v2 gmane
  1 sibling, 1 reply; 12+ messages in thread
From: gmane @ 2011-09-11 12:40 UTC (permalink / raw)
  To: alsa-devel; +Cc: Colin Guthrie

From: Colin Guthrie <colin@mageia.org>

When this is done, *.conf files can be placed in that directory and they
will be processed by as if they were included directly.

A directory (typically /usr/share/alsa/alsa.conf.d/) has been
added into the distribution.
---
 configure.in                     |    4 +-
 src/conf.c                       |   75 ++++-
 src/conf/Makefile.am             |    2 +-
 src/conf/alsa.conf               |  611 -------------------------------------
 src/conf/alsa.conf.d/Makefile.am |    8 +
 src/conf/alsa.conf.d/README      |    3 +
 src/conf/alsa.conf.in            |  612 ++++++++++++++++++++++++++++++++++++++
 7 files changed, 694 insertions(+), 621 deletions(-)
 delete mode 100644 src/conf/alsa.conf
 create mode 100644 src/conf/alsa.conf.d/Makefile.am
 create mode 100644 src/conf/alsa.conf.d/README
 create mode 100644 src/conf/alsa.conf.in

diff --git a/configure.in b/configure.in
index 7ee0ccc..ead0e6f 100644
--- a/configure.in
+++ b/configure.in
@@ -610,13 +610,15 @@ if test ! -L "$srcdir"/include/alsa ; then
   ln -sf . "$srcdir"/include/alsa
 fi
 
+AC_CONFIG_FILES([src/conf/alsa.conf:src/conf/alsa.conf.in])
 AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \
 	  include/Makefile include/sound/Makefile src/Versions src/Makefile \
           src/control/Makefile src/mixer/Makefile \
 	  src/pcm/Makefile src/pcm/scopes/Makefile \
 	  src/rawmidi/Makefile src/timer/Makefile \
           src/hwdep/Makefile src/seq/Makefile src/ucm/Makefile \
-          src/compat/Makefile src/alisp/Makefile src/conf/Makefile \
+          src/compat/Makefile src/alisp/Makefile \
+	  src/conf/Makefile src/conf/alsa.conf.d/Makefile \
 	  src/conf/cards/Makefile \
 	  src/conf/pcm/Makefile \
 	  modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile \
diff --git a/src/conf.c b/src/conf.c
index ddefff6..9b1169b 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -417,6 +417,7 @@ beginning:</P>
 #include <stdarg.h>
 #include <limits.h>
 #include <sys/stat.h>
+#include <dirent.h>
 #include <locale.h>
 #include "local.h"
 #ifdef HAVE_LIBPTHREAD
@@ -3373,6 +3374,25 @@ static int snd_config_hooks(snd_config_t *config, snd_config_t *private_data)
 	return err;
 }
 
+static int config_filename_filter(const struct dirent *dirent)
+{
+	size_t flen;
+
+	if (dirent == NULL)
+		return 0;
+	if (dirent->d_type == DT_DIR)
+		return 0;
+
+	flen = strlen(dirent->d_name);
+	if (flen <= 5)
+		return 0;
+
+	if (strncmp(&dirent->d_name[flen-5], ".conf", 5) == 0)
+		return 1;
+
+	return 0;
+}
+
 /**
  * \brief Loads and parses the given configurations files.
  * \param[in] root Handle to the root configuration node.
@@ -3458,18 +3478,57 @@ int snd_config_hook_load(snd_config_t *root, snd_config_t *config, snd_config_t
 	} while (hit);
 	for (idx = 0; idx < fi_count; idx++) {
 		snd_input_t *in;
+		struct stat st;
 		if (!errors && access(fi[idx].name, R_OK) < 0)
 			continue;
-		err = snd_input_stdio_open(&in, fi[idx].name, "r");
-		if (err >= 0) {
-			err = snd_config_load(root, in);
-			snd_input_close(in);
-			if (err < 0) {
-				SNDERR("%s may be old or corrupted: consider to remove or fix it", fi[idx].name);
-				goto _err;
+		if (stat(fi[idx].name, &st) < 0) {
+			SNDERR("cannot stat file/directory %s", fi[idx].name);
+			continue;
+		}
+		if (S_ISDIR(st.st_mode)) {
+			struct dirent **namelist;
+			int n;
+
+			n = scandir(fi[idx].name, &namelist, config_filename_filter, versionsort);
+			if (n > 0) {
+				int j;
+				err = 0;
+				for (j = 0; j < n; ++j) {
+					if (err >= 0) {
+						int sl = strlen(fi[idx].name) + strlen(namelist[j]->d_name) + 2;
+						char *filename = malloc(sl);
+						snprintf(filename, sl, "%s/%s", fi[idx].name, namelist[j]->d_name);
+						filename[sl-1] = '\0';
+
+						err = snd_input_stdio_open(&in, filename, "r");
+						if (err >= 0) {
+							err = snd_config_load(root, in);
+							snd_input_close(in);
+							if (err < 0)
+								SNDERR("%s may be old or corrupted: consider to remove or fix it", filename);
+						} else {
+							SNDERR("cannot access file %s", filename);
+						}
+						free(filename);
+					}
+					free(namelist[j]);
+				}
+				free(namelist);
+				if (err < 0)
+					goto _err;
 			}
 		} else {
-			SNDERR("cannot access file %s", fi[idx].name);
+			err = snd_input_stdio_open(&in, fi[idx].name, "r");
+			if (err >= 0) {
+				err = snd_config_load(root, in);
+				snd_input_close(in);
+				if (err < 0) {
+					SNDERR("%s may be old or corrupted: consider to remove or fix it", fi[idx].name);
+					goto _err;
+				}
+			} else {
+				SNDERR("cannot access file %s", fi[idx].name);
+			}
 		}
 	}
 	*dst = NULL;
diff --git a/src/conf/Makefile.am b/src/conf/Makefile.am
index 2e5d0bf..456454f 100644
--- a/src/conf/Makefile.am
+++ b/src/conf/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS=cards pcm
+SUBDIRS=cards pcm alsa.conf.d
 
 cfg_files = alsa.conf
 if BUILD_ALISP
diff --git a/src/conf/alsa.conf b/src/conf/alsa.conf
deleted file mode 100644
index a33c24e..0000000
--- a/src/conf/alsa.conf
+++ /dev/null
@@ -1,611 +0,0 @@
-#
-#  ALSA library configuration file
-#
-
-# pre-load the configuration files
-
-@hooks [
-	{
-		func load
-		files [
-			"/etc/asound.conf"
-			"~/.asoundrc"
-		]
-		errors false
-	}
-]
-
-# load card-specific configuration files (on request)
-
-cards.@hooks [
-	{
-		func load
-		files [
-			{
-				@func concat
-				strings [
-					{ @func datadir }
-					"/cards/aliases.conf"
-				]
-			}
-		]
-	}
-	{
-		func load_for_all_cards
-		files [
-			{
-				@func concat
-				strings [
-					{ @func datadir }
-					"/cards/"
-					{ @func private_string }
-					".conf"
-				]
-			}
-		]
-		errors false
-	}
-]
-
-#
-# defaults
-#
-
-# show all name hints also for definitions without hint {} section
-defaults.namehint.showall off
-# show just basic name hints
-defaults.namehint.basic on
-# show extended name hints
-defaults.namehint.extended off
-#
-defaults.ctl.card 0
-defaults.pcm.card 0
-defaults.pcm.device 0
-defaults.pcm.subdevice -1
-defaults.pcm.nonblock 1
-defaults.pcm.compat 0
-defaults.pcm.minperiodtime 5000		# in us
-defaults.pcm.ipc_key 5678293
-defaults.pcm.ipc_gid audio
-defaults.pcm.ipc_perm 0660
-defaults.pcm.dmix.max_periods 0
-defaults.pcm.dmix.rate 48000
-defaults.pcm.dmix.format "unchanged"
-defaults.pcm.dmix.card defaults.pcm.card
-defaults.pcm.dmix.device defaults.pcm.device
-defaults.pcm.dsnoop.card defaults.pcm.card
-defaults.pcm.dsnoop.device defaults.pcm.device
-defaults.pcm.front.card defaults.pcm.card
-defaults.pcm.front.device defaults.pcm.device
-defaults.pcm.rear.card defaults.pcm.card
-defaults.pcm.rear.device defaults.pcm.device
-defaults.pcm.center_lfe.card defaults.pcm.card
-defaults.pcm.center_lfe.device defaults.pcm.device
-defaults.pcm.side.card defaults.pcm.card
-defaults.pcm.side.device defaults.pcm.device
-defaults.pcm.surround40.card defaults.pcm.card
-defaults.pcm.surround40.device defaults.pcm.device
-defaults.pcm.surround41.card defaults.pcm.card
-defaults.pcm.surround41.device defaults.pcm.device
-defaults.pcm.surround50.card defaults.pcm.card
-defaults.pcm.surround50.device defaults.pcm.device
-defaults.pcm.surround51.card defaults.pcm.card
-defaults.pcm.surround51.device defaults.pcm.device
-defaults.pcm.surround71.card defaults.pcm.card
-defaults.pcm.surround71.device defaults.pcm.device
-defaults.pcm.iec958.card defaults.pcm.card
-defaults.pcm.iec958.device defaults.pcm.device
-defaults.pcm.modem.card defaults.pcm.card
-defaults.pcm.modem.device defaults.pcm.device
-# truncate files via file or tee PCM
-defaults.pcm.file_format	"raw"
-defaults.pcm.file_truncate	true
-defaults.rawmidi.card 0
-defaults.rawmidi.device 0
-defaults.rawmidi.subdevice -1
-defaults.hwdep.card 0
-defaults.hwdep.device 0
-defaults.timer.class 2
-defaults.timer.sclass 0
-defaults.timer.card 0
-defaults.timer.device 0
-defaults.timer.subdevice 0
-
-#
-#  PCM interface
-#
-
-# redirect to load-on-demand extended pcm definitions
-pcm.cards cards.pcm
-
-pcm.default cards.pcm.default
-pcm.sysdefault cards.pcm.default
-pcm.front cards.pcm.front
-pcm.rear cards.pcm.rear
-pcm.center_lfe cards.pcm.center_lfe
-pcm.side cards.pcm.side
-pcm.surround40 cards.pcm.surround40
-pcm.surround41 cards.pcm.surround41
-pcm.surround50 cards.pcm.surround50
-pcm.surround51 cards.pcm.surround51
-pcm.surround71 cards.pcm.surround71
-pcm.iec958 cards.pcm.iec958
-pcm.spdif iec958
-pcm.hdmi cards.pcm.hdmi
-pcm.dmix cards.pcm.dmix
-pcm.dsnoop cards.pcm.dsnoop
-pcm.modem cards.pcm.modem
-pcm.phoneline cards.pcm.phoneline
-
-pcm.hw {
-	@args [ CARD DEV SUBDEV ]
-	@args.CARD {
-		type string
-		default {
-			@func getenv
-			vars [
-				ALSA_PCM_CARD
-				ALSA_CARD
-			]
-			default {
-				@func refer
-				name defaults.pcm.card
-			}
-		}
-	}
-	@args.DEV {
-		type integer
-		default {
-			@func igetenv
-			vars [
-				ALSA_PCM_DEVICE
-			]
-			default {
-				@func refer
-				name defaults.pcm.device
-			}
-		}
-	}
-	@args.SUBDEV {
-		type integer
-		default {
-			@func refer
-			name defaults.pcm.subdevice
-		}
-	}		
-	type hw
-	card $CARD
-	device $DEV
-	subdevice $SUBDEV
-	hint {
-		show {
-			@func refer
-			name defaults.namehint.extended
-		}
-		description "Direct hardware device without any conversions"
-	}
-}
-
-pcm.plughw {
-	@args [ CARD DEV SUBDEV ]
-	@args.CARD {
-		type string
-		default {
-			@func getenv
-			vars [
-				ALSA_PCM_CARD
-				ALSA_CARD
-			]
-			default {
-				@func refer
-				name defaults.pcm.card
-			}
-		}
-	}
-	@args.DEV {
-		type integer
-		default {
-			@func igetenv
-			vars [
-				ALSA_PCM_DEVICE
-			]
-			default {
-				@func refer
-				name defaults.pcm.device
-			}
-		}
-	}
-	@args.SUBDEV {
-		type integer
-		default {
-			@func refer
-			name defaults.pcm.subdevice
-		}
-	}		
-	type plug
-	slave.pcm {
-		type hw
-		card $CARD
-		device $DEV
-		subdevice $SUBDEV
-	}
-	hint {
-		show {
-			@func refer
-			name defaults.namehint.extended
-		}
-		description "Hardware device with all software conversions"
-	}
-}
-
-pcm.plug {
-	@args [ SLAVE ]
-	@args.SLAVE {
-		type string
-	}
-	type plug
-	slave.pcm $SLAVE
-}
-
-pcm.shm {
-	@args [ SOCKET PCM ]
-	@args.SOCKET {
-		type string
-	}
-	@args.PCM {
-		type string
-	}
-	type shm
-	server $SOCKET
-	pcm $PCM
-}
-
-pcm.tee {
-	@args [ SLAVE FILE FORMAT ]
-	@args.SLAVE {
-		type string
-	}
-	@args.FILE {
-		type string
-	}
-	@args.FORMAT {
-		type string
-		default {
-			@func refer
-			name defaults.pcm.file_format
-		}
-	}
-	type file
-	slave.pcm $SLAVE
-	file $FILE
-	format $FORMAT
-	truncate {
-		@func refer
-		name defaults.pcm.file_truncate
-	}
-}
-
-pcm.file {
-	@args [ FILE FORMAT ]
-	@args.FILE {
-		type string
-	}
-	@args.FORMAT {
-		type string
-		default {
-			@func refer
-			name defaults.pcm.file_format
-		}
-	}
-	type file
-	slave.pcm null
-	file $FILE
-	format $FORMAT
-	truncate {
-		@func refer
-		name defaults.pcm.file_truncate
-	}
-}
-
-pcm.null {
-	type null
-	hint {
-		show {
-			@func refer
-			name defaults.namehint.basic
-		}
-		description "Discard all samples (playback) or generate zero samples (capture)"
-	}
-}
-
-#
-#  Control interface
-#
-	
-ctl.sysdefault {
-	type hw
-	card {
-		@func getenv
-		vars [
-			ALSA_CTL_CARD
-			ALSA_CARD
-		]
-		default {
-			@func refer
-			name defaults.ctl.card
-		}
-	}
-}
-ctl.default ctl.sysdefault
-
-ctl.hw {
-	@args [ CARD ]
-	@args.CARD {
-		type string
-		default {
-			@func getenv
-			vars [
-				ALSA_CTL_CARD
-				ALSA_CARD
-			]
-			default {
-				@func refer
-				name defaults.ctl.card
-			}
-		}
-	}
-	type hw
-	card $CARD
-}
-
-ctl.shm {
-	@args [ SOCKET CTL ]
-	@args.SOCKET {
-		type string
-	}
-	@args.CTL {
-		type string
-	}
-	type shm
-	server $SOCKET
-	ctl $CTL
-}
-
-#
-#  RawMidi interface
-#
-
-rawmidi.default {
-	type hw
-	card {
-		@func getenv
-		vars [
-			ALSA_RAWMIDI_CARD
-			ALSA_CARD
-		]
-		default {
-			@func refer
-			name defaults.rawmidi.card
-		}
-	}
-	device {
-		@func igetenv
-		vars [
-			ALSA_RAWMIDI_DEVICE
-		]
-		default {
-			@func refer
-			name defaults.rawmidi.device
-		}
-	}
-}
-
-rawmidi.hw {
-	@args [ CARD DEV SUBDEV ]
-	@args.CARD {
-		type string
-		default {
-			@func getenv
-			vars [
-				ALSA_RAWMIDI_CARD
-				ALSA_CARD
-			]
-			default {
-				@func refer
-				name defaults.rawmidi.card
-			}
-		}
-	}
-	@args.DEV {
-		type integer
-		default {
-			@func igetenv
-			vars [
-				ALSA_RAWMIDI_DEVICE
-			]
-			default {
-				@func refer
-				name defaults.rawmidi.device
-			}
-		}
-	}
-	@args.SUBDEV {
-		type integer
-		default -1
-	}
-	type hw
-	card $CARD
-	device $DEV
-	subdevice $SUBDEV
-	hint {
-		description "Direct rawmidi driver device"
-		device $DEV
-	}
-}
-
-rawmidi.virtual {
-	@args [ MERGE ]
-	@args.MERGE {
-		type string
-		default 1
-	}
-	type virtual
-	merge $MERGE
-}
-
-#
-#  Sequencer interface
-#
-
-seq.default {
-	type hw
-}
-
-seq.hw {
-	type hw
-}
-
-#
-#  HwDep interface
-#
-
-hwdep.default {
-	type hw
-	card {
-		@func getenv
-		vars [
-			ALSA_HWDEP_CARD
-			ALSA_CARD
-		]
-		default {
-			@func refer
-			name defaults.hwdep.card
-		}
-	}
-	device {
-		@func igetenv
-		vars [
-			ALSA_HWDEP_DEVICE
-		]
-		default {
-			@func refer
-			name defaults.hwdep.device
-		}
-	}
-}
-
-hwdep.hw {
-	@args [ CARD DEV ]
-	@args.CARD {
-		type string
-		default {
-			@func getenv
-			vars [
-				ALSA_HWDEP_CARD
-				ALSA_CARD
-			]
-			default {
-				@func refer
-				name defaults.hwdep.card
-			}
-		}
-	}
-	@args.DEV {
-		type integer
-		default {
-			@func igetenv
-			vars [
-				ALSA_HWDEP_DEVICE
-			]
-			default {
-				@func refer
-				name defaults.hwdep.device
-			}
-		}
-	}
-	type hw
-	card $CARD
-	device $DEV
-}
-
-#
-#  Timer interface
-#
-
-timer_query.default {
-	type hw
-}
-
-timer_query.hw {
-	type hw
-}
-
-timer.default {
-	type hw
-	class {
-		@func refer
-		name defaults.timer.class
-	}
-	sclass {
-		@func refer
-		name defaults.timer.sclass
-	}
-	card {
-		@func refer
-		name defaults.timer.card
-	}
-	device {
-		@func refer
-		name defaults.timer.device
-	}
-	subdevice {
-		@func refer
-		name defaults.timer.subdevice
-	}
-	hint.description "Default direct hardware timer device"
-}
-
-timer.hw {
-	@args [ CLASS SCLASS CARD DEV SUBDEV ]
-	@args.CLASS {
-		type integer
-		default {
-			@func refer
-			name defaults.timer.class
-		}
-	}
-	@args.SCLASS {
-		type integer
-		default {
-			@func refer
-			name defaults.timer.sclass
-		}
-	}
-	@args.CARD {
-		type string
-		default {
-			@func refer
-			name defaults.timer.card
-		}
-	}
-	@args.DEV {
-		type integer
-		default {
-			@func refer
-			name defaults.timer.device
-		}
-	}
-	@args.SUBDEV {
-		type integer
-		default {
-			@func refer
-			name defaults.timer.subdevice
-		}
-	}
-	type hw
-	class $CLASS
-	sclass $SCLASS
-	card $CARD
-	device $DEV
-	subdevice $SUBDEV
-}
diff --git a/src/conf/alsa.conf.d/Makefile.am b/src/conf/alsa.conf.d/Makefile.am
new file mode 100644
index 0000000..c91661e
--- /dev/null
+++ b/src/conf/alsa.conf.d/Makefile.am
@@ -0,0 +1,8 @@
+alsaconfigdir = @ALSA_CONFIG_DIR@
+alsadir = $(alsaconfigdir)/alsa.conf.d
+cfg_files = README
+
+alsa_DATA = $(cfg_files)
+
+EXTRA_DIST = \
+	$(cfg_files)
diff --git a/src/conf/alsa.conf.d/README b/src/conf/alsa.conf.d/README
new file mode 100644
index 0000000..04b3fdb
--- /dev/null
+++ b/src/conf/alsa.conf.d/README
@@ -0,0 +1,3 @@
+You can place files named *.conf in this folder and they will be processed
+when initialising alsa-lib
+
diff --git a/src/conf/alsa.conf.in b/src/conf/alsa.conf.in
new file mode 100644
index 0000000..de68bc3
--- /dev/null
+++ b/src/conf/alsa.conf.in
@@ -0,0 +1,612 @@
+#
+#  ALSA library configuration file
+#
+
+# pre-load the configuration files
+
+@hooks [
+	{
+		func load
+		files [
+			"@ALSA_CONFIG_DIR@/alsa.conf.d/"
+			"/etc/asound.conf"
+			"~/.asoundrc"
+		]
+		errors false
+	}
+]
+
+# load card-specific configuration files (on request)
+
+cards.@hooks [
+	{
+		func load
+		files [
+			{
+				@func concat
+				strings [
+					{ @func datadir }
+					"/cards/aliases.conf"
+				]
+			}
+		]
+	}
+	{
+		func load_for_all_cards
+		files [
+			{
+				@func concat
+				strings [
+					{ @func datadir }
+					"/cards/"
+					{ @func private_string }
+					".conf"
+				]
+			}
+		]
+		errors false
+	}
+]
+
+#
+# defaults
+#
+
+# show all name hints also for definitions without hint {} section
+defaults.namehint.showall off
+# show just basic name hints
+defaults.namehint.basic on
+# show extended name hints
+defaults.namehint.extended off
+#
+defaults.ctl.card 0
+defaults.pcm.card 0
+defaults.pcm.device 0
+defaults.pcm.subdevice -1
+defaults.pcm.nonblock 1
+defaults.pcm.compat 0
+defaults.pcm.minperiodtime 5000		# in us
+defaults.pcm.ipc_key 5678293
+defaults.pcm.ipc_gid audio
+defaults.pcm.ipc_perm 0660
+defaults.pcm.dmix.max_periods 0
+defaults.pcm.dmix.rate 48000
+defaults.pcm.dmix.format "unchanged"
+defaults.pcm.dmix.card defaults.pcm.card
+defaults.pcm.dmix.device defaults.pcm.device
+defaults.pcm.dsnoop.card defaults.pcm.card
+defaults.pcm.dsnoop.device defaults.pcm.device
+defaults.pcm.front.card defaults.pcm.card
+defaults.pcm.front.device defaults.pcm.device
+defaults.pcm.rear.card defaults.pcm.card
+defaults.pcm.rear.device defaults.pcm.device
+defaults.pcm.center_lfe.card defaults.pcm.card
+defaults.pcm.center_lfe.device defaults.pcm.device
+defaults.pcm.side.card defaults.pcm.card
+defaults.pcm.side.device defaults.pcm.device
+defaults.pcm.surround40.card defaults.pcm.card
+defaults.pcm.surround40.device defaults.pcm.device
+defaults.pcm.surround41.card defaults.pcm.card
+defaults.pcm.surround41.device defaults.pcm.device
+defaults.pcm.surround50.card defaults.pcm.card
+defaults.pcm.surround50.device defaults.pcm.device
+defaults.pcm.surround51.card defaults.pcm.card
+defaults.pcm.surround51.device defaults.pcm.device
+defaults.pcm.surround71.card defaults.pcm.card
+defaults.pcm.surround71.device defaults.pcm.device
+defaults.pcm.iec958.card defaults.pcm.card
+defaults.pcm.iec958.device defaults.pcm.device
+defaults.pcm.modem.card defaults.pcm.card
+defaults.pcm.modem.device defaults.pcm.device
+# truncate files via file or tee PCM
+defaults.pcm.file_format	"raw"
+defaults.pcm.file_truncate	true
+defaults.rawmidi.card 0
+defaults.rawmidi.device 0
+defaults.rawmidi.subdevice -1
+defaults.hwdep.card 0
+defaults.hwdep.device 0
+defaults.timer.class 2
+defaults.timer.sclass 0
+defaults.timer.card 0
+defaults.timer.device 0
+defaults.timer.subdevice 0
+
+#
+#  PCM interface
+#
+
+# redirect to load-on-demand extended pcm definitions
+pcm.cards cards.pcm
+
+pcm.default cards.pcm.default
+pcm.sysdefault cards.pcm.default
+pcm.front cards.pcm.front
+pcm.rear cards.pcm.rear
+pcm.center_lfe cards.pcm.center_lfe
+pcm.side cards.pcm.side
+pcm.surround40 cards.pcm.surround40
+pcm.surround41 cards.pcm.surround41
+pcm.surround50 cards.pcm.surround50
+pcm.surround51 cards.pcm.surround51
+pcm.surround71 cards.pcm.surround71
+pcm.iec958 cards.pcm.iec958
+pcm.spdif iec958
+pcm.hdmi cards.pcm.hdmi
+pcm.dmix cards.pcm.dmix
+pcm.dsnoop cards.pcm.dsnoop
+pcm.modem cards.pcm.modem
+pcm.phoneline cards.pcm.phoneline
+
+pcm.hw {
+	@args [ CARD DEV SUBDEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_PCM_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.device
+			}
+		}
+	}
+	@args.SUBDEV {
+		type integer
+		default {
+			@func refer
+			name defaults.pcm.subdevice
+		}
+	}		
+	type hw
+	card $CARD
+	device $DEV
+	subdevice $SUBDEV
+	hint {
+		show {
+			@func refer
+			name defaults.namehint.extended
+		}
+		description "Direct hardware device without any conversions"
+	}
+}
+
+pcm.plughw {
+	@args [ CARD DEV SUBDEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_PCM_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.pcm.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_PCM_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.pcm.device
+			}
+		}
+	}
+	@args.SUBDEV {
+		type integer
+		default {
+			@func refer
+			name defaults.pcm.subdevice
+		}
+	}		
+	type plug
+	slave.pcm {
+		type hw
+		card $CARD
+		device $DEV
+		subdevice $SUBDEV
+	}
+	hint {
+		show {
+			@func refer
+			name defaults.namehint.extended
+		}
+		description "Hardware device with all software conversions"
+	}
+}
+
+pcm.plug {
+	@args [ SLAVE ]
+	@args.SLAVE {
+		type string
+	}
+	type plug
+	slave.pcm $SLAVE
+}
+
+pcm.shm {
+	@args [ SOCKET PCM ]
+	@args.SOCKET {
+		type string
+	}
+	@args.PCM {
+		type string
+	}
+	type shm
+	server $SOCKET
+	pcm $PCM
+}
+
+pcm.tee {
+	@args [ SLAVE FILE FORMAT ]
+	@args.SLAVE {
+		type string
+	}
+	@args.FILE {
+		type string
+	}
+	@args.FORMAT {
+		type string
+		default {
+			@func refer
+			name defaults.pcm.file_format
+		}
+	}
+	type file
+	slave.pcm $SLAVE
+	file $FILE
+	format $FORMAT
+	truncate {
+		@func refer
+		name defaults.pcm.file_truncate
+	}
+}
+
+pcm.file {
+	@args [ FILE FORMAT ]
+	@args.FILE {
+		type string
+	}
+	@args.FORMAT {
+		type string
+		default {
+			@func refer
+			name defaults.pcm.file_format
+		}
+	}
+	type file
+	slave.pcm null
+	file $FILE
+	format $FORMAT
+	truncate {
+		@func refer
+		name defaults.pcm.file_truncate
+	}
+}
+
+pcm.null {
+	type null
+	hint {
+		show {
+			@func refer
+			name defaults.namehint.basic
+		}
+		description "Discard all samples (playback) or generate zero samples (capture)"
+	}
+}
+
+#
+#  Control interface
+#
+	
+ctl.sysdefault {
+	type hw
+	card {
+		@func getenv
+		vars [
+			ALSA_CTL_CARD
+			ALSA_CARD
+		]
+		default {
+			@func refer
+			name defaults.ctl.card
+		}
+	}
+}
+ctl.default ctl.sysdefault
+
+ctl.hw {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_CTL_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.ctl.card
+			}
+		}
+	}
+	type hw
+	card $CARD
+}
+
+ctl.shm {
+	@args [ SOCKET CTL ]
+	@args.SOCKET {
+		type string
+	}
+	@args.CTL {
+		type string
+	}
+	type shm
+	server $SOCKET
+	ctl $CTL
+}
+
+#
+#  RawMidi interface
+#
+
+rawmidi.default {
+	type hw
+	card {
+		@func getenv
+		vars [
+			ALSA_RAWMIDI_CARD
+			ALSA_CARD
+		]
+		default {
+			@func refer
+			name defaults.rawmidi.card
+		}
+	}
+	device {
+		@func igetenv
+		vars [
+			ALSA_RAWMIDI_DEVICE
+		]
+		default {
+			@func refer
+			name defaults.rawmidi.device
+		}
+	}
+}
+
+rawmidi.hw {
+	@args [ CARD DEV SUBDEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_RAWMIDI_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.rawmidi.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_RAWMIDI_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.rawmidi.device
+			}
+		}
+	}
+	@args.SUBDEV {
+		type integer
+		default -1
+	}
+	type hw
+	card $CARD
+	device $DEV
+	subdevice $SUBDEV
+	hint {
+		description "Direct rawmidi driver device"
+		device $DEV
+	}
+}
+
+rawmidi.virtual {
+	@args [ MERGE ]
+	@args.MERGE {
+		type string
+		default 1
+	}
+	type virtual
+	merge $MERGE
+}
+
+#
+#  Sequencer interface
+#
+
+seq.default {
+	type hw
+}
+
+seq.hw {
+	type hw
+}
+
+#
+#  HwDep interface
+#
+
+hwdep.default {
+	type hw
+	card {
+		@func getenv
+		vars [
+			ALSA_HWDEP_CARD
+			ALSA_CARD
+		]
+		default {
+			@func refer
+			name defaults.hwdep.card
+		}
+	}
+	device {
+		@func igetenv
+		vars [
+			ALSA_HWDEP_DEVICE
+		]
+		default {
+			@func refer
+			name defaults.hwdep.device
+		}
+	}
+}
+
+hwdep.hw {
+	@args [ CARD DEV ]
+	@args.CARD {
+		type string
+		default {
+			@func getenv
+			vars [
+				ALSA_HWDEP_CARD
+				ALSA_CARD
+			]
+			default {
+				@func refer
+				name defaults.hwdep.card
+			}
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func igetenv
+			vars [
+				ALSA_HWDEP_DEVICE
+			]
+			default {
+				@func refer
+				name defaults.hwdep.device
+			}
+		}
+	}
+	type hw
+	card $CARD
+	device $DEV
+}
+
+#
+#  Timer interface
+#
+
+timer_query.default {
+	type hw
+}
+
+timer_query.hw {
+	type hw
+}
+
+timer.default {
+	type hw
+	class {
+		@func refer
+		name defaults.timer.class
+	}
+	sclass {
+		@func refer
+		name defaults.timer.sclass
+	}
+	card {
+		@func refer
+		name defaults.timer.card
+	}
+	device {
+		@func refer
+		name defaults.timer.device
+	}
+	subdevice {
+		@func refer
+		name defaults.timer.subdevice
+	}
+	hint.description "Default direct hardware timer device"
+}
+
+timer.hw {
+	@args [ CLASS SCLASS CARD DEV SUBDEV ]
+	@args.CLASS {
+		type integer
+		default {
+			@func refer
+			name defaults.timer.class
+		}
+	}
+	@args.SCLASS {
+		type integer
+		default {
+			@func refer
+			name defaults.timer.sclass
+		}
+	}
+	@args.CARD {
+		type string
+		default {
+			@func refer
+			name defaults.timer.card
+		}
+	}
+	@args.DEV {
+		type integer
+		default {
+			@func refer
+			name defaults.timer.device
+		}
+	}
+	@args.SUBDEV {
+		type integer
+		default {
+			@func refer
+			name defaults.timer.subdevice
+		}
+	}
+	type hw
+	class $CLASS
+	sclass $SCLASS
+	card $CARD
+	device $DEV
+	subdevice $SUBDEV
+}
-- 
1.7.6

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] conf: Allow for a directory to be given as a config file.
  2011-09-11 12:40 ` [PATCH] conf: Allow for a directory to be given as a config file gmane
@ 2011-09-12  6:57   ` Jaroslav Kysela
  2011-09-12  8:23     ` Colin Guthrie
  2011-09-13 21:00     ` Colin Guthrie
  0 siblings, 2 replies; 12+ messages in thread
From: Jaroslav Kysela @ 2011-09-12  6:57 UTC (permalink / raw)
  To: gmane; +Cc: Colin Guthrie, alsa-devel

Date 11.9.2011 14:40, gmane@colin.guthr.ie wrote:
> From: Colin Guthrie <colin@mageia.org>
> 
> When this is done, *.conf files can be placed in that directory and they
> will be processed by as if they were included directly.
> 
> A directory (typically /usr/share/alsa/alsa.conf.d/) has been
> added into the distribution.

Thanks for this patch.


> +@hooks [
> +	{
> +		func load
> +		files [
> +			"@ALSA_CONFIG_DIR@/alsa.conf.d/"

I think that it might be more flexible and analogical to keep the
original configuration file and implement the confdir function - see the
datadir example.

Implemented:

	"{ @func datadir }"

To be added:

	"{ @func confdir }"

See snd_func_datadir() in confmisc.c.

					Jaroslav

-- 
Jaroslav Kysela <perex@perex.cz>
Linux Kernel Sound Maintainer
ALSA Project; Red Hat, Inc.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] conf: Allow for a directory to be given as a config file.
  2011-09-12  6:57   ` Jaroslav Kysela
@ 2011-09-12  8:23     ` Colin Guthrie
  2011-09-12  8:27       ` Takashi Iwai
  2011-09-13 21:00     ` Colin Guthrie
  1 sibling, 1 reply; 12+ messages in thread
From: Colin Guthrie @ 2011-09-12  8:23 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: alsa-devel

'Twas brillig, and Jaroslav Kysela at 12/09/11 07:57 did gyre and gimble:
> Date 11.9.2011 14:40, gmane@colin.guthr.ie wrote:
>> From: Colin Guthrie <colin@mageia.org>
>>
>> When this is done, *.conf files can be placed in that directory and they
>> will be processed by as if they were included directly.
>>
>> A directory (typically /usr/share/alsa/alsa.conf.d/) has been
>> added into the distribution.
> 
> Thanks for this patch.
> 
> 
>> +@hooks [
>> +	{
>> +		func load
>> +		files [
>> +			"@ALSA_CONFIG_DIR@/alsa.conf.d/"
> 
> I think that it might be more flexible and analogical to keep the
> original configuration file and implement the confdir function - see the
> datadir example.
> 
> Implemented:
> 
> 	"{ @func datadir }"
> 
> To be added:
> 
> 	"{ @func confdir }"
> 
> See snd_func_datadir() in confmisc.c.

Sure if you prefer it that way I can implement it. Seems a little overly
designed to me, but it should be easy enough to support.

Col


-- 

Colin Guthrie
gmane(at)colin.guthr.ie
http://colin.guthr.ie/

Day Job:
  Tribalogic Limited [http://www.tribalogic.net/]
Open Source:
  Mageia Contributor [http://www.mageia.org/]
  PulseAudio Hacker [http://www.pulseaudio.org/]
  Trac Hacker [http://trac.edgewall.org/]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] conf: Allow for a directory to be given as a config file.
  2011-09-12  8:23     ` Colin Guthrie
@ 2011-09-12  8:27       ` Takashi Iwai
  0 siblings, 0 replies; 12+ messages in thread
From: Takashi Iwai @ 2011-09-12  8:27 UTC (permalink / raw)
  To: Colin Guthrie; +Cc: alsa-devel

At Mon, 12 Sep 2011 09:23:15 +0100,
Colin Guthrie wrote:
> 
> 'Twas brillig, and Jaroslav Kysela at 12/09/11 07:57 did gyre and gimble:
> > Date 11.9.2011 14:40, gmane@colin.guthr.ie wrote:
> >> From: Colin Guthrie <colin@mageia.org>
> >>
> >> When this is done, *.conf files can be placed in that directory and they
> >> will be processed by as if they were included directly.
> >>
> >> A directory (typically /usr/share/alsa/alsa.conf.d/) has been
> >> added into the distribution.
> > 
> > Thanks for this patch.
> > 
> > 
> >> +@hooks [
> >> +	{
> >> +		func load
> >> +		files [
> >> +			"@ALSA_CONFIG_DIR@/alsa.conf.d/"
> > 
> > I think that it might be more flexible and analogical to keep the
> > original configuration file and implement the confdir function - see the
> > datadir example.
> > 
> > Implemented:
> > 
> > 	"{ @func datadir }"
> > 
> > To be added:
> > 
> > 	"{ @func confdir }"
> > 
> > See snd_func_datadir() in confmisc.c.
> 
> Sure if you prefer it that way I can implement it. Seems a little overly
> designed to me, but it should be easy enough to support.

The big difference is that you don't hard-code the path in the file.
Even without an addition of confdir, it can be represented like:

	{
		@func concat
		strings [
			{ @func datadir }
			"/alsa.conf.d/"
		]
	}

Takashi

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] conf: Allow for a directory to be given as a config file.
  2011-09-12  6:57   ` Jaroslav Kysela
  2011-09-12  8:23     ` Colin Guthrie
@ 2011-09-13 21:00     ` Colin Guthrie
  1 sibling, 0 replies; 12+ messages in thread
From: Colin Guthrie @ 2011-09-13 21:00 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: alsa-devel

'Twas brillig, and Jaroslav Kysela at 12/09/11 07:57 did gyre and gimble:
> Date 11.9.2011 14:40, gmane@colin.guthr.ie wrote:
>> From: Colin Guthrie <colin@mageia.org>
>>
>> When this is done, *.conf files can be placed in that directory and they
>> will be processed by as if they were included directly.
>>
>> A directory (typically /usr/share/alsa/alsa.conf.d/) has been
>> added into the distribution.
> 
> Thanks for this patch.
> 
> 
>> +@hooks [
>> +	{
>> +		func load
>> +		files [
>> +			"@ALSA_CONFIG_DIR@/alsa.conf.d/"
> 
> I think that it might be more flexible and analogical to keep the
> original configuration file and implement the confdir function - see the
> datadir example.
> 
> Implemented:
> 
> 	"{ @func datadir }"
> 
> To be added:
> 
> 	"{ @func confdir }"
> 
> See snd_func_datadir() in confmisc.c.
>

I had a look at the implementation of snd_func_datadir and it actually
returns ALSA_CONFIG_DIR already, so I actually don't need to do anything
special here, just use @func datadir and a bit of concatenation.

New patch coming up.

Col


-- 

Colin Guthrie
gmane(at)colin.guthr.ie
http://colin.guthr.ie/

Day Job:
  Tribalogic Limited [http://www.tribalogic.net/]
Open Source:
  Mageia Contributor [http://www.mageia.org/]
  PulseAudio Hacker [http://www.pulseaudio.org/]
  Trac Hacker [http://trac.edgewall.org/]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Allow alsa configuration to be loaded from a alsa.conf.d folder v2
  2011-09-11 12:40 Allow alsa configuration to be loaded from a alsa.conf.d folder gmane
  2011-09-11 12:40 ` [PATCH] conf: Allow for a directory to be given as a config file gmane
@ 2011-09-13 21:03 ` gmane
  2011-09-13 21:04   ` [PATCH] conf: Allow for a directory to be given as a config file gmane
  1 sibling, 1 reply; 12+ messages in thread
From: gmane @ 2011-09-13 21:03 UTC (permalink / raw)
  To: alsa-devel

2nd version of the patch without the need to use autotools to preprocess
alsa.conf.

This just reuses the "@func datadir" function used to load individual card
files a few lines below. I should have spotted this the first time round really.

Col

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH] conf: Allow for a directory to be given as a config file.
  2011-09-13 21:03 ` Allow alsa configuration to be loaded from a alsa.conf.d folder v2 gmane
@ 2011-09-13 21:04   ` gmane
  2011-09-16  6:51     ` Takashi Iwai
  0 siblings, 1 reply; 12+ messages in thread
From: gmane @ 2011-09-13 21:04 UTC (permalink / raw)
  To: alsa-devel; +Cc: Colin Guthrie

From: Colin Guthrie <colin@mageia.org>

When this is done, *.conf files can be placed in that directory and they
will be processed by as if they were included directly.

A directory (typically /usr/share/alsa/alsa.conf.d/) has been
added into the distribution.
---
 configure.in                     |    3 +-
 src/conf.c                       |   75 ++++++++++++++++++++++++++++++++++----
 src/conf/Makefile.am             |    2 +-
 src/conf/alsa.conf               |    7 ++++
 src/conf/alsa.conf.d/Makefile.am |    8 ++++
 src/conf/alsa.conf.d/README      |    2 +
 6 files changed, 87 insertions(+), 10 deletions(-)
 create mode 100644 src/conf/alsa.conf.d/Makefile.am
 create mode 100644 src/conf/alsa.conf.d/README

diff --git a/configure.in b/configure.in
index 7ee0ccc..13e38b8 100644
--- a/configure.in
+++ b/configure.in
@@ -616,7 +616,8 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \
 	  src/pcm/Makefile src/pcm/scopes/Makefile \
 	  src/rawmidi/Makefile src/timer/Makefile \
           src/hwdep/Makefile src/seq/Makefile src/ucm/Makefile \
-          src/compat/Makefile src/alisp/Makefile src/conf/Makefile \
+          src/compat/Makefile src/alisp/Makefile \
+	  src/conf/Makefile src/conf/alsa.conf.d/Makefile \
 	  src/conf/cards/Makefile \
 	  src/conf/pcm/Makefile \
 	  modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile \
diff --git a/src/conf.c b/src/conf.c
index ddefff6..9b1169b 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -417,6 +417,7 @@ beginning:</P>
 #include <stdarg.h>
 #include <limits.h>
 #include <sys/stat.h>
+#include <dirent.h>
 #include <locale.h>
 #include "local.h"
 #ifdef HAVE_LIBPTHREAD
@@ -3373,6 +3374,25 @@ static int snd_config_hooks(snd_config_t *config, snd_config_t *private_data)
 	return err;
 }
 
+static int config_filename_filter(const struct dirent *dirent)
+{
+	size_t flen;
+
+	if (dirent == NULL)
+		return 0;
+	if (dirent->d_type == DT_DIR)
+		return 0;
+
+	flen = strlen(dirent->d_name);
+	if (flen <= 5)
+		return 0;
+
+	if (strncmp(&dirent->d_name[flen-5], ".conf", 5) == 0)
+		return 1;
+
+	return 0;
+}
+
 /**
  * \brief Loads and parses the given configurations files.
  * \param[in] root Handle to the root configuration node.
@@ -3458,18 +3478,57 @@ int snd_config_hook_load(snd_config_t *root, snd_config_t *config, snd_config_t
 	} while (hit);
 	for (idx = 0; idx < fi_count; idx++) {
 		snd_input_t *in;
+		struct stat st;
 		if (!errors && access(fi[idx].name, R_OK) < 0)
 			continue;
-		err = snd_input_stdio_open(&in, fi[idx].name, "r");
-		if (err >= 0) {
-			err = snd_config_load(root, in);
-			snd_input_close(in);
-			if (err < 0) {
-				SNDERR("%s may be old or corrupted: consider to remove or fix it", fi[idx].name);
-				goto _err;
+		if (stat(fi[idx].name, &st) < 0) {
+			SNDERR("cannot stat file/directory %s", fi[idx].name);
+			continue;
+		}
+		if (S_ISDIR(st.st_mode)) {
+			struct dirent **namelist;
+			int n;
+
+			n = scandir(fi[idx].name, &namelist, config_filename_filter, versionsort);
+			if (n > 0) {
+				int j;
+				err = 0;
+				for (j = 0; j < n; ++j) {
+					if (err >= 0) {
+						int sl = strlen(fi[idx].name) + strlen(namelist[j]->d_name) + 2;
+						char *filename = malloc(sl);
+						snprintf(filename, sl, "%s/%s", fi[idx].name, namelist[j]->d_name);
+						filename[sl-1] = '\0';
+
+						err = snd_input_stdio_open(&in, filename, "r");
+						if (err >= 0) {
+							err = snd_config_load(root, in);
+							snd_input_close(in);
+							if (err < 0)
+								SNDERR("%s may be old or corrupted: consider to remove or fix it", filename);
+						} else {
+							SNDERR("cannot access file %s", filename);
+						}
+						free(filename);
+					}
+					free(namelist[j]);
+				}
+				free(namelist);
+				if (err < 0)
+					goto _err;
 			}
 		} else {
-			SNDERR("cannot access file %s", fi[idx].name);
+			err = snd_input_stdio_open(&in, fi[idx].name, "r");
+			if (err >= 0) {
+				err = snd_config_load(root, in);
+				snd_input_close(in);
+				if (err < 0) {
+					SNDERR("%s may be old or corrupted: consider to remove or fix it", fi[idx].name);
+					goto _err;
+				}
+			} else {
+				SNDERR("cannot access file %s", fi[idx].name);
+			}
 		}
 	}
 	*dst = NULL;
diff --git a/src/conf/Makefile.am b/src/conf/Makefile.am
index 2e5d0bf..456454f 100644
--- a/src/conf/Makefile.am
+++ b/src/conf/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS=cards pcm
+SUBDIRS=cards pcm alsa.conf.d
 
 cfg_files = alsa.conf
 if BUILD_ALISP
diff --git a/src/conf/alsa.conf b/src/conf/alsa.conf
index a33c24e..bc91df3 100644
--- a/src/conf/alsa.conf
+++ b/src/conf/alsa.conf
@@ -8,6 +8,13 @@
 	{
 		func load
 		files [
+			{
+				@func concat
+				strings [
+					{ @func datadir }
+					"/alsa.conf.d/"
+				]
+			}
 			"/etc/asound.conf"
 			"~/.asoundrc"
 		]
diff --git a/src/conf/alsa.conf.d/Makefile.am b/src/conf/alsa.conf.d/Makefile.am
new file mode 100644
index 0000000..c91661e
--- /dev/null
+++ b/src/conf/alsa.conf.d/Makefile.am
@@ -0,0 +1,8 @@
+alsaconfigdir = @ALSA_CONFIG_DIR@
+alsadir = $(alsaconfigdir)/alsa.conf.d
+cfg_files = README
+
+alsa_DATA = $(cfg_files)
+
+EXTRA_DIST = \
+	$(cfg_files)
diff --git a/src/conf/alsa.conf.d/README b/src/conf/alsa.conf.d/README
new file mode 100644
index 0000000..9997884
--- /dev/null
+++ b/src/conf/alsa.conf.d/README
@@ -0,0 +1,2 @@
+You can place files named *.conf in this folder and they will be processed
+when initialising alsa-lib.
-- 
1.7.6

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] conf: Allow for a directory to be given as a config file.
  2011-09-13 21:04   ` [PATCH] conf: Allow for a directory to be given as a config file gmane
@ 2011-09-16  6:51     ` Takashi Iwai
  2011-09-16  8:28       ` Colin Guthrie
  0 siblings, 1 reply; 12+ messages in thread
From: Takashi Iwai @ 2011-09-16  6:51 UTC (permalink / raw)
  To: gmane; +Cc: Colin Guthrie, alsa-devel

At Tue, 13 Sep 2011 22:04:00 +0100,
gmane@colin.guthr.ie wrote:
> 
> From: Colin Guthrie <colin@mageia.org>
> 
> When this is done, *.conf files can be placed in that directory and they
> will be processed by as if they were included directly.
> 
> A directory (typically /usr/share/alsa/alsa.conf.d/) has been
> added into the distribution.

In this code, the error behavior looks inconsistent.
In a config file case (no directory), the opening failure gives only
the error message but it continues.  In the case of directory, both
the open-error and the parse-error are treated as the fatal error.

OK, it's basically a mistake in the original code -- the open-error
should be handled as a fatal error more consistently.  But, still,
the old error code was overridden by the new entry, so the error in
the middle of the file-entry loop is ignored.  That looks no good.

And, the code becomes with too deep indentation.  This indicates
already something wrong.  Split a new function to handle the directory
case.  And create a small function to handle below code:

	err = snd_input_stdio_open(&in, filename, "r");
	if (err >= 0) {
		err = snd_config_load(root, in);
		snd_input_close(in);
		if (err < 0)
			SNDERR("%s may be old or corrupted: consider to remove or fix it", filename);
	} else
		SNDERR("cannot access file %s", filename);
	return err;

and use it from both a single file and files-in-directory cases.


thanks,

Takashi


> ---
>  configure.in                     |    3 +-
>  src/conf.c                       |   75 ++++++++++++++++++++++++++++++++++----
>  src/conf/Makefile.am             |    2 +-
>  src/conf/alsa.conf               |    7 ++++
>  src/conf/alsa.conf.d/Makefile.am |    8 ++++
>  src/conf/alsa.conf.d/README      |    2 +
>  6 files changed, 87 insertions(+), 10 deletions(-)
>  create mode 100644 src/conf/alsa.conf.d/Makefile.am
>  create mode 100644 src/conf/alsa.conf.d/README
> 
> diff --git a/configure.in b/configure.in
> index 7ee0ccc..13e38b8 100644
> --- a/configure.in
> +++ b/configure.in
> @@ -616,7 +616,8 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \
>  	  src/pcm/Makefile src/pcm/scopes/Makefile \
>  	  src/rawmidi/Makefile src/timer/Makefile \
>            src/hwdep/Makefile src/seq/Makefile src/ucm/Makefile \
> -          src/compat/Makefile src/alisp/Makefile src/conf/Makefile \
> +          src/compat/Makefile src/alisp/Makefile \
> +	  src/conf/Makefile src/conf/alsa.conf.d/Makefile \
>  	  src/conf/cards/Makefile \
>  	  src/conf/pcm/Makefile \
>  	  modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile \
> diff --git a/src/conf.c b/src/conf.c
> index ddefff6..9b1169b 100644
> --- a/src/conf.c
> +++ b/src/conf.c
> @@ -417,6 +417,7 @@ beginning:</P>
>  #include <stdarg.h>
>  #include <limits.h>
>  #include <sys/stat.h>
> +#include <dirent.h>
>  #include <locale.h>
>  #include "local.h"
>  #ifdef HAVE_LIBPTHREAD
> @@ -3373,6 +3374,25 @@ static int snd_config_hooks(snd_config_t *config, snd_config_t *private_data)
>  	return err;
>  }
>  
> +static int config_filename_filter(const struct dirent *dirent)
> +{
> +	size_t flen;
> +
> +	if (dirent == NULL)
> +		return 0;
> +	if (dirent->d_type == DT_DIR)
> +		return 0;
> +
> +	flen = strlen(dirent->d_name);
> +	if (flen <= 5)
> +		return 0;
> +
> +	if (strncmp(&dirent->d_name[flen-5], ".conf", 5) == 0)
> +		return 1;
> +
> +	return 0;
> +}
> +
>  /**
>   * \brief Loads and parses the given configurations files.
>   * \param[in] root Handle to the root configuration node.
> @@ -3458,18 +3478,57 @@ int snd_config_hook_load(snd_config_t *root, snd_config_t *config, snd_config_t
>  	} while (hit);
>  	for (idx = 0; idx < fi_count; idx++) {
>  		snd_input_t *in;
> +		struct stat st;
>  		if (!errors && access(fi[idx].name, R_OK) < 0)
>  			continue;
> -		err = snd_input_stdio_open(&in, fi[idx].name, "r");
> -		if (err >= 0) {
> -			err = snd_config_load(root, in);
> -			snd_input_close(in);
> -			if (err < 0) {
> -				SNDERR("%s may be old or corrupted: consider to remove or fix it", fi[idx].name);
> -				goto _err;
> +		if (stat(fi[idx].name, &st) < 0) {
> +			SNDERR("cannot stat file/directory %s", fi[idx].name);
> +			continue;
> +		}
> +		if (S_ISDIR(st.st_mode)) {
> +			struct dirent **namelist;
> +			int n;
> +
> +			n = scandir(fi[idx].name, &namelist, config_filename_filter, versionsort);
> +			if (n > 0) {
> +				int j;
> +				err = 0;
> +				for (j = 0; j < n; ++j) {
> +					if (err >= 0) {
> +						int sl = strlen(fi[idx].name) + strlen(namelist[j]->d_name) + 2;
> +						char *filename = malloc(sl);
> +						snprintf(filename, sl, "%s/%s", fi[idx].name, namelist[j]->d_name);
> +						filename[sl-1] = '\0';
> +
> +						err = snd_input_stdio_open(&in, filename, "r");
> +						if (err >= 0) {
> +							err = snd_config_load(root, in);
> +							snd_input_close(in);
> +							if (err < 0)
> +								SNDERR("%s may be old or corrupted: consider to remove or fix it", filename);
> +						} else {
> +							SNDERR("cannot access file %s", filename);
> +						}
> +						free(filename);
> +					}
> +					free(namelist[j]);
> +				}
> +				free(namelist);
> +				if (err < 0)
> +					goto _err;
>  			}
>  		} else {
> -			SNDERR("cannot access file %s", fi[idx].name);
> +			err = snd_input_stdio_open(&in, fi[idx].name, "r");
> +			if (err >= 0) {
> +				err = snd_config_load(root, in);
> +				snd_input_close(in);
> +				if (err < 0) {
> +					SNDERR("%s may be old or corrupted: consider to remove or fix it", fi[idx].name);
> +					goto _err;
> +				}
> +			} else {
> +				SNDERR("cannot access file %s", fi[idx].name);
> +			}
>  		}
>  	}
>  	*dst = NULL;
> diff --git a/src/conf/Makefile.am b/src/conf/Makefile.am
> index 2e5d0bf..456454f 100644
> --- a/src/conf/Makefile.am
> +++ b/src/conf/Makefile.am
> @@ -1,4 +1,4 @@
> -SUBDIRS=cards pcm
> +SUBDIRS=cards pcm alsa.conf.d
>  
>  cfg_files = alsa.conf
>  if BUILD_ALISP
> diff --git a/src/conf/alsa.conf b/src/conf/alsa.conf
> index a33c24e..bc91df3 100644
> --- a/src/conf/alsa.conf
> +++ b/src/conf/alsa.conf
> @@ -8,6 +8,13 @@
>  	{
>  		func load
>  		files [
> +			{
> +				@func concat
> +				strings [
> +					{ @func datadir }
> +					"/alsa.conf.d/"
> +				]
> +			}
>  			"/etc/asound.conf"
>  			"~/.asoundrc"
>  		]
> diff --git a/src/conf/alsa.conf.d/Makefile.am b/src/conf/alsa.conf.d/Makefile.am
> new file mode 100644
> index 0000000..c91661e
> --- /dev/null
> +++ b/src/conf/alsa.conf.d/Makefile.am
> @@ -0,0 +1,8 @@
> +alsaconfigdir = @ALSA_CONFIG_DIR@
> +alsadir = $(alsaconfigdir)/alsa.conf.d
> +cfg_files = README
> +
> +alsa_DATA = $(cfg_files)
> +
> +EXTRA_DIST = \
> +	$(cfg_files)
> diff --git a/src/conf/alsa.conf.d/README b/src/conf/alsa.conf.d/README
> new file mode 100644
> index 0000000..9997884
> --- /dev/null
> +++ b/src/conf/alsa.conf.d/README
> @@ -0,0 +1,2 @@
> +You can place files named *.conf in this folder and they will be processed
> +when initialising alsa-lib.
> -- 
> 1.7.6
> 
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] conf: Allow for a directory to be given as a config file.
  2011-09-16  6:51     ` Takashi Iwai
@ 2011-09-16  8:28       ` Colin Guthrie
  0 siblings, 0 replies; 12+ messages in thread
From: Colin Guthrie @ 2011-09-16  8:28 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel

'Twas brillig, and Takashi Iwai at 16/09/11 07:51 did gyre and gimble:
> At Tue, 13 Sep 2011 22:04:00 +0100,
> gmane@colin.guthr.ie wrote:
>>
>> From: Colin Guthrie <colin@mageia.org>
>>
>> When this is done, *.conf files can be placed in that directory and they
>> will be processed by as if they were included directly.
>>
>> A directory (typically /usr/share/alsa/alsa.conf.d/) has been
>> added into the distribution.
> 
> In this code, the error behavior looks inconsistent.
> In a config file case (no directory), the opening failure gives only
> the error message but it continues.  In the case of directory, both
> the open-error and the parse-error are treated as the fatal error.

Ahh right, yeah, I need to reset err = 0 after the SND_ERR message in
that case. Good catch.

> OK, it's basically a mistake in the original code -- the open-error
> should be handled as a fatal error more consistently.  But, still,
> the old error code was overridden by the new entry, so the error in
> the middle of the file-entry loop is ignored.  That looks no good.

ACK

> And, the code becomes with too deep indentation.  This indicates
> already something wrong.  Split a new function to handle the directory
> case.  And create a small function to handle below code:
> 
> 	err = snd_input_stdio_open(&in, filename, "r");
> 	if (err >= 0) {
> 		err = snd_config_load(root, in);
> 		snd_input_close(in);
> 		if (err < 0)
> 			SNDERR("%s may be old or corrupted: consider to remove or fix it", filename);
> 	} else
> 		SNDERR("cannot access file %s", filename);
> 	return err;
> 
> and use it from both a single file and files-in-directory cases.

Cool will do. Was going to do that anyway, but wasn't sure if the amount
of code was over the "threshold" for a separate function :) (I
appreciate that the "threshold" is very subjective.

Col


-- 

Colin Guthrie
gmane(at)colin.guthr.ie
http://colin.guthr.ie/

Day Job:
  Tribalogic Limited [http://www.tribalogic.net/]
Open Source:
  Mageia Contributor [http://www.mageia.org/]
  PulseAudio Hacker [http://www.pulseaudio.org/]
  Trac Hacker [http://trac.edgewall.org/]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] conf: Allow for a directory to be given as a config file.
  2011-09-16  9:04 gmane
@ 2011-09-20  8:09 ` Takashi Iwai
  0 siblings, 0 replies; 12+ messages in thread
From: Takashi Iwai @ 2011-09-20  8:09 UTC (permalink / raw)
  To: gmane; +Cc: Colin Guthrie, alsa-devel

At Fri, 16 Sep 2011 10:04:26 +0100,
gmane@colin.guthr.ie wrote:
> 
> From: Colin Guthrie <colin@mageia.org>
> 
> When this is done, *.conf files can be placed in that directory and they
> will be processed by as if they were included directly.
> 
> A directory (typically /usr/share/alsa/alsa.conf.d/) has been
> added into the distribution.
> 
> v2: Used existing conf syntax rather than processing via autotools
> v3: Split file loading into separate function and made error handling
> more consistent.
> 
> Signed-off-by: Colin Guthrie <colin@mageia.org>

Applied now.  Thanks.


Takashi

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH] conf: Allow for a directory to be given as a config file.
@ 2011-09-16  9:04 gmane
  2011-09-20  8:09 ` Takashi Iwai
  0 siblings, 1 reply; 12+ messages in thread
From: gmane @ 2011-09-16  9:04 UTC (permalink / raw)
  To: alsa-devel; +Cc: tiwai, Colin Guthrie

From: Colin Guthrie <colin@mageia.org>

When this is done, *.conf files can be placed in that directory and they
will be processed by as if they were included directly.

A directory (typically /usr/share/alsa/alsa.conf.d/) has been
added into the distribution.

v2: Used existing conf syntax rather than processing via autotools
v3: Split file loading into separate function and made error handling
more consistent.

Signed-off-by: Colin Guthrie <colin@mageia.org>
---
 configure.in                     |    3 +-
 src/conf.c                       |   78 ++++++++++++++++++++++++++++++++-----
 src/conf/Makefile.am             |    2 +-
 src/conf/alsa.conf               |    7 +++
 src/conf/alsa.conf.d/Makefile.am |    8 ++++
 src/conf/alsa.conf.d/README      |    2 +
 6 files changed, 87 insertions(+), 13 deletions(-)
 create mode 100644 src/conf/alsa.conf.d/Makefile.am
 create mode 100644 src/conf/alsa.conf.d/README

diff --git a/configure.in b/configure.in
index 7ee0ccc..13e38b8 100644
--- a/configure.in
+++ b/configure.in
@@ -616,7 +616,8 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \
 	  src/pcm/Makefile src/pcm/scopes/Makefile \
 	  src/rawmidi/Makefile src/timer/Makefile \
           src/hwdep/Makefile src/seq/Makefile src/ucm/Makefile \
-          src/compat/Makefile src/alisp/Makefile src/conf/Makefile \
+          src/compat/Makefile src/alisp/Makefile \
+	  src/conf/Makefile src/conf/alsa.conf.d/Makefile \
 	  src/conf/cards/Makefile \
 	  src/conf/pcm/Makefile \
 	  modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile \
diff --git a/src/conf.c b/src/conf.c
index ddefff6..5b1b5a6 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -417,6 +417,7 @@ beginning:</P>
 #include <stdarg.h>
 #include <limits.h>
 #include <sys/stat.h>
+#include <dirent.h>
 #include <locale.h>
 #include "local.h"
 #ifdef HAVE_LIBPTHREAD
@@ -3373,6 +3374,42 @@ static int snd_config_hooks(snd_config_t *config, snd_config_t *private_data)
 	return err;
 }
 
+static int config_filename_filter(const struct dirent *dirent)
+{
+	size_t flen;
+
+	if (dirent == NULL)
+		return 0;
+	if (dirent->d_type == DT_DIR)
+		return 0;
+
+	flen = strlen(dirent->d_name);
+	if (flen <= 5)
+		return 0;
+
+	if (strncmp(&dirent->d_name[flen-5], ".conf", 5) == 0)
+		return 1;
+
+	return 0;
+}
+
+static int config_file_open(snd_config_t *root, const char *filename)
+{
+	snd_input_t *in;
+	int err;
+
+	err = snd_input_stdio_open(&in, filename, "r");
+	if (err >= 0) {
+		err = snd_config_load(root, in);
+		snd_input_close(in);
+		if (err < 0)
+			SNDERR("%s may be old or corrupted: consider to remove or fix it", filename);
+	} else
+		SNDERR("cannot access file %s", filename);
+
+	return err;
+}
+
 /**
  * \brief Loads and parses the given configurations files.
  * \param[in] root Handle to the root configuration node.
@@ -3457,20 +3494,39 @@ int snd_config_hook_load(snd_config_t *root, snd_config_t *config, snd_config_t
 		}
 	} while (hit);
 	for (idx = 0; idx < fi_count; idx++) {
-		snd_input_t *in;
+		struct stat st;
 		if (!errors && access(fi[idx].name, R_OK) < 0)
 			continue;
-		err = snd_input_stdio_open(&in, fi[idx].name, "r");
-		if (err >= 0) {
-			err = snd_config_load(root, in);
-			snd_input_close(in);
-			if (err < 0) {
-				SNDERR("%s may be old or corrupted: consider to remove or fix it", fi[idx].name);
-				goto _err;
-			}
-		} else {
-			SNDERR("cannot access file %s", fi[idx].name);
+		if (stat(fi[idx].name, &st) < 0) {
+			SNDERR("cannot stat file/directory %s", fi[idx].name);
+			continue;
 		}
+		if (S_ISDIR(st.st_mode)) {
+			struct dirent **namelist;
+			int n;
+
+			n = scandir(fi[idx].name, &namelist, config_filename_filter, versionsort);
+			if (n > 0) {
+				int j;
+				err = 0;
+				for (j = 0; j < n; ++j) {
+					if (err >= 0) {
+						int sl = strlen(fi[idx].name) + strlen(namelist[j]->d_name) + 2;
+						char *filename = malloc(sl);
+						snprintf(filename, sl, "%s/%s", fi[idx].name, namelist[j]->d_name);
+						filename[sl-1] = '\0';
+
+						err = config_file_open(root, filename);
+						free(filename);
+					}
+					free(namelist[j]);
+				}
+				free(namelist);
+				if (err < 0)
+					goto _err;
+			}
+		} else if (config_file_open(root, fi[idx].name) < 0)
+			goto _err;
 	}
 	*dst = NULL;
 	err = 0;
diff --git a/src/conf/Makefile.am b/src/conf/Makefile.am
index 2e5d0bf..456454f 100644
--- a/src/conf/Makefile.am
+++ b/src/conf/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS=cards pcm
+SUBDIRS=cards pcm alsa.conf.d
 
 cfg_files = alsa.conf
 if BUILD_ALISP
diff --git a/src/conf/alsa.conf b/src/conf/alsa.conf
index a33c24e..bc91df3 100644
--- a/src/conf/alsa.conf
+++ b/src/conf/alsa.conf
@@ -8,6 +8,13 @@
 	{
 		func load
 		files [
+			{
+				@func concat
+				strings [
+					{ @func datadir }
+					"/alsa.conf.d/"
+				]
+			}
 			"/etc/asound.conf"
 			"~/.asoundrc"
 		]
diff --git a/src/conf/alsa.conf.d/Makefile.am b/src/conf/alsa.conf.d/Makefile.am
new file mode 100644
index 0000000..c91661e
--- /dev/null
+++ b/src/conf/alsa.conf.d/Makefile.am
@@ -0,0 +1,8 @@
+alsaconfigdir = @ALSA_CONFIG_DIR@
+alsadir = $(alsaconfigdir)/alsa.conf.d
+cfg_files = README
+
+alsa_DATA = $(cfg_files)
+
+EXTRA_DIST = \
+	$(cfg_files)
diff --git a/src/conf/alsa.conf.d/README b/src/conf/alsa.conf.d/README
new file mode 100644
index 0000000..9997884
--- /dev/null
+++ b/src/conf/alsa.conf.d/README
@@ -0,0 +1,2 @@
+You can place files named *.conf in this folder and they will be processed
+when initialising alsa-lib.
-- 
1.7.6

^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2011-09-20  8:09 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-11 12:40 Allow alsa configuration to be loaded from a alsa.conf.d folder gmane
2011-09-11 12:40 ` [PATCH] conf: Allow for a directory to be given as a config file gmane
2011-09-12  6:57   ` Jaroslav Kysela
2011-09-12  8:23     ` Colin Guthrie
2011-09-12  8:27       ` Takashi Iwai
2011-09-13 21:00     ` Colin Guthrie
2011-09-13 21:03 ` Allow alsa configuration to be loaded from a alsa.conf.d folder v2 gmane
2011-09-13 21:04   ` [PATCH] conf: Allow for a directory to be given as a config file gmane
2011-09-16  6:51     ` Takashi Iwai
2011-09-16  8:28       ` Colin Guthrie
2011-09-16  9:04 gmane
2011-09-20  8:09 ` Takashi Iwai

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.