[alsa-devel] Disable conversions

Takashi Iwai tiwai at suse.de
Wed Nov 21 15:29:03 CET 2007


At Wed, 21 Nov 2007 12:40:54 +0100,
I wrote:
> 
> At Tue, 20 Nov 2007 01:51:51 +0100,
> Lennart Poettering wrote:
> > 
> > 4) If I open an audio device with "plughw:" i can disable the software
> >    resampling that takes place via
> >    "snd_pcm_hw_params_get_rate_resample()". However, there is no
> >    equivalent for disabling the channel number adjustment or the
> >    sample format conversion. This would be very useful in PA however,
> >    since this would allow me to use only the parts of plughw I am
> >    interested in (softvol), and disable all the rest (resampling,
> >    conversion, channel remixing).
> 
> Hmm..  It's a bit difficult to implement in a clean way.
> For example, what would be the reason to disable softvol?  It's
> basically irrelevant with the PCM parameters.  It's added just because
> of lack of hardware volume controls.
> 
> One idea I have is to make an API like
> 
> 	snd_pcm_alias_plugin(src, dst);
> 
> For example,
> 
> 	snd_pcm_alias_plugin("softvol", "passthru");
> 
> would take passthru plugin instead of softvol plugin.
> (Suppose passthru plugin as a simply pass-through plugin to its
>  slave.pcm)

The below is an experimental patch.  We have already "empty" plugin
as passthru.  So, call
	snd_pcm_alias_plugin("softvol", "empty");
before snd_pcm_open() to suppress the softvol in all configs.


Takashi

diff -r 3539f279ec38 include/pcm.h
--- a/include/pcm.h	Wed Nov 21 12:19:43 2007 +0100
+++ b/include/pcm.h	Wed Nov 21 16:03:51 2007 +0100
@@ -935,6 +935,7 @@ int snd_pcm_areas_copy(const snd_pcm_cha
 int snd_pcm_areas_copy(const snd_pcm_channel_area_t *dst_channels, snd_pcm_uframes_t dst_offset,
 		       const snd_pcm_channel_area_t *src_channels, snd_pcm_uframes_t src_offset,
 		       unsigned int channels, snd_pcm_uframes_t frames, snd_pcm_format_t format);
+	int snd_pcm_alias_plugin(const char *plugin, const char *target);
 
 /** \} */
 
diff -r 3539f279ec38 src/pcm/pcm.c
--- a/src/pcm/pcm.c	Wed Nov 21 12:19:43 2007 +0100
+++ b/src/pcm/pcm.c	Wed Nov 21 16:03:51 2007 +0100
@@ -1987,6 +1987,33 @@ static char *build_in_pcms[] = {
 	NULL
 };
 
+/* plugin alias list */
+struct plugin_alias {
+	char *name;
+	char *target;
+	struct plugin_alias *next;
+};
+
+static struct plugin_alias *plugin_alias_list;
+
+/* find a plugin alias and set previous pointer */
+static struct plugin_alias *find_plugin_alias(const char *name,
+					      struct plugin_alias **prevp)
+{
+	struct plugin_alias *c, *prev;
+	prev = NULL;
+	for (c = plugin_alias_list; c; prev = c, c = c->next) {
+		if (!strcmp(c->name, name)) {
+			if (prevp)
+				*prevp = prev;
+			return c;
+		}
+	}
+	if (prevp)
+		*prevp = prev;
+	return NULL;
+}
+
 static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *name,
 			     snd_config_t *pcm_root, snd_config_t *pcm_conf,
 			     snd_pcm_stream_t stream, int mode)
@@ -2004,6 +2031,7 @@ static int snd_pcm_open_conf(snd_pcm_t *
 #ifndef PIC
 	extern void *snd_pcm_open_symbols(void);
 #endif
+	struct plugin_alias *palias;
 	void *h = NULL;
 	if (snd_config_get_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND) {
 		char *val;
@@ -2030,6 +2058,10 @@ static int snd_pcm_open_conf(snd_pcm_t *
 		SNDERR("Invalid type for %s", id);
 		return err;
 	}
+
+	while ((palias = find_plugin_alias(str, NULL)) != NULL)
+		str = palias->target;
+
 	err = snd_config_search_definition(pcm_root, "pcm_type", str, &type_conf);
 	if (err >= 0) {
 		if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) {
@@ -2241,6 +2273,67 @@ int snd_pcm_open_slave(snd_pcm_t **pcmp,
 	return snd_pcm_open_conf(pcmp, NULL, root, conf, stream, mode);
 }
 #endif
+
+/**
+ * \brief Make or remove an alias for a plugin
+ * \param plugin The plugin
+ * \param target The name of the aliased target plugin
+ * \return zero if successful or a negative error code
+ */
+int snd_pcm_alias_plugin(const char *plugin, const char *target)
+{
+	struct plugin_alias *c, *prev;
+
+	if (target) {
+		/* check any loop in the alias list */
+		const char *aname;
+		if (!strcmp(plugin, target)) {
+			SNDERR("Cannot alias to itself for plugin %s", plugin);
+			return -EINVAL;
+		}
+		aname = target;
+		while ((c = find_plugin_alias(aname, NULL)) != NULL) {
+			aname = c->target;
+			if (!strcmp(aname, plugin)) {
+				SNDERR("Loop is detected for alias %s", aname);
+				return -EINVAL;
+			}
+		}
+	}
+
+	c = find_plugin_alias(plugin, &prev);
+	if (c) {
+		/* remove the existing one */
+		if (prev)
+			prev->next = c->next;
+		else
+			plugin_alias_list = c->next;
+		free(c->name);
+		free(c->target);
+		free(c);
+		if (!target)
+			return 0;
+	} else {
+		if (!target)
+			return -ENOENT;
+	}
+		
+	/* create a new list member and add it */
+	c = malloc(sizeof(*c));
+	if (!c)
+		return -ENOMEM;
+	c->name = strdup(plugin);
+	c->target = strdup(target);
+	if (!c->name || !c->target) {
+		free(c->name);
+		free(c->target);
+		free(c);
+		return -ENOMEM;
+	}
+	c->next = plugin_alias_list;
+	plugin_alias_list = c;
+	return 0;
+}
 
 /**
  * \brief Wait for a PCM to become ready
diff -r 3539f279ec38 src/pcm/pcm_empty.c
--- a/src/pcm/pcm_empty.c	Wed Nov 21 12:19:43 2007 +0100
+++ b/src/pcm/pcm_empty.c	Wed Nov 21 16:03:51 2007 +0100
@@ -90,8 +90,7 @@ int _snd_pcm_empty_open(snd_pcm_t **pcmp
 			slave = n;
 			continue;
 		}
-		SNDERR("Unknown field %s", id);
-		return -EINVAL;
+		continue;
 	}
 	if (!slave) {
 		SNDERR("slave is not defined");


More information about the Alsa-devel mailing list