summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRicardo Cerqueira <ricardo@cyngn.com>2015-11-05 00:45:26 +0000
committerRicardo Cerqueira <ricardo@cyngn.com>2015-11-05 00:45:26 +0000
commitfbbf508bd695b8c27cbc524fb51573354091b5e0 (patch)
treed779d8df3ab89b12b1810a2ebf0bd2edf772fa8d
parentc49734d5552746ee9ced46e36bc1b1a4a5118086 (diff)
parent819130e136f54a3e7fa37ba830d87fedcf28a8ae (diff)
downloadhardware_qcom_audio-fbbf508bd695b8c27cbc524fb51573354091b5e0.tar.gz
hardware_qcom_audio-fbbf508bd695b8c27cbc524fb51573354091b5e0.tar.bz2
hardware_qcom_audio-fbbf508bd695b8c27cbc524fb51573354091b5e0.zip
Merge tag 'android-6.0.0_r26' into cm-13.0
Android 6.0.0 release 26
-rw-r--r--hal/Android.mk7
-rw-r--r--hal/audio_extn/audio_extn.c102
-rw-r--r--hal/audio_extn/audio_extn.h9
-rw-r--r--hal/audio_extn/soundtrigger.c10
-rw-r--r--hal/audio_hw.c190
-rw-r--r--hal/audio_hw.h23
-rw-r--r--hal/msm8960/platform.c16
-rw-r--r--hal/msm8960/platform.h4
-rw-r--r--hal/msm8974/platform.c613
-rw-r--r--hal/msm8974/platform.h21
-rw-r--r--hal/platform_api.h7
-rw-r--r--hal/platform_info.c57
-rw-r--r--hal/voice.c98
-rw-r--r--hal/voice.h5
-rw-r--r--post_proc/volume_listener.c37
15 files changed, 1024 insertions, 175 deletions
diff --git a/hal/Android.mk b/hal/Android.mk
index e5c719b6..5c21334d 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -12,15 +12,21 @@ ifneq ($(filter msm8974 msm8226 msm8084 msm8992 msm8994,$(TARGET_BOARD_PLATFORM)
AUDIO_PLATFORM = msm8974
ifneq ($(filter msm8226,$(TARGET_BOARD_PLATFORM)),)
LOCAL_CFLAGS := -DPLATFORM_MSM8x26
+ LOCAL_CFLAGS += -DMAX_TARGET_SPECIFIC_CHANNEL_CNT="2"
endif
ifneq ($(filter msm8084,$(TARGET_BOARD_PLATFORM)),)
LOCAL_CFLAGS := -DPLATFORM_MSM8084
+ LOCAL_CFLAGS += -DMAX_TARGET_SPECIFIC_CHANNEL_CNT="2"
endif
ifneq ($(filter msm8992,$(TARGET_BOARD_PLATFORM)),)
LOCAL_CFLAGS := -DPLATFORM_MSM8994
+ LOCAL_CFLAGS += -DMAX_TARGET_SPECIFIC_CHANNEL_CNT="4"
+ LOCAL_CFLAGS += -DKPI_OPTIMIZE_ENABLED
endif
ifneq ($(filter msm8994,$(TARGET_BOARD_PLATFORM)),)
LOCAL_CFLAGS := -DPLATFORM_MSM8994
+ LOCAL_CFLAGS += -DMAX_TARGET_SPECIFIC_CHANNEL_CNT="4"
+ LOCAL_CFLAGS += -DKPI_OPTIMIZE_ENABLED
endif
endif
@@ -29,6 +35,7 @@ LOCAL_SRC_FILES := \
voice.c \
platform_info.c \
audio_extn/ext_speaker.c \
+ audio_extn/audio_extn.c \
$(AUDIO_PLATFORM)/platform.c
LOCAL_SHARED_LIBRARIES := \
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
new file mode 100644
index 00000000..dcc9baf6
--- /dev/null
+++ b/hal/audio_extn/audio_extn.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_extn"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <cutils/properties.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "audio_extn.h"
+#include "platform.h"
+#include "platform_api.h"
+
+
+
+#ifdef KPI_OPTIMIZE_ENABLED
+typedef int (*perf_lock_acquire_t)(int, int, int*, int);
+typedef int (*perf_lock_release_t)(int);
+
+static void *qcopt_handle;
+static perf_lock_acquire_t perf_lock_acq;
+static perf_lock_release_t perf_lock_rel;
+
+static int perf_lock_handle;
+char opt_lib_path[PROPERTY_VALUE_MAX] = {0};
+
+int perf_lock_opts[] = {0x101, 0x20E, 0x30E};
+
+int audio_extn_perf_lock_init(void)
+{
+ int ret = 0;
+ if (qcopt_handle == NULL) {
+ if (property_get("ro.vendor.extension_library",
+ opt_lib_path, NULL) <= 0) {
+ ALOGE("%s: Failed getting perf property", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ if ((qcopt_handle = dlopen(opt_lib_path, RTLD_NOW)) == NULL) {
+ ALOGE("%s: Failed to open perf handle", __func__);
+ ret = -EINVAL;
+ goto err;
+ } else {
+ perf_lock_acq = (perf_lock_acquire_t)dlsym(qcopt_handle,
+ "perf_lock_acq");
+ if (perf_lock_acq == NULL) {
+ ALOGE("%s: Perf lock Acquire NULL", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ perf_lock_rel = (perf_lock_release_t)dlsym(qcopt_handle,
+ "perf_lock_rel");
+ if (perf_lock_rel == NULL) {
+ ALOGE("%s: Perf lock Release NULL", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ ALOGD("%s: Perf lock handles Success", __func__);
+ }
+ }
+err:
+ return ret;
+}
+
+void audio_extn_perf_lock_acquire(void)
+{
+ if (perf_lock_acq) {
+ perf_lock_handle = perf_lock_acq(perf_lock_handle, 0, perf_lock_opts, 3);
+ ALOGV("%s: Perf lock acquired", __func__);
+ } else {
+ ALOGE("%s: Perf lock acquire error", __func__);
+ }
+}
+
+void audio_extn_perf_lock_release(void)
+{
+ if (perf_lock_rel && perf_lock_handle) {
+ perf_lock_rel(perf_lock_handle);
+ ALOGV("%s: Perf lock released", __func__);
+ } else {
+ ALOGE("%s: Perf lock release error", __func__);
+ }
+}
+#endif /* KPI_OPTIMIZE_ENABLED */
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index b99378e8..c518faa7 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -101,4 +101,13 @@ void audio_extn_dsm_feedback_enable(struct audio_device *adev,
void audio_extn_hwdep_cal_send(int snd_card, void *acdb_handle);
#endif
+#ifndef KPI_OPTIMIZE_ENABLED
+#define audio_extn_perf_lock_init() (0)
+#define audio_extn_perf_lock_acquire() (0)
+#define audio_extn_perf_lock_release() (0)
+#else
+int audio_extn_perf_lock_init(void);
+void audio_extn_perf_lock_acquire(void);
+void audio_extn_perf_lock_release(void);
+#endif /* KPI_OPTIMIZE_ENABLED */
#endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/soundtrigger.c b/hal/audio_extn/soundtrigger.c
index 4d093879..b5475a17 100644
--- a/hal/audio_extn/soundtrigger.c
+++ b/hal/audio_extn/soundtrigger.c
@@ -209,12 +209,14 @@ void audio_extn_sound_trigger_update_device_status(snd_device_t snd_device,
return;
if (snd_device >= SND_DEVICE_OUT_BEGIN &&
- snd_device < SND_DEVICE_OUT_END)
+ snd_device < SND_DEVICE_OUT_END) {
device_type = PCM_PLAYBACK;
- else if (snd_device >= SND_DEVICE_IN_BEGIN &&
- snd_device < SND_DEVICE_IN_END)
+ } else if (snd_device >= SND_DEVICE_IN_BEGIN &&
+ snd_device < SND_DEVICE_IN_END) {
+ if (snd_device == SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)
+ return;
device_type = PCM_CAPTURE;
- else {
+ } else {
ALOGE("%s: invalid device 0x%x, for event %d",
__func__, snd_device, event);
return;
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 8fc7764d..d44eeb45 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -62,6 +62,13 @@
#define PROXY_OPEN_RETRY_COUNT 100
#define PROXY_OPEN_WAIT_TIME 20
+#define MIN_CHANNEL_COUNT 1
+#define DEFAULT_CHANNEL_COUNT 2
+
+#define MAX_CHANNEL_COUNT atoi(XSTR(MAX_TARGET_SPECIFIC_CHANNEL_CNT))
+#define XSTR(x) STR(x)
+#define STR(x) #x
+
static unsigned int configured_low_latency_capture_period_size =
LOW_LATENCY_CAPTURE_PERIOD_SIZE;
@@ -71,7 +78,7 @@ static unsigned int configured_low_latency_capture_period_size =
static const bool k_enable_extended_precision = false;
struct pcm_config pcm_config_deep_buffer = {
- .channels = 2,
+ .channels = DEFAULT_CHANNEL_COUNT,
.rate = DEFAULT_OUTPUT_SAMPLING_RATE,
.period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE,
.period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT,
@@ -82,7 +89,7 @@ struct pcm_config pcm_config_deep_buffer = {
};
struct pcm_config pcm_config_low_latency = {
- .channels = 2,
+ .channels = DEFAULT_CHANNEL_COUNT,
.rate = DEFAULT_OUTPUT_SAMPLING_RATE,
.period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
.period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
@@ -104,7 +111,7 @@ struct pcm_config pcm_config_hdmi_multi = {
};
struct pcm_config pcm_config_audio_capture = {
- .channels = 2,
+ .channels = DEFAULT_CHANNEL_COUNT,
.period_count = AUDIO_CAPTURE_PERIOD_COUNT,
.format = PCM_FORMAT_S16_LE,
.stop_threshold = INT_MAX,
@@ -148,6 +155,7 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = {
[USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback",
[USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
[USECASE_AUDIO_PLAYBACK_TTS] = "audio-tts-playback",
+ [USECASE_AUDIO_PLAYBACK_ULL] = "audio-ull-playback",
[USECASE_AUDIO_RECORD] = "audio-record",
[USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
@@ -300,6 +308,8 @@ int enable_snd_device(struct audio_device *adev,
return -EINVAL;
}
+ platform_send_audio_calibration(adev->platform, snd_device);
+
adev->snd_dev_ref_cnt[snd_device]++;
if (adev->snd_dev_ref_cnt[snd_device] > 1) {
ALOGV("%s: snd_device(%d: %s) is already active",
@@ -315,13 +325,6 @@ int enable_snd_device(struct audio_device *adev,
if (audio_extn_spkr_prot_is_enabled())
audio_extn_spkr_prot_calib_cancel(adev);
- if (platform_send_audio_calibration(adev->platform, snd_device) < 0) {
- adev->snd_dev_ref_cnt[snd_device]--;
- audio_extn_sound_trigger_update_device_status(snd_device,
- ST_EVENT_SND_DEVICE_FREE);
- return -EINVAL;
- }
-
audio_extn_dsm_feedback_enable(adev, snd_device, true);
if ((snd_device == SND_DEVICE_OUT_SPEAKER ||
@@ -339,6 +342,7 @@ int enable_snd_device(struct audio_device *adev,
for (i = 0; i < num_devices; i++) {
enable_snd_device(adev, new_snd_devices[i]);
}
+ platform_set_speaker_gain_in_combo(adev, snd_device, true);
} else {
const char * dev_path = platform_get_snd_device_name(snd_device);
ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, dev_path);
@@ -377,12 +381,14 @@ int disable_snd_device(struct audio_device *adev,
for (i = 0; i < num_devices; i++) {
disable_snd_device(adev, new_snd_devices[i]);
}
+ platform_set_speaker_gain_in_combo(adev, snd_device, false);
} else {
audio_route_reset_and_update_path(adev->audio_route, dev_path);
}
audio_extn_sound_trigger_update_device_status(snd_device,
ST_EVENT_SND_DEVICE_FREE);
}
+
return 0;
}
@@ -643,12 +649,13 @@ int select_devices(struct audio_device *adev,
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) {
- out_device = adev->primary_output->devices;
+ if (adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE);
- } else if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY) {
- out_device = AUDIO_DEVICE_OUT_TELEPHONY_TX;
+ if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY) {
+ out_device = AUDIO_DEVICE_OUT_TELEPHONY_TX;
+ } else if (adev->primary_output) {
+ out_device = adev->primary_output->devices;
+ }
}
in_snd_device = platform_get_input_snd_device(adev->platform, out_device);
}
@@ -673,6 +680,9 @@ int select_devices(struct audio_device *adev,
(usecase->in_snd_device != SND_DEVICE_NONE) &&
(usecase->out_snd_device != SND_DEVICE_NONE)) {
status = platform_switch_voice_call_device_pre(adev->platform);
+ /* Disable sidetone only if voice call already exists */
+ if (voice_is_call_state_active(adev))
+ voice_set_sidetone(adev, usecase->out_snd_device, false);
}
/* Disable current sound devices */
@@ -724,10 +734,14 @@ int select_devices(struct audio_device *adev,
* Enable device command should be sent to modem only after
* enabling voice call mixer controls
*/
- if (usecase->type == VOICE_CALL)
+ if (usecase->type == VOICE_CALL) {
status = platform_switch_voice_call_usecase_route_post(adev->platform,
out_snd_device,
in_snd_device);
+ /* Enable sidetone only if voice call already exists */
+ if (voice_is_call_state_active(adev))
+ voice_set_sidetone(adev, out_snd_device, true);
+ }
return status;
}
@@ -788,6 +802,9 @@ int start_input_stream(struct stream_in *in)
uc_info->out_snd_device = SND_DEVICE_NONE;
list_add_tail(&adev->usecase_list, &uc_info->list);
+
+ audio_extn_perf_lock_acquire();
+
select_devices(adev, in->usecase);
ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
@@ -820,11 +837,18 @@ int start_input_stream(struct stream_in *in)
break;
}
+ ALOGV("%s: pcm_prepare start", __func__);
+ pcm_prepare(in->pcm);
+
+ audio_extn_perf_lock_release();
+
ALOGV("%s: exit", __func__);
+
return ret;
error_open:
stop_input_stream(in);
+ audio_extn_perf_lock_release();
error_config:
adev->active_input = NULL;
@@ -833,6 +857,20 @@ error_config:
return ret;
}
+void lock_input_stream(struct stream_in *in)
+{
+ pthread_mutex_lock(&in->pre_lock);
+ pthread_mutex_lock(&in->lock);
+ pthread_mutex_unlock(&in->pre_lock);
+}
+
+void lock_output_stream(struct stream_out *out)
+{
+ pthread_mutex_lock(&out->pre_lock);
+ pthread_mutex_lock(&out->lock);
+ pthread_mutex_unlock(&out->pre_lock);
+}
+
/* must be called with out->lock locked */
static int send_offload_cmd_l(struct stream_out* out, int command)
{
@@ -873,7 +911,7 @@ static void *offload_thread_loop(void *context)
prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
ALOGV("%s", __func__);
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
for (;;) {
struct offload_cmd *cmd = NULL;
stream_callback_event_t event;
@@ -932,7 +970,7 @@ static void *offload_thread_loop(void *context)
ALOGE("%s unknown command received: %d", __func__, cmd->cmd);
break;
}
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
out->offload_thread_blocked = false;
pthread_cond_signal(&out->cond);
if (send_callback) {
@@ -964,7 +1002,7 @@ static int create_offload_callback_thread(struct stream_out *out)
static int destroy_offload_callback_thread(struct stream_out *out)
{
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
stop_compressed_output_l(out);
send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
@@ -1123,6 +1161,8 @@ int start_output_stream(struct stream_out *out)
list_add_tail(&adev->usecase_list, &uc_info->list);
+ audio_extn_perf_lock_acquire();
+
select_devices(adev, out->usecase);
audio_extn_extspk_update(adev->extspk);
@@ -1156,6 +1196,10 @@ int start_output_stream(struct stream_out *out)
}
break;
}
+ ALOGV("%s: pcm_prepare start", __func__);
+ if (pcm_is_ready(out->pcm))
+ pcm_prepare(out->pcm);
+
} else {
out->pcm = NULL;
out->compr = compress_open(adev->snd_card, out->pcm_device_id,
@@ -1175,9 +1219,11 @@ int start_output_stream(struct stream_out *out)
if (adev->offload_effects_start_output != NULL)
adev->offload_effects_start_output(out->handle, out->pcm_device_id);
}
+ audio_extn_perf_lock_release();
ALOGV("%s: exit", __func__);
return 0;
error_open:
+ audio_extn_perf_lock_release();
stop_output_stream(out);
error_config:
return ret;
@@ -1187,9 +1233,16 @@ static int check_input_parameters(uint32_t sample_rate,
audio_format_t format,
int channel_count)
{
- if (format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL;
+ if (format != AUDIO_FORMAT_PCM_16_BIT) {
+ ALOGE("%s: unsupported AUDIO FORMAT (%d) ", __func__, format);
+ return -EINVAL;
+ }
- if ((channel_count < 1) || (channel_count > 2)) return -EINVAL;
+ if ((channel_count < MIN_CHANNEL_COUNT) || (channel_count > MAX_CHANNEL_COUNT)) {
+ ALOGE("%s: unsupported channel count (%d) passed Min / Max (%d\%d)", __func__,
+ channel_count, MIN_CHANNEL_COUNT, MAX_CHANNEL_COUNT);
+ return -EINVAL;
+ }
switch (sample_rate) {
case 8000:
@@ -1203,6 +1256,7 @@ static int check_input_parameters(uint32_t sample_rate,
case 48000:
break;
default:
+ ALOGE("%s: unsupported (%d) samplerate passed ", __func__, sample_rate);
return -EINVAL;
}
@@ -1287,8 +1341,11 @@ static int out_standby(struct audio_stream *stream)
ALOGV("%s: enter: usecase(%d: %s)", __func__,
out->usecase, use_case_table[out->usecase]);
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
if (!out->standby) {
+ if (adev->adm_deregister_stream)
+ adev->adm_deregister_stream(adev->adm_data, out->handle);
+
pthread_mutex_lock(&adev->lock);
out->standby = true;
if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) {
@@ -1373,7 +1430,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
if (ret >= 0) {
val = atoi(value);
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
pthread_mutex_lock(&adev->lock);
/*
@@ -1537,7 +1594,7 @@ static ssize_t out_write_for_no_output(struct audio_stream_out *stream,
/* No Output device supported other than BT for playback.
* Sleep for the amount of buffer duration
*/
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
usleep(bytes * 1000000 / audio_stream_frame_size(&out->stream.common) /
out_get_sample_rate(&out->stream.common));
pthread_mutex_unlock(&out->lock);
@@ -1552,7 +1609,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
struct audio_device *adev = out->dev;
ssize_t ret = 0;
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
if (out->standby) {
out->standby = false;
pthread_mutex_lock(&adev->lock);
@@ -1563,6 +1620,8 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
out->standby = true;
goto exit;
}
+ if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD && adev->adm_register_output_stream)
+ adev->adm_register_output_stream(adev->adm_data, out->handle, out->flags);
}
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
@@ -1589,14 +1648,22 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
if (out->pcm) {
if (out->muted)
memset((void *)buffer, 0, bytes);
+
ALOGVV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes);
+ if (adev->adm_request_focus)
+ adev->adm_request_focus(adev->adm_data, out->handle);
+
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)
out->written += bytes / (out->config.channels * sizeof(short));
+
+ if (adev->adm_abandon_focus)
+ adev->adm_abandon_focus(adev->adm_data, out->handle);
}
}
@@ -1619,7 +1686,7 @@ static int out_get_render_position(const struct audio_stream_out *stream,
struct stream_out *out = (struct stream_out *)stream;
*dsp_frames = 0;
if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) {
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
if (out->compr != NULL) {
compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
&out->sample_rate);
@@ -1657,7 +1724,7 @@ static int out_get_presentation_position(const struct audio_stream_out *stream,
int ret = -1;
unsigned long dsp_frames;
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
if (out->compr != NULL) {
@@ -1701,7 +1768,7 @@ static int out_set_callback(struct audio_stream_out *stream,
struct stream_out *out = (struct stream_out *)stream;
ALOGV("%s", __func__);
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
out->offload_callback = callback;
out->offload_cookie = cookie;
pthread_mutex_unlock(&out->lock);
@@ -1714,7 +1781,7 @@ static int out_pause(struct audio_stream_out* stream)
int status = -ENOSYS;
ALOGV("%s", __func__);
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
status = compress_pause(out->compr);
out->offload_state = OFFLOAD_STATE_PAUSED;
@@ -1731,7 +1798,7 @@ static int out_resume(struct audio_stream_out* stream)
ALOGV("%s", __func__);
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
status = 0;
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) {
status = compress_resume(out->compr);
out->offload_state = OFFLOAD_STATE_PLAYING;
@@ -1747,7 +1814,7 @@ static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type )
int status = -ENOSYS;
ALOGV("%s", __func__);
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
if (type == AUDIO_DRAIN_EARLY_NOTIFY)
status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN);
else
@@ -1762,7 +1829,7 @@ static int out_flush(struct audio_stream_out* stream)
struct stream_out *out = (struct stream_out *)stream;
ALOGV("%s", __func__);
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
stop_compressed_output_l(out);
pthread_mutex_unlock(&out->lock);
return 0;
@@ -1814,7 +1881,8 @@ static int in_standby(struct audio_stream *stream)
struct audio_device *adev = in->dev;
int status = 0;
ALOGV("%s: enter", __func__);
- pthread_mutex_lock(&in->lock);
+
+ lock_input_stream(in);
if (!in->standby && in->is_st_session) {
ALOGD("%s: sound trigger pcm stop lab", __func__);
@@ -1823,6 +1891,9 @@ static int in_standby(struct audio_stream *stream)
}
if (!in->standby) {
+ if (adev->adm_deregister_stream)
+ adev->adm_deregister_stream(adev->adm_data, in->capture_handle);
+
pthread_mutex_lock(&adev->lock);
in->standby = true;
if (in->pcm) {
@@ -1859,7 +1930,8 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value));
- pthread_mutex_lock(&in->lock);
+ lock_input_stream(in);
+
pthread_mutex_lock(&adev->lock);
if (ret >= 0) {
val = atoi(value);
@@ -1907,7 +1979,8 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
struct audio_device *adev = in->dev;
int i, ret = -1;
- pthread_mutex_lock(&in->lock);
+ lock_input_stream(in);
+
if (in->is_st_session) {
ALOGVV(" %s: reading on st session bytes=%d", __func__, bytes);
/* Read from sound trigger HAL */
@@ -1924,8 +1997,13 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
goto exit;
}
in->standby = 0;
+ if (adev->adm_register_input_stream)
+ adev->adm_register_input_stream(adev->adm_data, in->capture_handle, in->flags);
}
+ if (adev->adm_request_focus)
+ adev->adm_request_focus(adev->adm_data, in->capture_handle);
+
if (in->pcm) {
if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) {
ret = pcm_mmap_read(in->pcm, buffer, bytes);
@@ -1933,6 +2011,9 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
ret = pcm_read(in->pcm, buffer, bytes);
}
+ if (adev->adm_abandon_focus)
+ adev->adm_abandon_focus(adev->adm_data, in->capture_handle);
+
/*
* Instead of writing zeroes here, we could trust the hardware
* to always provide zeroes when muted.
@@ -1971,7 +2052,7 @@ static int add_remove_audio_effect(const struct audio_stream *stream,
if (status != 0)
return status;
- pthread_mutex_lock(&in->lock);
+ lock_input_stream(in);
pthread_mutex_lock(&in->dev->lock);
if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
in->enable_aec != enable &&
@@ -2147,6 +2228,9 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
} else if (out->flags & AUDIO_OUTPUT_FLAG_TTS) {
out->usecase = USECASE_AUDIO_PLAYBACK_TTS;
out->config = pcm_config_deep_buffer;
+ } else if (out->flags & AUDIO_OUTPUT_FLAG_RAW) {
+ out->usecase = USECASE_AUDIO_PLAYBACK_ULL;
+ out->config = pcm_config_low_latency;
} else {
out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
out->config = pcm_config_low_latency;
@@ -2219,6 +2303,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
/* out->written = 0; by calloc() */
pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
+ pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL);
pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL);
config->format = out->stream.common.get_format(&out->stream.common);
@@ -2466,6 +2551,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev,
in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
+ pthread_mutex_init(&in->pre_lock, (const pthread_mutexattr_t *) NULL);
in->stream.common.get_sample_rate = in_get_sample_rate;
in->stream.common.set_sample_rate = in_set_sample_rate;
@@ -2489,6 +2575,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev,
in->standby = 1;
in->channel_mask = config->channel_mask;
in->capture_handle = handle;
+ in->flags = flags;
/* Update config params with the requested sample rate and channels */
if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
@@ -2714,10 +2801,13 @@ static int adev_close(hw_device_t *device)
for (i = 0; i < ARRAY_SIZE(adev->use_case_table); ++i) {
pcm_params_free(adev->use_case_table[i]);
}
+ if (adev->adm_deinit)
+ adev->adm_deinit(adev->adm_data);
free(device);
}
pthread_mutex_unlock(&adev_init_lock);
+
return 0;
}
@@ -2844,6 +2934,29 @@ static int adev_open(const hw_module_t *module, const char *name,
}
}
+ if (access(ADM_LIBRARY_PATH, R_OK) == 0) {
+ adev->adm_lib = dlopen(ADM_LIBRARY_PATH, RTLD_NOW);
+ if (adev->adm_lib == NULL) {
+ ALOGE("%s: DLOPEN failed for %s", __func__, ADM_LIBRARY_PATH);
+ } else {
+ ALOGV("%s: DLOPEN successful for %s", __func__, ADM_LIBRARY_PATH);
+ adev->adm_init = (adm_init_t)
+ dlsym(adev->adm_lib, "adm_init");
+ adev->adm_deinit = (adm_deinit_t)
+ dlsym(adev->adm_lib, "adm_deinit");
+ adev->adm_register_input_stream = (adm_register_input_stream_t)
+ dlsym(adev->adm_lib, "adm_register_input_stream");
+ adev->adm_register_output_stream = (adm_register_output_stream_t)
+ dlsym(adev->adm_lib, "adm_register_output_stream");
+ adev->adm_deregister_stream = (adm_deregister_stream_t)
+ dlsym(adev->adm_lib, "adm_deregister_stream");
+ adev->adm_request_focus = (adm_request_focus_t)
+ dlsym(adev->adm_lib, "adm_request_focus");
+ adev->adm_abandon_focus = (adm_abandon_focus_t)
+ dlsym(adev->adm_lib, "adm_abandon_focus");
+ }
+ }
+
adev->bt_wb_speech_enabled = false;
adev->enable_voicerx = false;
@@ -2873,6 +2986,11 @@ static int adev_open(const hw_module_t *module, const char *name,
audio_device_ref_count++;
pthread_mutex_unlock(&adev_init_lock);
+ if (adev->adm_init)
+ adev->adm_data = adev->adm_init();
+
+ audio_extn_perf_lock_init();
+
ALOGV("%s: exit", __func__);
return 0;
}
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index b4b2583e..b82ee8b1 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -29,6 +29,7 @@
#define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so"
#define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/system/lib/soundfx/libqcompostprocbundle.so"
+#define ADM_LIBRARY_PATH "/system/vendor/lib/libadm.so"
/* Flags used to initialize acdb_settings variable that goes to ACDB library */
#define DMIC_FLAG 0x00000002
@@ -58,6 +59,7 @@ enum {
USECASE_AUDIO_PLAYBACK_MULTI_CH,
USECASE_AUDIO_PLAYBACK_OFFLOAD,
USECASE_AUDIO_PLAYBACK_TTS,
+ USECASE_AUDIO_PLAYBACK_ULL,
/* HFP Use case*/
USECASE_AUDIO_HFP_SCO,
@@ -123,6 +125,7 @@ struct offload_cmd {
struct stream_out {
struct audio_stream_out stream;
pthread_mutex_t lock; /* see note below on mutex acquisition order */
+ pthread_mutex_t pre_lock; /* acquire before lock to avoid DOS by playback thread */
pthread_cond_t cond;
struct pcm_config config;
struct compr_config compr_config;
@@ -161,6 +164,7 @@ struct stream_out {
struct stream_in {
struct audio_stream_in stream;
pthread_mutex_t lock; /* see note below on mutex acquisition order */
+ pthread_mutex_t pre_lock; /* acquire before lock to avoid DOS by capture thread */
struct pcm_config config;
struct pcm *pcm;
int standby;
@@ -173,6 +177,7 @@ struct stream_in {
bool enable_ns;
audio_io_handle_t capture_handle;
+ audio_input_flags_t flags;
bool is_st_session;
bool is_st_session_active;
@@ -201,6 +206,14 @@ struct audio_usecase {
union stream_ptr stream;
};
+typedef void* (*adm_init_t)();
+typedef void (*adm_deinit_t)(void *);
+typedef void (*adm_register_output_stream_t)(void *, audio_io_handle_t, audio_output_flags_t);
+typedef void (*adm_register_input_stream_t)(void *, audio_io_handle_t, audio_input_flags_t);
+typedef void (*adm_deregister_stream_t)(void *, audio_io_handle_t);
+typedef void (*adm_request_focus_t)(void *, audio_io_handle_t);
+typedef void (*adm_abandon_focus_t)(void *, audio_io_handle_t);
+
struct audio_device {
struct audio_hw_device device;
pthread_mutex_t lock; /* see note below on mutex acquisition order */
@@ -240,6 +253,16 @@ struct audio_device {
void *offload_effects_lib;
int (*offload_effects_start_output)(audio_io_handle_t, int);
int (*offload_effects_stop_output)(audio_io_handle_t, int);
+
+ void *adm_data;
+ void *adm_lib;
+ adm_init_t adm_init;
+ adm_deinit_t adm_deinit;
+ adm_register_input_stream_t adm_register_input_stream;
+ adm_register_output_stream_t adm_register_output_stream;
+ adm_deregister_stream_t adm_deregister_stream;
+ adm_request_focus_t adm_request_focus;
+ adm_abandon_focus_t adm_abandon_focus;
};
int select_devices(struct audio_device *adev,
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 2f596bac..c78d9434 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -126,6 +126,8 @@ static const char * const device_table[SND_DEVICE_MAX] = {
[SND_DEVICE_OUT_BT_SCO] = "bt-sco-headset",
[SND_DEVICE_OUT_BT_SCO_WB] = "bt-sco-headset-wb",
[SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = "voice-handset-tmus",
+ [SND_DEVICE_OUT_VOICE_HANDSET] = "voice-handset-tmus",
+ [SND_DEVICE_OUT_VOICE_HAC_HANDSET] = "voice-handset-tmus",
[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",
@@ -173,6 +175,8 @@ static const int acdb_device_table[SND_DEVICE_MAX] = {
[SND_DEVICE_OUT_BT_SCO] = 22,
[SND_DEVICE_OUT_BT_SCO_WB] = 39,
[SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = 81,
+ [SND_DEVICE_OUT_VOICE_HANDSET] = 81,
+ [SND_DEVICE_OUT_VOICE_HAC_HANDSET] = 81,
[SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37,
@@ -423,6 +427,13 @@ int platform_get_snd_device_acdb_id(snd_device_t snd_device __unused)
return -ENOSYS;
}
+void platform_add_operator_specific_device(snd_device_t snd_device __unused,
+ const char *operator __unused,
+ const char *mixer_path __unused,
+ unsigned int acdb_id __unused)
+{
+}
+
int platform_send_audio_calibration(void *platform, snd_device_t snd_device)
{
struct platform_data *my_data = (struct platform_data *)platform;
@@ -540,6 +551,11 @@ int platform_stop_voice_call(void *platform, uint32_t vsid __unused)
return ret;
}
+void platform_set_speaker_gain_in_combo(struct audio_device *adev __unused,
+ snd_device_t snd_device __unused,
+ bool enable __unused) {
+}
+
int platform_set_voice_volume(void *platform, int volume)
{
struct platform_data *my_data = (struct platform_data *)platform;
diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h
index 02017723..b879c0b4 100644
--- a/hal/msm8960/platform.h
+++ b/hal/msm8960/platform.h
@@ -48,6 +48,8 @@ enum {
SND_DEVICE_OUT_BT_SCO,
SND_DEVICE_OUT_BT_SCO_WB,
SND_DEVICE_OUT_VOICE_HANDSET_TMUS,
+ SND_DEVICE_OUT_VOICE_HANDSET,
+ SND_DEVICE_OUT_VOICE_HAC_HANDSET,
SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET,
@@ -92,7 +94,7 @@ enum {
#define MIXER_CARD 0
#define SOUND_CARD 0
-
+#define MIXER_PATH_MAX_LENGTH 100
#define DEFAULT_OUTPUT_SAMPLING_RATE 48000
/*
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 03aa5967..66da2498 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#define LOG_TAG "msm8974_platform"
/*#define LOG_NDEBUG 0*/
#define LOG_NDDEBUG 0
@@ -34,9 +33,6 @@
#define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID"
#define CVD_VERSION_MIXER_CTL "CVD Version"
-#define DUALMIC_CONFIG_NONE 0 /* Target does not contain 2 mics */
-#define DUALMIC_CONFIG_ENDFIRE 1
-#define DUALMIC_CONFIG_BROADSIDE 2
/*
* This file will have a maximum of 38 bytes:
@@ -62,6 +58,9 @@
#define DEFAULT_APP_TYPE_RX_PATH 0x11130
+#define TOSTRING_(x) #x
+#define TOSTRING(x) TOSTRING_(x)
+
struct audio_block_header
{
int reserved;
@@ -74,6 +73,24 @@ enum {
CAL_MODE_RTAC = 0x4
};
+#define PLATFORM_CONFIG_KEY_OPERATOR_INFO "operator_info"
+
+struct operator_info {
+ struct listnode list;
+ char *name;
+ char *mccmnc;
+};
+
+struct operator_specific_device {
+ struct listnode list;
+ char *operator;
+ char *mixer_path;
+ int acdb_id;
+};
+
+static struct listnode operator_info_list;
+static struct listnode *operator_specific_device_table[SND_DEVICE_MAX];
+
/* Audio calibration related functions */
typedef void (*acdb_deallocate_t)();
typedef int (*acdb_init_v2_cvd_t)(char *, char *);
@@ -91,7 +108,9 @@ struct platform_data {
bool fluence_in_voice_call;
bool fluence_in_voice_comm;
bool fluence_in_voice_rec;
- int dualmic_config;
+ /* 0 = no fluence, 1 = fluence, 2 = fluence pro */
+ int fluence_type;
+ int source_mic_type;
bool speaker_lr_swap;
void *acdb_handle;
@@ -104,6 +123,8 @@ struct platform_data {
char ec_ref_mixer_path[64];
char *snd_card_name;
+ int max_vol_index;
+ int max_mic_count;
};
static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
@@ -115,12 +136,16 @@ static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
MULTIMEDIA2_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_OFFLOAD] = {PLAYBACK_OFFLOAD_DEVICE,
PLAYBACK_OFFLOAD_DEVICE},
- [USECASE_AUDIO_PLAYBACK_TTS] = {MULTIMEDIA3_PCM_DEVICE,
- MULTIMEDIA3_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_TTS] = {MULTIMEDIA2_PCM_DEVICE,
+ MULTIMEDIA2_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_ULL] = {MULTIMEDIA3_PCM_DEVICE,
+ MULTIMEDIA3_PCM_DEVICE},
+
[USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE,
AUDIO_RECORD_PCM_DEVICE},
[USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
LOWLATENCY_PCM_DEVICE},
+
[USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE,
VOICE_CALL_PCM_DEVICE},
[USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE},
@@ -221,10 +246,15 @@ static const char * const device_table[SND_DEVICE_MAX] = {
[SND_DEVICE_IN_VOICE_REC_MIC_NS] = "voice-rec-mic",
[SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = "voice-rec-dmic-ef",
[SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence",
+ [SND_DEVICE_IN_VOICE_REC_HEADSET_MIC] = "headset-mic",
[SND_DEVICE_IN_VOICE_RX] = "voice-rx",
+ [SND_DEVICE_IN_THREE_MIC] = "three-mic",
+ [SND_DEVICE_IN_QUAD_MIC] = "quad-mic",
[SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = "vi-feedback",
+ [SND_DEVICE_IN_HANDSET_TMIC] = "three-mic",
+ [SND_DEVICE_IN_HANDSET_QMIC] = "quad-mic",
};
/* ACDB IDs (audio DSP path configuration IDs) for each sound device */
@@ -300,10 +330,15 @@ static int acdb_device_table[SND_DEVICE_MAX] = {
[SND_DEVICE_IN_VOICE_REC_MIC_NS] = 113,
[SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = 35,
[SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 43,
+ [SND_DEVICE_IN_VOICE_REC_HEADSET_MIC] = 8,
[SND_DEVICE_IN_VOICE_RX] = 44,
+ [SND_DEVICE_IN_THREE_MIC] = 46,
+ [SND_DEVICE_IN_QUAD_MIC] = 46,
[SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = 102,
+ [SND_DEVICE_IN_HANDSET_TMIC] = 125,
+ [SND_DEVICE_IN_HANDSET_QMIC] = 125,
};
struct name_to_index {
@@ -386,8 +421,13 @@ static const struct name_to_index snd_device_name_index[SND_DEVICE_MAX] = {
{TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_MIC_NS)},
{TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_DMIC_STEREO)},
{TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_HEADSET_MIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_THREE_MIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_QUAD_MIC)},
{TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_TMIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_QMIC)},
};
static char * backend_tag_table[SND_DEVICE_MAX] = {0};
@@ -398,6 +438,8 @@ static const struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = {
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_LOW_LATENCY)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MULTI_CH)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_TTS)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_ULL)},
{TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
{TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)},
{TO_NAME_INDEX(USECASE_VOICE_CALL)},
@@ -453,6 +495,71 @@ bool is_operator_tmus()
return is_tmus;
}
+static char *get_current_operator()
+{
+ struct listnode *node;
+ struct operator_info *info_item;
+ char mccmnc[PROPERTY_VALUE_MAX];
+ char *ret = NULL;
+
+ property_get("gsm.sim.operator.numeric",mccmnc,"0");
+
+ list_for_each(node, &operator_info_list) {
+ info_item = node_to_item(node, struct operator_info, list);
+ if (strstr(info_item->mccmnc, mccmnc) != NULL) {
+ ret = info_item->name;
+ }
+ }
+
+ return ret;
+}
+
+static struct operator_specific_device *get_operator_specific_device(snd_device_t snd_device)
+{
+ struct listnode *node;
+ struct operator_specific_device *ret = NULL;
+ struct operator_specific_device *device_item;
+ char *operator_name;
+
+ operator_name = get_current_operator();
+ if (operator_name == NULL)
+ return ret;
+
+ list_for_each(node, operator_specific_device_table[snd_device]) {
+ device_item = node_to_item(node, struct operator_specific_device, list);
+ if (strcmp(operator_name, device_item->operator) == 0) {
+ ret = device_item;
+ }
+ }
+
+ return ret;
+}
+
+
+static int get_operator_specific_device_acdb_id(snd_device_t snd_device)
+{
+ struct operator_specific_device *device;
+ int ret = acdb_device_table[snd_device];
+
+ device = get_operator_specific_device(snd_device);
+ if (device != NULL)
+ ret = device->acdb_id;
+
+ return ret;
+}
+
+static const char *get_operator_specific_device_mixer_path(snd_device_t snd_device)
+{
+ struct operator_specific_device *device;
+ const char *ret = device_table[snd_device];
+
+ device = get_operator_specific_device(snd_device);
+ if (device != NULL)
+ ret = device->mixer_path;
+
+ return ret;
+}
+
bool platform_send_gain_dep_cal(void *platform, int level)
{
bool ret_val = false;
@@ -712,12 +819,13 @@ done:
#endif
}
-static void set_platform_defaults(struct platform_data * my_data __unused)
+static void set_platform_defaults(struct platform_data * my_data)
{
int32_t dev;
for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
backend_tag_table[dev] = NULL;
hw_interface_table[dev] = NULL;
+ operator_specific_device_table[dev] = NULL;
}
// To overwrite these go to the audio_platform_info.xml file.
@@ -758,6 +866,8 @@ static void set_platform_defaults(struct platform_data * my_data __unused)
hw_interface_table[SND_DEVICE_OUT_VOICE_TX] = strdup("AFE_PCM_RX");
hw_interface_table[SND_DEVICE_OUT_SPEAKER_PROTECTED] = strdup("SLIMBUS_0_RX");
hw_interface_table[SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = strdup("SLIMBUS_0_RX");
+
+ my_data->max_mic_count = PLATFORM_DEFAULT_MIC_COUNT;
}
void get_cvd_version(char *cvd_version, struct audio_device *adev)
@@ -792,6 +902,7 @@ void *platform_init(struct audio_device *adev)
char value[PROPERTY_VALUE_MAX];
struct platform_data *my_data;
int retry_num = 0, snd_card_num = 0;
+ bool dual_mic_config = false;
const char *snd_card_name;
char *cvd_version = NULL;
@@ -799,6 +910,8 @@ void *platform_init(struct audio_device *adev)
my_data->adev = adev;
+ list_init(&operator_info_list);
+
set_platform_defaults(my_data);
/* Initialize platform specific ids and/or backends*/
@@ -850,20 +963,32 @@ void *platform_init(struct audio_device *adev)
goto init_failed;
}
- my_data->dualmic_config = DUALMIC_CONFIG_NONE;
+ //set max volume step for voice call
+ property_get("ro.config.vc_call_vol_steps", value, TOSTRING(MAX_VOL_INDEX));
+ my_data->max_vol_index = atoi(value);
+
+ property_get("persist.audio.dualmic.config",value,"");
+ if (!strcmp("endfire", value)) {
+ dual_mic_config = true;
+ }
+
+ my_data->source_mic_type = SOURCE_DUAL_MIC;
+
my_data->fluence_in_spkr_mode = false;
my_data->fluence_in_voice_call = false;
my_data->fluence_in_voice_comm = false;
my_data->fluence_in_voice_rec = false;
- property_get("persist.audio.dualmic.config",value,"");
- if (!strcmp("broadside", value)) {
- ALOGE("%s: Unsupported dualmic configuration", __func__);
- } else if (!strcmp("endfire", value)) {
- my_data->dualmic_config = DUALMIC_CONFIG_ENDFIRE;
+ property_get("ro.qc.sdk.audio.fluencetype", value, "none");
+ if (!strcmp("fluencepro", value)) {
+ my_data->fluence_type = FLUENCE_PRO_ENABLE;
+ } else if (!strcmp("fluence", value) || (dual_mic_config)) {
+ my_data->fluence_type = FLUENCE_ENABLE;
+ } else if (!strcmp("none", value)) {
+ my_data->fluence_type = FLUENCE_DISABLE;
}
- if (my_data->dualmic_config != DUALMIC_CONFIG_NONE) {
+ if (my_data->fluence_type != FLUENCE_DISABLE) {
property_get("persist.audio.fluence.voicecall",value,"");
if (!strcmp("true", value)) {
my_data->fluence_in_voice_call = true;
@@ -885,6 +1010,30 @@ void *platform_init(struct audio_device *adev)
}
}
+ // support max to mono, example if max count is 3, usecase supports Three, dual and mono mic
+ switch (my_data->max_mic_count) {
+ case 4:
+ my_data->source_mic_type |= SOURCE_QUAD_MIC;
+ case 3:
+ my_data->source_mic_type |= SOURCE_THREE_MIC;
+ case 2:
+ my_data->source_mic_type |= SOURCE_DUAL_MIC;
+ case 1:
+ my_data->source_mic_type |= SOURCE_MONO_MIC;
+ break;
+ default:
+ ALOGE("%s: max_mic_count (%d), is not supported, setting to default",
+ __func__, my_data->max_mic_count);
+ my_data->source_mic_type = SOURCE_MONO_MIC|SOURCE_DUAL_MIC;
+ break;
+ }
+
+ ALOGV("%s: Fluence_Type(%d) max_mic_count(%d) mic_type(0x%x) fluence_in_voice_call(%d)"
+ " fluence_in_voice_comm(%d) fluence_in_voice_rec(%d) fluence_in_spkr_mode(%d) ",
+ __func__, my_data->fluence_type, my_data->max_mic_count, my_data->source_mic_type,
+ my_data->fluence_in_voice_call, my_data->fluence_in_voice_comm,
+ my_data->fluence_in_voice_rec, my_data->fluence_in_spkr_mode);
+
my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
if (my_data->acdb_handle == NULL) {
ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER);
@@ -976,6 +1125,9 @@ init_failed:
void platform_deinit(void *platform)
{
int32_t dev;
+ struct operator_info *info_item;
+ struct operator_specific_device *device_item;
+ struct listnode *node;
struct platform_data *my_data = (struct platform_data *)platform;
close_csd_client(my_data->csd);
@@ -985,19 +1137,42 @@ void platform_deinit(void *platform)
free(backend_tag_table[dev]);
if (hw_interface_table[dev])
free(hw_interface_table[dev]);
+ if (operator_specific_device_table[dev]) {
+ while (!list_empty(operator_specific_device_table[dev])) {
+ node = list_head(operator_specific_device_table[dev]);
+ list_remove(node);
+ device_item = node_to_item(node, struct operator_specific_device, list);
+ free(device_item->operator);
+ free(device_item->mixer_path);
+ free(device_item);
+ }
+ free(operator_specific_device_table[dev]);
+ }
}
if (my_data->snd_card_name)
free(my_data->snd_card_name);
+ while (!list_empty(&operator_info_list)) {
+ node = list_head(&operator_info_list);
+ list_remove(node);
+ info_item = node_to_item(node, struct operator_info, list);
+ free(info_item->name);
+ free(info_item->mccmnc);
+ free(info_item);
+ }
+
free(platform);
}
const char *platform_get_snd_device_name(snd_device_t snd_device)
{
- if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX)
+ if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) {
+ if (operator_specific_device_table[snd_device] != NULL) {
+ return get_operator_specific_device_mixer_path(snd_device);
+ }
return device_table[snd_device];
- else
+ } else
return "none";
}
@@ -1041,7 +1216,7 @@ bool platform_check_backends_match(snd_device_t snd_device1, snd_device_t snd_de
const char * be_itf2 = hw_interface_table[snd_device2];
if (NULL != be_itf1 && NULL != be_itf2) {
- if (0 != strcmp(be_itf1, be_itf2))
+ if ((NULL == strstr(be_itf2, be_itf1)) && (NULL == strstr(be_itf1, be_itf2)))
result = false;
}
@@ -1100,6 +1275,32 @@ int platform_get_usecase_index(const char *usecase_name)
return find_index(usecase_name_index, AUDIO_USECASE_MAX, usecase_name);
}
+void platform_add_operator_specific_device(snd_device_t snd_device,
+ const char *operator,
+ const char *mixer_path,
+ unsigned int acdb_id)
+{
+ struct operator_specific_device *device;
+
+ if (operator_specific_device_table[snd_device] == NULL) {
+ operator_specific_device_table[snd_device] =
+ (struct listnode *)calloc(1, sizeof(struct listnode));
+ list_init(operator_specific_device_table[snd_device]);
+ }
+
+ device = (struct operator_specific_device *)calloc(1, sizeof(struct operator_specific_device));
+
+ device->operator = strdup(operator);
+ device->mixer_path = strdup(mixer_path);
+ device->acdb_id = acdb_id;
+
+ list_add_tail(operator_specific_device_table[snd_device], &device->list);
+
+ ALOGD("%s : deivce[%s] -> operator[%s] mixer_path[%s] acdb_id [%d]", __func__,
+ platform_get_snd_device_name(snd_device), operator, mixer_path, acdb_id);
+
+}
+
int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id)
{
int ret = 0;
@@ -1124,7 +1325,11 @@ int platform_get_snd_device_acdb_id(snd_device_t snd_device)
ALOGE("%s: Invalid snd_device = %d", __func__, snd_device);
return -EINVAL;
}
- return acdb_device_table[snd_device];
+
+ if (operator_specific_device_table[snd_device] != NULL)
+ return get_operator_specific_device_acdb_id(snd_device);
+ else
+ return acdb_device_table[snd_device];
}
int platform_send_audio_calibration(void *platform, snd_device_t snd_device)
@@ -1181,11 +1386,11 @@ int platform_switch_voice_call_enable_device_config(void *platform,
if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER &&
audio_extn_spkr_prot_is_enabled())
- acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED];
+ acdb_rx_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_SPEAKER_PROTECTED);
else
- acdb_rx_id = acdb_device_table[out_snd_device];
+ acdb_rx_id = platform_get_snd_device_acdb_id(out_snd_device);
- acdb_tx_id = acdb_device_table[in_snd_device];
+ acdb_tx_id = platform_get_snd_device_acdb_id(in_snd_device);
if (acdb_rx_id > 0 && acdb_tx_id > 0) {
ret = my_data->csd->enable_device_config(acdb_rx_id, acdb_tx_id);
@@ -1215,8 +1420,8 @@ int platform_switch_voice_call_device_post(void *platform,
audio_extn_spkr_prot_is_enabled())
out_snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED;
- acdb_rx_id = acdb_device_table[out_snd_device];
- acdb_tx_id = acdb_device_table[in_snd_device];
+ acdb_rx_id = platform_get_snd_device_acdb_id(out_snd_device);
+ acdb_tx_id = platform_get_snd_device_acdb_id(in_snd_device);
if (acdb_rx_id > 0 && acdb_tx_id > 0)
my_data->acdb_send_voice_cal(acdb_rx_id, acdb_tx_id);
@@ -1241,11 +1446,11 @@ int platform_switch_voice_call_usecase_route_post(void *platform,
if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER &&
audio_extn_spkr_prot_is_enabled())
- acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED];
+ acdb_rx_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED);
else
- acdb_rx_id = acdb_device_table[out_snd_device];
+ acdb_rx_id = platform_get_snd_device_acdb_id(out_snd_device);
- acdb_tx_id = acdb_device_table[in_snd_device];
+ acdb_tx_id = platform_get_snd_device_acdb_id(in_snd_device);
if (acdb_rx_id > 0 && acdb_tx_id > 0) {
ret = my_data->csd->enable_device(acdb_rx_id, acdb_tx_id,
@@ -1303,6 +1508,43 @@ int platform_get_sample_rate(void *platform, uint32_t *rate)
return ret;
}
+void platform_set_speaker_gain_in_combo(struct audio_device *adev,
+ snd_device_t snd_device,
+ bool enable)
+{
+ const char* name;
+ switch (snd_device) {
+ case SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES:
+ if (enable)
+ name = "spkr-gain-in-headphone-combo";
+ else
+ name = "speaker-gain-default";
+ break;
+ case SND_DEVICE_OUT_SPEAKER_AND_LINE:
+ if (enable)
+ name = "spkr-gain-in-line-combo";
+ else
+ name = "speaker-gain-default";
+ break;
+ case SND_DEVICE_OUT_SPEAKER_SAFE_AND_HEADPHONES:
+ if (enable)
+ name = "spkr-safe-gain-in-headphone-combo";
+ else
+ name = "speaker-safe-gain-default";
+ break;
+ case SND_DEVICE_OUT_SPEAKER_SAFE_AND_LINE:
+ if (enable)
+ name = "spkr-safe-gain-in-line-combo";
+ else
+ name = "speaker-safe-gain-default";
+ break;
+ default:
+ return;
+ }
+
+ audio_route_apply_and_update_path(adev->audio_route, name);
+}
+
int platform_set_voice_volume(void *platform, int volume)
{
struct platform_data *my_data = (struct platform_data *)platform;
@@ -1317,7 +1559,7 @@ int platform_set_voice_volume(void *platform, int volume)
// Voice volume levels are mapped to adsp volume levels as follows.
// 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1 0 -> 0
// But this values don't changed in kernel. So, below change is need.
- vol_index = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX);
+ vol_index = (int)percent_to_index(volume, MIN_VOL_INDEX, my_data->max_vol_index);
set_values[0] = vol_index;
ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
@@ -1468,6 +1710,40 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi
goto exit;
}
+ if (popcount(devices) == 2) {
+ if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+ AUDIO_DEVICE_OUT_SPEAKER) ||
+ devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
+ AUDIO_DEVICE_OUT_SPEAKER)) {
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
+ } else if (devices == (AUDIO_DEVICE_OUT_LINE |
+ AUDIO_DEVICE_OUT_SPEAKER)) {
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_LINE;
+ } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE) ||
+ devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+ snd_device = SND_DEVICE_OUT_SPEAKER_SAFE_AND_HEADPHONES;
+ } else if (devices == (AUDIO_DEVICE_OUT_LINE |
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+ snd_device = SND_DEVICE_OUT_SPEAKER_SAFE_AND_LINE;
+ } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL |
+ AUDIO_DEVICE_OUT_SPEAKER)) {
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI;
+ } else {
+ ALOGE("%s: Invalid combo device(%#x)", __func__, devices);
+ goto exit;
+ }
+ if (snd_device != SND_DEVICE_NONE) {
+ goto exit;
+ }
+ }
+
+ if (popcount(devices) != 1) {
+ ALOGE("%s: Invalid output devices(%#x)", __func__, devices);
+ goto exit;
+ }
+
if (voice_is_in_call(adev) || adev->enable_voicerx) {
if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
devices & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
@@ -1510,40 +1786,6 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi
}
}
- if (popcount(devices) == 2) {
- if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
- AUDIO_DEVICE_OUT_SPEAKER) ||
- devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
- AUDIO_DEVICE_OUT_SPEAKER)) {
- snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
- } else if (devices == (AUDIO_DEVICE_OUT_LINE |
- AUDIO_DEVICE_OUT_SPEAKER)) {
- snd_device = SND_DEVICE_OUT_SPEAKER_AND_LINE;
- } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
- AUDIO_DEVICE_OUT_SPEAKER_SAFE) ||
- devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
- AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
- snd_device = SND_DEVICE_OUT_SPEAKER_SAFE_AND_HEADPHONES;
- } else if (devices == (AUDIO_DEVICE_OUT_LINE |
- AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
- snd_device = SND_DEVICE_OUT_SPEAKER_SAFE_AND_LINE;
- } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL |
- AUDIO_DEVICE_OUT_SPEAKER)) {
- snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI;
- } else {
- ALOGE("%s: Invalid combo device(%#x)", __func__, devices);
- goto exit;
- }
- if (snd_device != SND_DEVICE_NONE) {
- goto exit;
- }
- }
-
- if (popcount(devices) != 1) {
- ALOGE("%s: Invalid output devices(%#x)", __func__, devices);
- goto exit;
- }
-
if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
snd_device = SND_DEVICE_OUT_HEADPHONES;
@@ -1594,8 +1836,8 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d
snd_device_t snd_device = SND_DEVICE_NONE;
int channel_count = popcount(channel_mask);
- ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
- __func__, out_device, in_device);
+ ALOGV("%s: enter: out_device(%#x) in_device(%#x) channel_count (%d) channel_mask (0x%x)",
+ __func__, out_device, in_device, channel_count, channel_mask);
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 ||
@@ -1641,17 +1883,24 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d
snd_device = SND_DEVICE_IN_BT_SCO_MIC;
}
} else if (out_device & AUDIO_DEVICE_OUT_SPEAKER ||
- out_device & AUDIO_DEVICE_OUT_SPEAKER_SAFE ||
- out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
- out_device & AUDIO_DEVICE_OUT_LINE) {
- if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode &&
- my_data->dualmic_config != DUALMIC_CONFIG_NONE) {
- snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC;
- } else {
+ out_device & AUDIO_DEVICE_OUT_SPEAKER_SAFE ||
+ out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+ out_device & AUDIO_DEVICE_OUT_LINE) {
+ if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode) {
+ if (my_data->source_mic_type & SOURCE_DUAL_MIC) {
+ snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC;
+ } else {
+ snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
+ }
+ }
+
+ //select default
+ if (snd_device == SND_DEVICE_NONE) {
snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
}
- } else if (out_device & AUDIO_DEVICE_OUT_TELEPHONY_TX)
+ } 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) {
@@ -1659,20 +1908,37 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d
}
} else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) {
if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- if (my_data->dualmic_config != DUALMIC_CONFIG_NONE) {
- if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK)
- snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_STEREO;
- else if (my_data->fluence_in_voice_rec &&
- adev->active_input->enable_ns)
+ if (my_data->fluence_in_voice_rec && channel_count == 1) {
+ if ((my_data->fluence_type == FLUENCE_PRO_ENABLE) &&
+ (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
+ snd_device = SND_DEVICE_IN_HANDSET_QMIC;
+ } else if ((my_data->fluence_type == FLUENCE_PRO_ENABLE) &&
+ (my_data->source_mic_type & SOURCE_THREE_MIC)) {
+ snd_device = SND_DEVICE_IN_HANDSET_TMIC;
+ } else if (((my_data->fluence_type == FLUENCE_PRO_ENABLE) ||
+ (my_data->fluence_type == FLUENCE_ENABLE)) &&
+ (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE;
+ }
+ platform_set_echo_reference(adev, true, out_device);
+ } 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;
+ } else if (((int)channel_mask == AUDIO_CHANNEL_INDEX_MASK_3) &&
+ (my_data->source_mic_type & SOURCE_THREE_MIC)) {
+ snd_device = SND_DEVICE_IN_THREE_MIC;
+ } else if (((int)channel_mask == AUDIO_CHANNEL_INDEX_MASK_4) &&
+ (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
+ snd_device = SND_DEVICE_IN_QUAD_MIC;
}
-
if (snd_device == SND_DEVICE_NONE) {
if (adev->active_input->enable_ns)
snd_device = SND_DEVICE_IN_VOICE_REC_MIC_NS;
else
snd_device = SND_DEVICE_IN_VOICE_REC_MIC;
}
+ } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ snd_device = SND_DEVICE_IN_VOICE_REC_HEADSET_MIC;
}
} else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
if (out_device & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE))
@@ -1683,16 +1949,18 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d
if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
if (my_data->fluence_in_spkr_mode &&
my_data->fluence_in_voice_comm &&
- my_data->dualmic_config != DUALMIC_CONFIG_NONE) {
+ (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
- } else
+ } else {
snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
+ }
} else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
if (my_data->fluence_in_voice_comm &&
- my_data->dualmic_config != DUALMIC_CONFIG_NONE) {
+ (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC_NS;
- } else
+ } else {
snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC_NS;
+ }
} else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC;
}
@@ -1701,16 +1969,18 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d
if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
if (my_data->fluence_in_spkr_mode &&
my_data->fluence_in_voice_comm &&
- my_data->dualmic_config != DUALMIC_CONFIG_NONE) {
+ (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC;
- } else
+ } else {
snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC;
+ }
} else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
if (my_data->fluence_in_voice_comm &&
- my_data->dualmic_config != DUALMIC_CONFIG_NONE) {
+ (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC;
- } else
+ } else {
snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC;
+ }
} else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC;
}
@@ -1719,16 +1989,18 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d
if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
if (my_data->fluence_in_spkr_mode &&
my_data->fluence_in_voice_comm &&
- my_data->dualmic_config != DUALMIC_CONFIG_NONE) {
+ (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS;
- } else
+ } else {
snd_device = SND_DEVICE_IN_SPEAKER_MIC_NS;
+ }
} else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
if (my_data->fluence_in_voice_comm &&
- my_data->dualmic_config != DUALMIC_CONFIG_NONE) {
+ (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
snd_device = SND_DEVICE_IN_HANDSET_DMIC_NS;
- } else
+ } else {
snd_device = SND_DEVICE_IN_HANDSET_MIC_NS;
+ }
}
}
}
@@ -1745,17 +2017,37 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d
!(in_device & AUDIO_DEVICE_IN_VOICE_CALL) &&
!(in_device & AUDIO_DEVICE_IN_COMMUNICATION)) {
if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- if (my_data->dualmic_config != DUALMIC_CONFIG_NONE &&
- channel_count == 2)
+ if ((my_data->source_mic_type & SOURCE_QUAD_MIC) &&
+ (int)channel_mask == AUDIO_CHANNEL_INDEX_MASK_4) {
+ snd_device = SND_DEVICE_IN_QUAD_MIC;
+ } else if ((my_data->source_mic_type & SOURCE_THREE_MIC) &&
+ (int)channel_mask == AUDIO_CHANNEL_INDEX_MASK_3) {
+ snd_device = SND_DEVICE_IN_THREE_MIC;
+ } else if ((my_data->source_mic_type & SOURCE_DUAL_MIC) &&
+ channel_count == 2) {
snd_device = SND_DEVICE_IN_HANDSET_DMIC_STEREO;
- else
+ } else if ((my_data->source_mic_type & SOURCE_MONO_MIC) &&
+ channel_count == 1) {
+ snd_device = SND_DEVICE_IN_HANDSET_MIC;
+ } else {
+ ALOGE("%s: something wrong (1): source type (%d) channel_count (%d) .."
+ " channel mask (0x%x) no combination found .. setting to mono", __func__,
+ my_data->source_mic_type, channel_count, channel_mask);
snd_device = SND_DEVICE_IN_HANDSET_MIC;
+ }
} else if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
- if (my_data->dualmic_config != DUALMIC_CONFIG_NONE &&
- channel_count == 2)
+ if ((my_data->source_mic_type & SOURCE_DUAL_MIC) &&
+ channel_count == 2) {
snd_device = SND_DEVICE_IN_SPEAKER_DMIC_STEREO;
- else
+ } else if ((my_data->source_mic_type & SOURCE_MONO_MIC) &&
+ channel_count == 1) {
+ snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+ } else {
+ ALOGE("%s: something wrong (2): source type (%d) channel_count (%d) .."
+ " no combination found .. setting to mono", __func__,
+ my_data->source_mic_type, channel_count);
snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+ }
} else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
snd_device = SND_DEVICE_IN_HEADSET_MIC;
} else if (in_device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
@@ -1786,10 +2078,18 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d
out_device & AUDIO_DEVICE_OUT_SPEAKER_SAFE ||
out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
out_device & AUDIO_DEVICE_OUT_LINE) {
- if (channel_count == 2)
+ if ((my_data->source_mic_type & SOURCE_DUAL_MIC) &&
+ channel_count == 2) {
snd_device = SND_DEVICE_IN_SPEAKER_DMIC_STEREO;
- else
+ } else if ((my_data->source_mic_type & SOURCE_MONO_MIC) &&
+ channel_count == 1) {
snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+ } else {
+ ALOGE("%s: something wrong (3): source type (%d) channel_count (%d) .."
+ " no combination found .. setting to mono", __func__,
+ my_data->source_mic_type, channel_count);
+ snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+ }
} else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) {
if (adev->bt_wb_speech_enabled) {
if (adev->bluetooth_nrec)
@@ -1993,7 +2293,7 @@ int platform_stop_incall_music_usecase(void *platform)
int platform_set_parameters(void *platform, struct str_parms *parms)
{
struct platform_data *my_data = (struct platform_data *)platform;
- char value[64];
+ char value[128];
char *kv_pairs = str_parms_to_str(parms);
int ret = 0, err;
@@ -2013,6 +2313,32 @@ int platform_set_parameters(void *platform, struct str_parms *parms)
ALOGV("%s: sound card name %s", __func__, my_data->snd_card_name);
}
+ err = str_parms_get_str(parms, PLATFORM_CONFIG_KEY_OPERATOR_INFO,
+ value, sizeof(value));
+ if (err >= 0) {
+ struct operator_info *info;
+ char *str = value;
+ char *name;
+
+ str_parms_del(parms, PLATFORM_CONFIG_KEY_OPERATOR_INFO);
+ info = (struct operator_info *)calloc(1, sizeof(struct operator_info));
+ name = strtok(str, ";");
+ info->name = strdup(name);
+ info->mccmnc = strdup(str + strlen(name) + 1);
+
+ list_add_tail(&operator_info_list, &info->list);
+ ALOGD("%s: add operator[%s] mccmnc[%s]", __func__, info->name, info->mccmnc);
+ }
+
+ memset(value, 0, sizeof(value));
+ err = str_parms_get_str(parms, PLATFORM_CONFIG_KEY_MAX_MIC_COUNT,
+ value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, PLATFORM_CONFIG_KEY_MAX_MIC_COUNT);
+ my_data->max_mic_count = atoi(value);
+ ALOGV("%s: max_mic_count %s/%d", __func__, value, my_data->max_mic_count);
+ }
+
done:
ALOGV("%s: exit with code(%d)", __func__, ret);
if (kv_pairs != NULL)
@@ -2083,6 +2409,67 @@ done:
return ret;
}
+#define DEFAULT_NOMINAL_SPEAKER_GAIN 20
+int ramp_speaker_gain(struct audio_device *adev, bool ramp_up, int target_ramp_up_gain) {
+ // backup_gain: gain to try to set in case of an error during ramp
+ int start_gain, end_gain, step, backup_gain, i;
+ bool error = false;
+ const struct mixer_ctl *ctl;
+ const char *mixer_ctl_name_gain_left = "Left Speaker Gain";
+ const char *mixer_ctl_name_gain_right = "Right Speaker Gain";
+ struct mixer_ctl *ctl_left = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name_gain_left);
+ struct mixer_ctl *ctl_right = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name_gain_right);
+ if (!ctl_left || !ctl_right) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s or %s, not applying speaker gain ramp",
+ __func__, mixer_ctl_name_gain_left, mixer_ctl_name_gain_right);
+ return -EINVAL;
+ } else if ((mixer_ctl_get_num_values(ctl_left) != 1)
+ || (mixer_ctl_get_num_values(ctl_right) != 1)) {
+ ALOGE("%s: Unexpected num values for mixer cmd - %s or %s, not applying speaker gain ramp",
+ __func__, mixer_ctl_name_gain_left, mixer_ctl_name_gain_right);
+ return -EINVAL;
+ }
+ if (ramp_up) {
+ start_gain = 0;
+ end_gain = target_ramp_up_gain > 0 ? target_ramp_up_gain : DEFAULT_NOMINAL_SPEAKER_GAIN;
+ step = +1;
+ backup_gain = end_gain;
+ } else {
+ // using same gain on left and right
+ const int left_gain = mixer_ctl_get_value(ctl_left, 0);
+ start_gain = left_gain > 0 ? left_gain : DEFAULT_NOMINAL_SPEAKER_GAIN;
+ end_gain = 0;
+ step = -1;
+ backup_gain = start_gain;
+ }
+ for (i = start_gain ; i != (end_gain + step) ; i += step) {
+ //ALOGV("setting speaker gain to %d", i);
+ if (mixer_ctl_set_value(ctl_left, 0, i)) {
+ ALOGE("%s: error setting %s to %d during gain ramp",
+ __func__, mixer_ctl_name_gain_left, i);
+ error = true;
+ break;
+ }
+ if (mixer_ctl_set_value(ctl_right, 0, i)) {
+ ALOGE("%s: error setting %s to %d during gain ramp",
+ __func__, mixer_ctl_name_gain_right, i);
+ error = true;
+ break;
+ }
+ usleep(1000);
+ }
+ if (error) {
+ // an error occured during the ramp, let's still try to go back to a safe volume
+ if (mixer_ctl_set_value(ctl_left, 0, backup_gain)) {
+ ALOGE("%s: error restoring left gain to %d", __func__, backup_gain);
+ }
+ if (mixer_ctl_set_value(ctl_right, 0, backup_gain)) {
+ ALOGE("%s: error restoring right gain to %d", __func__, backup_gain);
+ }
+ }
+ return start_gain;
+}
+
int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels)
{
// only update if there is active pcm playback on speaker
@@ -2096,14 +2483,28 @@ int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels)
list_for_each(node, &adev->usecase_list) {
usecase = node_to_item(node, struct audio_usecase, list);
if (usecase->type == PCM_PLAYBACK &&
- usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
- const char *mixer_path;
- if (swap_channels) {
- mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_REVERSE);
- audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+ usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+ /*
+ * If acdb tuning is different for SPEAKER_REVERSE, it is must
+ * to perform device switch to disable the current backend to
+ * enable it with new acdb data.
+ */
+ if (acdb_device_table[SND_DEVICE_OUT_SPEAKER] !=
+ acdb_device_table[SND_DEVICE_OUT_SPEAKER_REVERSE]) {
+ const int initial_skpr_gain = ramp_speaker_gain(adev, false /*ramp_up*/, -1);
+ select_devices(adev, usecase->id);
+ if (initial_skpr_gain != -EINVAL) {
+ ramp_speaker_gain(adev, true /*ramp_up*/, initial_skpr_gain);
+ }
} else {
- mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER);
- audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+ const char *mixer_path;
+ if (swap_channels) {
+ mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_REVERSE);
+ audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+ } else {
+ mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER);
+ audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+ }
}
break;
}
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index f1c52399..4b4332e0 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -17,6 +17,19 @@
#ifndef QCOM_AUDIO_PLATFORM_H
#define QCOM_AUDIO_PLATFORM_H
+enum {
+ FLUENCE_DISABLE, /* Target dosent support fluence */
+ FLUENCE_ENABLE = 0x1, /* Target supports fluence */
+ FLUENCE_PRO_ENABLE = 0x2, /* Target supports fluence pro */
+};
+
+enum {
+ SOURCE_MONO_MIC = 0x1, /* Target contains 1 mic */
+ SOURCE_DUAL_MIC = 0x2, /* Target contains 2 mics */
+ SOURCE_THREE_MIC = 0x4, /* Target contains 3 mics */
+ SOURCE_QUAD_MIC = 0x8, /* Target contains 4 mics */
+};
+
/*
* Below are the devices for which is back end is same, SLIMBUS_0_RX.
* All these devices are handled by the internal HW codec. We can
@@ -115,11 +128,16 @@ enum {
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_REC_HEADSET_MIC,
SND_DEVICE_IN_VOICE_RX,
+ SND_DEVICE_IN_THREE_MIC,
+ SND_DEVICE_IN_QUAD_MIC,
SND_DEVICE_IN_CAPTURE_VI_FEEDBACK,
+ SND_DEVICE_IN_HANDSET_TMIC,
+ SND_DEVICE_IN_HANDSET_QMIC,
SND_DEVICE_IN_END,
SND_DEVICE_MAX = SND_DEVICE_IN_END,
@@ -131,6 +149,7 @@ enum {
#define ALL_SESSION_VSID 0xFFFFFFFF
#define DEFAULT_MUTE_RAMP_DURATION_MS 20
#define DEFAULT_VOLUME_RAMP_DURATION_MS 20
+#define MIXER_PATH_MAX_LENGTH 100
#define ACDB_ID_VOICE_SPEAKER 15
#define ACDB_ID_VOICE_HANDSET 7
@@ -207,6 +226,8 @@ enum {
#define LIB_MDM_DETECT "libmdmdetect.so"
#define PLATFORM_CONFIG_KEY_SOUNDCARD_NAME "snd_card_name"
+#define PLATFORM_CONFIG_KEY_MAX_MIC_COUNT "input_mic_max_count"
+#define PLATFORM_DEFAULT_MIC_COUNT 2
/* CSD-CLIENT related functions */
typedef int (*init_t)(bool);
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 61bb92f6..1e413587 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -41,6 +41,9 @@ int platform_switch_voice_call_usecase_route_post(void *platform,
int platform_start_voice_call(void *platform, uint32_t vsid);
int platform_stop_voice_call(void *platform, uint32_t vsid);
int platform_set_voice_volume(void *platform, int volume);
+void platform_set_speaker_gain_in_combo(struct audio_device *adev,
+ snd_device_t snd_device,
+ bool enable);
int platform_set_mic_mute(void *platform, bool state);
int platform_get_sample_rate(void *platform, uint32_t *rate);
int platform_set_device_mute(void *platform, bool state, char *dir);
@@ -48,6 +51,10 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi
snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device);
int platform_set_hdmi_channels(void *platform, int channel_count);
int platform_edid_get_max_channels(void *platform);
+void platform_add_operator_specific_device(snd_device_t snd_device,
+ const char *operator,
+ const char *mixer_path,
+ unsigned int acdb_id);
/* returns the latency for a usecase in Us */
int64_t platform_render_latency(audio_usecase_t usecase);
diff --git a/hal/platform_info.c b/hal/platform_info.c
index c0527b4b..45562947 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -33,6 +33,7 @@ typedef enum {
PCM_ID,
BACKEND_NAME,
CONFIG_PARAMS,
+ OPERATOR_SPECIFIC,
} section_t;
typedef void (* section_process_fn)(const XML_Char **attr);
@@ -42,6 +43,7 @@ static void process_pcm_id(const XML_Char **attr);
static void process_backend_name(const XML_Char **attr);
static void process_config_params(const XML_Char **attr);
static void process_root(const XML_Char **attr);
+static void process_operator_specific(const XML_Char **attr);
static section_process_fn section_table[] = {
[ROOT] = process_root,
@@ -49,6 +51,7 @@ static section_process_fn section_table[] = {
[PCM_ID] = process_pcm_id,
[BACKEND_NAME] = process_backend_name,
[CONFIG_PARAMS] = process_config_params,
+ [OPERATOR_SPECIFIC] = process_operator_specific,
};
static section_t section;
@@ -79,10 +82,18 @@ static struct platform_info my_data;
* </pcm_ids>
* <config_params>
* <param key="snd_card_name" value="msm8994-tomtom-mtp-snd-card"/>
+ * <param key="operator_info" value="tmus;aa;bb;cc"/>
+ * <param key="operator_info" value="sprint;xx;yy;zz"/>
* ...
* ...
* </config_params>
*
+ * <operator_specific>
+ * <device name="???" operator="???" mixer_path="???" acdb_id="???"/>
+ * ...
+ * ...
+ * </operator_specific>
+ *
* </audio_platform_info>
*/
@@ -214,6 +225,44 @@ done:
return;
}
+
+static void process_operator_specific(const XML_Char **attr)
+{
+ snd_device_t snd_device = SND_DEVICE_NONE;
+
+ if (strcmp(attr[0], "name") != 0) {
+ ALOGE("%s: 'name' not found", __func__);
+ goto done;
+ }
+
+ snd_device = platform_get_snd_device_index((char *)attr[1]);
+ if (snd_device < 0) {
+ ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
+ __func__, (char *)attr[3], PLATFORM_INFO_XML_PATH);
+ goto done;
+ }
+
+ if (strcmp(attr[2], "operator") != 0) {
+ ALOGE("%s: 'operator' not found", __func__);
+ goto done;
+ }
+
+ if (strcmp(attr[4], "mixer_path") != 0) {
+ ALOGE("%s: 'mixer_path' not found", __func__);
+ goto done;
+ }
+
+ if (strcmp(attr[6], "acdb_id") != 0) {
+ ALOGE("%s: 'acdb_id' not found", __func__);
+ goto done;
+ }
+
+ platform_add_operator_specific_device(snd_device, (char *)attr[3], (char *)attr[5], atoi((char *)attr[7]));
+
+done:
+ return;
+}
+
/* platform specific configuration key-value pairs */
static void process_config_params(const XML_Char **attr)
{
@@ -228,6 +277,7 @@ static void process_config_params(const XML_Char **attr)
}
str_parms_add_str(my_data.kvpairs, (char*)attr[1], (char*)attr[3]);
+ platform_set_parameters(my_data.platform, my_data.kvpairs);
done:
return;
}
@@ -247,8 +297,10 @@ static void start_tag(void *userdata __unused, const XML_Char *tag_name,
section = BACKEND_NAME;
} else if (strcmp(tag_name, "config_params") == 0) {
section = CONFIG_PARAMS;
+ } else if (strcmp(tag_name, "operator_specific") == 0) {
+ section = OPERATOR_SPECIFIC;
} else if (strcmp(tag_name, "device") == 0) {
- if ((section != ACDB) && (section != BACKEND_NAME)) {
+ if ((section != ACDB) && (section != BACKEND_NAME) && (section != OPERATOR_SPECIFIC)) {
ALOGE("device tag only supported for acdb/backend names");
return;
}
@@ -287,7 +339,8 @@ static void end_tag(void *userdata __unused, const XML_Char *tag_name)
section = ROOT;
} else if (strcmp(tag_name, "config_params") == 0) {
section = ROOT;
- platform_set_parameters(my_data.platform, my_data.kvpairs);
+ } else if (strcmp(tag_name, "operator_specific") == 0) {
+ section = ROOT;
}
}
diff --git a/hal/voice.c b/hal/voice.c
index 1f36b36b..a33305d3 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -52,6 +52,58 @@ static struct voice_session *voice_get_session_from_use_case(struct audio_device
return session;
}
+static bool voice_is_sidetone_device(snd_device_t out_device,
+ char *mixer_path)
+{
+ bool is_sidetone_dev = true;
+
+ switch (out_device) {
+ case SND_DEVICE_OUT_VOICE_HAC_HANDSET:
+ strlcpy(mixer_path, "sidetone-hac-handset", MIXER_PATH_MAX_LENGTH);
+ break;
+ case SND_DEVICE_OUT_VOICE_HANDSET:
+ strlcpy(mixer_path, "sidetone-handset", MIXER_PATH_MAX_LENGTH);
+ break;
+ case SND_DEVICE_OUT_VOICE_HEADPHONES:
+ strlcpy(mixer_path, "sidetone-headphones", MIXER_PATH_MAX_LENGTH);
+ break;
+ default:
+ is_sidetone_dev = false;
+ break;
+ }
+
+ return is_sidetone_dev;
+}
+
+void voice_set_sidetone(struct audio_device *adev,
+ snd_device_t out_snd_device, bool enable)
+{
+ char mixer_path[MIXER_PATH_MAX_LENGTH];
+ bool is_sidetone_dev;
+
+ ALOGD("%s: %s, out_snd_device: %d\n",
+ __func__, (enable ? "enable" : "disable"),
+ out_snd_device);
+
+ is_sidetone_dev = voice_is_sidetone_device(out_snd_device, mixer_path);
+
+ if (!is_sidetone_dev) {
+ ALOGD("%s: device %d does not support sidetone\n",
+ __func__, out_snd_device);
+ return;
+ }
+
+ ALOGD("%s: sidetone out device = %s\n",
+ __func__, mixer_path);
+
+ if (enable)
+ audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+ else
+ audio_route_reset_and_update_path(adev->audio_route, mixer_path);
+
+ return;
+}
+
int voice_stop_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
{
int i, ret = 0;
@@ -61,8 +113,20 @@ int voice_stop_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
ALOGD("%s: enter usecase:%s", __func__, use_case_table[usecase_id]);
session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id);
+
+ uc_info = get_usecase_from_list(adev, usecase_id);
+ if (uc_info == NULL) {
+ ALOGE("%s: Could not find the usecase (%d) in the list",
+ __func__, usecase_id);
+ return -EINVAL;
+ }
+
session->state.current = CALL_INACTIVE;
+ /* Disable sidetone only when no calls are active */
+ if (!voice_is_call_state_active(adev))
+ voice_set_sidetone(adev, uc_info->out_snd_device, false);
+
ret = platform_stop_voice_call(adev->platform, session->vsid);
/* 1. Close the PCM devices */
@@ -75,13 +139,6 @@ int voice_stop_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
session->pcm_tx = NULL;
}
- uc_info = get_usecase_from_list(adev, usecase_id);
- if (uc_info == NULL) {
- ALOGE("%s: Could not find the usecase (%d) in the list",
- __func__, usecase_id);
- return -EINVAL;
- }
-
/* 2. Get and set stream specific mixer controls */
disable_audio_route(adev, uc_info);
@@ -129,6 +186,17 @@ int voice_start_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
goto error_start_voice;
}
+ ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+ __func__, adev->snd_card, pcm_dev_tx_id);
+ session->pcm_tx = pcm_open(adev->snd_card,
+ pcm_dev_tx_id,
+ PCM_IN, &voice_config);
+ if (session->pcm_tx && !pcm_is_ready(session->pcm_tx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_tx));
+ ret = -EIO;
+ goto error_start_voice;
+ }
+
ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
__func__, adev->snd_card, pcm_dev_rx_id);
session->pcm_rx = pcm_open(adev->snd_card,
@@ -140,18 +208,12 @@ int voice_start_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
goto error_start_voice;
}
- ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
- __func__, adev->snd_card, pcm_dev_tx_id);
- session->pcm_tx = pcm_open(adev->snd_card,
- pcm_dev_tx_id,
- PCM_IN, &voice_config);
- if (session->pcm_tx && !pcm_is_ready(session->pcm_tx)) {
- ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_tx));
- ret = -EIO;
- goto error_start_voice;
- }
- pcm_start(session->pcm_rx);
pcm_start(session->pcm_tx);
+ pcm_start(session->pcm_rx);
+
+ /* Enable sidetone only when no calls are already active */
+ if (!voice_is_call_state_active(adev))
+ voice_set_sidetone(adev, uc_info->out_snd_device, true);
voice_set_volume(adev, adev->voice.volume);
diff --git a/hal/voice.h b/hal/voice.h
index 76f9d0dd..23b9ee39 100644
--- a/hal/voice.h
+++ b/hal/voice.h
@@ -40,6 +40,7 @@ struct str_parms;
struct stream_in;
struct stream_out;
typedef int audio_usecase_t;
+typedef int snd_device_t;
struct call_state {
int current;
@@ -90,4 +91,8 @@ int voice_check_and_set_incall_music_usecase(struct audio_device *adev,
int voice_check_and_stop_incall_rec_usecase(struct audio_device *adev,
struct stream_in *in);
void voice_update_devices_for_all_voice_usecases(struct audio_device *adev);
+void voice_set_sidetone(struct audio_device *adev,
+ snd_device_t out_snd_device,
+ bool enable);
+bool voice_is_call_state_active(struct audio_device *adev);
#endif //VOICE_H
diff --git a/post_proc/volume_listener.c b/post_proc/volume_listener.c
index cf15f1ca..34954bbc 100644
--- a/post_proc/volume_listener.c
+++ b/post_proc/volume_listener.c
@@ -312,6 +312,13 @@ static void check_and_set_gain_dep_cal()
* Effect Control Interface Implementation
*/
+static inline int16_t clamp16(int32_t sample)
+{
+ if ((sample>>15) ^ (sample>>31))
+ sample = 0x7FFF ^ (sample>>31);
+ return sample;
+}
+
static int vol_effect_process(effect_handle_t self,
audio_buffer_t *in_buffer,
audio_buffer_t *out_buffer)
@@ -330,7 +337,15 @@ static int vol_effect_process(effect_handle_t self,
// calculation based on channel count 2
if (in_buffer->raw != out_buffer->raw) {
- memcpy(out_buffer->raw, in_buffer->raw, out_buffer->frameCount * 2 * sizeof(int16_t));
+ if (context->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ size_t i;
+ for (i = 0; i < out_buffer->frameCount*2; i++) {
+ out_buffer->s16[i] = clamp16(out_buffer->s16[i] + in_buffer->s16[i]);
+ }
+ } else {
+ memcpy(out_buffer->raw, in_buffer->raw, out_buffer->frameCount * 2 * sizeof(int16_t));
+ }
+
} else {
ALOGW("%s: something wrong, didn't handle in_buffer and out_buffer same address case",
__func__);
@@ -374,6 +389,12 @@ static int vol_effect_command(effect_handle_t self,
case EFFECT_CMD_SET_CONFIG:
ALOGV("%s :: cmd called EFFECT_CMD_SET_CONFIG", __func__);
+ if (p_cmd_data == NULL || cmd_size != sizeof(effect_config_t)
+ || p_reply_data == NULL || reply_size == NULL || *reply_size != sizeof(int)) {
+ return -EINVAL;
+ }
+ context->config = *(effect_config_t *)p_cmd_data;
+ *(int *)p_reply_data = 0;
break;
case EFFECT_CMD_GET_CONFIG:
@@ -420,7 +441,7 @@ static int vol_effect_command(effect_handle_t self,
// After changing the state and if device is speaker
// recalculate gain dep cal level
- if (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) {
+ if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) {
check_and_set_gain_dep_cal();
}
@@ -447,7 +468,7 @@ static int vol_effect_command(effect_handle_t self,
// After changing the state and if device is speaker
// recalculate gain dep cal level
- if (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) {
+ if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) {
check_and_set_gain_dep_cal();
}
@@ -478,8 +499,8 @@ static int vol_effect_command(effect_handle_t self,
__func__, context->dev_id, new_device);
// check if old or new device is speaker
- if ((context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) ||
- (new_device & AUDIO_DEVICE_OUT_SPEAKER)) {
+ if ((context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) ||
+ (new_device == AUDIO_DEVICE_OUT_SPEAKER)) {
recompute_gain_dep_cal_Level = true;
}
@@ -504,7 +525,7 @@ static int vol_effect_command(effect_handle_t self,
goto exit;
}
- if (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) {
+ if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) {
recompute_gain_dep_cal_Level = true;
}
@@ -600,7 +621,7 @@ static int lib_init()
static int vol_prc_lib_create(const effect_uuid_t *uuid,
int32_t session_id,
- int32_t io_id,
+ int32_t io_id __unused,
effect_handle_t *p_handle)
{
int itt = 0;
@@ -682,7 +703,7 @@ static int vol_prc_lib_release(effect_handle_t handle)
ALOGV("--- Found something to remove ---");
list_remove(&context->effect_list_node);
PRINT_STREAM_TYPE(context->stream_type);
- if (context->dev_id && AUDIO_DEVICE_OUT_SPEAKER) {
+ if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) {
recompute_flag = true;
}
free(context);