[pulseaudio-commits] 6 commits - src/modules src/pulsecore
Tanu Kaskinen
tanuk at kemper.freedesktop.org
Fri Aug 21 04:41:48 PDT 2015
src/modules/alsa/alsa-mixer.c | 138 ++++++++++++++++--
src/modules/alsa/alsa-mixer.h | 10 +
src/modules/alsa/alsa-ucm.c | 268 +++++++++++++++++++++++++++++++-----
src/modules/alsa/alsa-ucm.h | 16 +-
src/modules/alsa/module-alsa-card.c | 19 +-
src/pulsecore/device-port.c | 14 +
6 files changed, 401 insertions(+), 64 deletions(-)
New commits:
commit 38e81f4c3dd1751fa78480daee3c71b73b45f7a7
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date: Mon May 4 21:03:45 2015 +0300
ucm: Add support for "JackHWMute"
JackHWMute is used to list devices that get forcibly muted by
a particular jack. We mark ports unavailable based on that
information.
diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index c6d6212..a0b2493 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -119,6 +119,7 @@ pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name) {
jack->state_unplugged = PA_AVAILABLE_NO;
jack->state_plugged = PA_AVAILABLE_YES;
jack->ucm_devices = pa_dynarray_new(NULL);
+ jack->ucm_hw_mute_devices = pa_dynarray_new(NULL);
return jack;
}
@@ -126,6 +127,9 @@ pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name) {
void pa_alsa_jack_free(pa_alsa_jack *jack) {
pa_assert(jack);
+ if (jack->ucm_hw_mute_devices)
+ pa_dynarray_free(jack->ucm_hw_mute_devices);
+
if (jack->ucm_devices)
pa_dynarray_free(jack->ucm_devices);
@@ -145,6 +149,9 @@ void pa_alsa_jack_set_has_control(pa_alsa_jack *jack, bool has_control) {
jack->has_control = has_control;
+ PA_DYNARRAY_FOREACH(device, jack->ucm_hw_mute_devices, idx)
+ pa_alsa_ucm_device_update_available(device);
+
PA_DYNARRAY_FOREACH(device, jack->ucm_devices, idx)
pa_alsa_ucm_device_update_available(device);
}
@@ -160,6 +167,44 @@ void pa_alsa_jack_set_plugged_in(pa_alsa_jack *jack, bool plugged_in) {
jack->plugged_in = plugged_in;
+ /* XXX: If this is a headphone jack that mutes speakers when plugged in,
+ * and the headphones get unplugged, then the headphone device must be set
+ * to unavailable and the speaker device must be set to unknown. So far so
+ * good. But there's an ugly detail: we must first set the availability of
+ * the speakers and then the headphones. We shouldn't need to care about
+ * the order, but we have to, because module-switch-on-port-available gets
+ * separate events for the two devices, and the intermediate state between
+ * the two events is such that the second event doesn't trigger the desired
+ * port switch, if the event order is "wrong".
+ *
+ * These are the transitions when the event order is "right":
+ *
+ * speakers: 1) unavailable -> 2) unknown -> 3) unknown
+ * headphones: 1) available -> 2) available -> 3) unavailable
+ *
+ * In the 2 -> 3 transition, headphones become unavailable, and
+ * module-switch-on-port-available sees that speakers can be used, so the
+ * port gets changed as it should.
+ *
+ * These are the transitions when the event order is "wrong":
+ *
+ * speakers: 1) unavailable -> 2) unavailable -> 3) unknown
+ * headphones: 1) available -> 2) unavailable -> 3) unavailable
+ *
+ * In the 1 -> 2 transition, headphones become unavailable, and there are
+ * no available ports to use, so no port change happens. In the 2 -> 3
+ * transition, speaker availability becomes unknown, but that's not
+ * a strong enough signal for module-switch-on-port-available, so it still
+ * doesn't do the port switch.
+ *
+ * We should somehow merge the two events so that
+ * module-switch-on-port-available would handle both transitions in one go.
+ * If module-switch-on-port-available used a defer event to delay
+ * the port availability processing, that would probably do the trick. */
+
+ PA_DYNARRAY_FOREACH(device, jack->ucm_hw_mute_devices, idx)
+ pa_alsa_ucm_device_update_available(device);
+
PA_DYNARRAY_FOREACH(device, jack->ucm_devices, idx)
pa_alsa_ucm_device_update_available(device);
}
@@ -171,6 +216,13 @@ void pa_alsa_jack_add_ucm_device(pa_alsa_jack *jack, pa_alsa_ucm_device *device)
pa_dynarray_append(jack->ucm_devices, device);
}
+void pa_alsa_jack_add_ucm_hw_mute_device(pa_alsa_jack *jack, pa_alsa_ucm_device *device) {
+ pa_assert(jack);
+ pa_assert(device);
+
+ pa_dynarray_append(jack->ucm_hw_mute_devices, device);
+}
+
static const char *lookup_description(const char *key, const struct description_map dm[], unsigned n) {
unsigned i;
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index 96a7a5e..621a71b 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -170,6 +170,7 @@ struct pa_alsa_jack {
pa_alsa_required_t required_absent;
pa_dynarray *ucm_devices; /* pa_alsa_ucm_device */
+ pa_dynarray *ucm_hw_mute_devices; /* pa_alsa_ucm_device */
};
pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name);
@@ -177,6 +178,7 @@ void pa_alsa_jack_free(pa_alsa_jack *jack);
void pa_alsa_jack_set_has_control(pa_alsa_jack *jack, bool has_control);
void pa_alsa_jack_set_plugged_in(pa_alsa_jack *jack, bool plugged_in);
void pa_alsa_jack_add_ucm_device(pa_alsa_jack *jack, pa_alsa_ucm_device *device);
+void pa_alsa_jack_add_ucm_hw_mute_device(pa_alsa_jack *jack, pa_alsa_ucm_device *device);
/* A path wraps a series of elements into a single entity which can be
* used to control it as if it had a single volume slider, a single
diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c
index d2c7140..c231bb4 100644
--- a/src/modules/alsa/alsa-ucm.c
+++ b/src/modules/alsa/alsa-ucm.c
@@ -77,6 +77,9 @@ struct ucm_info {
};
static void device_set_jack(pa_alsa_ucm_device *device, pa_alsa_jack *jack);
+static void device_add_hw_mute_jack(pa_alsa_ucm_device *device, pa_alsa_jack *jack);
+
+static pa_alsa_ucm_device *verb_find_device(pa_alsa_ucm_verb *verb, const char *device_name);
struct ucm_port {
pa_alsa_ucm_config *ucm;
@@ -107,6 +110,7 @@ static struct ucm_items item[] = {
{"CaptureChannels", PA_ALSA_PROP_UCM_CAPTURE_CHANNELS},
{"TQ", PA_ALSA_PROP_UCM_QOS},
{"JackControl", PA_ALSA_PROP_UCM_JACK_CONTROL},
+ {"JackHWMute", PA_ALSA_PROP_UCM_JACK_HW_MUTE},
{NULL, NULL},
};
@@ -414,6 +418,7 @@ static int ucm_get_devices(pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr) {
pa_proplist_sets(d->proplist, PA_ALSA_PROP_UCM_NAME, pa_strnull(dev_list[i]));
pa_proplist_sets(d->proplist, PA_ALSA_PROP_UCM_DESCRIPTION, pa_strna(dev_list[i + 1]));
d->ucm_ports = pa_dynarray_new(NULL);
+ d->hw_mute_jacks = pa_dynarray_new(NULL);
d->available = PA_AVAILABLE_UNKNOWN;
PA_LLIST_PREPEND(pa_alsa_ucm_device, verb->devices, d);
@@ -1381,6 +1386,7 @@ static int ucm_create_profile(
PA_LLIST_FOREACH(dev, verb->devices) {
pa_alsa_jack *jack;
+ const char *jack_hw_mute;
name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME);
@@ -1391,6 +1397,37 @@ static int ucm_create_profile(
jack = ucm_get_jack(ucm, dev);
device_set_jack(dev, jack);
+
+ /* JackHWMute contains a list of device names. Each listed device must
+ * be associated with the jack object that we just created. */
+ jack_hw_mute = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_JACK_HW_MUTE);
+ if (jack_hw_mute) {
+ char *hw_mute_device_name;
+ const char *state = NULL;
+
+ while ((hw_mute_device_name = pa_split_spaces(jack_hw_mute, &state))) {
+ pa_alsa_ucm_verb *verb2;
+ bool device_found = false;
+
+ /* Search the referenced device from all verbs. If there are
+ * multiple verbs that have a device with this name, we add the
+ * hw mute association to each of those devices. */
+ PA_LLIST_FOREACH(verb2, ucm->verbs) {
+ pa_alsa_ucm_device *hw_mute_device;
+
+ hw_mute_device = verb_find_device(verb2, hw_mute_device_name);
+ if (hw_mute_device) {
+ device_found = true;
+ device_add_hw_mute_jack(hw_mute_device, jack);
+ }
+ }
+
+ if (!device_found)
+ pa_log("[%s] JackHWMute references an unknown device: %s", name, hw_mute_device_name);
+
+ pa_xfree(hw_mute_device_name);
+ }
+ }
}
/* Now find modifiers that have their own PlaybackPCM and create
@@ -1596,6 +1633,9 @@ static void free_verb(pa_alsa_ucm_verb *verb) {
PA_LLIST_FOREACH_SAFE(di, dn, verb->devices) {
PA_LLIST_REMOVE(pa_alsa_ucm_device, verb->devices, di);
+ if (di->hw_mute_jacks)
+ pa_dynarray_free(di->hw_mute_jacks);
+
if (di->ucm_ports)
pa_dynarray_free(di->ucm_ports);
@@ -1621,6 +1661,23 @@ static void free_verb(pa_alsa_ucm_verb *verb) {
pa_xfree(verb);
}
+static pa_alsa_ucm_device *verb_find_device(pa_alsa_ucm_verb *verb, const char *device_name) {
+ pa_alsa_ucm_device *device;
+
+ pa_assert(verb);
+ pa_assert(device_name);
+
+ PA_LLIST_FOREACH(device, verb->devices) {
+ const char *name;
+
+ name = pa_proplist_gets(device->proplist, PA_ALSA_PROP_UCM_NAME);
+ if (pa_streq(name, device_name))
+ return device;
+ }
+
+ return NULL;
+}
+
void pa_alsa_ucm_free(pa_alsa_ucm_config *ucm) {
pa_alsa_ucm_verb *vi, *vn;
pa_alsa_jack *ji, *jn;
@@ -1737,6 +1794,16 @@ static void device_set_jack(pa_alsa_ucm_device *device, pa_alsa_jack *jack) {
pa_alsa_ucm_device_update_available(device);
}
+static void device_add_hw_mute_jack(pa_alsa_ucm_device *device, pa_alsa_jack *jack) {
+ pa_assert(device);
+ pa_assert(jack);
+
+ pa_dynarray_append(device->hw_mute_jacks, jack);
+ pa_alsa_jack_add_ucm_hw_mute_device(jack, device);
+
+ pa_alsa_ucm_device_update_available(device);
+}
+
static void device_set_available(pa_alsa_ucm_device *device, pa_available_t available) {
struct ucm_port *port;
unsigned idx;
@@ -1754,12 +1821,21 @@ static void device_set_available(pa_alsa_ucm_device *device, pa_available_t avai
void pa_alsa_ucm_device_update_available(pa_alsa_ucm_device *device) {
pa_available_t available = PA_AVAILABLE_UNKNOWN;
+ pa_alsa_jack *jack;
+ unsigned idx;
pa_assert(device);
if (device->jack && device->jack->has_control)
available = device->jack->plugged_in ? PA_AVAILABLE_YES : PA_AVAILABLE_NO;
+ PA_DYNARRAY_FOREACH(jack, device->hw_mute_jacks, idx) {
+ if (jack->plugged_in) {
+ available = PA_AVAILABLE_NO;
+ break;
+ }
+ }
+
device_set_available(device, available);
}
diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h
index 5ccc466..0930303 100644
--- a/src/modules/alsa/alsa-ucm.h
+++ b/src/modules/alsa/alsa-ucm.h
@@ -87,6 +87,9 @@ typedef void snd_use_case_mgr_t;
/* Corresponds to the "JackControl" UCM value. */
#define PA_ALSA_PROP_UCM_JACK_CONTROL "alsa.ucm.jack_control"
+/* Corresponds to the "JackHWMute" UCM value. */
+#define PA_ALSA_PROP_UCM_JACK_HW_MUTE "alsa.ucm.jack_hw_mute"
+
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;
@@ -148,6 +151,7 @@ struct pa_alsa_ucm_device {
pa_dynarray *ucm_ports; /* struct ucm_port */
pa_alsa_jack *jack;
+ pa_dynarray *hw_mute_jacks; /* pa_alsa_jack */
pa_available_t available;
};
commit d2bed5332ab6e25072d87f43f418feb1c93c080d
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date: Mon May 4 21:03:44 2015 +0300
ucm: Create only one jack object per kcontrol
Previously the UCM code created one jack object per device name (which
is not the same thing as creating one jack object per device, because
the UCM device namespace is scoped on per-verb basis, so devices in
different verbs may have the same name). I think it's conceptually
cleaner to create one jack object per alsa kcontrol. I plan to do
similar refactoring on the traditional mixer code later.
diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 3f19aa9..c6d6212 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -107,7 +107,7 @@ struct description_map {
const char *description;
};
-pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name, const char *alsa_name) {
+pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name) {
pa_alsa_jack *jack;
pa_assert(name);
@@ -115,12 +115,7 @@ pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name, const char
jack = pa_xnew0(pa_alsa_jack, 1);
jack->path = path;
jack->name = pa_xstrdup(name);
-
- if (alsa_name)
- jack->alsa_name = pa_xstrdup(alsa_name);
- else
- jack->alsa_name = pa_sprintf_malloc("%s Jack", name);
-
+ jack->alsa_name = pa_sprintf_malloc("%s Jack", name);
jack->state_unplugged = PA_AVAILABLE_NO;
jack->state_plugged = PA_AVAILABLE_YES;
jack->ucm_devices = pa_dynarray_new(NULL);
@@ -1857,7 +1852,7 @@ static pa_alsa_jack* jack_get(pa_alsa_path *p, const char *section) {
if (pa_streq(j->name, section))
goto finish;
- j = pa_alsa_jack_new(p, section, NULL);
+ j = pa_alsa_jack_new(p, section);
PA_LLIST_INSERT_AFTER(pa_alsa_jack, p->jacks, p->last_jack, j);
finish:
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index e5258c1..96a7a5e 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -172,7 +172,7 @@ struct pa_alsa_jack {
pa_dynarray *ucm_devices; /* pa_alsa_ucm_device */
};
-pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name, const char *alsa_name);
+pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name);
void pa_alsa_jack_free(pa_alsa_jack *jack);
void pa_alsa_jack_set_has_control(pa_alsa_jack *jack, bool has_control);
void pa_alsa_jack_set_plugged_in(pa_alsa_jack *jack, bool plugged_in);
diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c
index fde2d0c..d2c7140 100644
--- a/src/modules/alsa/alsa-ucm.c
+++ b/src/modules/alsa/alsa-ucm.c
@@ -1292,27 +1292,39 @@ static pa_alsa_jack* ucm_get_jack(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *d
pa_alsa_jack *j;
const char *device_name;
const char *jack_control;
- char *alsa_name;
+ char *name;
pa_assert(ucm);
pa_assert(device);
device_name = pa_proplist_gets(device->proplist, PA_ALSA_PROP_UCM_NAME);
- PA_LLIST_FOREACH(j, ucm->jacks)
- if (pa_streq(j->name, device_name))
- return j;
-
jack_control = pa_proplist_gets(device->proplist, PA_ALSA_PROP_UCM_JACK_CONTROL);
- if (jack_control)
- alsa_name = pa_xstrdup(jack_control);
- else
- alsa_name = pa_sprintf_malloc("%s Jack", device_name);
+ if (jack_control) {
+ if (!pa_endswith(jack_control, " Jack")) {
+ pa_log("[%s] Invalid JackControl value: \"%s\"", device_name, jack_control);
+ return NULL;
+ }
- j = pa_alsa_jack_new(NULL, device_name, alsa_name);
- pa_xfree(alsa_name);
+ /* pa_alsa_jack_new() expects a jack name without " Jack" at the
+ * end, so drop the trailing " Jack". */
+ name = pa_xstrndup(jack_control, strlen(jack_control) - 5);
+ } else {
+ /* The jack control hasn't been explicitly configured - try a jack name
+ * that is the same as the device name. */
+ name = pa_xstrdup(device_name);
+ }
+
+ PA_LLIST_FOREACH(j, ucm->jacks)
+ if (pa_streq(j->name, name))
+ goto finish;
+
+ j = pa_alsa_jack_new(NULL, name);
PA_LLIST_PREPEND(pa_alsa_jack, ucm->jacks, j);
+finish:
+ pa_xfree(name);
+
return j;
}
commit c9557e69692c4954e00ae468c0e974eb2263924f
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date: Mon May 4 21:03:43 2015 +0300
alsa: Move UCM port availability updating to the mixer code
Previously module-alsa-card assigned to pa_alsa_jack.plugged_in
directly, and then did the port availability updating manually. The
idea of pa_alsa_jack_set_plugged_in() is to move the availability
updating to the mixer infrastructure, where it really belongs.
Similarly, pa_alsa_jack.has_control was previously modified directly
from several places. The has_control field affects the port
availability, and pa_alsa_jack_set_has_control() takes care of
updating the availability.
For now, pa_alsa_jack_set_plugged_in() and
pa_alsa_jack_set_has_control() only update the port availability
when using UCM. My plan is to adapt the traditional mixer code later.
diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 0c56018..3f19aa9 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -139,6 +139,36 @@ void pa_alsa_jack_free(pa_alsa_jack *jack) {
pa_xfree(jack);
}
+void pa_alsa_jack_set_has_control(pa_alsa_jack *jack, bool has_control) {
+ pa_alsa_ucm_device *device;
+ unsigned idx;
+
+ pa_assert(jack);
+
+ if (has_control == jack->has_control)
+ return;
+
+ jack->has_control = has_control;
+
+ PA_DYNARRAY_FOREACH(device, jack->ucm_devices, idx)
+ pa_alsa_ucm_device_update_available(device);
+}
+
+void pa_alsa_jack_set_plugged_in(pa_alsa_jack *jack, bool plugged_in) {
+ pa_alsa_ucm_device *device;
+ unsigned idx;
+
+ pa_assert(jack);
+
+ if (plugged_in == jack->plugged_in)
+ return;
+
+ jack->plugged_in = plugged_in;
+
+ PA_DYNARRAY_FOREACH(device, jack->ucm_devices, idx)
+ pa_alsa_ucm_device_update_available(device);
+}
+
void pa_alsa_jack_add_ucm_device(pa_alsa_jack *jack, pa_alsa_ucm_device *device) {
pa_assert(jack);
pa_assert(device);
@@ -1755,10 +1785,13 @@ static int element_probe(pa_alsa_element *e, snd_mixer_t *m) {
}
static int jack_probe(pa_alsa_jack *j, snd_mixer_t *m) {
+ bool has_control;
+
pa_assert(j);
pa_assert(j->path);
- j->has_control = pa_alsa_mixer_find(m, j->alsa_name, 0) != NULL;
+ has_control = pa_alsa_mixer_find(m, j->alsa_name, 0) != NULL;
+ pa_alsa_jack_set_has_control(j, has_control);
if (j->has_control) {
if (j->required_absent != PA_ALSA_REQUIRED_IGNORE)
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index 92a61c2..e5258c1 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -174,6 +174,8 @@ struct pa_alsa_jack {
pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name, const char *alsa_name);
void pa_alsa_jack_free(pa_alsa_jack *jack);
+void pa_alsa_jack_set_has_control(pa_alsa_jack *jack, bool has_control);
+void pa_alsa_jack_set_plugged_in(pa_alsa_jack *jack, bool plugged_in);
void pa_alsa_jack_add_ucm_device(pa_alsa_jack *jack, pa_alsa_ucm_device *device);
/* A path wraps a series of elements into a single entity which can be
diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c
index 4b0adff..fde2d0c 100644
--- a/src/modules/alsa/alsa-ucm.c
+++ b/src/modules/alsa/alsa-ucm.c
@@ -90,6 +90,7 @@ struct ucm_port {
static struct ucm_port *ucm_port_new(pa_alsa_ucm_config *ucm, pa_device_port *core_port, pa_alsa_ucm_device **devices,
unsigned n_devices);
static void ucm_port_free(struct ucm_port *port);
+static void ucm_port_update_available(struct ucm_port *port);
static struct ucm_items item[] = {
{"PlaybackPCM", PA_ALSA_PROP_UCM_SINK},
@@ -413,6 +414,7 @@ static int ucm_get_devices(pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr) {
pa_proplist_sets(d->proplist, PA_ALSA_PROP_UCM_NAME, pa_strnull(dev_list[i]));
pa_proplist_sets(d->proplist, PA_ALSA_PROP_UCM_DESCRIPTION, pa_strna(dev_list[i + 1]));
d->ucm_ports = pa_dynarray_new(NULL);
+ d->available = PA_AVAILABLE_UNKNOWN;
PA_LLIST_PREPEND(pa_alsa_ucm_device, verb->devices, d);
}
@@ -1465,7 +1467,10 @@ static void ucm_mapping_jack_probe(pa_alsa_mapping *m) {
return;
PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) {
- dev->jack->has_control = pa_alsa_mixer_find(mixer_handle, dev->jack->alsa_name, 0) != NULL;
+ bool has_control;
+
+ has_control = pa_alsa_mixer_find(mixer_handle, dev->jack->alsa_name, 0) != NULL;
+ pa_alsa_jack_set_has_control(dev->jack, has_control);
pa_log_info("UCM jack %s has_control=%d", dev->jack->name, dev->jack->has_control);
}
@@ -1716,6 +1721,34 @@ static void device_set_jack(pa_alsa_ucm_device *device, pa_alsa_jack *jack) {
device->jack = jack;
pa_alsa_jack_add_ucm_device(jack, device);
+
+ pa_alsa_ucm_device_update_available(device);
+}
+
+static void device_set_available(pa_alsa_ucm_device *device, pa_available_t available) {
+ struct ucm_port *port;
+ unsigned idx;
+
+ pa_assert(device);
+
+ if (available == device->available)
+ return;
+
+ device->available = available;
+
+ PA_DYNARRAY_FOREACH(port, device->ucm_ports, idx)
+ ucm_port_update_available(port);
+}
+
+void pa_alsa_ucm_device_update_available(pa_alsa_ucm_device *device) {
+ pa_available_t available = PA_AVAILABLE_UNKNOWN;
+
+ pa_assert(device);
+
+ if (device->jack && device->jack->has_control)
+ available = device->jack->plugged_in ? PA_AVAILABLE_YES : PA_AVAILABLE_NO;
+
+ device_set_available(device, available);
}
static struct ucm_port *ucm_port_new(pa_alsa_ucm_config *ucm, pa_device_port *core_port, pa_alsa_ucm_device **devices,
@@ -1737,6 +1770,8 @@ static struct ucm_port *ucm_port_new(pa_alsa_ucm_config *ucm, pa_device_port *co
device_add_ucm_port(devices[i], port);
}
+ ucm_port_update_available(port);
+
return port;
}
@@ -1749,6 +1784,25 @@ static void ucm_port_free(struct ucm_port *port) {
pa_xfree(port);
}
+static void ucm_port_update_available(struct ucm_port *port) {
+ pa_alsa_ucm_device *device;
+ unsigned idx;
+ pa_available_t available = PA_AVAILABLE_YES;
+
+ pa_assert(port);
+
+ PA_DYNARRAY_FOREACH(device, port->devices, idx) {
+ if (device->available == PA_AVAILABLE_UNKNOWN)
+ available = PA_AVAILABLE_UNKNOWN;
+ else if (device->available == PA_AVAILABLE_NO) {
+ available = PA_AVAILABLE_NO;
+ break;
+ }
+ }
+
+ pa_device_port_set_available(port->core_port, available);
+}
+
#else /* HAVE_ALSA_UCM */
/* Dummy functions for systems without UCM support */
diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h
index 727d281..5ccc466 100644
--- a/src/modules/alsa/alsa-ucm.h
+++ b/src/modules/alsa/alsa-ucm.h
@@ -148,8 +148,11 @@ struct pa_alsa_ucm_device {
pa_dynarray *ucm_ports; /* struct ucm_port */
pa_alsa_jack *jack;
+ pa_available_t available;
};
+void pa_alsa_ucm_device_update_available(pa_alsa_ucm_device *device);
+
struct pa_alsa_ucm_modifier {
PA_LLIST_FIELDS(pa_alsa_ucm_modifier);
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index 382e40d..df4f848 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -378,16 +378,17 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) {
PA_HASHMAP_FOREACH(jack, u->jacks, state)
if (jack->melem == melem) {
- jack->plugged_in = plugged_in;
+ pa_alsa_jack_set_plugged_in(jack, plugged_in);
+
if (u->use_ucm) {
- pa_assert(u->card->ports);
- port = pa_hashmap_get(u->card->ports, jack->name);
- pa_assert(port);
- }
- else {
- pa_assert(jack->path);
- pa_assert_se(port = jack->path->port);
+ /* When using UCM, pa_alsa_jack_set_plugged_in() maps the jack
+ * state to port availability. */
+ continue;
}
+
+ /* When not using UCM, we have to do the jack state -> port
+ * availability mapping ourselves. */
+ pa_assert_se(port = jack->path->port);
report_port_state(port, u);
}
return 0;
@@ -515,7 +516,7 @@ static void init_jacks(struct userdata *u) {
jack->melem = pa_alsa_mixer_find(u->mixer_handle, jack->alsa_name, 0);
if (!jack->melem) {
pa_log_warn("Jack '%s' seems to have disappeared.", jack->alsa_name);
- jack->has_control = false;
+ pa_alsa_jack_set_has_control(jack, false);
continue;
}
snd_mixer_elem_set_callback(jack->melem, report_jack_state);
diff --git a/src/pulsecore/device-port.c b/src/pulsecore/device-port.c
index cfe2a80..906ab1f 100644
--- a/src/pulsecore/device-port.c
+++ b/src/pulsecore/device-port.c
@@ -66,8 +66,6 @@ void pa_device_port_new_data_done(pa_device_port_new_data *data) {
}
void pa_device_port_set_available(pa_device_port *p, pa_available_t status) {
- pa_core *core;
-
pa_assert(p);
if (p->available == status)
@@ -80,10 +78,14 @@ void pa_device_port_set_available(pa_device_port *p, pa_available_t status) {
status == PA_AVAILABLE_NO ? "no" : "unknown");
/* Post subscriptions to the card which owns us */
- pa_assert_se(core = p->core);
- pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, p->card->index);
-
- pa_hook_fire(&core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED], p);
+ /* XXX: We need to check p->card, because this function may be called
+ * before the card object has been created. The card object should probably
+ * be created before port objects, and then p->card could be non-NULL for
+ * the whole lifecycle of pa_device_port. */
+ if (p->card) {
+ pa_subscription_post(p->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, p->card->index);
+ pa_hook_fire(&p->core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED], p);
+ }
}
static void device_port_free(pa_object *o) {
commit 40714b6bcc0b2da87f0891ba90690714dfe34462
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date: Mon May 4 21:03:42 2015 +0300
alsa: Add associations between jacks, UCM devices and UCM ports
These associations will be used by subsequent UCM jack detection
refactoring work.
diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 3068fc3..0c56018 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -123,6 +123,7 @@ pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name, const char
jack->state_unplugged = PA_AVAILABLE_NO;
jack->state_plugged = PA_AVAILABLE_YES;
+ jack->ucm_devices = pa_dynarray_new(NULL);
return jack;
}
@@ -130,11 +131,21 @@ pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name, const char
void pa_alsa_jack_free(pa_alsa_jack *jack) {
pa_assert(jack);
+ if (jack->ucm_devices)
+ pa_dynarray_free(jack->ucm_devices);
+
pa_xfree(jack->alsa_name);
pa_xfree(jack->name);
pa_xfree(jack);
}
+void pa_alsa_jack_add_ucm_device(pa_alsa_jack *jack, pa_alsa_ucm_device *device) {
+ pa_assert(jack);
+ pa_assert(device);
+
+ pa_dynarray_append(jack->ucm_devices, device);
+}
+
static const char *lookup_description(const char *key, const struct description_map dm[], unsigned n) {
unsigned i;
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index 835361b..92a61c2 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -168,10 +168,13 @@ struct pa_alsa_jack {
pa_alsa_required_t required;
pa_alsa_required_t required_any;
pa_alsa_required_t required_absent;
+
+ pa_dynarray *ucm_devices; /* pa_alsa_ucm_device */
};
pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name, const char *alsa_name);
void pa_alsa_jack_free(pa_alsa_jack *jack);
+void pa_alsa_jack_add_ucm_device(pa_alsa_jack *jack, pa_alsa_ucm_device *device);
/* A path wraps a series of elements into a single entity which can be
* used to control it as if it had a single volume slider, a single
diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c
index 7ddb975..4b0adff 100644
--- a/src/modules/alsa/alsa-ucm.c
+++ b/src/modules/alsa/alsa-ucm.c
@@ -78,6 +78,19 @@ struct ucm_info {
static void device_set_jack(pa_alsa_ucm_device *device, pa_alsa_jack *jack);
+struct ucm_port {
+ pa_alsa_ucm_config *ucm;
+ pa_device_port *core_port;
+
+ /* A single port will be associated with multiple devices if it represents
+ * a combination of devices. */
+ pa_dynarray *devices; /* pa_alsa_ucm_device */
+};
+
+static struct ucm_port *ucm_port_new(pa_alsa_ucm_config *ucm, pa_device_port *core_port, pa_alsa_ucm_device **devices,
+ unsigned n_devices);
+static void ucm_port_free(struct ucm_port *port);
+
static struct ucm_items item[] = {
{"PlaybackPCM", PA_ALSA_PROP_UCM_SINK},
{"CapturePCM", PA_ALSA_PROP_UCM_SOURCE},
@@ -399,6 +412,7 @@ static int ucm_get_devices(pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr) {
d->proplist = pa_proplist_new();
pa_proplist_sets(d->proplist, PA_ALSA_PROP_UCM_NAME, pa_strnull(dev_list[i]));
pa_proplist_sets(d->proplist, PA_ALSA_PROP_UCM_DESCRIPTION, pa_strna(dev_list[i + 1]));
+ d->ucm_ports = pa_dynarray_new(NULL);
PA_LLIST_PREPEND(pa_alsa_ucm_device, verb->devices, d);
}
@@ -555,6 +569,8 @@ int pa_alsa_ucm_query_profiles(pa_alsa_ucm_config *ucm, int card_index) {
const char **verb_list;
int num_verbs, i, err = 0;
+ ucm->ports = pa_dynarray_new((pa_free_cb_t) ucm_port_free);
+
/* is UCM available for this card ? */
err = snd_card_get_name(card_index, &card_name);
if (err < 0) {
@@ -737,6 +753,8 @@ static void ucm_add_port_combination(
port = pa_hashmap_get(ports, name);
if (!port) {
+ struct ucm_port *ucm_port;
+
pa_device_port_new_data port_data;
pa_device_port_new_data_init(&port_data);
@@ -744,9 +762,12 @@ static void ucm_add_port_combination(
pa_device_port_new_data_set_description(&port_data, desc);
pa_device_port_new_data_set_direction(&port_data, is_sink ? PA_DIRECTION_OUTPUT : PA_DIRECTION_INPUT);
- port = pa_device_port_new(core, &port_data, 0);
+ port = pa_device_port_new(core, &port_data, sizeof(ucm_port));
pa_device_port_new_data_done(&port_data);
- pa_assert(port);
+
+ ucm_port = ucm_port_new(context->ucm, port, pdevices, num);
+ pa_dynarray_append(context->ucm->ports, ucm_port);
+ *((struct ucm_port **) PA_DEVICE_PORT_DATA(port)) = ucm_port;
pa_hashmap_put(ports, port->name, port);
pa_log_debug("Add port %s: %s", port->name, port->description);
@@ -1557,6 +1578,10 @@ static void free_verb(pa_alsa_ucm_verb *verb) {
PA_LLIST_FOREACH_SAFE(di, dn, verb->devices) {
PA_LLIST_REMOVE(pa_alsa_ucm_device, verb->devices, di);
+
+ if (di->ucm_ports)
+ pa_dynarray_free(di->ucm_ports);
+
pa_proplist_free(di->proplist);
if (di->conflicting_devices)
pa_idxset_free(di->conflicting_devices, NULL);
@@ -1583,6 +1608,9 @@ void pa_alsa_ucm_free(pa_alsa_ucm_config *ucm) {
pa_alsa_ucm_verb *vi, *vn;
pa_alsa_jack *ji, *jn;
+ if (ucm->ports)
+ pa_dynarray_free(ucm->ports);
+
PA_LLIST_FOREACH_SAFE(vi, vn, ucm->verbs) {
PA_LLIST_REMOVE(pa_alsa_ucm_verb, ucm->verbs, vi);
free_verb(vi);
@@ -1675,10 +1703,50 @@ void pa_alsa_ucm_roled_stream_end(pa_alsa_ucm_config *ucm, const char *role, pa_
}
}
+static void device_add_ucm_port(pa_alsa_ucm_device *device, struct ucm_port *port) {
+ pa_assert(device);
+ pa_assert(port);
+
+ pa_dynarray_append(device->ucm_ports, port);
+}
+
static void device_set_jack(pa_alsa_ucm_device *device, pa_alsa_jack *jack) {
pa_assert(device);
+ pa_assert(jack);
device->jack = jack;
+ pa_alsa_jack_add_ucm_device(jack, device);
+}
+
+static struct ucm_port *ucm_port_new(pa_alsa_ucm_config *ucm, pa_device_port *core_port, pa_alsa_ucm_device **devices,
+ unsigned n_devices) {
+ struct ucm_port *port;
+ unsigned i;
+
+ pa_assert(ucm);
+ pa_assert(core_port);
+ pa_assert(devices);
+
+ port = pa_xnew0(struct ucm_port, 1);
+ port->ucm = ucm;
+ port->core_port = core_port;
+ port->devices = pa_dynarray_new(NULL);
+
+ for (i = 0; i < n_devices; i++) {
+ pa_dynarray_append(port->devices, devices[i]);
+ device_add_ucm_port(devices[i], port);
+ }
+
+ return port;
+}
+
+static void ucm_port_free(struct ucm_port *port) {
+ pa_assert(port);
+
+ if (port->devices)
+ pa_dynarray_free(port->devices);
+
+ pa_xfree(port);
}
#else /* HAVE_ALSA_UCM */
diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h
index 8ce9b4b..727d281 100644
--- a/src/modules/alsa/alsa-ucm.h
+++ b/src/modules/alsa/alsa-ucm.h
@@ -142,6 +142,11 @@ struct pa_alsa_ucm_device {
pa_idxset *conflicting_devices;
pa_idxset *supported_devices;
+ /* One device may be part of multiple ports, since each device has
+ * a dedicated port, and in addition to that we sometimes generate ports
+ * that represent combinations of devices. */
+ pa_dynarray *ucm_ports; /* struct ucm_port */
+
pa_alsa_jack *jack;
};
@@ -184,6 +189,7 @@ struct pa_alsa_ucm_config {
PA_LLIST_HEAD(pa_alsa_ucm_verb, verbs);
PA_LLIST_HEAD(pa_alsa_jack, jacks);
+ pa_dynarray *ports; /* struct ucm_port */
};
struct pa_alsa_ucm_mapping_context {
commit d7ce78b234470f035dc1abe0455cd3a6f0c5dc72
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date: Mon May 4 21:03:41 2015 +0300
ucm: Don't create separate input and output jacks
The UCM spec doesn't support separate input and output jacks, so it's
redundant to have separate input and output jacks in
pa_alsa_ucm_device.
diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c
index 98d9a5d..7ddb975 100644
--- a/src/modules/alsa/alsa-ucm.c
+++ b/src/modules/alsa/alsa-ucm.c
@@ -76,6 +76,8 @@ struct ucm_info {
unsigned priority;
};
+static void device_set_jack(pa_alsa_ucm_device *device, pa_alsa_jack *jack);
+
static struct ucm_items item[] = {
{"PlaybackPCM", PA_ALSA_PROP_UCM_SINK},
{"CapturePCM", PA_ALSA_PROP_UCM_SOURCE},
@@ -1263,23 +1265,20 @@ static int ucm_create_mapping(
return ret;
}
-static pa_alsa_jack* ucm_get_jack(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *device, const char *pre_tag) {
+static pa_alsa_jack* ucm_get_jack(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *device) {
pa_alsa_jack *j;
const char *device_name;
- char *name;
const char *jack_control;
char *alsa_name;
pa_assert(ucm);
pa_assert(device);
- pa_assert(pre_tag);
device_name = pa_proplist_gets(device->proplist, PA_ALSA_PROP_UCM_NAME);
- name = pa_sprintf_malloc("%s%s", pre_tag, device_name);
PA_LLIST_FOREACH(j, ucm->jacks)
- if (pa_streq(j->name, name))
- goto out;
+ if (pa_streq(j->name, device_name))
+ return j;
jack_control = pa_proplist_gets(device->proplist, PA_ALSA_PROP_UCM_JACK_CONTROL);
if (jack_control)
@@ -1287,12 +1286,10 @@ static pa_alsa_jack* ucm_get_jack(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *d
else
alsa_name = pa_sprintf_malloc("%s Jack", device_name);
- j = pa_alsa_jack_new(NULL, name, alsa_name);
+ j = pa_alsa_jack_new(NULL, device_name, alsa_name);
pa_xfree(alsa_name);
PA_LLIST_PREPEND(pa_alsa_jack, ucm->jacks, j);
-out:
- pa_xfree(name);
return j;
}
@@ -1348,6 +1345,8 @@ static int ucm_create_profile(
p->priority = 1000;
PA_LLIST_FOREACH(dev, verb->devices) {
+ pa_alsa_jack *jack;
+
name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME);
sink = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_SINK);
@@ -1355,10 +1354,8 @@ static int ucm_create_profile(
ucm_create_mapping(ucm, ps, p, dev, verb_name, name, sink, source);
- if (sink)
- dev->output_jack = ucm_get_jack(ucm, dev, PA_UCM_PRE_TAG_OUTPUT);
- if (source)
- dev->input_jack = ucm_get_jack(ucm, dev, PA_UCM_PRE_TAG_INPUT);
+ jack = ucm_get_jack(ucm, dev);
+ device_set_jack(dev, jack);
}
/* Now find modifiers that have their own PlaybackPCM and create
@@ -1447,11 +1444,8 @@ static void ucm_mapping_jack_probe(pa_alsa_mapping *m) {
return;
PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) {
- pa_alsa_jack *jack;
- jack = m->direction == PA_ALSA_DIRECTION_OUTPUT ? dev->output_jack : dev->input_jack;
- pa_assert (jack);
- jack->has_control = pa_alsa_mixer_find(mixer_handle, jack->alsa_name, 0) != NULL;
- pa_log_info("UCM jack %s has_control=%d", jack->name, jack->has_control);
+ dev->jack->has_control = pa_alsa_mixer_find(mixer_handle, dev->jack->alsa_name, 0) != NULL;
+ pa_log_info("UCM jack %s has_control=%d", dev->jack->name, dev->jack->has_control);
}
snd_mixer_close(mixer_handle);
@@ -1681,6 +1675,12 @@ void pa_alsa_ucm_roled_stream_end(pa_alsa_ucm_config *ucm, const char *role, pa_
}
}
+static void device_set_jack(pa_alsa_ucm_device *device, pa_alsa_jack *jack) {
+ pa_assert(device);
+
+ device->jack = jack;
+}
+
#else /* HAVE_ALSA_UCM */
/* Dummy functions for systems without UCM support */
diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h
index a8c8090..8ce9b4b 100644
--- a/src/modules/alsa/alsa-ucm.h
+++ b/src/modules/alsa/alsa-ucm.h
@@ -142,8 +142,7 @@ struct pa_alsa_ucm_device {
pa_idxset *conflicting_devices;
pa_idxset *supported_devices;
- pa_alsa_jack *input_jack;
- pa_alsa_jack *output_jack;
+ pa_alsa_jack *jack;
};
struct pa_alsa_ucm_modifier {
commit f5fecff0b4cef99f7881ad146b72d44e4f06a698
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date: Mon May 4 21:03:40 2015 +0300
alsa: Add pa_alsa_jack_new() and pa_alsa_jack_free()
This reduces code duplication in alsa-mixer.c and alsa-ucm.c. No
functional changes.
diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index bbe1d0f..3068fc3 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -107,6 +107,34 @@ struct description_map {
const char *description;
};
+pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name, const char *alsa_name) {
+ pa_alsa_jack *jack;
+
+ pa_assert(name);
+
+ jack = pa_xnew0(pa_alsa_jack, 1);
+ jack->path = path;
+ jack->name = pa_xstrdup(name);
+
+ if (alsa_name)
+ jack->alsa_name = pa_xstrdup(alsa_name);
+ else
+ jack->alsa_name = pa_sprintf_malloc("%s Jack", name);
+
+ jack->state_unplugged = PA_AVAILABLE_NO;
+ jack->state_plugged = PA_AVAILABLE_YES;
+
+ return jack;
+}
+
+void pa_alsa_jack_free(pa_alsa_jack *jack) {
+ pa_assert(jack);
+
+ pa_xfree(jack->alsa_name);
+ pa_xfree(jack->name);
+ pa_xfree(jack);
+}
+
static const char *lookup_description(const char *key, const struct description_map dm[], unsigned n) {
unsigned i;
@@ -524,14 +552,6 @@ static void decibel_fix_free(pa_alsa_decibel_fix *db_fix) {
pa_xfree(db_fix);
}
-static void jack_free(pa_alsa_jack *j) {
- pa_assert(j);
-
- pa_xfree(j->alsa_name);
- pa_xfree(j->name);
- pa_xfree(j);
-}
-
static void element_free(pa_alsa_element *e) {
pa_alsa_option *o;
pa_assert(e);
@@ -557,7 +577,7 @@ void pa_alsa_path_free(pa_alsa_path *p) {
while ((j = p->jacks)) {
PA_LLIST_REMOVE(pa_alsa_jack, p->jacks, j);
- jack_free(j);
+ pa_alsa_jack_free(j);
}
while ((e = p->elements)) {
@@ -1793,12 +1813,7 @@ static pa_alsa_jack* jack_get(pa_alsa_path *p, const char *section) {
if (pa_streq(j->name, section))
goto finish;
- j = pa_xnew0(pa_alsa_jack, 1);
- j->state_unplugged = PA_AVAILABLE_NO;
- j->state_plugged = PA_AVAILABLE_YES;
- j->path = p;
- j->name = pa_xstrdup(section);
- j->alsa_name = pa_sprintf_malloc("%s Jack", section);
+ j = pa_alsa_jack_new(p, section, NULL);
PA_LLIST_INSERT_AFTER(pa_alsa_jack, p->jacks, p->last_jack, j);
finish:
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index ec39fab..835361b 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -170,6 +170,9 @@ struct pa_alsa_jack {
pa_alsa_required_t required_absent;
};
+pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name, const char *alsa_name);
+void pa_alsa_jack_free(pa_alsa_jack *jack);
+
/* A path wraps a series of elements into a single entity which can be
* used to control it as if it had a single volume slider, a single
* mute switch and a single list of selectable options. */
diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c
index ef6adcd..98d9a5d 100644
--- a/src/modules/alsa/alsa-ucm.c
+++ b/src/modules/alsa/alsa-ucm.c
@@ -1268,6 +1268,7 @@ static pa_alsa_jack* ucm_get_jack(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *d
const char *device_name;
char *name;
const char *jack_control;
+ char *alsa_name;
pa_assert(ucm);
pa_assert(device);
@@ -1280,17 +1281,14 @@ static pa_alsa_jack* ucm_get_jack(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *d
if (pa_streq(j->name, name))
goto out;
- j = pa_xnew0(pa_alsa_jack, 1);
- j->state_unplugged = PA_AVAILABLE_NO;
- j->state_plugged = PA_AVAILABLE_YES;
- j->name = pa_xstrdup(name);
-
jack_control = pa_proplist_gets(device->proplist, PA_ALSA_PROP_UCM_JACK_CONTROL);
if (jack_control)
- j->alsa_name = pa_xstrdup(jack_control);
+ alsa_name = pa_xstrdup(jack_control);
else
- j->alsa_name = pa_sprintf_malloc("%s Jack", device_name);
+ alsa_name = pa_sprintf_malloc("%s Jack", device_name);
+ j = pa_alsa_jack_new(NULL, name, alsa_name);
+ pa_xfree(alsa_name);
PA_LLIST_PREPEND(pa_alsa_jack, ucm->jacks, j);
out:
@@ -1597,9 +1595,7 @@ void pa_alsa_ucm_free(pa_alsa_ucm_config *ucm) {
}
PA_LLIST_FOREACH_SAFE(ji, jn, ucm->jacks) {
PA_LLIST_REMOVE(pa_alsa_jack, ucm->jacks, ji);
- pa_xfree(ji->alsa_name);
- pa_xfree(ji->name);
- pa_xfree(ji);
+ pa_alsa_jack_free(ji);
}
if (ucm->ucm_mgr) {
snd_use_case_mgr_close(ucm->ucm_mgr);
More information about the pulseaudio-commits
mailing list