diff options
author | Ricardo Cerqueira <ricardo@cyngn.com> | 2015-11-05 00:45:26 +0000 |
---|---|---|
committer | Ricardo Cerqueira <ricardo@cyngn.com> | 2015-11-05 00:45:26 +0000 |
commit | fbbf508bd695b8c27cbc524fb51573354091b5e0 (patch) | |
tree | d779d8df3ab89b12b1810a2ebf0bd2edf772fa8d | |
parent | c49734d5552746ee9ced46e36bc1b1a4a5118086 (diff) | |
parent | 819130e136f54a3e7fa37ba830d87fedcf28a8ae (diff) | |
download | hardware_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.mk | 7 | ||||
-rw-r--r-- | hal/audio_extn/audio_extn.c | 102 | ||||
-rw-r--r-- | hal/audio_extn/audio_extn.h | 9 | ||||
-rw-r--r-- | hal/audio_extn/soundtrigger.c | 10 | ||||
-rw-r--r-- | hal/audio_hw.c | 190 | ||||
-rw-r--r-- | hal/audio_hw.h | 23 | ||||
-rw-r--r-- | hal/msm8960/platform.c | 16 | ||||
-rw-r--r-- | hal/msm8960/platform.h | 4 | ||||
-rw-r--r-- | hal/msm8974/platform.c | 613 | ||||
-rw-r--r-- | hal/msm8974/platform.h | 21 | ||||
-rw-r--r-- | hal/platform_api.h | 7 | ||||
-rw-r--r-- | hal/platform_info.c | 57 | ||||
-rw-r--r-- | hal/voice.c | 98 | ||||
-rw-r--r-- | hal/voice.h | 5 | ||||
-rw-r--r-- | post_proc/volume_listener.c | 37 |
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); |