On 2011-05-10 22:29, Jorge Eduardo Candelaria wrote:
From: Margarita Olaya Cabrera<[email protected]>
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<[email protected]>
Signed-off-by: Jorge Eduardo Candelaria<[email protected]>
---
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<[email protected]>
+
+ 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<[email protected]>
+
+ 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
_______________________________________________
pulseaudio-discuss mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss