[pulseaudio-discuss] [PATCHv3 3/4] alsa: Add UCM API for managing UCM propoerties

David Henningsson david.henningsson at canonical.com
Fri Jul 8 05:38:00 PDT 2011


On 2011-05-10 22:29, Jorge Eduardo Candelaria wrote:
> From: Margarita Olaya Cabrera<magi at slimlogic.co.uk>
>
> The UCM stores the mixer settings per use case in configuration files, these
> files contains information such:
> - list of use case verbs per card or machine
> - supported devices per use case verb
> - use case sink device
> - use case source device
> - hardware playback volume control id (per use case verb and device)
> - hardware playback mute switch id
> - hardware capture volume control id
> - hardware capture mute switch id
>
> The new ucm data structures are used to store that info so it can be used by
> pulseaudio.
>
> This patch also adds ALSA UCM (Use Case Manager) calls.
> It checks if UCM is available for each card and if found, scans each UCM
> property verb, device and modifier for the card. It then then creates
> mappings for each supported UCM verb and device so that changes to the
> pulseaudio profile cause corresponding changes to the UCM verb and
> device for the card.

One basic thought of this: I'm wondering how much sense it makes to use 
the pa_alsa_mapping struct from the UCM code. To me this is a part of 
the alsa-mixer stuff (which UCM handles in a different way). You seem to 
put a lot of code into creating mappings, but you never use it. Why 
can't you just skip it? Or am I missing something?

>
> Signed-off-by: Margarita Olaya Cabrera<magi at slimlogic.co.uk>
> Signed-off-by: Jorge Eduardo Candelaria<jedu at slimlogic.co.uk>
> ---
> src/Makefile.am             |    2 +-
> src/modules/alsa/alsa-ucm.c |  532 +++++++++++++++++++++++++++++++++++++++++++
> src/modules/alsa/alsa-ucm.h |   80 +++++++
> 3 files changed, 613 insertions(+), 1 deletions(-)
> create mode 100644 src/modules/alsa/alsa-ucm.c
> create mode 100644 src/modules/alsa/alsa-ucm.h
>
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 71ad19b..38bc903 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -1553,7 +1553,7 @@ module_coreaudio_device_la_LIBADD = $(MODULE_LIBADD)
>
> # ALSA
>
> -libalsa_util_la_SOURCES = modules/alsa/alsa-util.c modules/alsa/alsa-util.h modules/alsa/alsa-mixer.c modules/alsa/alsa-mixer.h modules/alsa/alsa-sink.c modules/alsa/alsa-sink.h modules/alsa/alsa-source.c modules/alsa/alsa-source.h modules/reserve-wrap.c modules/reserve-wrap.h
> +libalsa_util_la_SOURCES = modules/alsa/alsa-util.c modules/alsa/alsa-util.h modules/alsa/alsa-mixer.c modules/alsa/alsa-mixer.h modules/alsa/alsa-sink.c modules/alsa/alsa-sink.h modules/alsa/alsa-source.c modules/alsa/alsa-source.h modules/alsa/alsa-ucm.c modules/alsa/alsa-ucm.h modules/reserve-wrap.c modules/reserve-wrap.h

