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"); _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx http://mailman.alsa-project.org/mailman/listinfo/alsa-devel