summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarter Hsu <carterhsu@google.com>2019-05-14 18:50:52 +0800
committerCarter Hsu <carterhsu@google.com>2019-05-29 03:45:27 +0000
commitb0c9148b009e4488f4a8b2ae3d009cb46ce2bc04 (patch)
treee2bb4f11eebd93b95ae684121a4d6c522e0a9ba8
parentaaa9496b9860c1f508342f875867897ce42a1a78 (diff)
downloadandroid_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.c2
-rw-r--r--hal/audio_hw.c199
-rw-r--r--hal/audio_hw.h4
-rw-r--r--hal/msm8974/platform.c11
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 {