Hmm, I wonder if it would make sense to explictly check for alsa >= 
1.0.24 here? (Just as Colin would like me to do for jack_free, but 
that's a different story :-) )

To make it easy to compile latest version of PA with older ALSA versions.

> libalsa_util_la_LDFLAGS = -avoid-version
> libalsa_util_la_LIBADD = $(MODULE_LIBADD) $(ASOUNDLIB_LIBS)
> libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS)
> diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c
> new file mode 100644
> index 0000000..8182a3b
> --- /dev/null
> +++ b/src/modules/alsa/alsa-ucm.c
> @@ -0,0 +1,532 @@
> +/***
> + This file is part of PulseAudio.
> +
> + Copyright 2011 Wolfson Microelectronics PLC
> + Author Margarita Olaya<magi at slimlogic.co.uk>
> +
> + PulseAudio 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.
> +
> + PulseAudio 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
> + General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public License
> + along with PulseAudio; if not, write to the Free Software
> + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
> + USA.
> +
> +***/
> +
> +#ifdef HAVE_CONFIG_H
> +#include<config.h>
> +#endif
> +
> +#include<sys/types.h>
> +#include<limits.h>
> +#include<asoundlib.h>
> +
> +#ifdef HAVE_VALGRIND_MEMCHECK_H
> +#include<valgrind/memcheck.h>
> +#endif
> +
> +#include<pulse/sample.h>
> +#include<pulse/xmalloc.h>
> +#include<pulse/timeval.h>
> +#include<pulse/util.h>
> +#include<pulse/i18n.h>
> +#include<pulse/utf8.h>
> +
> +#include<pulsecore/log.h>
> +#include<pulsecore/macro.h>
> +#include<pulsecore/core-util.h>
> +#include<pulsecore/atomic.h>
> +#include<pulsecore/core-error.h>
> +#include<pulsecore/once.h>
> +#include<pulsecore/thread.h>
> +#include<pulsecore/conf-parser.h>
> +#include<pulsecore/strbuf.h>
> +
> +#include "alsa-mixer.h"
> +#include "alsa-util.h"
> +#include "alsa-ucm.h"
> +
> +struct ucm_items {
> +    const char *id;
> +    const char *property;
> +};
> +
> +struct ucm_info {
> +    const char *id;
> +    int priority;
> +    pa_alsa_direction_t direction;
> +    int channels;
> +};
> +
> +/* UCM items - structure to set proplist items*/
> +static struct ucm_items item[] = {
> +    {"PlaybackPCM", PA_PROP_UCM_SINK},
> +    {"CapturePCM", PA_PROP_UCM_SOURCE},
> +    {"PlaybackVolume", PA_PROP_UCM_PLAYBACK_VOLUME},
> +    {"PlaybackSwitch", PA_PROP_UCM_PLAYBACK_SWITCH},
> +    {"CaptureVolume", PA_PROP_UCM_CAPTURE_VOLUME},
> +    {"CaptureSwitch", PA_PROP_UCM_CAPTURE_SWITCH},
> +    {"TQ", PA_PROP_UCM_QOS},
> +    {NULL, NULL},
> +};

This is more of a question than a comment, as I don't understand UCM 
syntax fully: In Ubuntu 11.04 we have e g 
/usr/share/alsa/ucm/SDP4430/hifi, which starts like:

