mirror of
https://gitlab.gnome.org/GNOME/libgnome-volume-control.git
synced 2024-12-22 04:12:07 +00:00
mixer-control: consolidate port finding and setting with/without ucm
Recently Intel added a new audio driver in the Linux kernel, it is called sof driver. This driver is needed on the laptops which connects the digital mic to the PCH instead of the codec. To make the sof driver work with pulseaudio, the ucm is mandatory. With the ucm, the multi-function audio jack has different port names in the pulseaudio from the one without ucm, these are the port names with the ucm: [In] Mic1: Digital Microphone [In] Mic2: Headphones Stereo Microphone [In] Headset: Headset Mono Microphone [Out] Headphones: Headphones [Out] Speaker: Speaker To make the audio device selection work on the machines using the ucm, the pulseaudio introduces a change to add 2 new members in the device port structure from the PA_PROTOCOL_VERSION=34, with these 2 members' help, we could consolidate the port finding and setting for both with ucm and without ucm. And this patch maintains the backward compatibility with the PA_PROTOCOL_VERSION < 34.
This commit is contained in:
parent
0aab80a78c
commit
960e01d957
@ -62,6 +62,7 @@ struct GvcMixerControlPrivate
|
||||
pa_glib_mainloop *pa_mainloop;
|
||||
pa_mainloop_api *pa_api;
|
||||
pa_context *pa_context;
|
||||
guint server_protocol_version;
|
||||
int n_outstanding;
|
||||
guint reconnect_id;
|
||||
char *name;
|
||||
@ -104,6 +105,11 @@ struct GvcMixerControlPrivate
|
||||
gboolean has_headsetmic;
|
||||
gboolean has_headphonemic;
|
||||
gboolean headset_plugged_in;
|
||||
char *headphones_name;
|
||||
char *headsetmic_name;
|
||||
char *headphonemic_name;
|
||||
char *internalspk_name;
|
||||
char *internalmic_name;
|
||||
#endif /* HAVE_ALSA */
|
||||
|
||||
GvcMixerControlState state;
|
||||
@ -2173,6 +2179,19 @@ source_info_cb (pa_context *c,
|
||||
|
||||
s = data->port_name_to_set;
|
||||
|
||||
for (j = 0; j < i->n_ports; j++) {
|
||||
if (g_str_equal (i->ports[j]->name, s)) {
|
||||
o = pa_context_set_default_source (c,
|
||||
i->name,
|
||||
NULL,
|
||||
NULL);
|
||||
if (o == NULL) {
|
||||
g_warning ("pa_context_set_default_source() failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i->active_port && strcmp (i->active_port->name, s) == 0)
|
||||
return;
|
||||
|
||||
@ -2196,6 +2215,9 @@ gvc_mixer_control_set_port_status_for_headset (GvcMixerControl *control,
|
||||
pa_operation *o;
|
||||
PortStatusData *data;
|
||||
|
||||
if (port_name == NULL)
|
||||
return;
|
||||
|
||||
data = g_new0 (PortStatusData, 1);
|
||||
data->port_name_to_set = g_strdup (port_name);
|
||||
data->headset_card = id;
|
||||
@ -2209,6 +2231,18 @@ gvc_mixer_control_set_port_status_for_headset (GvcMixerControl *control,
|
||||
}
|
||||
#endif /* HAVE_ALSA */
|
||||
|
||||
static void
|
||||
free_priv_port_names (GvcMixerControl *control)
|
||||
{
|
||||
#ifdef HAVE_ALSA
|
||||
g_clear_pointer (&control->priv->headphones_name, g_free);
|
||||
g_clear_pointer (&control->priv->headsetmic_name, g_free);
|
||||
g_clear_pointer (&control->priv->headphonemic_name, g_free);
|
||||
g_clear_pointer (&control->priv->internalspk_name, g_free);
|
||||
g_clear_pointer (&control->priv->internalmic_name, g_free);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
gvc_mixer_control_set_headset_port (GvcMixerControl *control,
|
||||
guint id,
|
||||
@ -2219,16 +2253,16 @@ gvc_mixer_control_set_headset_port (GvcMixerControl *control,
|
||||
#ifdef HAVE_ALSA
|
||||
switch (choice) {
|
||||
case GVC_HEADSET_PORT_CHOICE_HEADPHONES:
|
||||
gvc_mixer_control_set_port_status_for_headset (control, id, "analog-output-headphones", TRUE);
|
||||
gvc_mixer_control_set_port_status_for_headset (control, id, "analog-input-internal-mic", FALSE);
|
||||
gvc_mixer_control_set_port_status_for_headset (control, id, control->priv->headphones_name, TRUE);
|
||||
gvc_mixer_control_set_port_status_for_headset (control, id, control->priv->internalmic_name, FALSE);
|
||||
break;
|
||||
case GVC_HEADSET_PORT_CHOICE_HEADSET:
|
||||
gvc_mixer_control_set_port_status_for_headset (control, id, "analog-output-headphones", TRUE);
|
||||
gvc_mixer_control_set_port_status_for_headset (control, id, "analog-input-headset-mic", FALSE);
|
||||
gvc_mixer_control_set_port_status_for_headset (control, id, control->priv->headphones_name, TRUE);
|
||||
gvc_mixer_control_set_port_status_for_headset (control, id, control->priv->headsetmic_name, FALSE);
|
||||
break;
|
||||
case GVC_HEADSET_PORT_CHOICE_MIC:
|
||||
gvc_mixer_control_set_port_status_for_headset (control, id, "analog-output-speaker", TRUE);
|
||||
gvc_mixer_control_set_port_status_for_headset (control, id, "analog-input-headphone-mic", FALSE);
|
||||
gvc_mixer_control_set_port_status_for_headset (control, id, control->priv->internalspk_name, TRUE);
|
||||
gvc_mixer_control_set_port_status_for_headset (control, id, control->priv->headphonemic_name, FALSE);
|
||||
break;
|
||||
case GVC_HEADSET_PORT_CHOICE_NONE:
|
||||
default:
|
||||
@ -2244,16 +2278,24 @@ typedef struct {
|
||||
const pa_card_port_info *headphones;
|
||||
const pa_card_port_info *headsetmic;
|
||||
const pa_card_port_info *headphonemic;
|
||||
const pa_card_port_info *internalmic;
|
||||
const pa_card_port_info *internalspk;
|
||||
} headset_ports;
|
||||
|
||||
/*
|
||||
TODO: Check if we still need this with the changed PA port names
|
||||
|
||||
In PulseAudio ports will show up with the following names:
|
||||
In PulseAudio without ucm, ports will show up with the following names:
|
||||
Headphones - analog-output-headphones
|
||||
Headset mic - analog-input-headset-mic (was: analog-input-microphone-headset)
|
||||
Jack in mic-in mode - analog-input-headphone-mic (was: analog-input-microphone)
|
||||
|
||||
In PulseAudio with ucm, the ports name depends on the ucm, with the current
|
||||
ucm2, the ports will show up with the following names:
|
||||
Headphones - [Out] Headphone
|
||||
Headset mic - [In] Headset
|
||||
Jack in mic-in mode - [In] Mic2
|
||||
|
||||
However, since regular mics also show up as analog-input-microphone,
|
||||
we need to check for certain controls on alsa mixer level too, to know
|
||||
if we deal with a separate mic jack, or a multi-function jack with a
|
||||
@ -2268,10 +2310,18 @@ typedef struct {
|
||||
Headset Mic Jack - indicates headset jack where hardware can distinguish
|
||||
between headphones and headsets. There is no use popping up a dialog in
|
||||
this case, unless we already need to do this for the mic-in mode.
|
||||
|
||||
From the PA_PROCOTOL_VERSION=34, The device_port structure adds 2 members
|
||||
available_group and type, with the help of these 2 members, we could
|
||||
consolidate the port checking and port setting for non-ucm and with-ucm
|
||||
cases.
|
||||
*/
|
||||
|
||||
#define GET_PORT_NAME(x) (x ? g_strdup (x->name) : NULL)
|
||||
|
||||
static headset_ports *
|
||||
get_headset_ports (const pa_card_info *c)
|
||||
get_headset_ports (GvcMixerControl *control,
|
||||
const pa_card_info *c)
|
||||
{
|
||||
headset_ports *h;
|
||||
guint i;
|
||||
@ -2280,13 +2330,42 @@ get_headset_ports (const pa_card_info *c)
|
||||
|
||||
for (i = 0; i < c->n_ports; i++) {
|
||||
pa_card_port_info *p = c->ports[i];
|
||||
|
||||
if (strcmp (p->name, "analog-output-headphones") == 0)
|
||||
h->headphones = p;
|
||||
else if (strcmp (p->name, "analog-input-headset-mic") == 0)
|
||||
h->headsetmic = p;
|
||||
else if (strcmp(p->name, "analog-input-headphone-mic") == 0)
|
||||
h->headphonemic = p;
|
||||
if (control->priv->server_protocol_version < 34) {
|
||||
if (g_str_equal (p->name, "analog-output-headphones"))
|
||||
h->headphones = p;
|
||||
else if (g_str_equal (p->name, "analog-input-headset-mic"))
|
||||
h->headsetmic = p;
|
||||
else if (g_str_equal (p->name, "analog-input-headphone-mic"))
|
||||
h->headphonemic = p;
|
||||
else if (g_str_equal (p->name, "analog-input-internal-mic"))
|
||||
h->internalmic = p;
|
||||
else if (g_str_equal (p->name, "analog-output-speaker"))
|
||||
h->internalspk = p;
|
||||
} else {
|
||||
#if (PA_PROTOCOL_VERSION >= 34)
|
||||
if (p->available_group && strcmp (p->available_group, "Headphone Mic") == 0) {
|
||||
if (p->type == PA_DEVICE_PORT_TYPE_HEADPHONES)
|
||||
h->headphones = p;
|
||||
else if (p->type == PA_DEVICE_PORT_TYPE_HEADSET)
|
||||
h->headsetmic = p;
|
||||
else if (p->type == PA_DEVICE_PORT_TYPE_MIC)
|
||||
h->headphonemic = p;
|
||||
} else if (p->type == PA_DEVICE_PORT_TYPE_SPEAKER) {
|
||||
if (strcmp (p->name, "analog-output-speaker") == 0 ||
|
||||
strcmp (p->name, "[Out] Speaker") == 0 )
|
||||
h->internalspk = p;
|
||||
} else if (p->type == PA_DEVICE_PORT_TYPE_MIC) {
|
||||
if (strcmp (p->name, "analog-input-internal-mic") == 0 ||
|
||||
strcmp (p->name, "[In] Mic1") == 0 )
|
||||
h->internalmic = p;
|
||||
}
|
||||
#else
|
||||
g_warning_once ("libgnome-volume-control running against PulseAudio %u, "
|
||||
"but compiled against older %d, report a bug to your distribution",
|
||||
control->priv->server_protocol_version,
|
||||
PA_PROTOCOL_VERSION);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return h;
|
||||
}
|
||||
@ -2353,7 +2432,7 @@ check_audio_device_selection_needed (GvcMixerControl *control,
|
||||
|
||||
start_dialog = FALSE;
|
||||
stop_dialog = FALSE;
|
||||
h = get_headset_ports (info);
|
||||
h = get_headset_ports (control, info);
|
||||
|
||||
if (!h->headphones ||
|
||||
(!h->headsetmic && !h->headphonemic)) {
|
||||
@ -2363,7 +2442,8 @@ check_audio_device_selection_needed (GvcMixerControl *control,
|
||||
|
||||
if (control->priv->headset_card != (int) info->index) {
|
||||
int cardindex;
|
||||
gboolean hsmic, hpmic;
|
||||
gboolean hsmic = TRUE;
|
||||
gboolean hpmic = TRUE;
|
||||
const char *s;
|
||||
|
||||
s = pa_proplist_gets (info->proplist, "alsa.card");
|
||||
@ -2374,8 +2454,10 @@ check_audio_device_selection_needed (GvcMixerControl *control,
|
||||
if (cardindex == 0 && strcmp(s, "0") != 0)
|
||||
goto out;
|
||||
|
||||
if (!verify_alsa_card(cardindex, &hsmic, &hpmic))
|
||||
goto out;
|
||||
if (control->priv->server_protocol_version < 34) {
|
||||
if (!verify_alsa_card(cardindex, &hsmic, &hpmic))
|
||||
goto out;
|
||||
}
|
||||
|
||||
control->priv->headset_card = info->index;
|
||||
control->priv->has_headsetmic = hsmic && h->headsetmic;
|
||||
@ -2386,6 +2468,12 @@ check_audio_device_selection_needed (GvcMixerControl *control,
|
||||
}
|
||||
|
||||
control->priv->headset_plugged_in = h->headphones->available != PA_PORT_AVAILABLE_NO;
|
||||
free_priv_port_names (control);
|
||||
control->priv->headphones_name = GET_PORT_NAME(h->headphones);
|
||||
control->priv->headsetmic_name = GET_PORT_NAME(h->headsetmic);
|
||||
control->priv->headphonemic_name = GET_PORT_NAME(h->headphonemic);
|
||||
control->priv->internalspk_name = GET_PORT_NAME(h->internalspk);
|
||||
control->priv->internalmic_name = GET_PORT_NAME(h->internalmic);
|
||||
|
||||
if (!start_dialog &&
|
||||
!stop_dialog)
|
||||
@ -3268,6 +3356,7 @@ gvc_mixer_control_ready (GvcMixerControl *control)
|
||||
req_update_sink_input_info (control, -1);
|
||||
req_update_source_output_info (control, -1);
|
||||
|
||||
control->priv->server_protocol_version = pa_context_get_server_protocol_version (control->priv->pa_context);
|
||||
|
||||
control->priv->n_outstanding = 6;
|
||||
|
||||
@ -3350,6 +3439,7 @@ idle_reconnect (gpointer data)
|
||||
if (control->priv->pa_context) {
|
||||
pa_context_unref (control->priv->pa_context);
|
||||
control->priv->pa_context = NULL;
|
||||
control->priv->server_protocol_version = 0;
|
||||
gvc_mixer_new_pa_context (control);
|
||||
}
|
||||
|
||||
@ -3503,6 +3593,7 @@ gvc_mixer_control_dispose (GObject *object)
|
||||
control->priv->ui_inputs = NULL;
|
||||
}
|
||||
|
||||
free_priv_port_names (control);
|
||||
G_OBJECT_CLASS (gvc_mixer_control_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user