diff options
author | Carter Hsu <carterhsu@google.com> | 2019-05-14 18:50:52 +0800 |
---|---|---|
committer | Carter Hsu <carterhsu@google.com> | 2019-05-29 03:45:27 +0000 |
commit | b0c9148b009e4488f4a8b2ae3d009cb46ce2bc04 (patch) | |
tree | e2bb4f11eebd93b95ae684121a4d6c522e0a9ba8 | |
parent | aaa9496b9860c1f508342f875867897ce42a1a78 (diff) | |
download | android_hardware_qcom_audio-b0c9148b009e4488f4a8b2ae3d009cb46ce2bc04.tar.gz android_hardware_qcom_audio-b0c9148b009e4488f4a8b2ae3d009cb46ce2bc04.tar.bz2 android_hardware_qcom_audio-b0c9148b009e4488f4a8b2ae3d009cb46ce2bc04.zip |
audio: fix AEC/NS effect control
Android Q supports concurrent capture and will
create more than one AEC/NS effects if app creates
over 1 voice record tracks.
Refine the AEC/NS control to support mutilple
AEC/NS effects.
Also correct the voice-call stream type in STHAL.
Bug: 129111371
Bug: 128456220
Test: manual
Change-Id: Icd0863f54e17cd6a5ee765f9bb5fe1b4580743a4
Signed-off-by: Carter Hsu <carterhsu@google.com>
-rw-r--r-- | hal/audio_extn/soundtrigger.c | 2 | ||||
-rw-r--r-- | hal/audio_hw.c | 199 | ||||
-rw-r--r-- | hal/audio_hw.h | 4 | ||||
-rw-r--r-- | hal/msm8974/platform.c | 11 |
4 files changed, 195 insertions, 21 deletions
diff --git a/hal/audio_extn/soundtrigger.c b/hal/audio_extn/soundtrigger.c index 063a7bab..b6357776 100644 --- a/hal/audio_extn/soundtrigger.c +++ b/hal/audio_extn/soundtrigger.c @@ -422,7 +422,7 @@ void audio_extn_sound_trigger_update_stream_status(struct audio_usecase *uc_info if (valid_type && platform_sound_trigger_usecase_needs_event(uc_info->id)) { ALOGV("%s: uc_id %d of type %d for Event %d, with Raise=%d", __func__, uc_info->id, uc_info->type, event, raise_event); - if (uc_info->type == PCM_CAPTURE) { + if (uc_info->type == PCM_CAPTURE || uc_info->type == VOICE_CALL) { ev = (event == ST_EVENT_STREAM_BUSY) ? AUDIO_EVENT_CAPTURE_STREAM_ACTIVE : AUDIO_EVENT_CAPTURE_STREAM_INACTIVE; } else { diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 417d7cdb..2113c7db 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -344,6 +344,11 @@ static const struct string_to_enum channels_name_to_enum_table[] = { STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_8), }; +struct in_effect_list { + struct listnode list; + effect_handle_t handle; +}; + static int set_voice_volume_l(struct audio_device *adev, float volume); static struct audio_device *adev = NULL; static pthread_mutex_t adev_init_lock = PTHREAD_MUTEX_INITIALIZER; @@ -358,7 +363,6 @@ static int in_set_microphone_direction(const struct audio_stream_in *stream, audio_microphone_direction_t dir); static int in_set_microphone_field_dimension(const struct audio_stream_in *stream, float zoom); - static bool may_use_noirq_mode(struct audio_device *adev, audio_usecase_t uc_id, int flags __unused) { @@ -652,9 +656,36 @@ int enable_audio_route(struct audio_device *adev, audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_BUSY); - if (usecase->type == PCM_CAPTURE) + if (usecase->type == PCM_CAPTURE) { + struct stream_in *in = usecase->stream.in; + struct audio_usecase *uinfo; snd_device = usecase->in_snd_device; - else + + if (in) { + if (in->enable_aec || in->enable_ec_port) { + audio_devices_t out_device = AUDIO_DEVICE_OUT_SPEAKER; + struct listnode *node; + struct audio_usecase *voip_usecase = get_usecase_from_list(adev, + USECASE_AUDIO_PLAYBACK_VOIP); + if (voip_usecase) { + out_device = voip_usecase->stream.out->devices; + } else if (adev->primary_output && + !adev->primary_output->standby) { + out_device = adev->primary_output->devices; + } else { + list_for_each(node, &adev->usecase_list) { + uinfo = node_to_item(node, struct audio_usecase, list); + if (uinfo->type != PCM_CAPTURE) { + out_device = uinfo->stream.out->devices; + break; + } + } + } + platform_set_echo_reference(adev, true, out_device); + in->ec_opened = true; + } + } + } else snd_device = usecase->out_snd_device; audio_extn_utils_send_app_type_cfg(adev, usecase); audio_extn_ma_set_device(usecase); @@ -696,6 +727,13 @@ int disable_audio_route(struct audio_device *adev, ALOGD("%s: usecase(%d) reset and update mixer path: %s", __func__, usecase->id, mixer_path); audio_route_reset_and_update_path(adev->audio_route, mixer_path); + if (usecase->type == PCM_CAPTURE) { + struct stream_in *in = usecase->stream.in; + if (in && in->ec_opened) { + platform_set_echo_reference(in->dev, false, AUDIO_DEVICE_NONE); + in->ec_opened = false; + } + } audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_FREE); ALOGV("%s: exit", __func__); @@ -1497,6 +1535,61 @@ struct stream_in *get_voice_communication_input(const struct audio_device *adev) return NULL; } +/* + * Aligned with policy.h + */ +static inline int source_priority(int inputSource) +{ + switch (inputSource) { + case AUDIO_SOURCE_VOICE_COMMUNICATION: + return 9; + case AUDIO_SOURCE_CAMCORDER: + return 8; + case AUDIO_SOURCE_VOICE_PERFORMANCE: + return 7; + case AUDIO_SOURCE_UNPROCESSED: + return 6; + case AUDIO_SOURCE_MIC: + return 5; + case AUDIO_SOURCE_ECHO_REFERENCE: + return 4; + case AUDIO_SOURCE_FM_TUNER: + return 3; + case AUDIO_SOURCE_VOICE_RECOGNITION: + return 2; + case AUDIO_SOURCE_HOTWORD: + return 1; + default: + break; + } + return 0; +} + +static struct stream_in *get_priority_input(struct audio_device *adev) +{ + struct listnode *node; + struct audio_usecase *usecase; + int last_priority = 0, priority; + struct stream_in *priority_in = NULL; + struct stream_in *in; + + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == PCM_CAPTURE) { + in = usecase->stream.in; + if (!in) + continue; + priority = source_priority(in->source); + + if (priority > last_priority) { + last_priority = priority; + priority_in = in; + } + } + } + return priority_in; +} + int select_devices_with_force_switch(struct audio_device *adev, audio_usecase_t uc_id, bool force_switch) @@ -1575,13 +1668,14 @@ int select_devices_with_force_switch(struct audio_device *adev, if (in_snd_device == SND_DEVICE_NONE) { audio_devices_t out_device = AUDIO_DEVICE_NONE; struct stream_in *voip_in = get_voice_communication_input(adev); + struct stream_in *priority_in = NULL; if (voip_in != NULL) { - struct audio_usecase *voip_usecase = get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_VOIP); - platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE); + usecase->stream.in->enable_ec_port = false; + if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY) { out_device = AUDIO_DEVICE_OUT_TELEPHONY_TX; } else if (voip_usecase) { @@ -1594,9 +1688,17 @@ int select_devices_with_force_switch(struct audio_device *adev, in case o/p is not routed from same primary HAL */ out_device = AUDIO_DEVICE_OUT_SPEAKER; } + priority_in = voip_in; + } else { + /* get the input with the highest priority source*/ + priority_in = get_priority_input(adev); + + if (!priority_in) + priority_in = usecase->stream.in; } + in_snd_device = platform_get_input_snd_device(adev->platform, - usecase->stream.in, + priority_in, out_device); } } @@ -1759,6 +1861,7 @@ static int stop_input_stream(struct stream_in *in) int i, ret = 0; struct audio_usecase *uc_info; struct audio_device *adev = in->dev; + struct stream_in *priority_in = NULL; ALOGV("%s: enter: usecase(%d: %s)", __func__, in->usecase, use_case_table[in->usecase]); @@ -1770,6 +1873,8 @@ static int stop_input_stream(struct stream_in *in) return -EINVAL; } + priority_in = get_priority_input(adev); + /* Close in-call recording streams */ voice_check_and_stop_incall_rec_usecase(adev, in); @@ -1782,6 +1887,12 @@ static int stop_input_stream(struct stream_in *in) list_remove(&uc_info->list); free(uc_info); + if (priority_in == in) { + priority_in = get_priority_input(adev); + if (priority_in) + select_devices(adev, priority_in->usecase); + } + ALOGV("%s: exit: status(%d)", __func__, ret); return ret; } @@ -3998,11 +4109,14 @@ static int in_standby(struct audio_stream *stream) pcm_close(in->pcm); in->pcm = NULL; } - adev->enable_voicerx = false; - platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE ); + + if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) + adev->enable_voicerx = false; + if (do_stop) { status = stop_input_stream(in); } + pthread_mutex_unlock(&adev->lock); } pthread_mutex_unlock(&in->lock); @@ -4346,6 +4460,51 @@ exit: return ret; } +static int in_update_effect_list(bool add, effect_handle_t effect, + struct listnode *head) +{ + struct listnode *node; + struct in_effect_list *elist = NULL; + struct in_effect_list *target = NULL; + int ret = 0; + + if (!head) + return ret; + + list_for_each(node, head) { + elist = node_to_item(node, struct in_effect_list, list); + if (elist->handle == effect) { + target = elist; + break; + } + } + + if (add) { + if (target) { + ALOGD("effect %p already exist", effect); + return ret; + } + + target = (struct in_effect_list *) + calloc(1, sizeof(struct in_effect_list)); + + if (!target) { + ALOGE("%s:fail to allocate memory", __func__); + return -ENOMEM; + } + + target->handle = effect; + list_add_tail(head, &target->list); + } else { + if (target) { + list_remove(&target->list); + free(target); + } + } + + return ret; +} + static int add_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect, bool enable) @@ -4366,11 +4525,16 @@ static int add_remove_audio_effect(const struct audio_stream *stream, if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION || in->source == AUDIO_SOURCE_VOICE_RECOGNITION || adev->mode == AUDIO_MODE_IN_COMMUNICATION) && - in->enable_aec != enable && (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0)) { + + in_update_effect_list(enable, effect, &in->aec_list); + enable = !list_empty(&in->aec_list); + if (enable == in->enable_aec) + goto exit; + in->enable_aec = enable; - if (!enable) - platform_set_echo_reference(in->dev, enable, AUDIO_DEVICE_NONE); + ALOGD("AEC enable %d", enable); + if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION || adev->mode == AUDIO_MODE_IN_COMMUNICATION) { adev->enable_voicerx = enable; @@ -4386,15 +4550,22 @@ static int add_remove_audio_effect(const struct audio_stream *stream, && enable_disable_effect(in->dev, in, EFFECT_AEC, enable) == -ENOSYS) select_devices(in->dev, in->usecase); } - if (in->enable_ns != enable && - (memcmp(&desc.type, FX_IID_NS, sizeof(effect_uuid_t)) == 0)) { + if (memcmp(&desc.type, FX_IID_NS, sizeof(effect_uuid_t)) == 0) { + + in_update_effect_list(enable, effect, &in->ns_list); + enable = !list_empty(&in->ns_list); + if (enable == in->enable_ns) + goto exit; + in->enable_ns = enable; + ALOGD("NS enable %d", enable); if (!in->standby) { if (in->source != AUDIO_SOURCE_VOICE_COMMUNICATION || enable_disable_effect(in->dev, in, EFFECT_NS, enable) == -ENOSYS) select_devices(in->dev, in->usecase); } } +exit: pthread_mutex_unlock(&in->dev->lock); pthread_mutex_unlock(&in->lock); @@ -5704,6 +5875,8 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in->flags = flags; in->direction = MIC_DIRECTION_UNSPECIFIED; in->zoom = 0; + list_init(&in->aec_list); + list_init(&in->ns_list); ALOGV("%s: source %d, config->channel_mask %#x", __func__, source, config->channel_mask); if (source == AUDIO_SOURCE_VOICE_UPLINK || diff --git a/hal/audio_hw.h b/hal/audio_hw.h index e8fe65b7..764093ff 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -285,6 +285,10 @@ struct stream_in { audio_usecase_t usecase; bool enable_aec; bool enable_ns; + bool enable_ec_port; + bool ec_opened; + struct listnode aec_list; + struct listnode ns_list; int64_t frames_read; /* total frames read, not cleared when entering standby */ int64_t frames_muted; /* total frames muted, not cleared when entering standby */ int64_t mmap_time_offset_nanos; /* fudge factor to correct inaccuracies in DSP */ diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 21f7cf57..4ae5d1c3 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -3079,7 +3079,7 @@ exit: #ifdef DYNAMIC_ECNS_ENABLED static snd_device_t get_snd_device_for_voice_comm(struct platform_data *my_data, struct stream_in *in __unused, - audio_devices_t out_device, + audio_devices_t out_device __unused, audio_devices_t in_device) { struct audio_device *adev = my_data->adev; @@ -3114,7 +3114,7 @@ static snd_device_t get_snd_device_for_voice_comm(struct platform_data *my_data, ALOGE("%s: Unsupported in_device %#x", __func__, in_device); break; } - platform_set_echo_reference(adev, true, out_device); + in->enable_ec_port = true; } return snd_device; @@ -3122,7 +3122,7 @@ static snd_device_t get_snd_device_for_voice_comm(struct platform_data *my_data, #else static snd_device_t get_snd_device_for_voice_comm(struct platform_data *my_data, struct stream_in *in, - audio_devices_t out_device, + audio_devices_t out_device __unused, audio_devices_t in_device) { struct audio_device *adev = my_data->adev; @@ -3150,7 +3150,6 @@ static snd_device_t get_snd_device_for_voice_comm(struct platform_data *my_data, } else if (audio_is_usb_in_device(in_device | AUDIO_DEVICE_BIT_IN)) { snd_device = SND_DEVICE_IN_USB_HEADSET_MIC_AEC; } - platform_set_echo_reference(adev, true, out_device); } else if (in->enable_aec) { if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { if (my_data->fluence_in_spkr_mode && @@ -3172,7 +3171,6 @@ static snd_device_t get_snd_device_for_voice_comm(struct platform_data *my_data, } else if (audio_is_usb_in_device(in_device | AUDIO_DEVICE_BIT_IN)) { snd_device = SND_DEVICE_IN_USB_HEADSET_MIC_AEC; } - platform_set_echo_reference(adev, true, out_device); } else if (in->enable_ns) { if (in_device & AUDIO_DEVICE_IN_BACK_MIC) { if (my_data->fluence_in_spkr_mode && @@ -3366,7 +3364,7 @@ snd_device_t platform_get_input_snd_device(void *platform, else snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE; } - platform_set_echo_reference(adev, true, out_device); + in->enable_ec_port = true; } else if ((channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) && (my_data->source_mic_type & SOURCE_DUAL_MIC)) { snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_STEREO; @@ -3384,7 +3382,6 @@ snd_device_t platform_get_input_snd_device(void *platform, } else { snd_device = SND_DEVICE_IN_VOICE_REC_MIC_AEC; } - platform_set_echo_reference(adev, true, out_device); } else if (in->enable_ns) { snd_device = SND_DEVICE_IN_VOICE_REC_MIC_NS; } else { |