Merge "hal: Support config selection for playback on speaker"
diff --git a/hal/Android.mk b/hal/Android.mk
index 6d20f7e..1af245a 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -146,6 +146,19 @@
LOCAL_SRC_FILES += audio_extn/dev_arbi.c
endif
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_RECORD_PLAY_CONCURRENCY)),true)
+ LOCAL_CFLAGS += -DRECORD_PLAY_CONCURRENCY
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_DS2_DOLBY_DAP)),true)
+ LOCAL_CFLAGS += -DDS2_DOLBY_DAP_ENABLED
+ifneq ($(strip $(DOLBY_DDP)),true)
+ ifneq ($(strip $(DOLBY_DAP)),true)
+ LOCAL_SRC_FILES += audio_extn/dolby.c
+ endif
+endif
+endif
+
LOCAL_SHARED_LIBRARIES := \
liblog \
libcutils \
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index dd6063f..02add40 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -259,22 +259,27 @@
#define audio_extn_dolby_set_license(adev) (0)
#endif
-#ifndef DS1_DOLBY_DDP_ENABLED
+#ifndef DS1_DOLBY_DAP_ENABLED
#define audio_extn_dolby_set_endpoint(adev) (0)
#else
void audio_extn_dolby_set_endpoint(struct audio_device *adev);
#endif
-#ifndef DS1_DOLBY_DDP_ENABLED
-#define audio_extn_ddp_set_parameters(adev, parms) (0)
-#define audio_extn_is_dolby_format(format) (0)
-#define audio_extn_dolby_get_snd_codec_id(adev, out, format) (0)
-#define audio_extn_dolby_send_ddp_endp_params(adev) (0)
-#else
+
+#if defined(DS1_DOLBY_DDP_ENABLED) || defined(DS2_DOLBY_DAP_ENABLED)
bool audio_extn_is_dolby_format(audio_format_t format);
int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev,
struct stream_out *out,
audio_format_t format);
+#else
+#define audio_extn_is_dolby_format(format) (0)
+#define audio_extn_dolby_get_snd_codec_id(adev, out, format) (0)
+#endif
+
+#ifndef DS1_DOLBY_DDP_ENABLED
+#define audio_extn_ddp_set_parameters(adev, parms) (0)
+#define audio_extn_dolby_send_ddp_endp_params(adev) (0)
+#else
void audio_extn_ddp_set_parameters(struct audio_device *adev,
struct str_parms *parms);
void audio_extn_dolby_send_ddp_endp_params(struct audio_device *adev);
@@ -318,5 +323,39 @@
int audio_extn_utils_send_app_type_cfg(struct audio_usecase *usecase);
void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
struct audio_usecase *usecase);
+#ifdef DS2_DOLBY_DAP_ENABLED
+#define LIB_DS2_DAP_HAL "vendor/lib/libhwdaphal.so"
+#define SET_HW_INFO_FUNC "dap_hal_set_hw_info"
+typedef enum {
+ SND_CARD = 0,
+ HW_ENDPOINT = 1,
+ DMID = 2,
+ DEVICE_BE_ID_MAP = 3,
+ DAP_BYPASS = 4,
+} dap_hal_hw_info_t;
+typedef int (*dap_hal_set_hw_info_t)(int32_t hw_info, void* data);
+typedef struct {
+ int (*device_id_to_be_id)[2];
+ int len;
+} dap_hal_device_be_id_map_t;
+int audio_extn_dap_hal_init(int snd_card);
+int audio_extn_dap_hal_deinit();
+void audio_extn_dolby_ds2_set_endpoint(struct audio_device *adev);
+int audio_extn_ds2_enable(struct audio_device *adev);
+int audio_extn_dolby_set_dap_bypass(struct audio_device *adev, int state);
+#else
+#define audio_extn_dap_hal_init(snd_card) (0)
+#define audio_extn_dap_hal_deinit() (0)
+#define audio_extn_dolby_ds2_set_endpoint(adev) (0)
+#define audio_extn_ds2_enable(adev) (0)
+#define audio_extn_dolby_set_dap_bypass(adev, state) (0)
+#endif
+typedef enum {
+ DAP_STATE_ON = 0,
+ DAP_STATE_BYPASS,
+};
+#ifndef AUDIO_FORMAT_E_AC3_JOC
+#define AUDIO_FORMAT_E_AC3_JOC 0x19000000UL
+#endif
#endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c
index ddd2380..8670367 100644
--- a/hal/audio_extn/dolby.c
+++ b/hal/audio_extn/dolby.c
@@ -243,7 +243,8 @@
(usecase->devices & ddp_dev) &&
(usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
((usecase->stream.out->format == AUDIO_FORMAT_AC3) ||
- (usecase->stream.out->format == AUDIO_FORMAT_E_AC3))) {
+ (usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
+ (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC))) {
send_ddp_endp_params_stream(usecase->stream.out, ddp_dev,
dev_ch_cap, false /* set cache */);
}
@@ -260,7 +261,8 @@
(usecase->devices & AUDIO_DEVICE_OUT_ALL) &&
(usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
((usecase->stream.out->format == AUDIO_FORMAT_AC3) ||
- (usecase->stream.out->format == AUDIO_FORMAT_E_AC3))) {
+ (usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
+ (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC))) {
/*
* Use wfd /hdmi sink channel cap for dolby params if device is wfd
* or hdmi. Otherwise use stereo configuration
@@ -352,7 +354,9 @@
*/
send_ddp_endp_params(adev, ddp_dev, dev_ch_cap);
}
+#endif /* DS1_DOLBY_DDP_ENABLED */
+#if defined(DS1_DOLBY_DDP_ENABLED) || defined(DS2_DOLBY_DAP_ENABLED)
int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev,
struct stream_out *out,
audio_format_t format)
@@ -370,19 +374,20 @@
switch (format) {
case AUDIO_FORMAT_AC3:
id = SND_AUDIOCODEC_AC3;
+#ifdef DS1_DOLBY_DDP_ENABLED
send_ddp_endp_params_stream(out, out->devices,
channel_cap, true /* set_cache */);
-#ifndef DS1_DOLBY_DAP_ENABLED
- audio_extn_dolby_set_dmid(adev);
#endif
+ audio_extn_dolby_set_dmid(adev);
break;
case AUDIO_FORMAT_E_AC3:
+ case AUDIO_FORMAT_E_AC3_JOC:
id = SND_AUDIOCODEC_EAC3;
+#ifdef DS1_DOLBY_DDP_ENABLED
send_ddp_endp_params_stream(out, out->devices,
channel_cap, true /* set_cache */);
-#ifndef DS1_DOLBY_DAP_ENABLED
- audio_extn_dolby_set_dmid(adev);
#endif
+ audio_extn_dolby_set_dmid(adev);
break;
default:
ALOGE("%s: Unsupported audio format :%x", __func__, format);
@@ -394,13 +399,13 @@
bool audio_extn_is_dolby_format(audio_format_t format)
{
if (format == AUDIO_FORMAT_AC3 ||
- format == AUDIO_FORMAT_E_AC3)
+ format == AUDIO_FORMAT_E_AC3 ||
+ format == AUDIO_FORMAT_E_AC3_JOC)
return true;
else
return false;
}
-
-#endif /* DS1_DOLBY_DDP_ENABLED */
+#endif /* DS1_DOLBY_DDP_ENABLED || DS2_DOLBY_DAP_ENABLED */
#ifdef DS1_DOLBY_DAP_ENABLED
void audio_extn_dolby_set_endpoint(struct audio_device *adev)
@@ -499,3 +504,135 @@
return;
}
#endif /* DS1_DOLBY_DDP_ENABLED || DS1_DOLBY_DAP_ENABLED */
+
+#ifdef DS2_DOLBY_DAP_ENABLED
+struct ds2_extn_module {
+ void *ds2_handle;
+ dap_hal_set_hw_info_t dap_hal_set_hw_info;
+};
+
+static struct ds2_extn_module ds2extnmod = {
+ .ds2_handle = NULL,
+ .dap_hal_set_hw_info = NULL,
+};
+
+int audio_extn_dap_hal_init(int snd_card) {
+ char c_dmid[128] = {0};
+ void *handle = NULL;
+ int i_dmid, ret = -EINVAL;
+ dap_hal_device_be_id_map_t device_be_id_map;
+
+ ALOGV("%s: opening DAP HAL lib\n", __func__);
+ ds2extnmod.ds2_handle = dlopen(LIB_DS2_DAP_HAL, RTLD_NOW);
+ if (ds2extnmod.ds2_handle == NULL) {
+ ALOGE("%s: DLOPEN failed for %s error %s", __func__, LIB_DS2_DAP_HAL,
+ dlerror());
+ goto ret;
+ }
+ ds2extnmod.dap_hal_set_hw_info = (dap_hal_set_hw_info_t)dlsym(ds2extnmod.ds2_handle, SET_HW_INFO_FUNC);
+ if (ds2extnmod.dap_hal_set_hw_info == NULL) {
+ ALOGE("%s: dlsym error %s for %s", __func__, SET_HW_INFO_FUNC,
+ dlerror());
+ goto close;
+ }
+ ds2extnmod.dap_hal_set_hw_info(SND_CARD, (void*)(&snd_card));
+ ALOGV("%s Sound card number is:%d",__func__,snd_card);
+
+ property_get("dmid",c_dmid,"0");
+ i_dmid = atoi(c_dmid);
+ ds2extnmod.dap_hal_set_hw_info(DMID, (void*)(&i_dmid));
+ ALOGV("%s Dolby device manufacturer id is:%d",__func__,i_dmid);
+
+ platform_get_device_to_be_id_map(&device_be_id_map.device_id_to_be_id, &device_be_id_map.len);
+ ds2extnmod.dap_hal_set_hw_info(DEVICE_BE_ID_MAP, (void*)(&device_be_id_map));
+ ALOGV("%s Set be id map len:%d",__func__,device_be_id_map.len);
+ ret = 0;
+ goto ret;
+
+close:
+ dlclose(ds2extnmod.ds2_handle);
+ ds2extnmod.ds2_handle = NULL;
+ ds2extnmod.dap_hal_set_hw_info = NULL;
+ret:
+ return ret;
+}
+
+int audio_extn_dap_hal_deinit() {
+ if (ds2extnmod.ds2_handle != NULL) {
+ dlclose(ds2extnmod.ds2_handle);
+ ds2extnmod.ds2_handle = NULL;
+ }
+ ds2extnmod.dap_hal_set_hw_info = NULL;
+ return 0;
+}
+
+void audio_extn_dolby_ds2_set_endpoint(struct audio_device *adev) {
+ struct listnode *node;
+ struct audio_usecase *usecase;
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "DS1 DAP Endpoint";
+ int endpoint = 0, ret;
+ bool send = false;
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if ((usecase->type == PCM_PLAYBACK) &&
+ (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY)) {
+ endpoint |= usecase->devices & AUDIO_DEVICE_OUT_ALL;
+ send = true;
+ }
+ }
+ if (!send)
+ return;
+
+ if (ds2extnmod.dap_hal_set_hw_info) {
+ ds2extnmod.dap_hal_set_hw_info(HW_ENDPOINT, (void*)(&endpoint));
+ ALOGE("%s: Dolby set endpint :0x%x",__func__, endpoint);
+ } else {
+ ALOGE("%s: dap_hal_set_hw_info is NULL",__func__);
+ }
+
+ return;
+}
+
+int audio_extn_ds2_enable(struct audio_device *adev) {
+
+ char value[PROPERTY_VALUE_MAX] = {0};
+ bool ds2_enabled = false;
+ const char *mixer_ctl_name = "DS2 OnOff";
+ struct mixer_ctl *ctl;
+
+ property_get("audio.dolby.ds2.enabled", value, NULL);
+ ds2_enabled = atoi(value) || !strncmp("true", value, 4);
+
+ ALOGV("%s:", __func__);
+ if(ds2_enabled) {
+ ALOGD("%s:ds2_enabled %d", __func__, ds2_enabled);
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+
+ if (mixer_ctl_set_value(ctl, 0, ds2_enabled) < 0) {
+ ALOGE("%s: Could not set ds2 enable %d",
+ __func__, ds2_enabled);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+int audio_extn_dolby_set_dap_bypass(struct audio_device *adev, int state) {
+
+ ALOGV("%s: state %d", __func__, state);
+ if (ds2extnmod.dap_hal_set_hw_info) {
+ ds2extnmod.dap_hal_set_hw_info(DAP_BYPASS, (void*)(&state));
+ ALOGV("%s: Dolby set bypas :0x%x", __func__, state);
+ } else {
+ ALOGV("%s: dap_hal_set_hw_info is NULL", __func__);
+ }
+ return 0;
+}
+#endif
diff --git a/hal/audio_extn/soundtrigger.c b/hal/audio_extn/soundtrigger.c
index c6d7077..5f4c6ba 100644
--- a/hal/audio_extn/soundtrigger.c
+++ b/hal/audio_extn/soundtrigger.c
@@ -139,12 +139,12 @@
pthread_mutex_lock(&st_dev->lock);
st_ses_info = get_sound_trigger_info(in->capture_handle);
+ pthread_mutex_unlock(&st_dev->lock);
if (st_ses_info) {
event.u.ses_info = st_ses_info->st_ses;
ALOGV("%s: AUDIO_EVENT_STOP_LAB pcm %p", __func__, st_ses_info->st_ses.pcm);
st_dev->st_callback(AUDIO_EVENT_STOP_LAB, &event);
}
- pthread_mutex_unlock(&st_dev->lock);
}
void audio_extn_sound_trigger_check_and_get_session(struct stream_in *in)
{
@@ -252,7 +252,7 @@
{
audio_event_info_t event;
char value[32];
- int ret;
+ int ret, val;
if(!st_dev || !params) {
ALOGE("%s: str_params NULL", __func__);
@@ -287,6 +287,12 @@
else
ALOGE("%s: unknown CPE status", __func__);
}
+
+ ret = str_parms_get_int(params, "SVA_NUM_SESSIONS", &val);
+ if (ret >= 0) {
+ event.u.value = val;
+ st_dev->st_callback(AUDIO_EVENT_NUM_ST_SESSIONS, &event);
+ }
}
int audio_extn_sound_trigger_init(struct audio_device *adev)
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index 59b46fc..a350198 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -753,7 +753,8 @@
(const pthread_attr_t *) NULL, spkr_calibration_thread, &handle);
} else {
ALOGE("%s: thermal_client_request failed", __func__);
- if (handle.thermal_client_handle)
+ if (handle.thermal_client_handle &&
+ handle.thermal_client_unregister_callback)
handle.thermal_client_unregister_callback(handle.thermal_client_handle);
if (handle.thermal_handle)
dlclose(handle.thermal_handle);
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 05bf132..9e841df 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -60,9 +60,14 @@
#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96
#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
+#define PROXY_OPEN_RETRY_COUNT 100
+#define PROXY_OPEN_WAIT_TIME 20
#define USECASE_AUDIO_PLAYBACK_PRIMARY USECASE_AUDIO_PLAYBACK_DEEP_BUFFER
+static unsigned int configured_low_latency_capture_period_size =
+ LOW_LATENCY_CAPTURE_PERIOD_SIZE;
+
struct pcm_config pcm_config_deep_buffer = {
.channels = 2,
.rate = DEFAULT_OUTPUT_SAMPLING_RATE,
@@ -102,6 +107,37 @@
.format = PCM_FORMAT_S16_LE,
};
+#define AFE_PROXY_CHANNEL_COUNT 2
+#define AFE_PROXY_SAMPLING_RATE 48000
+
+#define AFE_PROXY_PLAYBACK_PERIOD_SIZE 768
+#define AFE_PROXY_PLAYBACK_PERIOD_COUNT 4
+
+struct pcm_config pcm_config_afe_proxy_playback = {
+ .channels = AFE_PROXY_CHANNEL_COUNT,
+ .rate = AFE_PROXY_SAMPLING_RATE,
+ .period_size = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
+ .period_count = AFE_PROXY_PLAYBACK_PERIOD_COUNT,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
+ .stop_threshold = INT_MAX,
+ .avail_min = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
+};
+
+#define AFE_PROXY_RECORD_PERIOD_SIZE 768
+#define AFE_PROXY_RECORD_PERIOD_COUNT 4
+
+struct pcm_config pcm_config_afe_proxy_record = {
+ .channels = AFE_PROXY_CHANNEL_COUNT,
+ .rate = AFE_PROXY_SAMPLING_RATE,
+ .period_size = AFE_PROXY_RECORD_PERIOD_SIZE,
+ .period_count = AFE_PROXY_RECORD_PERIOD_COUNT,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = AFE_PROXY_RECORD_PERIOD_SIZE,
+ .stop_threshold = INT_MAX,
+ .avail_min = AFE_PROXY_RECORD_PERIOD_SIZE,
+};
+
const char * const use_case_table[AUDIO_USECASE_MAX] = {
[USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback",
[USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
@@ -142,6 +178,9 @@
[USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2",
[USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib",
[USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record",
+
+ [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = "afe-proxy-playback",
+ [USECASE_AUDIO_RECORD_AFE_PROXY] = "afe-proxy-record",
};
static const audio_usecase_t offload_usecases[] = {
@@ -171,6 +210,12 @@
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
};
+static const struct string_to_enum out_formats_name_to_enum_table[] = {
+ STRING_TO_ENUM(AUDIO_FORMAT_AC3),
+ STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
+ STRING_TO_ENUM(AUDIO_FORMAT_E_AC3_JOC),
+};
+
static struct audio_device *adev = NULL;
static pthread_mutex_t adev_init_lock;
static unsigned int audio_device_ref_count;
@@ -288,6 +333,19 @@
return 0;
}
+int pcm_ioctl(struct pcm *pcm, int request, ...)
+{
+ va_list ap;
+ void * arg;
+ int pcm_fd = *(int*)pcm;
+
+ va_start(ap, request);
+ arg = va_arg(ap, void *);
+ va_end(ap);
+
+ return ioctl(pcm_fd, request, arg);
+}
+
int enable_audio_route(struct audio_device *adev,
struct audio_usecase *usecase)
{
@@ -308,6 +366,7 @@
audio_extn_dolby_set_dmid(adev);
audio_extn_dolby_set_endpoint(adev);
#endif
+ audio_extn_dolby_ds2_set_endpoint(adev);
audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_BUSY);
audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_BUSY);
audio_extn_utils_send_audio_calibration(adev, usecase);
@@ -571,7 +630,8 @@
usecase = node_to_item(node, struct audio_usecase, list);
if (usecase->type != PCM_PLAYBACK &&
usecase != uc_info &&
- usecase->in_snd_device != snd_device) {
+ usecase->in_snd_device != snd_device &&
+ (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
__func__, use_case_table[usecase->id],
platform_get_snd_device_name(usecase->in_snd_device));
@@ -704,7 +764,7 @@
* usecase. This is to avoid switching devices for voice call when
* check_usecases_codec_backend() is called below.
*/
- if (adev->voice.in_call && adev->mode == AUDIO_MODE_IN_CALL) {
+ if (voice_is_in_call(adev) && adev->mode == AUDIO_MODE_IN_CALL) {
vc_usecase = get_usecase_from_list(adev,
get_voice_usecase_id_from_list(adev));
if ((vc_usecase) && ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
@@ -744,14 +804,14 @@
usecase->devices = usecase->stream.in->device;
out_snd_device = SND_DEVICE_NONE;
if (in_snd_device == SND_DEVICE_NONE) {
+ audio_devices_t out_device = AUDIO_DEVICE_NONE;
if (adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
adev->primary_output && !adev->primary_output->standby) {
- in_snd_device = platform_get_input_snd_device(adev->platform,
- adev->primary_output->devices);
- } else {
- in_snd_device = platform_get_input_snd_device(adev->platform,
- AUDIO_DEVICE_NONE);
+ out_device = adev->primary_output->devices;
+ } else if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY) {
+ out_device = AUDIO_DEVICE_OUT_TELEPHONY_TX;
}
+ in_snd_device = platform_get_input_snd_device(adev->platform, out_device);
}
}
}
@@ -934,16 +994,33 @@
select_devices(adev, in->usecase);
ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
- __func__, adev->snd_card,
- in->pcm_device_id, in->config.channels);
- in->pcm = pcm_open(adev->snd_card,
- in->pcm_device_id, PCM_IN, &in->config);
- if (in->pcm && !pcm_is_ready(in->pcm)) {
- ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
- pcm_close(in->pcm);
- in->pcm = NULL;
- ret = -EIO;
- goto error_open;
+ __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
+
+ unsigned int flags = PCM_IN;
+ unsigned int pcm_open_retry_count = 0;
+
+ if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) {
+ flags |= PCM_MMAP | PCM_NOIRQ;
+ pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
+ }
+
+ while (1) {
+ in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
+ flags, &in->config);
+ if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
+ if (in->pcm != NULL) {
+ pcm_close(in->pcm);
+ in->pcm = NULL;
+ }
+ if (pcm_open_retry_count-- == 0) {
+ ret = -EIO;
+ goto error_open;
+ }
+ usleep(PROXY_OPEN_WAIT_TIME * 1000);
+ continue;
+ }
+ break;
}
ALOGV("%s: exit", __func__);
@@ -1345,18 +1422,34 @@
select_devices(adev, out->usecase);
- ALOGV("%s: Opening PCM device card_id(%d) device_id(%d)",
- __func__, 0, out->pcm_device_id);
+ ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)",
+ __func__, adev->snd_card, out->pcm_device_id, out->config.format);
if (!is_offload_usecase(out->usecase)) {
- out->pcm = pcm_open(adev->snd_card,
- out->pcm_device_id,
- PCM_OUT | PCM_MONOTONIC, &out->config);
- if (out->pcm && !pcm_is_ready(out->pcm)) {
- ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
- pcm_close(out->pcm);
- out->pcm = NULL;
- ret = -EIO;
- goto error_open;
+ unsigned int flags = PCM_OUT;
+ unsigned int pcm_open_retry_count = 0;
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) {
+ flags |= PCM_MMAP | PCM_NOIRQ;
+ pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
+ } else
+ flags |= PCM_MONOTONIC;
+
+ while (1) {
+ out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
+ flags, &out->config);
+ if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
+ if (out->pcm != NULL) {
+ pcm_close(out->pcm);
+ out->pcm = NULL;
+ }
+ if (pcm_open_retry_count-- == 0) {
+ ret = -EIO;
+ goto error_open;
+ }
+ usleep(PROXY_OPEN_WAIT_TIME * 1000);
+ continue;
+ }
+ break;
}
} else {
out->pcm = NULL;
@@ -1430,7 +1523,8 @@
static size_t get_input_buffer_size(uint32_t sample_rate,
audio_format_t format,
- int channel_count)
+ int channel_count,
+ bool is_low_latency)
{
size_t size = 0;
@@ -1438,13 +1532,19 @@
return 0;
size = (sample_rate * AUDIO_CAPTURE_PERIOD_DURATION_MSEC) / 1000;
+ if (is_low_latency)
+ size = configured_low_latency_capture_period_size;
/* ToDo: should use frame_size computed based on the format and
channel_count here. */
size *= sizeof(short) * channel_count;
- /* make sure the size is multiple of 64 */
- size += 0x3f;
- size &= ~0x3f;
+ /* make sure the size is multiple of 32 bytes
+ * At 48 kHz mono 16-bit PCM:
+ * 5.000 ms = 240 frames = 15*16*1*2 = 480, a whole multiple of 32 (15)
+ * 3.333 ms = 160 frames = 10*16*1*2 = 320, a whole multiple of 32 (10)
+ */
+ size += 0x1f;
+ size &= ~0x1f;
return size;
}
@@ -1621,6 +1721,10 @@
return 0;
}
+static bool output_drives_call(struct audio_device *adev, struct stream_out *out)
+{
+ return out == adev->primary_output || out == adev->voice_tx_output;
+}
static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
{
@@ -1681,23 +1785,19 @@
if (!out->standby)
select_devices(adev, out->usecase);
- if ((adev->mode == AUDIO_MODE_IN_CALL) &&
- !adev->voice.in_call &&
- (out == adev->primary_output)) {
- ret = voice_start_call(adev);
- } else if ((adev->mode == AUDIO_MODE_IN_CALL) &&
- adev->voice.in_call &&
- (out == adev->primary_output)) {
- voice_update_devices_for_all_voice_usecases(adev);
+ if (output_drives_call(adev, out)) {
+ if(!voice_is_in_call(adev)) {
+ if (adev->mode == AUDIO_MODE_IN_CALL) {
+ adev->current_call_output = out;
+ ret = voice_start_call(adev);
+ }
+ } else {
+ adev->current_call_output = out;
+ voice_update_devices_for_all_voice_usecases(adev);
+ }
}
}
- if ((adev->mode == AUDIO_MODE_NORMAL) &&
- adev->voice.in_call &&
- (out == adev->primary_output)) {
- ret = voice_stop_call(adev);
- }
-
pthread_mutex_unlock(&adev->lock);
pthread_mutex_unlock(&out->lock);
}
@@ -1886,7 +1986,10 @@
if (out->muted)
memset((void *)buffer, 0, bytes);
ALOGVV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes);
- ret = pcm_write(out->pcm, (void *)buffer, bytes);
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY)
+ ret = pcm_mmap_write(out->pcm, (void *)buffer, bytes);
+ else
+ ret = pcm_write(out->pcm, (void *)buffer, bytes);
if (ret < 0)
ret = -errno;
else if (ret == 0)
@@ -2234,7 +2337,7 @@
err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
if (err >= 0) {
val = atoi(value);
- if ((in->device != val) && (val != 0)) {
+ if (((int)in->device != val) && (val != 0)) {
in->device = val;
/* If recording is in progress, change the tx device to new device */
if (!in->standby && !in->is_st_session)
@@ -2323,6 +2426,8 @@
ret = audio_extn_ssr_read(stream, buffer, bytes);
else if (audio_extn_compr_cap_usecase_supported(in->usecase))
ret = audio_extn_compr_cap_read(in, buffer, bytes);
+ else if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY)
+ ret = pcm_mmap_read(in->pcm, buffer, bytes);
else
ret = pcm_read(in->pcm, buffer, bytes);
if (ret < 0)
@@ -2567,11 +2672,6 @@
out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE;
}
- if (out->bit_width == 24 && !platform_check_24_bit_support()) {
- ALOGW("24 bit support is not enabled, using 16 bit backend");
- out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE;
- }
-
if (config->offload_info.format == AUDIO_FORMAT_FLAC)
out->compr_config.codec->options.flac_dec.sample_size = PCM_OUTPUT_BIT_WIDTH;
@@ -2596,6 +2696,28 @@
__func__, ret);
goto error_open;
}
+ } else if (out->devices == AUDIO_DEVICE_OUT_TELEPHONY_TX) {
+ if (config->sample_rate == 0)
+ config->sample_rate = AFE_PROXY_SAMPLING_RATE;
+ if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
+ config->sample_rate != 8000) {
+ config->sample_rate = AFE_PROXY_SAMPLING_RATE;
+ ret = -EINVAL;
+ goto error_open;
+ }
+ out->sample_rate = config->sample_rate;
+ out->config.rate = config->sample_rate;
+ if (config->format == AUDIO_FORMAT_DEFAULT)
+ config->format = AUDIO_FORMAT_PCM_16_BIT;
+ if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
+ config->format = AUDIO_FORMAT_PCM_16_BIT;
+ ret = -EINVAL;
+ goto error_open;
+ }
+ out->format = config->format;
+ out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
+ out->config = pcm_config_afe_proxy_playback;
+ adev->voice_tx_output = out;
} else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
format = AUDIO_FORMAT_PCM_16_BIT;
out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
@@ -2706,6 +2828,10 @@
if (out->compr_config.codec != NULL)
free(out->compr_config.codec);
}
+
+ if (adev->voice_tx_output == out)
+ adev->voice_tx_output = NULL;
+
pthread_cond_destroy(&out->cond);
pthread_mutex_destroy(&out->lock);
free(stream);
@@ -2919,10 +3045,16 @@
static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
{
struct audio_device *adev = (struct audio_device *)dev;
+
pthread_mutex_lock(&adev->lock);
if (adev->mode != mode) {
- ALOGD("%s mode %d\n", __func__, mode);
+ ALOGD("%s: mode %d\n", __func__, mode);
adev->mode = mode;
+ if ((mode == AUDIO_MODE_NORMAL || mode == AUDIO_MODE_IN_COMMUNICATION) &&
+ voice_is_in_call(adev)) {
+ voice_stop_call(adev);
+ adev->current_call_output = NULL;
+ }
}
pthread_mutex_unlock(&adev->lock);
return 0;
@@ -2951,7 +3083,8 @@
{
int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
- return get_input_buffer_size(config->sample_rate, config->format, channel_count);
+ return get_input_buffer_size(config->sample_rate, config->format, channel_count,
+ false /* is_low_latency: since we don't know, be conservative */);
}
static int adev_open_input_stream(struct audio_hw_device *dev,
@@ -2967,7 +3100,7 @@
struct stream_in *in;
int ret = 0, buffer_size, frame_size;
int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
-
+ bool is_low_latency = false;
*stream_in = NULL;
if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0)
@@ -3011,11 +3144,39 @@
/* Update config params with the requested sample rate and channels */
in->usecase = USECASE_AUDIO_RECORD;
+ if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE &&
+ (flags & AUDIO_INPUT_FLAG_FAST) != 0) {
+ is_low_latency = true;
+#if LOW_LATENCY_CAPTURE_USE_CASE
+ in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY;
+#endif
+ }
in->config = pcm_config_audio_capture;
in->config.rate = config->sample_rate;
in->format = config->format;
- if (channel_count == 6) {
+ if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
+ if (config->sample_rate == 0)
+ config->sample_rate = AFE_PROXY_SAMPLING_RATE;
+ if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
+ config->sample_rate != 8000) {
+ config->sample_rate = AFE_PROXY_SAMPLING_RATE;
+ ret = -EINVAL;
+ goto err_open;
+ }
+ if (config->format == AUDIO_FORMAT_DEFAULT)
+ config->format = AUDIO_FORMAT_PCM_16_BIT;
+ if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
+ config->format = AUDIO_FORMAT_PCM_16_BIT;
+ ret = -EINVAL;
+ goto err_open;
+ }
+
+ in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY;
+ in->config = pcm_config_afe_proxy_record;
+ in->config.channels = channel_count;
+ in->config.rate = config->sample_rate;
+ } else if (channel_count == 6) {
if(audio_extn_ssr_get_enabled()) {
if(audio_extn_ssr_init(in)) {
ALOGE("%s: audio_extn_ssr_init failed", __func__);
@@ -3034,7 +3195,8 @@
frame_size = audio_stream_in_frame_size(&in->stream);
buffer_size = get_input_buffer_size(config->sample_rate,
config->format,
- channel_count);
+ channel_count,
+ is_low_latency);
in->config.period_size = buffer_size / frame_size;
}
@@ -3116,6 +3278,23 @@
return 0;
}
+/* This returns 1 if the input parameter looks at all plausible as a low latency period size,
+ * or 0 otherwise. A return value of 1 doesn't mean the value is guaranteed to work,
+ * just that it _might_ work.
+ */
+static int period_size_is_plausible_for_low_latency(int period_size)
+{
+ switch (period_size) {
+ case 160:
+ case 240:
+ case 320:
+ case 480:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
static int adev_open(const hw_module_t *module, const char *name,
hw_device_t **device)
{
@@ -3233,31 +3412,38 @@
adev->bt_wb_speech_enabled = false;
+ audio_extn_ds2_enable(adev);
*device = &adev->device.common;
audio_extn_utils_update_streams_output_cfg_list(adev->platform, adev->mixer,
&adev->streams_output_cfg_list);
audio_device_ref_count++;
+
+ char value[PROPERTY_VALUE_MAX];
+ int trial;
+ if (property_get("audio_hal.period_size", value, NULL) > 0) {
+ trial = atoi(value);
+ if (period_size_is_plausible_for_low_latency(trial)) {
+ pcm_config_low_latency.period_size = trial;
+ pcm_config_low_latency.start_threshold = trial / 4;
+ pcm_config_low_latency.avail_min = trial / 4;
+ configured_low_latency_capture_period_size = trial;
+ }
+ }
+ if (property_get("audio_hal.in_period_size", value, NULL) > 0) {
+ trial = atoi(value);
+ if (period_size_is_plausible_for_low_latency(trial)) {
+ configured_low_latency_capture_period_size = trial;
+ }
+ }
+
pthread_mutex_unlock(&adev_init_lock);
ALOGV("%s: exit", __func__);
return 0;
}
-int pcm_ioctl(struct pcm *pcm, int request, ...)
-{
- va_list ap;
- void * arg;
- int pcm_fd = *(int*)pcm;
-
- va_start(ap, request);
- arg = va_arg(ap, void *);
- va_end(ap);
-
- return ioctl(pcm_fd, request, arg);
-}
-
static struct hw_module_methods_t hal_module_methods = {
.open = adev_open,
};
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index bdb9aae..d05f743 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -32,9 +32,6 @@
#define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so"
#define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/system/lib/soundfx/libqcompostprocbundle.so"
-#define BT_SCO_SAMPLE_RATE "bt-sco-samplerate"
-#define BT_SCO_WB_SAMPLE_RATE "bt-sco-wb-samplerate"
-
/* Flags used to initialize acdb_settings variable that goes to ACDB library */
#define NONE_FLAG 0x00000000
#define ANC_FLAG 0x00000001
@@ -114,6 +111,10 @@
USECASE_AUDIO_SPKR_CALIB_RX,
USECASE_AUDIO_SPKR_CALIB_TX,
+
+ USECASE_AUDIO_PLAYBACK_AFE_PROXY,
+ USECASE_AUDIO_RECORD_AFE_PROXY,
+
AUDIO_USECASE_MAX
};
@@ -203,7 +204,7 @@
int standby;
int source;
int pcm_device_id;
- int device;
+ audio_devices_t device;
audio_channel_mask_t channel_mask;
audio_usecase_t usecase;
bool enable_aec;
@@ -269,6 +270,8 @@
audio_devices_t out_device;
struct stream_in *active_input;
struct stream_out *primary_output;
+ struct stream_out *voice_tx_output;
+ struct stream_out *current_call_output;
bool bluetooth_nrec;
bool screen_off;
int *snd_dev_ref_cnt;
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index b4476f5..cf64878 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <dlfcn.h>
+#include <fcntl.h>
#include <sys/ioctl.h>
#include <cutils/log.h>
#include <cutils/properties.h>
@@ -32,6 +33,8 @@
#include "platform.h"
#include "audio_extn.h"
#include "voice_extn.h"
+#include "sound/msmcal-hwdep.h"
+#define SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID (100)
#define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
#define MIXER_XML_PATH_MTP "/system/etc/mixer_paths_mtp.xml"
@@ -93,6 +96,15 @@
#define AUDIO_PARAMETER_KEY_SLOWTALK "st_enable"
#define AUDIO_PARAMETER_KEY_HD_VOICE "hd_voice"
#define AUDIO_PARAMETER_KEY_VOLUME_BOOST "volume_boost"
+#define MAX_CAL_NAME 20
+
+char cal_name_info[WCD9XXX_MAX_CAL][MAX_CAL_NAME] = {
+ [WCD9XXX_ANC_CAL] = "anc_cal",
+ [WCD9XXX_MBHC_CAL] = "mbhc_cal",
+ [WCD9XXX_MAD_CAL] = "mad_cal",
+};
+
+#define AUDIO_PARAMETER_KEY_REC_PLAY_CONC "rec_play_conc_on"
enum {
VOICE_FEATURE_SET_DEFAULT,
@@ -112,6 +124,8 @@
typedef void (*acdb_send_voice_cal_t)(int, int);
typedef int (*acdb_reload_vocvoltable_t)(int);
typedef int (*acdb_get_default_app_type_t)(void);
+typedef int (*acdb_loader_get_calibration_t)(char *attr, int size, void *data);
+acdb_loader_get_calibration_t acdb_loader_get_calibration;
struct platform_data {
struct audio_device *adev;
@@ -134,7 +148,9 @@
acdb_send_voice_cal_t acdb_send_voice_cal;
acdb_reload_vocvoltable_t acdb_reload_vocvoltable;
acdb_get_default_app_type_t acdb_get_default_app_type;
-
+#ifdef RECORD_PLAY_CONCURRENCY
+ bool rec_play_conc_set;
+#endif
void *hw_info;
struct csd_data *csd;
};
@@ -213,6 +229,11 @@
[SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = "speaker-and-anc-headphones",
[SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset",
[SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected",
+#ifdef RECORD_PLAY_CONCURRENCY
+ [SND_DEVICE_OUT_VOIP_HANDSET] = "voip-handset",
+ [SND_DEVICE_OUT_VOIP_SPEAKER] = "voip-speaker",
+ [SND_DEVICE_OUT_VOIP_HEADPHONES] = "voip-headphones",
+#endif
/* Capture sound devices */
[SND_DEVICE_IN_HANDSET_MIC] = "handset-mic",
@@ -294,6 +315,11 @@
[SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = 26,
[SND_DEVICE_OUT_ANC_HANDSET] = 103,
[SND_DEVICE_OUT_SPEAKER_PROTECTED] = 101,
+#ifdef RECORD_PLAY_CONCURRENCY
+ [SND_DEVICE_OUT_VOIP_HANDSET] = 133,
+ [SND_DEVICE_OUT_VOIP_SPEAKER] = 132,
+ [SND_DEVICE_OUT_VOIP_HEADPHONES] = 134,
+#endif
[SND_DEVICE_IN_HANDSET_MIC] = 4,
[SND_DEVICE_IN_HANDSET_MIC_AEC] = 106,
@@ -380,6 +406,11 @@
{TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET)},
{TO_NAME_INDEX(SND_DEVICE_OUT_ANC_HANDSET)},
{TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED)},
+#ifdef RECORD_PLAY_CONCURRENCY
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_HANDSET)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_SPEAKER)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_HEADPHONES)},
+#endif
{TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC)},
{TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC)},
{TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_NS)},
@@ -425,6 +456,64 @@
{TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)},
};
+#define NO_COLS 2
+static int msm_be_id_array_len;
+static int (*msm_device_to_be_id)[];
+
+/* Below table lists output device to BE_ID mapping*/
+/* Update the table based on the board configuration*/
+
+static int msm_device_to_be_id_internal_codec [][NO_COLS] = {
+ {AUDIO_DEVICE_OUT_EARPIECE , 34},
+ {AUDIO_DEVICE_OUT_SPEAKER , 34},
+ {AUDIO_DEVICE_OUT_WIRED_HEADSET , 34},
+ {AUDIO_DEVICE_OUT_WIRED_HEADPHONE , 34},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO , 11},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET , 11},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT , 11},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP , -1},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES , -1},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER , -1},
+ {AUDIO_DEVICE_OUT_AUX_DIGITAL , 4},
+ {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET , 9},
+ {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET , 9},
+ {AUDIO_DEVICE_OUT_USB_ACCESSORY , -1},
+ {AUDIO_DEVICE_OUT_USB_DEVICE , -1},
+ {AUDIO_DEVICE_OUT_REMOTE_SUBMIX , 9},
+ {AUDIO_DEVICE_OUT_PROXY , 9},
+ {AUDIO_DEVICE_OUT_FM , 7},
+ {AUDIO_DEVICE_OUT_FM_TX , 8},
+ {AUDIO_DEVICE_OUT_ALL , -1},
+ {AUDIO_DEVICE_NONE , -1},
+ {AUDIO_DEVICE_OUT_DEFAULT , -1},
+};
+
+static int msm_device_to_be_id_external_codec [][NO_COLS] = {
+ {AUDIO_DEVICE_OUT_EARPIECE , 2},
+ {AUDIO_DEVICE_OUT_SPEAKER , 2},
+ {AUDIO_DEVICE_OUT_WIRED_HEADSET , 2},
+ {AUDIO_DEVICE_OUT_WIRED_HEADPHONE , 2},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO , 11},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET , 11},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT , 11},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP , -1},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES , -1},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER , -1},
+ {AUDIO_DEVICE_OUT_AUX_DIGITAL , 4},
+ {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET , 9},
+ {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET , 9},
+ {AUDIO_DEVICE_OUT_USB_ACCESSORY , -1},
+ {AUDIO_DEVICE_OUT_USB_DEVICE , -1},
+ {AUDIO_DEVICE_OUT_REMOTE_SUBMIX , 9},
+ {AUDIO_DEVICE_OUT_PROXY , 9},
+ {AUDIO_DEVICE_OUT_FM , 7},
+ {AUDIO_DEVICE_OUT_FM_TX , 8},
+ {AUDIO_DEVICE_OUT_ALL , -1},
+ {AUDIO_DEVICE_NONE , -1},
+ {AUDIO_DEVICE_OUT_DEFAULT , -1},
+};
+
+
#define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
#define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
@@ -435,41 +524,89 @@
sizeof("msm8x16-snd-card-mtp"))) {
strlcpy(mixer_xml_path, MIXER_XML_PATH_MTP,
sizeof(MIXER_XML_PATH_MTP));
+
+ msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+ msm_be_id_array_len =
+ sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
} else if (!strncmp(snd_card_name, "msm8x16-skuh-snd-card",
sizeof("msm8x16-skuh-snd-card"))) {
strlcpy(mixer_xml_path, MIXER_XML_PATH_QRD_SKUH,
sizeof(MIXER_XML_PATH_QRD_SKUH));
+
+ msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+ msm_be_id_array_len =
+ sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
} else if (!strncmp(snd_card_name, "msm8x16-skui-snd-card",
sizeof("msm8x16-skui-snd-card"))) {
strlcpy(mixer_xml_path, MIXER_XML_PATH_QRD_SKUI,
sizeof(MIXER_XML_PATH_QRD_SKUI));
+
+ msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+ msm_be_id_array_len =
+ sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
} else if (!strncmp(snd_card_name, "msm8x16-skuhf-snd-card",
sizeof("msm8x16-skuhf-snd-card"))) {
strlcpy(mixer_xml_path, MIXER_XML_PATH_QRD_SKUHF,
sizeof(MIXER_XML_PATH_QRD_SKUHF));
+
+ msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+ msm_be_id_array_len =
+ sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
} else if (!strncmp(snd_card_name, "msm8939-snd-card-mtp",
sizeof("msm8939-snd-card-mtp"))) {
strlcpy(mixer_xml_path, MIXER_XML_PATH_MTP,
sizeof(MIXER_XML_PATH_MTP));
+
+ msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+ msm_be_id_array_len =
+ sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
} else if (!strncmp(snd_card_name, "msm8939-snd-card-skuk",
sizeof("msm8939-snd-card-skuk"))) {
strlcpy(mixer_xml_path, MIXER_XML_PATH_SKUK,
sizeof(MIXER_XML_PATH_SKUK));
+ msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+ msm_be_id_array_len =
+ sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
} else if (!strncmp(snd_card_name, "msm8939-tapan-snd-card",
sizeof("msm8939-tapan-snd-card"))) {
strlcpy(mixer_xml_path, MIXER_XML_PATH_WCD9306,
sizeof(MIXER_XML_PATH_WCD9306));
+ msm_device_to_be_id = msm_device_to_be_id_external_codec;
+ msm_be_id_array_len =
+ sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_external_codec[0]);
+
} else if (!strncmp(snd_card_name, "msm8939-tapan9302-snd-card",
sizeof("msm8939-tapan9302-snd-card"))) {
strlcpy(mixer_xml_path, MIXER_XML_PATH_WCD9306,
sizeof(MIXER_XML_PATH_WCD9306));
+
+ msm_device_to_be_id = msm_device_to_be_id_external_codec;
+ msm_be_id_array_len =
+ sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_external_codec[0]);
+
} else if (!strncmp(snd_card_name, "msm8939-tomtom9330-snd-card",
sizeof("msm8939-tomtom9330-snd-card"))) {
strlcpy(mixer_xml_path, MIXER_XML_PATH_WCD9330,
sizeof(MIXER_XML_PATH_WCD9330));
+
+ msm_device_to_be_id = msm_device_to_be_id_external_codec;
+ msm_be_id_array_len =
+ sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_external_codec[0]);
+
} else {
strlcpy(mixer_xml_path, MIXER_XML_PATH,
sizeof(MIXER_XML_PATH));
+
+ msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+ msm_be_id_array_len =
+ sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
}
}
@@ -658,6 +795,92 @@
return;
}
+static int hw_util_open(int card_no)
+{
+ int fd = -1;
+ char dev_name[256];
+
+ snprintf(dev_name, sizeof(dev_name), "/dev/snd/hwC%uD%u",
+ card_no, WCD9XXX_CODEC_HWDEP_NODE);
+ ALOGD("%s Opening device %s\n", __func__, dev_name);
+ fd = open(dev_name, O_WRONLY);
+ if (fd < 0) {
+ ALOGE("%s: cannot open device '%s'\n", __func__, dev_name);
+ return fd;
+ }
+ ALOGD("%s success", __func__);
+ return fd;
+}
+
+struct param_data {
+ int use_case;
+ int acdb_id;
+ int get_size;
+ int buff_size;
+ int data_size;
+ void *buff;
+};
+
+static int send_codec_cal(acdb_loader_get_calibration_t acdb_loader_get_calibration, int fd)
+{
+ int ret = 0, type;
+
+ for (type = WCD9XXX_ANC_CAL; type < WCD9XXX_MAX_CAL; type++) {
+ struct wcdcal_ioctl_buffer codec_buffer;
+ struct param_data calib;
+
+ if (!strcmp(cal_name_info[type], "mad_cal"))
+ calib.acdb_id = SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID;
+ calib.get_size = 1;
+ ret = acdb_loader_get_calibration(cal_name_info[type], sizeof(struct param_data),
+ &calib);
+ if (ret < 0) {
+ ALOGE("%s get_calibration failed\n", __func__);
+ return ret;
+ }
+ calib.get_size = 0;
+ calib.buff = malloc(calib.buff_size);
+ ret = acdb_loader_get_calibration(cal_name_info[type],
+ sizeof(struct param_data), &calib);
+ if (ret < 0) {
+ ALOGE("%s get_calibration failed\n", __func__);
+ free(calib.buff);
+ return ret;
+ }
+ codec_buffer.buffer = calib.buff;
+ codec_buffer.size = calib.data_size;
+ codec_buffer.cal_type = type;
+ if (ioctl(fd, SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE, &codec_buffer) < 0)
+ ALOGE("Failed to call ioctl for %s err=%d",
+ cal_name_info[type], errno);
+ ALOGD("%s cal sent for %s", __func__, cal_name_info[type]);
+ free(calib.buff);
+ }
+ return ret;
+}
+
+static void audio_hwdep_send_cal(struct platform_data *plat_data)
+{
+ int fd;
+
+ fd = hw_util_open(plat_data->adev->snd_card);
+ if (fd == -1) {
+ ALOGE("%s error open\n", __func__);
+ return;
+ }
+
+ acdb_loader_get_calibration = (acdb_loader_get_calibration_t)
+ dlsym(plat_data->acdb_handle, "acdb_loader_get_calibration");
+
+ if (acdb_loader_get_calibration == NULL) {
+ ALOGE("%s: ERROR. dlsym Error:%s acdb_loader_get_calibration", __func__,
+ dlerror());
+ return;
+ }
+ if (send_codec_cal(acdb_loader_get_calibration, fd) < 0)
+ ALOGE("%s: Could not send anc cal", __FUNCTION__);
+}
+
void *platform_init(struct audio_device *adev)
{
char platform[PROPERTY_VALUE_MAX];
@@ -666,7 +889,7 @@
struct platform_data *my_data = NULL;
int retry_num = 0, snd_card_num = 0;
const char *snd_card_name;
- char mixer_xml_path[100];
+ char mixer_xml_path[100],ffspEnable[PROPERTY_VALUE_MAX];
char *cvd_version = NULL;
my_data = calloc(1, sizeof(struct platform_data));
@@ -768,7 +991,13 @@
my_data->fluence_mode = FLUENCE_BROADSIDE;
}
}
-
+ property_get("persist.audio.FFSP.enable", ffspEnable, "");
+ if (!strncmp("true", ffspEnable, sizeof("true"))) {
+ acdb_device_table[SND_DEVICE_OUT_SPEAKER] = 131;
+ acdb_device_table[SND_DEVICE_OUT_SPEAKER_REVERSE] = 131;
+ acdb_device_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 131;
+ acdb_device_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 131;
+ }
my_data->voice_feature_set = VOICE_FEATURE_SET_DEFAULT;
my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
if (my_data->acdb_handle == NULL) {
@@ -838,6 +1067,7 @@
audio_extn_spkr_prot_init(adev);
audio_extn_dolby_set_license(adev);
+ audio_hwdep_send_cal(my_data);
return my_data;
}
@@ -1079,7 +1309,7 @@
int ret = 0;
if (my_data->csd != NULL &&
- my_data->adev->mode == AUDIO_MODE_IN_CALL) {
+ voice_is_in_call(my_data->adev)) {
/* This must be called before disabling mixer controls on APQ side */
ret = my_data->csd->disable_device();
if (ret < 0) {
@@ -1308,6 +1538,18 @@
struct audio_device *adev = my_data->adev;
audio_mode_t mode = adev->mode;
snd_device_t snd_device = SND_DEVICE_NONE;
+#ifdef RECORD_PLAY_CONCURRENCY
+ bool use_voip_out_devices = false;
+ bool prop_rec_play_enabled = false;
+ char recConcPropValue[PROPERTY_VALUE_MAX];
+
+ if (property_get("rec.playback.conc.disabled", recConcPropValue, NULL)) {
+ prop_rec_play_enabled = atoi(recConcPropValue) || !strncmp("true", recConcPropValue, 4);
+ }
+ use_voip_out_devices = prop_rec_play_enabled &&
+ (my_data->rec_play_conc_set || adev->mode == AUDIO_MODE_IN_COMMUNICATION);
+ ALOGV("platform_get_output_snd_device use_voip_out_devices : %d",use_voip_out_devices);
+#endif
audio_channel_mask_t channel_mask = (adev->active_input == NULL) ?
AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask;
@@ -1350,8 +1592,7 @@
goto exit;
}
- if ((mode == AUDIO_MODE_IN_CALL) ||
- voice_extn_compress_voip_is_active(adev)) {
+ if (voice_is_in_call(adev) || voice_extn_compress_voip_is_active(adev)) {
if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
@@ -1405,18 +1646,38 @@
devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
if (devices & AUDIO_DEVICE_OUT_WIRED_HEADSET
&& audio_extn_get_anc_enabled()) {
- if (audio_extn_should_use_fb_anc())
- snd_device = SND_DEVICE_OUT_ANC_FB_HEADSET;
+#ifdef RECORD_PLAY_CONCURRENCY
+ if (use_voip_out_devices) {
+ // ANC should be disabled for voip concurrency
+ snd_device = SND_DEVICE_OUT_VOIP_HEADPHONES;
+ } else
+#endif
+ {
+ if (audio_extn_should_use_fb_anc())
+ snd_device = SND_DEVICE_OUT_ANC_FB_HEADSET;
+ else
+ snd_device = SND_DEVICE_OUT_ANC_HEADSET;
+ }
+ } else {
+#ifdef RECORD_PLAY_CONCURRENCY
+ if (use_voip_out_devices)
+ snd_device = SND_DEVICE_OUT_VOIP_HEADPHONES;
else
- snd_device = SND_DEVICE_OUT_ANC_HEADSET;
+#endif
+ snd_device = SND_DEVICE_OUT_HEADPHONES;
}
- else
- snd_device = SND_DEVICE_OUT_HEADPHONES;
} else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
- if (adev->speaker_lr_swap)
- snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
- else
- snd_device = SND_DEVICE_OUT_SPEAKER;
+#ifdef RECORD_PLAY_CONCURRENCY
+ if (use_voip_out_devices) {
+ snd_device = SND_DEVICE_OUT_VOIP_SPEAKER;
+ } else
+#endif
+ {
+ if (adev->speaker_lr_swap)
+ snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
+ else
+ snd_device = SND_DEVICE_OUT_SPEAKER;
+ }
} else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
if (adev->bt_wb_speech_enabled)
snd_device = SND_DEVICE_OUT_BT_SCO_WB;
@@ -1432,7 +1693,12 @@
} else if (devices & AUDIO_DEVICE_OUT_FM_TX) {
snd_device = SND_DEVICE_OUT_TRANSMISSION_FM;
} else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
- snd_device = SND_DEVICE_OUT_HANDSET;
+#ifdef RECORD_PLAY_CONCURRENCY
+ if (use_voip_out_devices)
+ snd_device = SND_DEVICE_OUT_VOIP_HANDSET;
+ else
+#endif
+ snd_device = SND_DEVICE_OUT_HANDSET;
} else if (devices & AUDIO_DEVICE_OUT_PROXY) {
channel_count = audio_extn_get_afe_proxy_channel_count();
ALOGD("%s: setting sink capability(%d) for Proxy", __func__, channel_count);
@@ -1464,7 +1730,7 @@
ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
__func__, out_device, in_device);
- if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) ||
+ if ((out_device != AUDIO_DEVICE_NONE) && (voice_is_in_call(adev) ||
voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev))) {
if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
!voice_extn_compress_voip_is_active(adev)) {
@@ -1934,6 +2200,19 @@
}
}
+#ifdef RECORD_PLAY_CONCURRENCY
+ err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_REC_PLAY_CONC, value, sizeof(value));
+ if (err >= 0) {
+ if (!strncmp("true", value, sizeof("true"))) {
+ ALOGD("setting record playback concurrency to true");
+ my_data->rec_play_conc_set = true;
+ } else {
+ ALOGD("setting record playback concurrency to false");
+ my_data->rec_play_conc_set = false;
+ }
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_REC_PLAY_CONC);
+ }
+#endif
ALOGV("%s: exit with code(%d)", __func__, ret);
return ret;
}
@@ -2287,6 +2566,12 @@
return fragment_size;
}
+void platform_get_device_to_be_id_map(int **device_to_be_id, int *length)
+{
+ *device_to_be_id = msm_device_to_be_id;
+ *length = msm_be_id_array_len;
+}
+
bool platform_check_24_bit_support() {
return false;
}
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index dec9eda..5eeea60 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -77,6 +77,11 @@
SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
SND_DEVICE_OUT_ANC_HANDSET,
SND_DEVICE_OUT_SPEAKER_PROTECTED,
+#ifdef RECORD_PLAY_CONCURRENCY
+ SND_DEVICE_OUT_VOIP_HANDSET,
+ SND_DEVICE_OUT_VOIP_SPEAKER,
+ SND_DEVICE_OUT_VOIP_HEADPHONES,
+#endif
SND_DEVICE_OUT_END,
/*
@@ -164,6 +169,10 @@
#define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240
#define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2
+#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
+#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
+#define LOW_LATENCY_CAPTURE_USE_CASE 0
+
#define HDMI_MULTI_PERIOD_SIZE 336
#define HDMI_MULTI_PERIOD_COUNT 8
#define HDMI_MULTI_DEFAULT_CHANNEL_COUNT 6
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 87ce2cd..941d39f 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -505,7 +505,8 @@
struct platform_data *my_data = (struct platform_data *)platform;
int ret = 0;
- if (my_data->csd_client != NULL) {
+ if (my_data->csd_client != NULL &&
+ voice_is_in_call(my_data->adev)) {
/* This must be called before disabling the mixer controls on APQ side */
if (my_data->csd_disable_device == NULL) {
ALOGE("%s: dlsym error for csd_disable_device", __func__);
@@ -656,7 +657,7 @@
goto exit;
}
- if (mode == AUDIO_MODE_IN_CALL) {
+ if (voice_is_in_call(adev)) {
if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
if (adev->voice.tty_mode == TTY_MODE_FULL)
@@ -748,11 +749,7 @@
ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
__func__, out_device, in_device);
- if (mode == AUDIO_MODE_IN_CALL) {
- if (out_device == AUDIO_DEVICE_NONE) {
- ALOGE("%s: No output device set for voice call", __func__);
- goto exit;
- }
+ if ((out_device != AUDIO_DEVICE_NONE) && voice_is_in_call(adev)) {
if (adev->voice.tty_mode != TTY_MODE_OFF) {
if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
@@ -1042,10 +1039,6 @@
return false;
}
-bool platform_check_24_bit_support() {
- return false;
-}
-
bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev __unused,
struct audio_usecase *usecase __unused)
{
diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h
index 20984d8..950ea84 100644
--- a/hal/msm8960/platform.h
+++ b/hal/msm8960/platform.h
@@ -138,4 +138,11 @@
/* Define macro for Internal FM volume mixer */
#define FM_RX_VOLUME "Internal FM RX Volume"
+#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
+#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
+#define LOW_LATENCY_CAPTURE_USE_CASE 0
+
+#define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
+#define AFE_PROXY_RECORD_PCM_DEVICE 8
+
#endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 66c7731..e0d8a39 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <dlfcn.h>
+#include <fcntl.h>
#include <sys/ioctl.h>
#include <cutils/log.h>
#include <cutils/properties.h>
@@ -33,7 +34,9 @@
#include "audio_extn.h"
#include "voice_extn.h"
#include "sound/compress_params.h"
+#include "sound/msmcal-hwdep.h"
+#define SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID (100)
#define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
#define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
#define MIXER_XML_PATH_I2S "/system/etc/mixer_paths_i2s.xml"
@@ -98,6 +101,13 @@
#define EVENT_EXTERNAL_SPK_1 "qc_ext_spk_1"
#define EVENT_EXTERNAL_SPK_2 "qc_ext_spk_2"
#define EVENT_EXTERNAL_MIC "qc_ext_mic"
+#define MAX_CAL_NAME 20
+
+char cal_name_info[WCD9XXX_MAX_CAL][MAX_CAL_NAME] = {
+ [WCD9XXX_ANC_CAL] = "anc_cal",
+ [WCD9XXX_MBHC_CAL] = "mbhc_cal",
+ [WCD9XXX_MAD_CAL] = "mad_cal",
+};
enum {
VOICE_FEATURE_SET_DEFAULT,
@@ -117,6 +127,8 @@
typedef void (*acdb_send_voice_cal_t)(int, int);
typedef int (*acdb_reload_vocvoltable_t)(int);
typedef int (*acdb_get_default_app_type_t)(void);
+typedef int (*acdb_loader_get_calibration_t)(char *attr, int size, void *data);
+acdb_loader_get_calibration_t acdb_loader_get_calibration;
struct platform_data {
struct audio_device *adev;
@@ -208,6 +220,12 @@
INCALL_MUSIC_UPLINK2_PCM_DEVICE},
[USECASE_AUDIO_SPKR_CALIB_RX] = {SPKR_PROT_CALIB_RX_PCM_DEVICE, -1},
[USECASE_AUDIO_SPKR_CALIB_TX] = {-1, SPKR_PROT_CALIB_TX_PCM_DEVICE},
+
+ [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = {AFE_PROXY_PLAYBACK_PCM_DEVICE,
+ AFE_PROXY_RECORD_PCM_DEVICE},
+ [USECASE_AUDIO_RECORD_AFE_PROXY] = {AFE_PROXY_PLAYBACK_PCM_DEVICE,
+ AFE_PROXY_RECORD_PCM_DEVICE},
+
};
/* Array to store sound devices */
@@ -233,6 +251,7 @@
[SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones",
[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones",
[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset",
+ [SND_DEVICE_OUT_VOICE_TX] = "voice-tx",
[SND_DEVICE_OUT_AFE_PROXY] = "afe-proxy",
[SND_DEVICE_OUT_USB_HEADSET] = "usb-headphones",
[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = "speaker-and-usb-headphones",
@@ -280,6 +299,8 @@
[SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic",
[SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic",
[SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic",
+ [SND_DEVICE_IN_VOICE_RX] = "voice-rx",
+
[SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic",
[SND_DEVICE_IN_VOICE_REC_MIC_NS] = "voice-rec-mic",
[SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = "voice-rec-dmic-ef",
@@ -323,6 +344,7 @@
[SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37,
+ [SND_DEVICE_OUT_VOICE_TX] = 45,
[SND_DEVICE_OUT_AFE_PROXY] = 0,
[SND_DEVICE_OUT_USB_HEADSET] = 45,
[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 14,
@@ -369,6 +391,8 @@
[SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16,
[SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36,
[SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16,
+ [SND_DEVICE_IN_VOICE_RX] = 44,
+
[SND_DEVICE_IN_VOICE_REC_MIC] = 4,
[SND_DEVICE_IN_VOICE_REC_MIC_NS] = 107,
[SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = 34,
@@ -498,6 +522,67 @@
{TO_NAME_INDEX(USECASE_AUDIO_HFP_SCO)},
};
+#define NO_COLS 2
+#ifdef PLATFORM_APQ8084
+static int msm_device_to_be_id [][NO_COLS] = {
+ {AUDIO_DEVICE_OUT_EARPIECE , 2},
+ {AUDIO_DEVICE_OUT_SPEAKER , 2},
+ {AUDIO_DEVICE_OUT_WIRED_HEADSET , 2},
+ {AUDIO_DEVICE_OUT_WIRED_HEADPHONE , 2},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO , 11},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET , 11},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT , 11},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP , -1},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES , -1},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER , -1},
+ {AUDIO_DEVICE_OUT_AUX_DIGITAL , 4},
+ {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET , 9},
+ {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET , 9},
+ {AUDIO_DEVICE_OUT_USB_ACCESSORY , -1},
+ {AUDIO_DEVICE_OUT_USB_DEVICE , -1},
+ {AUDIO_DEVICE_OUT_REMOTE_SUBMIX , 9},
+ {AUDIO_DEVICE_OUT_PROXY , 9},
+ {AUDIO_DEVICE_OUT_FM , 7},
+ {AUDIO_DEVICE_OUT_FM_TX , 8},
+ {AUDIO_DEVICE_OUT_ALL , -1},
+ {AUDIO_DEVICE_NONE , -1},
+ {AUDIO_DEVICE_OUT_DEFAULT , -1},
+};
+#elif PLATFORM_MSM8994
+static int msm_device_to_be_id [][NO_COLS] = {
+ {AUDIO_DEVICE_OUT_EARPIECE , 2},
+ {AUDIO_DEVICE_OUT_SPEAKER , 2},
+ {AUDIO_DEVICE_OUT_WIRED_HEADSET , 2},
+ {AUDIO_DEVICE_OUT_WIRED_HEADPHONE , 2},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO , 38},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET , 38},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT , 38},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP , -1},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES , -1},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER , -1},
+ {AUDIO_DEVICE_OUT_AUX_DIGITAL , 4},
+ {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET , 9},
+ {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET , 9},
+ {AUDIO_DEVICE_OUT_USB_ACCESSORY , -1},
+ {AUDIO_DEVICE_OUT_USB_DEVICE , -1},
+ {AUDIO_DEVICE_OUT_REMOTE_SUBMIX , 9},
+ {AUDIO_DEVICE_OUT_PROXY , 9},
+/* Add the correct be ids */
+ {AUDIO_DEVICE_OUT_FM , 7},
+ {AUDIO_DEVICE_OUT_FM_TX , 8},
+ {AUDIO_DEVICE_OUT_ALL , -1},
+ {AUDIO_DEVICE_NONE , -1},
+ {AUDIO_DEVICE_OUT_DEFAULT , -1},
+};
+#else
+static int msm_device_to_be_id [][NO_COLS] = {
+ {AUDIO_DEVICE_NONE, -1},
+};
+#endif
+static int msm_be_id_array_len =
+ sizeof(msm_device_to_be_id) / sizeof(msm_device_to_be_id[0]);
+
+
#define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
#define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
@@ -710,6 +795,9 @@
backend_table[SND_DEVICE_OUT_BT_SCO_WB] = strdup("bt-sco-wb");
backend_table[SND_DEVICE_OUT_HDMI] = strdup("hdmi");
backend_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = strdup("speaker-and-hdmi");
+ backend_table[SND_DEVICE_OUT_VOICE_TX] = strdup("afe-proxy");
+ backend_table[SND_DEVICE_IN_VOICE_RX] = strdup("afe-proxy");
+
backend_table[SND_DEVICE_OUT_AFE_PROXY] = strdup("afe-proxy");
backend_table[SND_DEVICE_OUT_USB_HEADSET] = strdup("usb-headphones");
backend_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] =
@@ -746,6 +834,92 @@
return;
}
+static int hw_util_open(int card_no)
+{
+ int fd = -1;
+ char dev_name[256];
+
+ snprintf(dev_name, sizeof(dev_name), "/dev/snd/hwC%uD%u",
+ card_no, WCD9XXX_CODEC_HWDEP_NODE);
+ ALOGD("%s Opening device %s\n", __func__, dev_name);
+ fd = open(dev_name, O_WRONLY);
+ if (fd < 0) {
+ ALOGE("%s: cannot open device '%s'\n", __func__, dev_name);
+ return fd;
+ }
+ ALOGD("%s success", __func__);
+ return fd;
+}
+
+struct param_data {
+ int use_case;
+ int acdb_id;
+ int get_size;
+ int buff_size;
+ int data_size;
+ void *buff;
+};
+
+static int send_codec_cal(acdb_loader_get_calibration_t acdb_loader_get_calibration, int fd)
+{
+ int ret = 0, type;
+
+ for (type = WCD9XXX_ANC_CAL; type < WCD9XXX_MAX_CAL; type++) {
+ struct wcdcal_ioctl_buffer codec_buffer;
+ struct param_data calib;
+
+ if (!strcmp(cal_name_info[type], "mad_cal"))
+ calib.acdb_id = SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID;
+ calib.get_size = 1;
+ ret = acdb_loader_get_calibration(cal_name_info[type], sizeof(struct param_data),
+ &calib);
+ if (ret < 0) {
+ ALOGE("%s get_calibration failed\n", __func__);
+ return ret;
+ }
+ calib.get_size = 0;
+ calib.buff = malloc(calib.buff_size);
+ ret = acdb_loader_get_calibration(cal_name_info[type],
+ sizeof(struct param_data), &calib);
+ if (ret < 0) {
+ ALOGE("%s get_calibration failed\n", __func__);
+ free(calib.buff);
+ return ret;
+ }
+ codec_buffer.buffer = calib.buff;
+ codec_buffer.size = calib.data_size;
+ codec_buffer.cal_type = type;
+ if (ioctl(fd, SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE, &codec_buffer) < 0)
+ ALOGE("Failed to call ioctl for %s err=%d",
+ cal_name_info[type], errno);
+ ALOGD("%s cal sent for %s", __func__, cal_name_info[type]);
+ free(calib.buff);
+ }
+ return ret;
+}
+
+static void audio_hwdep_send_cal(struct platform_data *plat_data)
+{
+ int fd;
+
+ fd = hw_util_open(plat_data->adev->snd_card);
+ if (fd == -1) {
+ ALOGE("%s error open\n", __func__);
+ return;
+ }
+
+ acdb_loader_get_calibration = (acdb_loader_get_calibration_t)
+ dlsym(plat_data->acdb_handle, "acdb_loader_get_calibration");
+
+ if (acdb_loader_get_calibration == NULL) {
+ ALOGE("%s: ERROR. dlsym Error:%s acdb_loader_get_calibration", __func__,
+ dlerror());
+ return;
+ }
+ if (send_codec_cal(acdb_loader_get_calibration, fd) < 0)
+ ALOGE("%s: Could not send anc cal", __FUNCTION__);
+}
+
void *platform_init(struct audio_device *adev)
{
char platform[PROPERTY_VALUE_MAX];
@@ -949,11 +1123,15 @@
/* update sound cards appropriately */
audio_extn_usb_set_proxy_sound_card(adev->snd_card);
+ /* init dap hal */
+ audio_extn_dap_hal_init(adev->snd_card);
+
/* Read one time ssr property */
audio_extn_ssr_update_enabled();
audio_extn_spkr_prot_init(adev);
audio_extn_dolby_set_license(adev);
+ audio_hwdep_send_cal(my_data);
/* init audio device arbitration */
audio_extn_dev_arbi_init();
@@ -982,6 +1160,7 @@
free(platform);
/* deinit usb */
audio_extn_usb_deinit();
+ audio_extn_dap_hal_deinit();
}
const char *platform_get_snd_device_name(snd_device_t snd_device)
@@ -1227,7 +1406,7 @@
int ret = 0;
if (my_data->csd != NULL &&
- my_data->adev->mode == AUDIO_MODE_IN_CALL) {
+ voice_is_in_call(my_data->adev)) {
/* This must be called before disabling mixer controls on APQ side */
ret = my_data->csd->disable_device();
if (ret < 0) {
@@ -1535,7 +1714,7 @@
goto exit;
}
- if ((mode == AUDIO_MODE_IN_CALL) ||
+ if (voice_is_in_call(adev) ||
voice_extn_compress_voip_is_active(adev)) {
if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
@@ -1580,7 +1759,9 @@
snd_device = SND_DEVICE_OUT_ANC_HANDSET;
else
snd_device = SND_DEVICE_OUT_VOICE_HANDSET;
- }
+ } else if (devices & AUDIO_DEVICE_OUT_TELEPHONY_TX)
+ snd_device = SND_DEVICE_OUT_VOICE_TX;
+
if (snd_device != SND_DEVICE_NONE) {
goto exit;
}
@@ -1653,7 +1834,7 @@
ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
__func__, out_device, in_device);
if (my_data->external_mic) {
- if (((out_device != AUDIO_DEVICE_NONE) && (mode == AUDIO_MODE_IN_CALL)) ||
+ if ((out_device != AUDIO_DEVICE_NONE && voice_is_in_call(adev)) ||
voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev)) {
if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
out_device & AUDIO_DEVICE_OUT_EARPIECE ||
@@ -1668,7 +1849,7 @@
if (snd_device != AUDIO_DEVICE_NONE)
goto exit;
- if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) ||
+ if ((out_device != AUDIO_DEVICE_NONE) && ((voice_is_in_call(adev)) ||
voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev))) {
if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
!voice_extn_compress_voip_is_active(adev)) {
@@ -1690,7 +1871,8 @@
goto exit;
}
}
- if (out_device & AUDIO_DEVICE_OUT_EARPIECE) {
+ if (out_device & AUDIO_DEVICE_OUT_EARPIECE ||
+ out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
if (out_device & AUDIO_DEVICE_OUT_EARPIECE &&
audio_extn_should_use_handset_anc(channel_count)) {
snd_device = SND_DEVICE_IN_AANC_HANDSET_MIC;
@@ -1719,8 +1901,7 @@
else
snd_device = SND_DEVICE_IN_BT_SCO_MIC;
}
- } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER ||
- out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+ } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
if (my_data->fluence_type != FLUENCE_NONE &&
my_data->fluence_in_voice_call &&
my_data->fluence_in_spkr_mode) {
@@ -1737,7 +1918,8 @@
if (audio_extn_hfp_is_active(adev))
platform_set_echo_reference(adev->platform, true);
}
- }
+ } else if (out_device & AUDIO_DEVICE_OUT_TELEPHONY_TX)
+ snd_device = SND_DEVICE_IN_VOICE_RX;
} else if (source == AUDIO_SOURCE_CAMCORDER) {
if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
in_device & AUDIO_DEVICE_IN_BACK_MIC) {
@@ -1886,12 +2068,13 @@
snd_device = SND_DEVICE_IN_HANDSET_MIC;
} else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
snd_device = SND_DEVICE_IN_HEADSET_MIC;
- } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER ||
- out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+ } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
if (channel_count == 2)
snd_device = SND_DEVICE_IN_SPEAKER_STEREO_DMIC;
else
snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+ } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+ snd_device = SND_DEVICE_IN_HANDSET_MIC;
} else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) {
if (adev->bt_wb_speech_enabled) {
if (adev->bluetooth_nrec)
@@ -2451,17 +2634,6 @@
return fragment_size;
}
-bool platform_check_24_bit_support() {
-
- char value[PROPERTY_VALUE_MAX] = {0};
- property_get("audio.offload.24bit.enable", value, "0");
- if (atoi(value)) {
- ALOGW("Property audio.offload.24bit.enable is set");
- return true;
- }
- return false;
-}
-
int platform_set_codec_backend_cfg(struct audio_device* adev,
unsigned int bit_width, unsigned int sample_rate)
{
@@ -2554,24 +2726,20 @@
// For voice calls use default configuration
// force routing is not required here, caller will do it anyway
- if (adev->mode == AUDIO_MODE_IN_CALL ||
- adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
+ if (voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
ALOGW("%s:Use default bw and sr for voice/voip calls ",__func__);
- *new_bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
- *new_sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
- backend_change = true;
- }
-
- /*
- * The backend should be configured at highest bit width and/or
- * sample rate amongst all playback usecases.
- * If the selected sample rate and/or bit width differ with
- * current backend sample rate and/or bit width, then, we set the
- * backend re-configuration flag.
- *
- * Exception: 16 bit playbacks is allowed through 16 bit/48 khz backend only
- */
- if (!backend_change) {
+ bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+ sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+ } else {
+ /*
+ * The backend should be configured at highest bit width and/or
+ * sample rate amongst all playback usecases.
+ * If the selected sample rate and/or bit width differ with
+ * current backend sample rate and/or bit width, then, we set the
+ * backend re-configuration flag.
+ *
+ * Exception: 16 bit playbacks is allowed through 16 bit/48 khz backend only
+ */
list_for_each(node, &adev->usecase_list) {
struct audio_usecase *curr_usecase;
curr_usecase = node_to_item(node, struct audio_usecase, list);
@@ -2617,12 +2785,6 @@
bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase)
{
- // check if 24bit configuration is enabled first
- if (!platform_check_24_bit_support()) {
- ALOGW("24bit not enable, no need to check for backend change");
- return false;
- }
-
ALOGV("platform_check_and_set_codec_backend_cfg usecase = %d",usecase->id );
unsigned int new_bit_width, old_bit_width;
@@ -2677,3 +2839,9 @@
done:
return ret;
}
+
+void platform_get_device_to_be_id_map(int **device_to_be_id, int *length)
+{
+ *device_to_be_id = msm_device_to_be_id;
+ *length = msm_be_id_array_len;
+}
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 62aa40a..831ee58 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -70,6 +70,7 @@
SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET,
+ SND_DEVICE_OUT_VOICE_TX,
SND_DEVICE_OUT_AFE_PROXY,
SND_DEVICE_OUT_USB_HEADSET,
SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET,
@@ -127,6 +128,7 @@
SND_DEVICE_IN_VOICE_REC_MIC_NS,
SND_DEVICE_IN_VOICE_REC_DMIC_STEREO,
SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+ SND_DEVICE_IN_VOICE_RX,
SND_DEVICE_IN_USB_HEADSET_MIC,
SND_DEVICE_IN_CAPTURE_FM,
SND_DEVICE_IN_AANC_HANDSET_MIC,
@@ -178,6 +180,10 @@
#define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
#define AUDIO_CAPTURE_PERIOD_COUNT 2
+#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
+#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
+#define LOW_LATENCY_CAPTURE_USE_CASE 1
+
#define DEVICE_NAME_MAX_SIZE 128
#define HW_INFO_ARRAY_MAX_SIZE 32
@@ -278,6 +284,9 @@
#define VOWLAN_CALL_PCM_DEVICE 36
#endif
+#define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
+#define AFE_PROXY_RECORD_PCM_DEVICE 8
+
#ifdef PLATFORM_MSM8x26
#define HFP_SCO_RX 28
#define HFP_ASM_RX_TX 29
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 534630c..368677b 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -91,9 +91,9 @@
uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info);
bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase);
-bool platform_check_24_bit_support();
int platform_get_usecase_index(const char * usecase);
int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id);
void platform_set_echo_reference(void *platform, bool enable);
+void platform_get_device_to_be_id_map(int **be_id_map, int *length);
#endif // AUDIO_PLATFORM_API_H
diff --git a/hal/voice.c b/hal/voice.c
index ecad7a7..53e3033 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -131,8 +131,8 @@
uc_info->id = usecase_id;
uc_info->type = VOICE_CALL;
- uc_info->stream.out = adev->primary_output;
- uc_info->devices = adev->primary_output->devices;
+ uc_info->stream.out = adev->current_call_output ;
+ uc_info->devices = adev->current_call_output ->devices;
uc_info->in_snd_device = SND_DEVICE_NONE;
uc_info->out_snd_device = SND_DEVICE_NONE;
@@ -213,6 +213,11 @@
return call_state;
}
+bool voice_is_in_call(struct audio_device *adev)
+{
+ return adev->voice.in_call;
+}
+
bool voice_is_in_call_rec_stream(struct stream_in *in)
{
bool in_call_rec = false;
@@ -368,11 +373,11 @@
{
int ret = 0;
+ adev->voice.in_call = true;
ret = voice_extn_start_call(adev);
if (ret == -ENOSYS) {
ret = voice_start_usecase(adev, USECASE_VOICE_CALL);
}
- adev->voice.in_call = true;
return ret;
}
@@ -494,6 +499,7 @@
if (usecase->type == VOICE_CALL) {
ALOGV("%s: updating device for usecase:%s", __func__,
use_case_table[usecase->id]);
+ usecase->stream.out = adev->current_call_output;
select_devices(adev, usecase->id);
}
}
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
index 8952522..e5b979f 100644
--- a/hal/voice_extn/voice_extn.c
+++ b/hal/voice_extn/voice_extn.c
@@ -299,7 +299,8 @@
* occured, otherwise voice calls will be started unintendedly on
* speaker.
*/
- if (is_call_active || adev->voice.in_call) {
+ if (is_call_active ||
+ (adev->voice.in_call && adev->mode == AUDIO_MODE_IN_CALL)) {
/* Device routing is not triggered for voice calls on the subsequent
* subs, Hence update the call states if voice call is already
* active on other sub.