summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Henningsson <david.henningsson@canonical.com>2015-05-05 17:01:13 +0200
committerTanu Kaskinen <tanuk@iki.fi>2015-10-19 17:12:21 +0300
commit2e9c01193218e8b2c575732c7be8bc93dcfa5cdd (patch)
tree6b53d178b37f302622737db1eae0ccb07f7b75f2
parent470335638640e9515fb56e2fa4ae9117b785c383 (diff)
downloadpulseaudio-2e9c01193218e8b2c575732c7be8bc93dcfa5cdd.tar.gz
module-alsa-card: Report available ports before unavailable ones
In case the same jack causes one port to become available and another one unavailable, the available should be reported first. This is to avoid unnecessary changes: e g, consider a 'Headphone Jack' making 'Headphone' available and 'Speaker' unavailable. In case the unavailable change triggers first, and there is also a currently available third port (e g 'Digital out'), the routing system might choose to route to this port because neither of the 'Speaker' and 'Headphone' ports are available. Signed-off-by: David Henningsson <david.henningsson@canonical.com>
-rw-r--r--src/modules/alsa/module-alsa-card.c31
1 files changed, 25 insertions, 6 deletions
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index a88a83ff4..286cfc9e2 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -306,7 +306,7 @@ static void init_profile(struct userdata *u) {
am->source = pa_alsa_source_new(u->module, u->modargs, __FILE__, u->card, am);
}
-static void report_port_state(pa_device_port *p, struct userdata *u) {
+static pa_available_t calc_port_state(pa_device_port *p, struct userdata *u) {
void *state;
pa_alsa_jack *jack;
pa_available_t pa = PA_AVAILABLE_UNKNOWN;
@@ -350,10 +350,14 @@ static void report_port_state(pa_device_port *p, struct userdata *u) {
pa = cpa;
}
}
-
- pa_device_port_set_available(p, pa);
+ return pa;
}
+struct temp_port_avail {
+ pa_device_port *port;
+ pa_available_t avail;
+};
+
static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) {
struct userdata *u = snd_mixer_elem_get_callback_private(melem);
snd_hctl_elem_t *elem = snd_mixer_elem_get_private(melem);
@@ -361,7 +365,7 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) {
bool plugged_in;
void *state;
pa_alsa_jack *jack;
- pa_device_port *port;
+ struct temp_port_avail *tp, *tports;
pa_assert(u);
@@ -378,6 +382,8 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) {
pa_log_debug("Jack '%s' is now %s", pa_strnull(snd_hctl_elem_get_name(elem)), plugged_in ? "plugged in" : "unplugged");
+ tports = tp = pa_xnew0(struct temp_port_avail, pa_hashmap_size(u->jacks)+1);
+
PA_HASHMAP_FOREACH(jack, u->jacks, state)
if (jack->melem == melem) {
pa_alsa_jack_set_plugged_in(jack, plugged_in);
@@ -390,9 +396,22 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) {
/* 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);
+ pa_assert_se(tp->port = jack->path->port);
+ tp->avail = calc_port_state(tp->port, u);
+ tp++;
}
+
+ /* Report available ports before unavailable ones: in case port 1 becomes available when port 2 becomes unavailable,
+ this prevents an unnecessary switch port 1 -> port 3 -> port 2 */
+
+ for (tp = tports; tp->port; tp++)
+ if (tp->avail != PA_AVAILABLE_NO)
+ pa_device_port_set_available(tp->port, tp->avail);
+ for (tp = tports; tp->port; tp++)
+ if (tp->avail == PA_AVAILABLE_NO)
+ pa_device_port_set_available(tp->port, tp->avail);
+
+ pa_xfree(tports);
return 0;
}