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