[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