alsa-mixer: Make speaker get available=no when headphones are plugged in

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>
This commit is contained in:
David Henningsson 2012-02-23 07:17:07 +01:00 committed by Arun Raghavan
parent 793f46320e
commit e02cb7fb2e
7 changed files with 73 additions and 3 deletions

View 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);
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);
@ -2187,6 +2189,45 @@ static int element_parse_override_map(
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;
@ -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 },
/* [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 },

View 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_port_available_t state_unplugged, state_plugged;
pa_alsa_required_t required;
pa_alsa_required_t required_any;

View file

@ -23,6 +23,22 @@
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

View file

@ -22,6 +22,10 @@
priority = 100
name = analog-output-speaker
[Jack Headphone]
state.plugged = no
state.unplugged = unknown
[Element Hardware Master]
switch = mute
volume = merge

View file

@ -288,7 +288,7 @@ static void report_port_state(pa_device_port *p, struct userdata *u)
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)

View 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;
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)

View 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;
pa_assert(status != PA_PORT_AVAILABLE_UNKNOWN);
/* pa_assert(status != PA_PORT_AVAILABLE_UNKNOWN); */
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);