DO NOT MERGE Fix AudioEffect reply overflow am: 7ffa39c454 am: 0dac1009bb
am: 02bdc83136 -s ours
* commit '02bdc83136bd6d360d513d9a9a4015e4dab9eea3':
DO NOT MERGE Fix AudioEffect reply overflow
Change-Id: Ib0b37de80c6c9e23aa15967e019e7ea945061019
diff --git a/Android.mk b/Android.mk
index 1228876..6dbcccd 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,4 +1,4 @@
-ifneq ($(filter msm8960 msm8226 msm8x26 msm8974 msm8x74,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8960 msm8226 msm8x26 msm8974 msm8x74 msm8x84 msm8084,$(TARGET_BOARD_PLATFORM)),)
MY_LOCAL_PATH := $(call my-dir)
@@ -8,6 +8,7 @@
include $(MY_LOCAL_PATH)/hal/Android.mk
include $(MY_LOCAL_PATH)/voice_processing/Android.mk
include $(MY_LOCAL_PATH)/visualizer/Android.mk
+include $(MY_LOCAL_PATH)/post_proc/Android.mk
endif
endif
diff --git a/hal/Android.mk b/hal/Android.mk
index b5949da..18b8bf4 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -7,13 +7,22 @@
LOCAL_ARM_MODE := arm
AUDIO_PLATFORM := $(TARGET_BOARD_PLATFORM)
-ifneq ($(filter msm8974 msm8226,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8974 msm8226 msm8084,$(TARGET_BOARD_PLATFORM)),)
# B-family platform uses msm8974 code base
AUDIO_PLATFORM = msm8974
+ifneq ($(filter msm8226,$(TARGET_BOARD_PLATFORM)),)
+ LOCAL_CFLAGS := -DPLATFORM_MSM8x26
+endif
+ifneq ($(filter msm8084,$(TARGET_BOARD_PLATFORM)),)
+ LOCAL_CFLAGS := -DPLATFORM_MSM8084
+endif
endif
LOCAL_SRC_FILES := \
audio_hw.c \
+ voice.c \
+ platform_info.c \
+ audio_extn/ext_speaker.c \
$(AUDIO_PLATFORM)/platform.c
LOCAL_SHARED_LIBRARIES := \
@@ -22,17 +31,30 @@
libtinyalsa \
libtinycompress \
libaudioroute \
- libdl
-
+ libdl \
+ libexpat
LOCAL_C_INCLUDES += \
external/tinyalsa/include \
external/tinycompress/include \
$(call include-path-for, audio-route) \
$(call include-path-for, audio-effects) \
- $(LOCAL_PATH)/$(AUDIO_PLATFORM)
+ $(LOCAL_PATH)/$(AUDIO_PLATFORM) \
+ $(LOCAL_PATH)/audio_extn \
+ $(LOCAL_PATH)/voice_extn \
+ external/expat/lib
-LOCAL_MODULE := audio.primary.$(AUDIO_PLATFORM)
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_MULTI_VOICE_SESSIONS)),true)
+ LOCAL_CFLAGS += -DMULTI_VOICE_SESSION_ENABLED
+ LOCAL_SRC_FILES += voice_extn/voice_extn.c
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HFP)),true)
+ LOCAL_CFLAGS += -DHFP_ENABLED
+ LOCAL_SRC_FILES += audio_extn/hfp.c
+endif
+
+LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM)
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
new file mode 100644
index 0000000..26c2fb4
--- /dev/null
+++ b/hal/audio_extn/audio_extn.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef AUDIO_EXTN_H
+#define AUDIO_EXTN_H
+
+#include <cutils/str_parms.h>
+
+void *audio_extn_extspk_init(struct audio_device *adev);
+void audio_extn_extspk_deinit(void *extn);
+void audio_extn_extspk_update(void* extn);
+void audio_extn_extspk_set_mode(void* extn, audio_mode_t mode);
+void audio_extn_extspk_set_voice_vol(void* extn, float vol);
+
+#ifndef HFP_ENABLED
+#define audio_extn_hfp_is_active(adev) (0)
+#define audio_extn_hfp_get_usecase() (-1)
+#define audio_extn_hfp_set_parameters(adev, params) (0)
+#else
+bool audio_extn_hfp_is_active(struct audio_device *adev);
+
+audio_usecase_t audio_extn_hfp_get_usecase();
+
+void audio_extn_hfp_set_parameters(struct audio_device *adev,
+ struct str_parms *parms);
+#endif
+
+#endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/ext_speaker.c b/hal/audio_extn/ext_speaker.c
new file mode 100644
index 0000000..a551fb3
--- /dev/null
+++ b/hal/audio_extn/ext_speaker.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2014 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 "ext_speaker"
+/*#define LOG_NDEBUG 0*/
+#include <cutils/log.h>
+
+#include <audio_hw.h>
+#include <dlfcn.h>
+
+#ifdef __LP64__
+ #define LIB_SPEAKER_BUNDLE "/system/lib64/soundfx/libspeakerbundle.so"
+#else
+ #define LIB_SPEAKER_BUNDLE "/system/lib/soundfx/libspeakerbundle.so"
+#endif
+
+typedef void (*set_mode_t)(int);
+typedef void (*set_speaker_on_t)(bool);
+typedef void (*set_earpiece_on_t)(bool);
+typedef void (*set_voice_vol_t)(float);
+
+struct speaker_data {
+ struct audio_device *adev;
+ void *speaker_bundle;
+ set_mode_t set_mode;
+ set_speaker_on_t set_speaker_on;
+ set_earpiece_on_t set_earpiece_on;
+ set_voice_vol_t set_voice_vol;
+};
+
+static struct speaker_data* open_speaker_bundle()
+{
+ struct speaker_data *sd = calloc(1, sizeof(struct speaker_data));
+
+ sd->speaker_bundle = dlopen(LIB_SPEAKER_BUNDLE, RTLD_NOW);
+ if (sd->speaker_bundle == NULL) {
+ ALOGE("%s: DLOPEN failed for %s", __func__, LIB_SPEAKER_BUNDLE);
+ goto error;
+ } else {
+ ALOGV("%s: DLOPEN successful for %s", __func__, LIB_SPEAKER_BUNDLE);
+
+ sd->set_mode = (set_mode_t)dlsym(sd->speaker_bundle,
+ "set_mode");
+ if (sd->set_mode == NULL) {
+ ALOGE("%s: dlsym error %s for set_mode", __func__,
+ dlerror());
+ goto error;
+ }
+ sd->set_speaker_on = (set_speaker_on_t)dlsym(sd->speaker_bundle,
+ "set_speaker_on");
+ if (sd->set_speaker_on == NULL) {
+ ALOGE("%s: dlsym error %s for set_speaker_on", __func__,
+ dlerror());
+ goto error;
+ }
+ sd->set_earpiece_on = (set_earpiece_on_t)dlsym(sd->speaker_bundle,
+ "set_earpiece_on");
+ if (sd->set_earpiece_on == NULL) {
+ ALOGE("%s: dlsym error %s for set_earpiece_on", __func__,
+ dlerror());
+ goto error;
+ }
+ sd->set_voice_vol = (set_voice_vol_t)dlsym(sd->speaker_bundle,
+ "set_voice_volume");
+ if (sd->set_voice_vol == NULL) {
+ ALOGE("%s: dlsym error %s for set_voice_volume",
+ __func__, dlerror());
+ goto error;
+ }
+ }
+ return sd;
+
+error:
+ free(sd);
+ return 0;
+}
+
+static void close_speaker_bundle(struct speaker_data *sd)
+{
+ if (sd != NULL) {
+ dlclose(sd->speaker_bundle);
+ free(sd);
+ sd = NULL;
+ }
+}
+
+void *audio_extn_extspk_init(struct audio_device *adev)
+{
+ struct speaker_data *data = open_speaker_bundle();
+
+ if (data)
+ data->adev = adev;
+
+ return data;
+}
+
+void audio_extn_extspk_deinit(void *extn)
+{
+ struct speaker_data *data = (struct speaker_data*)extn;
+ close_speaker_bundle(data);
+}
+
+void audio_extn_extspk_update(void* extn)
+{
+ struct speaker_data *data = (struct speaker_data*)extn;
+
+ if (data) {
+ bool speaker_on = false;
+ bool earpiece_on = false;
+ struct listnode *node;
+ struct audio_usecase *usecase;
+ list_for_each(node, &data->adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->devices & AUDIO_DEVICE_OUT_EARPIECE) {
+ if(data->adev->snd_dev_ref_cnt[usecase->out_snd_device] != 0) {
+ earpiece_on = true;
+ }
+ }
+ if (usecase->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+ if(data->adev->snd_dev_ref_cnt[usecase->out_snd_device] != 0) {
+ speaker_on = true;
+ }
+ }
+ }
+ data->set_earpiece_on(earpiece_on);
+ data->set_speaker_on(speaker_on);
+ }
+}
+
+void audio_extn_extspk_set_mode(void* extn, audio_mode_t mode)
+{
+ struct speaker_data *data = (struct speaker_data*)extn;
+
+ if (data)
+ data->set_mode(mode);
+}
+
+void audio_extn_extspk_set_voice_vol(void* extn, float vol)
+{
+ struct speaker_data *data = (struct speaker_data*)extn;
+
+ if (data)
+ data->set_voice_vol(vol);
+}
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
new file mode 100644
index 0000000..a108730
--- /dev/null
+++ b/hal/audio_extn/hfp.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2014 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_hfp"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <math.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include <stdlib.h>
+#include <cutils/str_parms.h>
+
+#define AUDIO_PARAMETER_HFP_ENABLE "hfp_enable"
+#define AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE "hfp_set_sampling_rate"
+#define AUDIO_PARAMETER_KEY_HFP_VOLUME "hfp_volume"
+
+static int32_t start_hfp(struct audio_device *adev,
+ struct str_parms *parms);
+
+static int32_t stop_hfp(struct audio_device *adev);
+
+struct hfp_module {
+ struct pcm *hfp_sco_rx;
+ struct pcm *hfp_sco_tx;
+ struct pcm *hfp_pcm_rx;
+ struct pcm *hfp_pcm_tx;
+ float hfp_volume;
+ bool is_hfp_running;
+ audio_usecase_t ucid;
+};
+
+static struct hfp_module hfpmod = {
+ .hfp_sco_rx = NULL,
+ .hfp_sco_tx = NULL,
+ .hfp_pcm_rx = NULL,
+ .hfp_pcm_tx = NULL,
+ .hfp_volume = 0,
+ .is_hfp_running = 0,
+ .ucid = USECASE_AUDIO_HFP_SCO,
+};
+static struct pcm_config pcm_config_hfp = {
+ .channels = 1,
+ .rate = 8000,
+ .period_size = 240,
+ .period_count = 2,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = 0,
+ .stop_threshold = INT_MAX,
+ .avail_min = 0,
+};
+
+static int32_t hfp_set_volume(struct audio_device *adev, float value)
+{
+ int32_t vol, ret = 0;
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "Internal HFP RX Volume";
+
+ ALOGV("%s: entry", __func__);
+ ALOGD("%s: (%f)\n", __func__, value);
+
+ if (value < 0.0) {
+ ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
+ value = 0.0;
+ } else {
+ value = ((value > 15.000000) ? 1.0 : (value / 15));
+ ALOGW("%s: Volume brought with in range (%f)\n", __func__, value);
+ }
+ vol = lrint((value * 0x2000) + 0.5);
+ hfpmod.hfp_volume = value;
+
+ if (!hfpmod.is_hfp_running) {
+ ALOGV("%s: HFP not active, ignoring set_hfp_volume call", __func__);
+ return -EIO;
+ }
+
+ ALOGD("%s: Setting HFP volume to %d \n", __func__, vol);
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ if(mixer_ctl_set_value(ctl, 0, vol) < 0) {
+ ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, vol);
+ return -EINVAL;
+ }
+
+ ALOGV("%s: exit", __func__);
+ return ret;
+}
+
+static int32_t start_hfp(struct audio_device *adev,
+ struct str_parms *parms __unused)
+{
+ int32_t i, ret = 0;
+ struct audio_usecase *uc_info;
+ int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
+
+ ALOGD("%s: enter", __func__);
+
+ uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+ uc_info->id = hfpmod.ucid;
+ uc_info->type = PCM_HFP_CALL;
+ uc_info->stream.out = adev->primary_output;
+ uc_info->devices = adev->primary_output->devices;
+ uc_info->in_snd_device = SND_DEVICE_NONE;
+ uc_info->out_snd_device = SND_DEVICE_NONE;
+
+ list_add_tail(&adev->usecase_list, &uc_info->list);
+
+ select_devices(adev, hfpmod.ucid);
+
+ pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
+ pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
+ pcm_dev_asm_rx_id = HFP_ASM_RX_TX;
+ pcm_dev_asm_tx_id = HFP_ASM_RX_TX;
+ if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 ||
+ pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) {
+ ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)",
+ __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id);
+ ret = -EIO;
+ goto exit;
+ }
+
+ ALOGV("%s: HFP PCM devices (hfp rx tx: %d pcm rx tx: %d) for the usecase(%d)",
+ __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
+
+ ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
+ __func__, adev->snd_card, pcm_dev_rx_id);
+ hfpmod.hfp_sco_rx = pcm_open(adev->snd_card,
+ pcm_dev_asm_rx_id,
+ PCM_OUT, &pcm_config_hfp);
+ if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx));
+ ret = -EIO;
+ goto exit;
+ }
+ ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+ __func__, adev->snd_card, pcm_dev_tx_id);
+ hfpmod.hfp_pcm_rx = pcm_open(adev->snd_card,
+ pcm_dev_rx_id,
+ PCM_OUT, &pcm_config_hfp);
+ if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx));
+ ret = -EIO;
+ goto exit;
+ }
+ hfpmod.hfp_sco_tx = pcm_open(adev->snd_card,
+ pcm_dev_asm_tx_id,
+ PCM_IN, &pcm_config_hfp);
+ if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx));
+ ret = -EIO;
+ goto exit;
+ }
+ ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+ __func__, adev->snd_card, pcm_dev_tx_id);
+ hfpmod.hfp_pcm_tx = pcm_open(adev->snd_card,
+ pcm_dev_tx_id,
+ PCM_IN, &pcm_config_hfp);
+ if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx));
+ ret = -EIO;
+ goto exit;
+ }
+ pcm_start(hfpmod.hfp_sco_rx);
+ pcm_start(hfpmod.hfp_sco_tx);
+ pcm_start(hfpmod.hfp_pcm_rx);
+ pcm_start(hfpmod.hfp_pcm_tx);
+
+ hfpmod.is_hfp_running = true;
+ hfp_set_volume(adev, hfpmod.hfp_volume);
+
+ ALOGD("%s: exit: status(%d)", __func__, ret);
+ return 0;
+
+exit:
+ stop_hfp(adev);
+ ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret);
+ return ret;
+}
+
+static int32_t stop_hfp(struct audio_device *adev)
+{
+ int32_t i, ret = 0;
+ struct audio_usecase *uc_info;
+
+ ALOGD("%s: enter", __func__);
+ hfpmod.is_hfp_running = false;
+
+ /* 1. Close the PCM devices */
+ if (hfpmod.hfp_sco_rx) {
+ pcm_close(hfpmod.hfp_sco_rx);
+ hfpmod.hfp_sco_rx = NULL;
+ }
+ if (hfpmod.hfp_sco_tx) {
+ pcm_close(hfpmod.hfp_sco_tx);
+ hfpmod.hfp_sco_tx = NULL;
+ }
+ if (hfpmod.hfp_pcm_rx) {
+ pcm_close(hfpmod.hfp_pcm_rx);
+ hfpmod.hfp_pcm_rx = NULL;
+ }
+ if (hfpmod.hfp_pcm_tx) {
+ pcm_close(hfpmod.hfp_pcm_tx);
+ hfpmod.hfp_pcm_tx = NULL;
+ }
+
+ uc_info = get_usecase_from_list(adev, hfpmod.ucid);
+ if (uc_info == NULL) {
+ ALOGE("%s: Could not find the usecase (%d) in the list",
+ __func__, hfpmod.ucid);
+ return -EINVAL;
+ }
+
+ /* 2. Get and set stream specific mixer controls */
+ disable_audio_route(adev, uc_info);
+
+ /* 3. Disable the rx and tx devices */
+ disable_snd_device(adev, uc_info->out_snd_device);
+ disable_snd_device(adev, uc_info->in_snd_device);
+
+ list_remove(&uc_info->list);
+ free(uc_info);
+
+ ALOGD("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+
+bool audio_extn_hfp_is_active(struct audio_device *adev)
+{
+ struct audio_usecase *hfp_usecase = NULL;
+ hfp_usecase = get_usecase_from_list(adev, hfpmod.ucid);
+
+ if (hfp_usecase != NULL)
+ return true;
+ else
+ return false;
+}
+
+audio_usecase_t audio_extn_hfp_get_usecase()
+{
+ return hfpmod.ucid;
+}
+
+void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
+{
+ int ret;
+ int rate;
+ int val;
+ float vol;
+ char value[32]={0};
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
+ sizeof(value));
+ if (ret >= 0) {
+ if (!strncmp(value,"true",sizeof(value)))
+ ret = start_hfp(adev,parms);
+ else
+ stop_hfp(adev);
+ }
+ memset(value, 0, sizeof(value));
+ ret = str_parms_get_str(parms,AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value,
+ sizeof(value));
+ if (ret >= 0) {
+ rate = atoi(value);
+ if (rate == 8000){
+ hfpmod.ucid = USECASE_AUDIO_HFP_SCO;
+ pcm_config_hfp.rate = rate;
+ } else if (rate == 16000){
+ hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB;
+ pcm_config_hfp.rate = rate;
+ } else
+ ALOGE("Unsupported rate..");
+ }
+
+ if (hfpmod.is_hfp_running) {
+ memset(value, 0, sizeof(value));
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
+ value, sizeof(value));
+ if (ret >= 0) {
+ val = atoi(value);
+ if (val > 0)
+ select_devices(adev, hfpmod.ucid);
+ }
+ }
+
+ memset(value, 0, sizeof(value));
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_VOLUME,
+ value, sizeof(value));
+ if (ret >= 0) {
+ if (sscanf(value, "%f", &vol) != 1){
+ ALOGE("%s: error in retrieving hfp volume", __func__);
+ ret = -EIO;
+ goto exit;
+ }
+ ALOGD("%s: set_hfp_volume usecase, Vol: [%f]", __func__, vol);
+ hfp_set_volume(adev, vol);
+ }
+exit:
+ ALOGV("%s Exit",__func__);
+}
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 48c426d..cd9ded8 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2013-2014 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.
@@ -40,12 +40,15 @@
#include <cutils/sched_policy.h>
#include <hardware/audio_effect.h>
+#include <hardware/audio_alsaops.h>
#include <system/thread_defs.h>
#include <audio_effects/effect_aec.h>
#include <audio_effects/effect_ns.h>
#include "audio_hw.h"
+#include "audio_extn.h"
#include "platform_api.h"
#include <platform.h>
+#include "voice_extn.h"
#include "sound/compress_params.h"
@@ -55,6 +58,17 @@
#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96
#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
+#define PROXY_OPEN_RETRY_COUNT 100
+#define PROXY_OPEN_WAIT_TIME 20
+
+static unsigned int configured_low_latency_capture_period_size =
+ LOW_LATENCY_CAPTURE_PERIOD_SIZE;
+
+/* This constant enables extended precision handling.
+ * TODO The flag is off until more testing is done.
+ */
+static const bool k_enable_extended_precision = false;
+
struct pcm_config pcm_config_deep_buffer = {
.channels = 2,
.rate = DEFAULT_OUTPUT_SAMPLING_RATE,
@@ -94,22 +108,57 @@
.format = PCM_FORMAT_S16_LE,
};
-struct pcm_config pcm_config_voice_call = {
- .channels = 1,
- .rate = 8000,
- .period_size = 160,
- .period_count = 2,
+#define AFE_PROXY_CHANNEL_COUNT 2
+#define AFE_PROXY_SAMPLING_RATE 48000
+
+#define AFE_PROXY_PLAYBACK_PERIOD_SIZE 768
+#define AFE_PROXY_PLAYBACK_PERIOD_COUNT 4
+
+struct pcm_config pcm_config_afe_proxy_playback = {
+ .channels = AFE_PROXY_CHANNEL_COUNT,
+ .rate = AFE_PROXY_SAMPLING_RATE,
+ .period_size = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
+ .period_count = AFE_PROXY_PLAYBACK_PERIOD_COUNT,
.format = PCM_FORMAT_S16_LE,
+ .start_threshold = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
+ .stop_threshold = INT_MAX,
+ .avail_min = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
};
-static const char * const use_case_table[AUDIO_USECASE_MAX] = {
+#define AFE_PROXY_RECORD_PERIOD_SIZE 768
+#define AFE_PROXY_RECORD_PERIOD_COUNT 4
+
+struct pcm_config pcm_config_afe_proxy_record = {
+ .channels = AFE_PROXY_CHANNEL_COUNT,
+ .rate = AFE_PROXY_SAMPLING_RATE,
+ .period_size = AFE_PROXY_RECORD_PERIOD_SIZE,
+ .period_count = AFE_PROXY_RECORD_PERIOD_COUNT,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = AFE_PROXY_RECORD_PERIOD_SIZE,
+ .stop_threshold = INT_MAX,
+ .avail_min = AFE_PROXY_RECORD_PERIOD_SIZE,
+};
+
+const char * const use_case_table[AUDIO_USECASE_MAX] = {
[USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback",
[USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
[USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback",
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
+
[USECASE_AUDIO_RECORD] = "audio-record",
[USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
+
+ [USECASE_AUDIO_HFP_SCO] = "hfp-sco",
+ [USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb",
+
[USECASE_VOICE_CALL] = "voice-call",
- [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
+ [USECASE_VOICE2_CALL] = "voice2-call",
+ [USECASE_VOLTE_CALL] = "volte-call",
+ [USECASE_QCHAT_CALL] = "qchat-call",
+ [USECASE_VOWLAN_CALL] = "vowlan-call",
+
+ [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = "afe-proxy-playback",
+ [USECASE_AUDIO_RECORD_AFE_PROXY] = "afe-proxy-record",
};
@@ -130,10 +179,15 @@
static bool is_supported_format(audio_format_t format)
{
- if (format == AUDIO_FORMAT_MP3 ||
- format == AUDIO_FORMAT_AAC)
- return true;
-
+ switch (format) {
+ case AUDIO_FORMAT_MP3:
+ case AUDIO_FORMAT_AAC_LC:
+ case AUDIO_FORMAT_AAC_HE_V1:
+ case AUDIO_FORMAT_AAC_HE_V2:
+ return true;
+ default:
+ break;
+ }
return false;
}
@@ -141,7 +195,7 @@
{
int id = 0;
- switch (format) {
+ switch (format & AUDIO_FORMAT_MAIN_MASK) {
case AUDIO_FORMAT_MP3:
id = SND_AUDIOCODEC_MP3;
break;
@@ -155,9 +209,21 @@
return id;
}
-static int enable_audio_route(struct audio_device *adev,
- struct audio_usecase *usecase,
- bool update_mixer)
+int pcm_ioctl(void *pcm, int request, ...)
+{
+ va_list ap;
+ void * arg;
+ int pcm_fd = *(int*)pcm;
+
+ va_start(ap, request);
+ arg = va_arg(ap, void *);
+ va_end(ap);
+
+ return ioctl(pcm_fd, request, arg);
+}
+
+int enable_audio_route(struct audio_device *adev,
+ struct audio_usecase *usecase)
{
snd_device_t snd_device;
char mixer_path[50];
@@ -173,19 +239,16 @@
snd_device = usecase->out_snd_device;
strcpy(mixer_path, use_case_table[usecase->id]);
- platform_add_backend_name(mixer_path, snd_device);
- ALOGV("%s: apply mixer path: %s", __func__, mixer_path);
- audio_route_apply_path(adev->audio_route, mixer_path);
- if (update_mixer)
- audio_route_update_mixer(adev->audio_route);
+ platform_add_backend_name(adev->platform, mixer_path, snd_device);
+ ALOGD("%s: apply and update mixer path: %s", __func__, mixer_path);
+ audio_route_apply_and_update_path(adev->audio_route, mixer_path);
ALOGV("%s: exit", __func__);
return 0;
}
-static int disable_audio_route(struct audio_device *adev,
- struct audio_usecase *usecase,
- bool update_mixer)
+int disable_audio_route(struct audio_device *adev,
+ struct audio_usecase *usecase)
{
snd_device_t snd_device;
char mixer_path[50];
@@ -199,19 +262,16 @@
else
snd_device = usecase->out_snd_device;
strcpy(mixer_path, use_case_table[usecase->id]);
- platform_add_backend_name(mixer_path, snd_device);
- ALOGV("%s: reset mixer path: %s", __func__, mixer_path);
- audio_route_reset_path(adev->audio_route, mixer_path);
- if (update_mixer)
- audio_route_update_mixer(adev->audio_route);
+ platform_add_backend_name(adev->platform, mixer_path, snd_device);
+ ALOGD("%s: reset and update mixer path: %s", __func__, mixer_path);
+ audio_route_reset_and_update_path(adev->audio_route, mixer_path);
ALOGV("%s: exit", __func__);
return 0;
}
-static int enable_snd_device(struct audio_device *adev,
- snd_device_t snd_device,
- bool update_mixer)
+int enable_snd_device(struct audio_device *adev,
+ snd_device_t snd_device)
{
if (snd_device < SND_DEVICE_MIN ||
snd_device >= SND_DEVICE_MAX) {
@@ -231,18 +291,15 @@
return -EINVAL;
}
- ALOGV("%s: snd_device(%d: %s)", __func__,
- snd_device, platform_get_snd_device_name(snd_device));
- audio_route_apply_path(adev->audio_route, platform_get_snd_device_name(snd_device));
- if (update_mixer)
- audio_route_update_mixer(adev->audio_route);
+ const char * dev_path = platform_get_snd_device_name(snd_device);
+ ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, dev_path);
+ audio_route_apply_and_update_path(adev->audio_route, dev_path);
return 0;
}
-static int disable_snd_device(struct audio_device *adev,
- snd_device_t snd_device,
- bool update_mixer)
+int disable_snd_device(struct audio_device *adev,
+ snd_device_t snd_device)
{
if (snd_device < SND_DEVICE_MIN ||
snd_device >= SND_DEVICE_MAX) {
@@ -255,11 +312,9 @@
}
adev->snd_dev_ref_cnt[snd_device]--;
if (adev->snd_dev_ref_cnt[snd_device] == 0) {
- ALOGV("%s: snd_device(%d: %s)", __func__,
- snd_device, platform_get_snd_device_name(snd_device));
- audio_route_reset_path(adev->audio_route, platform_get_snd_device_name(snd_device));
- if (update_mixer)
- audio_route_update_mixer(adev->audio_route);
+ const char * dev_path = platform_get_snd_device_name(snd_device);
+ ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, dev_path);
+ audio_route_reset_and_update_path(adev->audio_route, dev_path);
}
return 0;
}
@@ -297,33 +352,27 @@
ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
__func__, use_case_table[usecase->id],
platform_get_snd_device_name(usecase->out_snd_device));
- disable_audio_route(adev, usecase, false);
+ disable_audio_route(adev, usecase);
switch_device[usecase->id] = true;
num_uc_to_switch++;
}
}
if (num_uc_to_switch) {
- /* Make sure all the streams are de-routed before disabling the device */
- audio_route_update_mixer(adev->audio_route);
-
list_for_each(node, &adev->usecase_list) {
usecase = node_to_item(node, struct audio_usecase, list);
if (switch_device[usecase->id]) {
- disable_snd_device(adev, usecase->out_snd_device, false);
+ disable_snd_device(adev, usecase->out_snd_device);
}
}
list_for_each(node, &adev->usecase_list) {
usecase = node_to_item(node, struct audio_usecase, list);
if (switch_device[usecase->id]) {
- enable_snd_device(adev, snd_device, false);
+ enable_snd_device(adev, snd_device);
}
}
- /* Make sure new snd device is enabled before re-routing the streams */
- audio_route_update_mixer(adev->audio_route);
-
/* Re-route all the usecases on the shared backend other than the
specified usecase to new snd devices */
list_for_each(node, &adev->usecase_list) {
@@ -331,11 +380,9 @@
/* Update the out_snd_device only before enabling the audio route */
if (switch_device[usecase->id] ) {
usecase->out_snd_device = snd_device;
- enable_audio_route(adev, usecase, false);
+ enable_audio_route(adev, usecase);
}
}
-
- audio_route_update_mixer(adev->audio_route);
}
}
@@ -369,27 +416,27 @@
ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
__func__, use_case_table[usecase->id],
platform_get_snd_device_name(usecase->in_snd_device));
- disable_audio_route(adev, usecase, false);
+ disable_audio_route(adev, usecase);
switch_device[usecase->id] = true;
num_uc_to_switch++;
}
}
if (num_uc_to_switch) {
- /* Make sure all the streams are de-routed before disabling the device */
- audio_route_update_mixer(adev->audio_route);
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (switch_device[usecase->id]) {
+ disable_snd_device(adev, usecase->in_snd_device);
+ }
+ }
list_for_each(node, &adev->usecase_list) {
usecase = node_to_item(node, struct audio_usecase, list);
if (switch_device[usecase->id]) {
- disable_snd_device(adev, usecase->in_snd_device, false);
- enable_snd_device(adev, snd_device, false);
+ enable_snd_device(adev, snd_device);
}
}
- /* Make sure new snd device is enabled before re-routing the streams */
- audio_route_update_mixer(adev->audio_route);
-
/* Re-route all the usecases on the shared backend other than the
specified usecase to new snd devices */
list_for_each(node, &adev->usecase_list) {
@@ -397,15 +444,12 @@
/* Update the in_snd_device only before enabling the audio route */
if (switch_device[usecase->id] ) {
usecase->in_snd_device = snd_device;
- enable_audio_route(adev, usecase, false);
+ enable_audio_route(adev, usecase);
}
}
-
- audio_route_update_mixer(adev->audio_route);
}
}
-
/* must be called with hw device mutex locked */
static int read_hdmi_channel_masks(struct stream_out *out)
{
@@ -434,8 +478,23 @@
return ret;
}
-static struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
- audio_usecase_t uc_id)
+static audio_usecase_t get_voice_usecase_id_from_list(struct audio_device *adev)
+{
+ struct audio_usecase *usecase;
+ struct listnode *node;
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->type == VOICE_CALL) {
+ ALOGV("%s: usecase id %d", __func__, usecase->id);
+ return usecase->id;
+ }
+ }
+ return USECASE_INVALID;
+}
+
+struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
+ audio_usecase_t uc_id)
{
struct audio_usecase *usecase;
struct listnode *node;
@@ -448,13 +507,15 @@
return NULL;
}
-static int select_devices(struct audio_device *adev,
- audio_usecase_t uc_id)
+int select_devices(struct audio_device *adev,
+ audio_usecase_t uc_id)
{
snd_device_t out_snd_device = SND_DEVICE_NONE;
snd_device_t in_snd_device = SND_DEVICE_NONE;
struct audio_usecase *usecase = NULL;
struct audio_usecase *vc_usecase = NULL;
+ struct audio_usecase *hfp_usecase = NULL;
+ audio_usecase_t hfp_ucid;
struct listnode *node;
int status = 0;
@@ -464,7 +525,8 @@
return -EINVAL;
}
- if (usecase->type == VOICE_CALL) {
+ if ((usecase->type == VOICE_CALL) ||
+ (usecase->type == PCM_HFP_CALL)) {
out_snd_device = platform_get_output_snd_device(adev->platform,
usecase->stream.out->devices);
in_snd_device = platform_get_input_snd_device(adev->platform, usecase->stream.out->devices);
@@ -477,12 +539,22 @@
* usecase. This is to avoid switching devices for voice call when
* check_usecases_codec_backend() is called below.
*/
- if (adev->in_call) {
- vc_usecase = get_usecase_from_list(adev, USECASE_VOICE_CALL);
- if (vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
+ if (voice_is_in_call(adev)) {
+ vc_usecase = get_usecase_from_list(adev,
+ get_voice_usecase_id_from_list(adev));
+ if ((vc_usecase != NULL) &&
+ ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
+ (usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL))) {
in_snd_device = vc_usecase->in_snd_device;
out_snd_device = vc_usecase->out_snd_device;
}
+ } else if (audio_extn_hfp_is_active(adev)) {
+ hfp_ucid = audio_extn_hfp_get_usecase();
+ hfp_usecase = get_usecase_from_list(adev, hfp_ucid);
+ if (hfp_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
+ in_snd_device = hfp_usecase->in_snd_device;
+ out_snd_device = hfp_usecase->out_snd_device;
+ }
}
if (usecase->type == PCM_PLAYBACK) {
usecase->devices = usecase->stream.out->devices;
@@ -500,14 +572,14 @@
usecase->devices = usecase->stream.in->device;
out_snd_device = SND_DEVICE_NONE;
if (in_snd_device == SND_DEVICE_NONE) {
+ audio_devices_t out_device = AUDIO_DEVICE_NONE;
if (adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
adev->primary_output && !adev->primary_output->standby) {
- in_snd_device = platform_get_input_snd_device(adev->platform,
- adev->primary_output->devices);
- } else {
- in_snd_device = platform_get_input_snd_device(adev->platform,
- AUDIO_DEVICE_NONE);
+ out_device = adev->primary_output->devices;
+ } else if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY) {
+ out_device = AUDIO_DEVICE_OUT_TELEPHONY_TX;
}
+ in_snd_device = platform_get_input_snd_device(adev->platform, out_device);
}
}
}
@@ -526,31 +598,45 @@
* and enable both RX and TX devices though one of them is same as current
* device.
*/
- if (usecase->type == VOICE_CALL) {
+ if ((usecase->type == VOICE_CALL) &&
+ (usecase->in_snd_device != SND_DEVICE_NONE) &&
+ (usecase->out_snd_device != SND_DEVICE_NONE)) {
status = platform_switch_voice_call_device_pre(adev->platform);
}
/* Disable current sound devices */
if (usecase->out_snd_device != SND_DEVICE_NONE) {
- disable_audio_route(adev, usecase, true);
- disable_snd_device(adev, usecase->out_snd_device, false);
+ disable_audio_route(adev, usecase);
+ disable_snd_device(adev, usecase->out_snd_device);
}
if (usecase->in_snd_device != SND_DEVICE_NONE) {
- disable_audio_route(adev, usecase, true);
- disable_snd_device(adev, usecase->in_snd_device, false);
+ disable_audio_route(adev, usecase);
+ disable_snd_device(adev, usecase->in_snd_device);
+ }
+
+ /* Applicable only on the targets that has external modem.
+ * New device information should be sent to modem before enabling
+ * the devices to reduce in-call device switch time.
+ */
+ if ((usecase->type == VOICE_CALL) &&
+ (usecase->in_snd_device != SND_DEVICE_NONE) &&
+ (usecase->out_snd_device != SND_DEVICE_NONE)) {
+ status = platform_switch_voice_call_enable_device_config(adev->platform,
+ out_snd_device,
+ in_snd_device);
}
/* Enable new sound devices */
if (out_snd_device != SND_DEVICE_NONE) {
if (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)
check_usecases_codec_backend(adev, usecase, out_snd_device);
- enable_snd_device(adev, out_snd_device, false);
+ enable_snd_device(adev, out_snd_device);
}
if (in_snd_device != SND_DEVICE_NONE) {
check_and_route_capture_usecases(adev, usecase, in_snd_device);
- enable_snd_device(adev, in_snd_device, false);
+ enable_snd_device(adev, in_snd_device);
}
if (usecase->type == VOICE_CALL)
@@ -558,12 +644,19 @@
out_snd_device,
in_snd_device);
- audio_route_update_mixer(adev->audio_route);
-
usecase->in_snd_device = in_snd_device;
usecase->out_snd_device = out_snd_device;
- enable_audio_route(adev, usecase, true);
+ enable_audio_route(adev, usecase);
+
+ /* Applicable only on the targets that has external modem.
+ * Enable device command should be sent to modem only after
+ * enabling voice call mixer controls
+ */
+ if (usecase->type == VOICE_CALL)
+ status = platform_switch_voice_call_usecase_route_post(adev->platform,
+ out_snd_device,
+ in_snd_device);
return status;
}
@@ -586,10 +679,10 @@
}
/* 1. Disable stream specific mixer controls */
- disable_audio_route(adev, uc_info, true);
+ disable_audio_route(adev, uc_info);
/* 2. Disable the tx device */
- disable_snd_device(adev, uc_info->in_snd_device, true);
+ disable_snd_device(adev, uc_info->in_snd_device);
list_remove(&uc_info->list);
free(uc_info);
@@ -627,16 +720,35 @@
select_devices(adev, in->usecase);
ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
- __func__, SOUND_CARD, in->pcm_device_id, in->config.channels);
- in->pcm = pcm_open(SOUND_CARD, in->pcm_device_id,
- PCM_IN, &in->config);
- if (in->pcm && !pcm_is_ready(in->pcm)) {
- ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
- pcm_close(in->pcm);
- in->pcm = NULL;
- ret = -EIO;
- goto error_open;
+ __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
+
+ unsigned int flags = PCM_IN;
+ unsigned int pcm_open_retry_count = 0;
+
+ if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) {
+ flags |= PCM_MMAP | PCM_NOIRQ;
+ pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
}
+
+ while (1) {
+ in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
+ flags, &in->config);
+ if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
+ if (in->pcm != NULL) {
+ pcm_close(in->pcm);
+ in->pcm = NULL;
+ }
+ if (pcm_open_retry_count-- == 0) {
+ ret = -EIO;
+ goto error_open;
+ }
+ usleep(PROXY_OPEN_WAIT_TIME * 1000);
+ continue;
+ }
+ break;
+ }
+
ALOGV("%s: exit", __func__);
return ret;
@@ -847,7 +959,7 @@
usecase = node_to_item(node, struct audio_usecase, list);
if (usecase->type == PCM_PLAYBACK &&
usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
- disable_audio_route(adev, usecase, true);
+ disable_audio_route(adev, usecase);
}
}
@@ -859,7 +971,7 @@
usecase = node_to_item(node, struct audio_usecase, list);
if (usecase->type == PCM_PLAYBACK &&
usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
- enable_audio_route(adev, usecase, true);
+ enable_audio_route(adev, usecase);
}
}
@@ -881,19 +993,24 @@
return -EINVAL;
}
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD &&
- adev->visualizer_stop_output != NULL)
- adev->visualizer_stop_output(out->handle);
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (adev->visualizer_stop_output != NULL)
+ adev->visualizer_stop_output(out->handle, out->pcm_device_id);
+ if (adev->offload_effects_stop_output != NULL)
+ adev->offload_effects_stop_output(out->handle, out->pcm_device_id);
+ }
/* 1. Get and set stream specific mixer controls */
- disable_audio_route(adev, uc_info, true);
+ disable_audio_route(adev, uc_info);
/* 2. Disable the rx device */
- disable_snd_device(adev, uc_info->out_snd_device, true);
+ disable_snd_device(adev, uc_info->out_snd_device);
list_remove(&uc_info->list);
free(uc_info);
+ audio_extn_extspk_update(adev->extspk);
+
/* Must be called after removing the usecase from list */
if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
check_and_set_hdmi_channels(adev, DEFAULT_HDMI_OUT_CHANNELS);
@@ -934,21 +1051,40 @@
select_devices(adev, out->usecase);
- ALOGV("%s: Opening PCM device card_id(%d) device_id(%d)",
- __func__, 0, out->pcm_device_id);
+ audio_extn_extspk_update(adev->extspk);
+
+ ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)",
+ __func__, adev->snd_card, out->pcm_device_id, out->config.format);
if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) {
- out->pcm = pcm_open(SOUND_CARD, out->pcm_device_id,
- PCM_OUT | PCM_MONOTONIC, &out->config);
- if (out->pcm && !pcm_is_ready(out->pcm)) {
- ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
- pcm_close(out->pcm);
- out->pcm = NULL;
- ret = -EIO;
- goto error_open;
+ unsigned int flags = PCM_OUT;
+ unsigned int pcm_open_retry_count = 0;
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) {
+ flags |= PCM_MMAP | PCM_NOIRQ;
+ pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
+ } else
+ flags |= PCM_MONOTONIC;
+
+ while (1) {
+ out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
+ flags, &out->config);
+ if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
+ if (out->pcm != NULL) {
+ pcm_close(out->pcm);
+ out->pcm = NULL;
+ }
+ if (pcm_open_retry_count-- == 0) {
+ ret = -EIO;
+ goto error_open;
+ }
+ usleep(PROXY_OPEN_WAIT_TIME * 1000);
+ continue;
+ }
+ break;
}
} else {
out->pcm = NULL;
- out->compr = compress_open(SOUND_CARD, out->pcm_device_id,
+ out->compr = compress_open(adev->snd_card, out->pcm_device_id,
COMPRESS_IN, &out->compr_config);
if (out->compr && !is_compress_ready(out->compr)) {
ALOGE("%s: %s", __func__, compress_get_error(out->compr));
@@ -961,7 +1097,9 @@
compress_nonblock(out->compr, out->non_blocking);
if (adev->visualizer_start_output != NULL)
- adev->visualizer_start_output(out->handle);
+ adev->visualizer_start_output(out->handle, out->pcm_device_id);
+ if (adev->offload_effects_start_output != NULL)
+ adev->offload_effects_start_output(out->handle, out->pcm_device_id);
}
ALOGV("%s: exit", __func__);
return 0;
@@ -971,120 +1109,6 @@
return ret;
}
-static int stop_voice_call(struct audio_device *adev)
-{
- int i, ret = 0;
- struct audio_usecase *uc_info;
-
- ALOGV("%s: enter", __func__);
- adev->in_call = false;
-
- ret = platform_stop_voice_call(adev->platform);
-
- /* 1. Close the PCM devices */
- if (adev->voice_call_rx) {
- pcm_close(adev->voice_call_rx);
- adev->voice_call_rx = NULL;
- }
- if (adev->voice_call_tx) {
- pcm_close(adev->voice_call_tx);
- adev->voice_call_tx = NULL;
- }
-
- uc_info = get_usecase_from_list(adev, USECASE_VOICE_CALL);
- if (uc_info == NULL) {
- ALOGE("%s: Could not find the usecase (%d) in the list",
- __func__, USECASE_VOICE_CALL);
- return -EINVAL;
- }
-
- /* 2. Get and set stream specific mixer controls */
- disable_audio_route(adev, uc_info, true);
-
- /* 3. Disable the rx and tx devices */
- disable_snd_device(adev, uc_info->out_snd_device, false);
- disable_snd_device(adev, uc_info->in_snd_device, true);
-
- list_remove(&uc_info->list);
- free(uc_info);
-
- ALOGV("%s: exit: status(%d)", __func__, ret);
- return ret;
-}
-
-static int start_voice_call(struct audio_device *adev)
-{
- int i, ret = 0;
- struct audio_usecase *uc_info;
- int pcm_dev_rx_id, pcm_dev_tx_id;
-
- ALOGV("%s: enter", __func__);
-
- uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
- uc_info->id = USECASE_VOICE_CALL;
- uc_info->type = VOICE_CALL;
- uc_info->stream.out = adev->primary_output;
- uc_info->devices = adev->primary_output->devices;
- uc_info->in_snd_device = SND_DEVICE_NONE;
- uc_info->out_snd_device = SND_DEVICE_NONE;
-
- list_add_tail(&adev->usecase_list, &uc_info->list);
-
- select_devices(adev, USECASE_VOICE_CALL);
-
- pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
- pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
-
- if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) {
- ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)",
- __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
- ret = -EIO;
- goto error_start_voice;
- }
-
- ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
- __func__, SOUND_CARD, pcm_dev_rx_id);
- adev->voice_call_rx = pcm_open(SOUND_CARD,
- pcm_dev_rx_id,
- PCM_OUT | PCM_MONOTONIC, &pcm_config_voice_call);
- if (adev->voice_call_rx && !pcm_is_ready(adev->voice_call_rx)) {
- ALOGE("%s: %s", __func__, pcm_get_error(adev->voice_call_rx));
- ret = -EIO;
- goto error_start_voice;
- }
-
- ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
- __func__, SOUND_CARD, pcm_dev_tx_id);
- adev->voice_call_tx = pcm_open(SOUND_CARD,
- pcm_dev_tx_id,
- PCM_IN, &pcm_config_voice_call);
- if (adev->voice_call_tx && !pcm_is_ready(adev->voice_call_tx)) {
- ALOGE("%s: %s", __func__, pcm_get_error(adev->voice_call_tx));
- ret = -EIO;
- goto error_start_voice;
- }
-
- /* set cached volume */
- set_voice_volume_l(adev, adev->voice_volume);
-
- pcm_start(adev->voice_call_rx);
- pcm_start(adev->voice_call_tx);
-
- ret = platform_start_voice_call(adev->platform);
- if (ret < 0) {
- ALOGE("%s: platform_start_voice_call error %d\n", __func__, ret);
- goto error_start_voice;
- }
- adev->in_call = true;
- return 0;
-
-error_start_voice:
- stop_voice_call(adev);
-
- ALOGD("%s: exit: status(%d)", __func__, ret);
- return ret;
-}
-
static int check_input_parameters(uint32_t sample_rate,
audio_format_t format,
int channel_count)
@@ -1113,7 +1137,8 @@
static size_t get_input_buffer_size(uint32_t sample_rate,
audio_format_t format,
- int channel_count)
+ int channel_count,
+ bool is_low_latency)
{
size_t size = 0;
@@ -1121,13 +1146,19 @@
return 0;
size = (sample_rate * AUDIO_CAPTURE_PERIOD_DURATION_MSEC) / 1000;
+ if (is_low_latency)
+ size = configured_low_latency_capture_period_size;
/* ToDo: should use frame_size computed based on the format and
channel_count here. */
size *= sizeof(short) * channel_count;
- /* make sure the size is multiple of 64 */
- size += 0x3f;
- size &= ~0x3f;
+ /* make sure the size is multiple of 32 bytes
+ * At 48 kHz mono 16-bit PCM:
+ * 5.000 ms = 240 frames = 15*16*1*2 = 480, a whole multiple of 32 (15)
+ * 3.333 ms = 160 frames = 10*16*1*2 = 320, a whole multiple of 32 (10)
+ */
+ size += 0x1f;
+ size &= ~0x1f;
return size;
}
@@ -1139,7 +1170,7 @@
return out->sample_rate;
}
-static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+static int out_set_sample_rate(struct audio_stream *stream __unused, uint32_t rate __unused)
{
return -ENOSYS;
}
@@ -1151,8 +1182,8 @@
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
return out->compr_config.fragment_size;
}
-
- return out->config.period_size * audio_stream_frame_size(stream);
+ return out->config.period_size *
+ audio_stream_out_frame_size((const struct audio_stream_out *)stream);
}
static uint32_t out_get_channels(const struct audio_stream *stream)
@@ -1169,7 +1200,7 @@
return out->format;
}
-static int out_set_format(struct audio_stream *stream, audio_format_t format)
+static int out_set_format(struct audio_stream *stream __unused, audio_format_t format __unused)
{
return -ENOSYS;
}
@@ -1208,7 +1239,7 @@
return 0;
}
-static int out_dump(const struct audio_stream *stream, int fd)
+static int out_dump(const struct audio_stream *stream __unused, int fd __unused)
{
return 0;
}
@@ -1245,6 +1276,10 @@
return 0;
}
+static bool output_drives_call(struct audio_device *adev, struct stream_out *out)
+{
+ return out == adev->primary_output || out == adev->voice_tx_output;
+}
static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
{
@@ -1256,6 +1291,7 @@
char value[32];
int ret, val = 0;
bool select_new_device = false;
+ int status = 0;
ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s",
__func__, out->usecase, use_case_table[out->usecase], kvpairs);
@@ -1302,22 +1338,24 @@
if (!out->standby)
select_devices(adev, out->usecase);
- if ((adev->mode == AUDIO_MODE_IN_CALL) && !adev->in_call &&
- (out == adev->primary_output)) {
- start_voice_call(adev);
- } else if ((adev->mode == AUDIO_MODE_IN_CALL) && adev->in_call &&
- (out == adev->primary_output)) {
- select_devices(adev, USECASE_VOICE_CALL);
+ if (output_drives_call(adev, out)) {
+ if (!voice_is_in_call(adev)) {
+ if (adev->mode == AUDIO_MODE_IN_CALL) {
+ adev->current_call_output = out;
+ ret = voice_start_call(adev);
+ }
+ } else {
+ adev->current_call_output = out;
+ voice_update_devices_for_all_voice_usecases(adev);
+ }
}
}
- if ((adev->mode == AUDIO_MODE_NORMAL) && adev->in_call &&
- (out == adev->primary_output)) {
- stop_voice_call(adev);
- }
-
pthread_mutex_unlock(&adev->lock);
pthread_mutex_unlock(&out->lock);
+
+ /*handles device and call state changes*/
+ audio_extn_extspk_update(adev->extspk);
}
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
@@ -1325,8 +1363,8 @@
}
str_parms_destroy(parms);
- ALOGV("%s: exit: code(%d)", __func__, ret);
- return ret;
+ ALOGV("%s: exit: code(%d)", __func__, status);
+ return status;
}
static char* out_get_parameters(const struct audio_stream *stream, const char *keys)
@@ -1393,12 +1431,19 @@
const char *mixer_ctl_name = "Compress Playback Volume";
struct audio_device *adev = out->dev;
struct mixer_ctl *ctl;
-
ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
if (!ctl) {
- ALOGE("%s: Could not get ctl for mixer cmd - %s",
- __func__, mixer_ctl_name);
- return -EINVAL;
+ /* try with the control based on device id */
+ int pcm_device_id = platform_get_pcm_device_id(out->usecase,
+ PCM_PLAYBACK);
+ char ctl_name[128] = {0};
+ snprintf(ctl_name, sizeof(ctl_name),
+ "Compress Playback %d Volume", pcm_device_id);
+ ctl = mixer_get_ctl_by_name(adev->mixer, ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get volume ctl mixer cmd", __func__);
+ return -EINVAL;
+ }
}
volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX);
volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
@@ -1454,7 +1499,11 @@
if (out->muted)
memset((void *)buffer, 0, bytes);
ALOGVV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes);
- ret = pcm_write(out->pcm, (void *)buffer, bytes);
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) {
+ ret = pcm_mmap_write(out->pcm, (void *)buffer, bytes);
+ }
+ else
+ ret = pcm_write(out->pcm, (void *)buffer, bytes);
if (ret == 0)
out->written += bytes / (out->config.channels * sizeof(short));
}
@@ -1467,7 +1516,7 @@
if (out->pcm)
ALOGE("%s: error %d - %s", __func__, ret, pcm_get_error(out->pcm));
out_standby(&out->stream.common);
- usleep(bytes * 1000000 / audio_stream_frame_size(&out->stream.common) /
+ usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
out_get_sample_rate(&out->stream.common));
}
return bytes;
@@ -1492,18 +1541,20 @@
return -EINVAL;
}
-static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+static int out_add_audio_effect(const struct audio_stream *stream __unused,
+ effect_handle_t effect __unused)
{
return 0;
}
-static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+static int out_remove_audio_effect(const struct audio_stream *stream __unused,
+ effect_handle_t effect __unused)
{
return 0;
}
-static int out_get_next_write_timestamp(const struct audio_stream_out *stream,
- int64_t *timestamp)
+static int out_get_next_write_timestamp(const struct audio_stream_out *stream __unused,
+ int64_t *timestamp __unused)
{
return -EINVAL;
}
@@ -1636,7 +1687,7 @@
return in->config.rate;
}
-static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+static int in_set_sample_rate(struct audio_stream *stream __unused, uint32_t rate __unused)
{
return -ENOSYS;
}
@@ -1645,7 +1696,8 @@
{
struct stream_in *in = (struct stream_in *)stream;
- return in->config.period_size * audio_stream_frame_size(stream);
+ return in->config.period_size *
+ audio_stream_in_frame_size((const struct audio_stream_in *)stream);
}
static uint32_t in_get_channels(const struct audio_stream *stream)
@@ -1655,12 +1707,12 @@
return in->channel_mask;
}
-static audio_format_t in_get_format(const struct audio_stream *stream)
+static audio_format_t in_get_format(const struct audio_stream *stream __unused)
{
return AUDIO_FORMAT_PCM_16_BIT;
}
-static int in_set_format(struct audio_stream *stream, audio_format_t format)
+static int in_set_format(struct audio_stream *stream __unused, audio_format_t format __unused)
{
return -ENOSYS;
}
@@ -1679,6 +1731,8 @@
pcm_close(in->pcm);
in->pcm = NULL;
}
+ adev->enable_voicerx = false;
+ platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE );
status = stop_input_stream(in);
pthread_mutex_unlock(&adev->lock);
}
@@ -1687,7 +1741,7 @@
return status;
}
-static int in_dump(const struct audio_stream *stream, int fd)
+static int in_dump(const struct audio_stream *stream __unused, int fd __unused)
{
return 0;
}
@@ -1700,6 +1754,7 @@
char *str;
char value[32];
int ret, val = 0;
+ int status = 0;
ALOGV("%s: enter: kvpairs=%s", __func__, kvpairs);
parms = str_parms_create_str(kvpairs);
@@ -1717,13 +1772,14 @@
}
ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
+
if (ret >= 0) {
val = atoi(value);
- if ((in->device != val) && (val != 0)) {
+ if (((int)in->device != val) && (val != 0)) {
in->device = val;
/* If recording is in progress, change the tx device to new device */
if (!in->standby)
- ret = select_devices(adev, in->usecase);
+ status = select_devices(adev, in->usecase);
}
}
@@ -1731,17 +1787,17 @@
pthread_mutex_unlock(&in->lock);
str_parms_destroy(parms);
- ALOGV("%s: exit: status(%d)", __func__, ret);
- return ret;
+ ALOGV("%s: exit: status(%d)", __func__, status);
+ return status;
}
-static char* in_get_parameters(const struct audio_stream *stream,
- const char *keys)
+static char* in_get_parameters(const struct audio_stream *stream __unused,
+ const char *keys __unused)
{
return strdup("");
}
-static int in_set_gain(struct audio_stream_in *stream, float gain)
+static int in_set_gain(struct audio_stream_in *stream __unused, float gain __unused)
{
return 0;
}
@@ -1765,14 +1821,18 @@
}
if (in->pcm) {
- ret = pcm_read(in->pcm, buffer, bytes);
+ if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) {
+ ret = pcm_mmap_read(in->pcm, buffer, bytes);
+ } else
+ ret = pcm_read(in->pcm, buffer, bytes);
}
/*
* Instead of writing zeroes here, we could trust the hardware
* to always provide zeroes when muted.
+ * No need to acquire adev->lock to read mic_muted here as we don't change its state.
*/
- if (ret == 0 && adev->mic_mute)
+ if (ret == 0 && adev->mic_muted && in->usecase != USECASE_AUDIO_RECORD_AFE_PROXY)
memset(buffer, 0, bytes);
exit:
@@ -1781,13 +1841,13 @@
if (ret != 0) {
in_standby(&in->stream.common);
ALOGV("%s: read failed - sleeping for buffer duration", __func__);
- usleep(bytes * 1000000 / audio_stream_frame_size(&in->stream.common) /
+ usleep(bytes * 1000000 / audio_stream_in_frame_size(stream) /
in_get_sample_rate(&in->stream.common));
}
return bytes;
}
-static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
+static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream __unused)
{
return 0;
}
@@ -1797,6 +1857,7 @@
bool enable)
{
struct stream_in *in = (struct stream_in *)stream;
+ struct audio_device *adev = in->dev;
int status = 0;
effect_descriptor_t desc;
@@ -1810,6 +1871,24 @@
in->enable_aec != enable &&
(memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0)) {
in->enable_aec = enable;
+ if (!enable)
+ platform_set_echo_reference(in->dev, enable, AUDIO_DEVICE_NONE);
+ adev->enable_voicerx = enable;
+ struct audio_usecase *usecase;
+ struct listnode *node;
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->type == PCM_PLAYBACK) {
+ select_devices(adev, usecase->id);
+ break;
+ }
+ }
+ if (!in->standby)
+ select_devices(in->dev, in->usecase);
+ }
+ if (in->enable_ns != enable &&
+ (memcmp(&desc.type, FX_IID_NS, sizeof(effect_uuid_t)) == 0)) {
+ in->enable_ns = enable;
if (!in->standby)
select_devices(in->dev, in->usecase);
}
@@ -1838,7 +1917,8 @@
audio_devices_t devices,
audio_output_flags_t flags,
struct audio_config *config,
- struct audio_stream_out **stream_out)
+ struct audio_stream_out **stream_out,
+ const char *address __unused)
{
struct audio_device *adev = (struct audio_device *)dev;
struct stream_out *out;
@@ -1881,12 +1961,8 @@
out->usecase = USECASE_AUDIO_PLAYBACK_MULTI_CH;
out->config = pcm_config_hdmi_multi;
out->config.rate = config->sample_rate;
- out->config.channels = popcount(out->channel_mask);
+ out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2);
- } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
- out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
- out->config = pcm_config_deep_buffer;
- out->sample_rate = out->config.rate;
} else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version ||
config->offload_info.size != AUDIO_INFO_INITIALIZER.size) {
@@ -1926,7 +2002,7 @@
out->compr_config.codec->bit_rate =
config->offload_info.bit_rate;
out->compr_config.codec->ch_in =
- popcount(config->channel_mask);
+ audio_channel_count_from_out_mask(config->channel_mask);
out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
@@ -1937,14 +2013,58 @@
ALOGV("%s: offloaded output offload_info version %04x bit rate %d",
__func__, config->offload_info.version,
config->offload_info.bit_rate);
+ } else if (out->devices == AUDIO_DEVICE_OUT_TELEPHONY_TX) {
+ if (config->sample_rate == 0)
+ config->sample_rate = AFE_PROXY_SAMPLING_RATE;
+ if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
+ config->sample_rate != 8000) {
+ config->sample_rate = AFE_PROXY_SAMPLING_RATE;
+ ret = -EINVAL;
+ goto error_open;
+ }
+ out->sample_rate = config->sample_rate;
+ out->config.rate = config->sample_rate;
+ if (config->format == AUDIO_FORMAT_DEFAULT)
+ config->format = AUDIO_FORMAT_PCM_16_BIT;
+ if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
+ config->format = AUDIO_FORMAT_PCM_16_BIT;
+ ret = -EINVAL;
+ goto error_open;
+ }
+ out->format = config->format;
+ out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
+ out->config = pcm_config_afe_proxy_playback;
+ adev->voice_tx_output = out;
} else {
- out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
- out->config = pcm_config_low_latency;
+ if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
+ out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
+ out->config = pcm_config_deep_buffer;
+ } else {
+ out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
+ out->config = pcm_config_low_latency;
+ }
+ if (config->format != audio_format_from_pcm_format(out->config.format)) {
+ if (k_enable_extended_precision
+ && pcm_params_format_test(adev->use_case_table[out->usecase],
+ pcm_format_from_audio_format(config->format))) {
+ out->config.format = pcm_format_from_audio_format(config->format);
+ /* out->format already set to config->format */
+ } else {
+ /* deny the externally proposed config format
+ * and use the one specified in audio_hw layer configuration.
+ * Note: out->format is returned by out->stream.common.get_format()
+ * and is used to set config->format in the code several lines below.
+ */
+ out->format = audio_format_from_pcm_format(out->config.format);
+ }
+ }
out->sample_rate = out->config.rate;
}
+ ALOGV("%s: Usecase(%s) config->format %#x out->config.format %#x\n",
+ __func__, use_case_table[out->usecase], config->format, out->config.format);
if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) {
- if(adev->primary_output == NULL)
+ if (adev->primary_output == NULL)
adev->primary_output = out;
else {
ALOGE("%s: Primary output is already opened", __func__);
@@ -2004,7 +2124,7 @@
return ret;
}
-static void adev_close_output_stream(struct audio_hw_device *dev,
+static void adev_close_output_stream(struct audio_hw_device *dev __unused,
struct audio_stream_out *stream)
{
struct stream_out *out = (struct stream_out *)stream;
@@ -2018,6 +2138,10 @@
if (out->compr_config.codec != NULL)
free(out->compr_config.codec);
}
+
+ if (adev->voice_tx_output == out)
+ adev->voice_tx_output = NULL;
+
pthread_cond_destroy(&out->cond);
pthread_mutex_destroy(&out->lock);
free(stream);
@@ -2032,33 +2156,16 @@
char value[32];
int val;
int ret;
+ int status = 0;
- ALOGV("%s: enter: %s", __func__, kvpairs);
+ ALOGD("%s: enter: %s", __func__, kvpairs);
+
+ pthread_mutex_lock(&adev->lock);
parms = str_parms_create_str(kvpairs);
- ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value));
- if (ret >= 0) {
- int tty_mode;
-
- if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_OFF) == 0)
- tty_mode = TTY_MODE_OFF;
- else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_VCO) == 0)
- tty_mode = TTY_MODE_VCO;
- else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_HCO) == 0)
- tty_mode = TTY_MODE_HCO;
- else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_FULL) == 0)
- tty_mode = TTY_MODE_FULL;
- else
- return -EINVAL;
-
- pthread_mutex_lock(&adev->lock);
- if (tty_mode != adev->tty_mode) {
- adev->tty_mode = tty_mode;
- adev->acdb_settings = (adev->acdb_settings & TTY_MODE_CLEAR) | tty_mode;
- if (adev->in_call)
- select_devices(adev, USECASE_VOICE_CALL);
- }
- pthread_mutex_unlock(&adev->lock);
+ status = voice_set_parameters(adev, parms);
+ if (status != 0) {
+ goto done;
}
ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value));
@@ -2096,93 +2203,94 @@
break;
default:
ALOGE("%s: unexpected rotation of %d", __func__, val);
+ status = -EINVAL;
}
- pthread_mutex_lock(&adev->lock);
- if (adev->speaker_lr_swap != reverse_speakers) {
- adev->speaker_lr_swap = reverse_speakers;
- // only update the selected device if there is active pcm playback
- struct audio_usecase *usecase;
- struct listnode *node;
- list_for_each(node, &adev->usecase_list) {
- usecase = node_to_item(node, struct audio_usecase, list);
- if (usecase->type == PCM_PLAYBACK) {
- select_devices(adev, usecase->id);
- break;
+ if (status == 0) {
+ if (adev->speaker_lr_swap != reverse_speakers) {
+ adev->speaker_lr_swap = reverse_speakers;
+ // only update the selected device if there is active pcm playback
+ struct audio_usecase *usecase;
+ struct listnode *node;
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->type == PCM_PLAYBACK) {
+ select_devices(adev, usecase->id);
+ break;
+ }
}
}
}
- pthread_mutex_unlock(&adev->lock);
}
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_SCO_WB, value, sizeof(value));
+ if (ret >= 0) {
+ adev->bt_wb_speech_enabled = !strcmp(value, AUDIO_PARAMETER_VALUE_ON);
+ }
+
+ audio_extn_hfp_set_parameters(adev, parms);
+done:
str_parms_destroy(parms);
- ALOGV("%s: exit with code(%d)", __func__, ret);
- return ret;
+ pthread_mutex_unlock(&adev->lock);
+ ALOGV("%s: exit with code(%d)", __func__, status);
+ return status;
}
static char* adev_get_parameters(const struct audio_hw_device *dev,
const char *keys)
{
- return strdup("");
+ struct audio_device *adev = (struct audio_device *)dev;
+ struct str_parms *reply = str_parms_create();
+ struct str_parms *query = str_parms_create_str(keys);
+ char *str;
+
+ pthread_mutex_lock(&adev->lock);
+
+ voice_get_parameters(adev, query, reply);
+ str = str_parms_to_str(reply);
+ str_parms_destroy(query);
+ str_parms_destroy(reply);
+
+ pthread_mutex_unlock(&adev->lock);
+ ALOGV("%s: exit: returns - %s", __func__, str);
+ return str;
}
-static int adev_init_check(const struct audio_hw_device *dev)
+static int adev_init_check(const struct audio_hw_device *dev __unused)
{
return 0;
}
-/* always called with adev lock held */
-static int set_voice_volume_l(struct audio_device *adev, float volume)
-{
- int vol, err = 0;
-
- if (adev->mode == AUDIO_MODE_IN_CALL) {
- if (volume < 0.0) {
- volume = 0.0;
- } else if (volume > 1.0) {
- volume = 1.0;
- }
-
- vol = lrint(volume * 100.0);
-
- // Voice volume levels from android are mapped to driver volume levels as follows.
- // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0
- // So adjust the volume to get the correct volume index in driver
- vol = 100 - vol;
-
- err = platform_set_voice_volume(adev->platform, vol);
- }
- return err;
-}
-
static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
{
int ret;
struct audio_device *adev = (struct audio_device *)dev;
+
+ audio_extn_extspk_set_voice_vol(adev->extspk, volume);
+
pthread_mutex_lock(&adev->lock);
- /* cache volume */
- adev->voice_volume = volume;
- ret = set_voice_volume_l(adev, adev->voice_volume);
+ ret = voice_set_volume(adev, volume);
pthread_mutex_unlock(&adev->lock);
+
return ret;
}
-static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
+static int adev_set_master_volume(struct audio_hw_device *dev __unused, float volume __unused)
{
return -ENOSYS;
}
-static int adev_get_master_volume(struct audio_hw_device *dev,
- float *volume)
+static int adev_get_master_volume(struct audio_hw_device *dev __unused,
+ float *volume __unused)
{
return -ENOSYS;
}
-static int adev_set_master_mute(struct audio_hw_device *dev, bool muted)
+static int adev_set_master_mute(struct audio_hw_device *dev __unused, bool muted __unused)
{
return -ENOSYS;
}
-static int adev_get_master_mute(struct audio_hw_device *dev, bool *muted)
+static int adev_get_master_mute(struct audio_hw_device *dev __unused, bool *muted __unused)
{
return -ENOSYS;
}
@@ -2193,52 +2301,64 @@
pthread_mutex_lock(&adev->lock);
if (adev->mode != mode) {
+ ALOGD("%s: mode %d\n", __func__, mode);
adev->mode = mode;
+ if ((mode == AUDIO_MODE_NORMAL || mode == AUDIO_MODE_IN_COMMUNICATION) &&
+ voice_is_in_call(adev)) {
+ voice_stop_call(adev);
+ adev->current_call_output = NULL;
+ }
}
pthread_mutex_unlock(&adev->lock);
+
+ audio_extn_extspk_set_mode(adev->extspk, mode);
+
return 0;
}
static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
{
+ int ret;
struct audio_device *adev = (struct audio_device *)dev;
- int err = 0;
+ ALOGD("%s: state %d\n", __func__, state);
pthread_mutex_lock(&adev->lock);
- adev->mic_mute = state;
-
- err = platform_set_mic_mute(adev->platform, state);
+ ret = voice_set_mic_mute(adev, state);
+ adev->mic_muted = state;
pthread_mutex_unlock(&adev->lock);
- return err;
+
+ return ret;
}
static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
{
- struct audio_device *adev = (struct audio_device *)dev;
-
- *state = adev->mic_mute;
-
+ *state = voice_get_mic_mute((struct audio_device *)dev);
return 0;
}
-static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
+static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev __unused,
const struct audio_config *config)
{
- int channel_count = popcount(config->channel_mask);
+ int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
- return get_input_buffer_size(config->sample_rate, config->format, channel_count);
+ return get_input_buffer_size(config->sample_rate, config->format, channel_count,
+ false /* is_low_latency: since we don't know, be conservative */);
}
static int adev_open_input_stream(struct audio_hw_device *dev,
- audio_io_handle_t handle,
+ audio_io_handle_t handle __unused,
audio_devices_t devices,
struct audio_config *config,
- struct audio_stream_in **stream_in)
+ struct audio_stream_in **stream_in,
+ audio_input_flags_t flags,
+ const char *address __unused,
+ audio_source_t source )
{
struct audio_device *adev = (struct audio_device *)dev;
struct stream_in *in;
- int ret, buffer_size, frame_size;
- int channel_count = popcount(config->channel_mask);
+ int ret = 0, buffer_size, frame_size;
+ int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
+ bool is_low_latency = false;
ALOGV("%s: enter", __func__);
*stream_in = NULL;
@@ -2247,6 +2367,8 @@
in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
+ pthread_mutex_init(&in->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;
in->stream.common.get_buffer_size = in_get_buffer_size;
@@ -2264,22 +2386,52 @@
in->stream.get_input_frames_lost = in_get_input_frames_lost;
in->device = devices;
- in->source = AUDIO_SOURCE_DEFAULT;
+ in->source = source;
in->dev = adev;
in->standby = 1;
in->channel_mask = config->channel_mask;
/* Update config params with the requested sample rate and channels */
- in->usecase = USECASE_AUDIO_RECORD;
- in->config = pcm_config_audio_capture;
+ if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
+ if (config->sample_rate == 0)
+ config->sample_rate = AFE_PROXY_SAMPLING_RATE;
+ if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
+ config->sample_rate != 8000) {
+ config->sample_rate = AFE_PROXY_SAMPLING_RATE;
+ ret = -EINVAL;
+ goto err_open;
+ }
+ if (config->format == AUDIO_FORMAT_DEFAULT)
+ config->format = AUDIO_FORMAT_PCM_16_BIT;
+ if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
+ config->format = AUDIO_FORMAT_PCM_16_BIT;
+ ret = -EINVAL;
+ goto err_open;
+ }
+
+ in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY;
+ in->config = pcm_config_afe_proxy_record;
+ } else {
+ in->usecase = USECASE_AUDIO_RECORD;
+ if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE &&
+ (flags & AUDIO_INPUT_FLAG_FAST) != 0) {
+ is_low_latency = true;
+#if LOW_LATENCY_CAPTURE_USE_CASE
+ in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY;
+#endif
+ }
+ in->config = pcm_config_audio_capture;
+
+ frame_size = audio_stream_in_frame_size(&in->stream);
+ buffer_size = get_input_buffer_size(config->sample_rate,
+ config->format,
+ channel_count,
+ is_low_latency);
+ in->config.period_size = buffer_size / frame_size;
+ }
in->config.channels = channel_count;
in->config.rate = config->sample_rate;
- frame_size = audio_stream_frame_size((struct audio_stream *)in);
- buffer_size = get_input_buffer_size(config->sample_rate,
- config->format,
- channel_count);
- in->config.period_size = buffer_size / frame_size;
*stream_in = &in->stream;
ALOGV("%s: exit", __func__);
@@ -2291,7 +2443,7 @@
return ret;
}
-static void adev_close_input_stream(struct audio_hw_device *dev,
+static void adev_close_input_stream(struct audio_hw_device *dev __unused,
struct audio_stream_in *stream)
{
ALOGV("%s", __func__);
@@ -2302,21 +2454,177 @@
return;
}
-static int adev_dump(const audio_hw_device_t *device, int fd)
+static int adev_dump(const audio_hw_device_t *device __unused, int fd __unused)
{
return 0;
}
+/* verifies input and output devices and their capabilities.
+ *
+ * This verification is required when enabling extended bit-depth or
+ * sampling rates, as not all qcom products support it.
+ *
+ * Suitable for calling only on initialization such as adev_open().
+ * It fills the audio_device use_case_table[] array.
+ *
+ * Has a side-effect that it needs to configure audio routing / devices
+ * in order to power up the devices and read the device parameters.
+ * It does not acquire any hw device lock. Should restore the devices
+ * back to "normal state" upon completion.
+ */
+static int adev_verify_devices(struct audio_device *adev)
+{
+ /* enumeration is a bit difficult because one really wants to pull
+ * the use_case, device id, etc from the hidden pcm_device_table[].
+ * In this case there are the following use cases and device ids.
+ *
+ * [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0},
+ * [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {15, 15},
+ * [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {1, 1},
+ * [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {9, 9},
+ * [USECASE_AUDIO_RECORD] = {0, 0},
+ * [USECASE_AUDIO_RECORD_LOW_LATENCY] = {15, 15},
+ * [USECASE_VOICE_CALL] = {2, 2},
+ *
+ * USECASE_AUDIO_PLAYBACK_OFFLOAD, USECASE_AUDIO_PLAYBACK_MULTI_CH omitted.
+ * USECASE_VOICE_CALL omitted, but possible for either input or output.
+ */
+
+ /* should be the usecases enabled in adev_open_input_stream() */
+ static const int test_in_usecases[] = {
+ USECASE_AUDIO_RECORD,
+ USECASE_AUDIO_RECORD_LOW_LATENCY, /* does not appear to be used */
+ };
+ /* should be the usecases enabled in adev_open_output_stream()*/
+ static const int test_out_usecases[] = {
+ USECASE_AUDIO_PLAYBACK_DEEP_BUFFER,
+ USECASE_AUDIO_PLAYBACK_LOW_LATENCY,
+ };
+ static const usecase_type_t usecase_type_by_dir[] = {
+ PCM_PLAYBACK,
+ PCM_CAPTURE,
+ };
+ static const unsigned flags_by_dir[] = {
+ PCM_OUT,
+ PCM_IN,
+ };
+
+ size_t i;
+ unsigned dir;
+ const unsigned card_id = adev->snd_card;
+ char info[512]; /* for possible debug info */
+
+ for (dir = 0; dir < 2; ++dir) {
+ const usecase_type_t usecase_type = usecase_type_by_dir[dir];
+ const unsigned flags_dir = flags_by_dir[dir];
+ const size_t testsize =
+ dir ? ARRAY_SIZE(test_in_usecases) : ARRAY_SIZE(test_out_usecases);
+ const int *testcases =
+ dir ? test_in_usecases : test_out_usecases;
+ const audio_devices_t audio_device =
+ dir ? AUDIO_DEVICE_IN_BUILTIN_MIC : AUDIO_DEVICE_OUT_SPEAKER;
+
+ for (i = 0; i < testsize; ++i) {
+ const audio_usecase_t audio_usecase = testcases[i];
+ int device_id;
+ snd_device_t snd_device;
+ struct pcm_params **pparams;
+ struct stream_out out;
+ struct stream_in in;
+ struct audio_usecase uc_info;
+ int retval;
+
+ pparams = &adev->use_case_table[audio_usecase];
+ pcm_params_free(*pparams); /* can accept null input */
+ *pparams = NULL;
+
+ /* find the device ID for the use case (signed, for error) */
+ device_id = platform_get_pcm_device_id(audio_usecase, usecase_type);
+ if (device_id < 0)
+ continue;
+
+ /* prepare structures for device probing */
+ memset(&uc_info, 0, sizeof(uc_info));
+ uc_info.id = audio_usecase;
+ uc_info.type = usecase_type;
+ if (dir) {
+ adev->active_input = ∈
+ memset(&in, 0, sizeof(in));
+ in.device = audio_device;
+ in.source = AUDIO_SOURCE_VOICE_COMMUNICATION;
+ uc_info.stream.in = ∈
+ } else {
+ adev->active_input = NULL;
+ }
+ memset(&out, 0, sizeof(out));
+ out.devices = audio_device; /* only field needed in select_devices */
+ uc_info.stream.out = &out;
+ uc_info.devices = audio_device;
+ uc_info.in_snd_device = SND_DEVICE_NONE;
+ uc_info.out_snd_device = SND_DEVICE_NONE;
+ list_add_tail(&adev->usecase_list, &uc_info.list);
+
+ /* select device - similar to start_(in/out)put_stream() */
+ retval = select_devices(adev, audio_usecase);
+ if (retval >= 0) {
+ *pparams = pcm_params_get(card_id, device_id, flags_dir);
+#if LOG_NDEBUG == 0
+ if (*pparams) {
+ ALOGV("%s: (%s) card %d device %d", __func__,
+ dir ? "input" : "output", card_id, device_id);
+ pcm_params_to_string(*pparams, info, ARRAY_SIZE(info));
+ ALOGV(info); /* print parameters */
+ } else {
+ ALOGV("%s: cannot locate card %d device %d", __func__, card_id, device_id);
+ }
+#endif
+ }
+
+ /* deselect device - similar to stop_(in/out)put_stream() */
+ /* 1. Get and set stream specific mixer controls */
+ retval = disable_audio_route(adev, &uc_info);
+ /* 2. Disable the rx device */
+ retval = disable_snd_device(adev,
+ dir ? uc_info.in_snd_device : uc_info.out_snd_device);
+ list_remove(&uc_info.list);
+ }
+ }
+ adev->active_input = NULL; /* restore adev state */
+ return 0;
+}
+
static int adev_close(hw_device_t *device)
{
+ size_t i;
struct audio_device *adev = (struct audio_device *)device;
audio_route_free(adev->audio_route);
free(adev->snd_dev_ref_cnt);
platform_deinit(adev->platform);
+ audio_extn_extspk_deinit(adev->extspk);
+ for (i = 0; i < ARRAY_SIZE(adev->use_case_table); ++i) {
+ pcm_params_free(adev->use_case_table[i]);
+ }
free(device);
return 0;
}
+/* This returns 1 if the input parameter looks at all plausible as a low latency period size,
+ * or 0 otherwise. A return value of 1 doesn't mean the value is guaranteed to work,
+ * just that it _might_ work.
+ */
+static int period_size_is_plausible_for_low_latency(int period_size)
+{
+ switch (period_size) {
+ case 160:
+ case 240:
+ case 320:
+ case 480:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
static int adev_open(const hw_module_t *module, const char *name,
hw_device_t **device)
{
@@ -2328,6 +2636,8 @@
adev = calloc(1, sizeof(struct audio_device));
+ pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL);
+
adev->device.common.tag = HARDWARE_DEVICE_TAG;
adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
adev->device.common.module = (struct hw_module_t *)module;
@@ -2356,16 +2666,11 @@
adev->mode = AUDIO_MODE_NORMAL;
adev->active_input = NULL;
adev->primary_output = NULL;
- adev->out_device = AUDIO_DEVICE_NONE;
- adev->voice_call_rx = NULL;
- adev->voice_call_tx = NULL;
- adev->voice_volume = 1.0f;
- adev->tty_mode = TTY_MODE_OFF;
adev->bluetooth_nrec = true;
- adev->in_call = false;
adev->acdb_settings = TTY_MODE_OFF;
/* adev->cur_hdmi_channels = 0; by calloc() */
adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int));
+ voice_init(adev);
list_init(&adev->usecase_list);
pthread_mutex_unlock(&adev->lock);
@@ -2379,6 +2684,8 @@
return -EINVAL;
}
+ adev->extspk = audio_extn_extspk_init(adev);
+
if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) {
adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW);
if (adev->visualizer_lib == NULL) {
@@ -2386,15 +2693,55 @@
} else {
ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH);
adev->visualizer_start_output =
- (int (*)(audio_io_handle_t))dlsym(adev->visualizer_lib,
+ (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
"visualizer_hal_start_output");
adev->visualizer_stop_output =
- (int (*)(audio_io_handle_t))dlsym(adev->visualizer_lib,
+ (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
"visualizer_hal_stop_output");
}
}
+ if (access(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, R_OK) == 0) {
+ adev->offload_effects_lib = dlopen(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, RTLD_NOW);
+ if (adev->offload_effects_lib == NULL) {
+ ALOGE("%s: DLOPEN failed for %s", __func__,
+ OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
+ } else {
+ ALOGV("%s: DLOPEN successful for %s", __func__,
+ OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
+ adev->offload_effects_start_output =
+ (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
+ "offload_effects_bundle_hal_start_output");
+ adev->offload_effects_stop_output =
+ (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
+ "offload_effects_bundle_hal_stop_output");
+ }
+ }
+
+ adev->bt_wb_speech_enabled = false;
+ adev->enable_voicerx = false;
+
*device = &adev->device.common;
+ if (k_enable_extended_precision)
+ adev_verify_devices(adev);
+
+ char value[PROPERTY_VALUE_MAX];
+ int trial;
+ if (property_get("audio_hal.period_size", value, NULL) > 0) {
+ trial = atoi(value);
+ if (period_size_is_plausible_for_low_latency(trial)) {
+ pcm_config_low_latency.period_size = trial;
+ pcm_config_low_latency.start_threshold = trial / 4;
+ pcm_config_low_latency.avail_min = trial / 4;
+ configured_low_latency_capture_period_size = trial;
+ }
+ }
+ if (property_get("audio_hal.in_period_size", value, NULL) > 0) {
+ trial = atoi(value);
+ if (period_size_is_plausible_for_low_latency(trial)) {
+ configured_low_latency_capture_period_size = trial;
+ }
+ }
ALOGV("%s: exit", __func__);
return 0;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 0da4324..bec19d0 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2013-2014 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.
@@ -17,6 +17,7 @@
#ifndef QCOM_AUDIO_HW_H
#define QCOM_AUDIO_HW_H
+#include <cutils/str_parms.h>
#include <cutils/list.h>
#include <hardware/audio.h>
@@ -24,8 +25,10 @@
#include <tinycompress/tinycompress.h>
#include <audio_route/audio_route.h>
+#include "voice.h"
#define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so"
+#define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/system/lib/soundfx/libqcompostprocbundle.so"
/* Flags used to initialize acdb_settings variable that goes to ACDB library */
#define DMIC_FLAG 0x00000002
@@ -47,7 +50,7 @@
* Each usecase is mapped to a specific PCM device.
* Refer to pcm_device_table[].
*/
-typedef enum {
+enum {
USECASE_INVALID = -1,
/* Playback usecases */
USECASE_AUDIO_PLAYBACK_DEEP_BUFFER = 0,
@@ -55,13 +58,32 @@
USECASE_AUDIO_PLAYBACK_MULTI_CH,
USECASE_AUDIO_PLAYBACK_OFFLOAD,
+ /* HFP Use case*/
+ USECASE_AUDIO_HFP_SCO,
+ USECASE_AUDIO_HFP_SCO_WB,
+
/* Capture usecases */
USECASE_AUDIO_RECORD,
USECASE_AUDIO_RECORD_LOW_LATENCY,
USECASE_VOICE_CALL,
+
+ /* Voice extension usecases */
+ USECASE_VOICE2_CALL,
+ USECASE_VOLTE_CALL,
+ USECASE_QCHAT_CALL,
+ USECASE_VOWLAN_CALL,
+ USECASE_INCALL_REC_UPLINK,
+ USECASE_INCALL_REC_DOWNLINK,
+ USECASE_INCALL_REC_UPLINK_AND_DOWNLINK,
+
+ USECASE_AUDIO_PLAYBACK_AFE_PROXY,
+ USECASE_AUDIO_RECORD_AFE_PROXY,
+
AUDIO_USECASE_MAX
-} audio_usecase_t;
+};
+
+const char * const use_case_table[AUDIO_USECASE_MAX];
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
@@ -139,10 +161,11 @@
int standby;
int source;
int pcm_device_id;
- int device;
+ audio_devices_t device;
audio_channel_mask_t channel_mask;
audio_usecase_t usecase;
bool enable_aec;
+ bool enable_ns;
struct audio_device *dev;
};
@@ -150,7 +173,8 @@
typedef enum {
PCM_PLAYBACK,
PCM_CAPTURE,
- VOICE_CALL
+ VOICE_CALL,
+ PCM_HFP_CALL
} usecase_type_t;
union stream_ptr {
@@ -173,31 +197,68 @@
pthread_mutex_t lock; /* see note below on mutex acquisition order */
struct mixer *mixer;
audio_mode_t mode;
- audio_devices_t out_device;
struct stream_in *active_input;
struct stream_out *primary_output;
- int in_call;
- float voice_volume;
- bool mic_mute;
- int tty_mode;
+ struct stream_out *voice_tx_output;
+ struct stream_out *current_call_output;
bool bluetooth_nrec;
bool screen_off;
- struct pcm *voice_call_rx;
- struct pcm *voice_call_tx;
int *snd_dev_ref_cnt;
struct listnode usecase_list;
struct audio_route *audio_route;
int acdb_settings;
bool speaker_lr_swap;
+ struct voice voice;
unsigned int cur_hdmi_channels;
+ bool bt_wb_speech_enabled;
+ bool mic_muted;
+ bool enable_voicerx;
+ int snd_card;
void *platform;
+ void *extspk;
void *visualizer_lib;
- int (*visualizer_start_output)(audio_io_handle_t);
- int (*visualizer_stop_output)(audio_io_handle_t);
+ int (*visualizer_start_output)(audio_io_handle_t, int);
+ int (*visualizer_stop_output)(audio_io_handle_t, int);
+
+ /* The pcm_params use_case_table is loaded by adev_verify_devices() upon
+ * calling adev_open().
+ *
+ * If an entry is not NULL, it can be used to determine if extended precision
+ * or other capabilities are present for the device corresponding to that usecase.
+ */
+ struct pcm_params *use_case_table[AUDIO_USECASE_MAX];
+ void *offload_effects_lib;
+ int (*offload_effects_start_output)(audio_io_handle_t, int);
+ int (*offload_effects_stop_output)(audio_io_handle_t, int);
};
+int pcm_ioctl(void *pcm, int request, ...);
+
+int select_devices(struct audio_device *adev,
+ audio_usecase_t uc_id);
+
+int disable_audio_route(struct audio_device *adev,
+ struct audio_usecase *usecase);
+
+int disable_snd_device(struct audio_device *adev,
+ snd_device_t snd_device);
+
+int enable_snd_device(struct audio_device *adev,
+ snd_device_t snd_device);
+
+int enable_audio_route(struct audio_device *adev,
+ struct audio_usecase *usecase);
+
+struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
+ audio_usecase_t uc_id);
+
+#define LITERAL_TO_STRING(x) #x
+#define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\
+ __FILE__ ":" LITERAL_TO_STRING(__LINE__)\
+ " ASSERT_FATAL(" #condition ") failed.")
+
/*
* NOTE: when multiple mutexes have to be acquired, always take the
* stream_in or stream_out mutex first, followed by the audio_device mutex.
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index b200e27..4eaf488 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2013-2014 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.
@@ -123,6 +123,7 @@
[SND_DEVICE_OUT_HDMI] = "hdmi",
[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi",
[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_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones",
[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones",
@@ -139,6 +140,7 @@
[SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic",
[SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic",
[SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic",
+ [SND_DEVICE_IN_BT_SCO_MIC_WB] = "bt-sco-mic-wb",
[SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic",
[SND_DEVICE_IN_VOICE_DMIC_EF] = "voice-dmic-ef",
[SND_DEVICE_IN_VOICE_DMIC_BS] = "voice-dmic-bs",
@@ -168,6 +170,7 @@
[SND_DEVICE_OUT_HDMI] = 18,
[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14,
[SND_DEVICE_OUT_BT_SCO] = 22,
+ [SND_DEVICE_OUT_BT_SCO_WB] = 39,
[SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = 81,
[SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
@@ -183,6 +186,7 @@
[SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8,
[SND_DEVICE_IN_HDMI_MIC] = 4,
[SND_DEVICE_IN_BT_SCO_MIC] = 21,
+ [SND_DEVICE_IN_BT_SCO_MIC_WB] = 38,
[SND_DEVICE_IN_CAMCORDER_MIC] = 61,
[SND_DEVICE_IN_VOICE_DMIC_EF] = 6,
[SND_DEVICE_IN_VOICE_DMIC_BS] = 5,
@@ -372,10 +376,11 @@
if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX)
return device_table[snd_device];
else
- return "";
+ return "none";
}
-void platform_add_backend_name(char *mixer_path, snd_device_t snd_device)
+void platform_add_backend_name(void *platform __unused, char *mixer_path,
+ snd_device_t snd_device)
{
if (snd_device == SND_DEVICE_IN_BT_SCO_MIC)
strcat(mixer_path, " bt-sco");
@@ -385,6 +390,9 @@
strcat(mixer_path, " hdmi");
else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI)
strcat(mixer_path, " speaker-and-hdmi");
+ else if (snd_device == SND_DEVICE_OUT_BT_SCO_WB ||
+ snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB)
+ strcat(mixer_path, " bt-sco-wb");
}
int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type)
@@ -397,6 +405,17 @@
return device_id;
}
+int platform_get_snd_device_index(char *snd_device_index_name __unused)
+{
+ return -ENODEV;
+}
+
+int platform_set_snd_device_acdb_id(snd_device_t snd_device __unused,
+ unsigned int acdb_id __unused)
+{
+ return -ENODEV;
+}
+
int platform_send_audio_calibration(void *platform, snd_device_t snd_device)
{
struct platform_data *my_data = (struct platform_data *)platform;
@@ -426,7 +445,8 @@
struct platform_data *my_data = (struct platform_data *)platform;
int ret = 0;
- if (my_data->csd_client != NULL) {
+ if (my_data->csd_client != NULL &&
+ voice_is_in_call(my_data->adev)) {
/* This must be called before disabling the mixer controls on APQ side */
if (my_data->csd_disable_device == NULL) {
ALOGE("%s: dlsym error for csd_disable_device", __func__);
@@ -474,7 +494,7 @@
return ret;
}
-int platform_start_voice_call(void *platform)
+int platform_start_voice_call(void *platform, uint32_t vsid __unused)
{
struct platform_data *my_data = (struct platform_data *)platform;
int ret = 0;
@@ -494,7 +514,7 @@
return ret;
}
-int platform_stop_voice_call(void *platform)
+int platform_stop_voice_call(void *platform, uint32_t vsid __unused)
{
struct platform_data *my_data = (struct platform_data *)platform;
int ret = 0;
@@ -557,6 +577,12 @@
return ret;
}
+int platform_set_device_mute(void *platform __unused, bool state __unused, char *dir __unused)
+{
+ ALOGE("%s: Not implemented", __func__);
+ return -ENOSYS;
+}
+
snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices)
{
struct platform_data *my_data = (struct platform_data *)platform;
@@ -571,19 +597,23 @@
goto exit;
}
- if (mode == AUDIO_MODE_IN_CALL) {
+ if (voice_is_in_call(adev)) {
if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
- if (adev->tty_mode == TTY_MODE_FULL)
+ if (adev->voice.tty_mode == TTY_MODE_FULL)
snd_device = SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES;
- else if (adev->tty_mode == TTY_MODE_VCO)
+ else if (adev->voice.tty_mode == TTY_MODE_VCO)
snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES;
- else if (adev->tty_mode == TTY_MODE_HCO)
+ else if (adev->voice.tty_mode == TTY_MODE_HCO)
snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET;
else
snd_device = SND_DEVICE_OUT_VOICE_HEADPHONES;
} else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
- snd_device = SND_DEVICE_OUT_BT_SCO;
+ if (adev->bt_wb_speech_enabled) {
+ snd_device = SND_DEVICE_OUT_BT_SCO_WB;
+ } else {
+ snd_device = SND_DEVICE_OUT_BT_SCO;
+ }
} else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
} else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
@@ -630,7 +660,11 @@
else
snd_device = SND_DEVICE_OUT_SPEAKER;
} else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
- snd_device = SND_DEVICE_OUT_BT_SCO;
+ if (adev->bt_wb_speech_enabled) {
+ snd_device = SND_DEVICE_OUT_BT_SCO_WB;
+ } else {
+ snd_device = SND_DEVICE_OUT_BT_SCO;
+ }
} else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
snd_device = SND_DEVICE_OUT_HDMI ;
} else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
@@ -660,15 +694,11 @@
ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
__func__, out_device, in_device);
- if (mode == AUDIO_MODE_IN_CALL) {
- if (out_device == AUDIO_DEVICE_NONE) {
- ALOGE("%s: No output device set for voice call", __func__);
- goto exit;
- }
- if (adev->tty_mode != TTY_MODE_OFF) {
+ if ((out_device != AUDIO_DEVICE_NONE) && voice_is_in_call(adev)) {
+ if (adev->voice.tty_mode != TTY_MODE_OFF) {
if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
- switch (adev->tty_mode) {
+ switch (adev->voice.tty_mode) {
case TTY_MODE_FULL:
snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC;
break;
@@ -679,7 +709,7 @@
snd_device = SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC;
break;
default:
- ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->tty_mode);
+ ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->voice.tty_mode);
}
goto exit;
}
@@ -702,7 +732,11 @@
} else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC;
} else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
- snd_device = SND_DEVICE_IN_BT_SCO_MIC ;
+ if (adev->bt_wb_speech_enabled) {
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+ } else {
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+ }
} else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode &&
my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) {
@@ -772,7 +806,11 @@
} 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) {
- snd_device = SND_DEVICE_IN_BT_SCO_MIC ;
+ if (adev->bt_wb_speech_enabled) {
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+ } else {
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+ }
} else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) {
snd_device = SND_DEVICE_IN_HDMI_MIC;
} else {
@@ -790,7 +828,11 @@
} else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
snd_device = SND_DEVICE_IN_HANDSET_MIC;
} else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) {
- snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+ if (adev->bt_wb_speech_enabled) {
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+ } else {
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+ }
} else if (out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
snd_device = SND_DEVICE_IN_HDMI_MIC;
} else {
@@ -838,7 +880,7 @@
return 0;
}
-int platform_edid_get_max_channels(void *platform)
+int platform_edid_get_max_channels(void *platform __unused)
{
FILE *file;
struct audio_block_header header;
@@ -884,6 +926,31 @@
return max_channels;
}
+int platform_set_incall_recording_session_id(void *platform __unused,
+ uint32_t session_id __unused, int rec_mode __unused)
+{
+ ALOGE("%s: Not implemented", __func__);
+ return -ENOSYS;
+}
+
+int platform_stop_incall_recording_usecase(void *platform __unused)
+{
+ ALOGE("%s: Not implemented", __func__);
+ return -ENOSYS;
+}
+
+int platform_start_incall_music_usecase(void *platform __unused)
+{
+ ALOGE("%s: Not implemented", __func__);
+ return -ENOSYS;
+}
+
+int platform_stop_incall_music_usecase(void *platform __unused)
+{
+ ALOGE("%s: Not implemented", __func__);
+ return -ENOSYS;
+}
+
/* Delay in Us */
int64_t platform_render_latency(audio_usecase_t usecase)
{
@@ -896,3 +963,44 @@
return 0;
}
}
+
+int platform_switch_voice_call_enable_device_config(void *platform __unused,
+ snd_device_t out_snd_device __unused,
+ snd_device_t in_snd_device __unused)
+{
+ return 0;
+}
+
+int platform_switch_voice_call_usecase_route_post(void *platform __unused,
+ snd_device_t out_snd_device __unused,
+ snd_device_t in_snd_device __unused)
+{
+ return 0;
+}
+
+int platform_get_sample_rate(void *platform __unused, uint32_t *rate __unused)
+{
+ return -ENOSYS;
+}
+
+int platform_get_usecase_index(const char * usecase __unused)
+{
+ return -ENOSYS;
+}
+
+int platform_set_usecase_pcm_id(audio_usecase_t usecase __unused, int32_t type __unused,
+ int32_t pcm_id __unused)
+{
+ return -ENOSYS;
+}
+
+int platform_set_snd_device_backend(snd_device_t device __unused,
+ const char *backend __unused)
+{
+ return -ENOSYS;
+}
+
+void platform_set_echo_reference(struct audio_device *adev, bool enable, audio_devices_t out_device)
+{
+ return;
+}
diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h
index 4bc5003..0201772 100644
--- a/hal/msm8960/platform.h
+++ b/hal/msm8960/platform.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2013-2014 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.
@@ -46,6 +46,7 @@
SND_DEVICE_OUT_HDMI,
SND_DEVICE_OUT_SPEAKER_AND_HDMI,
SND_DEVICE_OUT_BT_SCO,
+ SND_DEVICE_OUT_BT_SCO_WB,
SND_DEVICE_OUT_VOICE_HANDSET_TMUS,
SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
@@ -68,6 +69,7 @@
SND_DEVICE_IN_VOICE_HEADSET_MIC,
SND_DEVICE_IN_HDMI_MIC,
SND_DEVICE_IN_BT_SCO_MIC,
+ SND_DEVICE_IN_BT_SCO_MIC_WB,
SND_DEVICE_IN_CAMCORDER_MIC,
SND_DEVICE_IN_VOICE_DMIC_EF,
SND_DEVICE_IN_VOICE_DMIC_BS,
@@ -114,4 +116,12 @@
#define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
#define AUDIO_CAPTURE_PERIOD_COUNT 2
+#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
+#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
+#define LOW_LATENCY_CAPTURE_USE_CASE 0
+
+#define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
+#define AFE_PROXY_RECORD_PCM_DEVICE 8
+
+
#endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 15f8476..7248098 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2013-2014 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.
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <dlfcn.h>
#include <cutils/log.h>
+#include <cutils/str_parms.h>
#include <cutils/properties.h>
#include <audio_hw.h>
#include <platform_api.h>
@@ -50,11 +51,7 @@
/* Retry for delay in FW loading*/
#define RETRY_NUMBER 10
#define RETRY_US 500000
-
-#define MAX_VOL_INDEX 5
-#define MIN_VOL_INDEX 0
-#define percent_to_index(val, min, max) \
- ((val) * ((max) - (min)) * 0.01 + (min) + .5)
+#define MAX_SND_CARD 8
struct audio_block_header
{
@@ -62,34 +59,68 @@
int length;
};
+/* Audio calibration related functions */
typedef void (*acdb_deallocate_t)();
+#ifdef PLATFORM_MSM8084
+typedef int (*acdb_init_t)(char *);
+#else
typedef int (*acdb_init_t)();
+#endif
typedef void (*acdb_send_audio_cal_t)(int, int);
typedef void (*acdb_send_voice_cal_t)(int, int);
+typedef int (*acdb_reload_vocvoltable_t)(int);
/* Audio calibration related functions */
struct platform_data {
struct audio_device *adev;
bool fluence_in_spkr_mode;
bool fluence_in_voice_call;
+ bool fluence_in_voice_comm;
bool fluence_in_voice_rec;
int dualmic_config;
-
void *acdb_handle;
- acdb_init_t acdb_init;
- acdb_deallocate_t acdb_deallocate;
- acdb_send_audio_cal_t acdb_send_audio_cal;
- acdb_send_voice_cal_t acdb_send_voice_cal;
+ acdb_init_t acdb_init;
+ acdb_deallocate_t acdb_deallocate;
+ acdb_send_audio_cal_t acdb_send_audio_cal;
+ acdb_send_voice_cal_t acdb_send_voice_cal;
+ acdb_reload_vocvoltable_t acdb_reload_vocvoltable;
+ struct csd_data *csd;
+ bool ext_speaker;
+ bool ext_earpiece;
};
-static const int pcm_device_table[AUDIO_USECASE_MAX][2] = {
- [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0},
- [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {15, 15},
- [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {1, 1},
- [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {9, 9},
- [USECASE_AUDIO_RECORD] = {0, 0},
- [USECASE_AUDIO_RECORD_LOW_LATENCY] = {15, 15},
- [USECASE_VOICE_CALL] = {2, 2},
+static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
+ [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE,
+ DEEP_BUFFER_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
+ LOWLATENCY_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTIMEDIA2_PCM_DEVICE,
+ MULTIMEDIA2_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {PLAYBACK_OFFLOAD_DEVICE,
+ PLAYBACK_OFFLOAD_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},
+ [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE},
+ [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE},
+ [USECASE_VOWLAN_CALL] = {VOWLAN_CALL_PCM_DEVICE, VOWLAN_CALL_PCM_DEVICE},
+ [USECASE_INCALL_REC_UPLINK] = {AUDIO_RECORD_PCM_DEVICE,
+ AUDIO_RECORD_PCM_DEVICE},
+ [USECASE_INCALL_REC_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE,
+ AUDIO_RECORD_PCM_DEVICE},
+ [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE,
+ AUDIO_RECORD_PCM_DEVICE},
+ [USECASE_AUDIO_HFP_SCO] = {HFP_PCM_RX, HFP_SCO_RX},
+
+ [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = {AFE_PROXY_PLAYBACK_PCM_DEVICE,
+ AFE_PROXY_RECORD_PCM_DEVICE},
+ [USECASE_AUDIO_RECORD_AFE_PROXY] = {AFE_PROXY_PLAYBACK_PCM_DEVICE,
+ AFE_PROXY_RECORD_PCM_DEVICE},
+
};
/* Array to store sound devices */
@@ -99,90 +130,239 @@
[SND_DEVICE_OUT_HANDSET] = "handset",
[SND_DEVICE_OUT_SPEAKER] = "speaker",
[SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse",
+ [SND_DEVICE_OUT_SPEAKER_SAFE] = "speaker-safe",
[SND_DEVICE_OUT_HEADPHONES] = "headphones",
+ [SND_DEVICE_OUT_LINE] = "line",
[SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones",
+ [SND_DEVICE_OUT_SPEAKER_AND_LINE] = "speaker-and-line",
[SND_DEVICE_OUT_VOICE_HANDSET] = "voice-handset",
+ [SND_DEVICE_OUT_VOICE_HAC_HANDSET] = "voice-hac-handset",
[SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker",
[SND_DEVICE_OUT_VOICE_HEADPHONES] = "voice-headphones",
+ [SND_DEVICE_OUT_VOICE_LINE] = "voice-line",
[SND_DEVICE_OUT_HDMI] = "hdmi",
[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi",
[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_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones",
[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones",
[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset",
+ [SND_DEVICE_OUT_VOICE_TX] = "voice-tx",
/* Capture sound devices */
[SND_DEVICE_IN_HANDSET_MIC] = "handset-mic",
- [SND_DEVICE_IN_SPEAKER_MIC] = "speaker-mic",
- [SND_DEVICE_IN_HEADSET_MIC] = "headset-mic",
[SND_DEVICE_IN_HANDSET_MIC_AEC] = "handset-mic",
- [SND_DEVICE_IN_SPEAKER_MIC_AEC] = "speaker-mic-aec",
+ [SND_DEVICE_IN_HANDSET_MIC_NS] = "handset-mic",
+ [SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = "handset-mic",
+ [SND_DEVICE_IN_HANDSET_DMIC] = "dmic-endfire",
+ [SND_DEVICE_IN_HANDSET_DMIC_AEC] = "dmic-endfire",
+ [SND_DEVICE_IN_HANDSET_DMIC_NS] = "dmic-endfire",
+ [SND_DEVICE_IN_HANDSET_DMIC_AEC_NS] = "dmic-endfire",
+ [SND_DEVICE_IN_HANDSET_DMIC_STEREO] = "dmic-endfire",
+
+ [SND_DEVICE_IN_SPEAKER_MIC] = "speaker-mic",
+ [SND_DEVICE_IN_SPEAKER_MIC_AEC] = "speaker-mic",
+ [SND_DEVICE_IN_SPEAKER_MIC_NS] = "speaker-mic",
+ [SND_DEVICE_IN_SPEAKER_MIC_AEC_NS] = "speaker-mic",
+ [SND_DEVICE_IN_SPEAKER_DMIC] = "speaker-dmic-endfire",
+ [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = "speaker-dmic-endfire",
+ [SND_DEVICE_IN_SPEAKER_DMIC_NS] = "speaker-dmic-endfire",
+ [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS] = "speaker-dmic-endfire",
+ [SND_DEVICE_IN_SPEAKER_DMIC_STEREO] = "speaker-dmic-endfire",
+
+ [SND_DEVICE_IN_HEADSET_MIC] = "headset-mic",
[SND_DEVICE_IN_HEADSET_MIC_AEC] = "headset-mic",
- [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = "voice-speaker-mic",
- [SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic",
+
[SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic",
[SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic",
+ [SND_DEVICE_IN_BT_SCO_MIC_WB] = "bt-sco-mic-wb",
+
[SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic",
- [SND_DEVICE_IN_VOICE_DMIC_EF] = "voice-dmic-ef",
- [SND_DEVICE_IN_VOICE_DMIC_BS] = "voice-dmic-bs",
- [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = "voice-dmic-ef-tmus",
- [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = "voice-speaker-dmic-ef",
- [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = "voice-speaker-dmic-bs",
+
+ [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef",
+ [SND_DEVICE_IN_VOICE_DMIC_TMUS] = "voice-dmic-ef-tmus",
+ [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = "voice-speaker-mic",
+ [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = "voice-speaker-dmic-ef",
+ [SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic",
[SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic",
[SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic",
[SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic",
+
[SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic",
- [SND_DEVICE_IN_VOICE_REC_DMIC_EF] = "voice-rec-dmic-ef",
- [SND_DEVICE_IN_VOICE_REC_DMIC_BS] = "voice-rec-dmic-bs",
- [SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE] = "voice-rec-dmic-ef-fluence",
- [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = "voice-rec-dmic-bs-fluence",
+ [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_RX] = "voice-rx",
};
/* ACDB IDs (audio DSP path configuration IDs) for each sound device */
-static const int acdb_device_table[SND_DEVICE_MAX] = {
+static int acdb_device_table[SND_DEVICE_MAX] = {
[SND_DEVICE_NONE] = -1,
[SND_DEVICE_OUT_HANDSET] = 7,
[SND_DEVICE_OUT_SPEAKER] = 15,
[SND_DEVICE_OUT_SPEAKER_REVERSE] = 15,
+ [SND_DEVICE_OUT_SPEAKER_SAFE] = 15,
[SND_DEVICE_OUT_HEADPHONES] = 10,
+ [SND_DEVICE_OUT_LINE] = 77,
[SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10,
- [SND_DEVICE_OUT_VOICE_HANDSET] = 7,
- [SND_DEVICE_OUT_VOICE_SPEAKER] = 15,
+ [SND_DEVICE_OUT_SPEAKER_AND_LINE] = 77,
+ [SND_DEVICE_OUT_VOICE_HANDSET] = ACDB_ID_VOICE_HANDSET,
+ [SND_DEVICE_OUT_VOICE_SPEAKER] = ACDB_ID_VOICE_SPEAKER,
+ [SND_DEVICE_OUT_VOICE_HAC_HANDSET] = 53,
[SND_DEVICE_OUT_VOICE_HEADPHONES] = 10,
+ [SND_DEVICE_OUT_VOICE_LINE] = 77,
[SND_DEVICE_OUT_HDMI] = 18,
[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 15,
[SND_DEVICE_OUT_BT_SCO] = 22,
- [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = 88,
+ [SND_DEVICE_OUT_BT_SCO_WB] = 39,
+ [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = ACDB_ID_VOICE_HANDSET_TMUS,
[SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37,
+ [SND_DEVICE_OUT_VOICE_TX] = 45,
[SND_DEVICE_IN_HANDSET_MIC] = 4,
- [SND_DEVICE_IN_SPEAKER_MIC] = 4, /* ToDo: Check if this needs to changed to 11 */
+ [SND_DEVICE_IN_HANDSET_MIC_AEC] = 106,
+ [SND_DEVICE_IN_HANDSET_MIC_NS] = 107,
+ [SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = 108,
+ [SND_DEVICE_IN_HANDSET_DMIC] = 41,
+ [SND_DEVICE_IN_HANDSET_DMIC_AEC] = 109,
+ [SND_DEVICE_IN_HANDSET_DMIC_NS] = 110,
+ [SND_DEVICE_IN_HANDSET_DMIC_AEC_NS] = 111,
+ [SND_DEVICE_IN_HANDSET_DMIC_STEREO] = 34,
+
+ [SND_DEVICE_IN_SPEAKER_MIC] = 11,
+ [SND_DEVICE_IN_SPEAKER_MIC_AEC] = 112,
+ [SND_DEVICE_IN_SPEAKER_MIC_NS] = 113,
+ [SND_DEVICE_IN_SPEAKER_MIC_AEC_NS] = 114,
+ [SND_DEVICE_IN_SPEAKER_DMIC] = 43,
+ [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = 115,
+ [SND_DEVICE_IN_SPEAKER_DMIC_NS] = 116,
+ [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS] = 117,
+ [SND_DEVICE_IN_SPEAKER_DMIC_STEREO] = 35,
+
[SND_DEVICE_IN_HEADSET_MIC] = 8,
- [SND_DEVICE_IN_HANDSET_MIC_AEC] = 40,
- [SND_DEVICE_IN_SPEAKER_MIC_AEC] = 42,
- [SND_DEVICE_IN_HEADSET_MIC_AEC] = 47,
- [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11,
- [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8,
+ [SND_DEVICE_IN_HEADSET_MIC_AEC] = ACDB_ID_HEADSET_MIC_AEC,
+
[SND_DEVICE_IN_HDMI_MIC] = 4,
[SND_DEVICE_IN_BT_SCO_MIC] = 21,
+ [SND_DEVICE_IN_BT_SCO_MIC_WB] = 38,
+
[SND_DEVICE_IN_CAMCORDER_MIC] = 61,
- [SND_DEVICE_IN_VOICE_DMIC_EF] = 41,
- [SND_DEVICE_IN_VOICE_DMIC_BS] = 5,
- [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = 89,
- [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = 43,
- [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = 12,
+
+ [SND_DEVICE_IN_VOICE_DMIC] = 41,
+ [SND_DEVICE_IN_VOICE_DMIC_TMUS] = ACDB_ID_VOICE_DMIC_EF_TMUS,
+ [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11,
+ [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 43,
+ [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8,
[SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16,
[SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36,
[SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16,
+
[SND_DEVICE_IN_VOICE_REC_MIC] = 62,
- /* TODO: Update with proper acdb ids */
- [SND_DEVICE_IN_VOICE_REC_DMIC_EF] = 62,
- [SND_DEVICE_IN_VOICE_REC_DMIC_BS] = 62,
- [SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE] = 6,
- [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = 5,
+ [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_RX] = 44,
+};
+
+struct name_to_index {
+ char name[100];
+ unsigned int index;
+};
+
+#define TO_NAME_INDEX(X) #X, X
+
+/* Used to get index from parsed string */
+static const struct name_to_index snd_device_name_index[SND_DEVICE_MAX] = {
+ /* out */
+ {TO_NAME_INDEX(SND_DEVICE_OUT_HANDSET)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_REVERSE)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_SAFE)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_HEADPHONES)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_LINE)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_LINE)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HANDSET)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HEADPHONES)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_LINE)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_HDMI)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HDMI)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_BT_SCO)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_BT_SCO_WB)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HANDSET_TMUS)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HAC_HANDSET)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET)},
+
+ /* in */
+ {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_NS)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC_NS)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_DMIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_DMIC_AEC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_DMIC_NS)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_DMIC_AEC_NS)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_DMIC_STEREO)},
+
+ {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_MIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_MIC_AEC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_MIC_NS)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_MIC_AEC_NS)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_NS)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_STEREO)},
+
+ {TO_NAME_INDEX(SND_DEVICE_IN_HEADSET_MIC)},
+
+ {TO_NAME_INDEX(SND_DEVICE_IN_HDMI_MIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_BT_SCO_MIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_BT_SCO_MIC_WB)},
+
+ {TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_MIC)},
+
+ {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_DMIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_DMIC_TMUS)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_MIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_DMIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_HEADSET_MIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC)},
+
+ {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_MIC)},
+ {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)},
+};
+
+static char * backend_table[SND_DEVICE_MAX] = {0};
+
+static const struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = {
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_DEEP_BUFFER)},
+ {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_RECORD)},
+ {TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)},
+ {TO_NAME_INDEX(USECASE_VOICE_CALL)},
+ {TO_NAME_INDEX(USECASE_VOICE2_CALL)},
+ {TO_NAME_INDEX(USECASE_VOLTE_CALL)},
+ {TO_NAME_INDEX(USECASE_QCHAT_CALL)},
+ {TO_NAME_INDEX(USECASE_VOWLAN_CALL)},
+ {TO_NAME_INDEX(USECASE_INCALL_REC_UPLINK)},
+ {TO_NAME_INDEX(USECASE_INCALL_REC_DOWNLINK)},
+ {TO_NAME_INDEX(USECASE_INCALL_REC_UPLINK_AND_DOWNLINK)},
+ {TO_NAME_INDEX(USECASE_AUDIO_HFP_SCO)},
};
#define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
@@ -227,62 +407,287 @@
return is_tmus;
}
-static int set_volume_values(int type, int volume, int* values)
+void platform_set_echo_reference(struct audio_device *adev, bool enable, audio_devices_t out_device)
{
- values[0] = volume;
- values[1] = ALL_SESSION_VSID;
+ char mixer_path[50] = { 0 } ;
+ snd_device_t snd_device = SND_DEVICE_NONE;
+ struct listnode *node;
+ struct audio_usecase *usecase;
- switch(type) {
- case VOLUME_SET:
- values[2] = DEFAULT_VOLUME_RAMP_DURATION_MS;
- break;
- case MUTE_SET:
- values[2] = DEFAULT_MUTE_RAMP_DURATION;
- break;
- default:
- return -EINVAL;
+ strcpy(mixer_path, "echo-reference");
+ if (out_device != AUDIO_DEVICE_NONE) {
+ snd_device = platform_get_output_snd_device(adev->platform, out_device);
+ platform_add_backend_name(adev->platform, mixer_path, snd_device);
}
- return 0;
+
+ 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);
+
+ ALOGV("Setting EC Reference: %d for %s", enable, mixer_path);
}
-static int set_echo_reference(struct mixer *mixer, const char* ec_ref)
+static struct csd_data *open_csd_client(bool i2s_ext_modem)
{
- struct mixer_ctl *ctl;
- const char *mixer_ctl_name = "EC_REF_RX";
+ struct csd_data *csd = calloc(1, sizeof(struct csd_data));
- ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
- if (!ctl) {
- ALOGE("%s: Could not get ctl for mixer cmd - %s",
- __func__, mixer_ctl_name);
- return -EINVAL;
+ csd->csd_client = dlopen(LIB_CSD_CLIENT, RTLD_NOW);
+ if (csd->csd_client == NULL) {
+ ALOGE("%s: DLOPEN failed for %s", __func__, LIB_CSD_CLIENT);
+ goto error;
+ } else {
+ ALOGV("%s: DLOPEN successful for %s", __func__, LIB_CSD_CLIENT);
+
+ csd->deinit = (deinit_t)dlsym(csd->csd_client,
+ "csd_client_deinit");
+ if (csd->deinit == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_deinit", __func__,
+ dlerror());
+ goto error;
+ }
+ csd->disable_device = (disable_device_t)dlsym(csd->csd_client,
+ "csd_client_disable_device");
+ if (csd->disable_device == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_disable_device",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->enable_device_config = (enable_device_config_t)dlsym(csd->csd_client,
+ "csd_client_enable_device_config");
+ if (csd->enable_device_config == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_enable_device_config",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->enable_device = (enable_device_t)dlsym(csd->csd_client,
+ "csd_client_enable_device");
+ if (csd->enable_device == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_enable_device",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->start_voice = (start_voice_t)dlsym(csd->csd_client,
+ "csd_client_start_voice");
+ if (csd->start_voice == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_start_voice",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->stop_voice = (stop_voice_t)dlsym(csd->csd_client,
+ "csd_client_stop_voice");
+ if (csd->stop_voice == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_stop_voice",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->volume = (volume_t)dlsym(csd->csd_client,
+ "csd_client_volume");
+ if (csd->volume == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_volume",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->mic_mute = (mic_mute_t)dlsym(csd->csd_client,
+ "csd_client_mic_mute");
+ if (csd->mic_mute == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_mic_mute",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->slow_talk = (slow_talk_t)dlsym(csd->csd_client,
+ "csd_client_slow_talk");
+ if (csd->slow_talk == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_slow_talk",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->start_playback = (start_playback_t)dlsym(csd->csd_client,
+ "csd_client_start_playback");
+ if (csd->start_playback == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_start_playback",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->stop_playback = (stop_playback_t)dlsym(csd->csd_client,
+ "csd_client_stop_playback");
+ if (csd->stop_playback == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_stop_playback",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->start_record = (start_record_t)dlsym(csd->csd_client,
+ "csd_client_start_record");
+ if (csd->start_record == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_start_record",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->stop_record = (stop_record_t)dlsym(csd->csd_client,
+ "csd_client_stop_record");
+ if (csd->stop_record == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_stop_record",
+ __func__, dlerror());
+ goto error;
+ }
+
+ csd->get_sample_rate = (get_sample_rate_t)dlsym(csd->csd_client,
+ "csd_client_get_sample_rate");
+ if (csd->get_sample_rate == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_get_sample_rate",
+ __func__, dlerror());
+
+ goto error;
+ }
+
+ csd->init = (init_t)dlsym(csd->csd_client, "csd_client_init");
+
+ if (csd->init == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_init",
+ __func__, dlerror());
+ goto error;
+ } else {
+ csd->init(i2s_ext_modem);
+ }
}
- ALOGV("Setting EC Reference: %s", ec_ref);
- mixer_ctl_set_enum_by_string(ctl, ec_ref);
- return 0;
+ return csd;
+
+error:
+ free(csd);
+ csd = NULL;
+ return csd;
+}
+
+void close_csd_client(struct csd_data *csd)
+{
+ if (csd != NULL) {
+ csd->deinit();
+ dlclose(csd->csd_client);
+ free(csd);
+ csd = NULL;
+ }
+}
+
+static void platform_csd_init(struct platform_data *my_data)
+{
+#ifdef PLATFORM_MSM8084
+ int32_t modems, (*count_modems)(void);
+ const char *name = "libdetectmodem.so";
+ const char *func = "count_modems";
+ const char *error;
+
+ my_data->csd = NULL;
+
+ void *lib = dlopen(name, RTLD_NOW);
+ error = dlerror();
+ if (!lib) {
+ ALOGE("%s: could not find %s: %s", __func__, name, error);
+ return;
+ }
+
+ count_modems = NULL;
+ *(void **)(&count_modems) = dlsym(lib, func);
+ error = dlerror();
+ if (!count_modems) {
+ ALOGE("%s: could not find symbol %s in %s: %s",
+ __func__, func, name, error);
+ goto done;
+ }
+
+ modems = count_modems();
+ if (modems < 0) {
+ ALOGE("%s: count_modems failed\n", __func__);
+ goto done;
+ }
+
+ ALOGD("%s: num_modems %d\n", __func__, modems);
+ if (modems > 0)
+ my_data->csd = open_csd_client(false /*is_i2s_ext_modem*/);
+
+done:
+ dlclose(lib);
+#else
+ my_data->csd = NULL;
+#endif
+}
+
+static void set_platform_defaults(struct platform_data * my_data)
+{
+ int32_t dev;
+ for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
+ backend_table[dev] = NULL;
+ }
+
+ // TBD - do these go to the platform-info.xml file.
+ // will help in avoiding strdups here
+ backend_table[SND_DEVICE_IN_BT_SCO_MIC] = strdup("bt-sco");
+ backend_table[SND_DEVICE_OUT_BT_SCO] = strdup("bt-sco");
+ backend_table[SND_DEVICE_OUT_HDMI] = strdup("hdmi");
+ backend_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = strdup("speaker-and-hdmi");
+ backend_table[SND_DEVICE_OUT_BT_SCO_WB] = strdup("bt-sco-wb");
+ backend_table[SND_DEVICE_IN_BT_SCO_MIC_WB] = strdup("bt-sco-wb");
+ backend_table[SND_DEVICE_OUT_VOICE_TX] = strdup("afe-proxy");
+ backend_table[SND_DEVICE_IN_VOICE_RX] = strdup("afe-proxy");
+
+ if (my_data->ext_speaker) {
+ backend_table[SND_DEVICE_OUT_SPEAKER] = strdup("speaker");
+ backend_table[SND_DEVICE_OUT_SPEAKER_SAFE] = strdup("speaker");
+ backend_table[SND_DEVICE_OUT_VOICE_SPEAKER] = strdup("speaker");
+ backend_table[SND_DEVICE_OUT_SPEAKER_REVERSE] = strdup("speaker");
+ backend_table[SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] =
+ strdup("speaker-and-headphones");
+ backend_table[SND_DEVICE_OUT_SPEAKER_AND_LINE] =
+ strdup("speaker-and-line");
+ }
+
+ if (my_data->ext_earpiece) {
+ backend_table[SND_DEVICE_OUT_VOICE_HANDSET] = strdup("handset");
+ backend_table[SND_DEVICE_OUT_VOICE_HAC_HANDSET] = strdup("handset");
+ backend_table[SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = strdup("handset");
+ backend_table[SND_DEVICE_OUT_HANDSET] = strdup("handset");
+ backend_table[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = strdup("handset");
+ }
}
void *platform_init(struct audio_device *adev)
{
char value[PROPERTY_VALUE_MAX];
struct platform_data *my_data;
- int retry_num = 0;
+ int retry_num = 0, snd_card_num = 0;
+ const char *snd_card_name;
- adev->mixer = mixer_open(MIXER_CARD);
+ while (snd_card_num < MAX_SND_CARD) {
+ adev->mixer = mixer_open(snd_card_num);
- while (!adev->mixer && retry_num < RETRY_NUMBER) {
- usleep(RETRY_US);
- adev->mixer = mixer_open(MIXER_CARD);
- retry_num++;
+ while (!adev->mixer && retry_num < RETRY_NUMBER) {
+ usleep(RETRY_US);
+ adev->mixer = mixer_open(snd_card_num);
+ retry_num++;
+ }
+
+ if (!adev->mixer) {
+ ALOGE("%s: Unable to open the mixer card: %d", __func__,
+ snd_card_num);
+ retry_num = 0;
+ snd_card_num++;
+ continue;
+ }
+
+ snd_card_name = mixer_get_name(adev->mixer);
+ ALOGD("%s: snd_card_name: %s", __func__, snd_card_name);
+
+ adev->audio_route = audio_route_init(snd_card_num, MIXER_XML_PATH);
+ if (!adev->audio_route) {
+ ALOGE("%s: Failed to init audio route controls, aborting.", __func__);
+ return NULL;
+ }
+ adev->snd_card = snd_card_num;
+ ALOGD("%s: Opened sound card:%d", __func__, snd_card_num);
+ break;
}
- if (!adev->mixer) {
- ALOGE("Unable to open the mixer, aborting.");
- return NULL;
- }
-
- adev->audio_route = audio_route_init(MIXER_CARD, MIXER_XML_PATH);
- if (!adev->audio_route) {
- ALOGE("%s: Failed to init audio route controls, aborting.", __func__);
+ if (snd_card_num >= MAX_SND_CARD) {
+ ALOGE("%s: Unable to find correct sound card, aborting.", __func__);
return NULL;
}
@@ -292,15 +697,28 @@
my_data->dualmic_config = DUALMIC_CONFIG_NONE;
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;
+ /*
+ * The default assumption is that earpiece (handset), speaker and headphones
+ * devices are connected to internal HW codec and communicated through
+ * slimbus backend. If any platform communicates with speaker or earpiece
+ * or headphones through non-slimbus backend such as MI2S or AUXPCM etc.,
+ * the ext_xxxx flags must be set accordingly.
+ */
+ if (strstr(snd_card_name, "tfa9890_stereo")) {
+ my_data->ext_speaker = true;
+ my_data->ext_earpiece = true;
+ } else if (strstr(snd_card_name, "tfa9890")) {
+ my_data->ext_speaker = true;
+ }
+
property_get("persist.audio.dualmic.config",value,"");
if (!strcmp("broadside", value)) {
- my_data->dualmic_config = DUALMIC_CONFIG_BROADSIDE;
- adev->acdb_settings |= DMIC_FLAG;
+ ALOGE("%s: Unsupported dualmic configuration", __func__);
} else if (!strcmp("endfire", value)) {
my_data->dualmic_config = DUALMIC_CONFIG_ENDFIRE;
- adev->acdb_settings |= DMIC_FLAG;
}
if (my_data->dualmic_config != DUALMIC_CONFIG_NONE) {
@@ -309,6 +727,11 @@
my_data->fluence_in_voice_call = true;
}
+ property_get("persist.audio.fluence.voicecomm",value,"");
+ if (!strcmp("true", value)) {
+ my_data->fluence_in_voice_comm = true;
+ }
+
property_get("persist.audio.fluence.voicerec",value,"");
if (!strcmp("true", value)) {
my_data->fluence_in_voice_rec = true;
@@ -327,26 +750,60 @@
ALOGV("%s: DLOPEN successful for %s", __func__, LIB_ACDB_LOADER);
my_data->acdb_deallocate = (acdb_deallocate_t)dlsym(my_data->acdb_handle,
"acdb_loader_deallocate_ACDB");
+ if (!my_data->acdb_deallocate)
+ ALOGE("%s: Could not find the symbol acdb_loader_deallocate_ACDB from %s",
+ __func__, LIB_ACDB_LOADER);
+
my_data->acdb_send_audio_cal = (acdb_send_audio_cal_t)dlsym(my_data->acdb_handle,
"acdb_loader_send_audio_cal");
if (!my_data->acdb_send_audio_cal)
- ALOGW("%s: Could not find the symbol acdb_send_audio_cal from %s",
+ ALOGE("%s: Could not find the symbol acdb_send_audio_cal from %s",
__func__, LIB_ACDB_LOADER);
+
my_data->acdb_send_voice_cal = (acdb_send_voice_cal_t)dlsym(my_data->acdb_handle,
"acdb_loader_send_voice_cal");
+ if (!my_data->acdb_send_voice_cal)
+ ALOGE("%s: Could not find the symbol acdb_loader_send_voice_cal from %s",
+ __func__, LIB_ACDB_LOADER);
+
+ my_data->acdb_reload_vocvoltable = (acdb_reload_vocvoltable_t)dlsym(my_data->acdb_handle,
+ "acdb_loader_reload_vocvoltable");
+ if (!my_data->acdb_reload_vocvoltable)
+ ALOGE("%s: Could not find the symbol acdb_loader_reload_vocvoltable from %s",
+ __func__, LIB_ACDB_LOADER);
+#ifdef PLATFORM_MSM8084
+ my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
+ "acdb_loader_init_v2");
+ if (my_data->acdb_init == NULL)
+ ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__, dlerror());
+ else
+ my_data->acdb_init((char *)snd_card_name);
+#else
my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
"acdb_loader_init_ACDB");
if (my_data->acdb_init == NULL)
ALOGE("%s: dlsym error %s for acdb_loader_init_ACDB", __func__, dlerror());
else
my_data->acdb_init();
+#endif
+
}
+ set_platform_defaults(my_data);
+
+ /* Initialize platform specific ids and/or backends*/
+ platform_info_init();
+
+ /* load csd client */
+ platform_csd_init(my_data);
+
return my_data;
}
void platform_deinit(void *platform)
{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ close_csd_client(my_data->csd);
free(platform);
}
@@ -355,19 +812,25 @@
if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX)
return device_table[snd_device];
else
- return "";
+ return "none";
}
-void platform_add_backend_name(char *mixer_path, snd_device_t snd_device)
+void platform_add_backend_name(void *platform, char *mixer_path,
+ snd_device_t snd_device)
{
- if (snd_device == SND_DEVICE_IN_BT_SCO_MIC)
- strcat(mixer_path, " bt-sco");
- else if(snd_device == SND_DEVICE_OUT_BT_SCO)
- strcat(mixer_path, " bt-sco");
- else if (snd_device == SND_DEVICE_OUT_HDMI)
- strcat(mixer_path, " hdmi");
- else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI)
- strcat(mixer_path, " speaker-and-hdmi");
+ struct platform_data *my_data = (struct platform_data *)platform;
+
+ if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+ ALOGE("%s: Invalid snd_device = %d", __func__, snd_device);
+ return;
+ }
+
+ const char * suffix = backend_table[snd_device];
+
+ if (suffix != NULL) {
+ strcat(mixer_path, " ");
+ strcat(mixer_path, suffix);
+ }
}
int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type)
@@ -380,6 +843,63 @@
return device_id;
}
+static int find_index(const struct name_to_index * table, int32_t len,
+ const char * name)
+{
+ int ret = 0;
+ int32_t i;
+
+ if (table == NULL) {
+ ALOGE("%s: table is NULL", __func__);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ if (name == NULL) {
+ ALOGE("null key");
+ ret = -ENODEV;
+ goto done;
+ }
+
+ for (i=0; i < len; i++) {
+ if (!strcmp(table[i].name, name)) {
+ ret = table[i].index;
+ goto done;
+ }
+ }
+ ALOGE("%s: Could not find index for name = %s",
+ __func__, name);
+ ret = -ENODEV;
+done:
+ return ret;
+}
+
+int platform_get_snd_device_index(char *device_name)
+{
+ return find_index(snd_device_name_index, SND_DEVICE_MAX, device_name);
+}
+
+int platform_get_usecase_index(const char *usecase_name)
+{
+ return find_index(usecase_name_index, AUDIO_USECASE_MAX, usecase_name);
+}
+
+int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id)
+{
+ int ret = 0;
+
+ if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+ ALOGE("%s: Invalid snd_device = %d",
+ __func__, snd_device);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ acdb_device_table[snd_device] = acdb_id;
+done:
+ return ret;
+}
+
int platform_send_audio_calibration(void *platform, snd_device_t snd_device)
{
struct platform_data *my_data = (struct platform_data *)platform;
@@ -392,7 +912,7 @@
return -EINVAL;
}
if (my_data->acdb_send_audio_cal) {
- ("%s: sending audio calibration for snd_device(%d) acdb_id(%d)",
+ ALOGD("%s: sending audio calibration for snd_device(%d) acdb_id(%d)",
__func__, snd_device, acdb_dev_id);
if (snd_device >= SND_DEVICE_OUT_BEGIN &&
snd_device < SND_DEVICE_OUT_END)
@@ -406,7 +926,48 @@
int platform_switch_voice_call_device_pre(void *platform)
{
- return 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int ret = 0;
+
+ if (my_data->csd != NULL &&
+ voice_is_in_call(my_data->adev)) {
+ /* This must be called before disabling mixer controls on APQ side */
+ ret = my_data->csd->disable_device();
+ if (ret < 0) {
+ ALOGE("%s: csd_client_disable_device, failed, error %d",
+ __func__, ret);
+ }
+ }
+ return ret;
+}
+
+int platform_switch_voice_call_enable_device_config(void *platform,
+ snd_device_t out_snd_device,
+ snd_device_t in_snd_device)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int acdb_rx_id, acdb_tx_id;
+ int ret = 0;
+
+ if (my_data->csd == NULL)
+ return ret;
+
+ acdb_rx_id = acdb_device_table[out_snd_device];
+
+ acdb_tx_id = acdb_device_table[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);
+ if (ret < 0) {
+ ALOGE("%s: csd_enable_device_config, failed, error %d",
+ __func__, ret);
+ }
+ } else {
+ ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+ acdb_rx_id, acdb_tx_id);
+ }
+
+ return ret;
}
int platform_switch_voice_call_device_post(void *platform,
@@ -432,14 +993,75 @@
return 0;
}
-int platform_start_voice_call(void *platform)
+int platform_switch_voice_call_usecase_route_post(void *platform,
+ snd_device_t out_snd_device,
+ snd_device_t in_snd_device)
{
- return 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int acdb_rx_id, acdb_tx_id;
+ int ret = 0;
+
+ if (my_data->csd == NULL)
+ return ret;
+
+ acdb_rx_id = acdb_device_table[out_snd_device];
+
+ acdb_tx_id = acdb_device_table[in_snd_device];
+
+ if (acdb_rx_id > 0 && acdb_tx_id > 0) {
+ ret = my_data->csd->enable_device(acdb_rx_id, acdb_tx_id,
+ my_data->adev->acdb_settings);
+ if (ret < 0) {
+ ALOGE("%s: csd_enable_device, failed, error %d", __func__, ret);
+ }
+ } else {
+ ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+ acdb_rx_id, acdb_tx_id);
+ }
+
+ return ret;
}
-int platform_stop_voice_call(void *platform)
+int platform_start_voice_call(void *platform, uint32_t vsid)
{
- return 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int ret = 0;
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->start_voice(vsid);
+ if (ret < 0) {
+ ALOGE("%s: csd_start_voice error %d\n", __func__, ret);
+ }
+ }
+ return ret;
+}
+
+int platform_stop_voice_call(void *platform, uint32_t vsid)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int ret = 0;
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->stop_voice(vsid);
+ if (ret < 0) {
+ ALOGE("%s: csd_stop_voice error %d\n", __func__, ret);
+ }
+ }
+ return ret;
+}
+
+int platform_get_sample_rate(void *platform, uint32_t *rate)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int ret = 0;
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->get_sample_rate(rate);
+ if (ret < 0) {
+ ALOGE("%s: csd_get_sample_rate error %d\n", __func__, ret);
+ }
+ }
+ return ret;
}
int platform_set_voice_volume(void *platform, int volume)
@@ -448,13 +1070,16 @@
struct audio_device *adev = my_data->adev;
struct mixer_ctl *ctl;
const char *mixer_ctl_name = "Voice Rx Gain";
- int values[VOLUME_CTL_PARAM_NUM];
- int ret = 0;
+ int vol_index = 0, ret = 0;
+ uint32_t set_values[ ] = {0,
+ ALL_SESSION_VSID,
+ DEFAULT_VOLUME_RAMP_DURATION_MS};
// 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.
- volume = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX);
+ vol_index = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX);
+ set_values[0] = vol_index;
ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
if (!ctl) {
@@ -462,18 +1087,17 @@
__func__, mixer_ctl_name);
return -EINVAL;
}
- ret = set_volume_values(VOLUME_SET, volume, values);
- if (ret < 0) {
- ALOGV("%s: failed setting volume by incorrect type", __func__);
- return -EINVAL;
- }
- ret = mixer_ctl_set_array(ctl, values, sizeof(values)/sizeof(int));
- if (ret < 0) {
- ALOGV("%s: failed set mixer ctl by %d", __func__, ret);
- return -EINVAL;
- }
+ ALOGV("Setting voice volume index: %d", set_values[0]);
+ mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
- return 0;
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->volume(ALL_SESSION_VSID, volume,
+ DEFAULT_VOLUME_RAMP_DURATION_MS);
+ if (ret < 0) {
+ ALOGE("%s: csd_volume error %d", __func__, ret);
+ }
+ }
+ return ret;
}
int platform_set_mic_mute(void *platform, bool state)
@@ -482,30 +1106,70 @@
struct audio_device *adev = my_data->adev;
struct mixer_ctl *ctl;
const char *mixer_ctl_name = "Voice Tx Mute";
- int values[VOLUME_CTL_PARAM_NUM];
int ret = 0;
+ uint32_t set_values[ ] = {0,
+ ALL_SESSION_VSID,
+ DEFAULT_MUTE_RAMP_DURATION_MS};
- if (adev->mode == AUDIO_MODE_IN_CALL) {
- ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
- if (!ctl) {
- ALOGE("%s: Could not get ctl for mixer cmd - %s",
- __func__, mixer_ctl_name);
- return -EINVAL;
- }
- ALOGV("Setting mic mute: %d", state);
- ret = set_volume_values(MUTE_SET, state, values);
+ if (adev->mode != AUDIO_MODE_IN_CALL)
+ return 0;
+
+ set_values[0] = state;
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ ALOGV("Setting voice mute state: %d", state);
+ mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->mic_mute(ALL_SESSION_VSID, state,
+ DEFAULT_MUTE_RAMP_DURATION_MS);
if (ret < 0) {
- ALOGV("%s: failed setting mute by incorrect type", __func__);
- return -EINVAL;
- }
- ret = mixer_ctl_set_array(ctl, values, sizeof(values)/sizeof(int));
- if (ret < 0) {
- ALOGV("%s: failed set mixer ctl by %d", __func__, ret);
- return -EINVAL;
+ ALOGE("%s: csd_mic_mute error %d", __func__, ret);
}
}
+ return ret;
+}
- return 0;
+int platform_set_device_mute(void *platform, bool state, char *dir)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl;
+ char *mixer_ctl_name = NULL;
+ int ret = 0;
+ uint32_t set_values[ ] = {0,
+ ALL_SESSION_VSID,
+ 0};
+ if(dir == NULL) {
+ ALOGE("%s: Invalid direction:%s", __func__, dir);
+ return -EINVAL;
+ }
+
+ if (!strncmp("rx", dir, sizeof("rx"))) {
+ mixer_ctl_name = "Voice Rx Device Mute";
+ } else if (!strncmp("tx", dir, sizeof("tx"))) {
+ mixer_ctl_name = "Voice Tx Device Mute";
+ } else {
+ return -EINVAL;
+ }
+
+ set_values[0] = state;
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+
+ ALOGV("%s: Setting device mute state: %d, mixer ctrl:%s",
+ __func__,state, mixer_ctl_name);
+ mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+ return ret;
}
snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices)
@@ -522,27 +1186,43 @@
goto exit;
}
- if (mode == AUDIO_MODE_IN_CALL) {
+ if (voice_is_in_call(adev) || adev->enable_voicerx) {
if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
- devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
- if (adev->tty_mode == TTY_MODE_FULL)
+ devices & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+ devices & AUDIO_DEVICE_OUT_LINE) {
+ if (voice_is_in_call(adev) &&
+ (adev->voice.tty_mode == TTY_MODE_FULL))
snd_device = SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES;
- else if (adev->tty_mode == TTY_MODE_VCO)
+ else if (voice_is_in_call(adev) &&
+ (adev->voice.tty_mode == TTY_MODE_VCO))
snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES;
- else if (adev->tty_mode == TTY_MODE_HCO)
+ else if (voice_is_in_call(adev) &&
+ (adev->voice.tty_mode == TTY_MODE_HCO))
snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET;
- else
- snd_device = SND_DEVICE_OUT_VOICE_HEADPHONES;
+ else {
+ if (devices & AUDIO_DEVICE_OUT_LINE)
+ snd_device = SND_DEVICE_OUT_VOICE_LINE;
+ else
+ snd_device = SND_DEVICE_OUT_VOICE_HEADPHONES;
+ }
} else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
- snd_device = SND_DEVICE_OUT_BT_SCO;
- } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
+ if (adev->bt_wb_speech_enabled) {
+ snd_device = SND_DEVICE_OUT_BT_SCO_WB;
+ } else {
+ snd_device = SND_DEVICE_OUT_BT_SCO;
+ }
+ } else if (devices & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
} else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
- if (is_operator_tmus())
+ if(adev->voice.hac)
+ snd_device = SND_DEVICE_OUT_VOICE_HAC_HANDSET;
+ else if (is_operator_tmus())
snd_device = SND_DEVICE_OUT_VOICE_HANDSET_TMUS;
else
- snd_device = SND_DEVICE_OUT_HANDSET;
- }
+ snd_device = SND_DEVICE_OUT_VOICE_HANDSET;
+ } else if (devices & AUDIO_DEVICE_OUT_TELEPHONY_TX)
+ snd_device = SND_DEVICE_OUT_VOICE_TX;
+
if (snd_device != SND_DEVICE_NONE) {
goto exit;
}
@@ -555,6 +1235,9 @@
} else if (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_AUX_DIGITAL |
AUDIO_DEVICE_OUT_SPEAKER)) {
snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI;
@@ -575,17 +1258,29 @@
if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
snd_device = SND_DEVICE_OUT_HEADPHONES;
+ } else if (devices & AUDIO_DEVICE_OUT_LINE) {
+ snd_device = SND_DEVICE_OUT_LINE;
+ } else if (devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+ snd_device = SND_DEVICE_OUT_SPEAKER_SAFE;
} else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
if (adev->speaker_lr_swap)
snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
else
snd_device = SND_DEVICE_OUT_SPEAKER;
} else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
- snd_device = SND_DEVICE_OUT_BT_SCO;
+ if (adev->bt_wb_speech_enabled) {
+ snd_device = SND_DEVICE_OUT_BT_SCO_WB;
+ } else {
+ snd_device = SND_DEVICE_OUT_BT_SCO;
+ }
} else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
snd_device = SND_DEVICE_OUT_HDMI ;
} else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
- snd_device = SND_DEVICE_OUT_HANDSET;
+ /*HAC support for voice-ish audio (eg visual voicemail)*/
+ if(adev->voice.hac)
+ snd_device = SND_DEVICE_OUT_VOICE_HAC_HANDSET;
+ else
+ snd_device = SND_DEVICE_OUT_HANDSET;
} else {
ALOGE("%s: Unknown device(s) %#x", __func__, devices);
}
@@ -608,18 +1303,16 @@
audio_channel_mask_t channel_mask = (adev->active_input == NULL) ?
AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask;
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);
- if (mode == AUDIO_MODE_IN_CALL) {
- if (out_device == AUDIO_DEVICE_NONE) {
- ALOGE("%s: No output device set for voice call", __func__);
- goto exit;
- }
- if (adev->tty_mode != TTY_MODE_OFF) {
+ if ((out_device != AUDIO_DEVICE_NONE) && voice_is_in_call(adev)) {
+ if (adev->voice.tty_mode != TTY_MODE_OFF) {
if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
- out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
- switch (adev->tty_mode) {
+ out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+ out_device & AUDIO_DEVICE_OUT_LINE) {
+ switch (adev->voice.tty_mode) {
case TTY_MODE_FULL:
snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC;
break;
@@ -630,41 +1323,40 @@
snd_device = SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC;
break;
default:
- ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->tty_mode);
+ ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->voice.tty_mode);
}
goto exit;
}
}
- if (out_device & AUDIO_DEVICE_OUT_EARPIECE ||
- out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+ if (out_device & AUDIO_DEVICE_OUT_EARPIECE) {
if (my_data->fluence_in_voice_call == false) {
snd_device = SND_DEVICE_IN_HANDSET_MIC;
} else {
- if (my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) {
- if (is_operator_tmus())
- snd_device = SND_DEVICE_IN_VOICE_DMIC_EF_TMUS;
- else
- snd_device = SND_DEVICE_IN_VOICE_DMIC_EF;
- } else if(my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE)
- snd_device = SND_DEVICE_IN_VOICE_DMIC_BS;
+ if (is_operator_tmus())
+ snd_device = SND_DEVICE_IN_VOICE_DMIC_TMUS;
else
- snd_device = SND_DEVICE_IN_HANDSET_MIC;
+ snd_device = SND_DEVICE_IN_VOICE_DMIC;
}
} else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC;
} else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
- snd_device = SND_DEVICE_IN_BT_SCO_MIC ;
- } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
+ if (adev->bt_wb_speech_enabled) {
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+ } else {
+ 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_ENDFIRE) {
- snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF;
- } else if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode &&
- my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) {
- snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS;
+ my_data->dualmic_config != DUALMIC_CONFIG_NONE) {
+ snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC;
} else {
snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
}
- }
+ } 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) {
@@ -672,37 +1364,78 @@
}
} else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) {
if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- if (my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) {
+ if (my_data->dualmic_config != DUALMIC_CONFIG_NONE) {
if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK)
- snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_EF;
- else if (my_data->fluence_in_voice_rec)
- snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE;
- } else if (my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) {
- if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK)
- snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_BS;
- else if (my_data->fluence_in_voice_rec)
- snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE;
+ snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_STEREO;
+ else if (my_data->fluence_in_voice_rec &&
+ adev->active_input->enable_ns)
+ snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE;
}
if (snd_device == SND_DEVICE_NONE) {
- snd_device = SND_DEVICE_IN_VOICE_REC_MIC;
+ 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 (source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
- if (out_device & AUDIO_DEVICE_OUT_SPEAKER)
+ if (out_device & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE))
in_device = AUDIO_DEVICE_IN_BACK_MIC;
if (adev->active_input) {
- if (adev->active_input->enable_aec) {
+ if (adev->active_input->enable_aec &&
+ adev->active_input->enable_ns) {
if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
- snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC;
+ if (my_data->fluence_in_spkr_mode &&
+ my_data->fluence_in_voice_comm &&
+ my_data->dualmic_config != DUALMIC_CONFIG_NONE) {
+ snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
+ } else
+ snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
} else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC;
+ if (my_data->fluence_in_voice_comm &&
+ my_data->dualmic_config != DUALMIC_CONFIG_NONE) {
+ snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC_NS;
+ } 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;
}
- set_echo_reference(adev->mixer, "SLIM_RX");
- } else
- set_echo_reference(adev->mixer, "NONE");
+ platform_set_echo_reference(adev, true, out_device);
+ } else if (adev->active_input->enable_aec) {
+ 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) {
+ snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC;
+ } 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) {
+ snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC;
+ } 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;
+ }
+ platform_set_echo_reference(adev, true, out_device);
+ } else if (adev->active_input->enable_ns) {
+ 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) {
+ snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS;
+ } 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) {
+ snd_device = SND_DEVICE_IN_HANDSET_DMIC_NS;
+ } else
+ snd_device = SND_DEVICE_IN_HANDSET_MIC_NS;
+ }
+ }
}
} else if (source == AUDIO_SOURCE_DEFAULT) {
goto exit;
@@ -717,13 +1450,25 @@
!(in_device & AUDIO_DEVICE_IN_VOICE_CALL) &&
!(in_device & AUDIO_DEVICE_IN_COMMUNICATION)) {
if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- snd_device = SND_DEVICE_IN_HANDSET_MIC;
+ if (my_data->dualmic_config != DUALMIC_CONFIG_NONE &&
+ channel_count == 2)
+ snd_device = SND_DEVICE_IN_HANDSET_DMIC_STEREO;
+ else
+ snd_device = SND_DEVICE_IN_HANDSET_MIC;
} else if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
- snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+ if (my_data->dualmic_config != DUALMIC_CONFIG_NONE &&
+ channel_count == 2)
+ snd_device = SND_DEVICE_IN_SPEAKER_DMIC_STEREO;
+ else
+ 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) {
- snd_device = SND_DEVICE_IN_BT_SCO_MIC ;
+ if (adev->bt_wb_speech_enabled) {
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+ } else {
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+ }
} else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) {
snd_device = SND_DEVICE_IN_HDMI_MIC;
} else {
@@ -736,12 +1481,20 @@
snd_device = SND_DEVICE_IN_HANDSET_MIC;
} else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
snd_device = SND_DEVICE_IN_HEADSET_MIC;
- } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
- snd_device = SND_DEVICE_IN_SPEAKER_MIC;
- } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
- snd_device = SND_DEVICE_IN_HANDSET_MIC;
+ } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER ||
+ out_device & AUDIO_DEVICE_OUT_SPEAKER_SAFE ||
+ out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+ out_device & AUDIO_DEVICE_OUT_LINE) {
+ if (channel_count == 2)
+ snd_device = SND_DEVICE_IN_SPEAKER_DMIC_STEREO;
+ else
+ snd_device = SND_DEVICE_IN_SPEAKER_MIC;
} else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) {
- snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+ if (adev->bt_wb_speech_enabled) {
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+ } else {
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+ }
} else if (out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
snd_device = SND_DEVICE_IN_HDMI_MIC;
} else {
@@ -844,6 +1597,92 @@
return max_channels;
}
+int platform_set_incall_recording_session_id(void *platform,
+ uint32_t session_id, int rec_mode)
+{
+ int ret = 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "Voc VSID";
+ int num_ctl_values;
+ int i;
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ ret = -EINVAL;
+ } else {
+ num_ctl_values = mixer_ctl_get_num_values(ctl);
+ for (i = 0; i < num_ctl_values; i++) {
+ if (mixer_ctl_set_value(ctl, i, session_id)) {
+ ALOGV("Error: invalid session_id: %x", session_id);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ }
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->start_record(ALL_SESSION_VSID, rec_mode);
+ if (ret < 0) {
+ ALOGE("%s: csd_client_start_record failed, error %d",
+ __func__, ret);
+ }
+ }
+
+ return ret;
+}
+
+int platform_stop_incall_recording_usecase(void *platform)
+{
+ int ret = 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->stop_record(ALL_SESSION_VSID);
+ if (ret < 0) {
+ ALOGE("%s: csd_client_stop_record failed, error %d",
+ __func__, ret);
+ }
+ }
+
+ return ret;
+}
+
+int platform_start_incall_music_usecase(void *platform)
+{
+ int ret = 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->start_playback(ALL_SESSION_VSID);
+ if (ret < 0) {
+ ALOGE("%s: csd_client_start_playback failed, error %d",
+ __func__, ret);
+ }
+ }
+
+ return ret;
+}
+
+int platform_stop_incall_music_usecase(void *platform)
+{
+ int ret = 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->stop_playback(ALL_SESSION_VSID);
+ if (ret < 0) {
+ ALOGE("%s: csd_client_stop_playback failed, error %d",
+ __func__, ret);
+ }
+ }
+
+ return ret;
+}
+
/* Delay in Us */
int64_t platform_render_latency(audio_usecase_t usecase)
{
@@ -856,3 +1695,40 @@
return 0;
}
}
+
+int platform_set_snd_device_backend(snd_device_t device, const char *backend)
+{
+ int ret = 0;
+
+ if ((device < SND_DEVICE_MIN) || (device >= SND_DEVICE_MAX)) {
+ ALOGE("%s: Invalid snd_device = %d",
+ __func__, device);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (backend_table[device]) {
+ free(backend_table[device]);
+ }
+ backend_table[device] = strdup(backend);
+done:
+ return ret;
+}
+
+int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id)
+{
+ int ret = 0;
+ if ((usecase <= USECASE_INVALID) || (usecase >= AUDIO_USECASE_MAX)) {
+ ALOGE("%s: invalid usecase case idx %d", __func__, usecase);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((type != 0) && (type != 1)) {
+ ALOGE("%s: invalid usecase type", __func__);
+ ret = -EINVAL;
+ }
+ pcm_device_table[usecase][type] = pcm_id;
+done:
+ return ret;
+}
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index a6b3c31..4dc83bb 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2013-2014 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.
@@ -24,6 +24,7 @@
*/
#define AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND \
(AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | \
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE | \
AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE)
/* Sound devices specific to the platform
@@ -39,18 +40,25 @@
SND_DEVICE_OUT_HANDSET = SND_DEVICE_OUT_BEGIN,
SND_DEVICE_OUT_SPEAKER,
SND_DEVICE_OUT_SPEAKER_REVERSE,
+ SND_DEVICE_OUT_SPEAKER_SAFE,
SND_DEVICE_OUT_HEADPHONES,
+ SND_DEVICE_OUT_LINE,
SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_LINE,
SND_DEVICE_OUT_VOICE_HANDSET,
SND_DEVICE_OUT_VOICE_SPEAKER,
SND_DEVICE_OUT_VOICE_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_LINE,
SND_DEVICE_OUT_HDMI,
SND_DEVICE_OUT_SPEAKER_AND_HDMI,
SND_DEVICE_OUT_BT_SCO,
+ SND_DEVICE_OUT_BT_SCO_WB,
SND_DEVICE_OUT_VOICE_HANDSET_TMUS,
SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET,
+ SND_DEVICE_OUT_VOICE_HAC_HANDSET,
+ SND_DEVICE_OUT_VOICE_TX,
SND_DEVICE_OUT_END,
/*
@@ -60,46 +68,80 @@
/* Capture devices */
SND_DEVICE_IN_BEGIN = SND_DEVICE_OUT_END,
SND_DEVICE_IN_HANDSET_MIC = SND_DEVICE_IN_BEGIN,
- SND_DEVICE_IN_SPEAKER_MIC,
- SND_DEVICE_IN_HEADSET_MIC,
SND_DEVICE_IN_HANDSET_MIC_AEC,
+ SND_DEVICE_IN_HANDSET_MIC_NS,
+ SND_DEVICE_IN_HANDSET_MIC_AEC_NS,
+ SND_DEVICE_IN_HANDSET_DMIC,
+ SND_DEVICE_IN_HANDSET_DMIC_AEC,
+ SND_DEVICE_IN_HANDSET_DMIC_NS,
+ SND_DEVICE_IN_HANDSET_DMIC_AEC_NS,
+ SND_DEVICE_IN_HANDSET_DMIC_STEREO,
+
+ SND_DEVICE_IN_SPEAKER_MIC,
SND_DEVICE_IN_SPEAKER_MIC_AEC,
+ SND_DEVICE_IN_SPEAKER_MIC_NS,
+ SND_DEVICE_IN_SPEAKER_MIC_AEC_NS,
+ SND_DEVICE_IN_SPEAKER_DMIC,
+ SND_DEVICE_IN_SPEAKER_DMIC_AEC,
+ SND_DEVICE_IN_SPEAKER_DMIC_NS,
+ SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS,
+ SND_DEVICE_IN_SPEAKER_DMIC_STEREO,
+
+ SND_DEVICE_IN_HEADSET_MIC,
SND_DEVICE_IN_HEADSET_MIC_AEC,
- SND_DEVICE_IN_VOICE_SPEAKER_MIC,
- SND_DEVICE_IN_VOICE_HEADSET_MIC,
+
SND_DEVICE_IN_HDMI_MIC,
SND_DEVICE_IN_BT_SCO_MIC,
+ SND_DEVICE_IN_BT_SCO_MIC_WB,
+
SND_DEVICE_IN_CAMCORDER_MIC,
- SND_DEVICE_IN_VOICE_DMIC_EF,
- SND_DEVICE_IN_VOICE_DMIC_BS,
- SND_DEVICE_IN_VOICE_DMIC_EF_TMUS,
- SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF,
- SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS,
+
+ SND_DEVICE_IN_VOICE_DMIC,
+ SND_DEVICE_IN_VOICE_DMIC_TMUS,
+ SND_DEVICE_IN_VOICE_SPEAKER_MIC,
+ SND_DEVICE_IN_VOICE_SPEAKER_DMIC,
+ SND_DEVICE_IN_VOICE_HEADSET_MIC,
SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC,
SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC,
SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC,
+
SND_DEVICE_IN_VOICE_REC_MIC,
- SND_DEVICE_IN_VOICE_REC_DMIC_EF,
- SND_DEVICE_IN_VOICE_REC_DMIC_BS,
- SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE,
- SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE,
+ SND_DEVICE_IN_VOICE_REC_MIC_NS,
+ SND_DEVICE_IN_VOICE_REC_DMIC_STEREO,
+ SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+
+ SND_DEVICE_IN_VOICE_RX,
+
SND_DEVICE_IN_END,
SND_DEVICE_MAX = SND_DEVICE_IN_END,
};
-#define MIXER_CARD 0
-#define SOUND_CARD 0
-
#define DEFAULT_OUTPUT_SAMPLING_RATE 48000
-#define ALL_SESSION_VSID 0xFFFFFFFF
-#define DEFAULT_MUTE_RAMP_DURATION 500
+#define ALL_SESSION_VSID 0xFFFFFFFF
+#define DEFAULT_MUTE_RAMP_DURATION_MS 20
#define DEFAULT_VOLUME_RAMP_DURATION_MS 20
-#define VOLUME_SET 0
-#define MUTE_SET 1
-#define VOLUME_CTL_PARAM_NUM 3
+
+#ifdef PLATFORM_MSM8084
+#define ACDB_ID_VOICE_SPEAKER 66
+#define ACDB_ID_VOICE_HANDSET 67
+#define ACDB_ID_VOICE_HANDSET_TMUS 67
+#define ACDB_ID_VOICE_DMIC_EF_TMUS 89
+#define ACDB_ID_HEADSET_MIC_AEC 47
+#else
+#define ACDB_ID_VOICE_SPEAKER 15
+#define ACDB_ID_VOICE_HANDSET 7
+#define ACDB_ID_VOICE_HANDSET_TMUS 88
+#define ACDB_ID_VOICE_DMIC_EF_TMUS 89
+#define ACDB_ID_HEADSET_MIC_AEC 10
+#endif
+
+#define MAX_VOL_INDEX 5
+#define MIN_VOL_INDEX 0
+#define percent_to_index(val, min, max) \
+ ((val) * ((max) - (min)) * 0.01 + (min) + .5)
/*
* tinyAlsa library interprets period size as number of frames
@@ -122,4 +164,79 @@
#define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
#define AUDIO_CAPTURE_PERIOD_COUNT 2
+#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
+#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
+#define LOW_LATENCY_CAPTURE_USE_CASE 1
+
+#define DEEP_BUFFER_PCM_DEVICE 0
+#define AUDIO_RECORD_PCM_DEVICE 0
+#define MULTIMEDIA2_PCM_DEVICE 1
+#define PLAYBACK_OFFLOAD_DEVICE 9
+#define LOWLATENCY_PCM_DEVICE 15
+#define VOICE_VSID 0x10C01000
+#ifdef PLATFORM_MSM8084
+#define VOICE_CALL_PCM_DEVICE 20
+#define VOICE2_CALL_PCM_DEVICE 25
+#define VOLTE_CALL_PCM_DEVICE 21
+#define QCHAT_CALL_PCM_DEVICE 33
+#define VOWLAN_CALL_PCM_DEVICE -1
+#else
+#define VOICE_CALL_PCM_DEVICE 2
+#define VOICE2_CALL_PCM_DEVICE 22
+#define VOLTE_CALL_PCM_DEVICE 14
+#define QCHAT_CALL_PCM_DEVICE 20
+#define VOWLAN_CALL_PCM_DEVICE 36
+#endif
+
+#define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
+#define AFE_PROXY_RECORD_PCM_DEVICE 8
+
+#define HFP_PCM_RX 5
+#ifdef PLATFORM_MSM8x26
+#define HFP_SCO_RX 28
+#define HFP_ASM_RX_TX 29
+#else
+#define HFP_SCO_RX 23
+#define HFP_ASM_RX_TX 24
+#endif
+
+#define LIB_CSD_CLIENT "libcsd-client.so"
+#define LIB_MDM_DETECT "libmdmdetect.so"
+
+/* CSD-CLIENT related functions */
+typedef int (*init_t)(bool);
+typedef int (*deinit_t)();
+typedef int (*disable_device_t)();
+typedef int (*enable_device_config_t)(int, int);
+typedef int (*enable_device_t)(int, int, uint32_t);
+typedef int (*volume_t)(uint32_t, int, uint16_t);
+typedef int (*mic_mute_t)(uint32_t, int, uint16_t);
+typedef int (*slow_talk_t)(uint32_t, uint8_t);
+typedef int (*start_voice_t)(uint32_t);
+typedef int (*stop_voice_t)(uint32_t);
+typedef int (*start_playback_t)(uint32_t);
+typedef int (*stop_playback_t)(uint32_t);
+typedef int (*start_record_t)(uint32_t, int);
+typedef int (*stop_record_t)(uint32_t);
+typedef int (*get_sample_rate_t)(uint32_t *);
+/* CSD Client structure */
+struct csd_data {
+ void *csd_client;
+ init_t init;
+ deinit_t deinit;
+ disable_device_t disable_device;
+ enable_device_config_t enable_device_config;
+ enable_device_t enable_device;
+ volume_t volume;
+ mic_mute_t mic_mute;
+ slow_talk_t slow_talk;
+ start_voice_t start_voice;
+ stop_voice_t stop_voice;
+ start_playback_t start_playback;
+ stop_playback_t stop_playback;
+ start_record_t start_record;
+ stop_record_t stop_record;
+ get_sample_rate_t get_sample_rate;
+};
+
#endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/platform_api.h b/hal/platform_api.h
index afd2ee4..e50e06d 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2013-2014 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.
@@ -14,23 +14,34 @@
* limitations under the License.
*/
-#ifndef QCOM_AUDIO_PLATFORM_API_H
-#define QCOM_AUDIO_PLATFORM_API_H
+#ifndef AUDIO_PLATFORM_API_H
+#define AUDIO_PLATFORM_API_H
void *platform_init(struct audio_device *adev);
void platform_deinit(void *platform);
const char *platform_get_snd_device_name(snd_device_t snd_device);
-void platform_add_backend_name(char *mixer_path, snd_device_t snd_device);
+void platform_add_backend_name(void *platform, char *mixer_path,
+ snd_device_t snd_device);
int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type);
+int platform_get_snd_device_index(char *snd_device_index_name);
+int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id);
int platform_send_audio_calibration(void *platform, snd_device_t snd_device);
int platform_switch_voice_call_device_pre(void *platform);
+int platform_switch_voice_call_enable_device_config(void *platform,
+ snd_device_t out_snd_device,
+ snd_device_t in_snd_device);
int platform_switch_voice_call_device_post(void *platform,
snd_device_t out_snd_device,
snd_device_t in_snd_device);
-int platform_start_voice_call(void *platform);
-int platform_stop_voice_call(void *platform);
+int platform_switch_voice_call_usecase_route_post(void *platform,
+ snd_device_t out_snd_device,
+ snd_device_t in_snd_device);
+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);
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);
snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices);
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);
@@ -39,4 +50,19 @@
/* returns the latency for a usecase in Us */
int64_t platform_render_latency(audio_usecase_t usecase);
-#endif // QCOM_AUDIO_PLATFORM_API_H
+int platform_set_incall_recording_session_id(void *platform,
+ uint32_t session_id, int rec_mode);
+int platform_stop_incall_recording_usecase(void *platform);
+int platform_start_incall_music_usecase(void *platform);
+int platform_stop_incall_music_usecase(void *platform);
+
+int platform_set_snd_device_backend(snd_device_t snd_device, const char * backend);
+
+/* From platform_info_parser.c */
+int platform_info_init(void);
+
+int platform_get_usecase_index(const char * usecase);
+int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id);
+void platform_set_echo_reference(struct audio_device *adev, bool enable, audio_devices_t out_device);
+
+#endif // AUDIO_PLATFORM_API_H
diff --git a/hal/platform_info.c b/hal/platform_info.c
new file mode 100644
index 0000000..832c0f0
--- /dev/null
+++ b/hal/platform_info.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2014 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 "platform_info"
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <stdio.h>
+#include <expat.h>
+#include <cutils/log.h>
+#include <audio_hw.h>
+#include "platform_api.h"
+#include <platform.h>
+
+#define PLATFORM_INFO_XML_PATH "/system/etc/audio_platform_info.xml"
+
+typedef enum {
+ ROOT,
+ ACDB,
+ PCM_ID,
+ BACKEND_NAME,
+} section_t;
+
+typedef void (* section_process_fn)(const XML_Char **attr);
+
+static void process_acdb_id(const XML_Char **attr);
+static void process_pcm_id(const XML_Char **attr);
+static void process_backend_name(const XML_Char **attr);
+static void process_root(const XML_Char **attr);
+
+static section_process_fn section_table[] = {
+ [ROOT] = process_root,
+ [ACDB] = process_acdb_id,
+ [PCM_ID] = process_pcm_id,
+ [BACKEND_NAME] = process_backend_name,
+};
+
+static section_t section;
+
+/*
+ * <audio_platform_info>
+ * <acdb_ids>
+ * <device name="???" acdb_id="???"/>
+ * ...
+ * ...
+ * </acdb_ids>
+ * <backend_names>
+ * <device name="???" backend="???"/>
+ * ...
+ * ...
+ * </backend_names>
+ * <pcm_ids>
+ * <usecase name="???" type="in/out" id="???"/>
+ * ...
+ * ...
+ * </pcm_ids>
+ * </audio_platform_info>
+ */
+
+static void process_root(const XML_Char **attr __unused)
+{
+}
+
+/* mapping from usecase to pcm dev id */
+static void process_pcm_id(const XML_Char **attr)
+{
+ int index;
+
+ if (strcmp(attr[0], "name") != 0) {
+ ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
+ goto done;
+ }
+
+ index = platform_get_usecase_index((char *)attr[1]);
+ if (index < 0) {
+ ALOGE("%s: usecase %s in %s not found!",
+ __func__, attr[1], PLATFORM_INFO_XML_PATH);
+ goto done;
+ }
+
+ if (strcmp(attr[2], "type") != 0) {
+ ALOGE("%s: usecase type not mentioned", __func__);
+ goto done;
+ }
+
+ int type = -1;
+
+ if (!strcasecmp((char *)attr[3], "in")) {
+ type = 1;
+ } else if (!strcasecmp((char *)attr[3], "out")) {
+ type = 0;
+ } else {
+ ALOGE("%s: type must be IN or OUT", __func__);
+ goto done;
+ }
+
+ if (strcmp(attr[4], "id") != 0) {
+ ALOGE("%s: usecase id not mentioned", __func__);
+ goto done;
+ }
+
+ int id = atoi((char *)attr[5]);
+
+ if (platform_set_usecase_pcm_id(index, type, id) < 0) {
+ ALOGE("%s: usecase %s in %s, type %d id %d was not set!",
+ __func__, attr[1], PLATFORM_INFO_XML_PATH, type, id);
+ goto done;
+ }
+
+done:
+ return;
+}
+
+/* backend to be used for a device */
+static void process_backend_name(const XML_Char **attr)
+{
+ int index;
+
+ if (strcmp(attr[0], "name") != 0) {
+ ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
+ goto done;
+ }
+
+ index = platform_get_snd_device_index((char *)attr[1]);
+ if (index < 0) {
+ ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
+ __func__, attr[1], PLATFORM_INFO_XML_PATH);
+ goto done;
+ }
+
+ if (strcmp(attr[2], "backend") != 0) {
+ ALOGE("%s: Device %s in %s has no backed set!",
+ __func__, attr[1], PLATFORM_INFO_XML_PATH);
+ goto done;
+ }
+
+ if (platform_set_snd_device_backend(index, attr[3]) < 0) {
+ ALOGE("%s: Device %s in %s, backend %s was not set!",
+ __func__, attr[1], PLATFORM_INFO_XML_PATH, attr[3]);
+ goto done;
+ }
+
+done:
+ return;
+}
+
+static void process_acdb_id(const XML_Char **attr)
+{
+ int index;
+
+ if (strcmp(attr[0], "name") != 0) {
+ ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
+ goto done;
+ }
+
+ index = platform_get_snd_device_index((char *)attr[1]);
+ if (index < 0) {
+ ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
+ __func__, attr[1], PLATFORM_INFO_XML_PATH);
+ goto done;
+ }
+
+ if (strcmp(attr[2], "acdb_id") != 0) {
+ ALOGE("%s: Device %s in %s has no acdb_id, no ACDB ID set!",
+ __func__, attr[1], PLATFORM_INFO_XML_PATH);
+ goto done;
+ }
+
+ if (platform_set_snd_device_acdb_id(index, atoi((char *)attr[3])) < 0) {
+ ALOGE("%s: Device %s in %s, ACDB ID %d was not set!",
+ __func__, attr[1], PLATFORM_INFO_XML_PATH, atoi((char *)attr[3]));
+ goto done;
+ }
+
+done:
+ return;
+}
+
+static void start_tag(void *userdata __unused, const XML_Char *tag_name,
+ const XML_Char **attr)
+{
+ const XML_Char *attr_name = NULL;
+ const XML_Char *attr_value = NULL;
+ unsigned int i;
+
+ if (strcmp(tag_name, "acdb_ids") == 0) {
+ section = ACDB;
+ } else if (strcmp(tag_name, "pcm_ids") == 0) {
+ section = PCM_ID;
+ } else if (strcmp(tag_name, "backend_names") == 0) {
+ section = BACKEND_NAME;
+ } else if (strcmp(tag_name, "device") == 0) {
+ if ((section != ACDB) && (section != BACKEND_NAME)) {
+ ALOGE("device tag only supported for acdb/backend names");
+ return;
+ }
+
+ /* call into process function for the current section */
+ section_process_fn fn = section_table[section];
+ fn(attr);
+ } else if (strcmp(tag_name, "usecase") == 0) {
+ if (section != PCM_ID) {
+ ALOGE("usecase tag only supported with PCM_ID section");
+ return;
+ }
+
+ section_process_fn fn = section_table[PCM_ID];
+ fn(attr);
+ }
+
+ return;
+}
+
+static void end_tag(void *userdata __unused, const XML_Char *tag_name)
+{
+ if (strcmp(tag_name, "acdb_ids") == 0) {
+ section = ROOT;
+ } else if (strcmp(tag_name, "pcm_ids") == 0) {
+ section = ROOT;
+ } else if (strcmp(tag_name, "backend_names") == 0) {
+ section = ROOT;
+ }
+}
+
+int platform_info_init(void)
+{
+ XML_Parser parser;
+ FILE *file;
+ int ret = 0;
+ int bytes_read;
+ void *buf;
+ static const uint32_t kBufSize = 1024;
+
+ section = ROOT;
+
+ file = fopen(PLATFORM_INFO_XML_PATH, "r");
+ if (!file) {
+ ALOGD("%s: Failed to open %s, using defaults.",
+ __func__, PLATFORM_INFO_XML_PATH);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ parser = XML_ParserCreate(NULL);
+ if (!parser) {
+ ALOGE("%s: Failed to create XML parser!", __func__);
+ ret = -ENODEV;
+ goto err_close_file;
+ }
+
+ XML_SetElementHandler(parser, start_tag, end_tag);
+
+ while (1) {
+ buf = XML_GetBuffer(parser, kBufSize);
+ if (buf == NULL) {
+ ALOGE("%s: XML_GetBuffer failed", __func__);
+ ret = -ENOMEM;
+ goto err_free_parser;
+ }
+
+ bytes_read = fread(buf, 1, kBufSize, file);
+ if (bytes_read < 0) {
+ ALOGE("%s: fread failed, bytes read = %d", __func__, bytes_read);
+ ret = bytes_read;
+ goto err_free_parser;
+ }
+
+ if (XML_ParseBuffer(parser, bytes_read,
+ bytes_read == 0) == XML_STATUS_ERROR) {
+ ALOGE("%s: XML_ParseBuffer failed, for %s",
+ __func__, PLATFORM_INFO_XML_PATH);
+ ret = -EINVAL;
+ goto err_free_parser;
+ }
+
+ if (bytes_read == 0)
+ break;
+ }
+
+err_free_parser:
+ XML_ParserFree(parser);
+err_close_file:
+ fclose(file);
+done:
+ return ret;
+}
diff --git a/hal/voice.c b/hal/voice.c
new file mode 100644
index 0000000..044dc28
--- /dev/null
+++ b/hal/voice.c
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2014 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 "voice"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <math.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+
+#include "audio_hw.h"
+#include "voice.h"
+#include "voice_extn/voice_extn.h"
+#include "platform.h"
+#include "platform_api.h"
+
+struct pcm_config pcm_config_voice_call = {
+ .channels = 1,
+ .rate = 8000,
+ .period_size = 160,
+ .period_count = 2,
+ .format = PCM_FORMAT_S16_LE,
+};
+
+static struct voice_session *voice_get_session_from_use_case(struct audio_device *adev,
+ audio_usecase_t usecase_id)
+{
+ struct voice_session *session = NULL;
+ int ret = 0;
+
+ ret = voice_extn_get_session_from_use_case(adev, usecase_id, &session);
+ if (ret == -ENOSYS) {
+ session = &adev->voice.session[VOICE_SESS_IDX];
+ }
+
+ return session;
+}
+
+int voice_stop_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
+{
+ int i, ret = 0;
+ struct audio_usecase *uc_info;
+ struct voice_session *session = NULL;
+
+ ALOGD("%s: enter usecase:%s", __func__, use_case_table[usecase_id]);
+
+ session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id);
+ session->state.current = CALL_INACTIVE;
+
+ ret = platform_stop_voice_call(adev->platform, session->vsid);
+
+ /* 1. Close the PCM devices */
+ if (session->pcm_rx) {
+ pcm_close(session->pcm_rx);
+ session->pcm_rx = NULL;
+ }
+ if (session->pcm_tx) {
+ pcm_close(session->pcm_tx);
+ 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);
+
+ /* 3. Disable the rx and tx devices */
+ disable_snd_device(adev, uc_info->out_snd_device);
+ disable_snd_device(adev, uc_info->in_snd_device);
+
+ list_remove(&uc_info->list);
+ free(uc_info);
+
+ ALOGD("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+
+int voice_start_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
+{
+ int i, ret = 0;
+ struct audio_usecase *uc_info;
+ int pcm_dev_rx_id, pcm_dev_tx_id;
+ struct voice_session *session = NULL;
+ struct pcm_config voice_config = pcm_config_voice_call;
+
+ 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 = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+ uc_info->id = usecase_id;
+ uc_info->type = VOICE_CALL;
+ uc_info->stream.out = adev->current_call_output ;
+ uc_info->devices = adev->current_call_output ->devices;
+ uc_info->in_snd_device = SND_DEVICE_NONE;
+ uc_info->out_snd_device = SND_DEVICE_NONE;
+
+ list_add_tail(&adev->usecase_list, &uc_info->list);
+
+ select_devices(adev, usecase_id);
+
+ pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
+ pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
+
+ if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) {
+ ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)",
+ __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
+ 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,
+ pcm_dev_rx_id,
+ PCM_OUT, &voice_config);
+ if (session->pcm_rx && !pcm_is_ready(session->pcm_rx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_rx));
+ ret = -EIO;
+ 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);
+
+ voice_set_volume(adev, adev->voice.volume);
+
+ ret = platform_start_voice_call(adev->platform, session->vsid);
+ if (ret < 0) {
+ ALOGE("%s: platform_start_voice_call error %d\n", __func__, ret);
+ goto error_start_voice;
+ }
+
+ session->state.current = CALL_ACTIVE;
+ goto done;
+
+error_start_voice:
+ voice_stop_usecase(adev, usecase_id);
+
+done:
+ ALOGD("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+
+bool voice_is_call_state_active(struct audio_device *adev)
+{
+ bool call_state = false;
+ int ret = 0;
+
+ ret = voice_extn_is_call_state_active(adev, &call_state);
+ if (ret == -ENOSYS) {
+ call_state = (adev->voice.session[VOICE_SESS_IDX].state.current == CALL_ACTIVE) ? true : false;
+ }
+
+ return call_state;
+}
+
+bool voice_is_in_call(struct audio_device *adev)
+{
+ return adev->voice.in_call;
+}
+
+bool voice_is_in_call_rec_stream(struct stream_in *in)
+{
+ bool in_call_rec = false;
+ int ret = 0;
+
+ ret = voice_extn_is_in_call_rec_stream(in, &in_call_rec);
+ if (ret == -ENOSYS) {
+ in_call_rec = false;
+ }
+
+ return in_call_rec;
+}
+
+uint32_t voice_get_active_session_id(struct audio_device *adev)
+{
+ int ret = 0;
+ uint32_t session_id;
+
+ ret = voice_extn_get_active_session_id(adev, &session_id);
+ if (ret == -ENOSYS) {
+ session_id = VOICE_VSID;
+ }
+ return session_id;
+}
+
+int voice_check_and_set_incall_rec_usecase(struct audio_device *adev,
+ struct stream_in *in)
+{
+ int ret = 0;
+ uint32_t session_id;
+ int usecase_id;
+ int rec_mode = INCALL_REC_NONE;
+
+ if (voice_is_call_state_active(adev)) {
+ switch (in->source) {
+ case AUDIO_SOURCE_VOICE_UPLINK:
+ in->usecase = USECASE_INCALL_REC_UPLINK;
+ rec_mode = INCALL_REC_UPLINK;
+ break;
+ case AUDIO_SOURCE_VOICE_DOWNLINK:
+ in->usecase = USECASE_INCALL_REC_DOWNLINK;
+ rec_mode = INCALL_REC_DOWNLINK;
+ break;
+ case AUDIO_SOURCE_VOICE_CALL:
+ in->usecase = USECASE_INCALL_REC_UPLINK_AND_DOWNLINK;
+ rec_mode = INCALL_REC_UPLINK_AND_DOWNLINK;
+ break;
+ default:
+ ALOGV("%s: Source type %d doesnt match incall recording criteria",
+ __func__, in->source);
+ return ret;
+ }
+
+ session_id = voice_get_active_session_id(adev);
+ ret = platform_set_incall_recording_session_id(adev->platform,
+ session_id, rec_mode);
+ ALOGV("%s: Update usecase to %d",__func__, in->usecase);
+ } else {
+ ALOGV("%s: voice call not active", __func__);
+ }
+
+ return ret;
+}
+
+int voice_check_and_stop_incall_rec_usecase(struct audio_device *adev,
+ struct stream_in *in)
+{
+ int ret = 0;
+
+ if (in->source == AUDIO_SOURCE_VOICE_UPLINK ||
+ in->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
+ in->source == AUDIO_SOURCE_VOICE_CALL) {
+ ret = platform_stop_incall_recording_usecase(adev->platform);
+ ALOGV("%s: Stop In-call recording", __func__);
+ }
+
+ return ret;
+}
+
+int voice_check_and_set_incall_music_usecase(struct audio_device *adev,
+ struct stream_out *out)
+{
+ int ret = 0;
+
+ ret = voice_extn_check_and_set_incall_music_usecase(adev, out);
+ if (ret == -ENOSYS) {
+ /* Incall music delivery is used only for LCH call state */
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+int voice_set_mic_mute(struct audio_device *adev, bool state)
+{
+ int err = 0;
+
+ adev->voice.mic_mute = state;
+ if (adev->mode == AUDIO_MODE_IN_CALL)
+ err = platform_set_mic_mute(adev->platform, state);
+
+ return err;
+}
+
+bool voice_get_mic_mute(struct audio_device *adev)
+{
+ return adev->voice.mic_mute;
+}
+
+int voice_set_volume(struct audio_device *adev, float volume)
+{
+ int vol, err = 0;
+
+ adev->voice.volume = volume;
+ if (adev->mode == AUDIO_MODE_IN_CALL) {
+ if (volume < 0.0) {
+ volume = 0.0;
+ } else if (volume > 1.0) {
+ volume = 1.0;
+ }
+
+ vol = lrint(volume * 100.0);
+
+ // Voice volume levels from android are mapped to driver volume levels as follows.
+ // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0
+ // So adjust the volume to get the correct volume index in driver
+ vol = 100 - vol;
+
+ err = platform_set_voice_volume(adev->platform, vol);
+ }
+
+ return err;
+}
+
+int voice_start_call(struct audio_device *adev)
+{
+ int ret = 0;
+
+ adev->voice.in_call = true;
+ ret = voice_extn_start_call(adev);
+ if (ret == -ENOSYS) {
+ ret = voice_start_usecase(adev, USECASE_VOICE_CALL);
+ }
+
+ return ret;
+}
+
+int voice_stop_call(struct audio_device *adev)
+{
+ int ret = 0;
+
+ adev->voice.in_call = false;
+ ret = voice_extn_stop_call(adev);
+ if (ret == -ENOSYS) {
+ ret = voice_stop_usecase(adev, USECASE_VOICE_CALL);
+ }
+
+ return ret;
+}
+
+void voice_get_parameters(struct audio_device *adev,
+ struct str_parms *query,
+ struct str_parms *reply)
+{
+ voice_extn_get_parameters(adev, query, reply);
+}
+
+int voice_set_parameters(struct audio_device *adev, struct str_parms *parms)
+{
+ char *str;
+ char value[32];
+ int val;
+ int ret = 0, err;
+ char *kv_pairs = str_parms_to_str(parms);
+
+ ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
+
+ ret = voice_extn_set_parameters(adev, parms);
+ if (ret != 0) {
+ if (ret == -ENOSYS) {
+ ret = 0; /* ignore error */
+ } else {
+ goto done;
+ }
+ }
+
+ err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value));
+ if (err >= 0) {
+ int tty_mode;
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_TTY_MODE);
+ if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_OFF) == 0)
+ tty_mode = TTY_MODE_OFF;
+ else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_VCO) == 0)
+ tty_mode = TTY_MODE_VCO;
+ else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_HCO) == 0)
+ tty_mode = TTY_MODE_HCO;
+ else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_FULL) == 0)
+ tty_mode = TTY_MODE_FULL;
+ else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (tty_mode != adev->voice.tty_mode) {
+ adev->voice.tty_mode = tty_mode;
+ adev->acdb_settings = (adev->acdb_settings & TTY_MODE_CLEAR) | tty_mode;
+ if (voice_is_call_state_active(adev))
+ voice_update_devices_for_all_voice_usecases(adev);
+ }
+ }
+
+ err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HAC,
+ value, sizeof(value));
+ if (err >= 0) {
+ bool hac = false;
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_HAC);
+ if (strcmp(value, AUDIO_PARAMETER_VALUE_HAC_ON) == 0)
+ hac = true;
+
+ if (hac != adev->voice.hac) {
+ adev->voice.hac = hac;
+ if (voice_is_in_call(adev))
+ voice_update_devices_for_all_voice_usecases(adev);
+ }
+ }
+
+ err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC,
+ value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC);
+ if (strcmp(value, AUDIO_PARAMETER_VALUE_TRUE) == 0)
+ platform_start_incall_music_usecase(adev->platform);
+ else
+ platform_stop_incall_music_usecase(adev->platform);
+ }
+
+done:
+ ALOGV("%s: exit with code(%d)", __func__, ret);
+ free(kv_pairs);
+ return ret;
+}
+
+void voice_init(struct audio_device *adev)
+{
+ int i = 0;
+
+ memset(&adev->voice, 0, sizeof(adev->voice));
+ adev->voice.tty_mode = TTY_MODE_OFF;
+ adev->voice.hac = false;
+ adev->voice.volume = 1.0f;
+ adev->voice.mic_mute = false;
+ adev->voice.in_call = false;
+ for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+ adev->voice.session[i].pcm_rx = NULL;
+ adev->voice.session[i].pcm_tx = NULL;
+ adev->voice.session[i].state.current = CALL_INACTIVE;
+ adev->voice.session[i].state.new = CALL_INACTIVE;
+ adev->voice.session[i].vsid = VOICE_VSID;
+ }
+
+ voice_extn_init(adev);
+}
+
+void voice_update_devices_for_all_voice_usecases(struct audio_device *adev)
+{
+ struct listnode *node;
+ struct audio_usecase *usecase;
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->type == VOICE_CALL) {
+ ALOGV("%s: updating device for usecase:%s", __func__,
+ use_case_table[usecase->id]);
+ usecase->stream.out = adev->current_call_output;
+ select_devices(adev, usecase->id);
+ }
+ }
+}
+
+
diff --git a/hal/voice.h b/hal/voice.h
new file mode 100644
index 0000000..76f9d0d
--- /dev/null
+++ b/hal/voice.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef VOICE_H
+#define VOICE_H
+
+#define BASE_SESS_IDX 0
+#define VOICE_SESS_IDX (BASE_SESS_IDX)
+
+#ifdef MULTI_VOICE_SESSION_ENABLED
+#define MAX_VOICE_SESSIONS 5
+#else
+#define MAX_VOICE_SESSIONS 1
+#endif
+
+#define BASE_CALL_STATE 1
+#define CALL_INACTIVE (BASE_CALL_STATE)
+#define CALL_ACTIVE (BASE_CALL_STATE + 1)
+
+#define VOICE_VSID 0x10C01000
+
+#define AUDIO_PARAMETER_KEY_INCALLMUSIC "incall_music_enabled"
+#define AUDIO_PARAMETER_VALUE_TRUE "true"
+
+struct audio_device;
+struct str_parms;
+struct stream_in;
+struct stream_out;
+typedef int audio_usecase_t;
+
+struct call_state {
+ int current;
+ int new;
+};
+
+struct voice_session {
+ struct pcm *pcm_rx;
+ struct pcm *pcm_tx;
+ struct call_state state;
+ uint32_t vsid;
+};
+
+struct voice {
+ struct voice_session session[MAX_VOICE_SESSIONS];
+ int tty_mode;
+ bool hac;
+ bool mic_mute;
+ float volume;
+ bool in_call;
+};
+
+enum {
+ INCALL_REC_NONE = -1,
+ INCALL_REC_UPLINK,
+ INCALL_REC_DOWNLINK,
+ INCALL_REC_UPLINK_AND_DOWNLINK,
+};
+
+int voice_start_usecase(struct audio_device *adev, audio_usecase_t usecase_id);
+int voice_stop_usecase(struct audio_device *adev, audio_usecase_t usecase_id);
+
+int voice_start_call(struct audio_device *adev);
+int voice_stop_call(struct audio_device *adev);
+int voice_set_parameters(struct audio_device *adev, struct str_parms *parms);
+void voice_get_parameters(struct audio_device *adev, struct str_parms *query,
+ struct str_parms *reply);
+void voice_init(struct audio_device *adev);
+bool voice_is_in_call(struct audio_device *adev);
+bool voice_is_in_call_rec_stream(struct stream_in *in);
+int voice_set_mic_mute(struct audio_device *dev, bool state);
+bool voice_get_mic_mute(struct audio_device *dev);
+int voice_set_volume(struct audio_device *adev, float volume);
+int voice_check_and_set_incall_rec_usecase(struct audio_device *adev,
+ struct stream_in *in);
+int voice_check_and_set_incall_music_usecase(struct audio_device *adev,
+ struct stream_out *out);
+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);
+#endif //VOICE_H
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
new file mode 100644
index 0000000..89b659c
--- /dev/null
+++ b/hal/voice_extn/voice_extn.c
@@ -0,0 +1,573 @@
+/*
+ * Copyright (C) 2014 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 "voice_extn"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <math.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <sys/ioctl.h>
+#include <sound/voice_params.h>
+
+#include "audio_hw.h"
+#include "voice.h"
+#include "platform.h"
+#include "platform_api.h"
+#include "voice_extn.h"
+
+#define AUDIO_PARAMETER_KEY_VSID "vsid"
+#define AUDIO_PARAMETER_KEY_CALL_STATE "call_state"
+#define AUDIO_PARAMETER_KEY_AUDIO_MODE "audio_mode"
+#define AUDIO_PARAMETER_KEY_ALL_CALL_STATES "all_call_states"
+#define AUDIO_PARAMETER_KEY_DEVICE_MUTE "device_mute"
+#define AUDIO_PARAMETER_KEY_DIRECTION "direction"
+
+#define VOICE_EXTN_PARAMETER_VALUE_MAX_LEN 256
+
+#define VOICE2_VSID 0x10DC1000
+#define VOLTE_VSID 0x10C02000
+#define QCHAT_VSID 0x10803000
+#define VOWLAN_VSID 0x10002000
+#define ALL_VSID 0xFFFFFFFF
+
+/* Voice Session Indices */
+#define VOICE2_SESS_IDX (VOICE_SESS_IDX + 1)
+#define VOLTE_SESS_IDX (VOICE_SESS_IDX + 2)
+#define QCHAT_SESS_IDX (VOICE_SESS_IDX + 3)
+#define VOWLAN_SESS_IDX (VOICE_SESS_IDX + 4)
+
+/* Call States */
+#define CALL_HOLD (BASE_CALL_STATE + 2)
+#define CALL_LOCAL_HOLD (BASE_CALL_STATE + 3)
+
+struct pcm_config pcm_config_incall_music = {
+ .channels = 1,
+ .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
+ .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
+ .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+ .stop_threshold = INT_MAX,
+ .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+};
+
+int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active);
+
+static bool is_valid_call_state(int call_state)
+{
+ if (call_state < CALL_INACTIVE || call_state > CALL_LOCAL_HOLD)
+ return false;
+ else
+ return true;
+}
+
+static bool is_valid_vsid(uint32_t vsid)
+{
+ if (vsid == VOICE_VSID ||
+ vsid == VOICE2_VSID ||
+ vsid == VOLTE_VSID ||
+ vsid == QCHAT_VSID ||
+ vsid == VOWLAN_VSID)
+ return true;
+ else
+ return false;
+}
+
+static audio_usecase_t voice_extn_get_usecase_for_session_idx(const int index)
+{
+ audio_usecase_t usecase_id = -1;
+
+ switch(index) {
+ case VOICE_SESS_IDX:
+ usecase_id = USECASE_VOICE_CALL;
+ break;
+
+ case VOICE2_SESS_IDX:
+ usecase_id = USECASE_VOICE2_CALL;
+ break;
+
+ case VOLTE_SESS_IDX:
+ usecase_id = USECASE_VOLTE_CALL;
+ break;
+
+ case QCHAT_SESS_IDX:
+ usecase_id = USECASE_QCHAT_CALL;
+ break;
+
+ case VOWLAN_SESS_IDX:
+ usecase_id = USECASE_VOWLAN_CALL;
+ break;
+
+ default:
+ ALOGE("%s: Invalid voice session index\n", __func__);
+ }
+
+ return usecase_id;
+}
+
+static uint32_t get_session_id_with_state(struct audio_device *adev,
+ int call_state)
+{
+ struct voice_session *session = NULL;
+ int i = 0;
+ uint32_t session_id = 0;
+
+ for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+ session = &adev->voice.session[i];
+ if(session->state.current == call_state){
+ session_id = session->vsid;
+ break;
+ }
+ }
+
+ return session_id;
+}
+
+static int update_calls(struct audio_device *adev)
+{
+ int i = 0;
+ audio_usecase_t usecase_id = 0;
+ enum voice_lch_mode lch_mode;
+ struct voice_session *session = NULL;
+ int fd = 0;
+ int ret = 0;
+
+ ALOGD("%s: enter:", __func__);
+
+ for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+ usecase_id = voice_extn_get_usecase_for_session_idx(i);
+ session = &adev->voice.session[i];
+ ALOGD("%s: cur_state=%d new_state=%d vsid=%x",
+ __func__, session->state.current, session->state.new, session->vsid);
+
+ switch(session->state.new)
+ {
+ case CALL_ACTIVE:
+ switch(session->state.current)
+ {
+ case CALL_INACTIVE:
+ ALOGD("%s: INACTIVE -> ACTIVE vsid:%x", __func__, session->vsid);
+ ret = voice_start_usecase(adev, usecase_id);
+ if(ret < 0) {
+ ALOGE("%s: voice_start_usecase() failed for usecase: %d\n",
+ __func__, usecase_id);
+ } else {
+ session->state.current = session->state.new;
+ }
+ break;
+
+ case CALL_HOLD:
+ ALOGD("%s: HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
+ session->state.current = session->state.new;
+ break;
+
+ case CALL_LOCAL_HOLD:
+ ALOGD("%s: LOCAL_HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
+ lch_mode = VOICE_LCH_STOP;
+ if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
+ ALOGE("LOCAL_HOLD -> ACTIVE failed");
+ } else {
+ session->state.current = session->state.new;
+ }
+ break;
+
+ default:
+ ALOGV("%s: CALL_ACTIVE cannot be handled in state=%d vsid:%x",
+ __func__, session->state.current, session->vsid);
+ break;
+ }
+ break;
+
+ case CALL_INACTIVE:
+ switch(session->state.current)
+ {
+ case CALL_ACTIVE:
+ case CALL_HOLD:
+ case CALL_LOCAL_HOLD:
+ ALOGD("%s: ACTIVE/HOLD/LOCAL_HOLD -> INACTIVE vsid:%x", __func__, session->vsid);
+ ret = voice_stop_usecase(adev, usecase_id);
+ if(ret < 0) {
+ ALOGE("%s: voice_stop_usecase() failed for usecase: %d\n",
+ __func__, usecase_id);
+ } else {
+ session->state.current = session->state.new;
+ }
+ break;
+
+ default:
+ ALOGV("%s: CALL_INACTIVE cannot be handled in state=%d vsid:%x",
+ __func__, session->state.current, session->vsid);
+ break;
+ }
+ break;
+
+ case CALL_HOLD:
+ switch(session->state.current)
+ {
+ case CALL_ACTIVE:
+ ALOGD("%s: CALL_ACTIVE -> HOLD vsid:%x", __func__, session->vsid);
+ session->state.current = session->state.new;
+ break;
+
+ case CALL_LOCAL_HOLD:
+ ALOGD("%s: CALL_LOCAL_HOLD -> HOLD vsid:%x", __func__, session->vsid);
+ lch_mode = VOICE_LCH_STOP;
+ if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
+ ALOGE("LOCAL_HOLD -> HOLD failed");
+ } else {
+ session->state.current = session->state.new;
+ }
+ break;
+
+ default:
+ ALOGV("%s: CALL_HOLD cannot be handled in state=%d vsid:%x",
+ __func__, session->state.current, session->vsid);
+ break;
+ }
+ break;
+
+ case CALL_LOCAL_HOLD:
+ switch(session->state.current)
+ {
+ case CALL_ACTIVE:
+ case CALL_HOLD:
+ ALOGD("%s: ACTIVE/CALL_HOLD -> LOCAL_HOLD vsid:%x", __func__,
+ session->vsid);
+ lch_mode = VOICE_LCH_START;
+ if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
+ ALOGE("LOCAL_HOLD -> HOLD failed");
+ } else {
+ session->state.current = session->state.new;
+ }
+ break;
+
+ default:
+ ALOGV("%s: CALL_LOCAL_HOLD cannot be handled in state=%d vsid:%x",
+ __func__, session->state.current, session->vsid);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ } //end out switch loop
+ } //end for loop
+
+ return ret;
+}
+
+static int update_call_states(struct audio_device *adev,
+ const uint32_t vsid, const int call_state)
+{
+ struct voice_session *session = NULL;
+ int i = 0;
+ bool is_call_active;
+
+ for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+ if (vsid == adev->voice.session[i].vsid) {
+ session = &adev->voice.session[i];
+ break;
+ }
+ }
+
+ if (session) {
+ session->state.new = call_state;
+ voice_extn_is_call_state_active(adev, &is_call_active);
+ ALOGD("%s is_call_active:%d in_call:%d, mode:%d\n",
+ __func__, is_call_active, adev->voice.in_call, adev->mode);
+ /* Dont start voice call before device routing for voice usescases has
+ * occured, otherwise voice calls will be started unintendedly on
+ * speaker.
+ */
+ if (is_call_active ||
+ (adev->voice.in_call && adev->mode == AUDIO_MODE_IN_CALL)) {
+ /* Device routing is not triggered for voice calls on the subsequent
+ * subs, Hence update the call states if voice call is already
+ * active on other sub.
+ */
+ update_calls(adev);
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+
+}
+
+int voice_extn_get_active_session_id(struct audio_device *adev,
+ uint32_t *session_id)
+{
+ *session_id = get_session_id_with_state(adev, CALL_ACTIVE);
+ return 0;
+}
+
+int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active)
+{
+ struct voice_session *session = NULL;
+ int i = 0;
+ *is_call_active = false;
+
+ for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+ session = &adev->voice.session[i];
+ if(session->state.current != CALL_INACTIVE){
+ *is_call_active = true;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int voice_extn_is_in_call_rec_stream(struct stream_in *in, bool *in_call_rec)
+{
+ *in_call_rec = false;
+
+ if(in->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
+ in->source == AUDIO_SOURCE_VOICE_UPLINK ||
+ in->source == AUDIO_SOURCE_VOICE_CALL) {
+ *in_call_rec = true;
+ }
+
+ return 0;
+}
+
+void voice_extn_init(struct audio_device *adev)
+{
+ adev->voice.session[VOICE_SESS_IDX].vsid = VOICE_VSID;
+ adev->voice.session[VOICE2_SESS_IDX].vsid = VOICE2_VSID;
+ adev->voice.session[VOLTE_SESS_IDX].vsid = VOLTE_VSID;
+ adev->voice.session[QCHAT_SESS_IDX].vsid = QCHAT_VSID;
+ adev->voice.session[VOWLAN_SESS_IDX].vsid = VOWLAN_VSID;
+}
+
+int voice_extn_get_session_from_use_case(struct audio_device *adev,
+ const audio_usecase_t usecase_id,
+ struct voice_session **session)
+{
+
+ switch(usecase_id)
+ {
+ case USECASE_VOICE_CALL:
+ *session = &adev->voice.session[VOICE_SESS_IDX];
+ break;
+
+ case USECASE_VOICE2_CALL:
+ *session = &adev->voice.session[VOICE2_SESS_IDX];
+ break;
+
+ case USECASE_VOLTE_CALL:
+ *session = &adev->voice.session[VOLTE_SESS_IDX];
+ break;
+
+ case USECASE_QCHAT_CALL:
+ *session = &adev->voice.session[QCHAT_SESS_IDX];
+ break;
+
+ case USECASE_VOWLAN_CALL:
+ *session = &adev->voice.session[VOWLAN_SESS_IDX];
+ break;
+
+ default:
+ ALOGE("%s: Invalid usecase_id:%d\n", __func__, usecase_id);
+ *session = NULL;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int voice_extn_start_call(struct audio_device *adev)
+{
+ /* Start voice calls on sessions whose call state has been
+ * udpated.
+ */
+ ALOGV("%s: enter:", __func__);
+ return update_calls(adev);
+}
+
+int voice_extn_stop_call(struct audio_device *adev)
+{
+ int i;
+ int ret = 0;
+
+ ALOGV("%s: enter:", __func__);
+
+ /* If BT device is enabled and voice calls are ended, telephony will call
+ * set_mode(AUDIO_MODE_NORMAL) which will trigger audio policy manager to
+ * set routing with device BT A2DP profile. Hence end all voice calls when
+ * set_mode(AUDIO_MODE_NORMAL) before BT A2DP profile is selected.
+ */
+ if (adev->mode == AUDIO_MODE_NORMAL) {
+ ALOGD("%s: end all calls", __func__);
+ for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+ adev->voice.session[i].state.new = CALL_INACTIVE;
+ }
+
+ ret = update_calls(adev);
+ }
+
+ return ret;
+}
+
+int voice_extn_set_parameters(struct audio_device *adev,
+ struct str_parms *parms)
+{
+ char *str;
+ int value;
+ int ret = 0, err;
+ char *kv_pairs = str_parms_to_str(parms);
+ char str_value[256] = {0};
+
+ ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
+
+ err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_VSID, &value);
+ if (err >= 0) {
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_VSID);
+ uint32_t vsid = value;
+ int call_state = -1;
+ err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_CALL_STATE, &value);
+ if (err >= 0) {
+ call_state = value;
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_CALL_STATE);
+ } else {
+ ALOGE("%s: call_state key not found", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (is_valid_vsid(vsid) && is_valid_call_state(call_state)) {
+ ret = update_call_states(adev, vsid, call_state);
+ } else {
+ ALOGE("%s: invalid vsid:%x or call_state:%d",
+ __func__, vsid, call_state);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DEVICE_MUTE, str_value,
+ sizeof(str_value));
+ if (err >= 0) {
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_DEVICE_MUTE);
+ bool mute = false;
+
+ if (!strncmp("true", str_value, sizeof("true"))) {
+ mute = true;
+ }
+
+ err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DIRECTION, str_value,
+ sizeof(str_value));
+ if (err >= 0) {
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_DIRECTION);
+ } else {
+ ALOGE("%s: direction key not found", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = platform_set_device_mute(adev->platform, mute, str_value);
+ if (ret != 0) {
+ ALOGE("%s: Failed to set mute err:%d", __func__, ret);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+done:
+ ALOGV("%s: exit with code(%d)", __func__, ret);
+ free(kv_pairs);
+ return ret;
+}
+
+static int get_all_call_states_str(const struct audio_device *adev,
+ char *value)
+{
+ int ret = 0;
+ char *cur_ptr = value;
+ int i, len=0;
+
+ for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+ snprintf(cur_ptr, VOICE_EXTN_PARAMETER_VALUE_MAX_LEN - len,
+ "%d:%d,",adev->voice.session[i].vsid,
+ adev->voice.session[i].state.current);
+ len = strlen(cur_ptr);
+ cur_ptr = cur_ptr + len;
+ }
+ ALOGV("%s:value=%s", __func__, value);
+ return ret;
+}
+
+void voice_extn_get_parameters(const struct audio_device *adev,
+ struct str_parms *query,
+ struct str_parms *reply)
+{
+ int ret;
+ char value[VOICE_EXTN_PARAMETER_VALUE_MAX_LEN] = {0};
+ char *str = str_parms_to_str(query);
+
+ ALOGV_IF(str != NULL, "%s: enter %s", __func__, str);
+ free(str);
+
+ ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_AUDIO_MODE, value,
+ sizeof(value));
+ if (ret >= 0) {
+ str_parms_add_int(reply, AUDIO_PARAMETER_KEY_AUDIO_MODE, adev->mode);
+ }
+
+ ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ALL_CALL_STATES,
+ value, sizeof(value));
+ if (ret >= 0) {
+ ret = get_all_call_states_str(adev, value);
+ if (ret) {
+ ALOGE("%s: Error fetching call states, err:%d", __func__, ret);
+ return;
+ }
+ str_parms_add_str(reply, AUDIO_PARAMETER_KEY_ALL_CALL_STATES, value);
+ }
+
+ str = str_parms_to_str(reply);
+ ALOGV_IF(str != NULL, "%s: exit: returns \"%s\"", __func__, str);
+ free(str);
+}
+
+#ifdef INCALL_MUSIC_ENABLED
+int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev,
+ struct stream_out *out)
+{
+ uint32_t session_id = 0;
+
+ session_id = get_session_id_with_state(adev, CALL_LOCAL_HOLD);
+ if (session_id == VOICE_VSID) {
+ out->usecase = USECASE_INCALL_MUSIC_UPLINK;
+ } else if (session_id == VOICE2_VSID) {
+ out->usecase = USECASE_INCALL_MUSIC_UPLINK2;
+ } else {
+ ALOGE("%s: Invalid session id %x", __func__, session_id);
+ return -EINVAL;
+ }
+
+ out->config = pcm_config_incall_music;
+ out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_MONO;
+ out->channel_mask = AUDIO_CHANNEL_OUT_MONO;
+
+ return 0;
+}
+#endif
+
diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h
new file mode 100644
index 0000000..8689c9c
--- /dev/null
+++ b/hal/voice_extn/voice_extn.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef VOICE_EXTN_H
+#define VOICE_EXTN_H
+
+#ifdef MULTI_VOICE_SESSION_ENABLED
+int voice_extn_start_call(struct audio_device *adev);
+int voice_extn_stop_call(struct audio_device *adev);
+int voice_extn_get_session_from_use_case(struct audio_device *adev,
+ const audio_usecase_t usecase_id,
+ struct voice_session **session);
+void voice_extn_init(struct audio_device *adev);
+int voice_extn_set_parameters(struct audio_device *adev,
+ struct str_parms *parms);
+void voice_extn_get_parameters(const struct audio_device *adev,
+ struct str_parms *query,
+ struct str_parms *reply);
+int voice_extn_is_in_call_rec_stream(struct stream_in *in, bool *in_call_rec);
+int voice_extn_get_active_session_id(struct audio_device *adev,
+ uint32_t *session_id);
+int voice_extn_is_call_state_active(struct audio_device *adev,
+ bool *is_call_active);
+#else
+static int voice_extn_start_call(struct audio_device *adev __unused)
+{
+ return -ENOSYS;
+}
+
+static int voice_extn_stop_call(struct audio_device *adev __unused)
+{
+ return -ENOSYS;
+}
+
+static int voice_extn_get_session_from_use_case(struct audio_device *adev __unused,
+ const audio_usecase_t usecase_id __unused,
+ struct voice_session **session __unused)
+{
+ return -ENOSYS;
+}
+
+static void voice_extn_init(struct audio_device *adev __unused)
+{
+}
+
+static int voice_extn_set_parameters(struct audio_device *adev __unused,
+ struct str_parms *parms __unused)
+{
+ return -ENOSYS;
+}
+
+static void voice_extn_get_parameters(const struct audio_device *adev __unused,
+ struct str_parms *query __unused,
+ struct str_parms *reply __unused)
+{
+}
+
+static int voice_extn_is_call_state_active(struct audio_device *adev __unused,
+ bool *is_call_active __unused)
+{
+ return -ENOSYS;
+}
+
+static int voice_extn_is_in_call_rec_stream(struct stream_in *in __unused, bool *in_call_rec __unused)
+{
+ return -ENOSYS;
+}
+
+static int voice_extn_get_active_session_id(struct audio_device *adev __unused,
+ uint32_t *session_id __unused)
+{
+ return -ENOSYS;
+}
+
+#endif
+
+#ifdef INCALL_MUSIC_ENABLED
+int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev,
+ struct stream_out *out);
+#else
+static int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev __unused,
+ struct stream_out *out __unused)
+{
+ return -ENOSYS;
+}
+#endif
+
+#endif //VOICE_EXTN_H
diff --git a/legacy/alsa_sound/audio_hw_hal.cpp b/legacy/alsa_sound/audio_hw_hal.cpp
index ab15e27..f8b02e8 100644
--- a/legacy/alsa_sound/audio_hw_hal.cpp
+++ b/legacy/alsa_sound/audio_hw_hal.cpp
@@ -554,7 +554,8 @@
audio_devices_t devices,
audio_output_flags_t flags,
struct audio_config *config,
- struct audio_stream_out **stream_out)
+ struct audio_stream_out **stream_out,
+ const char *address __unused)
{
struct qcom_audio_device *qadev = to_ladev(dev);
status_t status;
@@ -620,7 +621,10 @@
audio_io_handle_t handle,
audio_devices_t devices,
audio_config *config,
- audio_stream_in **stream_in)
+ audio_stream_in **stream_in,
+ audio_input_flags_t flags __unused,
+ const char *address __unused,
+ audio_source_t source __unused)
{
struct qcom_audio_device *qadev = to_ladev(dev);
status_t status;
diff --git a/post_proc/Android.mk b/post_proc/Android.mk
new file mode 100644
index 0000000..91ed2bc
--- /dev/null
+++ b/post_proc/Android.mk
@@ -0,0 +1,33 @@
+ifneq ($(filter msm8974 msm8226 msm8084,$(TARGET_BOARD_PLATFORM)),)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ bundle.c \
+ equalizer.c \
+ bass_boost.c \
+ virtualizer.c \
+ reverb.c \
+ effect_api.c
+
+LOCAL_CFLAGS+= -O2 -fvisibility=hidden
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ liblog \
+ libtinyalsa
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
+LOCAL_MODULE:= libqcompostprocbundle
+
+LOCAL_C_INCLUDES := \
+ external/tinyalsa/include \
+ $(call include-path-for, audio-effects)
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
\ No newline at end of file
diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c
new file mode 100644
index 0000000..f303886
--- /dev/null
+++ b/post_proc/bass_boost.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2014 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 "offload_effect_bass_boost"
+//#define LOG_NDEBUG 0
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <sound/audio_effects.h>
+#include <audio_effects/effect_bassboost.h>
+
+#include "effect_api.h"
+#include "bass_boost.h"
+
+/* Offload bassboost UUID: 2c4a8c24-1581-487f-94f6-0002a5d5c51b */
+const effect_descriptor_t bassboost_descriptor = {
+ {0x0634f220, 0xddd4, 0x11db, 0xa0fc, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }},
+ {0x2c4a8c24, 0x1581, 0x487f, 0x94f6, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_HW_ACC_TUNNEL),
+ 0, /* TODO */
+ 1,
+ "MSM offload bassboost",
+ "The Android Open Source Project",
+};
+
+/*
+ * Bassboost operations
+ */
+
+int bassboost_get_strength(bassboost_context_t *context)
+{
+ ALOGV("%s: strength: %d", __func__, context->strength);
+ return context->strength;
+}
+
+int bassboost_set_strength(bassboost_context_t *context, uint32_t strength)
+{
+ ALOGV("%s: strength: %d", __func__, strength);
+ context->strength = strength;
+
+ offload_bassboost_set_strength(&(context->offload_bass), strength);
+ if (context->ctl)
+ offload_bassboost_send_params(context->ctl, &context->offload_bass,
+ OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
+ OFFLOAD_SEND_BASSBOOST_STRENGTH);
+ return 0;
+}
+
+int bassboost_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ void *value = p->data + voffset;
+ int i;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
+ if (p->vsize < sizeof(uint32_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint32_t);
+ break;
+ case BASSBOOST_PARAM_STRENGTH:
+ if (p->vsize < sizeof(int16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(int16_t);
+ break;
+ default:
+ p->status = -EINVAL;
+ }
+
+ *size = sizeof(effect_param_t) + voffset + p->vsize;
+
+ if (p->status != 0)
+ return 0;
+
+ switch (param) {
+ case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
+ ALOGV("%s: BASSBOOST_PARAM_STRENGTH_SUPPORTED", __func__);
+ *(uint32_t *)value = 1;
+ break;
+
+ case BASSBOOST_PARAM_STRENGTH:
+ ALOGV("%s: BASSBOOST_PARAM_STRENGTH", __func__);
+ *(int16_t *)value = bassboost_get_strength(bass_ctxt);
+ break;
+
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int bassboost_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size __unused)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ void *value = p->data + voffset;
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ uint32_t strength;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case BASSBOOST_PARAM_STRENGTH:
+ ALOGV("%s BASSBOOST_PARAM_STRENGTH", __func__);
+ strength = (uint32_t)(*(int16_t *)value);
+ bassboost_set_strength(bass_ctxt, strength);
+ break;
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int bassboost_set_device(effect_context_t *context, uint32_t device)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+ ALOGV("%s: device: %d", __func__, device);
+ bass_ctxt->device = device;
+ if ((device == AUDIO_DEVICE_OUT_SPEAKER) ||
+ (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) ||
+ (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) ||
+ (device == AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
+ (device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET)) {
+ if (!bass_ctxt->temp_disabled) {
+ if (effect_is_active(&bass_ctxt->common)) {
+ offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false);
+ if (bass_ctxt->ctl)
+ offload_bassboost_send_params(bass_ctxt->ctl,
+ &bass_ctxt->offload_bass,
+ OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+ }
+ bass_ctxt->temp_disabled = true;
+ }
+ } else {
+ if (bass_ctxt->temp_disabled) {
+ if (effect_is_active(&bass_ctxt->common)) {
+ offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true);
+ if (bass_ctxt->ctl)
+ offload_bassboost_send_params(bass_ctxt->ctl,
+ &bass_ctxt->offload_bass,
+ OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+ }
+ bass_ctxt->temp_disabled = false;
+ }
+ }
+ offload_bassboost_set_device(&(bass_ctxt->offload_bass), device);
+ return 0;
+}
+
+int bassboost_reset(effect_context_t *context)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+ return 0;
+}
+
+int bassboost_init(effect_context_t *context)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+ ALOGV("%s", __func__);
+ context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+ context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.inputCfg.samplingRate = 44100;
+ context->config.inputCfg.bufferProvider.getBuffer = NULL;
+ context->config.inputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.inputCfg.bufferProvider.cookie = NULL;
+ context->config.inputCfg.mask = EFFECT_CONFIG_ALL;
+ context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+ context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.outputCfg.samplingRate = 44100;
+ context->config.outputCfg.bufferProvider.getBuffer = NULL;
+ context->config.outputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.outputCfg.bufferProvider.cookie = NULL;
+ context->config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+ set_config(context, &context->config);
+
+ bass_ctxt->temp_disabled = false;
+ memset(&(bass_ctxt->offload_bass), 0, sizeof(struct bass_boost_params));
+
+ return 0;
+}
+
+int bassboost_enable(effect_context_t *context)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+ ALOGV("%s", __func__);
+
+ if (!offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)) &&
+ !(bass_ctxt->temp_disabled)) {
+ offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true);
+ if (bass_ctxt->ctl && bass_ctxt->strength)
+ offload_bassboost_send_params(bass_ctxt->ctl,
+ &bass_ctxt->offload_bass,
+ OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
+ OFFLOAD_SEND_BASSBOOST_STRENGTH);
+ }
+ return 0;
+}
+
+int bassboost_disable(effect_context_t *context)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+ ALOGV("%s", __func__);
+ if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) {
+ offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false);
+ if (bass_ctxt->ctl)
+ offload_bassboost_send_params(bass_ctxt->ctl,
+ &bass_ctxt->offload_bass,
+ OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+ }
+ return 0;
+}
+
+int bassboost_start(effect_context_t *context, output_context_t *output)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+ ALOGV("%s", __func__);
+ bass_ctxt->ctl = output->ctl;
+ ALOGV("output->ctl: %p", output->ctl);
+ if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)))
+ if (bass_ctxt->ctl)
+ offload_bassboost_send_params(bass_ctxt->ctl, &bass_ctxt->offload_bass,
+ OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
+ OFFLOAD_SEND_BASSBOOST_STRENGTH);
+ return 0;
+}
+
+int bassboost_stop(effect_context_t *context, output_context_t *output __unused)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+ ALOGV("%s", __func__);
+ bass_ctxt->ctl = NULL;
+ return 0;
+}
diff --git a/post_proc/bass_boost.h b/post_proc/bass_boost.h
new file mode 100644
index 0000000..7717b12
--- /dev/null
+++ b/post_proc/bass_boost.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef OFFLOAD_EFFECT_BASS_BOOST_H_
+#define OFFLOAD_EFFECT_BASS_BOOST_H_
+
+#include "bundle.h"
+
+extern const effect_descriptor_t bassboost_descriptor;
+
+typedef struct bassboost_context_s {
+ effect_context_t common;
+
+ int strength;
+
+ // Offload vars
+ struct mixer_ctl *ctl;
+ bool temp_disabled;
+ uint32_t device;
+ struct bass_boost_params offload_bass;
+} bassboost_context_t;
+
+int bassboost_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size);
+
+int bassboost_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size);
+
+int bassboost_set_device(effect_context_t *context, uint32_t device);
+
+int bassboost_reset(effect_context_t *context);
+
+int bassboost_init(effect_context_t *context);
+
+int bassboost_enable(effect_context_t *context);
+
+int bassboost_disable(effect_context_t *context);
+
+int bassboost_start(effect_context_t *context, output_context_t *output);
+
+int bassboost_stop(effect_context_t *context, output_context_t *output);
+
+#endif /* OFFLOAD_EFFECT_BASS_BOOST_H_ */
diff --git a/post_proc/bundle.c b/post_proc/bundle.c
new file mode 100644
index 0000000..8518e54
--- /dev/null
+++ b/post_proc/bundle.c
@@ -0,0 +1,758 @@
+/*
+ * Copyright (C) 2014 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 "offload_effect_bundle"
+//#define LOG_NDEBUG 0
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <system/thread_defs.h>
+#include <tinyalsa/asoundlib.h>
+#include <hardware/audio_effect.h>
+
+#include "bundle.h"
+#include "equalizer.h"
+#include "bass_boost.h"
+#include "virtualizer.h"
+#include "reverb.h"
+
+enum {
+ EFFECT_STATE_UNINITIALIZED,
+ EFFECT_STATE_INITIALIZED,
+ EFFECT_STATE_ACTIVE,
+};
+
+const effect_descriptor_t *descriptors[] = {
+ &equalizer_descriptor,
+ &bassboost_descriptor,
+ &virtualizer_descriptor,
+ &aux_env_reverb_descriptor,
+ &ins_env_reverb_descriptor,
+ &aux_preset_reverb_descriptor,
+ &ins_preset_reverb_descriptor,
+ NULL,
+};
+
+pthread_once_t once = PTHREAD_ONCE_INIT;
+int init_status;
+/*
+ * list of created effects.
+ * Updated by offload_effects_bundle_hal_start_output()
+ * and offload_effects_bundle_hal_stop_output()
+ */
+struct listnode created_effects_list;
+/*
+ * list of active output streams.
+ * Updated by offload_effects_bundle_hal_start_output()
+ * and offload_effects_bundle_hal_stop_output()
+ */
+struct listnode active_outputs_list;
+/*
+ * lock must be held when modifying or accessing
+ * created_effects_list or active_outputs_list
+ */
+pthread_mutex_t lock;
+
+
+/*
+ * Local functions
+ */
+static void init_once() {
+ list_init(&created_effects_list);
+ list_init(&active_outputs_list);
+
+ pthread_mutex_init(&lock, NULL);
+
+ init_status = 0;
+}
+
+int lib_init()
+{
+ pthread_once(&once, init_once);
+ return init_status;
+}
+
+bool effect_exists(effect_context_t *context)
+{
+ struct listnode *node;
+
+ list_for_each(node, &created_effects_list) {
+ effect_context_t *fx_ctxt = node_to_item(node,
+ effect_context_t,
+ effects_list_node);
+ if (fx_ctxt == context) {
+ return true;
+ }
+ }
+ return false;
+}
+
+output_context_t *get_output(audio_io_handle_t output)
+{
+ struct listnode *node;
+
+ list_for_each(node, &active_outputs_list) {
+ output_context_t *out_ctxt = node_to_item(node,
+ output_context_t,
+ outputs_list_node);
+ if (out_ctxt->handle == output)
+ return out_ctxt;
+ }
+ return NULL;
+}
+
+void add_effect_to_output(output_context_t * output, effect_context_t *context)
+{
+ struct listnode *fx_node;
+
+ list_for_each(fx_node, &output->effects_list) {
+ effect_context_t *fx_ctxt = node_to_item(fx_node,
+ effect_context_t,
+ output_node);
+ if (fx_ctxt == context)
+ return;
+ }
+ list_add_tail(&output->effects_list, &context->output_node);
+ if (context->ops.start)
+ context->ops.start(context, output);
+
+}
+
+void remove_effect_from_output(output_context_t * output,
+ effect_context_t *context)
+{
+ struct listnode *fx_node;
+
+ list_for_each(fx_node, &output->effects_list) {
+ effect_context_t *fx_ctxt = node_to_item(fx_node,
+ effect_context_t,
+ output_node);
+ if (fx_ctxt == context) {
+ if (context->ops.stop)
+ context->ops.stop(context, output);
+ list_remove(&context->output_node);
+ return;
+ }
+ }
+}
+
+bool effects_enabled()
+{
+ struct listnode *out_node;
+
+ list_for_each(out_node, &active_outputs_list) {
+ struct listnode *fx_node;
+ output_context_t *out_ctxt = node_to_item(out_node,
+ output_context_t,
+ outputs_list_node);
+
+ list_for_each(fx_node, &out_ctxt->effects_list) {
+ effect_context_t *fx_ctxt = node_to_item(fx_node,
+ effect_context_t,
+ output_node);
+ if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
+ (fx_ctxt->ops.process != NULL))
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/*
+ * Interface from audio HAL
+ */
+__attribute__ ((visibility ("default")))
+int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id)
+{
+ int ret = 0;
+ struct listnode *node;
+ char mixer_string[128];
+ output_context_t * out_ctxt = NULL;
+
+ ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
+
+ if (lib_init() != 0)
+ return init_status;
+
+ pthread_mutex_lock(&lock);
+ if (get_output(output) != NULL) {
+ ALOGW("%s output already started", __func__);
+ ret = -ENOSYS;
+ goto exit;
+ }
+
+ out_ctxt = (output_context_t *)
+ malloc(sizeof(output_context_t));
+ out_ctxt->handle = output;
+ out_ctxt->pcm_device_id = pcm_id;
+
+ /* populate the mixer control to send offload parameters */
+ snprintf(mixer_string, sizeof(mixer_string),
+ "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id);
+ out_ctxt->mixer = mixer_open(MIXER_CARD);
+ if (!out_ctxt->mixer) {
+ ALOGE("Failed to open mixer");
+ out_ctxt->ctl = NULL;
+ ret = -EINVAL;
+ free(out_ctxt);
+ goto exit;
+ } else {
+ out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string);
+ if (!out_ctxt->ctl) {
+ ALOGE("mixer_get_ctl_by_name failed");
+ mixer_close(out_ctxt->mixer);
+ out_ctxt->mixer = NULL;
+ ret = -EINVAL;
+ free(out_ctxt);
+ goto exit;
+ }
+ }
+
+ list_init(&out_ctxt->effects_list);
+
+ list_for_each(node, &created_effects_list) {
+ effect_context_t *fx_ctxt = node_to_item(node,
+ effect_context_t,
+ effects_list_node);
+ if (fx_ctxt->out_handle == output) {
+ if (fx_ctxt->ops.start)
+ fx_ctxt->ops.start(fx_ctxt, out_ctxt);
+ list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node);
+ }
+ }
+ list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node);
+exit:
+ pthread_mutex_unlock(&lock);
+ return ret;
+}
+
+__attribute__ ((visibility ("default")))
+int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id)
+{
+ int ret;
+ struct listnode *node;
+ struct listnode *fx_node;
+ output_context_t *out_ctxt;
+
+ ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
+
+ if (lib_init() != 0)
+ return init_status;
+
+ pthread_mutex_lock(&lock);
+
+ out_ctxt = get_output(output);
+ if (out_ctxt == NULL) {
+ ALOGW("%s output not started", __func__);
+ ret = -ENOSYS;
+ goto exit;
+ }
+
+ if (out_ctxt->mixer)
+ mixer_close(out_ctxt->mixer);
+
+ list_for_each(fx_node, &out_ctxt->effects_list) {
+ effect_context_t *fx_ctxt = node_to_item(fx_node,
+ effect_context_t,
+ output_node);
+ if (fx_ctxt->ops.stop)
+ fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
+ }
+
+ list_remove(&out_ctxt->outputs_list_node);
+
+ free(out_ctxt);
+
+exit:
+ pthread_mutex_unlock(&lock);
+ return ret;
+}
+
+
+/*
+ * Effect operations
+ */
+int set_config(effect_context_t *context, effect_config_t *config)
+{
+ context->config = *config;
+
+ if (context->ops.reset)
+ context->ops.reset(context);
+
+ return 0;
+}
+
+void get_config(effect_context_t *context, effect_config_t *config)
+{
+ *config = context->config;
+}
+
+
+/*
+ * Effect Library Interface Implementation
+ */
+int effect_lib_create(const effect_uuid_t *uuid,
+ int32_t sessionId,
+ int32_t ioId,
+ effect_handle_t *pHandle) {
+ int ret;
+ int i;
+
+ ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId);
+ if (lib_init() != 0)
+ return init_status;
+
+ if (pHandle == NULL || uuid == NULL)
+ return -EINVAL;
+
+ for (i = 0; descriptors[i] != NULL; i++) {
+ if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0)
+ break;
+ }
+
+ if (descriptors[i] == NULL)
+ return -EINVAL;
+
+ effect_context_t *context;
+ if (memcmp(uuid, &equalizer_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) {
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)
+ calloc(1, sizeof(equalizer_context_t));
+ context = (effect_context_t *)eq_ctxt;
+ context->ops.init = equalizer_init;
+ context->ops.reset = equalizer_reset;
+ context->ops.set_parameter = equalizer_set_parameter;
+ context->ops.get_parameter = equalizer_get_parameter;
+ context->ops.set_device = equalizer_set_device;
+ context->ops.enable = equalizer_enable;
+ context->ops.disable = equalizer_disable;
+ context->ops.start = equalizer_start;
+ context->ops.stop = equalizer_stop;
+
+ context->desc = &equalizer_descriptor;
+ eq_ctxt->ctl = NULL;
+ } else if (memcmp(uuid, &bassboost_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) {
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)
+ calloc(1, sizeof(bassboost_context_t));
+ context = (effect_context_t *)bass_ctxt;
+ context->ops.init = bassboost_init;
+ context->ops.reset = bassboost_reset;
+ context->ops.set_parameter = bassboost_set_parameter;
+ context->ops.get_parameter = bassboost_get_parameter;
+ context->ops.set_device = bassboost_set_device;
+ context->ops.enable = bassboost_enable;
+ context->ops.disable = bassboost_disable;
+ context->ops.start = bassboost_start;
+ context->ops.stop = bassboost_stop;
+
+ context->desc = &bassboost_descriptor;
+ bass_ctxt->ctl = NULL;
+ } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) {
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
+ calloc(1, sizeof(virtualizer_context_t));
+ context = (effect_context_t *)virt_ctxt;
+ context->ops.init = virtualizer_init;
+ context->ops.reset = virtualizer_reset;
+ context->ops.set_parameter = virtualizer_set_parameter;
+ context->ops.get_parameter = virtualizer_get_parameter;
+ context->ops.set_device = virtualizer_set_device;
+ context->ops.enable = virtualizer_enable;
+ context->ops.disable = virtualizer_disable;
+ context->ops.start = virtualizer_start;
+ context->ops.stop = virtualizer_stop;
+
+ context->desc = &virtualizer_descriptor;
+ virt_ctxt->ctl = NULL;
+ } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) ||
+ (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) ||
+ (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) ||
+ (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0)) {
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)
+ calloc(1, sizeof(reverb_context_t));
+ context = (effect_context_t *)reverb_ctxt;
+ context->ops.init = reverb_init;
+ context->ops.reset = reverb_reset;
+ context->ops.set_parameter = reverb_set_parameter;
+ context->ops.get_parameter = reverb_get_parameter;
+ context->ops.set_device = reverb_set_device;
+ context->ops.enable = reverb_enable;
+ context->ops.disable = reverb_disable;
+ context->ops.start = reverb_start;
+ context->ops.stop = reverb_stop;
+
+ if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) {
+ context->desc = &aux_env_reverb_descriptor;
+ reverb_auxiliary_init(reverb_ctxt);
+ } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) {
+ context->desc = &ins_env_reverb_descriptor;
+ reverb_insert_init(reverb_ctxt);
+ } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) {
+ context->desc = &aux_preset_reverb_descriptor;
+ reverb_auxiliary_init(reverb_ctxt);
+ } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) {
+ context->desc = &ins_preset_reverb_descriptor;
+ reverb_preset_init(reverb_ctxt);
+ }
+ reverb_ctxt->ctl = NULL;
+ } else {
+ return -EINVAL;
+ }
+
+ context->itfe = &effect_interface;
+ context->state = EFFECT_STATE_UNINITIALIZED;
+ context->out_handle = (audio_io_handle_t)ioId;
+
+ ret = context->ops.init(context);
+ if (ret < 0) {
+ ALOGW("%s init failed", __func__);
+ free(context);
+ return ret;
+ }
+
+ context->state = EFFECT_STATE_INITIALIZED;
+
+ pthread_mutex_lock(&lock);
+ list_add_tail(&created_effects_list, &context->effects_list_node);
+ output_context_t *out_ctxt = get_output(ioId);
+ if (out_ctxt != NULL)
+ add_effect_to_output(out_ctxt, context);
+ pthread_mutex_unlock(&lock);
+
+ *pHandle = (effect_handle_t)context;
+
+ ALOGV("%s created context %p", __func__, context);
+
+ return 0;
+
+}
+
+int effect_lib_release(effect_handle_t handle)
+{
+ effect_context_t *context = (effect_context_t *)handle;
+ int status;
+
+ if (lib_init() != 0)
+ return init_status;
+
+ ALOGV("%s context %p", __func__, handle);
+ pthread_mutex_lock(&lock);
+ status = -EINVAL;
+ if (effect_exists(context)) {
+ output_context_t *out_ctxt = get_output(context->out_handle);
+ if (out_ctxt != NULL)
+ remove_effect_from_output(out_ctxt, context);
+ list_remove(&context->effects_list_node);
+ if (context->ops.release)
+ context->ops.release(context);
+ free(context);
+ status = 0;
+ }
+ pthread_mutex_unlock(&lock);
+
+ return status;
+}
+
+int effect_lib_get_descriptor(const effect_uuid_t *uuid,
+ effect_descriptor_t *descriptor)
+{
+ int i;
+
+ if (lib_init() != 0)
+ return init_status;
+
+ if (descriptor == NULL || uuid == NULL) {
+ ALOGV("%s called with NULL pointer", __func__);
+ return -EINVAL;
+ }
+
+ for (i = 0; descriptors[i] != NULL; i++) {
+ if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
+ *descriptor = *descriptors[i];
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+
+/*
+ * Effect Control Interface Implementation
+ */
+
+/* Stub function for effect interface: never called for offloaded effects */
+int effect_process(effect_handle_t self,
+ audio_buffer_t *inBuffer __unused,
+ audio_buffer_t *outBuffer __unused)
+{
+ effect_context_t * context = (effect_context_t *)self;
+ int status = 0;
+
+ ALOGW("%s Called ?????", __func__);
+
+ pthread_mutex_lock(&lock);
+ if (!effect_exists(context)) {
+ status = -ENOSYS;
+ goto exit;
+ }
+
+ if (context->state != EFFECT_STATE_ACTIVE) {
+ status = -ENODATA;
+ goto exit;
+ }
+
+exit:
+ pthread_mutex_unlock(&lock);
+ return status;
+}
+
+int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
+ void *pCmdData, uint32_t *replySize, void *pReplyData)
+{
+
+ effect_context_t * context = (effect_context_t *)self;
+ int retsize;
+ int status = 0;
+
+ pthread_mutex_lock(&lock);
+
+ if (!effect_exists(context)) {
+ status = -ENOSYS;
+ goto exit;
+ }
+
+ if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
+ status = -ENOSYS;
+ goto exit;
+ }
+
+ switch (cmdCode) {
+ case EFFECT_CMD_INIT:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (context->ops.init)
+ *(int *) pReplyData = context->ops.init(context);
+ else
+ *(int *) pReplyData = 0;
+ break;
+ case EFFECT_CMD_SET_CONFIG:
+ if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
+ || pReplyData == NULL || *replySize != sizeof(int)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
+ break;
+ case EFFECT_CMD_GET_CONFIG:
+ if (pReplyData == NULL ||
+ *replySize != sizeof(effect_config_t)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (!context->offload_enabled) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ get_config(context, (effect_config_t *)pReplyData);
+ break;
+ case EFFECT_CMD_RESET:
+ if (context->ops.reset)
+ context->ops.reset(context);
+ break;
+ case EFFECT_CMD_ENABLE:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (context->state != EFFECT_STATE_INITIALIZED) {
+ status = -ENOSYS;
+ goto exit;
+ }
+ context->state = EFFECT_STATE_ACTIVE;
+ if (context->ops.enable)
+ context->ops.enable(context);
+ ALOGV("%s EFFECT_CMD_ENABLE", __func__);
+ *(int *)pReplyData = 0;
+ break;
+ case EFFECT_CMD_DISABLE:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (context->state != EFFECT_STATE_ACTIVE) {
+ status = -ENOSYS;
+ goto exit;
+ }
+ context->state = EFFECT_STATE_INITIALIZED;
+ if (context->ops.disable)
+ context->ops.disable(context);
+ ALOGV("%s EFFECT_CMD_DISABLE", __func__);
+ *(int *)pReplyData = 0;
+ break;
+ case EFFECT_CMD_GET_PARAM: {
+ if (pCmdData == NULL ||
+ cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
+ pReplyData == NULL ||
+ *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
+ sizeof(uint16_t))) {
+ status = -EINVAL;
+ ALOGV("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
+ cmdSize, *replySize);
+ goto exit;
+ }
+ if (!context->offload_enabled) {
+ status = -EINVAL;
+ goto exit;
+ }
+ effect_param_t *q = (effect_param_t *)pCmdData;
+ memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
+ effect_param_t *p = (effect_param_t *)pReplyData;
+ if (context->ops.get_parameter)
+ context->ops.get_parameter(context, p, replySize);
+ } break;
+ case EFFECT_CMD_SET_PARAM: {
+ if (pCmdData == NULL ||
+ cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
+ sizeof(uint16_t)) ||
+ pReplyData == NULL || *replySize != sizeof(int32_t)) {
+ status = -EINVAL;
+ ALOGV("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
+ cmdSize, *replySize);
+ goto exit;
+ }
+ *(int32_t *)pReplyData = 0;
+ effect_param_t *p = (effect_param_t *)pCmdData;
+ if (context->ops.set_parameter)
+ *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
+ *replySize);
+
+ } break;
+ case EFFECT_CMD_SET_DEVICE: {
+ uint32_t device;
+ ALOGV("\t EFFECT_CMD_SET_DEVICE start");
+ if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
+ status = -EINVAL;
+ ALOGV("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
+ goto exit;
+ }
+ device = *(uint32_t *)pCmdData;
+ if (context->ops.set_device)
+ context->ops.set_device(context, device);
+ } break;
+ case EFFECT_CMD_SET_VOLUME:
+ case EFFECT_CMD_SET_AUDIO_MODE:
+ break;
+
+ case EFFECT_CMD_OFFLOAD: {
+ output_context_t *out_ctxt;
+
+ if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
+ || pReplyData == NULL || *replySize != sizeof(int)) {
+ ALOGV("%s EFFECT_CMD_OFFLOAD bad format", __func__);
+ status = -EINVAL;
+ break;
+ }
+
+ effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
+
+ ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
+ offload_param->isOffload, offload_param->ioHandle);
+
+ *(int *)pReplyData = 0;
+
+ context->offload_enabled = offload_param->isOffload;
+ if (context->out_handle == offload_param->ioHandle)
+ break;
+
+ out_ctxt = get_output(context->out_handle);
+ if (out_ctxt != NULL)
+ remove_effect_from_output(out_ctxt, context);
+
+ context->out_handle = offload_param->ioHandle;
+ out_ctxt = get_output(context->out_handle);
+ if (out_ctxt != NULL)
+ add_effect_to_output(out_ctxt, context);
+
+ } break;
+
+
+ default:
+ if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
+ status = context->ops.command(context, cmdCode, cmdSize,
+ pCmdData, replySize, pReplyData);
+ else {
+ ALOGW("%s invalid command %d", __func__, cmdCode);
+ status = -EINVAL;
+ }
+ break;
+ }
+
+exit:
+ pthread_mutex_unlock(&lock);
+
+ return status;
+}
+
+/* Effect Control Interface Implementation: get_descriptor */
+int effect_get_descriptor(effect_handle_t self,
+ effect_descriptor_t *descriptor)
+{
+ effect_context_t *context = (effect_context_t *)self;
+
+ if (!effect_exists(context) || (descriptor == NULL))
+ return -EINVAL;
+
+ *descriptor = *context->desc;
+
+ return 0;
+}
+
+bool effect_is_active(effect_context_t * ctxt) {
+ return ctxt->state == EFFECT_STATE_ACTIVE;
+}
+
+/* effect_handle_t interface implementation for offload effects */
+const struct effect_interface_s effect_interface = {
+ effect_process,
+ effect_command,
+ effect_get_descriptor,
+ NULL,
+};
+
+__attribute__ ((visibility ("default")))
+audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
+ tag : AUDIO_EFFECT_LIBRARY_TAG,
+ version : EFFECT_LIBRARY_API_VERSION,
+ name : "Offload Effects Bundle Library",
+ implementor : "The Android Open Source Project",
+ create_effect : effect_lib_create,
+ release_effect : effect_lib_release,
+ get_descriptor : effect_lib_get_descriptor,
+};
diff --git a/post_proc/bundle.h b/post_proc/bundle.h
new file mode 100644
index 0000000..70a06d4
--- /dev/null
+++ b/post_proc/bundle.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef OFFLOAD_EFFECT_BUNDLE_H
+#define OFFLOAD_EFFECT_BUNDLE_H
+
+#include <tinyalsa/asoundlib.h>
+#include <sound/audio_effects.h>
+#include "effect_api.h"
+
+/* Retry for delay for mixer open */
+#define RETRY_NUMBER 10
+#define RETRY_US 500000
+
+#define MIXER_CARD 0
+#define SOUND_CARD 0
+
+extern const struct effect_interface_s effect_interface;
+
+typedef struct output_context_s output_context_t;
+typedef struct effect_ops_s effect_ops_t;
+typedef struct effect_context_s effect_context_t;
+
+struct output_context_s {
+ /* node in active_outputs_list */
+ struct listnode outputs_list_node;
+ /* io handle */
+ audio_io_handle_t handle;
+ /* list of effects attached to this output */
+ struct listnode effects_list;
+ /* pcm device id */
+ int pcm_device_id;
+ struct mixer *mixer;
+ struct mixer_ctl *ctl;
+};
+
+/* effect specific operations.
+ * Only the init() and process() operations must be defined.
+ * Others are optional.
+ */
+struct effect_ops_s {
+ int (*init)(effect_context_t *context);
+ int (*release)(effect_context_t *context);
+ int (*reset)(effect_context_t *context);
+ int (*enable)(effect_context_t *context);
+ int (*start)(effect_context_t *context, output_context_t *output);
+ int (*stop)(effect_context_t *context, output_context_t *output);
+ int (*disable)(effect_context_t *context);
+ int (*process)(effect_context_t *context, audio_buffer_t *in, audio_buffer_t *out);
+ int (*set_parameter)(effect_context_t *context, effect_param_t *param, uint32_t size);
+ int (*get_parameter)(effect_context_t *context, effect_param_t *param, uint32_t *size);
+ int (*set_device)(effect_context_t *context, uint32_t device);
+ int (*command)(effect_context_t *context, uint32_t cmdCode, uint32_t cmdSize,
+ void *pCmdData, uint32_t *replySize, void *pReplyData);
+};
+
+struct effect_context_s {
+ const struct effect_interface_s *itfe;
+ /* node in created_effects_list */
+ struct listnode effects_list_node;
+ /* node in output_context_t.effects_list */
+ struct listnode output_node;
+ effect_config_t config;
+ const effect_descriptor_t *desc;
+ /* io handle of the output the effect is attached to */
+ audio_io_handle_t out_handle;
+ uint32_t state;
+ bool offload_enabled;
+ effect_ops_t ops;
+};
+
+int set_config(effect_context_t *context, effect_config_t *config);
+
+bool effect_is_active(effect_context_t *context);
+
+#endif /* OFFLOAD_EFFECT_BUNDLE_H */
diff --git a/post_proc/effect_api.c b/post_proc/effect_api.c
new file mode 100644
index 0000000..cf3968b
--- /dev/null
+++ b/post_proc/effect_api.c
@@ -0,0 +1,599 @@
+/*
+ * Copyright (C) 2014 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 "offload_effect_api"
+//#define LOG_NDEBUG 0
+
+#include <stdbool.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <sound/audio_effects.h>
+
+#include "effect_api.h"
+
+#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+
+#define OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL 19
+const int map_eq_opensl_preset_2_offload_preset[] = {
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL, /* Normal Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+1, /* Classical Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+2, /* Dance Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+3, /* Flat Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+4, /* Folk Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+5, /* Heavy Metal Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+6, /* Hip Hop Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+7, /* Jazz Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+8, /* Pop Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+9, /* Rock Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+10 /* FX Booster */
+};
+
+const int map_reverb_opensl_preset_2_offload_preset
+ [NUM_OSL_REVERB_PRESETS_SUPPORTED][2] = {
+ {1, 15},
+ {2, 16},
+ {3, 17},
+ {4, 18},
+ {5, 3},
+ {6, 20}
+};
+
+int offload_update_mixer_and_effects_ctl(int card, int device_id,
+ struct mixer *mixer,
+ struct mixer_ctl *ctl)
+{
+ char mixer_string[128];
+
+ snprintf(mixer_string, sizeof(mixer_string),
+ "%s %d", "Audio Effects Config", device_id);
+ ALOGV("%s: mixer_string: %s", __func__, mixer_string);
+ mixer = mixer_open(card);
+ if (!mixer) {
+ ALOGE("Failed to open mixer");
+ ctl = NULL;
+ return -EINVAL;
+ } else {
+ ctl = mixer_get_ctl_by_name(mixer, mixer_string);
+ if (!ctl) {
+ ALOGE("mixer_get_ctl_by_name failed");
+ mixer_close(mixer);
+ mixer = NULL;
+ return -EINVAL;
+ }
+ }
+ ALOGV("mixer: %p, ctl: %p", mixer, ctl);
+ return 0;
+}
+
+void offload_close_mixer(struct mixer *mixer)
+{
+ mixer_close(mixer);
+}
+
+void offload_bassboost_set_device(struct bass_boost_params *bassboost,
+ uint32_t device)
+{
+ ALOGV("%s", __func__);
+ bassboost->device = device;
+}
+
+void offload_bassboost_set_enable_flag(struct bass_boost_params *bassboost,
+ bool enable)
+{
+ ALOGV("%s", __func__);
+ bassboost->enable_flag = enable;
+}
+
+int offload_bassboost_get_enable_flag(struct bass_boost_params *bassboost)
+{
+ ALOGV("%s", __func__);
+ return bassboost->enable_flag;
+}
+
+void offload_bassboost_set_strength(struct bass_boost_params *bassboost,
+ int strength)
+{
+ ALOGV("%s", __func__);
+ bassboost->strength = strength;
+}
+
+void offload_bassboost_set_mode(struct bass_boost_params *bassboost,
+ int mode)
+{
+ ALOGV("%s", __func__);
+ bassboost->mode = mode;
+}
+
+int offload_bassboost_send_params(struct mixer_ctl *ctl,
+ struct bass_boost_params *bassboost,
+ unsigned param_send_flags)
+{
+ int param_values[128] = {0};
+ int *p_param_values = param_values;
+
+ ALOGV("%s", __func__);
+ *p_param_values++ = BASS_BOOST_MODULE;
+ *p_param_values++ = bassboost->device;
+ *p_param_values++ = 0; /* num of commands*/
+ if (param_send_flags & OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG) {
+ *p_param_values++ = BASS_BOOST_ENABLE;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = BASS_BOOST_ENABLE_PARAM_LEN;
+ *p_param_values++ = bassboost->enable_flag;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_BASSBOOST_STRENGTH) {
+ *p_param_values++ = BASS_BOOST_STRENGTH;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = BASS_BOOST_STRENGTH_PARAM_LEN;
+ *p_param_values++ = bassboost->strength;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_BASSBOOST_MODE) {
+ *p_param_values++ = BASS_BOOST_MODE;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = BASS_BOOST_MODE_PARAM_LEN;
+ *p_param_values++ = bassboost->mode;
+ param_values[2] += 1;
+ }
+
+ if (param_values[2] && ctl)
+ mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+
+ return 0;
+}
+
+void offload_virtualizer_set_device(struct virtualizer_params *virtualizer,
+ uint32_t device)
+{
+ ALOGV("%s", __func__);
+ virtualizer->device = device;
+}
+
+void offload_virtualizer_set_enable_flag(struct virtualizer_params *virtualizer,
+ bool enable)
+{
+ ALOGV("%s", __func__);
+ virtualizer->enable_flag = enable;
+}
+
+int offload_virtualizer_get_enable_flag(struct virtualizer_params *virtualizer)
+{
+ ALOGV("%s", __func__);
+ return virtualizer->enable_flag;
+}
+
+void offload_virtualizer_set_strength(struct virtualizer_params *virtualizer,
+ int strength)
+{
+ ALOGV("%s", __func__);
+ virtualizer->strength = strength;
+}
+
+void offload_virtualizer_set_out_type(struct virtualizer_params *virtualizer,
+ int out_type)
+{
+ ALOGV("%s", __func__);
+ virtualizer->out_type = out_type;
+}
+
+void offload_virtualizer_set_gain_adjust(struct virtualizer_params *virtualizer,
+ int gain_adjust)
+{
+ ALOGV("%s", __func__);
+ virtualizer->gain_adjust = gain_adjust;
+}
+
+int offload_virtualizer_send_params(struct mixer_ctl *ctl,
+ struct virtualizer_params *virtualizer,
+ unsigned param_send_flags)
+{
+ int param_values[128] = {0};
+ int *p_param_values = param_values;
+
+ ALOGV("%s", __func__);
+ *p_param_values++ = VIRTUALIZER_MODULE;
+ *p_param_values++ = virtualizer->device;
+ *p_param_values++ = 0; /* num of commands*/
+ if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG) {
+ *p_param_values++ = VIRTUALIZER_ENABLE;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = VIRTUALIZER_ENABLE_PARAM_LEN;
+ *p_param_values++ = virtualizer->enable_flag;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_STRENGTH) {
+ *p_param_values++ = VIRTUALIZER_STRENGTH;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = VIRTUALIZER_STRENGTH_PARAM_LEN;
+ *p_param_values++ = virtualizer->strength;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE) {
+ *p_param_values++ = VIRTUALIZER_OUT_TYPE;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = VIRTUALIZER_OUT_TYPE_PARAM_LEN;
+ *p_param_values++ = virtualizer->out_type;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_GAIN_ADJUST) {
+ *p_param_values++ = VIRTUALIZER_GAIN_ADJUST;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = VIRTUALIZER_GAIN_ADJUST_PARAM_LEN;
+ *p_param_values++ = virtualizer->gain_adjust;
+ param_values[2] += 1;
+ }
+
+ if (param_values[2] && ctl)
+ mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+
+ return 0;
+}
+
+void offload_eq_set_device(struct eq_params *eq, uint32_t device)
+{
+ ALOGV("%s", __func__);
+ eq->device = device;
+}
+
+void offload_eq_set_enable_flag(struct eq_params *eq, bool enable)
+{
+ ALOGV("%s", __func__);
+ eq->enable_flag = enable;
+}
+
+int offload_eq_get_enable_flag(struct eq_params *eq)
+{
+ ALOGV("%s", __func__);
+ return eq->enable_flag;
+}
+
+void offload_eq_set_preset(struct eq_params *eq, int preset)
+{
+ ALOGV("%s", __func__);
+ eq->config.preset_id = preset;
+ eq->config.eq_pregain = Q27_UNITY;
+}
+
+void offload_eq_set_bands_level(struct eq_params *eq, int num_bands,
+ const uint16_t *band_freq_list,
+ int *band_gain_list)
+{
+ int i;
+ ALOGV("%s", __func__);
+ eq->config.num_bands = num_bands;
+ for (i=0; i<num_bands; i++) {
+ eq->per_band_cfg[i].band_idx = i;
+ eq->per_band_cfg[i].filter_type = EQ_BAND_BOOST;
+ eq->per_band_cfg[i].freq_millihertz = band_freq_list[i] * 1000;
+ eq->per_band_cfg[i].gain_millibels = band_gain_list[i] * 100;
+ eq->per_band_cfg[i].quality_factor = Q8_UNITY;
+ }
+}
+
+int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params *eq,
+ unsigned param_send_flags)
+{
+ int param_values[128] = {0};
+ int *p_param_values = param_values;
+ uint32_t i;
+
+ ALOGV("%s", __func__);
+ if (eq->config.preset_id < -1 ) {
+ ALOGV("No Valid preset to set");
+ return 0;
+ }
+ *p_param_values++ = EQ_MODULE;
+ *p_param_values++ = eq->device;
+ *p_param_values++ = 0; /* num of commands*/
+ if (param_send_flags & OFFLOAD_SEND_EQ_ENABLE_FLAG) {
+ *p_param_values++ = EQ_ENABLE;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = EQ_ENABLE_PARAM_LEN;
+ *p_param_values++ = eq->enable_flag;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_EQ_PRESET) {
+ *p_param_values++ = EQ_CONFIG;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = EQ_CONFIG_PARAM_LEN;
+ *p_param_values++ = eq->config.eq_pregain;
+ *p_param_values++ =
+ map_eq_opensl_preset_2_offload_preset[eq->config.preset_id];
+ *p_param_values++ = 0;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_EQ_BANDS_LEVEL) {
+ *p_param_values++ = EQ_CONFIG;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = EQ_CONFIG_PARAM_LEN +
+ eq->config.num_bands * EQ_CONFIG_PER_BAND_PARAM_LEN;
+ *p_param_values++ = eq->config.eq_pregain;
+ *p_param_values++ = CUSTOM_OPENSL_PRESET;
+ *p_param_values++ = eq->config.num_bands;
+ for (i=0; i<eq->config.num_bands; i++) {
+ *p_param_values++ = eq->per_band_cfg[i].band_idx;
+ *p_param_values++ = eq->per_band_cfg[i].filter_type;
+ *p_param_values++ = eq->per_band_cfg[i].freq_millihertz;
+ *p_param_values++ = eq->per_band_cfg[i].gain_millibels;
+ *p_param_values++ = eq->per_band_cfg[i].quality_factor;
+ }
+ param_values[2] += 1;
+ }
+
+ if (param_values[2] && ctl)
+ mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+
+ return 0;
+}
+
+void offload_reverb_set_device(struct reverb_params *reverb, uint32_t device)
+{
+ ALOGV("%s", __func__);
+ reverb->device = device;
+}
+
+void offload_reverb_set_enable_flag(struct reverb_params *reverb, bool enable)
+{
+ ALOGV("%s", __func__);
+ reverb->enable_flag = enable;
+}
+
+int offload_reverb_get_enable_flag(struct reverb_params *reverb)
+{
+ ALOGV("%s", __func__);
+ return reverb->enable_flag;
+}
+
+void offload_reverb_set_mode(struct reverb_params *reverb, int mode)
+{
+ ALOGV("%s", __func__);
+ reverb->mode = mode;
+}
+
+void offload_reverb_set_preset(struct reverb_params *reverb, int preset)
+{
+ ALOGV("%s", __func__);
+ if (preset && (preset <= NUM_OSL_REVERB_PRESETS_SUPPORTED))
+ reverb->preset = map_reverb_opensl_preset_2_offload_preset[preset-1][1];
+}
+
+void offload_reverb_set_wet_mix(struct reverb_params *reverb, int wet_mix)
+{
+ ALOGV("%s", __func__);
+ reverb->wet_mix = wet_mix;
+}
+
+void offload_reverb_set_gain_adjust(struct reverb_params *reverb,
+ int gain_adjust)
+{
+ ALOGV("%s", __func__);
+ reverb->gain_adjust = gain_adjust;
+}
+
+void offload_reverb_set_room_level(struct reverb_params *reverb, int room_level)
+{
+ ALOGV("%s", __func__);
+ reverb->room_level = room_level;
+}
+
+void offload_reverb_set_room_hf_level(struct reverb_params *reverb,
+ int room_hf_level)
+{
+ ALOGV("%s", __func__);
+ reverb->room_hf_level = room_hf_level;
+}
+
+void offload_reverb_set_decay_time(struct reverb_params *reverb, int decay_time)
+{
+ ALOGV("%s", __func__);
+ reverb->decay_time = decay_time;
+}
+
+void offload_reverb_set_decay_hf_ratio(struct reverb_params *reverb,
+ int decay_hf_ratio)
+{
+ ALOGV("%s", __func__);
+ reverb->decay_hf_ratio = decay_hf_ratio;
+}
+
+void offload_reverb_set_reflections_level(struct reverb_params *reverb,
+ int reflections_level)
+{
+ ALOGV("%s", __func__);
+ reverb->reflections_level = reflections_level;
+}
+
+void offload_reverb_set_reflections_delay(struct reverb_params *reverb,
+ int reflections_delay)
+{
+ ALOGV("%s", __func__);
+ reverb->reflections_delay = reflections_delay;
+}
+
+void offload_reverb_set_reverb_level(struct reverb_params *reverb,
+ int reverb_level)
+{
+ ALOGV("%s", __func__);
+ reverb->level = reverb_level;
+}
+
+void offload_reverb_set_delay(struct reverb_params *reverb, int delay)
+{
+ ALOGV("%s", __func__);
+ reverb->delay = delay;
+}
+
+void offload_reverb_set_diffusion(struct reverb_params *reverb, int diffusion)
+{
+ ALOGV("%s", __func__);
+ reverb->diffusion = diffusion;
+}
+
+void offload_reverb_set_density(struct reverb_params *reverb, int density)
+{
+ ALOGV("%s", __func__);
+ reverb->density = density;
+}
+
+int offload_reverb_send_params(struct mixer_ctl *ctl,
+ struct reverb_params *reverb,
+ unsigned param_send_flags)
+{
+ int param_values[128] = {0};
+ int *p_param_values = param_values;
+
+ ALOGV("%s", __func__);
+ *p_param_values++ = REVERB_MODULE;
+ *p_param_values++ = reverb->device;
+ *p_param_values++ = 0; /* num of commands*/
+
+ if (param_send_flags & OFFLOAD_SEND_REVERB_ENABLE_FLAG) {
+ *p_param_values++ = REVERB_ENABLE;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_ENABLE_PARAM_LEN;
+ *p_param_values++ = reverb->enable_flag;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_MODE) {
+ *p_param_values++ = REVERB_MODE;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_MODE_PARAM_LEN;
+ *p_param_values++ = reverb->mode;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_PRESET) {
+ *p_param_values++ = REVERB_PRESET;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_PRESET_PARAM_LEN;
+ *p_param_values++ = reverb->preset;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_WET_MIX) {
+ *p_param_values++ = REVERB_WET_MIX;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_WET_MIX_PARAM_LEN;
+ *p_param_values++ = reverb->wet_mix;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_GAIN_ADJUST) {
+ *p_param_values++ = REVERB_GAIN_ADJUST;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_GAIN_ADJUST_PARAM_LEN;
+ *p_param_values++ = reverb->gain_adjust;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_ROOM_LEVEL) {
+ *p_param_values++ = REVERB_ROOM_LEVEL;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_ROOM_LEVEL_PARAM_LEN;
+ *p_param_values++ = reverb->room_level;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL) {
+ *p_param_values++ = REVERB_ROOM_HF_LEVEL;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_ROOM_HF_LEVEL_PARAM_LEN;
+ *p_param_values++ = reverb->room_hf_level;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_DECAY_TIME) {
+ *p_param_values++ = REVERB_DECAY_TIME;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_DECAY_TIME_PARAM_LEN;
+ *p_param_values++ = reverb->decay_time;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_DECAY_HF_RATIO) {
+ *p_param_values++ = REVERB_DECAY_HF_RATIO;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_DECAY_HF_RATIO_PARAM_LEN;
+ *p_param_values++ = reverb->decay_hf_ratio;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL) {
+ *p_param_values++ = REVERB_REFLECTIONS_LEVEL;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_REFLECTIONS_LEVEL_PARAM_LEN;
+ *p_param_values++ = reverb->reflections_level;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY) {
+ *p_param_values++ = REVERB_REFLECTIONS_DELAY;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_REFLECTIONS_DELAY_PARAM_LEN;
+ *p_param_values++ = reverb->reflections_delay;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_LEVEL) {
+ *p_param_values++ = REVERB_LEVEL;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_LEVEL_PARAM_LEN;
+ *p_param_values++ = reverb->level;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_DELAY) {
+ *p_param_values++ = REVERB_DELAY;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_DELAY_PARAM_LEN;
+ *p_param_values++ = reverb->delay;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_DIFFUSION) {
+ *p_param_values++ = REVERB_DIFFUSION;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_DIFFUSION_PARAM_LEN;
+ *p_param_values++ = reverb->diffusion;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_DENSITY) {
+ *p_param_values++ = REVERB_DENSITY;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_DENSITY_PARAM_LEN;
+ *p_param_values++ = reverb->density;
+ param_values[2] += 1;
+ }
+
+ if (param_values[2] && ctl)
+ mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+
+ return 0;
+}
diff --git a/post_proc/effect_api.h b/post_proc/effect_api.h
new file mode 100644
index 0000000..b169319
--- /dev/null
+++ b/post_proc/effect_api.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef OFFLOAD_EFFECT_API_H_
+#define OFFLOAD_EFFECT_API_H_
+
+int offload_update_mixer_and_effects_ctl(int card, int device_id,
+ struct mixer *mixer,
+ struct mixer_ctl *ctl);
+void offload_close_mixer(struct mixer *mixer);
+
+#define OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG (1 << 0)
+#define OFFLOAD_SEND_BASSBOOST_STRENGTH \
+ (OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG << 1)
+#define OFFLOAD_SEND_BASSBOOST_MODE \
+ (OFFLOAD_SEND_BASSBOOST_STRENGTH << 1)
+void offload_bassboost_set_device(struct bass_boost_params *bassboost,
+ uint32_t device);
+void offload_bassboost_set_enable_flag(struct bass_boost_params *bassboost,
+ bool enable);
+int offload_bassboost_get_enable_flag(struct bass_boost_params *bassboost);
+void offload_bassboost_set_strength(struct bass_boost_params *bassboost,
+ int strength);
+void offload_bassboost_set_mode(struct bass_boost_params *bassboost,
+ int mode);
+int offload_bassboost_send_params(struct mixer_ctl *ctl,
+ struct bass_boost_params *bassboost,
+ unsigned param_send_flags);
+
+#define OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG (1 << 0)
+#define OFFLOAD_SEND_VIRTUALIZER_STRENGTH \
+ (OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG << 1)
+#define OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE \
+ (OFFLOAD_SEND_VIRTUALIZER_STRENGTH << 1)
+#define OFFLOAD_SEND_VIRTUALIZER_GAIN_ADJUST \
+ (OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE << 1)
+void offload_virtualizer_set_device(struct virtualizer_params *virtualizer,
+ uint32_t device);
+void offload_virtualizer_set_enable_flag(struct virtualizer_params *virtualizer,
+ bool enable);
+int offload_virtualizer_get_enable_flag(struct virtualizer_params *virtualizer);
+void offload_virtualizer_set_strength(struct virtualizer_params *virtualizer,
+ int strength);
+void offload_virtualizer_set_out_type(struct virtualizer_params *virtualizer,
+ int out_type);
+void offload_virtualizer_set_gain_adjust(struct virtualizer_params *virtualizer,
+ int gain_adjust);
+int offload_virtualizer_send_params(struct mixer_ctl *ctl,
+ struct virtualizer_params *virtualizer,
+ unsigned param_send_flags);
+
+#define OFFLOAD_SEND_EQ_ENABLE_FLAG (1 << 0)
+#define OFFLOAD_SEND_EQ_PRESET \
+ (OFFLOAD_SEND_EQ_ENABLE_FLAG << 1)
+#define OFFLOAD_SEND_EQ_BANDS_LEVEL \
+ (OFFLOAD_SEND_EQ_PRESET << 1)
+void offload_eq_set_device(struct eq_params *eq, uint32_t device);
+void offload_eq_set_enable_flag(struct eq_params *eq, bool enable);
+int offload_eq_get_enable_flag(struct eq_params *eq);
+void offload_eq_set_preset(struct eq_params *eq, int preset);
+void offload_eq_set_bands_level(struct eq_params *eq, int num_bands,
+ const uint16_t *band_freq_list,
+ int *band_gain_list);
+int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params *eq,
+ unsigned param_send_flags);
+
+#define OFFLOAD_SEND_REVERB_ENABLE_FLAG (1 << 0)
+#define OFFLOAD_SEND_REVERB_MODE \
+ (OFFLOAD_SEND_REVERB_ENABLE_FLAG << 1)
+#define OFFLOAD_SEND_REVERB_PRESET \
+ (OFFLOAD_SEND_REVERB_MODE << 1)
+#define OFFLOAD_SEND_REVERB_WET_MIX \
+ (OFFLOAD_SEND_REVERB_PRESET << 1)
+#define OFFLOAD_SEND_REVERB_GAIN_ADJUST \
+ (OFFLOAD_SEND_REVERB_WET_MIX << 1)
+#define OFFLOAD_SEND_REVERB_ROOM_LEVEL \
+ (OFFLOAD_SEND_REVERB_GAIN_ADJUST << 1)
+#define OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL \
+ (OFFLOAD_SEND_REVERB_ROOM_LEVEL << 1)
+#define OFFLOAD_SEND_REVERB_DECAY_TIME \
+ (OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL << 1)
+#define OFFLOAD_SEND_REVERB_DECAY_HF_RATIO \
+ (OFFLOAD_SEND_REVERB_DECAY_TIME << 1)
+#define OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL \
+ (OFFLOAD_SEND_REVERB_DECAY_HF_RATIO << 1)
+#define OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY \
+ (OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL << 1)
+#define OFFLOAD_SEND_REVERB_LEVEL \
+ (OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY << 1)
+#define OFFLOAD_SEND_REVERB_DELAY \
+ (OFFLOAD_SEND_REVERB_LEVEL << 1)
+#define OFFLOAD_SEND_REVERB_DIFFUSION \
+ (OFFLOAD_SEND_REVERB_DELAY << 1)
+#define OFFLOAD_SEND_REVERB_DENSITY \
+ (OFFLOAD_SEND_REVERB_DIFFUSION << 1)
+void offload_reverb_set_device(struct reverb_params *reverb, uint32_t device);
+void offload_reverb_set_enable_flag(struct reverb_params *reverb, bool enable);
+int offload_reverb_get_enable_flag(struct reverb_params *reverb);
+void offload_reverb_set_mode(struct reverb_params *reverb, int mode);
+void offload_reverb_set_preset(struct reverb_params *reverb, int preset);
+void offload_reverb_set_wet_mix(struct reverb_params *reverb, int wet_mix);
+void offload_reverb_set_gain_adjust(struct reverb_params *reverb,
+ int gain_adjust);
+void offload_reverb_set_room_level(struct reverb_params *reverb,
+ int room_level);
+void offload_reverb_set_room_hf_level(struct reverb_params *reverb,
+ int room_hf_level);
+void offload_reverb_set_decay_time(struct reverb_params *reverb,
+ int decay_time);
+void offload_reverb_set_decay_hf_ratio(struct reverb_params *reverb,
+ int decay_hf_ratio);
+void offload_reverb_set_reflections_level(struct reverb_params *reverb,
+ int reflections_level);
+void offload_reverb_set_reflections_delay(struct reverb_params *reverb,
+ int reflections_delay);
+void offload_reverb_set_reverb_level(struct reverb_params *reverb,
+ int reverb_level);
+void offload_reverb_set_delay(struct reverb_params *reverb, int delay);
+void offload_reverb_set_diffusion(struct reverb_params *reverb, int diffusion);
+void offload_reverb_set_density(struct reverb_params *reverb, int density);
+int offload_reverb_send_params(struct mixer_ctl *ctl,
+ struct reverb_params *reverb,
+ unsigned param_send_flags);
+
+#endif /*OFFLOAD_EFFECT_API_H_*/
diff --git a/post_proc/equalizer.c b/post_proc/equalizer.c
new file mode 100644
index 0000000..7cff348
--- /dev/null
+++ b/post_proc/equalizer.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2014 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 "offload_effect_equalizer"
+//#define LOG_NDEBUG 0
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <sound/audio_effects.h>
+#include <audio_effects/effect_equalizer.h>
+
+#include "effect_api.h"
+#include "equalizer.h"
+
+/* Offload equalizer UUID: a0dac280-401c-11e3-9379-0002a5d5c51b */
+const effect_descriptor_t equalizer_descriptor = {
+ {0x0bed4300, 0xddd6, 0x11db, 0x8f34, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type
+ {0xa0dac280, 0x401c, 0x11e3, 0x9379, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_HW_ACC_TUNNEL),
+ 0, /* TODO */
+ 1,
+ "MSM offload equalizer",
+ "The Android Open Source Project",
+};
+
+static const char *equalizer_preset_names[] = {
+ "Normal",
+ "Classical",
+ "Dance",
+ "Flat",
+ "Folk",
+ "Heavy Metal",
+ "Hip Hop",
+ "Jazz",
+ "Pop",
+ "Rock"
+ };
+
+static const uint32_t equalizer_band_freq_range[NUM_EQ_BANDS][2] = {
+ {30000, 120000},
+ {120001, 460000},
+ {460001, 1800000},
+ {1800001, 7000000},
+ {7000001, 20000000}};
+
+static const int16_t equalizer_band_presets_level[] = {
+ 3, 0, 0, 0, 3, /* Normal Preset */
+ 5, 3, -2, 4, 4, /* Classical Preset */
+ 6, 0, 2, 4, 1, /* Dance Preset */
+ 0, 0, 0, 0, 0, /* Flat Preset */
+ 3, 0, 0, 2, -1, /* Folk Preset */
+ 4, 1, 9, 3, 0, /* Heavy Metal Preset */
+ 5, 3, 0, 1, 3, /* Hip Hop Preset */
+ 4, 2, -2, 2, 5, /* Jazz Preset */
+ -1, 2, 5, 1, -2, /* Pop Preset */
+ 5, 3, -1, 3, 5}; /* Rock Preset */
+
+const uint16_t equalizer_band_presets_freq[NUM_EQ_BANDS] = {
+ 60, /* Frequencies in Hz */
+ 230,
+ 910,
+ 3600,
+ 14000
+};
+
+/*
+ * Equalizer operations
+ */
+
+int equalizer_get_band_level(equalizer_context_t *context, int32_t band)
+{
+ ALOGV("%s: band: %d level: %d", __func__, band,
+ context->band_levels[band] * 100);
+ return context->band_levels[band] * 100;
+}
+
+int equalizer_set_band_level(equalizer_context_t *context, int32_t band,
+ int32_t level)
+{
+ ALOGV("%s: band: %d, level: %d", __func__, band, level);
+ if (level > 0) {
+ level = (int)((level+50)/100);
+ } else {
+ level = (int)((level-50)/100);
+ }
+ context->band_levels[band] = level;
+ context->preset = PRESET_CUSTOM;
+
+ offload_eq_set_preset(&(context->offload_eq), PRESET_CUSTOM);
+ offload_eq_set_bands_level(&(context->offload_eq),
+ NUM_EQ_BANDS,
+ equalizer_band_presets_freq,
+ context->band_levels);
+ if (context->ctl)
+ offload_eq_send_params(context->ctl, &context->offload_eq,
+ OFFLOAD_SEND_EQ_ENABLE_FLAG |
+ OFFLOAD_SEND_EQ_BANDS_LEVEL);
+ return 0;
+}
+
+int equalizer_get_center_frequency(equalizer_context_t *context __unused, int32_t band)
+{
+ ALOGV("%s: band: %d", __func__, band);
+ return (equalizer_band_freq_range[band][0] +
+ equalizer_band_freq_range[band][1]) / 2;
+}
+
+int equalizer_get_band_freq_range(equalizer_context_t *context __unused, int32_t band,
+ uint32_t *low, uint32_t *high)
+{
+ ALOGV("%s: band: %d", __func__, band);
+ *low = equalizer_band_freq_range[band][0];
+ *high = equalizer_band_freq_range[band][1];
+ return 0;
+}
+
+int equalizer_get_band(equalizer_context_t *context __unused, uint32_t freq)
+{
+ int i;
+
+ ALOGV("%s: freq: %d", __func__, freq);
+ for (i = 0; i < NUM_EQ_BANDS; i++) {
+ if (freq <= equalizer_band_freq_range[i][1]) {
+ return i;
+ }
+ }
+ return NUM_EQ_BANDS - 1;
+}
+
+int equalizer_get_preset(equalizer_context_t *context)
+{
+ ALOGV("%s: preset: %d", __func__, context->preset);
+ return context->preset;
+}
+
+int equalizer_set_preset(equalizer_context_t *context, int preset)
+{
+ int i;
+
+ ALOGV("%s: preset: %d", __func__, preset);
+ context->preset = preset;
+ for (i=0; i<NUM_EQ_BANDS; i++)
+ context->band_levels[i] =
+ equalizer_band_presets_level[i + preset * NUM_EQ_BANDS];
+
+ offload_eq_set_preset(&(context->offload_eq), preset);
+ offload_eq_set_bands_level(&(context->offload_eq),
+ NUM_EQ_BANDS,
+ equalizer_band_presets_freq,
+ context->band_levels);
+ if(context->ctl)
+ offload_eq_send_params(context->ctl, &context->offload_eq,
+ OFFLOAD_SEND_EQ_ENABLE_FLAG |
+ OFFLOAD_SEND_EQ_PRESET);
+ return 0;
+}
+
+const char * equalizer_get_preset_name(equalizer_context_t *context __unused,
+ int32_t preset)
+{
+ ALOGV("%s: preset: %s", __func__, equalizer_preset_names[preset]);
+ if (preset == PRESET_CUSTOM) {
+ return "Custom";
+ } else {
+ return equalizer_preset_names[preset];
+ }
+}
+
+int equalizer_get_num_presets(equalizer_context_t *context __unused)
+{
+ ALOGV("%s: presets_num: %d", __func__,
+ sizeof(equalizer_preset_names)/sizeof(char *));
+ return sizeof(equalizer_preset_names)/sizeof(char *);
+}
+
+int equalizer_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size)
+{
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ int32_t param2;
+ char *name;
+ void *value = p->data + voffset;
+ int i;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case EQ_PARAM_NUM_BANDS:
+ case EQ_PARAM_CUR_PRESET:
+ case EQ_PARAM_GET_NUM_OF_PRESETS:
+ case EQ_PARAM_BAND_LEVEL:
+ case EQ_PARAM_GET_BAND:
+ if (p->vsize < sizeof(int16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(int16_t);
+ break;
+
+ case EQ_PARAM_LEVEL_RANGE:
+ if (p->vsize < 2 * sizeof(int16_t))
+ p->status = -EINVAL;
+ p->vsize = 2 * sizeof(int16_t);
+ break;
+ case EQ_PARAM_BAND_FREQ_RANGE:
+ if (p->vsize < 2 * sizeof(int32_t))
+ p->status = -EINVAL;
+ p->vsize = 2 * sizeof(int32_t);
+ break;
+
+ case EQ_PARAM_CENTER_FREQ:
+ if (p->vsize < sizeof(int32_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(int32_t);
+ break;
+
+ case EQ_PARAM_GET_PRESET_NAME:
+ break;
+
+ case EQ_PARAM_PROPERTIES:
+ if (p->vsize < (2 + NUM_EQ_BANDS) * sizeof(uint16_t))
+ p->status = -EINVAL;
+ p->vsize = (2 + NUM_EQ_BANDS) * sizeof(uint16_t);
+ break;
+
+ default:
+ p->status = -EINVAL;
+ }
+
+ *size = sizeof(effect_param_t) + voffset + p->vsize;
+
+ if (p->status != 0)
+ return 0;
+
+ switch (param) {
+ case EQ_PARAM_NUM_BANDS:
+ ALOGV("%s: EQ_PARAM_NUM_BANDS", __func__);
+ *(uint16_t *)value = (uint16_t)NUM_EQ_BANDS;
+ break;
+
+ case EQ_PARAM_LEVEL_RANGE:
+ ALOGV("%s: EQ_PARAM_LEVEL_RANGE", __func__);
+ *(int16_t *)value = -1500;
+ *((int16_t *)value + 1) = 1500;
+ break;
+
+ case EQ_PARAM_BAND_LEVEL:
+ ALOGV("%s: EQ_PARAM_BAND_LEVEL", __func__);
+ param2 = *param_tmp;
+ if (param2 >= NUM_EQ_BANDS) {
+ p->status = -EINVAL;
+ break;
+ }
+ *(int16_t *)value = (int16_t)equalizer_get_band_level(eq_ctxt, param2);
+ break;
+
+ case EQ_PARAM_CENTER_FREQ:
+ ALOGV("%s: EQ_PARAM_CENTER_FREQ", __func__);
+ param2 = *param_tmp;
+ if (param2 >= NUM_EQ_BANDS) {
+ p->status = -EINVAL;
+ break;
+ }
+ *(int32_t *)value = equalizer_get_center_frequency(eq_ctxt, param2);
+ break;
+
+ case EQ_PARAM_BAND_FREQ_RANGE:
+ ALOGV("%s: EQ_PARAM_BAND_FREQ_RANGE", __func__);
+ param2 = *param_tmp;
+ if (param2 >= NUM_EQ_BANDS) {
+ p->status = -EINVAL;
+ break;
+ }
+ equalizer_get_band_freq_range(eq_ctxt, param2, (uint32_t *)value,
+ ((uint32_t *)value + 1));
+ break;
+
+ case EQ_PARAM_GET_BAND:
+ ALOGV("%s: EQ_PARAM_GET_BAND", __func__);
+ param2 = *param_tmp;
+ *(uint16_t *)value = (uint16_t)equalizer_get_band(eq_ctxt, param2);
+ break;
+
+ case EQ_PARAM_CUR_PRESET:
+ ALOGV("%s: EQ_PARAM_CUR_PRESET", __func__);
+ *(uint16_t *)value = (uint16_t)equalizer_get_preset(eq_ctxt);
+ break;
+
+ case EQ_PARAM_GET_NUM_OF_PRESETS:
+ ALOGV("%s: EQ_PARAM_GET_NUM_OF_PRESETS", __func__);
+ *(uint16_t *)value = (uint16_t)equalizer_get_num_presets(eq_ctxt);
+ break;
+
+ case EQ_PARAM_GET_PRESET_NAME:
+ ALOGV("%s: EQ_PARAM_GET_PRESET_NAME", __func__);
+ param2 = *param_tmp;
+ ALOGV("param2: %d", param2);
+ if (param2 >= equalizer_get_num_presets(eq_ctxt)) {
+ p->status = -EINVAL;
+ break;
+ }
+ name = (char *)value;
+ strlcpy(name, equalizer_get_preset_name(eq_ctxt, param2), p->vsize - 1);
+ name[p->vsize - 1] = 0;
+ p->vsize = strlen(name) + 1;
+ break;
+
+ case EQ_PARAM_PROPERTIES: {
+ ALOGV("%s: EQ_PARAM_PROPERTIES", __func__);
+ int16_t *prop = (int16_t *)value;
+ prop[0] = (int16_t)equalizer_get_preset(eq_ctxt);
+ prop[1] = (int16_t)NUM_EQ_BANDS;
+ for (i = 0; i < NUM_EQ_BANDS; i++) {
+ prop[2 + i] = (int16_t)equalizer_get_band_level(eq_ctxt, i);
+ }
+ } break;
+
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int equalizer_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size __unused)
+{
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ void *value = p->data + voffset;
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ int32_t preset;
+ int32_t band;
+ int32_t level;
+ int i;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case EQ_PARAM_CUR_PRESET:
+ ALOGV("EQ_PARAM_CUR_PRESET");
+ preset = (int32_t)(*(uint16_t *)value);
+
+ if ((preset >= equalizer_get_num_presets(eq_ctxt)) || (preset < 0)) {
+ p->status = -EINVAL;
+ break;
+ }
+ equalizer_set_preset(eq_ctxt, preset);
+ break;
+ case EQ_PARAM_BAND_LEVEL:
+ ALOGV("EQ_PARAM_BAND_LEVEL");
+ band = *param_tmp;
+ level = (int32_t)(*(int16_t *)value);
+ if (band >= NUM_EQ_BANDS) {
+ p->status = -EINVAL;
+ break;
+ }
+ equalizer_set_band_level(eq_ctxt, band, level);
+ break;
+ case EQ_PARAM_PROPERTIES: {
+ ALOGV("EQ_PARAM_PROPERTIES");
+ int16_t *prop = (int16_t *)value;
+ if ((int)prop[0] >= equalizer_get_num_presets(eq_ctxt)) {
+ p->status = -EINVAL;
+ break;
+ }
+ if (prop[0] >= 0) {
+ equalizer_set_preset(eq_ctxt, (int)prop[0]);
+ } else {
+ if ((int)prop[1] != NUM_EQ_BANDS) {
+ p->status = -EINVAL;
+ break;
+ }
+ for (i = 0; i < NUM_EQ_BANDS; i++) {
+ equalizer_set_band_level(eq_ctxt, i, (int)prop[2 + i]);
+ }
+ }
+ } break;
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int equalizer_set_device(effect_context_t *context, uint32_t device)
+{
+ ALOGV("%s: device: %d", __func__, device);
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+ eq_ctxt->device = device;
+ offload_eq_set_device(&(eq_ctxt->offload_eq), device);
+ return 0;
+}
+
+int equalizer_reset(effect_context_t *context)
+{
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+ return 0;
+}
+
+int equalizer_init(effect_context_t *context)
+{
+ ALOGV("%s", __func__);
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+ context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+ context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.inputCfg.samplingRate = 44100;
+ context->config.inputCfg.bufferProvider.getBuffer = NULL;
+ context->config.inputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.inputCfg.bufferProvider.cookie = NULL;
+ context->config.inputCfg.mask = EFFECT_CONFIG_ALL;
+ context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+ context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.outputCfg.samplingRate = 44100;
+ context->config.outputCfg.bufferProvider.getBuffer = NULL;
+ context->config.outputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.outputCfg.bufferProvider.cookie = NULL;
+ context->config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+ set_config(context, &context->config);
+
+ memset(&(eq_ctxt->offload_eq), 0, sizeof(struct eq_params));
+ offload_eq_set_preset(&(eq_ctxt->offload_eq), INVALID_PRESET);
+
+ return 0;
+}
+
+int equalizer_enable(effect_context_t *context)
+{
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+ ALOGV("%s", __func__);
+
+ if (!offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) {
+ offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), true);
+ if (eq_ctxt->ctl)
+ offload_eq_send_params(eq_ctxt->ctl, &eq_ctxt->offload_eq,
+ OFFLOAD_SEND_EQ_ENABLE_FLAG |
+ OFFLOAD_SEND_EQ_BANDS_LEVEL);
+ }
+ return 0;
+}
+
+int equalizer_disable(effect_context_t *context)
+{
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+ ALOGV("%s", __func__);
+ if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) {
+ offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), false);
+ if (eq_ctxt->ctl)
+ offload_eq_send_params(eq_ctxt->ctl, &eq_ctxt->offload_eq,
+ OFFLOAD_SEND_EQ_ENABLE_FLAG);
+ }
+ return 0;
+}
+
+int equalizer_start(effect_context_t *context, output_context_t *output)
+{
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+ ALOGV("%s: %p", __func__, output->ctl);
+ eq_ctxt->ctl = output->ctl;
+ if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq)))
+ if (eq_ctxt->ctl)
+ offload_eq_send_params(eq_ctxt->ctl, &eq_ctxt->offload_eq,
+ OFFLOAD_SEND_EQ_ENABLE_FLAG |
+ OFFLOAD_SEND_EQ_BANDS_LEVEL);
+ return 0;
+}
+
+int equalizer_stop(effect_context_t *context, output_context_t *output __unused)
+{
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+ ALOGV("%s", __func__);
+ eq_ctxt->ctl = NULL;
+ return 0;
+}
diff --git a/post_proc/equalizer.h b/post_proc/equalizer.h
new file mode 100644
index 0000000..00ad616
--- /dev/null
+++ b/post_proc/equalizer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef OFFLOAD_EQUALIZER_H_
+#define OFFLOAD_EQUALIZER_H_
+
+#include "bundle.h"
+
+#define NUM_EQ_BANDS 5
+#define INVALID_PRESET -2
+#define PRESET_CUSTOM -1
+
+extern const effect_descriptor_t equalizer_descriptor;
+
+typedef struct equalizer_context_s {
+ effect_context_t common;
+
+ int preset;
+ int band_levels[NUM_EQ_BANDS];
+
+ // Offload vars
+ struct mixer_ctl *ctl;
+ uint32_t device;
+ struct eq_params offload_eq;
+} equalizer_context_t;
+
+int equalizer_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size);
+
+int equalizer_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size);
+
+int equalizer_set_device(effect_context_t *context, uint32_t device);
+
+int equalizer_reset(effect_context_t *context);
+
+int equalizer_init(effect_context_t *context);
+
+int equalizer_enable(effect_context_t *context);
+
+int equalizer_disable(effect_context_t *context);
+
+int equalizer_start(effect_context_t *context, output_context_t *output);
+
+int equalizer_stop(effect_context_t *context, output_context_t *output);
+
+#endif /*OFFLOAD_EQUALIZER_H_*/
diff --git a/post_proc/reverb.c b/post_proc/reverb.c
new file mode 100644
index 0000000..e5fc950
--- /dev/null
+++ b/post_proc/reverb.c
@@ -0,0 +1,632 @@
+/*
+ * Copyright (C) 2014 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 "offload_effect_reverb"
+//#define LOG_NDEBUG 0
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <sound/audio_effects.h>
+#include <audio_effects/effect_environmentalreverb.h>
+#include <audio_effects/effect_presetreverb.h>
+
+#include "effect_api.h"
+#include "reverb.h"
+
+/* Offload auxiliary environmental reverb UUID: 79a18026-18fd-4185-8233-0002a5d5c51b */
+const effect_descriptor_t aux_env_reverb_descriptor = {
+ { 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, { 0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e } },
+ { 0x79a18026, 0x18fd, 0x4185, 0x8233, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } },
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_HW_ACC_TUNNEL),
+ 0, /* TODO */
+ 1,
+ "MSM offload Auxiliary Environmental Reverb",
+ "The Android Open Source Project",
+};
+
+/* Offload insert environmental reverb UUID: eb64ea04-973b-43d2-8f5e-0002a5d5c51b */
+const effect_descriptor_t ins_env_reverb_descriptor = {
+ {0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}},
+ {0xeb64ea04, 0x973b, 0x43d2, 0x8f5e, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST | EFFECT_FLAG_HW_ACC_TUNNEL),
+ 0, /* TODO */
+ 1,
+ "MSM offload Insert Environmental Reverb",
+ "The Android Open Source Project",
+};
+
+// Offload auxiliary preset reverb UUID: 6987be09-b142-4b41-9056-0002a5d5c51b */
+const effect_descriptor_t aux_preset_reverb_descriptor = {
+ {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ {0x6987be09, 0xb142, 0x4b41, 0x9056, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_HW_ACC_TUNNEL),
+ 0, /* TODO */
+ 1,
+ "MSM offload Auxiliary Preset Reverb",
+ "The Android Open Source Project",
+};
+
+// Offload insert preset reverb UUID: aa2bebf6-47cf-4613-9bca-0002a5d5c51b */
+const effect_descriptor_t ins_preset_reverb_descriptor = {
+ {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ {0xaa2bebf6, 0x47cf, 0x4613, 0x9bca, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST | EFFECT_FLAG_HW_ACC_TUNNEL),
+ 0, /* TODO */
+ 1,
+ "MSM offload Insert Preset Reverb",
+ "The Android Open Source Project",
+};
+
+static const reverb_settings_t reverb_presets[] = {
+ // REVERB_PRESET_NONE: values are unused
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ // REVERB_PRESET_SMALLROOM
+ {-400, -600, 1100, 830, -400, 5, 500, 10, 1000, 1000},
+ // REVERB_PRESET_MEDIUMROOM
+ {-400, -600, 1300, 830, -1000, 20, -200, 20, 1000, 1000},
+ // REVERB_PRESET_LARGEROOM
+ {-400, -600, 1500, 830, -1600, 5, -1000, 40, 1000, 1000},
+ // REVERB_PRESET_MEDIUMHALL
+ {-400, -600, 1800, 700, -1300, 15, -800, 30, 1000, 1000},
+ // REVERB_PRESET_LARGEHALL
+ {-400, -600, 1800, 700, -2000, 30, -1400, 60, 1000, 1000},
+ // REVERB_PRESET_PLATE
+ {-400, -200, 1300, 900, 0, 2, 0, 10, 1000, 750},
+};
+
+
+void reverb_auxiliary_init(reverb_context_t *context)
+{
+ context->auxiliary = true;
+ context->preset = false;
+}
+
+void reverb_insert_init(reverb_context_t *context)
+{
+ context->auxiliary = false;
+ context->preset = true;
+ context->cur_preset = REVERB_PRESET_LAST + 1;
+ context->next_preset = REVERB_DEFAULT_PRESET;
+}
+
+void reverb_preset_init(reverb_context_t *context)
+{
+ context->auxiliary = false;
+ context->preset = true;
+ context->cur_preset = REVERB_PRESET_LAST + 1;
+ context->next_preset = REVERB_DEFAULT_PRESET;
+}
+
+/*
+ * Reverb operations
+ */
+int16_t reverb_get_room_level(reverb_context_t *context)
+{
+ ALOGV("%s: room level: %d", __func__, context->reverb_settings.roomLevel);
+ return context->reverb_settings.roomLevel;
+}
+
+void reverb_set_room_level(reverb_context_t *context, int16_t room_level)
+{
+ ALOGV("%s: room level: %d", __func__, room_level);
+ context->reverb_settings.roomLevel = room_level;
+ offload_reverb_set_room_level(&(context->offload_reverb), room_level);
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, &context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_ROOM_LEVEL);
+}
+
+int16_t reverb_get_room_hf_level(reverb_context_t *context)
+{
+ ALOGV("%s: room hf level: %d", __func__,
+ context->reverb_settings.roomHFLevel);
+ return context->reverb_settings.roomHFLevel;
+}
+
+void reverb_set_room_hf_level(reverb_context_t *context, int16_t room_hf_level)
+{
+ ALOGV("%s: room hf level: %d", __func__, room_hf_level);
+ context->reverb_settings.roomHFLevel = room_hf_level;
+ offload_reverb_set_room_hf_level(&(context->offload_reverb), room_hf_level);
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, &context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL);
+}
+
+uint32_t reverb_get_decay_time(reverb_context_t *context)
+{
+ ALOGV("%s: decay time: %d", __func__, context->reverb_settings.decayTime);
+ return context->reverb_settings.decayTime;
+}
+
+void reverb_set_decay_time(reverb_context_t *context, uint32_t decay_time)
+{
+ ALOGV("%s: decay_time: %d", __func__, decay_time);
+ context->reverb_settings.decayTime = decay_time;
+ offload_reverb_set_decay_time(&(context->offload_reverb), decay_time);
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, &context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_DECAY_TIME);
+}
+
+int16_t reverb_get_decay_hf_ratio(reverb_context_t *context)
+{
+ ALOGV("%s: decay hf ratio: %d", __func__,
+ context->reverb_settings.decayHFRatio);
+ return context->reverb_settings.decayHFRatio;
+}
+
+void reverb_set_decay_hf_ratio(reverb_context_t *context, int16_t decay_hf_ratio)
+{
+ ALOGV("%s: decay_hf_ratio: %d", __func__, decay_hf_ratio);
+ context->reverb_settings.decayHFRatio = decay_hf_ratio;
+ offload_reverb_set_decay_hf_ratio(&(context->offload_reverb), decay_hf_ratio);
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, &context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_DECAY_HF_RATIO);
+}
+
+int16_t reverb_get_reverb_level(reverb_context_t *context)
+{
+ ALOGV("%s: reverb level: %d", __func__, context->reverb_settings.reverbLevel);
+ return context->reverb_settings.reverbLevel;
+}
+
+void reverb_set_reverb_level(reverb_context_t *context, int16_t reverb_level)
+{
+ ALOGV("%s: reverb level: %d", __func__, reverb_level);
+ context->reverb_settings.reverbLevel = reverb_level;
+ offload_reverb_set_reverb_level(&(context->offload_reverb), reverb_level);
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, &context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_LEVEL);
+}
+
+int16_t reverb_get_diffusion(reverb_context_t *context)
+{
+ ALOGV("%s: diffusion: %d", __func__, context->reverb_settings.diffusion);
+ return context->reverb_settings.diffusion;
+}
+
+void reverb_set_diffusion(reverb_context_t *context, int16_t diffusion)
+{
+ ALOGV("%s: diffusion: %d", __func__, diffusion);
+ context->reverb_settings.diffusion = diffusion;
+ offload_reverb_set_diffusion(&(context->offload_reverb), diffusion);
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, &context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_DIFFUSION);
+}
+
+int16_t reverb_get_density(reverb_context_t *context)
+{
+ ALOGV("%s: density: %d", __func__, context->reverb_settings.density);
+ return context->reverb_settings.density;
+}
+
+void reverb_set_density(reverb_context_t *context, int16_t density)
+{
+ ALOGV("%s: density: %d", __func__, density);
+ context->reverb_settings.density = density;
+ offload_reverb_set_density(&(context->offload_reverb), density);
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, &context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_DENSITY);
+}
+
+void reverb_set_preset(reverb_context_t *context, int16_t preset)
+{
+ bool enable;
+ ALOGV("%s: preset: %d", __func__, preset);
+ context->next_preset = preset;
+ offload_reverb_set_preset(&(context->offload_reverb), preset);
+
+ enable = (preset == REVERB_PRESET_NONE) ? false: true;
+ offload_reverb_set_enable_flag(&(context->offload_reverb), enable);
+
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, &context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_PRESET);
+}
+
+void reverb_set_all_properties(reverb_context_t *context,
+ reverb_settings_t *reverb_settings)
+{
+ ALOGV("%s", __func__);
+ context->reverb_settings.roomLevel = reverb_settings->roomLevel;
+ context->reverb_settings.roomHFLevel = reverb_settings->roomHFLevel;
+ context->reverb_settings.decayTime = reverb_settings->decayTime;
+ context->reverb_settings.decayHFRatio = reverb_settings->decayHFRatio;
+ context->reverb_settings.reverbLevel = reverb_settings->reverbLevel;
+ context->reverb_settings.diffusion = reverb_settings->diffusion;
+ context->reverb_settings.density = reverb_settings->density;
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, &context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_ROOM_LEVEL |
+ OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL |
+ OFFLOAD_SEND_REVERB_DECAY_TIME |
+ OFFLOAD_SEND_REVERB_DECAY_HF_RATIO |
+ OFFLOAD_SEND_REVERB_LEVEL |
+ OFFLOAD_SEND_REVERB_DIFFUSION |
+ OFFLOAD_SEND_REVERB_DENSITY);
+}
+
+void reverb_load_preset(reverb_context_t *context)
+{
+ context->cur_preset = context->next_preset;
+
+ if (context->cur_preset != REVERB_PRESET_NONE) {
+ const reverb_settings_t *preset = &reverb_presets[context->cur_preset];
+ reverb_set_room_level(context, preset->roomLevel);
+ reverb_set_room_hf_level(context, preset->roomHFLevel);
+ reverb_set_decay_time(context, preset->decayTime);
+ reverb_set_decay_hf_ratio(context, preset->decayHFRatio);
+ reverb_set_reverb_level(context, preset->reverbLevel);
+ reverb_set_diffusion(context, preset->diffusion);
+ reverb_set_density(context, preset->density);
+ }
+}
+
+int reverb_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ void *value = p->data + voffset;
+ reverb_settings_t *reverb_settings;
+ int i;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ if (reverb_ctxt->preset) {
+ if (param != REVERB_PARAM_PRESET || p->vsize < sizeof(uint16_t))
+ return -EINVAL;
+ *(uint16_t *)value = reverb_ctxt->next_preset;
+ ALOGV("get REVERB_PARAM_PRESET, preset %d", reverb_ctxt->next_preset);
+ return 0;
+ }
+ switch (param) {
+ case REVERB_PARAM_ROOM_LEVEL:
+ if (p->vsize < sizeof(uint16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint16_t);
+ break;
+ case REVERB_PARAM_ROOM_HF_LEVEL:
+ if (p->vsize < sizeof(uint16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint16_t);
+ break;
+ case REVERB_PARAM_DECAY_TIME:
+ if (p->vsize < sizeof(uint32_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint32_t);
+ break;
+ case REVERB_PARAM_DECAY_HF_RATIO:
+ if (p->vsize < sizeof(uint16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint16_t);
+ break;
+ case REVERB_PARAM_REFLECTIONS_LEVEL:
+ if (p->vsize < sizeof(uint16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint16_t);
+ break;
+ case REVERB_PARAM_REFLECTIONS_DELAY:
+ if (p->vsize < sizeof(uint32_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint32_t);
+ break;
+ case REVERB_PARAM_REVERB_LEVEL:
+ if (p->vsize < sizeof(uint16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint16_t);
+ break;
+ case REVERB_PARAM_REVERB_DELAY:
+ if (p->vsize < sizeof(uint32_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint32_t);
+ break;
+ case REVERB_PARAM_DIFFUSION:
+ if (p->vsize < sizeof(uint16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint16_t);
+ break;
+ case REVERB_PARAM_DENSITY:
+ if (p->vsize < sizeof(uint16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint16_t);
+ break;
+ case REVERB_PARAM_PROPERTIES:
+ if (p->vsize < sizeof(reverb_settings_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(reverb_settings_t);
+ break;
+ default:
+ p->status = -EINVAL;
+ }
+
+ *size = sizeof(effect_param_t) + voffset + p->vsize;
+
+ if (p->status != 0)
+ return 0;
+
+ switch (param) {
+ case REVERB_PARAM_PROPERTIES:
+ ALOGV("%s: REVERB_PARAM_PROPERTIES", __func__);
+ reverb_settings = (reverb_settings_t *)value;
+ reverb_settings->roomLevel = reverb_get_room_level(reverb_ctxt);
+ reverb_settings->roomHFLevel = reverb_get_room_hf_level(reverb_ctxt);
+ reverb_settings->decayTime = reverb_get_decay_time(reverb_ctxt);
+ reverb_settings->decayHFRatio = reverb_get_decay_hf_ratio(reverb_ctxt);
+ reverb_settings->reflectionsLevel = 0;
+ reverb_settings->reflectionsDelay = 0;
+ reverb_settings->reverbDelay = 0;
+ reverb_settings->reverbLevel = reverb_get_reverb_level(reverb_ctxt);
+ reverb_settings->diffusion = reverb_get_diffusion(reverb_ctxt);
+ reverb_settings->density = reverb_get_density(reverb_ctxt);
+ break;
+ case REVERB_PARAM_ROOM_LEVEL:
+ ALOGV("%s: REVERB_PARAM_ROOM_LEVEL", __func__);
+ *(int16_t *)value = reverb_get_room_level(reverb_ctxt);
+ break;
+ case REVERB_PARAM_ROOM_HF_LEVEL:
+ ALOGV("%s: REVERB_PARAM_ROOM_HF_LEVEL", __func__);
+ *(int16_t *)value = reverb_get_room_hf_level(reverb_ctxt);
+ break;
+ case REVERB_PARAM_DECAY_TIME:
+ ALOGV("%s: REVERB_PARAM_DECAY_TIME", __func__);
+ *(uint32_t *)value = reverb_get_decay_time(reverb_ctxt);
+ break;
+ case REVERB_PARAM_DECAY_HF_RATIO:
+ ALOGV("%s: REVERB_PARAM_DECAY_HF_RATIO", __func__);
+ *(int16_t *)value = reverb_get_decay_hf_ratio(reverb_ctxt);
+ break;
+ case REVERB_PARAM_REVERB_LEVEL:
+ ALOGV("%s: REVERB_PARAM_REVERB_LEVEL", __func__);
+ *(int16_t *)value = reverb_get_reverb_level(reverb_ctxt);
+ break;
+ case REVERB_PARAM_DIFFUSION:
+ ALOGV("%s: REVERB_PARAM_DIFFUSION", __func__);
+ *(int16_t *)value = reverb_get_diffusion(reverb_ctxt);
+ break;
+ case REVERB_PARAM_DENSITY:
+ ALOGV("%s: REVERB_PARAM_DENSITY", __func__);
+ *(int16_t *)value = reverb_get_density(reverb_ctxt);
+ break;
+ case REVERB_PARAM_REFLECTIONS_LEVEL:
+ ALOGV("%s: REVERB_PARAM_REFLECTIONS_LEVEL", __func__);
+ *(uint16_t *)value = 0;
+ break;
+ case REVERB_PARAM_REFLECTIONS_DELAY:
+ ALOGV("%s: REVERB_PARAM_REFLECTIONS_DELAY", __func__);
+ *(uint32_t *)value = 0;
+ break;
+ case REVERB_PARAM_REVERB_DELAY:
+ ALOGV("%s: REVERB_PARAM_REVERB_DELAY", __func__);
+ *(uint32_t *)value = 0;
+ break;
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int reverb_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size __unused)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ void *value = p->data + voffset;
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ reverb_settings_t *reverb_settings;
+ int16_t level;
+ int16_t ratio;
+ uint32_t time;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ if (reverb_ctxt->preset) {
+ if (param != REVERB_PARAM_PRESET)
+ return -EINVAL;
+ uint16_t preset = *(uint16_t *)value;
+ ALOGV("set REVERB_PARAM_PRESET, preset %d", preset);
+ if (preset > REVERB_PRESET_LAST) {
+ return -EINVAL;
+ }
+ reverb_set_preset(reverb_ctxt, preset);
+ return 0;
+ }
+ switch (param) {
+ case REVERB_PARAM_PROPERTIES:
+ ALOGV("%s: REVERB_PARAM_PROPERTIES", __func__);
+ reverb_settings = (reverb_settings_t *)value;
+ break;
+ case REVERB_PARAM_ROOM_LEVEL:
+ ALOGV("%s: REVERB_PARAM_ROOM_LEVEL", __func__);
+ level = *(int16_t *)value;
+ reverb_set_room_level(reverb_ctxt, level);
+ break;
+ case REVERB_PARAM_ROOM_HF_LEVEL:
+ ALOGV("%s: REVERB_PARAM_ROOM_HF_LEVEL", __func__);
+ level = *(int16_t *)value;
+ reverb_set_room_hf_level(reverb_ctxt, level);
+ break;
+ case REVERB_PARAM_DECAY_TIME:
+ ALOGV("%s: REVERB_PARAM_DECAY_TIME", __func__);
+ time = *(uint32_t *)value;
+ reverb_set_decay_time(reverb_ctxt, time);
+ break;
+ case REVERB_PARAM_DECAY_HF_RATIO:
+ ALOGV("%s: REVERB_PARAM_DECAY_HF_RATIO", __func__);
+ ratio = *(int16_t *)value;
+ reverb_set_decay_hf_ratio(reverb_ctxt, ratio);
+ break;
+ case REVERB_PARAM_REVERB_LEVEL:
+ ALOGV("%s: REVERB_PARAM_REVERB_LEVEL", __func__);
+ level = *(int16_t *)value;
+ reverb_set_reverb_level(reverb_ctxt, level);
+ break;
+ case REVERB_PARAM_DIFFUSION:
+ ALOGV("%s: REVERB_PARAM_DIFFUSION", __func__);
+ ratio = *(int16_t *)value;
+ reverb_set_diffusion(reverb_ctxt, ratio);
+ break;
+ case REVERB_PARAM_DENSITY:
+ ALOGV("%s: REVERB_PARAM_DENSITY", __func__);
+ ratio = *(int16_t *)value;
+ reverb_set_density(reverb_ctxt, ratio);
+ break;
+ case REVERB_PARAM_REFLECTIONS_LEVEL:
+ case REVERB_PARAM_REFLECTIONS_DELAY:
+ case REVERB_PARAM_REVERB_DELAY:
+ break;
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int reverb_set_device(effect_context_t *context, uint32_t device)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+ ALOGV("%s: device: %d", __func__, device);
+ reverb_ctxt->device = device;
+ offload_reverb_set_device(&(reverb_ctxt->offload_reverb), device);
+ return 0;
+}
+
+int reverb_reset(effect_context_t *context)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+ return 0;
+}
+
+int reverb_init(effect_context_t *context)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+ context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+ /*
+ FIXME: channel mode is mono for auxiliary. is it needed for offload ?
+ If so, this set config needs to be updated accordingly
+ */
+ context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.inputCfg.samplingRate = 44100;
+ context->config.inputCfg.bufferProvider.getBuffer = NULL;
+ context->config.inputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.inputCfg.bufferProvider.cookie = NULL;
+ context->config.inputCfg.mask = EFFECT_CONFIG_ALL;
+ context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+ context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.outputCfg.samplingRate = 44100;
+ context->config.outputCfg.bufferProvider.getBuffer = NULL;
+ context->config.outputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.outputCfg.bufferProvider.cookie = NULL;
+ context->config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+ set_config(context, &context->config);
+
+ memset(&(reverb_ctxt->reverb_settings), 0, sizeof(reverb_settings_t));
+ memset(&(reverb_ctxt->offload_reverb), 0, sizeof(struct reverb_params));
+
+ if (reverb_ctxt->preset &&
+ reverb_ctxt->next_preset != reverb_ctxt->cur_preset)
+ reverb_load_preset(reverb_ctxt);
+
+ return 0;
+}
+
+int reverb_enable(effect_context_t *context)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+ ALOGV("%s", __func__);
+
+ if (!offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb)))
+ offload_reverb_set_enable_flag(&(reverb_ctxt->offload_reverb), true);
+ return 0;
+}
+
+int reverb_disable(effect_context_t *context)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+ ALOGV("%s", __func__);
+ if (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))) {
+ offload_reverb_set_enable_flag(&(reverb_ctxt->offload_reverb), false);
+ if (reverb_ctxt->ctl)
+ offload_reverb_send_params(reverb_ctxt->ctl,
+ &reverb_ctxt->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG);
+ }
+ return 0;
+}
+
+int reverb_start(effect_context_t *context, output_context_t *output)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+ ALOGV("%s", __func__);
+ reverb_ctxt->ctl = output->ctl;
+ if (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))) {
+ if (reverb_ctxt->ctl && reverb_ctxt->preset) {
+ offload_reverb_send_params(reverb_ctxt->ctl, &reverb_ctxt->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_PRESET);
+ }
+ }
+
+ return 0;
+}
+
+int reverb_stop(effect_context_t *context, output_context_t *output __unused)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+ ALOGV("%s", __func__);
+ reverb_ctxt->ctl = NULL;
+ return 0;
+}
+
diff --git a/post_proc/reverb.h b/post_proc/reverb.h
new file mode 100644
index 0000000..aba2b27
--- /dev/null
+++ b/post_proc/reverb.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef OFFLOAD_REVERB_H_
+#define OFFLOAD_REVERB_H_
+
+#include "bundle.h"
+
+#define REVERB_DEFAULT_PRESET REVERB_PRESET_NONE
+
+extern const effect_descriptor_t aux_env_reverb_descriptor;
+extern const effect_descriptor_t ins_env_reverb_descriptor;
+extern const effect_descriptor_t aux_preset_reverb_descriptor;
+extern const effect_descriptor_t ins_preset_reverb_descriptor;
+
+typedef struct reverb_settings_s {
+ int16_t roomLevel;
+ int16_t roomHFLevel;
+ uint32_t decayTime;
+ int16_t decayHFRatio;
+ int16_t reflectionsLevel;
+ uint32_t reflectionsDelay;
+ int16_t reverbLevel;
+ uint32_t reverbDelay;
+ int16_t diffusion;
+ int16_t density;
+} reverb_settings_t;
+
+typedef struct reverb_context_s {
+ effect_context_t common;
+
+ // Offload vars
+ struct mixer_ctl *ctl;
+ bool auxiliary;
+ bool preset;
+ uint16_t cur_preset;
+ uint16_t next_preset;
+ reverb_settings_t reverb_settings;
+ uint32_t device;
+ struct reverb_params offload_reverb;
+} reverb_context_t;
+
+
+void reverb_auxiliary_init(reverb_context_t *context);
+
+void reverb_preset_init(reverb_context_t *context);
+
+void reverb_insert_init(reverb_context_t *context);
+
+int reverb_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size);
+
+int reverb_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size);
+
+int reverb_set_device(effect_context_t *context, uint32_t device);
+
+int reverb_reset(effect_context_t *context);
+
+int reverb_init(effect_context_t *context);
+
+int reverb_enable(effect_context_t *context);
+
+int reverb_disable(effect_context_t *context);
+
+int reverb_start(effect_context_t *context, output_context_t *output);
+
+int reverb_stop(effect_context_t *context, output_context_t *output);
+
+#endif /* OFFLOAD_REVERB_H_ */
diff --git a/post_proc/virtualizer.c b/post_proc/virtualizer.c
new file mode 100644
index 0000000..40bbf38
--- /dev/null
+++ b/post_proc/virtualizer.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2014 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 "offload_effect_virtualizer"
+//#define LOG_NDEBUG 0
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <sound/audio_effects.h>
+#include <audio_effects/effect_virtualizer.h>
+
+#include "effect_api.h"
+#include "virtualizer.h"
+
+/* Offload Virtualizer UUID: 509a4498-561a-4bea-b3b1-0002a5d5c51b */
+const effect_descriptor_t virtualizer_descriptor = {
+ {0x37cc2c00, 0xdddd, 0x11db, 0x8577, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ {0x509a4498, 0x561a, 0x4bea, 0xb3b1, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_HW_ACC_TUNNEL),
+ 0, /* TODO */
+ 1,
+ "MSM offload virtualizer",
+ "The Android Open Source Project",
+};
+
+/*
+ * Virtualizer operations
+ */
+
+int virtualizer_get_strength(virtualizer_context_t *context)
+{
+ ALOGV("%s: strength: %d", __func__, context->strength);
+ return context->strength;
+}
+
+int virtualizer_set_strength(virtualizer_context_t *context, uint32_t strength)
+{
+ ALOGV("%s: strength: %d", __func__, strength);
+ context->strength = strength;
+
+ offload_virtualizer_set_strength(&(context->offload_virt), strength);
+ if (context->ctl)
+ offload_virtualizer_send_params(context->ctl, &context->offload_virt,
+ OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
+ OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
+ return 0;
+}
+
+int virtualizer_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ void *value = p->data + voffset;
+ int i;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED:
+ if (p->vsize < sizeof(uint32_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint32_t);
+ break;
+ case VIRTUALIZER_PARAM_STRENGTH:
+ if (p->vsize < sizeof(int16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(int16_t);
+ break;
+ default:
+ p->status = -EINVAL;
+ }
+
+ *size = sizeof(effect_param_t) + voffset + p->vsize;
+
+ if (p->status != 0)
+ return 0;
+
+ switch (param) {
+ case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED:
+ ALOGV("%s: VIRTUALIZER_PARAM_STRENGTH_SUPPORTED", __func__);
+ *(uint32_t *)value = 1;
+ break;
+
+ case VIRTUALIZER_PARAM_STRENGTH:
+ ALOGV("%s: VIRTUALIZER_PARAM_STRENGTH", __func__);
+ *(int16_t *)value = virtualizer_get_strength(virt_ctxt);
+ break;
+
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int virtualizer_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size __unused)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ void *value = p->data + voffset;
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ uint32_t strength;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case VIRTUALIZER_PARAM_STRENGTH:
+ ALOGV("%s VIRTUALIZER_PARAM_STRENGTH", __func__);
+ strength = (uint32_t)(*(int16_t *)value);
+ virtualizer_set_strength(virt_ctxt, strength);
+ break;
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int virtualizer_set_device(effect_context_t *context, uint32_t device)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+ ALOGV("%s: device: %d", __func__, device);
+ virt_ctxt->device = device;
+ if ((device == AUDIO_DEVICE_OUT_SPEAKER) ||
+ (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) ||
+ (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) ||
+ (device == AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
+ (device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET)) {
+ if (!virt_ctxt->temp_disabled) {
+ if (effect_is_active(&virt_ctxt->common)) {
+ offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
+ if (virt_ctxt->ctl)
+ offload_virtualizer_send_params(virt_ctxt->ctl,
+ &virt_ctxt->offload_virt,
+ OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+ }
+ virt_ctxt->temp_disabled = true;
+ }
+ } else {
+ if (virt_ctxt->temp_disabled) {
+ if (effect_is_active(&virt_ctxt->common)) {
+ offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
+ if (virt_ctxt->ctl)
+ offload_virtualizer_send_params(virt_ctxt->ctl,
+ &virt_ctxt->offload_virt,
+ OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+ }
+ virt_ctxt->temp_disabled = false;
+ }
+ }
+ offload_virtualizer_set_device(&(virt_ctxt->offload_virt), device);
+ return 0;
+}
+
+int virtualizer_reset(effect_context_t *context)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+ return 0;
+}
+
+int virtualizer_init(effect_context_t *context)
+{
+ ALOGV("%s", __func__);
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+ context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+ context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.inputCfg.samplingRate = 44100;
+ context->config.inputCfg.bufferProvider.getBuffer = NULL;
+ context->config.inputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.inputCfg.bufferProvider.cookie = NULL;
+ context->config.inputCfg.mask = EFFECT_CONFIG_ALL;
+ context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+ context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.outputCfg.samplingRate = 44100;
+ context->config.outputCfg.bufferProvider.getBuffer = NULL;
+ context->config.outputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.outputCfg.bufferProvider.cookie = NULL;
+ context->config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+ set_config(context, &context->config);
+
+ virt_ctxt->temp_disabled = false;
+ memset(&(virt_ctxt->offload_virt), 0, sizeof(struct virtualizer_params));
+
+ return 0;
+}
+
+int virtualizer_enable(effect_context_t *context)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+ ALOGV("%s", __func__);
+
+ if (!offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)) &&
+ !(virt_ctxt->temp_disabled)) {
+ offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
+ if (virt_ctxt->ctl && virt_ctxt->strength)
+ offload_virtualizer_send_params(virt_ctxt->ctl,
+ &virt_ctxt->offload_virt,
+ OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
+ OFFLOAD_SEND_BASSBOOST_STRENGTH);
+ }
+ return 0;
+}
+
+int virtualizer_disable(effect_context_t *context)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+ ALOGV("%s", __func__);
+ if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) {
+ offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
+ if (virt_ctxt->ctl)
+ offload_virtualizer_send_params(virt_ctxt->ctl,
+ &virt_ctxt->offload_virt,
+ OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+ }
+ return 0;
+}
+
+int virtualizer_start(effect_context_t *context, output_context_t *output)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+ ALOGV("%s", __func__);
+ virt_ctxt->ctl = output->ctl;
+ if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)))
+ if (virt_ctxt->ctl)
+ offload_virtualizer_send_params(virt_ctxt->ctl, &virt_ctxt->offload_virt,
+ OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
+ OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
+ return 0;
+}
+
+int virtualizer_stop(effect_context_t *context, output_context_t *output __unused)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+ ALOGV("%s", __func__);
+ virt_ctxt->ctl = NULL;
+ return 0;
+}
diff --git a/post_proc/virtualizer.h b/post_proc/virtualizer.h
new file mode 100644
index 0000000..978dc86
--- /dev/null
+++ b/post_proc/virtualizer.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef OFFLOAD_VIRTUALIZER_H_
+#define OFFLOAD_VIRTUALIZER_H_
+
+#include "bundle.h"
+
+extern const effect_descriptor_t virtualizer_descriptor;
+
+typedef struct virtualizer_context_s {
+ effect_context_t common;
+
+ int strength;
+
+ // Offload vars
+ struct mixer_ctl *ctl;
+ bool temp_disabled;
+ uint32_t device;
+ struct virtualizer_params offload_virt;
+} virtualizer_context_t;
+
+int virtualizer_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size);
+
+int virtualizer_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size);
+
+int virtualizer_set_device(effect_context_t *context, uint32_t device);
+
+int virtualizer_reset(effect_context_t *context);
+
+int virtualizer_init(effect_context_t *context);
+
+int virtualizer_enable(effect_context_t *context);
+
+int virtualizer_disable(effect_context_t *context);
+
+int virtualizer_start(effect_context_t *context, output_context_t *output);
+
+int virtualizer_stop(effect_context_t *context, output_context_t *output);
+
+#endif /* OFFLOAD_VIRTUALIZER_H_ */
diff --git a/visualizer/offload_visualizer.c b/visualizer/offload_visualizer.c
index 2f2bb14..9b11e20 100644
--- a/visualizer/offload_visualizer.c
+++ b/visualizer/offload_visualizer.c
@@ -37,6 +37,7 @@
};
typedef struct effect_context_s effect_context_t;
+typedef struct output_context_s output_context_t;
/* effect specific operations. Only the init() and process() operations must be defined.
* Others are optional.
@@ -47,6 +48,8 @@
int (*reset)(effect_context_t *context);
int (*enable)(effect_context_t *context);
int (*disable)(effect_context_t *context);
+ int (*start)(effect_context_t *context, output_context_t *output);
+ int (*stop)(effect_context_t *context, output_context_t *output);
int (*process)(effect_context_t *context, audio_buffer_t *in, audio_buffer_t *out);
int (*set_parameter)(effect_context_t *context, effect_param_t *param, uint32_t size);
int (*get_parameter)(effect_context_t *context, effect_param_t *param, uint32_t *size);
@@ -247,6 +250,8 @@
return;
}
list_add_tail(&output->effects_list, &context->output_node);
+ if (context->ops.start)
+ context->ops.start(context, output);
}
void remove_effect_from_output(output_context_t * output, effect_context_t *context) {
@@ -257,6 +262,8 @@
effect_context_t,
output_node);
if (fx_ctxt == context) {
+ if (context->ops.stop)
+ context->ops.stop(context, output);
list_remove(&context->output_node);
return;
}
@@ -276,7 +283,7 @@
effect_context_t *fx_ctxt = node_to_item(fx_node,
effect_context_t,
output_node);
- if (fx_ctxt->state == EFFECT_STATE_ACTIVE)
+ if (fx_ctxt->state == EFFECT_STATE_ACTIVE && fx_ctxt->ops.process != NULL)
return true;
}
}
@@ -299,7 +306,7 @@
}
-void *capture_thread_loop(void *arg)
+void *capture_thread_loop(void *arg __unused)
{
int16_t data[AUDIO_CAPTURE_PERIOD_SIZE * AUDIO_CAPTURE_CHANNEL_COUNT * sizeof(int16_t)];
audio_buffer_t buf;
@@ -379,7 +386,8 @@
effect_context_t *fx_ctxt = node_to_item(fx_node,
effect_context_t,
output_node);
- fx_ctxt->ops.process(fx_ctxt, &buf, &buf);
+ if (fx_ctxt->ops.process != NULL)
+ fx_ctxt->ops.process(fx_ctxt, &buf, &buf);
}
}
} else {
@@ -405,11 +413,11 @@
*/
__attribute__ ((visibility ("default")))
-int visualizer_hal_start_output(audio_io_handle_t output) {
+int visualizer_hal_start_output(audio_io_handle_t output, int pcm_id) {
int ret;
struct listnode *node;
- ALOGV("%s", __func__);
+ ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
if (lib_init() != 0)
return init_status;
@@ -431,6 +439,8 @@
effect_context_t,
effects_list_node);
if (fx_ctxt->out_handle == output) {
+ if (fx_ctxt->ops.start)
+ fx_ctxt->ops.start(fx_ctxt, out_ctxt);
list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node);
}
}
@@ -449,12 +459,13 @@
}
__attribute__ ((visibility ("default")))
-int visualizer_hal_stop_output(audio_io_handle_t output) {
+int visualizer_hal_stop_output(audio_io_handle_t output, int pcm_id) {
int ret;
struct listnode *node;
+ struct listnode *fx_node;
output_context_t *out_ctxt;
- ALOGV("%s", __func__);
+ ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
if (lib_init() != 0)
return init_status;
@@ -468,7 +479,13 @@
ret = -ENOSYS;
goto exit;
}
-
+ list_for_each(fx_node, &out_ctxt->effects_list) {
+ effect_context_t *fx_ctxt = node_to_item(fx_node,
+ effect_context_t,
+ output_node);
+ if (fx_ctxt->ops.stop)
+ fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
+ }
list_remove(&out_ctxt->outputs_list_node);
pthread_cond_signal(&cond);
@@ -580,7 +597,7 @@
visu_ctxt->scaling_mode = VISUALIZER_SCALING_MODE_NORMALIZED;
// measurement initialization
- visu_ctxt->channel_count = popcount(context->config.inputCfg.channels);
+ visu_ctxt->channel_count = audio_channel_count_from_out_mask(context->config.inputCfg.channels);
visu_ctxt->meas_mode = MEASUREMENT_MODE_NONE;
visu_ctxt->meas_wndw_size_in_buffers = MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS;
visu_ctxt->meas_buffer_idx = 0;
@@ -630,7 +647,7 @@
return 0;
}
-int visualizer_set_parameter(effect_context_t *context, effect_param_t *p, uint32_t size)
+int visualizer_set_parameter(effect_context_t *context, effect_param_t *p, uint32_t size __unused)
{
visualizer_context_t *visu_ctxt = (visualizer_context_t *)context;
@@ -763,8 +780,8 @@
return 0;
}
-int visualizer_command(effect_context_t * context, uint32_t cmdCode, uint32_t cmdSize,
- void *pCmdData, uint32_t *replySize, void *pReplyData)
+int visualizer_command(effect_context_t * context, uint32_t cmdCode, uint32_t cmdSize __unused,
+ void *pCmdData __unused, uint32_t *replySize, void *pReplyData)
{
visualizer_context_t * visu_ctxt = (visualizer_context_t *)context;
@@ -886,7 +903,7 @@
*/
int effect_lib_create(const effect_uuid_t *uuid,
- int32_t sessionId,
+ int32_t sessionId __unused,
int32_t ioId,
effect_handle_t *pHandle) {
int ret;
@@ -917,6 +934,7 @@
context->ops.set_parameter = visualizer_set_parameter;
context->ops.get_parameter = visualizer_get_parameter;
context->ops.command = visualizer_command;
+ context->desc = &visualizer_descriptor;
} else {
return -EINVAL;
}
@@ -924,7 +942,6 @@
context->itfe = &effect_interface;
context->state = EFFECT_STATE_UNINITIALIZED;
context->out_handle = (audio_io_handle_t)ioId;
- context->desc = &visualizer_descriptor;
ret = context->ops.init(context);
if (ret < 0) {
@@ -1003,8 +1020,8 @@
/* Stub function for effect interface: never called for offloaded effects */
int effect_process(effect_handle_t self,
- audio_buffer_t *inBuffer,
- audio_buffer_t *outBuffer)
+ audio_buffer_t *inBuffer __unused,
+ audio_buffer_t *outBuffer __unused)
{
effect_context_t * context = (effect_context_t *)self;
int status = 0;
@@ -1177,12 +1194,12 @@
out_ctxt = get_output(context->out_handle);
if (out_ctxt != NULL)
remove_effect_from_output(out_ctxt, context);
+
+ context->out_handle = offload_param->ioHandle;
out_ctxt = get_output(offload_param->ioHandle);
if (out_ctxt != NULL)
add_effect_to_output(out_ctxt, context);
- context->out_handle = offload_param->ioHandle;
-
} break;
diff --git a/voice_processing/voice_processing.c b/voice_processing/voice_processing.c
index e556333..08acdb4 100644
--- a/voice_processing/voice_processing.c
+++ b/voice_processing/voice_processing.c
@@ -559,9 +559,7 @@
if (pCmdData == NULL ||
cmdSize < (int)sizeof(effect_param_t) ||
pReplyData == NULL ||
- *replySize < (int)sizeof(effect_param_t) ||
- // constrain memcpy below
- ((effect_param_t *)pCmdData)->psize > *replySize - sizeof(effect_param_t)) {
+ *replySize < (int)sizeof(effect_param_t)) {
ALOGV("fx_command() EFFECT_CMD_GET_PARAM invalid args");
return -EINVAL;
}