]> code.delx.au - pulseaudio/commitdiff
alsa-mixer: Make speaker get available=no when headphones are plugged in
authorDavid Henningsson <david.henningsson@canonical.com>
Thu, 23 Feb 2012 06:17:07 +0000 (07:17 +0100)
committerArun Raghavan <arun.raghavan@collabora.co.uk>
Sun, 11 Mar 2012 06:53:46 +0000 (12:23 +0530)
While developing the new UI we had to ask ourselves the question of whether
"speakers" should be considered available when headphones are plugged in.
In most cases, they are not available and therefore we should list them
as such.

OTOH, we don't want unplugging the headphones to be considered an act of
wanting to use the speakers (the user might prefer HDMI), and there might
be line-outs that keeps the speakers from unmuting anyway. So, at this point,
I think the most reasonable would be to make the speakers have
PA_PORT_AVAILABLE_NO when headphones are plugged in and
PA_PORT_AVAILABLE_UNKNOWN when they are not. But we might want to revisit
this decision once we have the priority lists up and running.

The same reasoning applies for "Internal Mic", which should become unavailable
when any other mic is plugged in.

Signed-off-by: David Henningsson <david.henningsson@canonical.com>
src/modules/alsa/alsa-mixer.c
src/modules/alsa/alsa-mixer.h
src/modules/alsa/mixer/paths/analog-input-internal-mic.conf
src/modules/alsa/mixer/paths/analog-output-speaker.conf
src/modules/alsa/module-alsa-card.c
src/modules/module-switch-on-port-available.c
src/pulsecore/device-port.c

index 1813ad9f8e24320f6089aeaab2050e39a07c1d5b..59a9ac9fedda89be081737f9bc4290a4da414d39 100644 (file)
@@ -1724,6 +1724,8 @@ static pa_alsa_jack* jack_get(pa_alsa_path *p, const char *section) {
             goto finish;
 
     j = pa_xnew0(pa_alsa_jack, 1);
             goto finish;
 
     j = pa_xnew0(pa_alsa_jack, 1);
+    j->state_unplugged = PA_PORT_AVAILABLE_NO;
+    j->state_plugged = PA_PORT_AVAILABLE_YES;
     j->path = p;
     j->name = pa_xstrdup(section);
     j->alsa_name = pa_sprintf_malloc("%s Jack", section);
     j->path = p;
     j->name = pa_xstrdup(section);
     j->alsa_name = pa_sprintf_malloc("%s Jack", section);
@@ -2187,6 +2189,45 @@ static int element_parse_override_map(
     return 0;
 }
 
     return 0;
 }
 