SectionVerb {
         EnableSequence [
                 cdev "hw:SDP4430"
                 cset "name='DL1 Mixer Multimedia' 1"
                 cset "name='Sidetone Mixer Playback' 1"

do the names "cdev" and "cset" correspond in any way to the name 
constants above? Is there any documentation anywhere where I can read 
about the "PlaybackPCM" constants as well as the "cdev" names? (A quick 
google just pointed me to infiniband drivers!)

> +
> +/* UCM device info - this should eventually be part of policy manangement */
> +static struct ucm_info dev_info[] = {
> +    {SND_USE_CASE_DEV_SPEAKER, 100, PA_ALSA_DIRECTION_OUTPUT, 2},
> +    {SND_USE_CASE_DEV_LINE, 100, PA_ALSA_DIRECTION_ANY, 2},
> +    {SND_USE_CASE_DEV_HEADPHONES, 100, PA_ALSA_DIRECTION_OUTPUT, 2},
> +    {SND_USE_CASE_DEV_HEADSET, 300, PA_ALSA_DIRECTION_ANY, 2},
> +    {SND_USE_CASE_DEV_HANDSET, 200, PA_ALSA_DIRECTION_ANY, 2},
> +    {SND_USE_CASE_DEV_BLUETOOTH, 400, PA_ALSA_DIRECTION_ANY, 1},
> +    {SND_USE_CASE_DEV_EARPIECE, 100, PA_ALSA_DIRECTION_OUTPUT, 1},
> +    {SND_USE_CASE_DEV_SPDIF, 100, PA_ALSA_DIRECTION_ANY, 2},
> +    {SND_USE_CASE_DEV_HDMI, 100, PA_ALSA_DIRECTION_ANY, 8},
> +    {SND_USE_CASE_DEV_NONE, 100, PA_ALSA_DIRECTION_ANY, 2},
> +    {NULL, 0, PA_ALSA_DIRECTION_ANY, 0},
> +};
> +
> +/* UCM profile properties - The verb data is store so it can be used to fill
> + * the new profiles properties */
> +
> +int ucm_get_property(struct pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr, const char *verb_name) {

This function is not used outside alsa-ucm and should be declared static.

> +    const char *value;
> +    int i = 0;
> +
> +    do {
> +        int err;
> +
> +        err = snd_use_case_get(uc_mgr, item[i].id,&value);
> +        if (err<  0 ) {
> +            pa_log_debug("No %s for verb %s", item[i].id, verb_name);
> +            continue;
> +        }
> +
> +        pa_log_debug("Got %s for verb %s", item[i].id, verb_name);
> +        pa_proplist_sets(verb->proplist, item[i].property, value);
> +    } while (item[++i].id);
> +
> +    return 0;
> +};
> +
> +/* Create a property list for this ucm device */
> +static int ucm_get_device_property(struct pa_alsa_ucm_device *device, snd_use_case_mgr_t *uc_mgr, const char *device_name) {
> +    const char *value;
> +    char *id;
> +    int i = 0;
> +
> +    do {
> +        int err;
> +
> +        id = pa_sprintf_malloc("%s/%s", item[i].id, device_name);
> +
> +        err = snd_use_case_get(uc_mgr, id,&value);
> +        if (err<  0 ) {
> +            pa_log_debug("No %s for device %s", id, device_name);
> +            pa_xfree(id);
> +            continue;
> +        }
> +
> +        pa_log_debug("Got %s for device %s", id, device_name);
> +        pa_xfree(id);
> +        pa_proplist_sets(device->proplist, item[i].property, value);
> +    }  while (item[++i].id);
> +
> +    return 0;
> +};
> +
> +/* Create a property list for this ucm modifier */
> +static int ucm_get_modifier_property(struct pa_alsa_ucm_modifier *modifier, snd_use_case_mgr_t *uc_mgr, const char *modifier_name) {
> +    const char *value;
> +    char *id;
> +    int i = 0;
> +
> +    do {
> +        int err;
> +
> +        id = pa_sprintf_malloc("%s/%s", item[i].id, modifier_name);
> +
> +        err = snd_use_case_get(uc_mgr, id,&value);
> +        if (err<  0 ) {
> +            pa_log_debug("No %s for modifier %s", id, modifier_name);
> +            pa_xfree(id);
> +            continue;
> +        }
> +
> +        pa_log_debug("Got %s for modifier %s", id, modifier_name);
> +        pa_xfree(id);
> +        pa_proplist_sets(modifier->proplist, item[i].property, value);
> +    } while (item[++i].id);
> +
> +    return 0;
> +};
> +
> +/* Create a list of devices for this verb */
> +static int ucm_get_devices(struct pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr) {
> +    const char **dev_list;
> +    int num_dev, i;
> +
> +    num_dev = snd_use_case_get_list(uc_mgr, "_devices",&dev_list);
> +    if (num_dev<  0)
> +        return num_dev;
> +
> +    for (i = 0; i<  num_dev; i += 2) {
> +        pa_alsa_ucm_device *d;
> +        d = pa_xnew0(pa_alsa_ucm_device, 1);
> +        d->proplist = pa_proplist_new();
> +        pa_proplist_sets(d->proplist, PA_PROP_UCM_NAME, dev_list[i]);
> +        PA_LLIST_PREPEND(pa_alsa_ucm_device, verb->devices, d);
> +    }
> +
> +    return 0;
> +};
> +
> +static int ucm_get_modifiers(struct pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr) {
> +    const char **mod_list;
> +    int num_mod, i;
> +
> +    num_mod = snd_use_case_get_list(uc_mgr, "_modifiers",&mod_list);
> +    if (num_mod<  0)
> +        return num_mod;
> +
> +    for (i = 0; i<  num_mod; i += 2) {
> +        pa_alsa_ucm_modifier *m;
> +        m = pa_xnew0(pa_alsa_ucm_modifier, 1);
> +        m->proplist = pa_proplist_new();
> +        pa_proplist_sets(m->proplist, PA_PROP_UCM_NAME, mod_list[i]);
> +        PA_LLIST_PREPEND(pa_alsa_ucm_modifier, verb->modifiers, m);
> +    }
> +
> +    return 0;
> +};
> +
> +int ucm_get_properties(struct pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr, const char *verb_name) {
> +    struct pa_alsa_ucm_device *d;
> +    struct pa_alsa_ucm_modifier *mod;
> +    int err;
> +
> +    err = snd_use_case_set(uc_mgr, "_verb", verb_name);
> +    if (err<  0)
> +        return err;
> +
> +    err = ucm_get_devices(verb, uc_mgr);
> +    if (err<  0)
> +        pa_log("No UCM devices for verb %s", verb_name);
> +
> +    err = ucm_get_modifiers(verb, uc_mgr);
> +    if (err<  0)
> +        pa_log("No UCM modifiers for verb %s", verb_name);

Is missing UCM modifiers considered an error?

> +
> +    /* Verb properties */
> +    ucm_get_property(verb, uc_mgr, verb_name);
> +
> +    PA_LLIST_FOREACH(d, verb->devices) {
> +        const char *dev_name = pa_proplist_gets(d->proplist, PA_PROP_UCM_NAME);
> +
> +        /* Devices properties */
> +        ucm_get_device_property(d, uc_mgr, dev_name);
> +    }
> +
> +    PA_LLIST_FOREACH(mod, verb->modifiers) {
> +        const char *mod_name = pa_proplist_gets(mod->proplist, PA_PROP_UCM_NAME);
> +
> +        /* Modifier properties */
> +        ucm_get_modifier_property(mod, uc_mgr, mod_name);
> +    }
> +
> +    return 0;
> +}
> +/* Change UCM verb and device to match selected card profile */
> +int ucm_set_profile(struct pa_alsa_ucm_config *ucm, char *profile_name, struct profile_data *d)
> +{
> +    char *new_verb_name, *new_device_name, *old_verb_name, *old_device_name, *tmp;
> +    int ret = 0;
> +
> +    new_device_name = strchr(profile_name, ':') + 2;
> +    if (!new_device_name) {

strchr never returns -2, so the comparision above is always false.

> +        pa_log("no new device found for %s", profile_name);
> +        return -1;
> +    }
> +
> +    old_device_name = strchr(d->profile->name, ':') + 2;
> +    if (!old_device_name) {
> +        pa_log("no current device found for %s", d->profile->name);
> +        return -1;
> +    }
> +
> +    new_verb_name = pa_xstrdup(profile_name);
> +    tmp = strchr(new_verb_name, ':');
> +    if (!tmp) {
> +        pa_log("no new verb found for %s", profile_name);
> +        pa_xfree(new_verb_name);
> +        return -1;
> +    }
> +    *tmp = 0;
> +
> +    old_verb_name = pa_xstrdup(d->profile->name);
> +    tmp = strchr(old_verb_name, ':');
> +    if (!tmp) {
> +        pa_log("no new verb found for %s", d->profile->name);
> +        pa_xfree(new_verb_name);
> +        pa_xfree(old_verb_name);
> +        return -1;
> +    }
> +    *tmp = 0;
> +
> +    pa_log_debug("set ucm: old verb %s device %s", old_verb_name,
> +						old_device_name);
> +    pa_log_debug("set ucm: new verb %s device %s", new_verb_name,
> +						new_device_name);
> +
> +    /* do we need to change the verb */
> +    if (strcmp(new_verb_name, old_verb_name) == 0) {
> +        /* just change the device only */
> +        tmp = pa_sprintf_malloc("_swdev/%s", old_device_name);
> +        if ((snd_use_case_set(ucm->ucm_mgr, tmp, new_device_name))<  0) {
> +            pa_log("failed to switch device %s %s", tmp, new_device_name);
> +            ret = -1;
> +        }
> +        pa_xfree(tmp);
> +    } else {
> +        /* change verb and device */
> +        if ((snd_use_case_set(ucm->ucm_mgr, "_verb", new_verb_name))<  0) {
> +            pa_log("failed to set verb %s", new_verb_name);
> +            ret = -1;
> +        }
> +        if (snd_use_case_set(ucm->ucm_mgr, "_enadev", new_device_name)<  0) {
> +            pa_log("failed to set device %s", new_device_name);
> +            ret = -1;
> +        }
> +    }
> +
> +    pa_xfree(new_verb_name);
> +    pa_xfree(old_verb_name);
> +    return ret;
> +}
> +
> +static void ucm_add_mapping(pa_alsa_profile *p, pa_alsa_mapping *m)
> +{
> +    switch (m->direction) {
> +    case PA_ALSA_DIRECTION_ANY:
> +        pa_idxset_put(p->output_mappings, m, NULL);
> +        pa_idxset_put(p->input_mappings, m, NULL);
> +        break;
> +     case PA_ALSA_DIRECTION_OUTPUT:
> +        pa_idxset_put(p->output_mappings, m, NULL);
> +        break;
> +     case PA_ALSA_DIRECTION_INPUT:
> +        pa_idxset_put(p->input_mappings, m, NULL);
> +        break;
> +    }
> +    p->priority += m->priority * 100;
> +}
> +
> +static pa_alsa_profile *ucm_new_profile(pa_alsa_profile_set *ps, const char *verb_name, const char *dev_name)
> +{
> +    pa_alsa_profile *p;
> +    char *profile_name;
> +
> +    if (dev_name)
> +        profile_name = pa_sprintf_malloc("%s: %s", verb_name, dev_name);
> +    else
> +        profile_name = pa_sprintf_malloc("%s:", verb_name);
> +
> +    if (pa_hashmap_get(ps->profiles, verb_name)) {
> +        pa_xfree(profile_name);
> +        return NULL;
> +    }
> +
> +    p = pa_xnew0(pa_alsa_profile, 1);
> +    p->profile_set = ps;
> +    p->name = profile_name;
> +
> +    p->output_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
> +    p->input_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
> +
> +    ps->probed = TRUE;
> +    p->supported = 1;
> +    pa_hashmap_put(ps->profiles, p->name, p);

Could you explain this a little: Why do you use profile_name when you 
put something into the hashmap but verb_name when you check for if 
something is already in the map?


> +    return p;
> +}
> +
> +static int ucm_create_mapping(pa_alsa_profile_set *ps, struct pa_alsa_profile *p, struct pa_alsa_ucm_device *device, const char *verb_name, const char *device_name, char *strings)
> +{
> +    pa_alsa_mapping *m;
> +    char *mapping_name;
> +    int i = 0;
> +
> +    if (device_name)
> +        mapping_name = pa_sprintf_malloc("Mapping %s: %s", verb_name, device_name);
> +    else
> +        mapping_name = pa_sprintf_malloc("Mapping %s", verb_name);
> +
> +    m = mapping_get(ps, mapping_name);
> +    if (!m) {
> +        pa_log("no mapping for %s", mapping_name);
> +        pa_xfree(mapping_name);
> +        return -1;
> +    }
> +    pa_log_info("ucm mapping: %s dev %s", mapping_name, strings);
> +
> +    m->supported = TRUE;
> +    m->channel_map.map[0] = PA_CHANNEL_POSITION_LEFT;
> +    m->channel_map.map[1] = PA_CHANNEL_POSITION_RIGHT;
> +    m->device_strings = pa_split_spaces_strv(strings);
> +    pa_xfree(mapping_name);
> +
> +    if (!device_name)
> +        goto not_found;
> +    do {
> +        if (strcmp(dev_info[i].id, device_name) == 0)
> +            goto found;
> +    } while (dev_info[++i].id);
> +
> +not_found:
> +    /* use default values */
> +    m->priority = 100;
> +    m->direction = PA_ALSA_DIRECTION_ANY;
> +    m->channel_map.channels = 2;
> +    ucm_add_mapping(p, m);
> +    return 0;
> +
> +found:
> +    m->priority = dev_info[i].priority;
> +    m->direction = dev_info[i].direction;
> +    m->channel_map.channels = dev_info[i].channels;
> +    ucm_add_mapping(p, m);
> +    return 0;
> +}
> +
> +static int ucm_create_profile(pa_alsa_profile_set *ps, struct pa_alsa_ucm_verb *verb,
> +        const char *verb_name, const char *verb_sink, const char *verb_source) {
> +
> +    struct pa_alsa_profile *p;
> +    struct pa_alsa_ucm_device *dev;
> +    char *dev_strings;
> +    int num_devices = 0;
> +
> +    pa_assert(ps);
> +
> +    /* Add a mapping for each verb modifier for this profile if the sink/source is different to the verb */
> +    PA_LLIST_FOREACH(dev, verb->devices) {
> +        const char *dev_name, *sink, *source;
> +
> +        dev_name = pa_proplist_gets(dev->proplist, PA_PROP_UCM_NAME);
> +

The (eight) rows below are duplicated in add_ucm_profile_set. Maybe they 
can be consolidated? Also, perhaps hw:"alsa-card-index" would be a 
better choice? And what about verbs that is in one direction only?

> +        /* if no default sink is set use hw:0 */
> +       sink = pa_proplist_gets(dev->proplist, PA_PROP_UCM_SINK);
> +        if (sink == NULL)
> +            sink = "hw:0";
> +
> +        /* if no default sink is set use hw:0 */
> +        source = pa_proplist_gets(dev->proplist, PA_PROP_UCM_SOURCE);
> +        if (source == NULL)
> +            source = "hw:0";
> +

Nitpick: Indentation error on the row below.

> +		dev_strings = pa_sprintf_malloc("%s %s", sink, source);
> +        p = ucm_new_profile(ps, verb_name, dev_name);
> +        ucm_create_mapping(ps, p, dev, verb_name, dev_name, dev_strings);
> +        pa_xfree(dev_strings);
> +        pa_alsa_profile_dump(p);
> +        num_devices++;
> +    }
> +
> +    if (num_devices)
> +		return 0;
> +
> +    /* Create a default mapping for each verb/profile */
> +    dev_strings = pa_sprintf_malloc("%s %s", verb_sink, verb_source);
> +    p = ucm_new_profile(ps, verb_name, NULL);
> +    ucm_create_mapping(ps, p, dev, verb_name, NULL, dev_strings);

I'm not getting this. You create "a default mapping", and then a default 
profile, but you still use the "dev" variable in a call here.

> +    pa_xfree(dev);

You probably mean pa_xfree(dev_strings) instead?

> +
> +    return 0;
> +}
> +
> +pa_alsa_profile_set* add_ucm_profile_set(struct pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map) {
> +    struct pa_alsa_ucm_verb *verb;
> +    pa_alsa_profile_set *ps;
> +    pa_alsa_profile *p;
> +    pa_alsa_mapping *m;
> +    void *state;
> +
> +    ps = pa_xnew0(pa_alsa_profile_set, 1);
> +    ps->mappings = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
> +    ps->profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
> +    ps->decibel_fixes = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
> +
> +    /* create a profile for each verb */
> +    PA_LLIST_FOREACH(verb, ucm->verbs) {
> +        const char *sink, *source, *verb_name;
> +        char *dev;
> +
> +        verb_name = pa_proplist_gets(verb->proplist, PA_PROP_UCM_NAME);
> +        if (verb_name == NULL) {
> +            pa_log("verb with no name");
> +            continue;
> +        }
> +
> +        /* if no default sink is set use hw:0 */
> +        sink = pa_proplist_gets(verb->proplist, PA_PROP_UCM_SINK);
> +        if (sink == NULL)
> +            sink = "hw:0";
> +
> +        /* if no default sink is set use hw:0 */
> +        source = pa_proplist_gets(verb->proplist, PA_PROP_UCM_SOURCE);
> +        if (source == NULL)
> +            source = "hw:0";
> +
> +        dev = pa_sprintf_malloc("%s %s", sink, source);

The "dev" variable is never used for anything.

> +	    ucm_create_profile(ps, verb, verb_name, sink, source);
> +        pa_xfree(dev);
> +    }
> +
> +    PA_HASHMAP_FOREACH(m, ps->mappings, state)
> +        if (mapping_verify(m, default_channel_map)<  0)
> +            goto fail;
> +
> +    PA_HASHMAP_FOREACH(p, ps->profiles, state)
> +        if (profile_verify(p)<  0)
> +            goto fail;
> +
> +    return ps;
> +
> +fail:
> +    pa_log("failed to add UCM mappings");
> +    pa_alsa_profile_set_free(ps);
> +    return NULL;
> +}
> +
> +void free_ucm(struct pa_alsa_ucm_config *ucm)
> +{
> +    struct pa_alsa_ucm_device *di, *dn;
> +    struct pa_alsa_ucm_modifier *mi, *mn;
> +    struct pa_alsa_ucm_verb *verb, *vi, *vn;
> +
> +    verb = ucm->verbs;
> +
> +    PA_LLIST_FOREACH_SAFE(di, dn, verb->devices) {
> +        PA_LLIST_REMOVE(pa_alsa_ucm_device, verb->devices, di);
> +        pa_proplist_free(di->proplist);
> +        pa_xfree(di);
> +    }
> +
> +    PA_LLIST_FOREACH_SAFE(mi, mn, verb->modifiers) {
> +        PA_LLIST_REMOVE(pa_alsa_ucm_modifier, verb->modifiers, mi);
> +        pa_proplist_free(mi->proplist);
> +        pa_xfree(mi);
> +    }
> +
> +    PA_LLIST_FOREACH_SAFE(vi, vn, ucm->verbs) {
> +        PA_LLIST_REMOVE(pa_alsa_ucm_verb, ucm->verbs, vi);
> +        pa_proplist_free(vi->proplist);
> +        pa_xfree(vi);
> +    }
> +}
> diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h
> new file mode 100644
> index 0000000..e748528
> --- /dev/null
> +++ b/src/modules/alsa/alsa-ucm.h
> @@ -0,0 +1,80 @@
> +#ifndef foopulseucmhfoo
> +#define foopulseucmhfoo
> +
> +/***
> +  This file is part of PulseAudio.
> +
> +  Copyright 2011 Wolfson Microelectronics PLC
> +  Author Margarita Olaya<magi at slimlogic.co.uk>
> +
> +  PulseAudio 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.
> +
> +  PulseAudio 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
> +  General Public License for more details.
> +
> +  You should have received a copy of the GNU Lesser General Public License
> +  along with PulseAudio; if not, write to the Free Software
> +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
> +  USA.
> +***/
> +
> +#include<asoundlib.h>
> +#include<use-case.h>
> +
> +typedef struct pa_alsa_ucm_verb pa_alsa_ucm_verb;
> +typedef struct pa_alsa_ucm_modifier pa_alsa_ucm_modifier;
> +typedef struct pa_alsa_ucm_device pa_alsa_ucm_device;
> +typedef struct pa_alsa_ucm_config pa_alsa_ucm_config;
> +

Same as for patch 1: the functions below should start with pa_

> +int ucm_set_profile(struct pa_alsa_ucm_config *ucm, char *profile_name, struct profile_data *d);
> +void free_ucm(struct pa_alsa_ucm_config *ucm);
> +pa_alsa_profile_set* add_ucm_profile_set(struct pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map);
> +int ucm_get_property(struct pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr, const char *verb_name);
> +int ucm_get_properties(struct pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr, const char *verb_name);
> +
> +typedef enum pa_alsa_ucm_mapping_type {
> +    PA_ALSA_UCM_MAPPING_DEVICE,
> +    PA_ALSA_UCM_MAPPING_MODIFIER
> +} pa_alsa_ucm_mapping_type_t;
> +
> +/* UCM may not be available in some cards. */
> +typedef enum pa_alsa_ucm_status {
> +    PA_ALSA_UCM_DISABLED = 0,
> +    PA_ALSA_UCM_ENABLED,
> +} pa_alsa_ucm_status_t;
> +
> +struct pa_alsa_ucm_device {
> +    PA_LLIST_FIELDS(pa_alsa_ucm_device);
> +    pa_proplist *proplist;
> +    pa_alsa_ucm_status_t status;
> +};
> +
> +struct pa_alsa_ucm_modifier {
> +    PA_LLIST_FIELDS(pa_alsa_ucm_modifier);
> +    pa_proplist *proplist;
> +    pa_alsa_ucm_status_t status;
> +};
> +
> +struct pa_alsa_ucm_verb {
> +    PA_LLIST_FIELDS(pa_alsa_ucm_verb);
> +    pa_proplist *proplist;
> +    pa_alsa_ucm_status_t status;
> +    PA_LLIST_HEAD(pa_alsa_ucm_device, devices);
> +    PA_LLIST_HEAD(pa_alsa_ucm_modifier, modifiers);
> +};
> +
> +struct pa_alsa_ucm_config {
> +    snd_use_case_mgr_t *ucm_mgr;
> +    const char *verb_ini;
> +    const char *verb_new;
> +    pa_alsa_ucm_status_t status;
> +
> +    PA_LLIST_HEAD(pa_alsa_ucm_verb, verbs);
> +};
> +
> +#endif


-- 
David Henningsson, Canonical Ltd.
http://launchpad.net/~diwic


More information about the pulseaudio-discuss mailing list