[PATCH] ALSA: hda/realtek: add more delay time before determine_headset_type

Takashi Iwai tiwai at suse.de
Tue Mar 16 15:17:59 CET 2021


On Tue, 16 Mar 2021 12:55:49 +0100,
Hui Wang wrote:
> 
> We found a recording issue on the headset-mic recently, sometimes
> users plug a headset and select headset-mic from UI, but can't record
> any sound from headset-mic. The root cause is the
> determine_headset_type() returns a wrong type, e.g. users plug a ctia
> type headset, but that function returns omtp type.
> 
> In the past, determine_headset_type() worked well because the internal
> mic is connected to the codec, so the "Input Source" or
> "Capture Source" is internal mic by default when users plug a headset,
> the determine_headset_type() will not be called unless users select
> headset-mic from UI, when users select headset-mic, the plugging
> action already finished and the headset is completely plugged into the
> jack, so determine_headset_type() could return a correct type.
> 
> But more and more machines connect the internal mic to the PCH now,
> and the "Input Source" is headset mic by default, when users plug a
> headset, the determine_headset_type() will be called immediately, if
> the headset is not completely plugged in, it will return a wrong type.
> 
> Here add 2s delay before calling determine_headset_type(), and since
> there is a pop-up dialogue when users do plugging action, to avoid
> freezing the UI, use the deleyed_work to call that function.

Hm, two seconds are quite long, IMHO.  How is this delay determined?


Takashi

> 
> Signed-off-by: Hui Wang <hui.wang at canonical.com>
> ---
>  sound/pci/hda/patch_realtek.c | 31 ++++++++++++++++++++++++-------
>  1 file changed, 24 insertions(+), 7 deletions(-)
> 
> diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
> index b47504fa8dfd..1f6fc8addf3e 100644
> --- a/sound/pci/hda/patch_realtek.c
> +++ b/sound/pci/hda/patch_realtek.c
> @@ -127,6 +127,8 @@ struct alc_spec {
>  	unsigned int coef0;
>  	struct input_dev *kb_dev;
>  	u8 alc_mute_keycode_map[1];
> +	struct hda_codec *codec;
> +	struct delayed_work headset_set_work;
>  };
>  
>  /*
> @@ -1160,6 +1162,7 @@ static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
>  		kfree(spec);
>  		return err;
>  	}
> +	spec->codec = codec;
>  	return 0;
>  }
>  
> @@ -5363,6 +5366,21 @@ static void alc_determine_headset_type(struct hda_codec *codec)
>  	spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP;
>  }
>  
> +static void alc_headset_check_and_set(struct work_struct *work)
> +{
> +	struct alc_spec *spec = container_of(work, struct alc_spec,
> +					     headset_set_work.work);
> +	struct hda_codec *codec = spec->codec;
> +
> +	if (spec->current_headset_type == ALC_HEADSET_TYPE_UNKNOWN)
> +		alc_determine_headset_type(codec);
> +	if (spec->current_headset_type == ALC_HEADSET_TYPE_CTIA)
> +		alc_headset_mode_ctia(codec);
> +	else if (spec->current_headset_type == ALC_HEADSET_TYPE_OMTP)
> +		alc_headset_mode_omtp(codec);
> +	spec->gen.hp_jack_present = true;
> +}
> +
>  static void alc_update_headset_mode(struct hda_codec *codec)
>  {
>  	struct alc_spec *spec = codec->spec;
> @@ -5386,6 +5404,7 @@ static void alc_update_headset_mode(struct hda_codec *codec)
>  		return;
>  	}
>  
> +	cancel_delayed_work_sync(&spec->headset_set_work);
>  	switch (new_headset_mode) {
>  	case ALC_HEADSET_MODE_UNPLUGGED:
>  		alc_headset_mode_unplugged(codec);
> @@ -5394,13 +5413,7 @@ static void alc_update_headset_mode(struct hda_codec *codec)
>  		spec->gen.hp_jack_present = false;
>  		break;
>  	case ALC_HEADSET_MODE_HEADSET:
> -		if (spec->current_headset_type == ALC_HEADSET_TYPE_UNKNOWN)
> -			alc_determine_headset_type(codec);
> -		if (spec->current_headset_type == ALC_HEADSET_TYPE_CTIA)
> -			alc_headset_mode_ctia(codec);
> -		else if (spec->current_headset_type == ALC_HEADSET_TYPE_OMTP)
> -			alc_headset_mode_omtp(codec);
> -		spec->gen.hp_jack_present = true;
> +		schedule_delayed_work(&spec->headset_set_work, msecs_to_jiffies(2000));
>  		break;
>  	case ALC_HEADSET_MODE_MIC:
>  		alc_headset_mode_mic_in(codec, hp_pin, spec->headphone_mic_pin);
> @@ -5466,6 +5479,7 @@ static void alc_fixup_headset_mode(struct hda_codec *codec,
>  		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC | HDA_PINCFG_HEADPHONE_MIC;
>  		break;
>  	case HDA_FIXUP_ACT_PROBE:
> +		INIT_DELAYED_WORK(&spec->headset_set_work, alc_headset_check_and_set);
>  		alc_probe_headset_mode(codec);
>  		break;
>  	case HDA_FIXUP_ACT_INIT:
> @@ -5475,6 +5489,9 @@ static void alc_fixup_headset_mode(struct hda_codec *codec,
>  		}
>  		alc_update_headset_mode(codec);
>  		break;
> +	case HDA_FIXUP_ACT_FREE:
> +		cancel_delayed_work_sync(&spec->headset_set_work);
> +		break;
>  	}
>  }
>  
> -- 
> 2.25.1
> 


More information about the Alsa-devel mailing list