+static int jack_parse_state(
+        const char *filename,
+        unsigned line,
+        const char *section,
+        const char *lvalue,
+        const char *rvalue,
+        void *data,
+        void *userdata) {
+
+    pa_alsa_path *p = userdata;
+    pa_alsa_jack *j;
+    pa_port_available_t pa;
+
+    if (!(j = jack_get(p, section))) {
+        pa_log("[%s:%u] state makes no sense in '%s'", filename, line, section);
+        return -1;
+    }
+
+    if (!strcmp(rvalue,"yes"))
+       pa = PA_PORT_AVAILABLE_YES;
+    else if (!strcmp(rvalue,"no"))
+       pa = PA_PORT_AVAILABLE_NO;
+    else if (!strcmp(rvalue,"unknown"))
+       pa = PA_PORT_AVAILABLE_UNKNOWN;
+    else {
+        pa_log("[%s:%u] state must be 'yes','no' or 'unknown' in '%s'", filename, line, section);
+        return -1;
+    }
+
+    if (!strcmp(lvalue, "state.unplugged"))
+        j->state_unplugged = pa;
+    else {
+        j->state_plugged = pa;
+        pa_assert(!strcmp(lvalue, "state.plugged"));
+    }
+
+    return 0;
+}
+
 static int element_set_option(pa_alsa_element *e, snd_mixer_t *m, int alsa_idx) {
     snd_mixer_selem_id_t *sid;
     snd_mixer_elem_t *me;
 static int element_set_option(pa_alsa_element *e, snd_mixer_t *m, int alsa_idx) {
     snd_mixer_selem_id_t *sid;
     snd_mixer_elem_t *me;
@@ -2380,6 +2421,10 @@ pa_alsa_path* pa_alsa_path_new(const char *paths_dir, const char *fname, pa_alsa
         { "priority",            option_parse_priority,             NULL, NULL },
         { "name",                option_parse_name,                 NULL, NULL },
 
         { "priority",            option_parse_priority,             NULL, NULL },
         { "name",                option_parse_name,                 NULL, NULL },
 
+        /* [Jack ...] */
+        { "state.plugged",       jack_parse_state,                  NULL, NULL },
+        { "state.unplugged",     jack_parse_state,                  NULL, NULL },
+
         /* [Element ...] */
         { "switch",              element_parse_switch,              NULL, NULL },
         { "volume",              element_parse_volume,              NULL, NULL },
         /* [Element ...] */
         { "switch",              element_parse_switch,              NULL, NULL },
         { "volume",              element_parse_volume,              NULL, NULL },
index 1912ba18011f9db58ce4ef6229e07ab67a3fddc7..59bd3fbe0af05b4dc747ea40e4f295ebd698e71e 100644 (file)
@@ -164,6 +164,7 @@ struct pa_alsa_jack {
     pa_bool_t has_control; /* is the jack itself present? */
     pa_bool_t plugged_in; /* is this jack currently plugged in? */
     snd_hctl_elem_t *hctl_elem; /* Jack detection handle */
     pa_bool_t has_control; /* is the jack itself present? */
     pa_bool_t plugged_in; /* is this jack currently plugged in? */
     snd_hctl_elem_t *hctl_elem; /* Jack detection handle */
+    pa_port_available_t state_unplugged, state_plugged;
 
     pa_alsa_required_t required;
     pa_alsa_required_t required_any;
 
     pa_alsa_required_t required;
     pa_alsa_required_t required_any;
index dd400754e98af4b4d303416dd877bac0ef9c0af5..ba15f1c7a6d2228c6dde3fb7823f9e57e71049d8 100644 (file)
 priority = 89
 name = analog-input-microphone-internal
 
 priority = 89
 name = analog-input-microphone-internal
 
+[Jack Mic]
+state.plugged = no
+state.unplugged = unknown
+
+[Jack Dock Mic]
+state.plugged = no
+state.unplugged = unknown
+
+[Jack Front Mic]
+state.plugged = no
+state.unplugged = unknown
+
+[Jack Rear Mic]
+state.plugged = no
+state.unplugged = unknown
+
 [Element Internal Mic Boost]
 required-any = any
 switch = select
 [Element Internal Mic Boost]
 required-any = any
 switch = select
index 0ba3e911c445fd6bfa97d12da9c0132985723884..9c58ed9fcddc7a426095b00fd5bc36763de8095c 100644 (file)
 priority = 100
 name = analog-output-speaker
 
 priority = 100
 name = analog-output-speaker
 
+[Jack Headphone]
+state.plugged = no
+state.unplugged = unknown
+
 [Element Hardware Master]
 switch = mute
 volume = merge
 [Element Hardware Master]
 switch = mute
 volume = merge
index c5bffcd295f525bc503bda43ad140aba4c7b1e1e..3493465ad3bcbc3de6d85f79e1f1a7cd00c34709 100644 (file)
@@ -288,7 +288,7 @@ static void report_port_state(pa_device_port *p, struct userdata *u)
         if (p != jack->path->port)
             continue;
 
         if (p != jack->path->port)
             continue;
 
-        cpa = jack->plugged_in ? PA_PORT_AVAILABLE_YES : PA_PORT_AVAILABLE_NO;
+        cpa = jack->plugged_in ? jack->state_plugged : jack->state_unplugged;
 
         /* "Yes" and "no" trumphs "unknown" if we have more than one jack */
         if (cpa == PA_PORT_AVAILABLE_UNKNOWN)
 
         /* "Yes" and "no" trumphs "unknown" if we have more than one jack */
         if (cpa == PA_PORT_AVAILABLE_UNKNOWN)
index 9149b6dd4d7445acf2b029da121906b2ea79e2e4..0a115d32e6f6321d8468655dee168e58f22a175e 100644 (file)
@@ -120,6 +120,9 @@ static pa_hook_result_t port_available_hook_callback(pa_core *c, pa_device_port
     pa_source *source;
     pa_bool_t is_active_profile, is_active_port;
 
     pa_source *source;
     pa_bool_t is_active_profile, is_active_port;
 
+    if (port->available == PA_PORT_AVAILABLE_UNKNOWN)
+        return PA_HOOK_OK;
+
     pa_log_debug("finding port %s", port->name);
 
     PA_IDXSET_FOREACH(card, c->cards, state)
     pa_log_debug("finding port %s", port->name);
 
     PA_IDXSET_FOREACH(card, c->cards, state)
index 30fb02529ef26be9961c36321f110e9061c96f17..50c99b8f238aa13b65d828a45a131cb144bd1ec3 100644 (file)
@@ -39,10 +39,11 @@ void pa_device_port_set_available(pa_device_port *p, pa_port_available_t status)
     if (p->available == status)
         return;
 
     if (p->available == status)
         return;
 
-    pa_assert(status != PA_PORT_AVAILABLE_UNKNOWN);
+/*    pa_assert(status != PA_PORT_AVAILABLE_UNKNOWN); */
 
     p->available = status;
 
     p->available = status;
-    pa_log_debug("Setting port %s to status %s", p->name, status == PA_PORT_AVAILABLE_YES ? "yes" : "no");
+    pa_log_debug("Setting port %s to status %s", p->name, status == PA_PORT_AVAILABLE_YES ? "yes" :
+       status == PA_PORT_AVAILABLE_NO ? "no" : "unknown");
 
     /* Post subscriptions to the card which owns us */
     pa_assert_se(core = p->core);
 
     /* Post subscriptions to the card which owns us */
     pa_assert_se(core = p->core);