msm8660: Import audio HAL
Change-Id: I81ca52d392e5bba337f4a3a1288f716ba265ffe1
diff --git a/Android.mk b/Android.mk
index 7a0a25a..021396d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,4 +1,4 @@
-ifneq ($(filter msm8960 msm7x30,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8960 msm8660 msm7x30,$(TARGET_BOARD_PLATFORM)),)
ifeq ($(TARGET_QCOM_AUDIO_VARIANT),caf)
AUDIO_HW_ROOT := $(call my-dir)
@@ -13,6 +13,9 @@
ifeq ($(TARGET_BOARD_PLATFORM),msm7x30)
include $(AUDIO_HW_ROOT)/msm7x30/Android.mk
endif
-
+ifeq ($(TARGET_BOARD_PLATFORM),msm8660)
+ include $(AUDIO_HW_ROOT)/msm8660/Android.mk
+ include $(AUDIO_HW_ROOT)/mm-audio/Android.mk
+endif
endif
endif
diff --git a/msm8660/Android.mk b/msm8660/Android.mk
new file mode 100644
index 0000000..1d1ec09
--- /dev/null
+++ b/msm8660/Android.mk
@@ -0,0 +1,127 @@
+#AUDIO_POLICY_TEST := true
+#ENABLE_AUDIO_DUMP := true
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS := -D_POSIX_SOURCE
+
+LOCAL_SRC_FILES := \
+ AudioHardware.cpp \
+ audio_hw_hal.cpp
+
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+ LOCAL_CFLAGS += -DWITH_A2DP
+endif
+
+ifeq ($(BOARD_HAVE_QCOM_FM),true)
+ LOCAL_CFLAGS += -DQCOM_FM_ENABLED
+endif
+
+ifeq ($(BOARD_USE_QCOM_LPA),true)
+ LOCAL_CFLAGS += -DQCOM_TUNNEL_LPA_ENABLED
+endif
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libmedia \
+ libaudioalsa \
+ libacdbloader \
+ libacdbmapper
+
+# hack for prebuilt
+$(shell mkdir -p $(OUT)/obj/SHARED_LIBRARIES/libaudioalsa_intermediates/)
+$(shell touch $(OUT)/obj/SHARED_LIBRARIES/libaudioalsa_intermediates/export_includes)
+$(shell mkdir -p $(OUT)/obj/SHARED_LIBRARIES/libacdbloader_intermediates/)
+$(shell touch $(OUT)/obj/SHARED_LIBRARIES/libacdbloader_intermediates/export_includes)
+$(shell mkdir -p $(OUT)/obj/SHARED_LIBRARIES/libacdbmapper_intermediates/)
+$(shell touch $(OUT)/obj/SHARED_LIBRARIES/libacdbmapper_intermediates/export_includes)
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_STATIC_LIBRARIES := \
+ libmedia_helper \
+ libaudiohw_legacy \
+ libaudiopolicy_legacy \
+
+LOCAL_MODULE := audio.primary.msm8660
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS += -fno-short-enums
+
+LOCAL_C_INCLUDES := $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audcal
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-acdb-util
+LOCAL_C_INCLUDES += hardware/libhardware/include
+LOCAL_C_INCLUDES += hardware/libhardware_legacy/include
+LOCAL_C_INCLUDES += frameworks/base/include
+LOCAL_C_INCLUDES += system/core/include
+
+ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
+LOCAL_CFLAGS += -DQCOM_ACDB_ENABLED
+endif
+
+ifeq ($(BOARD_HAVE_SAMSUNG_AUDIO),true)
+LOCAL_CFLAGS += -DSAMSUNG_AUDIO
+endif
+
+ifeq ($(BOARD_HAVE_SONY_AUDIO),true)
+LOCAL_CFLAGS += -DSONY_AUDIO
+endif
+
+ifeq ($(BOARD_HAVE_BACK_MIC_CAMCORDER),true)
+LOCAL_CFLAGS += -DBACK_MIC_CAMCORDER
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+# The audio policy is implemented on top of legacy policy code
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ AudioPolicyManager.cpp \
+ audio_policy_hal.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libmedia
+
+LOCAL_STATIC_LIBRARIES := \
+ libaudiohw_legacy \
+ libmedia_helper \
+ libaudiopolicy_legacy
+
+LOCAL_MODULE := audio_policy.msm8660
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_TAGS := optional
+
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+ LOCAL_CFLAGS += -DWITH_A2DP
+endif
+
+LOCAL_C_INCLUDES += hardware/libhardware_legacy/audio
+
+ifeq ($(BOARD_HAVE_SAMSUNG_AUDIO),true)
+LOCAL_CFLAGS += -DSAMSUNG_AUDIO
+endif
+
+ifeq ($(BOARD_HAVE_BACK_MIC_CAMCORDER),true)
+LOCAL_CFLAGS += -DBACK_MIC_CAMCORDER
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Load audio_policy.conf to system/etc/
+include $(CLEAR_VARS)
+LOCAL_MODULE := audio_policy.conf
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/
+LOCAL_SRC_FILES := audio_policy.conf
+include $(BUILD_PREBUILT)
diff --git a/msm8660/AudioHardware.cpp b/msm8660/AudioHardware.cpp
new file mode 100644
index 0000000..4eb6d71
--- /dev/null
+++ b/msm8660/AudioHardware.cpp
@@ -0,0 +1,5311 @@
+/*
+** Copyright 2008, The Android Open-Source Project
+** Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+**
+** 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.
+*/
+
+#include <math.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AudioHardwareMSM8660"
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include "AudioHardware.h"
+#include <media/AudioSystem.h>
+#include <cutils/properties.h>
+
+#include <linux/android_pmem.h>
+#ifdef QCOM_ACDB_ENABLED
+#include <linux/msm_audio_acdb.h>
+#endif
+#include <linux/msm_audio_mvs.h>
+#include <sys/mman.h>
+#include "control.h"
+#include "acdb.h"
+
+#ifdef HTC_ACOUSTIC_AUDIO
+ extern "C" {
+ #include <linux/spi_aic3254.h>
+ #include <linux/tpa2051d3.h>
+ }
+ #define DSP_EFFECT_KEY "dolby_srs_eq"
+#endif
+
+#define VOICE_SESSION_NAME "Voice session"
+#define VOIP_SESSION_NAME "VoIP session"
+
+// hardware specific functions
+
+#define LOG_SND_RPC 0 // Set to 1 to log sound RPC's
+
+#define DUALMIC_KEY "dualmic_enabled"
+#define BTHEADSET_VGS "bt_headset_vgs"
+#define ANC_KEY "anc_enabled"
+#define TTY_MODE_KEY "tty_mode"
+#define ECHO_SUPRESSION "ec_supported"
+
+
+#define MVS_DEVICE "/dev/msm_mvs"
+
+#ifdef QCOM_FM_ENABLED
+#define FM_DEVICE "/dev/msm_fm"
+#define FM_A2DP_REC 1
+#define FM_FILE_REC 2
+#endif
+
+#ifdef QCOM_ACDB_ENABLED
+#define INVALID_ACDB_ID -1
+#endif
+
+namespace android_audio_legacy {
+
+Mutex mDeviceSwitchLock;
+#ifdef HTC_ACOUSTIC_AUDIO
+Mutex mAIC3254ConfigLock;
+#endif
+static int audpre_index, tx_iir_index;
+static void * acoustic;
+const uint32_t AudioHardware::inputSamplingRates[] = {
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+static const uint32_t INVALID_DEVICE = 65535;
+static const uint32_t SND_DEVICE_CURRENT = -1;
+static const uint32_t SND_DEVICE_HANDSET = 0;
+static const uint32_t SND_DEVICE_SPEAKER = 1;
+static const uint32_t SND_DEVICE_HEADSET = 2;
+static const uint32_t SND_DEVICE_FM_HANDSET = 3;
+static const uint32_t SND_DEVICE_FM_SPEAKER = 4;
+static const uint32_t SND_DEVICE_FM_HEADSET = 5;
+static const uint32_t SND_DEVICE_BT = 6;
+static const uint32_t SND_DEVICE_HEADSET_AND_SPEAKER = 7;
+static const uint32_t SND_DEVICE_NO_MIC_HEADSET = 8;
+static const uint32_t SND_DEVICE_IN_S_SADC_OUT_HANDSET = 9;
+static const uint32_t SND_DEVICE_IN_S_SADC_OUT_SPEAKER_PHONE= 10;
+static const uint32_t SND_DEVICE_TTY_HEADSET = 11;
+static const uint32_t SND_DEVICE_TTY_HCO = 12;
+static const uint32_t SND_DEVICE_TTY_VCO = 13;
+static const uint32_t SND_DEVICE_TTY_FULL = 14;
+static const uint32_t SND_DEVICE_HDMI = 15;
+static const uint32_t SND_DEVICE_CARKIT = -1;
+static const uint32_t SND_DEVICE_ANC_HEADSET = 16;
+static const uint32_t SND_DEVICE_NO_MIC_ANC_HEADSET = 17;
+static const uint32_t SND_DEVICE_HEADPHONE_AND_SPEAKER = 18;
+static const uint32_t SND_DEVICE_FM_TX = 19;
+static const uint32_t SND_DEVICE_FM_TX_AND_SPEAKER = 20;
+static const uint32_t SND_DEVICE_SPEAKER_TX = 21;
+static const uint32_t SND_DEVICE_BACK_MIC_CAMCORDER = 33;
+#ifdef HTC_ACOUSTIC_AUDIO
+static const uint32_t SND_DEVICE_SPEAKER_BACK_MIC = 26;
+static const uint32_t SND_DEVICE_HANDSET_BACK_MIC = 27;
+static const uint32_t SND_DEVICE_NO_MIC_HEADSET_BACK_MIC = 28;
+static const uint32_t SND_DEVICE_HEADSET_AND_SPEAKER_BACK_MIC = 30;
+static const uint32_t SND_DEVICE_I2S_SPEAKER = 32;
+static const uint32_t SND_DEVICE_BT_EC_OFF = 45;
+static const uint32_t SND_DEVICE_HAC = 252;
+static const uint32_t SND_DEVICE_USB_HEADSET = 253;
+#else
+static const uint32_t SND_DEVICE_BT_EC_OFF = -1;
+#endif
+#ifdef SAMSUNG_AUDIO
+static uint32_t SND_DEVICE_VOIP_HANDSET = 50;
+static uint32_t SND_DEVICE_VOIP_SPEAKER = 51;
+static uint32_t SND_DEVICE_VOIP_HEADSET = 52;
+static uint32_t SND_DEVICE_CALL_HANDSET = 60;
+static uint32_t SND_DEVICE_CALL_SPEAKER = 61;
+static uint32_t SND_DEVICE_CALL_HEADSET = 62;
+static uint32_t SND_DEVICE_VR_SPEAKER = 70;
+static uint32_t SND_DEVICE_VR_HEADSET = 71;
+static uint32_t SND_DEVICE_HAC = 252;
+static uint32_t SND_DEVICE_USB_HEADSET = 253;
+#endif
+static const uint32_t DEVICE_HANDSET_RX = 0; // handset_rx
+static const uint32_t DEVICE_HANDSET_TX = 1;//handset_tx
+static const uint32_t DEVICE_SPEAKER_RX = 2; //speaker_stereo_rx
+static const uint32_t DEVICE_SPEAKER_TX = 3;//speaker_mono_tx
+static const uint32_t DEVICE_HEADSET_RX = 4; //headset_stereo_rx
+static const uint32_t DEVICE_HEADSET_TX = 5; //headset_mono_tx
+static const uint32_t DEVICE_FMRADIO_HANDSET_RX = 6; //fmradio_handset_rx
+static const uint32_t DEVICE_FMRADIO_HEADSET_RX = 7; //fmradio_headset_rx
+static const uint32_t DEVICE_FMRADIO_SPEAKER_RX = 8; //fmradio_speaker_rx
+static const uint32_t DEVICE_DUALMIC_HANDSET_TX = 9; //handset_dual_mic_endfire_tx
+static const uint32_t DEVICE_DUALMIC_SPEAKER_TX = 10; //speaker_dual_mic_endfire_tx
+static const uint32_t DEVICE_TTY_HEADSET_MONO_RX = 11; //tty_headset_mono_rx
+static const uint32_t DEVICE_TTY_HEADSET_MONO_TX = 12; //tty_headset_mono_tx
+static const uint32_t DEVICE_SPEAKER_HEADSET_RX = 13; //headset_stereo_speaker_stereo_rx
+static const uint32_t DEVICE_FMRADIO_STEREO_TX = 14;
+static const uint32_t DEVICE_HDMI_STERO_RX = 15; //hdmi_stereo_rx
+static const uint32_t DEVICE_ANC_HEADSET_STEREO_RX = 16; //ANC RX
+static const uint32_t DEVICE_BT_SCO_RX = 17; //bt_sco_rx
+static const uint32_t DEVICE_BT_SCO_TX = 18; //bt_sco_tx
+static const uint32_t DEVICE_FMRADIO_STEREO_RX = 19;
+#ifdef SAMSUNG_AUDIO
+// Samsung devices
+static uint32_t DEVICE_HANDSET_VOIP_RX = 40; // handset_voip_rx
+static uint32_t DEVICE_HANDSET_VOIP_TX = 41; // handset_voip_tx
+static uint32_t DEVICE_SPEAKER_VOIP_RX = 42; // speaker_voip_rx
+static uint32_t DEVICE_SPEAKER_VOIP_TX = 43; // speaker_voip_tx
+static uint32_t DEVICE_HEADSET_VOIP_RX = 44; // headset_voip_rx
+static uint32_t DEVICE_HEADSET_VOIP_TX = 45; // headset_voip_tx
+static uint32_t DEVICE_HANDSET_CALL_RX = 60; // handset_call_rx
+static uint32_t DEVICE_HANDSET_CALL_TX = 61; // handset_call_tx
+static uint32_t DEVICE_SPEAKER_CALL_RX = 62; // speaker_call_rx
+static uint32_t DEVICE_SPEAKER_CALL_TX = 63; // speaker_call_tx
+static uint32_t DEVICE_HEADSET_CALL_RX = 64; // headset_call_rx
+static uint32_t DEVICE_HEADSET_CALL_TX = 65; // headset_call_tx
+static uint32_t DEVICE_SPEAKER_VR_TX = 82; // speaker_vr_tx
+static uint32_t DEVICE_HEADSET_VR_TX = 83; // headset_vr_tx
+#endif
+static uint32_t DEVICE_CAMCORDER_TX = 105; // camcoder_tx (misspelled by Samsung)
+ // secondary_mic_tx (sony)
+
+static uint32_t FLUENCE_MODE_ENDFIRE = 0;
+static uint32_t FLUENCE_MODE_BROADSIDE = 1;
+static int vr_enable = 0;
+
+int dev_cnt = 0;
+const char ** name = NULL;
+int mixer_cnt = 0;
+static uint32_t cur_tx = INVALID_DEVICE;
+static uint32_t cur_rx = INVALID_DEVICE;
+#ifdef QCOM_VOIP_ENABLED
+int voip_session_id = 0;
+int voip_session_mute = 0;
+#endif
+int voice_session_id = 0;
+int voice_session_mute = 0;
+static bool dualmic_enabled = false;
+static bool anc_running = false;
+static bool anc_setting = false;
+// This flag is used for avoiding multiple init/deinit of ANC driver.
+static bool anc_enabled = false;
+bool vMicMute = false;
+
+#ifdef QCOM_ACDB_ENABLED
+static bool bInitACDB = false;
+#endif
+#ifdef HTC_ACOUSTIC_AUDIO
+int rx_htc_acdb = 0;
+int tx_htc_acdb = 0;
+static bool support_aic3254 = true;
+static bool aic3254_enabled = true;
+int (*set_sound_effect)(const char* effect);
+static bool support_tpa2051 = true;
+static bool support_htc_backmic = true;
+static bool fm_enabled = false;
+static int alt_enable = 0;
+static int hac_enable = 0;
+static uint32_t cur_aic_tx = UPLINK_OFF;
+static uint32_t cur_aic_rx = DOWNLINK_OFF;
+static int cur_tpa_mode = 0;
+#endif
+
+typedef struct routing_table
+{
+ unsigned short dec_id;
+ int dev_id;
+ int dev_id_tx;
+ int stream_type;
+ bool active;
+ struct routing_table *next;
+} Routing_table;
+Routing_table* head;
+Mutex mRoutingTableLock;
+
+typedef struct device_table
+{
+ int dev_id;
+ int acdb_id;
+ int class_id;
+ int capability;
+}Device_table;
+Device_table* device_list;
+
+enum STREAM_TYPES {
+ PCM_PLAY=1,
+ PCM_REC,
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+ LPA_DECODE,
+#endif
+ VOICE_CALL,
+#ifdef QCOM_VOIP_ENABLED
+ VOIP_CALL,
+#endif
+#ifdef QCOM_FM_ENABLED
+ FM_RADIO,
+ FM_REC,
+ FM_A2DP,
+#endif
+ INVALID_STREAM
+};
+
+typedef struct ComboDeviceType
+{
+ uint32_t DeviceId;
+ STREAM_TYPES StreamType;
+}CurrentComboDeviceStruct;
+CurrentComboDeviceStruct CurrentComboDeviceData;
+Mutex mComboDeviceLock;
+
+#ifdef QCOM_FM_ENABLED
+enum FM_STATE {
+ FM_INVALID=1,
+ FM_OFF,
+ FM_ON
+};
+
+FM_STATE fmState = FM_INVALID;
+#endif
+
+static uint32_t fmDevice = INVALID_DEVICE;
+
+#define MAX_DEVICE_COUNT 200
+#define DEV_ID(X) device_list[X].dev_id
+#ifdef QCOM_ACDB_ENABLED
+#define ACDB_ID(X) device_list[X].acdb_id
+#endif
+#define CAPABILITY(X) device_list[X].capability
+
+void addToTable(int decoder_id,int device_id,int device_id_tx,int stream_type,bool active) {
+ Routing_table* temp_ptr;
+ ALOGD("addToTable stream %d",stream_type);
+ Mutex::Autolock lock(mRoutingTableLock);
+ temp_ptr = (Routing_table* ) malloc(sizeof(Routing_table));
+ temp_ptr->next = NULL;
+ temp_ptr->dec_id = decoder_id;
+ temp_ptr->dev_id = device_id;
+ temp_ptr->dev_id_tx = device_id_tx;
+ temp_ptr->stream_type = stream_type;
+ temp_ptr->active = active;
+ //make sure Voice node is always on top.
+ //For voice call device Switching, there a limitation
+ //Routing must happen before disabling/Enabling device.
+ if(head->next != NULL){
+ if(head->next->stream_type == VOICE_CALL){
+ temp_ptr->next = head->next->next;
+ head->next->next = temp_ptr;
+ return;
+ }
+ }
+ //add new Node to head.
+ temp_ptr->next =head->next;
+ head->next = temp_ptr;
+}
+
+bool isStreamOn(int Stream_type) {
+ Routing_table* temp_ptr;
+ Mutex::Autolock lock(mRoutingTableLock);
+ temp_ptr = head->next;
+ while(temp_ptr!=NULL) {
+ if(temp_ptr->stream_type == Stream_type)
+ return true;
+ temp_ptr=temp_ptr->next;
+ }
+ return false;
+}
+
+bool isStreamOnAndActive(int Stream_type) {
+ Routing_table* temp_ptr;
+ Mutex::Autolock lock(mRoutingTableLock);
+ temp_ptr = head->next;
+ while(temp_ptr!=NULL) {
+ if(temp_ptr->stream_type == Stream_type) {
+ if(temp_ptr->active == true) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ temp_ptr=temp_ptr->next;
+ }
+ return false;
+}
+
+bool isStreamOnAndInactive(int Stream_type) {
+ Routing_table* temp_ptr;
+ Mutex::Autolock lock(mRoutingTableLock);
+ temp_ptr = head->next;
+ while(temp_ptr!=NULL) {
+ if(temp_ptr->stream_type == Stream_type) {
+ if(temp_ptr->active == false) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ temp_ptr=temp_ptr->next;
+ }
+ return false;
+}
+
+Routing_table* getNodeByStreamType(int Stream_type) {
+ Routing_table* temp_ptr;
+ Mutex::Autolock lock(mRoutingTableLock);
+ temp_ptr = head->next;
+ while(temp_ptr!=NULL) {
+ if(temp_ptr->stream_type == Stream_type) {
+ return temp_ptr;
+ }
+ temp_ptr=temp_ptr->next;
+ }
+ return NULL;
+}
+
+void modifyActiveStateOfStream(int Stream_type, bool Active) {
+ Routing_table* temp_ptr;
+ Mutex::Autolock lock(mRoutingTableLock);
+ temp_ptr = head->next;
+ while(temp_ptr!=NULL) {
+ if(temp_ptr->stream_type == Stream_type) {
+ temp_ptr->active = Active;
+ }
+ temp_ptr=temp_ptr->next;
+ }
+}
+
+void modifyActiveDeviceOfStream(int Stream_type,int Device_id,int Device_id_tx) {
+ Routing_table* temp_ptr;
+ temp_ptr = head->next;
+ while(temp_ptr!=NULL) {
+ if(temp_ptr->stream_type == Stream_type) {
+ temp_ptr->dev_id = Device_id;
+ temp_ptr->dev_id_tx = Device_id_tx;
+ }
+ temp_ptr=temp_ptr->next;
+ }
+}
+
+void printTable()
+{
+ Routing_table * temp_ptr;
+ Mutex::Autolock lock(mRoutingTableLock);
+ temp_ptr = head->next;
+ while(temp_ptr!=NULL) {
+ printf("%d %d %d %d %d\n",temp_ptr->dec_id,temp_ptr->dev_id,temp_ptr->dev_id_tx,temp_ptr->stream_type,temp_ptr->active);
+ temp_ptr = temp_ptr->next;
+ }
+}
+
+void deleteFromTable(int Stream_type) {
+ Routing_table *temp_ptr,*temp1;
+ ALOGD("deleteFromTable stream %d",Stream_type);
+ Mutex::Autolock lock(mRoutingTableLock);
+ temp_ptr = head;
+ while(temp_ptr->next!=NULL) {
+ if(temp_ptr->next->stream_type == Stream_type) {
+ temp1 = temp_ptr->next;
+ temp_ptr->next = temp_ptr->next->next;
+ free(temp1);
+ return;
+ }
+ temp_ptr=temp_ptr->next;
+ }
+
+}
+
+bool isDeviceListEmpty() {
+ if(head->next == NULL)
+ return true;
+ else
+ return false;
+}
+
+#ifdef QCOM_ANC_HEADSET_ENABLED
+//NEEDS to be called with device already enabled
+#define ANC_ACDB_STEREO_FF_ID 26
+int enableANC(int enable, uint32_t device)
+{
+ int rc;
+ device = 16;
+ ALOGD("%s: enable=%d, device=%d", __func__, enable, device);
+
+ // If anc is already enabled/disabled, then don't initalize the driver again.
+ if (enable == anc_enabled)
+ {
+ ALOGV("ANC driver is already in state %d. Not calling anc driver", enable);
+ return -EPERM;
+ }
+
+ if (enable) {
+#ifdef QCOM_ACDB_ENABLED
+ rc = acdb_loader_send_anc_cal(ANC_ACDB_STEREO_FF_ID);
+ if (rc) {
+ ALOGE("Error processing ANC ACDB data\n");
+ return rc;
+ }
+#endif
+ }
+ rc = msm_enable_anc(DEV_ID(device),enable);
+
+ if ( rc == 0 )
+ {
+ ALOGV("msm_enable_anc was successful");
+ anc_enabled = enable;
+ } else
+ {
+ ALOGV("msm_enable_anc failed");
+ }
+
+ return rc;
+}
+#endif
+
+#ifdef QCOM_ACDB_ENABLED
+static void initACDB() {
+ while(bInitACDB == false) {
+ ALOGD("Calling acdb_loader_init_ACDB()");
+ if(acdb_loader_init_ACDB() == 0){
+ ALOGD("acdb_loader_init_ACDB() successful");
+ bInitACDB = true;
+ }
+ }
+}
+#endif
+
+int enableDevice(int device,short enable) {
+
+ // prevent disabling of a device if it doesn't exist
+ //Temporaray hack till speaker_tx device is mainlined
+ if(DEV_ID(device) == INVALID_DEVICE) {
+ return 0;
+ }
+#ifdef QCOM_ACDB_ENABLED
+ if(bInitACDB == false) {
+ initACDB();
+ }
+#endif
+ ALOGE("value of device and enable is %d %d ALSA dev id:%d",device,enable,DEV_ID(device));
+ if( msm_en_device(DEV_ID(device), enable)) {
+ ALOGE("msm_en_device(%d,%d) failed errno = %d",DEV_ID(device),enable, errno);
+ return -1;
+ }
+ return 0;
+}
+
+static status_t updateDeviceInfo(int rx_device,int tx_device) {
+ bool isRxDeviceEnabled = false,isTxDeviceEnabled = false;
+ Routing_table *temp_ptr,*temp_head;
+ int tx_dev_prev = INVALID_DEVICE;
+ temp_head = head;
+
+ ALOGD("updateDeviceInfo: E");
+ Mutex::Autolock lock(mDeviceSwitchLock);
+
+ if(temp_head->next == NULL) {
+ ALOGD("simple device switch");
+ if(cur_rx!=INVALID_DEVICE)
+ enableDevice(cur_rx,0);
+ if(cur_tx != INVALID_DEVICE)
+ enableDevice(cur_tx,0);
+ cur_rx = rx_device;
+ cur_tx = tx_device;
+ if(cur_rx == DEVICE_ANC_HEADSET_STEREO_RX) {
+ enableDevice(cur_rx,1);
+ enableDevice(cur_tx,1);
+ }
+ return NO_ERROR;
+ }
+
+ Mutex::Autolock lock_1(mRoutingTableLock);
+
+ while(temp_head->next != NULL) {
+ temp_ptr = temp_head->next;
+ switch(temp_ptr->stream_type) {
+ case PCM_PLAY:
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+ case LPA_DECODE:
+#endif
+#ifdef QCOM_FM_ENABLED
+ case FM_RADIO:
+ case FM_A2DP:
+#endif
+ if(rx_device == INVALID_DEVICE)
+ return -1;
+ ALOGD("The node type is %d", temp_ptr->stream_type);
+ ALOGV("rx_device = %d,temp_ptr->dev_id = %d",rx_device,temp_ptr->dev_id);
+ if(rx_device != temp_ptr->dev_id) {
+ enableDevice(temp_ptr->dev_id,0);
+ }
+ if(msm_route_stream(PCM_PLAY,temp_ptr->dec_id,DEV_ID(temp_ptr->dev_id),0)) {
+ ALOGV("msm_route_stream(PCM_PLAY,%d,%d,0) failed",temp_ptr->dec_id,DEV_ID(temp_ptr->dev_id));
+ }
+ if(isRxDeviceEnabled == false) {
+ enableDevice(rx_device,1);
+#ifdef QCOM_ACDB_ENABLED
+ acdb_loader_send_audio_cal(ACDB_ID(rx_device), CAPABILITY(rx_device));
+#endif
+ isRxDeviceEnabled = true;
+ }
+ if(msm_route_stream(PCM_PLAY,temp_ptr->dec_id,DEV_ID(rx_device),1)) {
+ ALOGV("msm_route_stream(PCM_PLAY,%d,%d,1) failed",temp_ptr->dec_id,DEV_ID(rx_device));
+ }
+ modifyActiveDeviceOfStream(temp_ptr->stream_type,rx_device,INVALID_DEVICE);
+ cur_tx = tx_device ;
+ cur_rx = rx_device ;
+ break;
+
+ case PCM_REC:
+
+ if(tx_device == INVALID_DEVICE)
+ return -1;
+
+ // If dual mic is enabled in QualComm settings then that takes preference.
+ if ( dualmic_enabled && (DEV_ID(DEVICE_DUALMIC_SPEAKER_TX) != INVALID_DEVICE))
+ {
+ tx_device = DEVICE_DUALMIC_SPEAKER_TX;
+ }
+
+ ALOGD("case PCM_REC");
+ if(isTxDeviceEnabled == false) {
+ enableDevice(temp_ptr->dev_id,0);
+ enableDevice(tx_device,1);
+#ifdef QCOM_ACDB_ENABLED
+ acdb_loader_send_audio_cal(ACDB_ID(tx_device), CAPABILITY(tx_device));
+#endif
+ isTxDeviceEnabled = true;
+ }
+ if(msm_route_stream(PCM_REC,temp_ptr->dec_id,DEV_ID(temp_ptr->dev_id),0)) {
+ ALOGV("msm_route_stream(PCM_PLAY,%d,%d,0) failed",temp_ptr->dec_id,DEV_ID(temp_ptr->dev_id));
+ }
+ if(msm_route_stream(PCM_REC,temp_ptr->dec_id,DEV_ID(tx_device),1)) {
+ ALOGV("msm_route_stream(PCM_REC,%d,%d,1) failed",temp_ptr->dec_id,DEV_ID(tx_device));
+ }
+ modifyActiveDeviceOfStream(PCM_REC,tx_device,INVALID_DEVICE);
+ tx_dev_prev = cur_tx;
+ cur_tx = tx_device ;
+ cur_rx = rx_device ;
+ if((vMicMute == true) && (tx_dev_prev != cur_tx)) {
+ ALOGD("REC:device switch with mute enabled :tx_dev_prev %d cur_tx: %d",tx_dev_prev, cur_tx);
+ msm_device_mute(DEV_ID(cur_tx), true);
+ }
+ break;
+ case VOICE_CALL:
+#ifdef QCOM_VOIP_ENABLED
+ case VOIP_CALL:
+#endif
+ if(rx_device == INVALID_DEVICE || tx_device == INVALID_DEVICE)
+ return -1;
+ ALOGD("case VOICE_CALL/VOIP CALL %d",temp_ptr->stream_type);
+#ifdef QCOM_ACDB_ENABLED
+ #ifdef HTC_ACOUSTIC_AUDIO
+ if (rx_htc_acdb == 0)
+ rx_htc_acdb = ACDB_ID(rx_device);
+ if (tx_htc_acdb == 0)
+ tx_htc_acdb = ACDB_ID(tx_device);
+ ALOGD("acdb_loader_send_voice_cal acdb_rx = %d, acdb_tx = %d", rx_htc_acdb, tx_htc_acdb);
+ acdb_loader_send_voice_cal(rx_htc_acdb, tx_htc_acdb);
+ #else
+ acdb_loader_send_voice_cal(ACDB_ID(rx_device),ACDB_ID(tx_device));
+ #endif
+#endif
+ msm_route_voice(DEV_ID(rx_device),DEV_ID(tx_device),1);
+
+ // Temporary work around for Speaker mode. The driver is not
+ // supporting Speaker Rx and Handset Tx combo
+ if(isRxDeviceEnabled == false) {
+ if (rx_device != temp_ptr->dev_id)
+ {
+ enableDevice(temp_ptr->dev_id,0);
+ }
+ isRxDeviceEnabled = true;
+ }
+ if(isTxDeviceEnabled == false) {
+ if (tx_device != temp_ptr->dev_id_tx)
+ {
+ enableDevice(temp_ptr->dev_id_tx,0);
+ }
+ isTxDeviceEnabled = true;
+ }
+
+ if (rx_device != temp_ptr->dev_id)
+ {
+ enableDevice(rx_device,1);
+ }
+
+ if (tx_device != temp_ptr->dev_id_tx)
+ {
+ enableDevice(tx_device,1);
+ }
+
+ cur_rx = rx_device;
+ cur_tx = tx_device;
+ modifyActiveDeviceOfStream(temp_ptr->stream_type,cur_rx,cur_tx);
+ break;
+ default:
+ break;
+ }
+ temp_head = temp_head->next;
+ }
+ ALOGD("updateDeviceInfo: X");
+ return NO_ERROR;
+}
+
+void freeMemory() {
+ Routing_table *temp;
+ while(head != NULL) {
+ temp = head->next;
+ free(head);
+ head = temp;
+ }
+free(device_list);
+}
+
+//
+// ----------------------------------------------------------------------------
+
+AudioHardware::AudioHardware() :
+ mInit(false), mMicMute(true), mBluetoothNrec(true), mBluetoothId(0),
+#ifdef HTC_ACOUSTIC_AUDIO
+ mHACSetting(false), mBluetoothIdTx(0), mBluetoothIdRx(0),
+#endif
+ mOutput(0),mBluetoothVGS(false),
+ mCurSndDevice(-1),
+ mTtyMode(TTY_OFF), mFmFd(-1), mNumPcmRec(0)
+#ifdef QCOM_VOIP_ENABLED
+ , mVoipFd(-1), mNumVoipStreams(0), mDirectOutput(0)
+#endif
+#ifdef HTC_ACOUSTIC_AUDIO
+ , mRecordState(false), mEffectEnabled(false)
+#endif
+{
+
+ int control;
+ int i = 0,index = 0;
+#ifdef QCOM_ACDB_ENABLED
+ int acdb_id = INVALID_ACDB_ID;
+#endif
+ int fluence_mode = FLUENCE_MODE_ENDFIRE;
+ char value[128];
+#ifdef HTC_ACOUSTIC_AUDIO
+ int (*snd_get_num)();
+ int (*snd_get_bt_endpoint)(msm_bt_endpoint *);
+ int (*set_acoustic_parameters)();
+ int (*set_tpa2051_parameters)();
+ int (*set_aic3254_parameters)();
+ int (*support_back_mic)();
+
+ struct msm_bt_endpoint *ept;
+#endif
+ head = (Routing_table* ) malloc(sizeof(Routing_table));
+ head->next = NULL;
+
+#ifdef HTC_ACOUSTIC_AUDIO
+ acoustic =:: dlopen("/system/lib/libhtc_acoustic.so", RTLD_NOW);
+ if (acoustic == NULL ) {
+ ALOGD("Could not open libhtc_acoustic.so");
+ /* this is not really an error on non-htc devices... */
+ mNumBTEndpoints = 0;
+ support_aic3254 = false;
+ support_tpa2051 = false;
+ support_htc_backmic = false;
+ }
+#endif
+
+ ALOGD("msm_mixer_open: Opening the device");
+ control = msm_mixer_open("/dev/snd/controlC0", 0);
+ if(control< 0)
+ ALOGE("ERROR opening the device");
+
+
+ mixer_cnt = msm_mixer_count();
+ ALOGD("msm_mixer_count:mixer_cnt =%d",mixer_cnt);
+
+ dev_cnt = msm_get_device_count();
+ ALOGV("got device_count %d",dev_cnt);
+ if (dev_cnt <= 0) {
+ ALOGE("NO devices registered\n");
+ return;
+ }
+
+ //End any voice call if it exists. This is to ensure the next request
+ //to voice call after a mediaserver crash or sub system restart
+ //is not ignored by the voice driver.
+ if (msm_end_voice() < 0)
+ ALOGE("msm_end_voice() failed");
+
+ if(msm_reset_all_device() < 0)
+ ALOGE("msm_reset_all_device() failed");
+
+ name = msm_get_device_list();
+ device_list = (Device_table* )malloc(sizeof(Device_table)*MAX_DEVICE_COUNT);
+ if(device_list == NULL) {
+ ALOGE("malloc failed for device list");
+ return;
+ }
+ property_get("persist.audio.fluence.mode",value,"0");
+ if (!strcmp("broadside", value)) {
+ fluence_mode = FLUENCE_MODE_BROADSIDE;
+ }
+
+ property_get("persist.audio.vr.enable",value,"Unknown");
+ if (!strcmp("true", value))
+ vr_enable = 1;
+
+ for(i = 0;i<MAX_DEVICE_COUNT;i++)
+ device_list[i].dev_id = INVALID_DEVICE;
+
+ for(i = 0; i < dev_cnt;i++) {
+ if(strcmp((char* )name[i],"handset_rx") == 0) {
+ index = DEVICE_HANDSET_RX;
+ }
+ else if(strcmp((char* )name[i],"handset_tx") == 0) {
+ index = DEVICE_HANDSET_TX;
+ }
+ else if((strcmp((char* )name[i],"speaker_stereo_rx") == 0) ||
+ (strcmp((char* )name[i],"speaker_stereo_rx_playback") == 0) ||
+ (strcmp((char* )name[i],"speaker_rx") == 0)) {
+ index = DEVICE_SPEAKER_RX;
+ }
+ else if((strcmp((char* )name[i],"speaker_mono_tx") == 0) || (strcmp((char* )name[i],"speaker_tx") == 0)) {
+ index = DEVICE_SPEAKER_TX;
+ }
+ else if((strcmp((char* )name[i],"headset_stereo_rx") == 0) || (strcmp((char* )name[i],"headset_rx") == 0)) {
+ index = DEVICE_HEADSET_RX;
+ }
+ else if((strcmp((char* )name[i],"headset_mono_tx") == 0) || (strcmp((char* )name[i],"headset_tx") == 0)) {
+ index = DEVICE_HEADSET_TX;
+ }
+ else if(strcmp((char* )name[i],"fmradio_handset_rx") == 0) {
+ index = DEVICE_FMRADIO_HANDSET_RX;
+ }
+ else if((strcmp((char* )name[i],"fmradio_headset_rx") == 0) || (strcmp((char* )name[i],"fm_radio_headset_rx") == 0)) {
+ index = DEVICE_FMRADIO_HEADSET_RX;
+ }
+ else if((strcmp((char* )name[i],"fmradio_speaker_rx") == 0) || (strcmp((char* )name[i],"fm_radio_speaker_rx") == 0)) {
+ index = DEVICE_FMRADIO_SPEAKER_RX;
+ }
+ else if((strcmp((char* )name[i],"handset_dual_mic_endfire_tx") == 0) || (strcmp((char* )name[i],"dualmic_handset_ef_tx") == 0)) {
+ if (fluence_mode == FLUENCE_MODE_ENDFIRE) {
+ index = DEVICE_DUALMIC_HANDSET_TX;
+ } else {
+ ALOGV("Endfire handset found but user request for %d\n", fluence_mode);
+ continue;
+ }
+ }
+ else if((strcmp((char* )name[i],"speaker_dual_mic_endfire_tx") == 0)|| (strcmp((char* )name[i],"dualmic_speaker_ef_tx") == 0)) {
+ if (fluence_mode == FLUENCE_MODE_ENDFIRE) {
+ index = DEVICE_DUALMIC_SPEAKER_TX;
+ } else {
+ ALOGV("Endfire speaker found but user request for %d\n", fluence_mode);
+ continue;
+ }
+ }
+ else if(strcmp((char* )name[i],"handset_dual_mic_broadside_tx") == 0) {
+ if (fluence_mode == FLUENCE_MODE_BROADSIDE) {
+ index = DEVICE_DUALMIC_HANDSET_TX;
+ } else {
+ ALOGV("Broadside handset found but user request for %d\n", fluence_mode);
+ continue;
+ }
+ }
+ else if(strcmp((char* )name[i],"speaker_dual_mic_broadside_tx") == 0) {
+ if (fluence_mode == FLUENCE_MODE_BROADSIDE) {
+ index = DEVICE_DUALMIC_SPEAKER_TX;
+ } else {
+ ALOGV("Broadside speaker found but user request for %d\n", fluence_mode);
+ continue;
+ }
+ }
+ else if((strcmp((char* )name[i],"tty_headset_mono_rx") == 0) || (strcmp((char* )name[i],"tty_headset_rx") == 0)) {
+ index = DEVICE_TTY_HEADSET_MONO_RX;
+ }
+ else if((strcmp((char* )name[i],"tty_headset_mono_tx") == 0) || (strcmp((char* )name[i],"tty_headset_tx") == 0)) {
+ index = DEVICE_TTY_HEADSET_MONO_TX;
+ }
+ else if((strcmp((char* )name[i],"bt_sco_rx") == 0) || (strcmp((char* )name[i],"bt_sco_mono_rx") == 0)) {
+ index = DEVICE_BT_SCO_RX;
+ }
+ else if((strcmp((char* )name[i],"bt_sco_tx") == 0) || (strcmp((char* )name[i],"bt_sco_mono_tx") == 0)) {
+ index = DEVICE_BT_SCO_TX;
+ }
+ else if((strcmp((char*)name[i],"headset_stereo_speaker_stereo_rx") == 0) ||
+ (strcmp((char*)name[i],"headset_stereo_rx_playback") == 0) ||
+ (strcmp((char*)name[i],"headset_speaker_stereo_rx") == 0) || (strcmp((char*)name[i],"speaker_headset_rx") == 0)) {
+ index = DEVICE_SPEAKER_HEADSET_RX;
+ }
+ else if((strcmp((char*)name[i],"fmradio_stereo_tx") == 0) || (strcmp((char*)name[i],"fm_radio_tx") == 0)) {
+ index = DEVICE_FMRADIO_STEREO_TX;
+ }
+ else if((strcmp((char*)name[i],"hdmi_stereo_rx") == 0) || (strcmp((char*)name[i],"hdmi_rx") == 0)) {
+ index = DEVICE_HDMI_STERO_RX;
+ }
+ //to check for correct name and ACDB number for ANC
+ else if(strcmp((char*)name[i],"anc_headset_stereo_rx") == 0) {
+ index = DEVICE_ANC_HEADSET_STEREO_RX;
+ }
+ else if(strcmp((char*)name[i],"fmradio_stereo_rx") == 0)
+ index = DEVICE_FMRADIO_STEREO_RX;
+#ifdef SAMSUNG_AUDIO
+ else if(strcmp((char* )name[i], "handset_voip_rx") == 0)
+ index = DEVICE_HANDSET_VOIP_RX;
+ else if(strcmp((char* )name[i], "handset_voip_tx") == 0)
+ index = DEVICE_HANDSET_VOIP_TX;
+ else if(strcmp((char* )name[i], "speaker_voip_rx") == 0)
+ index = DEVICE_SPEAKER_VOIP_RX;
+ else if(strcmp((char* )name[i], "speaker_voip_tx") == 0)
+ index = DEVICE_SPEAKER_VOIP_TX;
+ else if(strcmp((char* )name[i], "headset_voip_rx") == 0)
+ index = DEVICE_HEADSET_VOIP_RX;
+ else if(strcmp((char* )name[i], "headset_voip_tx") == 0)
+ index = DEVICE_HEADSET_VOIP_TX;
+ else if(strcmp((char* )name[i], "handset_call_rx") == 0)
+ index = DEVICE_HANDSET_CALL_RX;
+ else if(strcmp((char* )name[i], "handset_call_tx") == 0)
+ index = DEVICE_HANDSET_CALL_TX;
+ else if(strcmp((char* )name[i], "speaker_call_rx") == 0)
+ index = DEVICE_SPEAKER_CALL_RX;
+ else if(strcmp((char* )name[i], "speaker_call_tx") == 0)
+ index = DEVICE_SPEAKER_CALL_TX;
+ else if(strcmp((char* )name[i], "headset_call_rx") == 0)
+ index = DEVICE_HEADSET_CALL_RX;
+ else if(strcmp((char* )name[i], "headset_call_tx") == 0)
+ index = DEVICE_HEADSET_CALL_TX;
+ else if(strcmp((char* )name[i], "speaker_vr_tx") == 0)
+ index = DEVICE_SPEAKER_VR_TX;
+ else if(strcmp((char* )name[i], "headset_vr_tx") == 0)
+ index = DEVICE_HEADSET_VR_TX;
+#endif
+ else if((strcmp((char* )name[i], "camcoder_tx") == 0) ||
+#ifdef SONY_AUDIO
+ (strcmp((char* )name[i], "secondary_mic_tx") == 0))
+#else
+ (strcmp((char* )name[i], "camcorder_tx") == 0) ||
+ (strcmp((char* )name[i], "handset_lgcam_tx") == 0))
+#endif
+ index = DEVICE_CAMCORDER_TX;
+ else {
+ ALOGI("Not used device: %s", ( char* )name[i]);
+ continue;
+ }
+ ALOGI("index = %d",index);
+
+ device_list[index].dev_id = msm_get_device((char* )name[i]);
+ if(device_list[index].dev_id >= 0) {
+ ALOGI("Found device: %s:index = %d,dev_id: %d",( char* )name[i], index,device_list[index].dev_id);
+ }
+#ifdef QCOM_ACDB_ENABLED
+ acdb_mapper_get_acdb_id_from_dev_name((char* )name[i], &device_list[index].acdb_id);
+ device_list[index].class_id = msm_get_device_class(device_list[index].dev_id);
+ device_list[index].capability = msm_get_device_capability(device_list[index].dev_id);
+ ALOGI("acdb ID = %d,class ID = %d,capablity = %d for device %d",device_list[index].acdb_id,
+ device_list[index].class_id,device_list[index].capability,device_list[index].dev_id);
+#endif
+ }
+
+ CurrentComboDeviceData.DeviceId = INVALID_DEVICE;
+ CurrentComboDeviceData.StreamType = INVALID_STREAM;
+#ifdef HTC_ACOUSTIC_AUDIO
+ set_acoustic_parameters = (int (*)(void))::dlsym(acoustic, "set_acoustic_parameters");
+ if ((*set_acoustic_parameters) == 0 ) {
+ ALOGE("Could not open set_acoustic_parameters()");
+ return;
+ }
+
+ int rc = set_acoustic_parameters();
+ if (rc < 0) {
+ ALOGD("Could not set acoustic parameters to share memory: %d", rc);
+ }
+
+ /* Check the system property for enable or not the ALT function */
+ property_get("htc.audio.alt.enable", value, "0");
+ alt_enable = atoi(value);
+ ALOGV("Enable ALT function: %d", alt_enable);
+
+ /* Check the system property for enable or not the HAC function */
+ property_get("htc.audio.hac.enable", value, "0");
+ hac_enable = atoi(value);
+ ALOGV("Enable HAC function: %d", hac_enable);
+
+ set_tpa2051_parameters = (int (*)(void))::dlsym(acoustic, "set_tpa2051_parameters");
+ if ((*set_tpa2051_parameters) == 0) {
+ ALOGI("set_tpa2051_parameters() not present");
+ support_tpa2051 = false;
+ }
+
+ if (support_tpa2051) {
+ if (set_tpa2051_parameters() < 0) {
+ ALOGI("Speaker amplifies tpa2051 is not supported");
+ support_tpa2051 = false;
+ }
+ }
+
+ set_aic3254_parameters = (int (*)(void))::dlsym(acoustic, "set_aic3254_parameters");
+ if ((*set_aic3254_parameters) == 0 ) {
+ ALOGI("set_aic3254_parameters() not present");
+ support_aic3254 = false;
+ }
+
+ if (support_aic3254) {
+ if (set_aic3254_parameters() < 0) {
+ ALOGI("AIC3254 DSP is not supported");
+ support_aic3254 = false;
+ }
+ }
+
+ if (support_aic3254) {
+ set_sound_effect = (int (*)(const char*))::dlsym(acoustic, "set_sound_effect");
+ if ((*set_sound_effect) == 0 ) {
+ ALOGI("set_sound_effect() not present");
+ ALOGI("AIC3254 DSP is not supported");
+ support_aic3254 = false;
+ } else
+ strcpy(mEffect, "\0");
+ }
+
+ support_back_mic = (int (*)(void))::dlsym(acoustic, "support_back_mic");
+ if ((*support_back_mic) == 0 ) {
+ ALOGI("support_back_mic() not present");
+ support_htc_backmic = false;
+ }
+
+ if (support_htc_backmic) {
+ if (support_back_mic() != 1) {
+ ALOGI("HTC DualMic is not supported");
+ support_htc_backmic = false;
+ }
+ }
+
+ snd_get_num = (int (*)(void))::dlsym(acoustic, "snd_get_num");
+ if ((*snd_get_num) == 0 ) {
+ ALOGD("Could not open snd_get_num()");
+ }
+
+ mNumBTEndpoints = snd_get_num();
+ ALOGV("mNumBTEndpoints = %d", mNumBTEndpoints);
+ mBTEndpoints = new msm_bt_endpoint[mNumBTEndpoints];
+ ALOGV("constructed %d SND endpoints)", mNumBTEndpoints);
+ ept = mBTEndpoints;
+ snd_get_bt_endpoint = (int (*)(msm_bt_endpoint *))::dlsym(acoustic, "snd_get_bt_endpoint");
+ if ((*snd_get_bt_endpoint) == 0 ) {
+ mInit = true;
+ ALOGE("Could not open snd_get_bt_endpoint()");
+ return;
+ }
+ snd_get_bt_endpoint(mBTEndpoints);
+
+ for (int i = 0; i < mNumBTEndpoints; i++) {
+ ALOGV("BT name %s (tx,rx)=(%d,%d)", mBTEndpoints[i].name, mBTEndpoints[i].tx, mBTEndpoints[i].rx);
+ }
+#endif
+ mInit = true;
+}
+
+AudioHardware::~AudioHardware()
+{
+ for (size_t index = 0; index < mInputs.size(); index++) {
+ closeInputStream((AudioStreamIn*)mInputs[index]);
+ }
+ mInputs.clear();
+#ifdef QCOM_VOIP_ENABLED
+ mVoipInputs.clear();
+#endif
+ closeOutputStream((AudioStreamOut*)mOutput);
+ if (acoustic) {
+ ::dlclose(acoustic);
+ acoustic = 0;
+ }
+ msm_mixer_close();
+#ifdef QCOM_ACDB_ENABLED
+ acdb_loader_deallocate_ACDB();
+#endif
+ freeMemory();
+
+ mInit = false;
+}
+
+status_t AudioHardware::initCheck()
+{
+ return mInit ? NO_ERROR : NO_INIT;
+}
+
+AudioStreamOut* AudioHardware::openOutputStream(
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
+{
+ { // scope for the lock
+ status_t lStatus;
+ audio_output_flags_t flags = static_cast<audio_output_flags_t> (*status);
+ Mutex::Autolock lock(mLock);
+#ifdef QCOM_VOIP_ENABLED
+ // only one output stream allowed
+ if (mOutput && !((flags & AUDIO_OUTPUT_FLAG_DIRECT) && (flags & AUDIO_OUTPUT_FLAG_VOIP_RX))
+ && !(flags & AUDIO_OUTPUT_FLAG_LPA)) {
+ if (status) {
+ *status = INVALID_OPERATION;
+ }
+ ALOGE(" AudioHardware::openOutputStream Only one output stream allowed \n");
+ return 0;
+ }
+
+ if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) && (flags & AUDIO_OUTPUT_FLAG_VOIP_RX)) {
+ // open direct output stream
+ if(mDirectOutput == 0) {
+ ALOGV(" AudioHardware::openOutputStream Direct output stream \n");
+ AudioStreamOutDirect* out = new AudioStreamOutDirect();
+ lStatus = out->set(this, devices, format, channels, sampleRate);
+ if (status) {
+ *status = lStatus;
+ }
+ if (lStatus == NO_ERROR) {
+ mDirectOutput = out;
+ ALOGV(" \n set sucessful for AudioStreamOutDirect");
+ } else {
+ ALOGE(" \n set Failed for AudioStreamOutDirect");
+ delete out;
+ }
+ }
+ else {
+ ALOGE(" \n AudioHardware::AudioStreamOutDirect is already open");
+ }
+ return mDirectOutput;
+ } else
+#endif
+ if (flags & AUDIO_OUTPUT_FLAG_LPA) {
+ status_t err = BAD_VALUE;
+#if 0
+ if (mOutput) {
+ if (status) {
+ *status = INVALID_OPERATION;
+ }
+ ALOGE(" AudioHardware::openOutputStream Only one output stream allowed \n");
+ return 0;
+ }
+#endif
+ // create new output LPA stream
+ AudioSessionOutLPA* out = NULL;
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+ out = new AudioSessionOutLPA(this, devices, *format, *channels,*sampleRate,0,&err);
+ if(err != NO_ERROR) {
+ delete out;
+ out = NULL;
+ }
+#endif
+ if (status) *status = err;
+ mOutputLPA = out;
+ return mOutputLPA;
+
+ } else {
+#if 0
+ ALOGV(" AudioHardware::openOutputStream AudioStreamOutMSM8x60 output stream \n");
+ // only one output stream allowed
+ if (mOutput) {
+ if (status) {
+ *status = INVALID_OPERATION;
+ }
+ ALOGE(" AudioHardware::openOutputStream Only one output stream allowed \n");
+ return 0;
+ }
+#endif
+ // create new output stream
+ AudioStreamOutMSM8x60* out = new AudioStreamOutMSM8x60();
+ lStatus = out->set(this, devices, format, channels, sampleRate);
+ if (status) {
+ *status = lStatus;
+ }
+ if (lStatus == NO_ERROR) {
+ mOutput = out;
+ } else {
+ delete out;
+ }
+ return mOutput;
+ }
+ }
+ return NULL;
+}
+
+
+void AudioHardware::closeOutputStream(AudioStreamOut* out) {
+ Mutex::Autolock lock(mLock);
+ if ((mOutput == 0
+#ifdef QCOM_VOIP_ENABLED
+ && mDirectOutput == 0
+#endif
+ && mOutputLPA == 0) || ((mOutput != out)
+#ifdef QCOM_VOIP_ENABLED
+ && (mDirectOutput != out)
+#endif
+ && (mOutputLPA != out))) {
+ ALOGW("Attempt to close invalid output stream");
+ }
+ else if (mOutput == out) {
+ delete mOutput;
+ mOutput = 0;
+ }
+#ifdef QCOM_VOIP_ENABLED
+ else if (mDirectOutput == out) {
+ ALOGV(" deleting mDirectOutput \n");
+ delete mDirectOutput;
+ mDirectOutput = 0;
+ }
+#endif
+ else if (mOutputLPA == out) {
+ ALOGV(" deleting mOutputLPA \n");
+ delete mOutputLPA;
+ mOutputLPA = 0;
+ }
+}
+
+AudioStreamIn* AudioHardware::openInputStream(
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status,
+ AudioSystem::audio_in_acoustics acoustic_flags)
+{
+ // check for valid input source
+ if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
+ return 0;
+ }
+
+ mLock.lock();
+#ifdef QCOM_VOIP_ENABLED
+ if(devices == AudioSystem::DEVICE_IN_COMMUNICATION) {
+ ALOGE("Create Audio stream Voip \n");
+ AudioStreamInVoip* inVoip = new AudioStreamInVoip();
+ status_t lStatus = NO_ERROR;
+ lStatus = inVoip->set(this, devices, format, channels, sampleRate, acoustic_flags);
+ if (status) {
+ *status = lStatus;
+ }
+ if (lStatus != NO_ERROR) {
+ ALOGE(" Error creating voip input \n");
+ mLock.unlock();
+ delete inVoip;
+ return 0;
+ }
+ mVoipInputs.add(inVoip);
+ mLock.unlock();
+ return inVoip;
+ } else
+#endif
+ {
+ AudioStreamInMSM8x60* in8x60 = new AudioStreamInMSM8x60();
+ status_t lStatus = in8x60->set(this, devices, format, channels, sampleRate, acoustic_flags);
+ if (status) {
+ *status = lStatus;
+ }
+ if (lStatus != NO_ERROR) {
+ ALOGE("Error creating Audio stream AudioStreamInMSM8x60 \n");
+ mLock.unlock();
+ delete in8x60;
+ return 0;
+ }
+ mInputs.add(in8x60);
+ mLock.unlock();
+ return in8x60;
+ }
+}
+
+void AudioHardware::closeInputStream(AudioStreamIn* in) {
+ Mutex::Autolock lock(mLock);
+
+ ssize_t index = -1;
+ if((index = mInputs.indexOf((AudioStreamInMSM8x60 *)in)) >= 0) {
+ ALOGV("closeInputStream AudioStreamInMSM8x60");
+ mLock.unlock();
+ delete mInputs[index];
+ mLock.lock();
+ mInputs.removeAt(index);
+ }
+#ifdef QCOM_VOIP_ENABLED
+ else if ((index = mVoipInputs.indexOf((AudioStreamInVoip *)in)) >= 0) {
+ ALOGV("closeInputStream mVoipInputs");
+ mLock.unlock();
+ delete mVoipInputs[index];
+ mLock.lock();
+ mInputs.removeAt(index);
+ }
+#endif
+ else {
+ ALOGE("Attempt to close invalid input stream");
+ }
+}
+
+status_t AudioHardware::setMode(int mode)
+{
+ status_t status = AudioHardwareBase::setMode(mode);
+ if (status == NO_ERROR) {
+ // make sure that doAudioRouteOrMute() is called by doRouting()
+ // even if the new device selected is the same as current one.
+ clearCurDevice();
+ }
+ return status;
+}
+
+bool AudioHardware::checkOutputStandby()
+{
+ if (mOutput)
+ if (!mOutput->checkStandby())
+ return false;
+
+ return true;
+}
+
+status_t AudioHardware::setMicMute(bool state)
+{
+ Mutex::Autolock lock(mLock);
+ return setMicMute_nosync(state);
+}
+
+// always call with mutex held
+status_t AudioHardware::setMicMute_nosync(bool state)
+{
+ int session_id = 0;
+ if (mMicMute != state) {
+ mMicMute = state;
+ ALOGD("setMicMute_nosync calling voice mute with the mMicMute %d", mMicMute);
+ if(isStreamOnAndActive(VOICE_CALL)) {
+ session_id = voice_session_id;
+ voice_session_mute = mMicMute;
+#ifdef QCOM_VOIP_ENABLED
+ } else if (isStreamOnAndActive(VOIP_CALL)) {
+ session_id = voip_session_id;
+ voip_session_mute = mMicMute;
+#endif
+ } else {
+ ALOGE(" unknown voice stream");
+ return -1;
+ }
+#ifdef LEGACY_QCOM_VOICE
+ msm_set_voice_tx_mute(mMicMute);
+#else
+ msm_set_voice_tx_mute_ext(mMicMute,session_id);
+#endif
+ }
+ return NO_ERROR;
+}
+
+status_t AudioHardware::getMicMute(bool* state)
+{
+ int session_id = 0;
+ if(isStreamOnAndActive(VOICE_CALL)) {
+ session_id = voice_session_id;
+ *state = mMicMute = voice_session_mute;
+#ifdef QCOM_VOIP_ENABLED
+ } else if (isStreamOnAndActive(VOIP_CALL)) {
+ session_id = voip_session_id;
+ *state = mMicMute = voip_session_mute;
+#endif
+ } else
+ *state = mMicMute;
+ return NO_ERROR;
+}
+
+status_t AudioHardware::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ int rc = 0;
+ String8 value;
+ String8 key;
+ const char BT_NREC_KEY[] = "bt_headset_nrec";
+ const char BT_NAME_KEY[] = "bt_headset_name";
+ const char BT_NREC_VALUE_ON[] = "on";
+#ifdef QCOM_FM_ENABLED
+ const char FM_NAME_KEY[] = "FMRadioOn";
+ const char FM_VALUE_HANDSET[] = "handset";
+ const char FM_VALUE_SPEAKER[] = "speaker";
+ const char FM_VALUE_HEADSET[] = "headset";
+ const char FM_VALUE_FALSE[] = "false";
+#endif
+#ifdef HTC_ACOUSTIC_AUDIO
+ const char ACTIVE_AP[] = "active_ap";
+ const char EFFECT_ENABLED[] = "sound_effect_enable";
+#endif
+
+ ALOGV("setParameters() %s", keyValuePairs.string());
+
+ if (keyValuePairs.length() == 0) return BAD_VALUE;
+
+ key = String8(BT_NREC_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ if (value == BT_NREC_VALUE_ON) {
+ mBluetoothNrec = true;
+ } else {
+ mBluetoothNrec = false;
+ ALOGI("Turning noise reduction and echo cancellation off for BT "
+ "headset");
+ }
+ }
+ key = String8(BTHEADSET_VGS);
+ if (param.get(key, value) == NO_ERROR) {
+ if (value == BT_NREC_VALUE_ON) {
+ mBluetoothVGS = true;
+ } else {
+ mBluetoothVGS = false;
+ }
+ }
+ key = String8(BT_NAME_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+#ifdef HTC_ACOUSTIC_AUDIO
+ mBluetoothIdTx = 0;
+ mBluetoothIdRx = 0;
+ for (int i = 0; i < mNumBTEndpoints; i++) {
+ if (!strcasecmp(value.string(), mBTEndpoints[i].name)) {
+ mBluetoothIdTx = mBTEndpoints[i].tx;
+ mBluetoothIdRx = mBTEndpoints[i].rx;
+ ALOGD("Using custom acoustic parameters for %s", value.string());
+ break;
+ }
+ }
+ if (mBluetoothIdTx == 0) {
+ ALOGD("Using default acoustic parameters "
+ "(%s not in acoustic database)", value.string());
+ }
+#endif
+ doRouting(NULL);
+ }
+
+ key = String8(DUALMIC_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ if (value == "true") {
+ dualmic_enabled = true;
+ ALOGI("DualMic feature Enabled");
+ } else {
+ dualmic_enabled = false;
+ ALOGI("DualMic feature Disabled");
+ }
+ doRouting(NULL);
+ }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ key = String8(ANC_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ if (value == "true") {
+ ALOGE("Enabling ANC setting in the setparameter\n");
+ anc_setting= true;
+ } else {
+ ALOGE("Disabling ANC setting in the setparameter\n");
+ anc_setting= false;
+ //disabling ANC feature.
+ enableANC(0,cur_rx);
+ anc_running = false;
+ }
+ doRouting(NULL);
+ }
+#endif
+
+ key = String8(TTY_MODE_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ if (value == "full") {
+ mTtyMode = TTY_FULL;
+ } else if (value == "hco") {
+ mTtyMode = TTY_HCO;
+ } else if (value == "vco") {
+ mTtyMode = TTY_VCO;
+ } else {
+ mTtyMode = TTY_OFF;
+ }
+ if(mMode != AudioSystem::MODE_IN_CALL){
+ return NO_ERROR;
+ }
+ ALOGI("Changed TTY Mode=%s", value.string());
+ if((mMode == AudioSystem::MODE_IN_CALL) &&
+ (cur_rx == DEVICE_HEADSET_RX) &&
+ (cur_tx == DEVICE_HEADSET_TX))
+ doRouting(NULL);
+ }
+#ifdef HTC_ACOUSTIC_AUDIO
+ key = String8(ACTIVE_AP);
+ if (param.get(key, value) == NO_ERROR) {
+ const char* active_ap = value.string();
+ ALOGD("Active AP = %s", active_ap);
+ strcpy(mActiveAP, active_ap);
+
+ const char* dsp_effect = "\0";
+ key = String8(DSP_EFFECT_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ ALOGD("DSP Effect = %s", value.string());
+ dsp_effect = value.string();
+ strcpy(mEffect, dsp_effect);
+ }
+
+ key = String8(EFFECT_ENABLED);
+ if (param.get(key, value) == NO_ERROR) {
+ const char* sound_effect_enable = value.string();
+ ALOGD("Sound Effect Enabled = %s", sound_effect_enable);
+ if (value == "on") {
+ mEffectEnabled = true;
+ if (support_aic3254)
+ aic3254_config(get_snd_dev());
+ } else {
+ strcpy(mEffect, "\0");
+ mEffectEnabled = false;
+ }
+ }
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+String8 AudioHardware::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+
+ String8 key = String8(DUALMIC_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ value = String8(dualmic_enabled ? "true" : "false");
+ param.add(key, value);
+ }
+#ifdef QCOM_FM_ENABLED
+ key = String8("Fm-radio");
+ if ( param.get(key,value) == NO_ERROR ) {
+ if ( getNodeByStreamType(FM_RADIO) ) {
+ param.addInt(String8("isFMON"), true );
+ }
+ }
+#endif
+ key = String8(BTHEADSET_VGS);
+ if (param.get(key, value) == NO_ERROR) {
+ if(mBluetoothVGS)
+ param.addInt(String8("isVGS"), true);
+ }
+ key = String8(ECHO_SUPRESSION);
+ if (param.get(key, value) == NO_ERROR) {
+ value = String8("yes");
+ param.add(key, value);
+ }
+
+#ifdef HTC_ACOUSTIC_AUDIO
+ key = String8(DSP_EFFECT_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ value = String8(mCurDspProfile);
+ param.add(key, value);
+ }
+#endif
+ ALOGV("AudioHardware::getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+
+static unsigned calculate_audpre_table_index(unsigned index)
+{
+ switch (index) {
+ case 48000: return SAMP_RATE_INDX_48000;
+ case 44100: return SAMP_RATE_INDX_44100;
+ case 32000: return SAMP_RATE_INDX_32000;
+ case 24000: return SAMP_RATE_INDX_24000;
+ case 22050: return SAMP_RATE_INDX_22050;
+ case 16000: return SAMP_RATE_INDX_16000;
+ case 12000: return SAMP_RATE_INDX_12000;
+ case 11025: return SAMP_RATE_INDX_11025;
+ case 8000: return SAMP_RATE_INDX_8000;
+ default: return -1;
+ }
+}
+size_t AudioHardware::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+ if (format != AudioSystem::PCM_16_BIT){
+ ALOGW("getInputBufferSize bad format: %d", format);
+ return 0;
+ }
+ if (channelCount < 1 || channelCount > 2) {
+ ALOGW("getInputBufferSize bad channel count: %d", channelCount);
+ return 0;
+ }
+
+ if (sampleRate == 8000) {
+ return 320*channelCount;
+ } else if (sampleRate == 16000){
+ return 640*channelCount;
+ } else {
+ /*
+ Return pcm record buffer size based on the sampling rate:
+ If sampling rate >= 44.1 Khz, use 512 samples/channel pcm recording and
+ If sampling rate < 44.1 Khz, use 256 samples/channel pcm recording
+ */
+ if(sampleRate >= 44100){
+ return 1024*channelCount;
+ } else {
+ return 512*channelCount;
+ }
+ }
+}
+
+static status_t set_volume_rpc(uint32_t device,
+ uint32_t method,
+ uint32_t volume)
+{
+ ALOGV("set_volume_rpc(%d, %d, %d)\n", device, method, volume);
+
+ if (device == -1UL) return NO_ERROR;
+ return NO_ERROR;
+}
+
+status_t AudioHardware::setVoiceVolume(float v)
+{
+ int session_id = 0;
+ if (v < 0.0) {
+ ALOGW("setVoiceVolume(%f) under 0.0, assuming 0.0\n", v);
+ v = 0.0;
+ } else if (v > 1.0) {
+ ALOGW("setVoiceVolume(%f) over 1.0, assuming 1.0\n", v);
+ v = 1.0;
+ }
+
+#ifdef HTC_ACOUSTIC_AUDIO
+ mVoiceVolume = v;
+#endif
+
+ if(isStreamOnAndActive(VOICE_CALL)) {
+ session_id = voice_session_id;
+ }
+#ifdef QCOM_VOIP_ENABLED
+ else if (isStreamOnAndActive(VOIP_CALL)) {
+ session_id = voip_session_id;
+ }
+#endif
+ else {
+ ALOGE(" unknown stream ");
+ return -1;
+ }
+ int vol = lrint(v * 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
+ vol = 5 - (vol/20);
+ ALOGD("setVoiceVolume(%f)\n", v);
+ ALOGI("Setting in-call volume to %d (available range is 5(MIN VOLUME) to 0(MAX VOLUME)\n", vol);
+
+#ifdef LEGACY_QCOM_VOICE
+ if (msm_set_voice_rx_vol(vol)) {
+ ALOGE("msm_set_voice_rx_vol(%d) failed errno = %d", vol, errno);
+ return -1;
+ }
+#else
+ if(msm_set_voice_rx_vol_ext(vol,session_id)) {
+ ALOGE("msm_set_voice_rx_vol(%d) failed errno = %d",vol,errno);
+ return -1;
+ }
+#endif
+ ALOGV("msm_set_voice_rx_vol(%d) succeeded session_id %d",vol,session_id);
+ return NO_ERROR;
+}
+
+#ifdef QCOM_FM_ENABLED
+status_t AudioHardware::setFmVolume(float v)
+{
+ int vol = android::AudioSystem::logToLinear( (v?(v + 0.005):v) );
+ if ( vol > 100 ) {
+ vol = 100;
+ }
+ else if ( vol < 0 ) {
+ vol = 0;
+ }
+ ALOGV("setFmVolume(%f)\n", v);
+ ALOGV("Setting FM volume to %d (available range is 0 to 100)\n", vol);
+ Routing_table* temp = NULL;
+ temp = getNodeByStreamType(FM_RADIO);
+ if(temp == NULL){
+ ALOGV("No Active FM stream is running");
+ return NO_ERROR;
+ }
+ if(msm_set_volume(temp->dec_id, vol)) {
+ ALOGE("msm_set_volume(%d) failed for FM errno = %d",vol,errno);
+ return -1;
+ }
+ ALOGV("msm_set_volume(%d) for FM succeeded",vol);
+ return NO_ERROR;
+}
+#endif
+
+status_t AudioHardware::setMasterVolume(float v)
+{
+ Mutex::Autolock lock(mLock);
+ int vol = ceil(v * 7.0);
+ ALOGI("Set master volume to %d.\n", vol);
+
+ set_volume_rpc(SND_DEVICE_HANDSET, SND_METHOD_VOICE, vol);
+ set_volume_rpc(SND_DEVICE_SPEAKER, SND_METHOD_VOICE, vol);
+ set_volume_rpc(SND_DEVICE_BT, SND_METHOD_VOICE, vol);
+ set_volume_rpc(SND_DEVICE_HEADSET, SND_METHOD_VOICE, vol);
+ //TBD - does HDMI require this handling
+
+ // We return an error code here to let the audioflinger do in-software
+ // volume on top of the maximum volume that we set through the SND API.
+ // return error - software mixer will handle it
+ return -1;
+}
+
+#ifdef HTC_ACOUSTIC_AUDIO
+status_t get_batt_temp(int *batt_temp) {
+ ALOGD("Enable ALT for speaker");
+
+ int i, fd, len;
+ char get_batt_temp[6] = { 0 };
+ const char *fn = "/sys/class/power_supply/battery/batt_temp";
+
+ if ((fd = open(fn, O_RDONLY)) < 0) {
+ ALOGE("Couldn't open sysfs file batt_temp");
+ return UNKNOWN_ERROR;
+ }
+
+ if ((len = read(fd, get_batt_temp, sizeof(get_batt_temp))) <= 1) {
+ ALOGE("read battery temp fail: %s", strerror(errno));
+ close(fd);
+ return BAD_VALUE;
+ }
+
+ *batt_temp = strtol(get_batt_temp, NULL, 10);
+ ALOGD("ALT batt_temp = %d", *batt_temp);
+
+ close(fd);
+ return NO_ERROR;
+}
+
+status_t do_tpa2051_control(int mode)
+{
+ int fd, rc;
+ int tpa_mode = 0;
+
+ if (mode) {
+ if (cur_rx == DEVICE_HEADSET_RX)
+ tpa_mode = TPA2051_MODE_VOICECALL_HEADSET;
+ else if (cur_rx == DEVICE_SPEAKER_RX)
+ tpa_mode = TPA2051_MODE_VOICECALL_SPKR;
+ } else {
+ switch (cur_rx) {
+ case DEVICE_FMRADIO_HEADSET_RX:
+ tpa_mode = TPA2051_MODE_FM_HEADSET;
+ break;
+ case DEVICE_FMRADIO_SPEAKER_RX:
+ tpa_mode = TPA2051_MODE_FM_SPKR;
+ break;
+ case DEVICE_SPEAKER_HEADSET_RX:
+ tpa_mode = TPA2051_MODE_RING;
+ break;
+ case DEVICE_HEADSET_RX:
+ tpa_mode = TPA2051_MODE_PLAYBACK_HEADSET;
+ break;
+ case DEVICE_SPEAKER_RX:
+ tpa_mode = TPA2051_MODE_PLAYBACK_SPKR;
+ break;
+ default:
+ break;
+ }
+ }
+
+ fd = open("/dev/tpa2051d3", O_RDWR);
+ if (fd < 0) {
+ ALOGE("can't open /dev/tpa2051d3 %d", fd);
+ return -1;
+ }
+
+ if (tpa_mode != cur_tpa_mode) {
+ cur_tpa_mode = tpa_mode;
+ rc = ioctl(fd, TPA2051_SET_MODE, &tpa_mode);
+ if (rc < 0)
+ ALOGE("ioctl TPA2051_SET_MODE failed: %s", strerror(errno));
+ else
+ ALOGD("update TPA2051_SET_MODE to mode %d success", tpa_mode);
+ }
+
+ close(fd);
+ return 0;
+}
+#endif
+
+static status_t do_route_audio_rpc(uint32_t device,
+ int mode, bool mic_mute)
+{
+ if(device == -1)
+ return 0;
+
+ int new_rx_device = INVALID_DEVICE,new_tx_device = INVALID_DEVICE,fm_device = INVALID_DEVICE;
+ Routing_table* temp = NULL;
+ ALOGV("do_route_audio_rpc(%d, %d, %d)", device, mode, mic_mute);
+
+ if(device == SND_DEVICE_HANDSET) {
+ new_rx_device = DEVICE_HANDSET_RX;
+ new_tx_device = DEVICE_HANDSET_TX;
+ ALOGV("In HANDSET");
+ }
+ else if(device == SND_DEVICE_SPEAKER) {
+ new_rx_device = DEVICE_SPEAKER_RX;
+ new_tx_device = DEVICE_SPEAKER_TX;
+ ALOGV("In SPEAKER");
+ }
+ else if(device == SND_DEVICE_HEADSET) {
+ new_rx_device = DEVICE_HEADSET_RX;
+ new_tx_device = DEVICE_HEADSET_TX;
+ ALOGV("In HEADSET");
+ }
+ else if(device == SND_DEVICE_NO_MIC_HEADSET) {
+ new_rx_device = DEVICE_HEADSET_RX;
+ new_tx_device = DEVICE_HANDSET_TX;
+ ALOGV("In NO MIC HEADSET");
+ }
+#ifdef QCOM_FM_ENABLED
+ else if (device == SND_DEVICE_FM_HANDSET) {
+ fm_device = DEVICE_FMRADIO_HANDSET_RX;
+ ALOGV("In FM HANDSET");
+ }
+ else if(device == SND_DEVICE_FM_SPEAKER) {
+ fm_device = DEVICE_FMRADIO_SPEAKER_RX;
+ ALOGV("In FM SPEAKER");
+ }
+ else if(device == SND_DEVICE_FM_HEADSET) {
+ fm_device = DEVICE_FMRADIO_HEADSET_RX;
+ ALOGV("In FM HEADSET");
+ }
+#endif
+#ifdef SAMSUNG_AUDIO
+ else if(device == SND_DEVICE_IN_S_SADC_OUT_HANDSET) {
+ new_rx_device = DEVICE_HANDSET_CALL_RX;
+ new_tx_device = DEVICE_DUALMIC_HANDSET_TX;
+ ALOGV("In DUALMIC_CALL_HANDSET");
+ if(DEV_ID(new_tx_device) == INVALID_DEVICE) {
+ new_tx_device = DEVICE_HANDSET_CALL_TX;
+ ALOGV("Falling back to HANDSET_CALL_RX AND HANDSET_CALL_TX as no DUALMIC_HANDSET_TX support found");
+ }
+ }
+#else
+ else if(device == SND_DEVICE_IN_S_SADC_OUT_HANDSET) {
+ new_rx_device = DEVICE_HANDSET_RX;
+ new_tx_device = DEVICE_DUALMIC_HANDSET_TX;
+ ALOGV("In DUALMIC_HANDSET");
+ if(DEV_ID(new_tx_device) == INVALID_DEVICE) {
+ new_tx_device = DEVICE_HANDSET_TX;
+ ALOGV("Falling back to HANDSET_RX AND HANDSET_TX as no DUALMIC_HANDSET_TX support found");
+ }
+ }
+#endif
+ else if(device == SND_DEVICE_IN_S_SADC_OUT_SPEAKER_PHONE) {
+ new_rx_device = DEVICE_SPEAKER_RX;
+ new_tx_device = DEVICE_DUALMIC_SPEAKER_TX;
+ ALOGV("In DUALMIC_SPEAKER");
+ if(DEV_ID(new_tx_device) == INVALID_DEVICE) {
+ new_tx_device = DEVICE_SPEAKER_TX;
+ ALOGV("Falling back to SPEAKER_RX AND SPEAKER_TX as no DUALMIC_SPEAKER_TX support found");
+ }
+ }
+ else if(device == SND_DEVICE_TTY_FULL) {
+ new_rx_device = DEVICE_TTY_HEADSET_MONO_RX;
+ new_tx_device = DEVICE_TTY_HEADSET_MONO_TX;
+ ALOGV("In TTY_FULL");
+ }
+ else if(device == SND_DEVICE_TTY_VCO) {
+ new_rx_device = DEVICE_TTY_HEADSET_MONO_RX;
+ new_tx_device = DEVICE_HANDSET_TX;
+ ALOGV("In TTY_VCO");
+ }
+ else if(device == SND_DEVICE_TTY_HCO) {
+ new_rx_device = DEVICE_HANDSET_RX;
+ new_tx_device = DEVICE_TTY_HEADSET_MONO_TX;
+ ALOGV("In TTY_HCO");
+ }
+#ifdef HTC_ACOUSTIC_AUDIO
+ else if((device == SND_DEVICE_BT) ||
+ (device == SND_DEVICE_BT_EC_OFF)) {
+#else
+ else if(device == SND_DEVICE_BT) {
+#endif
+ new_rx_device = DEVICE_BT_SCO_RX;
+ new_tx_device = DEVICE_BT_SCO_TX;
+ ALOGV("In BT_HCO");
+ }
+ else if(device == SND_DEVICE_HEADSET_AND_SPEAKER) {
+ new_rx_device = DEVICE_SPEAKER_HEADSET_RX;
+ new_tx_device = DEVICE_HEADSET_TX;
+ ALOGV("In DEVICE_SPEAKER_HEADSET_RX and DEVICE_HEADSET_TX");
+ if(DEV_ID(new_rx_device) == INVALID_DEVICE) {
+ new_rx_device = DEVICE_HEADSET_RX;
+ ALOGV("Falling back to HEADSET_RX AND HEADSET_TX as no combo device support found");
+ }
+ }
+ else if(device == SND_DEVICE_HEADPHONE_AND_SPEAKER) {
+ new_rx_device = DEVICE_SPEAKER_HEADSET_RX;
+ new_tx_device = DEVICE_HANDSET_TX;
+ ALOGV("In DEVICE_SPEAKER_HEADSET_RX and DEVICE_HANDSET_TX");
+ if(DEV_ID(new_rx_device) == INVALID_DEVICE) {
+ new_rx_device = DEVICE_HEADSET_RX;
+ ALOGV("Falling back to HEADSET_RX AND HANDSET_TX as no combo device support found");
+ }
+ }
+ else if (device == SND_DEVICE_HDMI) {
+ new_rx_device = DEVICE_HDMI_STERO_RX;
+ new_tx_device = cur_tx;
+ ALOGI("In DEVICE_HDMI_STERO_RX and cur_tx");
+ }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ else if(device == SND_DEVICE_ANC_HEADSET) {
+ new_rx_device = DEVICE_ANC_HEADSET_STEREO_RX;
+ new_tx_device = DEVICE_HEADSET_TX;
+ ALOGI("In ANC HEADSET");
+ }
+ else if(device == SND_DEVICE_NO_MIC_ANC_HEADSET) {
+ new_rx_device = DEVICE_ANC_HEADSET_STEREO_RX;
+ new_tx_device = DEVICE_HANDSET_TX;
+ ALOGI("In ANC HEADPhone");
+ }
+#endif
+#ifdef QCOM_FM_ENABLED
+ else if(device == SND_DEVICE_FM_TX){
+ new_rx_device = DEVICE_FMRADIO_STEREO_RX;
+ ALOGI("In DEVICE_FMRADIO_STEREO_RX and cur_tx");
+ }
+#endif
+ else if(device == SND_DEVICE_SPEAKER_TX) {
+ new_rx_device = cur_rx;
+ new_tx_device = DEVICE_SPEAKER_TX;
+ ALOGI("In SPEAKER_TX cur_rx = %d\n", cur_rx);
+ }
+#ifdef SAMSUNG_AUDIO
+#if 0
+ else if (device == SND_DEVICE_VOIP_HANDSET) {
+ new_rx_device = DEVICE_HANDSET_VOIP_RX;
+ new_tx_device = DEVICE_HANDSET_VOIP_TX;
+ ALOGD("In VOIP HANDSET");
+ }
+ else if (device == SND_DEVICE_VOIP_SPEAKER) {
+ new_rx_device = DEVICE_SPEAKER_VOIP_RX;
+ new_tx_device = DEVICE_SPEAKER_VOIP_TX;
+ ALOGD("In VOIP SPEAKER");
+ }
+ else if (device == SND_DEVICE_VOIP_HEADSET) {
+ new_rx_device = DEVICE_HEADSET_VOIP_RX;
+ new_tx_device = DEVICE_HEADSET_VOIP_TX;
+ ALOGD("In VOIP HEADSET");
+ }
+#endif
+ else if (device == SND_DEVICE_CALL_HANDSET) {
+ new_rx_device = DEVICE_HANDSET_CALL_RX;
+ new_tx_device = DEVICE_HANDSET_CALL_TX;
+ ALOGD("In CALL HANDSET");
+ }
+ else if (device == SND_DEVICE_CALL_SPEAKER) {
+ new_rx_device = DEVICE_SPEAKER_CALL_RX;
+ new_tx_device = DEVICE_SPEAKER_CALL_TX;
+ ALOGD("In CALL SPEAKER");
+ }
+ else if (device == SND_DEVICE_CALL_HEADSET) {
+ new_rx_device = DEVICE_HEADSET_CALL_RX;
+ new_tx_device = DEVICE_HEADSET_CALL_TX;
+ ALOGD("In CALL HEADSET");
+ }
+ else if(device == SND_DEVICE_VR_SPEAKER) {
+ new_rx_device = DEVICE_SPEAKER_RX;
+ new_tx_device = DEVICE_SPEAKER_VR_TX;
+ ALOGV("In VR SPEAKER");
+ }
+ else if(device == SND_DEVICE_VR_HEADSET) {
+ new_rx_device = DEVICE_HEADSET_RX;
+ new_tx_device = DEVICE_HEADSET_VR_TX;
+ ALOGV("In VR HEADSET");
+ }
+#endif
+#ifdef BACK_MIC_CAMCORDER
+ else if (device == SND_DEVICE_BACK_MIC_CAMCORDER) {
+ new_rx_device = cur_rx;
+ new_tx_device = DEVICE_CAMCORDER_TX;
+ ALOGV("In BACK_MIC_CAMCORDER");
+ }
+#endif
+ if(new_rx_device != INVALID_DEVICE)
+ ALOGD("new_rx = %d", DEV_ID(new_rx_device));
+ if(new_tx_device != INVALID_DEVICE)
+ ALOGD("new_tx = %d", DEV_ID(new_tx_device));
+
+ if ((mode == AudioSystem::MODE_IN_CALL) && !isStreamOn(VOICE_CALL)) {
+#ifdef LEGACY_QCOM_VOICE
+ msm_start_voice();
+#endif
+ ALOGV("Going to enable RX/TX device for voice stream");
+ // Routing Voice
+ if ( (new_rx_device != INVALID_DEVICE) && (new_tx_device != INVALID_DEVICE))
+ {
+#ifdef QCOM_ACDB_ENABLED
+ initACDB();
+ acdb_loader_send_voice_cal(ACDB_ID(new_rx_device),ACDB_ID(new_tx_device));
+#endif
+ ALOGD("Starting voice on Rx %d and Tx %d device", DEV_ID(new_rx_device), DEV_ID(new_tx_device));
+ msm_route_voice(DEV_ID(new_rx_device),DEV_ID(new_tx_device), 1);
+ }
+ else
+ {
+ return -1;
+ }
+
+ if(cur_rx != INVALID_DEVICE && (enableDevice(cur_rx,0) == -1))
+ return -1;
+
+ if(cur_tx != INVALID_DEVICE&&(enableDevice(cur_tx,0) == -1))
+ return -1;
+
+ //Enable RX device
+ if(new_rx_device !=INVALID_DEVICE && (enableDevice(new_rx_device,1) == -1))
+ return -1;
+ //Enable TX device
+ if(new_tx_device !=INVALID_DEVICE && (enableDevice(new_tx_device,1) == -1))
+ return -1;
+#ifdef LEGACY_QCOM_VOICE
+ msm_set_voice_tx_mute(0);
+#else
+ voice_session_id = msm_get_voc_session(VOICE_SESSION_NAME);
+ if(voice_session_id <=0) {
+ ALOGE("voice session invalid");
+ return 0;
+ }
+ msm_start_voice_ext(voice_session_id);
+ msm_set_voice_tx_mute_ext(voice_session_mute,voice_session_id);
+#endif
+
+ if(!isDeviceListEmpty())
+ updateDeviceInfo(new_rx_device,new_tx_device);
+ cur_rx = new_rx_device;
+ cur_tx = new_tx_device;
+ addToTable(0,cur_rx,cur_tx,VOICE_CALL,true);
+ }
+ else if ((mode == AudioSystem::MODE_NORMAL) && isStreamOnAndActive(VOICE_CALL)) {
+ ALOGV("Going to disable RX/TX device during end of voice call");
+ temp = getNodeByStreamType(VOICE_CALL);
+ if(temp == NULL)
+ return 0;
+
+ // Ending voice call
+ ALOGD("Ending Voice call");
+#ifdef LEGACY_QCOM_VOICE
+ msm_end_voice();
+#else
+ msm_end_voice_ext(voice_session_id);
+ voice_session_id = 0;
+ voice_session_mute = 0;
+#endif
+
+ if((temp->dev_id != INVALID_DEVICE && temp->dev_id_tx != INVALID_DEVICE)
+#ifdef QCOM_VOIP_ENABLED
+ && (!isStreamOn(VOIP_CALL))
+#endif
+ ) {
+ enableDevice(temp->dev_id,0);
+ enableDevice(temp->dev_id_tx,0);
+ }
+ deleteFromTable(VOICE_CALL);
+ updateDeviceInfo(new_rx_device,new_tx_device);
+ if(new_rx_device != INVALID_DEVICE && new_tx_device != INVALID_DEVICE) {
+ cur_rx = new_rx_device;
+ cur_tx = new_tx_device;
+ }
+ }
+ else {
+ ALOGD("updateDeviceInfo() called for default case");
+ updateDeviceInfo(new_rx_device,new_tx_device);
+ }
+#ifdef HTC_ACOUSTIC_AUDIO
+ if (support_tpa2051)
+ do_tpa2051_control(mode ^1);
+#endif
+ return NO_ERROR;
+}
+
+// always call with mutex held
+status_t AudioHardware::doAudioRouteOrMute(uint32_t device)
+{
+// BT acoustics is not supported. This might be used by OEMs. Hence commenting
+// the code and not removing it.
+#if 0
+ if (device == (uint32_t)SND_DEVICE_BT || device == (uint32_t)SND_DEVICE_CARKIT) {
+ if (mBluetoothId) {
+ device = mBluetoothId;
+ } else if (!mBluetoothNrec) {
+ device = SND_DEVICE_BT_EC_OFF;
+ }
+ }
+#endif
+
+#ifdef HTC_ACOUSTIC_AUDIO
+ if (device == SND_DEVICE_BT) {
+ if (!mBluetoothNrec)
+ device = SND_DEVICE_BT_EC_OFF;
+ }
+
+ if (support_aic3254) {
+ aic3254_config(device);
+ do_aic3254_control(device);
+ }
+
+ getACDB(device);
+#endif
+
+ if (isStreamOnAndActive(VOICE_CALL) && mMicMute == false)
+ msm_set_voice_tx_mute(0);
+
+#ifdef HTC_ACOUSTIC_AUDIO
+ if (isInCall())
+ setVoiceVolume(mVoiceVolume);
+#endif
+ ALOGV("doAudioRouteOrMute() device %x, mMode %d, mMicMute %d", device, mMode, mMicMute);
+ return do_route_audio_rpc(device, mMode, mMicMute);
+}
+
+#ifdef HTC_ACOUSTIC_AUDIO
+status_t AudioHardware::set_mRecordState(bool onoff) {
+ mRecordState = onoff;
+ return 0;
+}
+
+status_t AudioHardware::get_mRecordState(void) {
+ return mRecordState;
+}
+
+status_t AudioHardware::get_snd_dev(void) {
+ return mCurSndDevice;
+}
+
+void AudioHardware::getACDB(uint32_t device) {
+ rx_htc_acdb = 0;
+ tx_htc_acdb = 0;
+
+ if (device == SND_DEVICE_BT) {
+ if (mBluetoothIdTx != 0) {
+ rx_htc_acdb = mBluetoothIdRx;
+ tx_htc_acdb = mBluetoothIdTx;
+ } else {
+ /* use default BT entry defined in AudioBTID.csv */
+ rx_htc_acdb = mBTEndpoints[0].rx;
+ tx_htc_acdb = mBTEndpoints[0].tx;
+ }
+ } else if (device == SND_DEVICE_CARKIT ||
+ device == SND_DEVICE_BT_EC_OFF) {
+ if (mBluetoothIdTx != 0) {
+ rx_htc_acdb = mBluetoothIdRx;
+ tx_htc_acdb = mBluetoothIdTx;
+ } else {
+ /* use default carkit entry defined in AudioBTID.csv */
+ rx_htc_acdb = mBTEndpoints[1].rx;
+ tx_htc_acdb = mBTEndpoints[1].tx;
+ }
+ }
+
+ ALOGV("getACDB: device = %d, HTC RX ACDB ID = %d, HTC TX ACDB ID = %d",
+ device, rx_htc_acdb, tx_htc_acdb);
+}
+
+status_t AudioHardware::do_aic3254_control(uint32_t device) {
+ ALOGD("do_aic3254_control device: %d mode: %d record: %d", device, mMode, mRecordState);
+
+ uint32_t new_aic_txmode = UPLINK_OFF;
+ uint32_t new_aic_rxmode = DOWNLINK_OFF;
+
+ Mutex::Autolock lock(mAIC3254ConfigLock);
+
+ if (isInCall()) {
+ switch (device) {
+ case SND_DEVICE_HEADSET:
+ new_aic_rxmode = CALL_DOWNLINK_EMIC_HEADSET;
+ new_aic_txmode = CALL_UPLINK_EMIC_HEADSET;
+ break;
+ case SND_DEVICE_SPEAKER:
+ case SND_DEVICE_SPEAKER_BACK_MIC:
+ new_aic_rxmode = CALL_DOWNLINK_IMIC_SPEAKER;
+ new_aic_txmode = CALL_UPLINK_IMIC_SPEAKER;
+ break;
+ case SND_DEVICE_HEADSET_AND_SPEAKER:
+ case SND_DEVICE_HEADSET_AND_SPEAKER_BACK_MIC:
+ new_aic_rxmode = RING_HEADSET_SPEAKER;
+ break;
+ case SND_DEVICE_NO_MIC_HEADSET:
+ case SND_DEVICE_NO_MIC_HEADSET_BACK_MIC:
+ new_aic_rxmode = CALL_DOWNLINK_IMIC_HEADSET;
+ new_aic_txmode = CALL_UPLINK_IMIC_HEADSET;
+ break;
+ case SND_DEVICE_HANDSET:
+ case SND_DEVICE_HANDSET_BACK_MIC:
+ new_aic_rxmode = CALL_DOWNLINK_IMIC_RECEIVER;
+ new_aic_txmode = CALL_UPLINK_IMIC_RECEIVER;
+ break;
+ default:
+ break;
+ }
+ } else {
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+ if (checkOutputStandby() && !isStreamOnAndActive(LPA_DECODE)) {
+#else
+ if (checkOutputStandby()) {
+#endif
+ if (device == SND_DEVICE_FM_HEADSET) {
+ new_aic_rxmode = FM_OUT_HEADSET;
+ new_aic_txmode = FM_IN_HEADSET;
+ } else if (device == SND_DEVICE_FM_SPEAKER) {
+ new_aic_rxmode = FM_OUT_SPEAKER;
+ new_aic_txmode = FM_IN_SPEAKER;
+ }
+ } else {
+ switch (device) {
+ case SND_DEVICE_HEADSET_AND_SPEAKER:
+ case SND_DEVICE_HEADSET_AND_SPEAKER_BACK_MIC:
+ case SND_DEVICE_HEADPHONE_AND_SPEAKER:
+ new_aic_rxmode = RING_HEADSET_SPEAKER;
+ break;
+ case SND_DEVICE_SPEAKER:
+ case SND_DEVICE_SPEAKER_BACK_MIC:
+ new_aic_rxmode = PLAYBACK_SPEAKER;
+ break;
+ case SND_DEVICE_HANDSET:
+ case SND_DEVICE_HANDSET_BACK_MIC:
+ new_aic_rxmode = PLAYBACK_RECEIVER;
+ break;
+ case SND_DEVICE_HEADSET:
+ case SND_DEVICE_NO_MIC_HEADSET:
+ case SND_DEVICE_NO_MIC_HEADSET_BACK_MIC:
+ new_aic_rxmode = PLAYBACK_HEADSET;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (mRecordState) {
+ switch (device) {
+ case SND_DEVICE_HEADSET:
+ new_aic_txmode = VOICERECORD_EMIC;
+ break;
+ case SND_DEVICE_HANDSET_BACK_MIC:
+ case SND_DEVICE_SPEAKER_BACK_MIC:
+ case SND_DEVICE_NO_MIC_HEADSET_BACK_MIC:
+ case SND_DEVICE_HEADSET_AND_SPEAKER_BACK_MIC:
+ new_aic_txmode = VIDEORECORD_IMIC;
+ break;
+ case SND_DEVICE_HANDSET:
+ case SND_DEVICE_SPEAKER:
+ case SND_DEVICE_NO_MIC_HEADSET:
+ case SND_DEVICE_HEADSET_AND_SPEAKER:
+ new_aic_txmode = VOICERECORD_IMIC;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (new_aic_rxmode != cur_aic_rx)
+ ALOGD("do_aic3254_control: set aic3254 rx to %d", new_aic_rxmode);
+ if (aic3254_ioctl(AIC3254_CONFIG_RX, new_aic_rxmode) >= 0)
+ cur_aic_rx = new_aic_rxmode;
+
+ if (new_aic_txmode != cur_aic_tx)
+ ALOGD("do_aic3254_control: set aic3254 tx to %d", new_aic_txmode);
+ if (aic3254_ioctl(AIC3254_CONFIG_TX, new_aic_txmode) >= 0)
+ cur_aic_tx = new_aic_txmode;
+
+ if (cur_aic_tx == UPLINK_OFF && cur_aic_rx == DOWNLINK_OFF && aic3254_enabled) {
+ strcpy(mCurDspProfile, "\0");
+ aic3254_enabled = false;
+ aic3254_powerdown();
+ } else if (cur_aic_tx != UPLINK_OFF || cur_aic_rx != DOWNLINK_OFF)
+ aic3254_enabled = true;
+
+ return NO_ERROR;
+}
+
+bool AudioHardware::isAic3254Device(uint32_t device) {
+ switch(device) {
+ case SND_DEVICE_HANDSET:
+ case SND_DEVICE_SPEAKER:
+ case SND_DEVICE_HEADSET:
+ case SND_DEVICE_NO_MIC_HEADSET:
+ case SND_DEVICE_FM_HEADSET:
+ case SND_DEVICE_HEADSET_AND_SPEAKER:
+ case SND_DEVICE_FM_SPEAKER:
+ case SND_DEVICE_HEADPHONE_AND_SPEAKER:
+ case SND_DEVICE_HANDSET_BACK_MIC:
+ case SND_DEVICE_SPEAKER_BACK_MIC:
+ case SND_DEVICE_NO_MIC_HEADSET_BACK_MIC:
+ case SND_DEVICE_HEADSET_AND_SPEAKER_BACK_MIC:
+ return true;
+ break;
+ default:
+ return false;
+ break;
+ }
+}
+
+status_t AudioHardware::aic3254_config(uint32_t device) {
+ ALOGD("aic3254_config: device %d enabled %d", device, aic3254_enabled);
+ char name[22] = "\0";
+ char aap[9] = "\0";
+
+ if ((!isAic3254Device(device) ||
+ !aic3254_enabled) &&
+ strlen(mCurDspProfile) != 0)
+ return NO_ERROR;
+
+ Mutex::Autolock lock(mAIC3254ConfigLock);
+
+ if (mMode == AudioSystem::MODE_IN_CALL) {
+ strcpy(name, "Phone_Default");
+ switch (device) {
+ case SND_DEVICE_HANDSET:
+ case SND_DEVICE_HANDSET_BACK_MIC:
+ strcpy(name, "Phone_Handset_Dualmic");
+ break;
+ case SND_DEVICE_HEADSET:
+ case SND_DEVICE_HEADSET_AND_SPEAKER:
+ case SND_DEVICE_HEADSET_AND_SPEAKER_BACK_MIC:
+ case SND_DEVICE_NO_MIC_HEADSET:
+ strcpy(name, "Phone_Headset");
+ break;
+ case SND_DEVICE_SPEAKER:
+ strcpy(name, "Phone_Speaker_Dualmic");
+ break;
+ default:
+ break;
+ }
+ } else {
+ if ((strcasecmp(mActiveAP, "Camcorder") == 0)) {
+ if (strlen(mEffect) != 0) {
+ strcpy(name, "Recording_");
+ strcat(name, mEffect);
+ } else
+ strcpy(name, "Playback_Default");
+ } else if (mRecordState) {
+ strcpy(name, "Record_Default");
+ } else if (strlen(mEffect) == 0 && !mEffectEnabled)
+ strcpy(name, "Playback_Default");
+ else {
+ if (mEffectEnabled)
+ strcpy(name, mEffect);
+
+ if ((strcasecmp(name, "Srs") == 0) ||
+ (strcasecmp(name, "Dolby") == 0)) {
+ strcpy(mEffect, name);
+ if (strcasecmp(mActiveAP, "Music") == 0)
+ strcat(name, "_a");
+ else if (strcasecmp(mActiveAP, "Video") == 0)
+ strcat(name, "_v");
+ if (device == SND_DEVICE_SPEAKER)
+ strcat(name, "_spk");
+ else
+ strcat(name, "_hp");
+ }
+ }
+ }
+
+ if (strcasecmp(mCurDspProfile, name)) {
+ ALOGD("aic3254_config: loading effect %s", name);
+ strcpy(mCurDspProfile, name);
+ } else {
+ ALOGD("aic3254_config: effect %s already loaded", name);
+ return NO_ERROR;
+ }
+
+ int rc = set_sound_effect(name);
+ if (rc < 0) {
+ ALOGE("Could not set sound effect %s: %d", name, rc);
+ return rc;
+ }
+
+ return NO_ERROR;
+}
+
+int AudioHardware::aic3254_ioctl(int cmd, const int argc) {
+ int rc = -1;
+ int (*set_aic3254_ioctl)(int, const int*);
+
+ set_aic3254_ioctl = (int (*)(int, const int*))::dlsym(acoustic, "set_aic3254_ioctl");
+ if ((*set_aic3254_ioctl) == 0) {
+ ALOGE("Could not open set_aic3254_ioctl()");
+ return rc;
+ }
+
+ rc = set_aic3254_ioctl(cmd, &argc);
+ if (rc < 0)
+ ALOGE("aic3254_ioctl failed");
+
+ return rc;
+}
+
+void AudioHardware::aic3254_powerdown() {
+ int rc = aic3254_ioctl(AIC3254_POWERDOWN, 0);
+ if (rc < 0)
+ ALOGE("aic3254_powerdown failed");
+ else
+ ALOGI("aic3254 powered off");
+}
+#endif
+
+status_t AudioHardware::doRouting(AudioStreamInMSM8x60 *input)
+{
+ Mutex::Autolock lock(mLock);
+ uint32_t outputDevices = mOutput->devices();
+ status_t ret = NO_ERROR;
+ int audProcess = (ADRC_DISABLE | EQ_DISABLE | RX_IIR_DISABLE);
+ int sndDevice = -1;
+
+
+
+ if (input != NULL) {
+ uint32_t inputDevice = input->devices();
+ ALOGI("do input routing device %x\n", inputDevice);
+ // ignore routing device information when we start a recording in voice
+ // call
+ // Recording will happen through currently active tx device
+ if((inputDevice == AudioSystem::DEVICE_IN_VOICE_CALL)
+#ifdef QCOM_FM_ENABLED
+ || (inputDevice == AudioSystem::DEVICE_IN_FM_RX)
+ || (inputDevice == AudioSystem::DEVICE_IN_FM_RX_A2DP)
+#endif
+ )
+ return NO_ERROR;
+ if (inputDevice != 0) {
+ if (inputDevice & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ ALOGI("Routing audio to Bluetooth PCM\n");
+ sndDevice = SND_DEVICE_BT;
+#ifdef BACK_MIC_CAMCORDER
+ } else if (inputDevice & AudioSystem::DEVICE_IN_BACK_MIC) {
+ ALOGI("Routing audio to back mic (camcorder)");
+ sndDevice = SND_DEVICE_BACK_MIC_CAMCORDER;
+#endif
+ } else if (inputDevice & AudioSystem::DEVICE_IN_WIRED_HEADSET) {
+ if ((outputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) &&
+ (outputDevices & AudioSystem::DEVICE_OUT_SPEAKER)) {
+ ALOGI("Routing audio to Wired Headset and Speaker\n");
+ sndDevice = SND_DEVICE_HEADSET_AND_SPEAKER;
+ audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+ } else {
+ ALOGI("Routing audio to Wired Headset\n");
+ sndDevice = SND_DEVICE_HEADSET;
+ }
+ }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ else if (inputDevice & AudioSystem::DEVICE_IN_ANC_HEADSET) {
+ ALOGI("Routing audio to ANC Headset\n");
+ sndDevice = SND_DEVICE_ANC_HEADSET;
+ }
+#endif
+ else if (isStreamOnAndActive(PCM_PLAY)
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+ || isStreamOnAndActive(LPA_DECODE)
+#endif
+ ) {
+ if (outputDevices & AudioSystem::DEVICE_OUT_EARPIECE) {
+ ALOGI("Routing audio to Handset\n");
+ sndDevice = SND_DEVICE_HANDSET;
+ } else if (outputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) {
+ ALOGI("Routing audio to Speakerphone\n");
+ sndDevice = SND_DEVICE_NO_MIC_HEADSET;
+ }
+#ifdef QCOM_FM_ENABLED
+ else if (outputDevices & AudioSystem::DEVICE_OUT_FM_TX) {
+ ALOGE("Routing audio_rx to Speaker\n");
+ sndDevice = SND_DEVICE_SPEAKER_TX;
+ }
+#endif
+ else {
+ ALOGI("Routing audio to Speaker\n");
+ sndDevice = SND_DEVICE_SPEAKER;
+ }
+ } else {
+ ALOGI("Routing audio to Speaker (default)\n");
+ sndDevice = SND_DEVICE_SPEAKER;
+ }
+#ifdef SAMSUNG_AUDIO
+ if (input->isForVR()) {
+ if (sndDevice == SND_DEVICE_SPEAKER)
+ sndDevice = SND_DEVICE_VR_SPEAKER;
+ else if (sndDevice == SND_DEVICE_HEADSET)
+ sndDevice = SND_DEVICE_VR_HEADSET;
+ }
+#endif
+ }
+ // if inputDevice == 0, restore output routing
+ }
+
+ if (sndDevice == -1) {
+ if (outputDevices & (outputDevices - 1)) {
+ if ((outputDevices & AudioSystem::DEVICE_OUT_SPEAKER) == 0) {
+ ALOGW("Hardware does not support requested route combination (%#X),"
+ " picking closest possible route...", outputDevices);
+ }
+ }
+ if ((mTtyMode != TTY_OFF) && (mMode == AudioSystem::MODE_IN_CALL) &&
+ ((outputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET)
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ ||(outputDevices & AudioSystem::DEVICE_OUT_ANC_HEADSET)
+#endif
+ )) {
+ if (mTtyMode == TTY_FULL) {
+ ALOGI("Routing audio to TTY FULL Mode\n");
+ sndDevice = SND_DEVICE_TTY_FULL;
+ } else if (mTtyMode == TTY_VCO) {
+ ALOGI("Routing audio to TTY VCO Mode\n");
+ sndDevice = SND_DEVICE_TTY_VCO;
+ } else if (mTtyMode == TTY_HCO) {
+ ALOGI("Routing audio to TTY HCO Mode\n");
+ sndDevice = SND_DEVICE_TTY_HCO;
+ }
+ } else if (outputDevices &
+ (AudioSystem::DEVICE_OUT_BLUETOOTH_SCO | AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET)) {
+ ALOGI("Routing audio to Bluetooth PCM\n");
+ sndDevice = SND_DEVICE_BT;
+ } else if (outputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
+ ALOGI("Routing audio to Bluetooth PCM\n");
+ sndDevice = SND_DEVICE_CARKIT;
+ } else if (outputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
+ ALOGI("Routing audio to HDMI\n");
+ sndDevice = SND_DEVICE_HDMI;
+ } else if ((outputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) &&
+ (outputDevices & AudioSystem::DEVICE_OUT_SPEAKER)) {
+ ALOGI("Routing audio to Wired Headset and Speaker\n");
+ sndDevice = SND_DEVICE_HEADSET_AND_SPEAKER;
+ audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+ } else
+#ifdef QCOM_FM_ENABLED
+ if ((outputDevices & AudioSystem::DEVICE_OUT_FM_TX) &&
+ (outputDevices & AudioSystem::DEVICE_OUT_SPEAKER)) {
+ ALOGI("Routing audio to FM Tx and Speaker\n");
+ sndDevice = SND_DEVICE_FM_TX_AND_SPEAKER;
+ enableComboDevice(sndDevice,1);
+ audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+ } else
+#endif
+ if (outputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) {
+ if (outputDevices & AudioSystem::DEVICE_OUT_SPEAKER) {
+ ALOGI("Routing audio to No microphone Wired Headset and Speaker (%d,%x)\n", mMode, outputDevices);
+ sndDevice = SND_DEVICE_HEADPHONE_AND_SPEAKER;
+ audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+ } else {
+ ALOGI("Routing audio to No microphone Wired Headset (%d,%x)\n", mMode, outputDevices);
+ sndDevice = SND_DEVICE_NO_MIC_HEADSET;
+ audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+ }
+ }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ else if (outputDevices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE) {
+ ALOGI("Routing audio to No microphone ANC Headset (%d,%x)\n", mMode, outputDevices);
+ sndDevice = SND_DEVICE_NO_MIC_ANC_HEADSET;
+ audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+ }
+#endif
+ else if (outputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) {
+ ALOGI("Routing audio to Wired Headset\n");
+ sndDevice = SND_DEVICE_HEADSET;
+ audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+ }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ else if (outputDevices & AudioSystem::DEVICE_OUT_ANC_HEADSET) {
+ ALOGI("Routing audio to ANC Headset\n");
+ sndDevice = SND_DEVICE_ANC_HEADSET;
+ audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+ }
+#endif
+ else if (outputDevices & AudioSystem::DEVICE_OUT_SPEAKER) {
+ ALOGI("Routing audio to Speakerphone\n");
+ sndDevice = SND_DEVICE_SPEAKER;
+ audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+ } else
+#ifdef QCOM_FM_ENABLED
+ if (outputDevices & AudioSystem::DEVICE_OUT_FM_TX){
+ ALOGI("Routing audio to FM Tx Device\n");
+ sndDevice = SND_DEVICE_FM_TX;
+ audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+ } else
+#endif
+ if(outputDevices & AudioSystem::DEVICE_OUT_EARPIECE){
+ ALOGI("Routing audio to Handset\n");
+ sndDevice = SND_DEVICE_HANDSET;
+ audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE | MBADRC_ENABLE);
+ }
+ }
+
+ if (dualmic_enabled) {
+#ifdef SAMSUNG_AUDIO
+ if (sndDevice == SND_DEVICE_HANDSET) {
+ ALOGI("Routing audio to Handset with DualMike enabled\n");
+ sndDevice = SND_DEVICE_IN_S_SADC_OUT_HANDSET;
+ }
+#else
+ if (sndDevice == SND_DEVICE_HANDSET) {
+ ALOGI("Routing audio to Handset with DualMike enabled\n");
+ sndDevice = SND_DEVICE_IN_S_SADC_OUT_HANDSET;
+ } else if (sndDevice == SND_DEVICE_SPEAKER) {
+ ALOGI("Routing audio to Speakerphone with DualMike enabled\n");
+ sndDevice = SND_DEVICE_IN_S_SADC_OUT_SPEAKER_PHONE;
+ }
+#endif
+ }
+
+#ifdef SAMSUNG_AUDIO
+ if (mMode == AudioSystem::MODE_IN_CALL) {
+ if ((!dualmic_enabled) && (sndDevice == SND_DEVICE_HANDSET)) {
+ ALOGD("Routing audio to Call Handset\n");
+ sndDevice = SND_DEVICE_CALL_HANDSET;
+ } else if (sndDevice == SND_DEVICE_SPEAKER) {
+ ALOGD("Routing audio to Call Speaker\n");
+ sndDevice = SND_DEVICE_CALL_SPEAKER;
+ } else if (sndDevice == SND_DEVICE_HEADSET) {
+ ALOGD("Routing audio to Call Headset\n");
+ sndDevice = SND_DEVICE_CALL_HEADSET;
+ }
+#if 0
+ } else if (mMode == AudioSystem::MODE_IN_COMMUNICATION) {
+ if (sndDevice == SND_DEVICE_HANDSET) {
+ ALOGD("Routing audio to VOIP handset\n");
+ sndDevice = SND_DEVICE_VOIP_HANDSET;
+ } else if (sndDevice == SND_DEVICE_SPEAKER) {
+ ALOGD("Routing audio to VOIP speaker\n");
+ sndDevice = SND_DEVICE_VOIP_SPEAKER;
+ } else if (sndDevice == SND_DEVICE_HEADSET) {
+ ALOGD("Routing audio to VOIP headset\n");
+ sndDevice = SND_DEVICE_VOIP_HEADSET;
+ }
+#endif
+ }
+#endif
+
+#ifdef QCOM_FM_ENABLED
+ if ((outputDevices & AudioSystem::DEVICE_OUT_FM) && (mFmFd == -1)){
+ enableFM(sndDevice);
+ }
+ if ((mFmFd != -1) && !(outputDevices & AudioSystem::DEVICE_OUT_FM)){
+ disableFM();
+ }
+
+ if ((CurrentComboDeviceData.DeviceId == INVALID_DEVICE) &&
+ (sndDevice == SND_DEVICE_FM_TX_AND_SPEAKER )){
+ /* speaker rx is already enabled change snd device to the fm tx
+ * device and let the flow take the regular route to
+ * updatedeviceinfo().
+ */
+ Mutex::Autolock lock_1(mComboDeviceLock);
+
+ CurrentComboDeviceData.DeviceId = SND_DEVICE_FM_TX_AND_SPEAKER;
+ sndDevice = DEVICE_FMRADIO_STEREO_RX;
+ }
+ else
+#endif
+ if(CurrentComboDeviceData.DeviceId != INVALID_DEVICE){
+ /* time to disable the combo device */
+ enableComboDevice(CurrentComboDeviceData.DeviceId,0);
+ Mutex::Autolock lock_2(mComboDeviceLock);
+ CurrentComboDeviceData.DeviceId = INVALID_DEVICE;
+ CurrentComboDeviceData.StreamType = INVALID_STREAM;
+ }
+
+ if (sndDevice != -1 && sndDevice != mCurSndDevice) {
+ ret = doAudioRouteOrMute(sndDevice);
+ mCurSndDevice = sndDevice;
+ }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ //check if ANC setting is ON
+ if (anc_setting == true
+ && (sndDevice == SND_DEVICE_ANC_HEADSET
+ || sndDevice ==SND_DEVICE_NO_MIC_ANC_HEADSET)) {
+ enableANC(1,sndDevice);
+ anc_running = true;
+ } else {
+ //disconnection case
+ anc_running = false;
+ }
+#endif
+ return ret;
+}
+
+status_t AudioHardware::enableComboDevice(uint32_t sndDevice, bool enableOrDisable)
+{
+ ALOGD("enableComboDevice %u",enableOrDisable);
+ status_t status = NO_ERROR;
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+ Routing_table *LpaNode = getNodeByStreamType(LPA_DECODE);
+#endif
+ Routing_table *PcmNode = getNodeByStreamType(PCM_PLAY);
+
+ if(enableDevice(DEVICE_SPEAKER_RX, enableOrDisable)) {
+ ALOGE("enableDevice failed for device %d", DEVICE_SPEAKER_RX);
+ return -1;
+ }
+#ifdef QCOM_FM_ENABLED
+ if(SND_DEVICE_FM_TX_AND_SPEAKER == sndDevice){
+
+ if(getNodeByStreamType(VOICE_CALL) || getNodeByStreamType(FM_RADIO) ||
+ getNodeByStreamType(FM_A2DP)){
+ ALOGE("voicecall/FM radio active bailing out");
+ return NO_ERROR;
+ }
+
+ if(
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+ !LpaNode &&
+#endif
+ !PcmNode) {
+ ALOGE("No active playback session active bailing out ");
+ cur_rx = DEVICE_FMRADIO_STEREO_RX;
+ return NO_ERROR;
+ }
+
+ Mutex::Autolock lock_1(mComboDeviceLock);
+
+ Routing_table* temp = NULL;
+
+ if (enableOrDisable == 1) {
+ if(CurrentComboDeviceData.StreamType == INVALID_STREAM){
+ if (PcmNode){
+ temp = PcmNode;
+ CurrentComboDeviceData.StreamType = PCM_PLAY;
+ ALOGD("PCM_PLAY session Active ");
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+ }else if(LpaNode){
+ temp = LpaNode;
+ CurrentComboDeviceData.StreamType = LPA_DECODE;
+ ALOGD("LPA_DECODE session Active ");
+#endif
+ } else {
+ ALOGE("no PLAYback session Active ");
+ return -1;
+ }
+ }else
+ temp = getNodeByStreamType(CurrentComboDeviceData.StreamType);
+
+ if(temp == NULL){
+ ALOGE("speaker de-route not possible");
+ return -1;
+ }
+
+ ALOGD("combo:msm_route_stream(%d,%d,1)",temp->dec_id,
+ DEV_ID(DEVICE_SPEAKER_RX));
+ if(msm_route_stream(PCM_PLAY, temp->dec_id, DEV_ID(DEVICE_SPEAKER_RX),
+ 1)) {
+ ALOGE("msm_route_stream failed");
+ return -1;
+ }
+
+ }else if(enableOrDisable == 0) {
+ temp = getNodeByStreamType(CurrentComboDeviceData.StreamType);
+
+
+ if(temp == NULL){
+ ALOGE("speaker de-route not possible");
+ return -1;
+ }
+
+ ALOGD("combo:de-route msm_route_stream(%d,%d,0)",temp->dec_id,
+ DEV_ID(DEVICE_SPEAKER_RX));
+ if(msm_route_stream(PCM_PLAY, temp->dec_id,
+ DEV_ID(DEVICE_SPEAKER_RX), 0)) {
+ ALOGE("msm_route_stream failed");
+ return -1;
+ }
+ }
+
+ }
+#endif
+
+ return status;
+}
+#ifdef QCOM_FM_ENABLED
+status_t AudioHardware::enableFM(int sndDevice)
+{
+ ALOGD("enableFM");
+ status_t status = NO_INIT;
+ unsigned short session_id = INVALID_DEVICE;
+ status = ::open(FM_DEVICE, O_RDWR);
+ if (status < 0) {
+ ALOGE("Cannot open FM_DEVICE errno: %d", errno);
+ goto Error;
+ }
+ mFmFd = status;
+ if(ioctl(mFmFd, AUDIO_GET_SESSION_ID, &session_id)) {
+ ALOGE("AUDIO_GET_SESSION_ID failed*********");
+ goto Error;
+ }
+
+ if(enableDevice(DEVICE_FMRADIO_STEREO_TX, 1)) {
+ ALOGE("enableDevice failed for device %d", DEVICE_FMRADIO_STEREO_TX);
+ goto Error;
+ }
+#ifdef QCOM_ACDB_ENABLED
+ acdb_loader_send_audio_cal(ACDB_ID(DEVICE_FMRADIO_STEREO_TX),
+ CAPABILITY(DEVICE_FMRADIO_STEREO_TX));
+#endif
+ if(msm_route_stream(PCM_PLAY, session_id, DEV_ID(DEVICE_FMRADIO_STEREO_TX), 1)) {
+ ALOGE("msm_route_stream failed");
+ goto Error;
+ }
+ addToTable(session_id,cur_rx,INVALID_DEVICE,FM_RADIO,true);
+ if(sndDevice == mCurSndDevice || mCurSndDevice == -1) {
+ enableDevice(cur_rx, 1);
+#ifdef QCOM_ACDB_ENABLED
+ acdb_loader_send_audio_cal(ACDB_ID(cur_rx), CAPABILITY(cur_rx));
+#endif
+ msm_route_stream(PCM_PLAY,session_id,DEV_ID(cur_rx),1);
+ }
+ status = ioctl(mFmFd, AUDIO_START, 0);
+ if (status < 0) {
+ ALOGE("Cannot do AUDIO_START");
+ goto Error;
+ }
+ return NO_ERROR;
+ Error:
+ if (mFmFd >= 0) {
+ ::close(mFmFd);
+ mFmFd = -1;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioHardware::disableFM()
+{
+ ALOGD("disableFM");
+ Routing_table* temp = NULL;
+ temp = getNodeByStreamType(FM_RADIO);
+ if(temp == NULL)
+ return 0;
+ if (mFmFd >= 0) {
+ ::close(mFmFd);
+ mFmFd = -1;
+ }
+ if(msm_route_stream(PCM_PLAY, temp->dec_id, DEV_ID(DEVICE_FMRADIO_STEREO_TX), 0)) {
+ ALOGE("msm_route_stream failed");
+ return 0;
+ }
+ if(!getNodeByStreamType(FM_A2DP)) {
+ if(enableDevice(DEVICE_FMRADIO_STEREO_TX, 0)) {
+ ALOGE("Device disable failed for device %d", DEVICE_FMRADIO_STEREO_TX);
+ }
+ }
+ deleteFromTable(FM_RADIO);
+ if(!getNodeByStreamType(VOICE_CALL)
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+ && !getNodeByStreamType(LPA_DECODE)
+#endif
+ && !getNodeByStreamType(PCM_PLAY)
+#ifdef QCOM_VOIP_ENABLED
+ && !getNodeByStreamType(VOIP_CALL)
+#endif
+ ) {
+ if(enableDevice(cur_rx, 0)) {
+ ALOGV("Disable device[%d] failed errno = %d",DEV_ID(cur_rx),errno);
+ return 0;
+ }
+ }
+ return NO_ERROR;
+}
+#endif
+
+status_t AudioHardware::dumpInternals(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ result.append("AudioHardware::dumpInternals\n");
+ snprintf(buffer, SIZE, "\tmInit: %s\n", mInit? "true": "false");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmMicMute: %s\n", mMicMute? "true": "false");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmBluetoothNrec: %s\n", mBluetoothNrec? "true": "false");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmBluetoothId: %d\n", mBluetoothId);
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioHardware::dump(int fd, const Vector<String16>& args)
+{
+ dumpInternals(fd, args);
+ for (size_t index = 0; index < mInputs.size(); index++) {
+ mInputs[index]->dump(fd, args);
+ }
+
+ if (mOutput) {
+ mOutput->dump(fd, args);
+ }
+ return NO_ERROR;
+}
+
+uint32_t AudioHardware::getInputSampleRate(uint32_t sampleRate)
+{
+ uint32_t i;
+ uint32_t prevDelta;
+ uint32_t delta;
+
+ for (i = 0, prevDelta = 0xFFFFFFFF; i < sizeof(inputSamplingRates)/sizeof(uint32_t); i++, prevDelta = delta) {
+ delta = abs(sampleRate - inputSamplingRates[i]);
+ if (delta > prevDelta) break;
+ }
+ // i is always > 0 here
+ return inputSamplingRates[i-1];
+}
+
+
+
+// ----------------------------------------------------------------------------
+
+AudioHardware::AudioStreamOutMSM8x60::AudioStreamOutMSM8x60() :
+ mHardware(0), mFd(-1), mStartCount(0), mRetryCount(0), mStandby(true), mDevices(0)
+{
+}
+
+status_t AudioHardware::AudioStreamOutMSM8x60::set(
+ AudioHardware* hw, uint32_t devices, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
+{
+ int lFormat = pFormat ? *pFormat : 0;
+ uint32_t lChannels = pChannels ? *pChannels : 0;
+ uint32_t lRate = pRate ? *pRate : 0;
+
+ mHardware = hw;
+
+ // fix up defaults
+ if (lFormat == 0) lFormat = format();
+ if (lChannels == 0) lChannels = channels();
+ if (lRate == 0) lRate = sampleRate();
+
+ // check values
+ if ((lFormat != format()) ||
+ (lChannels != channels()) ||
+ (lRate != sampleRate())) {
+ if (pFormat) *pFormat = format();
+ if (pChannels) *pChannels = channels();
+ if (pRate) *pRate = sampleRate();
+ return BAD_VALUE;
+ }
+
+ if (pFormat) *pFormat = lFormat;
+ if (pChannels) *pChannels = lChannels;
+ if (pRate) *pRate = lRate;
+
+ mDevices = devices;
+
+ return NO_ERROR;
+}
+
+AudioHardware::AudioStreamOutMSM8x60::~AudioStreamOutMSM8x60()
+{
+ if (mFd >= 0) close(mFd);
+}
+
+ssize_t AudioHardware::AudioStreamOutMSM8x60::write(const void* buffer, size_t bytes)
+{
+ //ALOGE("AudioStreamOutMSM8x60::write(%p, %u)", buffer, bytes);
+ status_t status = NO_INIT;
+ size_t count = bytes;
+ const uint8_t* p = static_cast<const uint8_t*>(buffer);
+ unsigned short dec_id = INVALID_DEVICE;
+
+ if (mStandby) {
+
+ // open driver
+ ALOGV("open driver");
+ status = ::open("/dev/msm_pcm_out", O_WRONLY/*O_RDWR*/);
+ if (status < 0) {
+ ALOGE("Cannot open /dev/msm_pcm_out errno: %d", errno);
+ goto Error;
+ }
+ mFd = status;
+
+ // configuration
+ ALOGV("get config");
+ struct msm_audio_config config;
+ status = ioctl(mFd, AUDIO_GET_CONFIG, &config);
+ if (status < 0) {
+ ALOGE("Cannot read config");
+ goto Error;
+ }
+
+ ALOGV("set config");
+ config.channel_count = AudioSystem::popCount(channels());
+ config.sample_rate = sampleRate();
+ config.buffer_size = bufferSize();
+ config.buffer_count = AUDIO_HW_NUM_OUT_BUF;
+ config.type = CODEC_TYPE_PCM;
+ status = ioctl(mFd, AUDIO_SET_CONFIG, &config);
+ if (status < 0) {
+ ALOGE("Cannot set config");
+ goto Error;
+ }
+
+ ALOGV("buffer_size: %u", config.buffer_size);
+ ALOGV("buffer_count: %u", config.buffer_count);
+ ALOGV("channel_count: %u", config.channel_count);
+ ALOGV("sample_rate: %u", config.sample_rate);
+
+ // fill 2 buffers before AUDIO_START
+ mStartCount = AUDIO_HW_NUM_OUT_BUF;
+ mStandby = false;
+#ifdef HTC_ACOUSTIC_AUDIO
+ if (support_tpa2051)
+ do_tpa2051_control(0);
+#endif
+ }
+
+ while (count) {
+ ssize_t written = ::write(mFd, p, count);
+ if (written > 0) {
+ count -= written;
+ p += written;
+ } else {
+ if (errno != EAGAIN) return written;
+ mRetryCount++;
+ ALOGW("EAGAIN - retry");
+ }
+ }
+
+ // start audio after we fill 2 buffers
+ if (mStartCount) {
+ if (--mStartCount == 0) {
+ if(ioctl(mFd, AUDIO_GET_SESSION_ID, &dec_id)) {
+ ALOGE("AUDIO_GET_SESSION_ID failed*********");
+ return 0;
+ }
+ ALOGE("write(): dec_id = %d cur_rx = %d\n",dec_id,cur_rx);
+ if(cur_rx == INVALID_DEVICE) {
+ //return 0; //temporary fix until team upmerges code to froyo tip
+ cur_rx = 0;
+ cur_tx = 1;
+ }
+
+ Mutex::Autolock lock(mDeviceSwitchLock);
+
+#ifdef HTC_ACOUSTIC_AUDIO
+ int snd_dev = mHardware->get_snd_dev();
+ if (support_aic3254)
+ mHardware->do_aic3254_control(snd_dev);
+#endif
+ ALOGE("cur_rx for pcm playback = %d",cur_rx);
+ if(enableDevice(cur_rx, 1)) {
+ ALOGE("enableDevice failed for device cur_rx %d", cur_rx);
+ return 0;
+ }
+#ifdef QCOM_ACDB_ENABLED
+ acdb_loader_send_audio_cal(ACDB_ID(cur_rx), CAPABILITY(cur_rx));
+#endif
+ if(msm_route_stream(PCM_PLAY, dec_id, DEV_ID(cur_rx), 1)) {
+ ALOGE("msm_route_stream failed");
+ return 0;
+ }
+ Mutex::Autolock lock_1(mComboDeviceLock);
+#ifdef QCOM_FM_ENABLED
+ if(CurrentComboDeviceData.DeviceId == SND_DEVICE_FM_TX_AND_SPEAKER){
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+ Routing_table *LpaNode = getNodeByStreamType(LPA_DECODE);
+ /* This de-routes the LPA being routed on to speaker, which is done in
+ * enablecombo()
+ */
+ if(LpaNode != NULL) {
+ ALOGD("combo:de-route:msm_route_stream(%d,%d,0)",LpaNode ->dec_id,
+ DEV_ID(DEVICE_SPEAKER_RX));
+ if(msm_route_stream(PCM_PLAY, LpaNode ->dec_id,
+ DEV_ID(DEVICE_SPEAKER_RX), 0)) {
+ ALOGE("msm_route_stream failed");
+ return -1;
+ }
+ }
+#endif
+ ALOGD("Routing PCM stream to speaker for combo device");
+ ALOGD("combo:msm_route_stream(PCM_PLAY,session id:%d,dev id:%d,1)",dec_id,
+ DEV_ID(DEVICE_SPEAKER_RX));
+ if(msm_route_stream(PCM_PLAY, dec_id, DEV_ID(DEVICE_SPEAKER_RX),
+ 1)) {
+ ALOGE("msm_route_stream failed");
+ return -1;
+ }
+ CurrentComboDeviceData.StreamType = PCM_PLAY;
+ }
+#endif
+ addToTable(dec_id,cur_rx,INVALID_DEVICE,PCM_PLAY,true);
+ ioctl(mFd, AUDIO_START, 0);
+ }
+ }
+ return bytes;
+
+Error:
+ if (mFd >= 0) {
+ ::close(mFd);
+ mFd = -1;
+ }
+ // Simulate audio output timing in case of error
+ usleep(bytes * 1000000 / frameSize() / sampleRate());
+ return status;
+}
+
+status_t AudioHardware::AudioStreamOutMSM8x60::standby()
+{
+ Routing_table* temp = NULL;
+ ALOGD("AudioStreamOutMSM8x60::standby()");
+ status_t status = NO_ERROR;
+
+ temp = getNodeByStreamType(PCM_PLAY);
+
+ if(temp == NULL)
+ return NO_ERROR;
+
+ ALOGD("Deroute pcm stream");
+ if(msm_route_stream(PCM_PLAY, temp->dec_id,DEV_ID(temp->dev_id), 0)) {
+ ALOGE("could not set stream routing\n");
+ deleteFromTable(PCM_PLAY);
+ return -1;
+ }
+ deleteFromTable(PCM_PLAY);
+ if(!getNodeByStreamType(VOICE_CALL)
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+ && !getNodeByStreamType(LPA_DECODE)
+#endif
+#ifdef QCOM_FM_ENABLED
+ && !getNodeByStreamType(FM_RADIO)
+#endif
+#ifdef QCOM_VOIP_ENABLED
+ && !getNodeByStreamType(VOIP_CALL)
+#endif
+ ) {
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ //in case if ANC don't disable cur device.
+ if (anc_running == false){
+#endif
+ if(enableDevice(cur_rx, 0)) {
+ ALOGE("Disabling device failed for cur_rx %d", cur_rx);
+ return 0;
+ }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ }
+#endif
+ }
+
+ if (!mStandby && mFd >= 0) {
+ ::close(mFd);
+ mFd = -1;
+ }
+
+ mStandby = true;
+#ifdef HTC_ACOUSTIC_AUDIO
+ if (support_aic3254)
+ mHardware->do_aic3254_control(mHardware->get_snd_dev());
+#endif
+ return status;
+}
+
+status_t AudioHardware::AudioStreamOutMSM8x60::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ result.append("AudioStreamOutMSM8x60::dump\n");
+ snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tformat: %d\n", format());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmHardware: %p\n", mHardware);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmStartCount: %d\n", mStartCount);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmRetryCount: %d\n", mRetryCount);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmStandby: %s\n", mStandby? "true": "false");
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+bool AudioHardware::AudioStreamOutMSM8x60::checkStandby()
+{
+ return mStandby;
+}
+
+
+status_t AudioHardware::AudioStreamOutMSM8x60::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key = String8(AudioParameter::keyRouting);
+ status_t status = NO_ERROR;
+ int device;
+ ALOGV("AudioStreamOutMSM8x60::setParameters() %s", keyValuePairs.string());
+
+ if (param.getInt(key, device) == NO_ERROR) {
+ mDevices = device;
+ ALOGV("set output routing %x", mDevices);
+ status = mHardware->doRouting(NULL);
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 AudioHardware::AudioStreamOutMSM8x60::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8(AudioParameter::keyRouting);
+
+ if (param.get(key, value) == NO_ERROR) {
+ ALOGV("get routing %x", mDevices);
+ param.addInt(key, (int)mDevices);
+ }
+
+ ALOGV("AudioStreamOutMSM8x60::getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+status_t AudioHardware::AudioStreamOutMSM8x60::getRenderPosition(uint32_t *dspFrames)
+{
+ //TODO: enable when supported by driver
+ return INVALID_OPERATION;
+}
+
+#ifdef QCOM_VOIP_ENABLED
+// ----------------------------------------------------------------------------
+// Audio Stream from DirectOutput thread
+// ----------------------------------------------------------------------------
+
+AudioHardware::AudioStreamOutDirect::AudioStreamOutDirect() :
+ mHardware(0), mFd(-1), mStartCount(0), mRetryCount(0), mStandby(true), mDevices(0),mChannels(AudioSystem::CHANNEL_OUT_MONO),
+ mSampleRate(AUDIO_HW_VOIP_SAMPLERATE_8K), mBufferSize(AUDIO_HW_VOIP_BUFFERSIZE_8K)
+{
+}
+
+status_t AudioHardware::AudioStreamOutDirect::set(
+ AudioHardware* hw, uint32_t devices, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
+{
+ int lFormat = pFormat ? *pFormat : 0;
+ uint32_t lChannels = pChannels ? *pChannels : 0;
+ uint32_t lRate = pRate ? *pRate : 0;
+
+ ALOGV("set1 lFormat = %d lChannels= %u lRate = %u\n", lFormat, lChannels, lRate );
+ mHardware = hw;
+
+ // fix up defaults
+ if (lFormat == 0) lFormat = format();
+ if (lChannels == 0) lChannels = channels();
+ if (lRate == 0) lRate = sampleRate();
+
+ // check values
+ mFormat = lFormat;
+ mChannels = lChannels;
+ mSampleRate = lRate;
+ if(mSampleRate == AUDIO_HW_VOIP_SAMPLERATE_8K) {
+ mBufferSize = AUDIO_HW_VOIP_BUFFERSIZE_8K;
+ } else if(mSampleRate == AUDIO_HW_VOIP_SAMPLERATE_16K) {
+ mBufferSize = AUDIO_HW_VOIP_BUFFERSIZE_16K;
+ } else {
+ ALOGE(" AudioStreamOutDirect::set return bad values\n");
+ return BAD_VALUE;
+ }
+
+ mDevices = devices;
+
+#ifndef LEGACY_QCOM_VOICE
+ if((voip_session_id <= 0)) {
+ voip_session_id = msm_get_voc_session(VOIP_SESSION_NAME);
+ }
+#endif
+ mHardware->mNumVoipStreams++;
+ return NO_ERROR;
+}
+
+AudioHardware::AudioStreamOutDirect::~AudioStreamOutDirect()
+{
+ ALOGV("AudioStreamOutDirect destructor");
+ standby();
+ if (mHardware->mNumVoipStreams)
+ mHardware->mNumVoipStreams--;
+}
+
+ssize_t AudioHardware::AudioStreamOutDirect::write(const void* buffer, size_t bytes)
+{
+ status_t status = NO_INIT;
+ size_t count = bytes;
+ const uint8_t* p = static_cast<const uint8_t*>(buffer);
+ unsigned short dec_id = INVALID_DEVICE;
+
+ if (mStandby) {
+ if(mHardware->mVoipFd >= 0) {
+ mFd = mHardware->mVoipFd;
+ }
+ else {
+ // open driver
+ ALOGV("open mvs driver");
+ status = ::open(MVS_DEVICE, /*O_WRONLY*/ O_RDWR);
+ if (status < 0) {
+ ALOGE("Cannot open %s errno: %d",MVS_DEVICE, errno);
+ goto Error;
+ }
+ mFd = status;
+ mHardware->mVoipFd = mFd;
+ // configuration
+ ALOGV("get mvs config");
+ struct msm_audio_mvs_config mvs_config;
+ status = ioctl(mFd, AUDIO_GET_MVS_CONFIG, &mvs_config);
+ if (status < 0) {
+ ALOGE("Cannot read mvs config");
+ goto Error;
+ }
+
+ ALOGV("set mvs config");
+ int samplerate = sampleRate();
+ if(samplerate == AUDIO_HW_VOIP_SAMPLERATE_8K) {
+ mvs_config.mvs_mode = MVS_MODE_PCM;
+ } else if(samplerate == AUDIO_HW_VOIP_SAMPLERATE_16K) {
+ mvs_config.mvs_mode = MVS_MODE_PCM_WB;
+ } else {
+ ALOGE("unsupported samplerate for voip");
+ goto Error;
+ }
+ status = ioctl(mFd, AUDIO_SET_MVS_CONFIG, &mvs_config);
+ if (status < 0) {
+ ALOGE("Cannot set mvs config");
+ goto Error;
+ }
+
+ ALOGV("start mvs config");
+ status = ioctl(mFd, AUDIO_START, 0);
+ if (status < 0) {
+ ALOGE("Cannot start mvs driver");
+ goto Error;
+ }
+
+ // fill 2 buffers before AUDIO_START
+ mStartCount = AUDIO_HW_NUM_OUT_BUF;
+ mStandby = false;
+
+ Mutex::Autolock lock(mDeviceSwitchLock);
+ //Routing Voip
+ if ((cur_rx != INVALID_DEVICE) && (cur_tx != INVALID_DEVICE))
+ {
+ ALOGV("Starting voip call on Rx %d and Tx %d device", DEV_ID(cur_rx), DEV_ID(cur_tx));
+ msm_route_voice(DEV_ID(cur_rx),DEV_ID(cur_tx), 1);
+ }
+ else {
+ return -1;
+ }
+
+ //Enable RX device
+ if(cur_rx != INVALID_DEVICE && (enableDevice(cur_rx,1) == -1))
+ {
+ return -1;
+ }
+
+ //Enable TX device
+ if(cur_tx != INVALID_DEVICE&&(enableDevice(cur_tx,1) == -1))
+ {
+ return -1;
+ }
+#ifdef QCOM_ACDB_ENABLED
+ // voip calibration
+ acdb_loader_send_voice_cal(ACDB_ID(cur_rx),ACDB_ID(cur_tx));
+#endif
+ // start Voip call
+ ALOGD("Starting voip call and UnMuting the call");
+#ifdef LEGACY_QCOM_VOICE
+ msm_start_voice();
+ msm_set_voice_tx_mute(0);
+#else
+ msm_start_voice_ext(voip_session_id);
+ msm_set_voice_tx_mute_ext(voip_session_mute,voip_session_id);
+#endif
+ addToTable(0,cur_rx,cur_tx,VOIP_CALL,true);
+ }
+ }
+ struct msm_audio_mvs_frame audio_mvs_frame;
+ audio_mvs_frame.frame_type = 0;
+ while (count) {
+ audio_mvs_frame.len = count;
+ memcpy(&audio_mvs_frame.voc_pkt, p, count);
+ size_t written = ::write(mFd, &audio_mvs_frame, sizeof(audio_mvs_frame));
+ ALOGV(" mvs bytes count = %d written : %d \n", count, written);
+ if (written == 0) {
+ count -= audio_mvs_frame.len;
+ p += audio_mvs_frame.len;
+ } else {
+ if (errno != EAGAIN) return written;
+ mRetryCount++;
+ ALOGW("EAGAIN - retry");
+ }
+ }
+
+ // start audio after we fill 2 buffers
+ if (mStartCount) {
+ if (--mStartCount == 0) {
+ if(ioctl(mFd, AUDIO_GET_SESSION_ID, &dec_id)) {
+ ALOGE("AUDIO_GET_SESSION_ID failed*********");
+ return 0;
+ }
+ ALOGD("write(): dec_id = %d cur_rx = %d\n",dec_id,cur_rx);
+ if(cur_rx == INVALID_DEVICE) {
+ //return 0; //temporary fix until team upmerges code to froyo tip
+ cur_rx = 0;
+ cur_tx = 1;
+ }
+ }
+ }
+ bytes = audio_mvs_frame.len;
+ return bytes;
+
+Error:
+ALOGE(" write Error \n");
+ if (mFd >= 0) {
+ ::close(mFd);
+ mFd = -1;
+ mHardware->mVoipFd = -1;
+ }
+ // Simulate audio output timing in case of error
+ usleep(bytes * 1000000 / frameSize() / sampleRate());
+
+ return status;
+}
+
+status_t AudioHardware::AudioStreamOutDirect::standby()
+{
+ Routing_table* temp = NULL;
+ ALOGD("AudioStreamOutDirect::standby()");
+ status_t status = NO_ERROR;
+ int ret = 0;
+
+ ALOGV(" AudioStreamOutDirect::standby mHardware->mNumVoipStreams = %d mFd = %d\n", mHardware->mNumVoipStreams, mFd);
+ if (mFd >= 0 && (mHardware->mNumVoipStreams == 1)) {
+#ifdef LEGACY_QCOM_VOICE
+ msm_end_voice();
+#else
+ ret = msm_end_voice_ext(voip_session_id);
+ if (ret < 0)
+ ALOGE("Error %d ending voip\n", ret);
+#endif
+ temp = getNodeByStreamType(VOIP_CALL);
+ if(temp == NULL)
+ {
+ ALOGE("VOIP: Going to disable RX/TX return 0");
+ return 0;
+ }
+
+ if((temp->dev_id != INVALID_DEVICE && temp->dev_id_tx != INVALID_DEVICE)&& (!isStreamOn(VOICE_CALL))) {
+ ALOGE(" Streamout: disable VOIP rx tx ");
+ enableDevice(temp->dev_id,0);
+ enableDevice(temp->dev_id_tx,0);
+ }
+ deleteFromTable(VOIP_CALL);
+ if (mFd >= 0) {
+ ret = ioctl(mFd, AUDIO_STOP, NULL);
+ ALOGE("MVS stop returned %d \n", ret);
+ ::close(mFd);
+ mFd = mHardware->mVoipFd = -1;
+ ALOGV("driver closed");
+ voip_session_id = 0;
+ voip_session_mute = 0;
+ }
+ }
+ mStandby = true;
+ return status;
+}
+
+status_t AudioHardware::AudioStreamOutDirect::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ result.append("AudioStreamOutDirect::dump\n");
+ snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tformat: %d\n", format());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmHardware: %p\n", mHardware);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmStartCount: %d\n", mStartCount);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmRetryCount: %d\n", mRetryCount);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmStandby: %s\n", mStandby? "true": "false");
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+bool AudioHardware::AudioStreamOutDirect::checkStandby()
+{
+ return mStandby;
+}
+
+
+status_t AudioHardware::AudioStreamOutDirect::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key = String8(AudioParameter::keyRouting);
+ status_t status = NO_ERROR;
+ int device;
+ ALOGV("AudioStreamOutDirect::setParameters() %s", keyValuePairs.string());
+
+ if (param.getInt(key, device) == NO_ERROR) {
+ mDevices = device;
+ ALOGV("set output routing %x", mDevices);
+ status = mHardware->doRouting(NULL);
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 AudioHardware::AudioStreamOutDirect::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8(AudioParameter::keyRouting);
+
+ if (param.get(key, value) == NO_ERROR) {
+ ALOGV("get routing %x", mDevices);
+ param.addInt(key, (int)mDevices);
+ }
+
+ ALOGV("AudioStreamOutDirect::getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+status_t AudioHardware::AudioStreamOutDirect::getRenderPosition(uint32_t *dspFrames)
+{
+ //TODO: enable when supported by driver
+ return INVALID_OPERATION;
+}
+
+// End AudioStreamOutDirect
+//.----------------------------------------------------------------------------
+#endif
+
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+// ----------------------------------------------------------------------------
+// Audio Stream from LPA output
+// Start AudioSessionOutLPA
+// ----------------------------------------------------------------------------
+
+AudioHardware::AudioSessionOutLPA::AudioSessionOutLPA( AudioHardware *hw,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t samplingRate,
+ int type,
+ status_t *status)
+{
+ Mutex::Autolock autoLock(mLock);
+ // Default initilization
+ mHardware = hw;
+ ALOGE("AudioSessionOutLPA constructor");
+ mFormat = format;
+ mSampleRate = samplingRate;
+ mChannels = popcount(channels);
+ mBufferSize = LPA_BUFFER_SIZE; //TODO to check what value is correct
+ *status = BAD_VALUE;
+
+ mPaused = false;
+ mIsDriverStarted = false;
+ mSeeking = false;
+ mReachedEOS = false;
+ mSkipWrite = false;
+ timeStarted = 0;
+ timePlayed = 0;
+
+ mInputBufferSize = LPA_BUFFER_SIZE;
+ mInputBufferCount = BUFFER_COUNT;
+ efd = -1;
+ mEosEventReceived =false;
+
+ mEventThread = NULL;
+ mEventThreadAlive = false;
+ mKillEventThread = false;
+ mObserver = NULL;
+ if((format == AUDIO_FORMAT_PCM_16_BIT) && (mChannels == 0 || mChannels > 2)) {
+ ALOGE("Invalid number of channels %d", channels);
+ return;
+ }
+
+ *status = openAudioSessionDevice();
+
+ //Creates the event thread to poll events from LPA Driver
+ if (*status == NO_ERROR)
+ createEventThread();
+}
+
+AudioHardware::AudioSessionOutLPA::~AudioSessionOutLPA()
+{
+ ALOGV("AudioSessionOutLPA destructor");
+ mSkipWrite = true;
+ mWriteCv.signal();
+
+ //TODO: This might need to be Locked using Parent lock
+ reset();
+ //standby();//TODO Do we really need standby?
+
+}
+
+ssize_t AudioHardware::AudioSessionOutLPA::write(const void* buffer, size_t bytes)
+{
+ Mutex::Autolock autoLock(mLock);
+ int err;
+ ALOGV("write Empty Queue size() = %d, Filled Queue size() = %d ",
+ mEmptyQueue.size(),mFilledQueue.size());
+
+ if (mSkipWrite) {
+ mSkipWrite = false;
+ if (bytes < LPA_BUFFER_SIZE)
+ bytes = 0;
+ else
+ return 0;
+ }
+
+ if (mSkipWrite)
+ mSkipWrite = false;
+
+ //2.) Dequeue the buffer from empty buffer queue. Copy the data to be
+ // written into the buffer. Then Enqueue the buffer to the filled
+ // buffer queue
+ List<BuffersAllocated>::iterator it = mEmptyQueue.begin();
+ BuffersAllocated buf = *it;
+ mEmptyQueue.erase(it);
+ mEmptyQueueMutex.unlock();
+
+ memset(buf.memBuf, 0, bytes);
+ memcpy(buf.memBuf, buffer, bytes);
+ buf.bytesToWrite = bytes;
+
+ struct msm_audio_aio_buf aio_buf_local;
+ if ( buf.bytesToWrite > 0) {
+ memset(&aio_buf_local, 0, sizeof(msm_audio_aio_buf));
+ aio_buf_local.buf_addr = buf.memBuf;
+ aio_buf_local.buf_len = buf.bytesToWrite;
+ aio_buf_local.data_len = buf.bytesToWrite;
+ aio_buf_local.private_data = (void*) buf.memFd;
+
+ if ( (buf.bytesToWrite % 2) != 0 ) {
+ ALOGV("Increment for even bytes");
+ aio_buf_local.data_len += 1;
+ }
+ if (timeStarted == 0)
+ timeStarted = nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+ } else {
+ /* Put the buffer back into requestQ */
+ ALOGV("mEmptyQueueMutex locking: %d", __LINE__);
+ mEmptyQueueMutex.lock();
+ ALOGV("mEmptyQueueMutex locked: %d", __LINE__);
+ mEmptyQueue.push_back(buf);
+ ALOGV("mEmptyQueueMutex unlocking: %d", __LINE__);
+ mEmptyQueueMutex.unlock();
+ ALOGV("mEmptyQueueMutex unlocked: %d", __LINE__);
+ //Post EOS in case the filled queue is empty and EOS is reached.
+ mReachedEOS = true;
+ mFilledQueueMutex.lock();
+ if (mFilledQueue.empty() && !mEosEventReceived) {
+ ALOGV("mEosEventReceived made true");
+ mEosEventReceived = true;
+ if (mObserver != NULL) {
+ ALOGV("mObserver: posting EOS");
+ mObserver->postEOS(0);
+ }
+ }
+ mFilledQueueMutex.unlock();
+ return NO_ERROR;
+ }
+ mFilledQueueMutex.lock();
+ mFilledQueue.push_back(buf);
+ mFilledQueueMutex.unlock();
+
+ ALOGV("PCM write start");
+ //3.) Write the buffer to the Driver
+ if(mIsDriverStarted) {
+ if ( ioctl(afd, AUDIO_ASYNC_WRITE, &aio_buf_local ) < 0 ) {
+ ALOGE("error on async write\n");
+ }
+ }
+ ALOGV("PCM write complete");
+
+ if (bytes < LPA_BUFFER_SIZE) {
+ ALOGV("Last buffer case");
+ if (fsync(afd) != 0) {
+ ALOGE("fsync failed.");
+ }
+ mReachedEOS = true;
+ }
+
+ return NO_ERROR; //TODO Do we need to send error
+}
+
+
+status_t AudioHardware::AudioSessionOutLPA::standby()
+{
+ ALOGD("AudioSessionOutLPA::standby()");
+ status_t status = NO_ERROR;
+ //TODO Do we really need standby()
+ return status;
+}
+
+
+status_t AudioHardware::AudioSessionOutLPA::dump(int fd, const Vector<String16>& args)
+{
+ return NO_ERROR;
+}
+
+status_t AudioHardware::AudioSessionOutLPA::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key = String8(AudioParameter::keyRouting);
+ status_t status = NO_ERROR;
+ int device;
+ ALOGE("AudioSessionOutLPA::setParameters() %s", keyValuePairs.string());
+
+ if (param.getInt(key, device) == NO_ERROR) {
+ mDevices = device;
+ ALOGE("set output routing %x", mDevices);
+ status = mHardware->doRouting(NULL);
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 AudioHardware::AudioSessionOutLPA::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8(AudioParameter::keyRouting);
+
+ if (param.get(key, value) == NO_ERROR) {
+ ALOGV("get routing %x", mDevices);
+ param.addInt(key, (int)mDevices);
+ }
+
+ ALOGV("AudioSessionOutLPA::getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+status_t AudioHardware::AudioSessionOutLPA::setVolume(float left, float right)
+{
+ float v = (left + right) / 2;
+ int sessionId = 0;
+ unsigned short decId;
+ if (v < 0.0) {
+ ALOGW("AudioSessionOutLPA::setVolume(%f) under 0.0, assuming 0.0\n", v);
+ v = 0.0;
+ } else if (v > 1.0) {
+ ALOGW("AudioSessionOutLPA::setVolume(%f) over 1.0, assuming 1.0\n", v);
+ v = 1.0;
+ }
+ if ( ioctl(afd, AUDIO_GET_SESSION_ID, &decId) == -1 ) {
+ ALOGE("AUDIO_GET_SESSION_ID FAILED\n");
+ return BAD_VALUE;
+ } else {
+ sessionId = (int)decId;
+ ALOGE("AUDIO_GET_SESSION_ID success : decId = %d", decId);
+ }
+ // Ensure to convert the log volume back to linear for LPA
+ float vol = v * 100;
+ ALOGV("AudioSessionOutLPA::setVolume(%f)\n", v);
+ ALOGV("Setting session volume to %f (available range is 0 to 100)\n", vol);
+
+ if(msm_set_volume(sessionId, vol)) {
+ ALOGE("msm_set_volume(%d %f) failed errno = %d",sessionId, vol,errno);
+ return -1;
+ }
+ ALOGV("LPA volume set (%f) succeeded",vol);
+ return NO_ERROR;
+}
+
+status_t AudioHardware::AudioSessionOutLPA::openAudioSessionDevice( )
+{
+ status_t status = NO_ERROR;
+
+ //It opens LPA driver
+ ALOGE("Opening LPA pcm_dec driver");
+ afd = open("/dev/msm_pcm_lp_dec", O_WRONLY | O_NONBLOCK);
+ if ( afd < 0 ) {
+ ALOGE("pcm_lp_dec: cannot open pcm_dec device and the error is %d", errno);
+ //initCheck = false;
+ return UNKNOWN_ERROR;
+ } else {
+ //initCheck = true;
+ ALOGV("pcm_lp_dec: pcm_lp_dec Driver opened");
+ }
+
+ start();
+ ALOGE("Calling bufferAlloc ");
+ bufferAlloc();
+
+ return status;
+}
+
+void AudioHardware::AudioSessionOutLPA::bufferAlloc( )
+{
+ // Allocate ION buffers
+ void *ion_buf; int32_t ion_fd;
+ struct msm_audio_ion_info ion_info;
+ ALOGE("Allocate ION buffers");
+ //1. Open the ion_audio
+ ionfd = open("/dev/ion", O_RDONLY | O_SYNC);
+ if (ionfd < 0) {
+ ALOGE("/dev/ion open failed \n");
+ return;
+ }
+ for (int i = 0; i < mInputBufferCount; i++) {
+ ion_buf = memBufferAlloc(mInputBufferSize, &ion_fd);
+ memset(&ion_info, 0, sizeof(msm_audio_ion_info));
+ ALOGE("Registering ION with fd %d and address as %p", ion_fd, ion_buf);
+ ion_info.fd = ion_fd;
+ ion_info.vaddr = ion_buf;
+ if ( ioctl(afd, AUDIO_REGISTER_ION, &ion_info) < 0 ) {
+ ALOGE("Registration of ION with the Driver failed with fd %d and memory %x",
+ ion_info.fd, (unsigned int)ion_info.vaddr);
+ }
+ }
+ ALOGE("Allocating ION buffers complete");
+}
+
+
+void* AudioHardware::AudioSessionOutLPA::memBufferAlloc(int nSize, int32_t *ion_fd)
+{
+ void *ion_buf = NULL;
+ void *local_buf = NULL;
+ struct ion_fd_data fd_data;
+ struct ion_allocation_data alloc_data;
+
+ alloc_data.len = nSize;
+ alloc_data.align = 0x1000;
+ alloc_data.flags = ION_HEAP(ION_AUDIO_HEAP_ID);
+ int rc = ioctl(ionfd, ION_IOC_ALLOC, &alloc_data);
+ if (rc) {
+ ALOGE("ION_IOC_ALLOC ioctl failed\n");
+ return ion_buf;
+ }
+ fd_data.handle = alloc_data.handle;
+
+ rc = ioctl(ionfd, ION_IOC_SHARE, &fd_data);
+ if (rc) {
+ ALOGE("ION_IOC_SHARE ioctl failed\n");
+ rc = ioctl(ionfd, ION_IOC_FREE, &(alloc_data.handle));
+ if (rc) {
+ ALOGE("ION_IOC_FREE ioctl failed\n");
+ }
+ return ion_buf;
+ }
+
+ // 2. MMAP to get the virtual address
+ ion_buf = mmap(NULL, nSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd_data.fd, 0);
+ if(MAP_FAILED == ion_buf) {
+ ALOGE("mmap() failed \n");
+ close(fd_data.fd);
+ rc = ioctl(ionfd, ION_IOC_FREE, &(alloc_data.handle));
+ if (rc) {
+ ALOGE("ION_IOC_FREE ioctl failed\n");
+ }
+ return ion_buf;
+ }
+
+ local_buf = malloc(nSize);
+ if (NULL == local_buf) {
+ // unmap the corresponding ION buffer and close the fd
+ munmap(ion_buf, mInputBufferSize);
+ close(fd_data.fd);
+ rc = ioctl(ionfd, ION_IOC_FREE, &(alloc_data.handle));
+ if (rc) {
+ ALOGE("ION_IOC_FREE ioctl failed\n");
+ }
+ return NULL;
+ }
+
+ // 3. Store this information for internal mapping / maintanence
+ BuffersAllocated buf(local_buf, ion_buf, nSize, fd_data.fd, alloc_data.handle);
+ mEmptyQueue.push_back(buf);
+
+ // 4. Send the mem fd information
+ *ion_fd = fd_data.fd;
+ ALOGV("IONBufferAlloc calling with required size %d", nSize);
+ ALOGV("ION allocated is %d, fd_data.fd %d and buffer is %x", *ion_fd, fd_data.fd, (unsigned int)ion_buf);
+
+ // 5. Return the virtual address
+ return ion_buf;
+}
+
+void AudioHardware::AudioSessionOutLPA::bufferDeAlloc()
+{
+ // De-Allocate ION buffers
+ int rc = 0;
+ //Remove all the buffers from empty queue
+ mEmptyQueueMutex.lock();
+ while (!mEmptyQueue.empty()) {
+ List<BuffersAllocated>::iterator it = mEmptyQueue.begin();
+ BuffersAllocated &ionBuffer = *it;
+ struct msm_audio_ion_info ion_info;
+ ion_info.vaddr = (*it).memBuf;
+ ion_info.fd = (*it).memFd;
+ if (ioctl(afd, AUDIO_DEREGISTER_ION, &ion_info) < 0) {
+ ALOGE("ION deregister failed");
+ }
+ ALOGV("Ion Unmapping the address %p, size %d, fd %d from empty",ionBuffer.memBuf,ionBuffer.bytesToWrite,ionBuffer.memFd);
+ munmap(ionBuffer.memBuf, mInputBufferSize);
+ ALOGV("closing the ion shared fd");
+ close(ionBuffer.memFd);
+ rc = ioctl(ionfd, ION_IOC_FREE, &ionBuffer.ion_handle);
+ if (rc) {
+ ALOGE("ION_IOC_FREE ioctl failed\n");
+ }
+ // free the local buffer corresponding to ion buffer
+ free(ionBuffer.localBuf);
+ ALOGE("Removing from empty Q");
+ mEmptyQueue.erase(it);
+ }
+ mEmptyQueueMutex.unlock();
+
+ //Remove all the buffers from Filled queue
+ mFilledQueueMutex.lock();
+ while(!mFilledQueue.empty()){
+ List<BuffersAllocated>::iterator it = mFilledQueue.begin();
+ BuffersAllocated &ionBuffer = *it;
+ struct msm_audio_ion_info ion_info;
+ ion_info.vaddr = (*it).memBuf;
+ ion_info.fd = (*it).memFd;
+ if (ioctl(afd, AUDIO_DEREGISTER_ION, &ion_info) < 0) {
+ ALOGE("ION deregister failed");
+ }
+ ALOGV("Ion Unmapping the address %p, size %d, fd %d from Request",ionBuffer.memBuf,ionBuffer.bytesToWrite,ionBuffer.memFd);
+ munmap(ionBuffer.memBuf, mInputBufferSize);
+ ALOGV("closing the ion shared fd");
+ close(ionBuffer.memFd);
+ rc = ioctl(ionfd, ION_IOC_FREE, &ionBuffer.ion_handle);
+ if (rc) {
+ ALOGE("ION_IOC_FREE ioctl failed\n");
+ }
+ // free the local buffer corresponding to ion buffer
+ free(ionBuffer.localBuf);
+ ALOGV("Removing from Filled Q");
+ mFilledQueue.erase(it);
+ }
+ mFilledQueueMutex.unlock();
+ if (ionfd >= 0) {
+ close(ionfd);
+ ionfd = -1;
+ }
+}
+
+uint32_t AudioHardware::AudioSessionOutLPA::latency() const
+{
+ // Android wants latency in milliseconds.
+ return 1000;//TODO to correct the value
+}
+
+void AudioHardware::AudioSessionOutLPA::requestAndWaitForEventThreadExit()
+{
+ if (!mEventThreadAlive)
+ return;
+ mKillEventThread = true;
+ if (ioctl(afd, AUDIO_ABORT_GET_EVENT, 0) < 0) {
+ ALOGE("Audio Abort event failed");
+ }
+ pthread_join(mEventThread,NULL);
+}
+
+void * AudioHardware::AudioSessionOutLPA::eventThreadWrapper(void *me)
+{
+ static_cast<AudioSessionOutLPA *>(me)->eventThreadEntry();
+ return NULL;
+}
+
+void AudioHardware::AudioSessionOutLPA::eventThreadEntry()
+{
+ struct msm_audio_event cur_pcmdec_event;
+ mEventThreadAlive = true;
+ int rc = 0;
+ //2.) Set the priority for the event thread
+ pid_t tid = gettid();
+ androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
+ prctl(PR_SET_NAME, (unsigned long)"HAL Audio EventThread", 0, 0, 0);
+ ALOGV("event thread created ");
+ if (mKillEventThread) {
+ mEventThreadAlive = false;
+ ALOGV("Event Thread is dying.");
+ return;
+ }
+ while (1) {
+ //Wait for an event to occur
+ rc = ioctl(afd, AUDIO_GET_EVENT, &cur_pcmdec_event);
+ ALOGE("pcm dec Event Thread rc = %d and errno is %d",rc, errno);
+
+ if ( (rc < 0) && ((errno == ENODEV) || (errno == EBADF)) ) {
+ ALOGV("AUDIO__GET_EVENT called. Exit the thread");
+ break;
+ }
+
+ switch ( cur_pcmdec_event.event_type ) {
+ case AUDIO_EVENT_WRITE_DONE:
+ {
+ ALOGE("WRITE_DONE: addr %p len %d and fd is %d\n",
+ cur_pcmdec_event.event_payload.aio_buf.buf_addr,
+ cur_pcmdec_event.event_payload.aio_buf.data_len,
+ (int32_t) cur_pcmdec_event.event_payload.aio_buf.private_data);
+ Mutex::Autolock autoLock(mLock);
+ mFilledQueueMutex.lock();
+ BuffersAllocated buf = *(mFilledQueue.begin());
+ for (List<BuffersAllocated>::iterator it = mFilledQueue.begin();
+ it != mFilledQueue.end(); ++it) {
+ if (it->memBuf == cur_pcmdec_event.event_payload.aio_buf.buf_addr) {
+ buf = *it;
+ mFilledQueue.erase(it);
+ // Post buffer to Empty Q
+ ALOGV("mEmptyQueueMutex locking: %d", __LINE__);
+ mEmptyQueueMutex.lock();
+ ALOGV("mEmptyQueueMutex locked: %d", __LINE__);
+ mEmptyQueue.push_back(buf);
+ ALOGV("mEmptyQueueMutex unlocking: %d", __LINE__);
+ mEmptyQueueMutex.unlock();
+ ALOGV("mEmptyQueueMutex unlocked: %d", __LINE__);
+ if (mFilledQueue.empty() && mReachedEOS) {
+ ALOGV("Posting the EOS to the observer player %p", mObserver);
+ mEosEventReceived = true;
+ if (mObserver != NULL) {
+ ALOGV("mObserver: posting EOS");
+ mObserver->postEOS(0);
+ }
+ }
+ break;
+ }
+ }
+ mFilledQueueMutex.unlock();
+ mWriteCv.signal();
+ }
+ break;
+ case AUDIO_EVENT_SUSPEND:
+ {
+ struct msm_audio_stats stats;
+ int nBytesConsumed = 0;
+
+ ALOGV("AUDIO_EVENT_SUSPEND received\n");
+ if (!mPaused) {
+ ALOGV("Not in paused, no need to honor SUSPEND event");
+ break;
+ }
+ // 1. Get the Byte count that is consumed
+ if ( ioctl(afd, AUDIO_GET_STATS, &stats) < 0 ) {
+ ALOGE("AUDIO_GET_STATUS failed");
+ } else {
+ ALOGV("Number of bytes consumed by DSP is %u", stats.byte_count);
+ nBytesConsumed = stats.byte_count;
+ }
+ // Reset eosflag to resume playback where we actually paused
+ mReachedEOS = false;
+ // 3. Call AUDIO_STOP on the Driver.
+ ALOGV("Received AUDIO_EVENT_SUSPEND and calling AUDIO_STOP");
+ if ( ioctl(afd, AUDIO_STOP, 0) < 0 ) {
+ ALOGE("AUDIO_STOP failed");
+ }
+ mIsDriverStarted = false;
+ break;
+ }
+ break;
+ case AUDIO_EVENT_RESUME:
+ {
+ ALOGV("AUDIO_EVENT_RESUME received\n");
+ }
+ break;
+ default:
+ ALOGE("Received Invalid Event from driver\n");
+ break;
+ }
+ }
+ mEventThreadAlive = false;
+ ALOGV("Event Thread is dying.");
+}
+
+
+void AudioHardware::AudioSessionOutLPA::createEventThread()
+{
+ ALOGV("Creating Event Thread");
+ mKillEventThread = false;
+ mEventThreadAlive = true;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ pthread_create(&mEventThread, &attr, eventThreadWrapper, this);
+ ALOGV("Event Thread created");
+}
+
+status_t AudioHardware::AudioSessionOutLPA::start( )
+{
+
+ ALOGE("LPA playback start");
+ if (mPaused && mIsDriverStarted) {
+ mPaused = false;
+ if (ioctl(afd, AUDIO_PAUSE, 0) < 0) {
+ ALOGE("Resume:: LPA driver resume failed");
+ return UNKNOWN_ERROR;
+ }
+
+ } else {
+ //get config, set config and AUDIO_START LPA driver
+ int sessionId = 0;
+ mPaused = false;
+ if ( afd >= 0 ) {
+ struct msm_audio_config config;
+ if ( ioctl(afd, AUDIO_GET_CONFIG, &config) < 0 ) {
+ ALOGE("could not get config");
+ close(afd);
+ afd = -1;
+ return BAD_VALUE;
+ }
+
+ config.sample_rate = mSampleRate;
+ config.channel_count = mChannels;
+ ALOGE("sample_rate=%d and channel count=%d \n", mSampleRate, mChannels);
+ if ( ioctl(afd, AUDIO_SET_CONFIG, &config) < 0 ) {
+ ALOGE("could not set config");
+ close(afd);
+ afd = -1;
+ return BAD_VALUE;
+ }
+ }
+ unsigned short decId;
+ // Get the session id from the LPA Driver
+ // Register the session id with HAL for routing
+ if ( ioctl(afd, AUDIO_GET_SESSION_ID, &decId) == -1 ) {
+ ALOGE("AUDIO_GET_SESSION_ID FAILED\n");
+ return BAD_VALUE;
+ } else {
+ sessionId = (int)decId;
+ ALOGV("AUDIO_GET_SESSION_ID success : decId = %d", decId);
+ }
+
+ Mutex::Autolock lock(mDeviceSwitchLock);
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+ if(getNodeByStreamType(LPA_DECODE) != NULL) {
+ ALOGE("Not allowed, There is alread an LPA Node existing");
+ return -1;
+ }
+ ALOGE("AudioSessionOutMSM8x60::set() Adding LPA_DECODE Node to Table");
+ addToTable(sessionId,cur_rx,INVALID_DEVICE,LPA_DECODE,true);
+#endif
+ ALOGE("enableDevice(cur_rx = %d, dev_id = %d)",cur_rx,DEV_ID(cur_rx));
+ if (enableDevice(cur_rx, 1)) {
+ ALOGE("enableDevice failed for device cur_rx %d", cur_rx);
+ return -1;
+ }
+
+ ALOGE("msm_route_stream(PCM_PLAY,%d,%d,0)",sessionId,DEV_ID(cur_rx));
+#ifdef QCOM_ACDB_ENABLED
+ acdb_loader_send_audio_cal(ACDB_ID(cur_rx), CAPABILITY(cur_rx));
+#endif
+ if(msm_route_stream(PCM_PLAY,sessionId,DEV_ID(cur_rx),1)) {
+ ALOGE("msm_route_stream(PCM_PLAY,%d,%d,1) failed",sessionId,DEV_ID(cur_rx));
+ return -1;
+ }
+
+ Mutex::Autolock lock_1(mComboDeviceLock);
+#ifdef QCOM_FM_ENABLED
+ if(CurrentComboDeviceData.DeviceId == SND_DEVICE_FM_TX_AND_SPEAKER){
+ ALOGD("Routing LPA steam to speaker for combo device");
+ ALOGD("combo:msm_route_stream(LPA_DECODE,session id:%d,dev id:%d,1)",sessionId,
+ DEV_ID(DEVICE_SPEAKER_RX));
+ /* music session is already routed to speaker in
+ * enableComboDevice(), but at this point it can
+ * be said that it was done with incorrect session id,
+ * so re-routing with correct session id here.
+ */
+ if(msm_route_stream(PCM_PLAY, sessionId, DEV_ID(DEVICE_SPEAKER_RX),
+ 1)) {
+ ALOGE("msm_route_stream failed");
+ return -1;
+ }
+ CurrentComboDeviceData.StreamType = LPA_DECODE;
+ }
+#endif
+ //Start the Driver
+ if (ioctl(afd, AUDIO_START,0) < 0) {
+ ALOGE("Driver start failed!");
+ return BAD_VALUE;
+ }
+ mIsDriverStarted = true;
+ ALOGE("LPA Playback started");
+ if (timeStarted == 0)
+ timeStarted = nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC));// Needed
+ }
+ return NO_ERROR;
+}
+
+status_t AudioHardware::AudioSessionOutLPA::pause()
+{
+ ALOGV("LPA playback pause");
+ if (ioctl(afd, AUDIO_PAUSE, 1) < 0) {
+ ALOGE("Audio Pause failed");
+ }
+ mPaused = true;
+ timePlayed += (nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC)) - timeStarted);//needed
+ return NO_ERROR;
+}
+
+status_t AudioHardware::AudioSessionOutLPA::drain()
+{
+ ALOGV("LPA playback EOS");
+ return NO_ERROR;
+}
+
+status_t AudioHardware::AudioSessionOutLPA::flush()
+{
+ ALOGV("LPA playback flush ");
+ int err;
+
+ // 2.) Add all the available buffers to Empty Queue (Maintain order)
+ mFilledQueueMutex.lock();
+ mEmptyQueueMutex.lock();
+ while (!mFilledQueue.empty()) {
+ List<BuffersAllocated>::iterator it = mFilledQueue.begin();
+ BuffersAllocated buf = *it;
+ buf.bytesToWrite = 0;
+ mEmptyQueue.push_back(buf);
+ mFilledQueue.erase(it);
+ }
+ mEmptyQueueMutex.unlock();
+ mFilledQueueMutex.unlock();
+ ALOGV("Transferred all the buffers from Filled queue to "
+ "Empty queue to handle seek");
+ mReachedEOS = false;
+ if (!mPaused) {
+ if (!mEosEventReceived) {
+ if (ioctl(afd, AUDIO_PAUSE, 1) < 0) {
+ ALOGE("Audio Pause failed");
+ return UNKNOWN_ERROR;
+ }
+ if (ioctl(afd, AUDIO_FLUSH, 0) < 0) {
+ ALOGE("Audio Flush failed");
+ return UNKNOWN_ERROR;
+ }
+ }
+ } else {
+ timeStarted = 0;
+ if (ioctl(afd, AUDIO_FLUSH, 0) < 0) {
+ ALOGE("Audio Flush failed");
+ return UNKNOWN_ERROR;
+ }
+ if (ioctl(afd, AUDIO_PAUSE, 1) < 0) {
+ ALOGE("Audio Pause failed");
+ return UNKNOWN_ERROR;
+ }
+ }
+ mEosEventReceived = false;
+ //4.) Skip the current write from the decoder and signal to the Write get
+ // the next set of data from the decoder
+ mSkipWrite = true;
+ mWriteCv.signal();
+ return NO_ERROR;
+}
+status_t AudioHardware::AudioSessionOutLPA::stop()
+{
+ Mutex::Autolock autoLock(mLock);
+ ALOGV("AudioSessionOutLPA- stop");
+ // close all the existing PCM devices
+ mSkipWrite = true;
+ mWriteCv.signal();
+ return NO_ERROR;
+}
+
+status_t AudioHardware::AudioSessionOutLPA::setObserver(void *observer)
+{
+ ALOGV("Registering the callback \n");
+ mObserver = reinterpret_cast<AudioEventObserver *>(observer);
+ return NO_ERROR;
+}
+
+status_t AudioHardware::AudioSessionOutLPA::getNextWriteTimestamp(int64_t *timestamp)
+{
+
+ *timestamp = nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC)) - timeStarted + timePlayed;//needed
+ ALOGV("Timestamp returned = %lld\n", *timestamp);
+ return NO_ERROR;
+}
+
+void AudioHardware::AudioSessionOutLPA::reset()
+{
+ Routing_table* temp = NULL;
+ ALOGD("AudioSessionOutLPA::reset()");
+ ioctl(afd,AUDIO_STOP,0);
+ mIsDriverStarted = false;
+ requestAndWaitForEventThreadExit();
+ status_t status = NO_ERROR;
+ bufferDeAlloc();
+ ::close(afd);
+ temp = getNodeByStreamType(LPA_DECODE);
+
+ if (temp == NULL) {
+ ALOGE("LPA node does not exist");
+ return ;
+ }
+ ALOGD("Deroute lpa playback stream");
+ if(msm_route_stream(PCM_PLAY, temp->dec_id,DEV_ID(temp->dev_id), 0)) {
+ ALOGE("could not set stream routing\n");
+ deleteFromTable(LPA_DECODE);
+ }
+ deleteFromTable(LPA_DECODE);
+ if (!getNodeByStreamType(VOICE_CALL) && !getNodeByStreamType(PCM_PLAY)
+#ifdef QCOM_FM_ENABLED
+ && !getNodeByStreamType(FM_RADIO)
+#endif
+#ifdef QCOM_VOIP_ENABLED
+ && !getNodeByStreamType(VOIP_CALL)
+#endif
+ ) {
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ if (anc_running == false) {
+#endif
+ if (enableDevice(cur_rx, 0)) {
+ ALOGE("Disabling device failed for cur_rx %d", cur_rx);
+ }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ }
+#endif
+ }
+ ALOGE("AudioSessionOutLPA::reset() complete");
+}
+
+status_t AudioHardware::AudioSessionOutLPA::getRenderPosition(uint32_t *dspFrames)
+{
+ //TODO: enable when supported by driver
+ return INVALID_OPERATION;
+}
+
+
+status_t AudioHardware::AudioSessionOutLPA::getBufferInfo(buf_info **buf) {
+
+ buf_info *tempbuf = (buf_info *)malloc(sizeof(buf_info) + mInputBufferCount*sizeof(int *));
+ ALOGV("Get buffer info");
+ tempbuf->bufsize = LPA_BUFFER_SIZE;
+ tempbuf->nBufs = mInputBufferCount;
+ tempbuf->buffers = (int **)((char*)tempbuf + sizeof(buf_info));
+ List<BuffersAllocated>::iterator it = mEmptyQueue.begin();
+ for (int i = 0; i < mInputBufferCount; i++) {
+ tempbuf->buffers[i] = (int *)it->memBuf;
+ it++;
+ }
+ *buf = tempbuf;
+ return NO_ERROR;
+}
+
+status_t AudioHardware::AudioSessionOutLPA::isBufferAvailable(int *isAvail) {
+
+ Mutex::Autolock autoLock(mLock);
+ ALOGV("isBufferAvailable Empty Queue size() = %d, Filled Queue size() = %d ",
+ mEmptyQueue.size(),mFilledQueue.size());
+ *isAvail = false;
+ // 1.) Wait till a empty buffer is available in the Empty buffer queue
+ mEmptyQueueMutex.lock();
+ if (mEmptyQueue.empty()) {
+ ALOGV("Write: waiting on mWriteCv");
+ mLock.unlock();
+ mWriteCv.wait(mEmptyQueueMutex);
+ mLock.lock();
+ if (mSkipWrite) {
+ ALOGV("Write: Flushing the previous write buffer");
+ mSkipWrite = false;
+ mEmptyQueueMutex.unlock();
+ return NO_ERROR;
+ }
+ ALOGV("Write: received a signal to wake up");
+ }
+ mEmptyQueueMutex.unlock();
+
+ *isAvail = true;
+ return NO_ERROR;
+}
+
+// End AudioSessionOutLPA
+//.----------------------------------------------------------------------------
+#endif
+
+int mFdin = -1;
+AudioHardware::AudioStreamInMSM8x60::AudioStreamInMSM8x60() :
+ mHardware(0), mState(AUDIO_INPUT_CLOSED), mRetryCount(0),
+ mFormat(AUDIO_HW_IN_FORMAT), mChannels(AUDIO_HW_IN_CHANNELS),
+ mSampleRate(AUDIO_HW_IN_SAMPLERATE), mBufferSize(AUDIO_HW_IN_BUFFERSIZE),
+ mAcoustics((AudioSystem::audio_in_acoustics)0), mDevices(0), mForVR(0)
+{
+}
+
+status_t AudioHardware::AudioStreamInMSM8x60::set(
+ AudioHardware* hw, uint32_t devices, int *pFormat, uint32_t *pChannels, uint32_t *pRate,
+ AudioSystem::audio_in_acoustics acoustic_flags)
+{
+ if ((pFormat == 0) || (*pFormat != AUDIO_HW_IN_FORMAT))
+ {
+ *pFormat = AUDIO_HW_IN_FORMAT;
+ return BAD_VALUE;
+ }
+
+ if (pRate == 0) {
+ return BAD_VALUE;
+ }
+ uint32_t rate = hw->getInputSampleRate(*pRate);
+ if (rate != *pRate) {
+ *pRate = rate;
+ ALOGE(" sample rate does not match\n");
+ return BAD_VALUE;
+ }
+
+ if (pChannels == 0 || (*pChannels & (AudioSystem::CHANNEL_IN_MONO | AudioSystem::CHANNEL_IN_STEREO)) == 0) {
+ *pChannels = AUDIO_HW_IN_CHANNELS;
+ ALOGE(" Channel count does not match\n");
+ return BAD_VALUE;
+ }
+
+ mHardware = hw;
+
+ ALOGV("AudioStreamInMSM8x60::set(%d, %d, %u)", *pFormat, *pChannels, *pRate);
+ if (mFdin >= 0) {
+ ALOGE("Audio record already open");
+ return -EPERM;
+ }
+ status_t status =0;
+ struct msm_voicerec_mode voc_rec_cfg;
+#ifdef QCOM_FM_ENABLED
+ if(devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
+ status = ::open("/dev/msm_pcm_in", O_RDONLY);
+ if (status < 0) {
+ ALOGE("Cannot open /dev/msm_pcm_in errno: %d", errno);
+ goto Error;
+ }
+ mFdin = status;
+ // configuration
+ ALOGV("get config");
+ struct msm_audio_config config;
+ status = ioctl(mFdin, AUDIO_GET_CONFIG, &config);
+ if (status < 0) {
+ ALOGE("Cannot read config");
+ goto Error;
+ }
+
+ ALOGV("set config");
+ config.channel_count = AudioSystem::popCount(*pChannels);
+ config.sample_rate = *pRate;
+ config.buffer_size = bufferSize();
+ config.buffer_count = 2;
+ config.type = CODEC_TYPE_PCM;
+ status = ioctl(mFdin, AUDIO_SET_CONFIG, &config);
+ if (status < 0) {
+ ALOGE("Cannot set config");
+ if (ioctl(mFdin, AUDIO_GET_CONFIG, &config) == 0) {
+ if (config.channel_count == 1) {
+ *pChannels = AudioSystem::CHANNEL_IN_MONO;
+ } else {
+ *pChannels = AudioSystem::CHANNEL_IN_STEREO;
+ }
+ *pRate = config.sample_rate;
+ }
+ goto Error;
+ }
+
+ ALOGV("confirm config");
+ status = ioctl(mFdin, AUDIO_GET_CONFIG, &config);
+ if (status < 0) {
+ ALOGE("Cannot read config");
+ goto Error;
+ }
+ ALOGV("buffer_size: %u", config.buffer_size);
+ ALOGV("buffer_count: %u", config.buffer_count);
+ ALOGV("channel_count: %u", config.channel_count);
+ ALOGV("sample_rate: %u", config.sample_rate);
+
+ mDevices = devices;
+ mFormat = AUDIO_HW_IN_FORMAT;
+ mChannels = *pChannels;
+ mSampleRate = config.sample_rate;
+ mBufferSize = config.buffer_size;
+ } else
+#endif
+ if (*pFormat == AUDIO_HW_IN_FORMAT) {
+ if (mHardware->mNumPcmRec > 0) {
+ /* Only one PCM recording is allowed at a time */
+ ALOGE("Multiple PCM recordings is not allowed");
+ status = -1;
+ goto Error;
+ }
+ // open audio input device
+ status = ::open("/dev/msm_pcm_in", O_RDWR);
+ if (status < 0) {
+ ALOGE("Cannot open /dev/msm_pcm_in errno: %d", errno);
+ goto Error;
+ }
+ mHardware->mNumPcmRec ++;
+ mFdin = status;
+
+ // configuration
+ ALOGV("get config");
+ struct msm_audio_config config;
+ status = ioctl(mFdin, AUDIO_GET_CONFIG, &config);
+ if (status < 0) {
+ ALOGE("Cannot read config");
+ goto Error;
+ }
+
+ ALOGV("set config");
+ config.channel_count = AudioSystem::popCount((*pChannels) &
+ (AudioSystem::CHANNEL_IN_STEREO|
+ AudioSystem::CHANNEL_IN_MONO));
+
+ config.sample_rate = *pRate;
+
+ mBufferSize = mHardware->getInputBufferSize(config.sample_rate,
+ AUDIO_HW_IN_FORMAT,
+ config.channel_count);
+ config.buffer_size = bufferSize();
+ // Make buffers to be allocated in driver equal to the number of buffers
+ // that AudioFlinger allocates (Shared memory)
+ config.buffer_count = 4;
+ config.type = CODEC_TYPE_PCM;
+ status = ioctl(mFdin, AUDIO_SET_CONFIG, &config);
+ if (status < 0) {
+ ALOGE("Cannot set config");
+ if (ioctl(mFdin, AUDIO_GET_CONFIG, &config) == 0) {
+ if (config.channel_count == 1) {
+ *pChannels = AudioSystem::CHANNEL_IN_MONO;
+ } else {
+ *pChannels = AudioSystem::CHANNEL_IN_STEREO;
+ }
+ *pRate = config.sample_rate;
+ }
+ goto Error;
+ }
+
+ ALOGV("confirm config");
+ status = ioctl(mFdin, AUDIO_GET_CONFIG, &config);
+ if (status < 0) {
+ ALOGE("Cannot read config");
+ goto Error;
+ }
+ ALOGV("buffer_size: %u", config.buffer_size);
+ ALOGV("buffer_count: %u", config.buffer_count);
+ ALOGV("channel_count: %u", config.channel_count);
+ ALOGV("sample_rate: %u", config.sample_rate);
+
+ mDevices = devices;
+ mFormat = AUDIO_HW_IN_FORMAT;
+ mChannels = *pChannels;
+ mSampleRate = config.sample_rate;
+ mBufferSize = config.buffer_size;
+
+ if (mDevices == AudioSystem::DEVICE_IN_VOICE_CALL) {
+ if ((mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) &&
+ (mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK)) {
+ ALOGV("Recording Source: Voice Call Both Uplink and Downlink");
+ voc_rec_cfg.rec_mode = VOC_REC_BOTH;
+ } else if (mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
+ ALOGV("Recording Source: Voice Call DownLink");
+ voc_rec_cfg.rec_mode = VOC_REC_DOWNLINK;
+ } else if (mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) {
+ ALOGV("Recording Source: Voice Call UpLink");
+ voc_rec_cfg.rec_mode = VOC_REC_UPLINK;
+ }
+ if (ioctl(mFdin, AUDIO_SET_INCALL, &voc_rec_cfg)) {
+ ALOGE("Error: AUDIO_SET_INCALL failed\n");
+ goto Error;
+ }
+ }
+#ifdef QCOM_ACDB_ENABLED
+ if(vr_enable && dualmic_enabled) {
+ int audpre_mask = 0;
+ audpre_mask = FLUENCE_ENABLE;
+
+ ALOGV("enable fluence");
+ if (ioctl(mFdin, AUDIO_ENABLE_AUDPRE, &audpre_mask)) {
+ ALOGV("cannot write audio config");
+ goto Error;
+ }
+ }
+#endif
+ }
+ //mHardware->setMicMute_nosync(false);
+ mState = AUDIO_INPUT_OPENED;
+#ifdef HTC_ACOUSTIC_AUDIO
+ mHardware->set_mRecordState(true);
+#endif
+
+ if (!acoustic)
+ {
+ return NO_ERROR;
+ }
+#ifdef QCOM_ACDB_ENABLED
+ int (*msm8x60_set_audpre_params)(int, int);
+ msm8x60_set_audpre_params = (int (*)(int, int))::dlsym(acoustic, "msm8x60_set_audpre_params");
+ if ((*msm8x60_set_audpre_params) == 0) {
+ ALOGI("msm8x60_set_audpre_params not present");
+ return NO_ERROR;
+ }
+
+ int (*msm8x60_enable_audpre)(int, int, int);
+ msm8x60_enable_audpre = (int (*)(int, int, int))::dlsym(acoustic, "msm8x60_enable_audpre");
+ if ((*msm8x60_enable_audpre) == 0) {
+ ALOGI("msm8x60_enable_audpre not present");
+ return NO_ERROR;
+ }
+
+ audpre_index = calculate_audpre_table_index(mSampleRate);
+ tx_iir_index = (audpre_index * 2) + (hw->checkOutputStandby() ? 0 : 1);
+ ALOGD("audpre_index = %d, tx_iir_index = %d\n", audpre_index, tx_iir_index);
+
+ /**
+ * If audio-preprocessing failed, we should not block record.
+ */
+ status = msm8x60_set_audpre_params(audpre_index, tx_iir_index);
+ if (status < 0)
+ ALOGE("Cannot set audpre parameters");
+
+ mAcoustics = acoustic_flags;
+ status = msm8x60_enable_audpre((int)acoustic_flags, audpre_index, tx_iir_index);
+ if (status < 0)
+ ALOGE("Cannot enable audpre");
+#endif
+ return NO_ERROR;
+
+Error:
+ if (mFdin >= 0) {
+ ::close(mFdin);
+ mFdin = -1;
+ }
+ return status;
+}
+
+AudioHardware::AudioStreamInMSM8x60::~AudioStreamInMSM8x60()
+{
+ ALOGV("AudioStreamInMSM8x60 destructor");
+ standby();
+}
+
+ssize_t AudioHardware::AudioStreamInMSM8x60::read( void* buffer, ssize_t bytes)
+{
+ unsigned short dec_id = INVALID_DEVICE;
+ ALOGV("AudioStreamInMSM8x60::read(%p, %ld)", buffer, bytes);
+ if (!mHardware) return -1;
+
+ size_t count = bytes;
+ size_t aac_framesize= bytes;
+ uint8_t* p = static_cast<uint8_t*>(buffer);
+ uint32_t* recogPtr = (uint32_t *)p;
+ uint16_t* frameCountPtr;
+ uint16_t* frameSizePtr;
+
+ if (mState < AUDIO_INPUT_OPENED) {
+ AudioHardware *hw = mHardware;
+ hw->mLock.lock();
+ status_t status = set(hw, mDevices, &mFormat, &mChannels, &mSampleRate, mAcoustics);
+ if (status != NO_ERROR) {
+ hw->mLock.unlock();
+ return -1;
+ }
+#ifdef QCOM_FM_ENABLED
+ if((mDevices == AudioSystem::DEVICE_IN_FM_RX) || (mDevices == AudioSystem::DEVICE_IN_FM_RX_A2DP) ){
+ if(ioctl(mFdin, AUDIO_GET_SESSION_ID, &dec_id)) {
+ ALOGE("AUDIO_GET_SESSION_ID failed*********");
+ hw->mLock.unlock();
+ return -1;
+ }
+
+ if(enableDevice(DEVICE_FMRADIO_STEREO_TX, 1)) {
+ ALOGE("enableDevice DEVICE_FMRADIO_STEREO_TX failed");
+ hw->mLock.unlock();
+ return -1;
+ }
+
+ acdb_loader_send_audio_cal(ACDB_ID(DEVICE_FMRADIO_STEREO_TX),
+ CAPABILITY(DEVICE_FMRADIO_STEREO_TX));
+
+ ALOGV("route FM");
+ if(msm_route_stream(PCM_REC, dec_id, DEV_ID(DEVICE_FMRADIO_STEREO_TX), 1)) {
+ ALOGE("msm_route_stream failed");
+ hw->mLock.unlock();
+ return -1;
+ }
+
+ //addToTable(dec_id,cur_tx,INVALID_DEVICE,PCM_REC,true);
+ mFirstread = false;
+ if (mDevices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
+ addToTable(dec_id,cur_tx,INVALID_DEVICE,FM_A2DP,true);
+ mFmRec = FM_A2DP_REC;
+ } else {
+ addToTable(dec_id,cur_tx,INVALID_DEVICE,FM_REC,true);
+ mFmRec = FM_FILE_REC;
+ }
+ hw->mLock.unlock();
+ } else
+#endif
+ {
+ hw->mLock.unlock();
+ if(ioctl(mFdin, AUDIO_GET_SESSION_ID, &dec_id)) {
+ ALOGE("AUDIO_GET_SESSION_ID failed*********");
+ return -1;
+ }
+ Mutex::Autolock lock(mDeviceSwitchLock);
+ if (!(mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK ||
+ mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK)) {
+ ALOGV("dec_id = %d,cur_tx= %d",dec_id,cur_tx);
+ if(cur_tx == INVALID_DEVICE)
+ cur_tx = DEVICE_HANDSET_TX;
+ if(enableDevice(cur_tx, 1)) {
+ ALOGE("enableDevice failed for device cur_rx %d",cur_rx);
+ return -1;
+ }
+#ifdef QCOM_ACDB_ENABLED
+ acdb_loader_send_audio_cal(ACDB_ID(cur_tx), CAPABILITY(cur_tx));
+#endif
+ if(msm_route_stream(PCM_REC, dec_id, DEV_ID(cur_tx), 1)) {
+ ALOGE("msm_route_stream failed");
+ return -1;
+ }
+ addToTable(dec_id,cur_tx,INVALID_DEVICE,PCM_REC,true);
+ }
+ mFirstread = false;
+ }
+ }
+
+
+ if (mState < AUDIO_INPUT_STARTED) {
+ if (!(mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK ||
+ mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK)) {
+#ifdef QCOM_FM_ENABLED
+ // force routing to input device
+ // for FM recording, no need to reconfigure afe loopback path
+ if (mFmRec != FM_FILE_REC) {
+#endif
+ mHardware->clearCurDevice();
+ mHardware->doRouting(this);
+#ifdef HTC_ACOUSTIC_AUDIO
+ if (support_aic3254) {
+ int snd_dev = mHardware->get_snd_dev();
+ mHardware->aic3254_config(snd_dev);
+ mHardware->do_aic3254_control(snd_dev);
+ }
+#endif
+#ifdef QCOM_FM_ENABLED
+ }
+#endif
+ }
+ if (ioctl(mFdin, AUDIO_START, 0)) {
+ ALOGE("Error starting record");
+ standby();
+ return -1;
+ }
+ mState = AUDIO_INPUT_STARTED;
+ }
+
+ bytes = 0;
+ if(mFormat == AUDIO_HW_IN_FORMAT)
+ {
+ if(count < mBufferSize) {
+ ALOGE("read:: read size requested is less than min input buffer size");
+ return 0;
+ }
+ while (count >= mBufferSize) {
+ ssize_t bytesRead = ::read(mFdin, buffer, count);
+ usleep(1);
+ if (bytesRead >= 0) {
+ count -= bytesRead;
+ p += bytesRead;
+ bytes += bytesRead;
+ if(!mFirstread)
+ {
+ mFirstread = true;
+ ALOGE(" FirstRead Done bytesRead = %d count = %d",bytesRead,count);
+ break;
+ }
+ } else {
+ if (errno != EAGAIN) return bytesRead;
+ mRetryCount++;
+ ALOGW("EAGAIN - retrying");
+ }
+ }
+ }
+
+ return bytes;
+}
+
+status_t AudioHardware::AudioStreamInMSM8x60::standby()
+{
+ bool isDriverClosed = false;
+ ALOGD("AudioStreamInMSM8x60::standby()");
+ Routing_table* temp = NULL;
+ if (!mHardware) return -1;
+#ifdef HTC_ACOUSTIC_AUDIO
+ mHardware->set_mRecordState(false);
+ if (support_aic3254) {
+ int snd_dev = mHardware->get_snd_dev();
+ mHardware->aic3254_config(snd_dev);
+ mHardware->do_aic3254_control(snd_dev);
+ }
+#endif
+ if (mState > AUDIO_INPUT_CLOSED) {
+ if (mFdin >= 0) {
+ ::close(mFdin);
+ mFdin = -1;
+ ALOGV("driver closed");
+ isDriverClosed = true;
+ if(mHardware->mNumPcmRec && mFormat == AUDIO_HW_IN_FORMAT) {
+ mHardware->mNumPcmRec --;
+ }
+ }
+ mState = AUDIO_INPUT_CLOSED;
+ }
+#ifdef QCOM_FM_ENABLED
+ if (mFmRec == FM_A2DP_REC) {
+ //A2DP Recording
+ temp = getNodeByStreamType(FM_A2DP);
+ if(temp == NULL)
+ return NO_ERROR;
+ if(msm_route_stream(PCM_PLAY, temp->dec_id, DEV_ID(DEVICE_FMRADIO_STEREO_TX), 0)) {
+ ALOGE("msm_route_stream failed");
+ return 0;
+ }
+ deleteFromTable(FM_A2DP);
+ if(enableDevice(DEVICE_FMRADIO_STEREO_TX, 0)) {
+ ALOGE("enableDevice failed for device cur_rx %d", cur_rx);
+ }
+ }
+ if (mFmRec == FM_FILE_REC) {
+ //FM Recording
+ temp = getNodeByStreamType(FM_REC);
+ if(temp == NULL)
+ return NO_ERROR;
+ if(msm_route_stream(PCM_PLAY, temp->dec_id, DEV_ID(DEVICE_FMRADIO_STEREO_TX), 0)) {
+ ALOGE("msm_route_stream failed");
+ return 0;
+ }
+ deleteFromTable(FM_REC);
+ }
+#endif
+ temp = getNodeByStreamType(PCM_REC);
+ if(temp == NULL)
+ return NO_ERROR;
+
+ if(isDriverClosed){
+ ALOGV("Deroute pcm stream");
+ if (!(mChannels & AudioSystem::CHANNEL_IN_VOICE_DNLINK ||
+ mChannels & AudioSystem::CHANNEL_IN_VOICE_UPLINK)) {
+ if(msm_route_stream(PCM_REC, temp->dec_id,DEV_ID(temp->dev_id), 0)) {
+ ALOGE("could not set stream routing\n");
+ deleteFromTable(PCM_REC);
+ return -1;
+ }
+ }
+ ALOGV("Disable device");
+ deleteFromTable(PCM_REC);
+ if(!getNodeByStreamType(VOICE_CALL)
+#ifdef QCOM_VOIP_ENABLED
+ && !getNodeByStreamType(VOIP_CALL)
+#endif
+ ) {
+ if(enableDevice(cur_tx, 0)) {
+ ALOGE("Disabling device failed for cur_tx %d", cur_tx);
+ return 0;
+ }
+ }
+ } //isDriverClosed condition
+ // restore output routing if necessary
+ mHardware->clearCurDevice();
+ mHardware->doRouting(this);
+ return NO_ERROR;
+}
+
+status_t AudioHardware::AudioStreamInMSM8x60::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ result.append("AudioStreamInMSM8x60::dump\n");
+ snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tformat: %d\n", format());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmHardware: %p\n", mHardware);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmFd count: %d\n", mFdin);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmState: %d\n", mState);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmRetryCount: %d\n", mRetryCount);
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioHardware::AudioStreamInMSM8x60::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key = String8(AudioParameter::keyRouting);
+ status_t status = NO_ERROR;
+ int device;
+ ALOGV("AudioStreamInMSM8x60::setParameters() %s", keyValuePairs.string());
+
+ if (param.getInt(String8("vr_mode"), mForVR) == NO_ERROR)
+ ALOGV("voice_recognition=%d", mForVR);
+
+ if (param.getInt(key, device) == NO_ERROR) {
+ ALOGV("set input routing %x", device);
+ if (device & (device - 1)) {
+ status = BAD_VALUE;
+ } else if (device) {
+ mDevices = device;
+ status = mHardware->doRouting(this);
+ }
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 AudioHardware::AudioStreamInMSM8x60::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8(AudioParameter::keyRouting);
+
+ if (param.get(key, value) == NO_ERROR) {
+ ALOGV("get routing %x", mDevices);
+ param.addInt(key, (int)mDevices);
+ }
+
+ ALOGV("AudioStreamInMSM8x60::getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+// getActiveInput_l() must be called with mLock held
+AudioHardware::AudioStreamInMSM8x60 *AudioHardware::getActiveInput_l()
+{
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ // return first input found not being in standby mode
+ // as only one input can be in this state
+ if (mInputs[i]->state() > AudioStreamInMSM8x60::AUDIO_INPUT_CLOSED) {
+ return mInputs[i];
+ }
+ }
+
+ return NULL;
+}
+
+#ifdef QCOM_VOIP_ENABLED
+// ----------------------------------------------------------------------------
+// VOIP stream class
+//.----------------------------------------------------------------------------
+AudioHardware::AudioStreamInVoip::AudioStreamInVoip() :
+ mHardware(0), mFd(-1), mState(AUDIO_INPUT_CLOSED), mRetryCount(0),
+ mFormat(AUDIO_HW_IN_FORMAT), mChannels(AUDIO_HW_IN_CHANNELS),
+ mSampleRate(AUDIO_HW_VOIP_SAMPLERATE_8K), mBufferSize(AUDIO_HW_VOIP_BUFFERSIZE_8K),
+ mAcoustics((AudioSystem::audio_in_acoustics)0), mDevices(0)
+{
+}
+
+status_t AudioHardware::AudioStreamInVoip::set(
+ AudioHardware* hw, uint32_t devices, int *pFormat, uint32_t *pChannels, uint32_t *pRate,
+ AudioSystem::audio_in_acoustics acoustic_flags)
+{
+ ALOGV(" AudioHardware::AudioStreamInVoip::set devices = %u format = %d pChannels = %u Rate = %u \n",
+ devices, *pFormat, *pChannels, *pRate);
+ ALOGV("AudioStreamInVoip cur_rx %d, cur_tx %d" ,cur_rx,cur_tx);
+ if ((pFormat == 0) || (*pFormat != AUDIO_HW_IN_FORMAT))
+ {
+ *pFormat = AUDIO_HW_IN_FORMAT;
+ return BAD_VALUE;
+ }
+
+ if (pRate == 0) {
+ return BAD_VALUE;
+ }
+ uint32_t rate = hw->getInputSampleRate(*pRate);
+ if (rate != *pRate) {
+ *pRate = rate;
+ ALOGE(" sample rate does not match\n");
+ return BAD_VALUE;
+ }
+
+ if (pChannels == 0 || (*pChannels & (AudioSystem::CHANNEL_IN_MONO)) == 0) {
+ *pChannels = AUDIO_HW_IN_CHANNELS;
+ ALOGE(" Channle count does not match\n");
+ return BAD_VALUE;
+ }
+
+ mHardware = hw;
+
+ ALOGV("AudioStreamInVoip::set(%d, %d, %u)", *pFormat, *pChannels, *pRate);
+ if (mFd >= 0) {
+ ALOGE("Audio record already open");
+ return -EPERM;
+ }
+
+ status_t status = NO_INIT;
+ // open driver
+ ALOGV("Check if driver is open");
+ if(mHardware->mVoipFd >= 0) {
+ mFd = mHardware->mVoipFd;
+ // Increment voip stream count
+ mHardware->mNumVoipStreams++;
+ ALOGV("MVS driver is already opened, mHardware->mNumVoipStreams = %d \n", mHardware->mNumVoipStreams);
+ }
+ else {
+ ALOGE("open mvs driver");
+ status = ::open(MVS_DEVICE, /*O_WRONLY*/ O_RDWR);
+ if (status < 0) {
+ ALOGE("Cannot open %s errno: %d",MVS_DEVICE, errno);
+ goto Error;
+ }
+ mFd = status;
+ ALOGE("VOPIstreamin : Save the fd \n");
+ mHardware->mVoipFd = mFd;
+ // Increment voip stream count
+ mHardware->mNumVoipStreams++;
+ ALOGV(" input stream set mHardware->mNumVoipStreams = %d \n", mHardware->mNumVoipStreams);
+
+ // configuration
+ ALOGV("get mvs config");
+ struct msm_audio_mvs_config mvs_config;
+ status = ioctl(mFd, AUDIO_GET_MVS_CONFIG, &mvs_config);
+ if (status < 0) {
+ ALOGE("Cannot read mvs config");
+ goto Error;
+ }
+
+ ALOGV("set mvs config");
+ int samplerate = *pRate;
+ if(samplerate == AUDIO_HW_VOIP_SAMPLERATE_8K) {
+ mvs_config.mvs_mode = MVS_MODE_PCM;
+ } else if(samplerate == AUDIO_HW_VOIP_SAMPLERATE_16K) {
+ mvs_config.mvs_mode = MVS_MODE_PCM_WB;
+ } else {
+ ALOGE("unsupported samplerate for voip");
+ goto Error;
+ }
+ status = ioctl(mFd, AUDIO_SET_MVS_CONFIG, &mvs_config);
+ if (status < 0) {
+ ALOGE("Cannot set mvs config");
+ goto Error;
+ }
+
+ ALOGV("start mvs");
+ status = ioctl(mFd, AUDIO_START, 0);
+ if (status < 0) {
+ ALOGE("Cannot start mvs driver");
+ goto Error;
+ }
+
+ ALOGV("Going to enable RX/TX device for voice stream");
+
+ Mutex::Autolock lock(mDeviceSwitchLock);
+ // Routing Voip
+ if ( (cur_rx != INVALID_DEVICE) && (cur_tx != INVALID_DEVICE))
+ {
+ ALOGV("Starting voip on Rx %d and Tx %d device", DEV_ID(cur_rx), DEV_ID(cur_tx));
+ msm_route_voice(DEV_ID(cur_rx),DEV_ID(cur_tx), 1);
+ }
+ else
+ {
+ return -1;
+ }
+
+ if(cur_rx != INVALID_DEVICE && (enableDevice(cur_rx,1) == -1))
+ {
+ ALOGE(" Enable device for cur_rx failed \n");
+ return -1;
+ }
+
+ if(cur_tx != INVALID_DEVICE&&(enableDevice(cur_tx,1) == -1))
+ {
+ ALOGE(" Enable device for cur_tx failed \n");
+ return -1;
+ }
+#ifdef QCOM_ACDB_ENABLED
+ // voice calibration
+ acdb_loader_send_voice_cal(ACDB_ID(cur_rx),ACDB_ID(cur_tx));
+#endif
+ // start Voice call
+#ifdef LEGACY_QCOM_VOICE
+ msm_start_voice();
+ msm_set_voice_tx_mute(0);
+#else
+ if(voip_session_id <= 0) {
+ voip_session_id = msm_get_voc_session(VOIP_SESSION_NAME);
+ }
+ ALOGD("Starting voip call and UnMuting the call");
+ msm_start_voice_ext(voip_session_id);
+ msm_set_voice_tx_mute_ext(voip_session_mute,voip_session_id);
+#endif
+ addToTable(0,cur_rx,cur_tx,VOIP_CALL,true);
+ }
+ mFormat = *pFormat;
+ mChannels = *pChannels;
+ mSampleRate = *pRate;
+ if(mSampleRate == 8000)
+ mBufferSize = 320;
+ else if(mSampleRate == 16000)
+ mBufferSize = 640;
+ else
+ {
+ ALOGE(" unsupported sample rate");
+ return -1;
+ }
+
+ ALOGV(" AudioHardware::AudioStreamInVoip::set after configuring devices = %u format = %d pChannels = %u Rate = %u \n",
+ devices, mFormat, mChannels, mSampleRate);
+
+ ALOGV(" Set state AUDIO_INPUT_OPENED\n");
+ mState = AUDIO_INPUT_OPENED;
+
+ if (!acoustic)
+ return NO_ERROR;
+
+ return NO_ERROR;
+
+Error:
+ if (mFd >= 0) {
+ ::close(mFd);
+ mFd = -1;
+ mHardware->mVoipFd = -1;
+ }
+ ALOGE("Error : ret status \n");
+ return status;
+}
+
+AudioHardware::AudioStreamInVoip::~AudioStreamInVoip()
+{
+ ALOGV("AudioStreamInVoip destructor");
+ standby();
+ if (mHardware->mNumVoipStreams)
+ mHardware->mNumVoipStreams--;
+}
+
+ssize_t AudioHardware::AudioStreamInVoip::read( void* buffer, ssize_t bytes)
+{
+ unsigned short dec_id = INVALID_DEVICE;
+ ALOGV("AudioStreamInVoip::read(%p, %ld)", buffer, bytes);
+ if (!mHardware) return -1;
+
+ size_t count = bytes;
+ size_t totalBytesRead = 0;
+ size_t aac_framesize= bytes;
+ uint8_t* p = static_cast<uint8_t*>(buffer);
+ uint32_t* recogPtr = (uint32_t *)p;
+ uint16_t* frameCountPtr;
+ uint16_t* frameSizePtr;
+ if (mState < AUDIO_INPUT_OPENED) {
+ ALOGE(" reopen the device \n");
+ AudioHardware *hw = mHardware;
+ hw->mLock.lock();
+ status_t status = set(hw, mDevices, &mFormat, &mChannels, &mSampleRate, mAcoustics);
+ if (status != NO_ERROR) {
+ hw->mLock.unlock();
+ return -1;
+ }
+ hw->mLock.unlock();
+ mState = AUDIO_INPUT_STARTED;
+ bytes = 0;
+ } else {
+ ALOGE("AudioStreamInVoip::read : device is already open \n");
+ }
+
+
+ if(mFormat == AUDIO_HW_IN_FORMAT)
+ {
+ if(count < mBufferSize) {
+ ALOGE("read:: read size requested is less than min input buffer size");
+ return 0;
+ }
+
+ struct msm_audio_mvs_frame audio_mvs_frame;
+ audio_mvs_frame.frame_type = 0;
+ while (count >= mBufferSize) {
+ audio_mvs_frame.len = count;
+ ALOGV("Calling read count = %u mBufferSize = %u\n",count, mBufferSize );
+ int bytesRead = ::read(mFd, &audio_mvs_frame, sizeof(audio_mvs_frame));
+ ALOGV("read_bytes = %d \n", bytesRead);
+ if (bytesRead > 0) {
+ memcpy(buffer,&audio_mvs_frame.voc_pkt, count);
+ count -= audio_mvs_frame.len;
+ p += audio_mvs_frame.len;
+ totalBytesRead += audio_mvs_frame.len;
+ if(!mFirstread) {
+ mFirstread = true;
+ break;
+ }
+ } else {
+ ALOGE("retry read count = %d buffersize = %d\n", count, mBufferSize);
+ if (errno != EAGAIN) return bytesRead;
+ mRetryCount++;
+ ALOGW("EAGAIN - retrying");
+ }
+ }
+ }
+ return totalBytesRead;
+}
+
+status_t AudioHardware::AudioStreamInVoip::standby()
+{
+ bool isDriverClosed = false;
+ Routing_table* temp = NULL;
+ if (!mHardware) return -1;
+ ALOGV(" AudioStreamInVoip::standby = %d \n", mHardware->mNumVoipStreams);
+ if (mState > AUDIO_INPUT_CLOSED && (mHardware->mNumVoipStreams == 1)) {
+ ALOGE(" closing mvs driver\n");
+ //Mute and disable the device.
+ int ret = 0;
+#ifdef LEGACY_QCOM_VOICE
+ msm_end_voice();
+#else
+ ret = msm_end_voice_ext(voip_session_id);
+ if (ret < 0)
+ ALOGE("Error %d ending voice\n", ret);
+#endif
+ temp = getNodeByStreamType(VOIP_CALL);
+ if(temp == NULL)
+ {
+ ALOGE("VOIPin: Going to disable RX/TX return 0");
+ return 0;
+ }
+
+ if((temp->dev_id != INVALID_DEVICE && temp->dev_id_tx != INVALID_DEVICE)) {
+ if(!getNodeByStreamType(VOICE_CALL)
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+ && !getNodeByStreamType(LPA_DECODE)
+#endif /*QCOM_TUNNEL_LPA_ENABLED*/
+ && !getNodeByStreamType(PCM_PLAY)
+#ifdef QCOM_FM_ENABLED
+ && !getNodeByStreamType(FM_RADIO)
+#endif /*QCOM_FM_ENABLED*/
+ ) {
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ if (anc_running == false) {
+#endif
+ enableDevice(temp->dev_id, 0);
+ ALOGV("Voipin: disable voip rx");
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ }
+#endif
+ }
+ if(!getNodeByStreamType(VOICE_CALL) && !getNodeByStreamType(PCM_REC)) {
+ enableDevice(temp->dev_id_tx,0);
+ ALOGD("VOIPin: disable voip tx");
+ }
+ }
+ deleteFromTable(VOIP_CALL);
+ if (mFd >= 0) {
+ ret = ioctl(mFd, AUDIO_STOP, NULL);
+ ALOGE("MVS stop returned %d \n", ret);
+ ::close(mFd);
+ mFd = mHardware->mVoipFd = -1;
+ ALOGV("driver closed");
+ isDriverClosed = true;
+ voip_session_id = 0;
+ voip_session_mute = 0;
+ }
+ mState = AUDIO_INPUT_CLOSED;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioHardware::AudioStreamInVoip::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ result.append("AudioStreamInVoip::dump\n");
+ snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tformat: %d\n", format());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmHardware: %p\n", mHardware);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmFd count: %d\n", mFd);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmState: %d\n", mState);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmRetryCount: %d\n", mRetryCount);
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioHardware::AudioStreamInVoip::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key = String8(AudioParameter::keyRouting);
+ status_t status = NO_ERROR;
+ int device;
+ ALOGV("AudioStreamInVoip::setParameters() %s", keyValuePairs.string());
+
+ if (param.getInt(key, device) == NO_ERROR) {
+ ALOGV("set input routing %x", device);
+ if (device & (device - 1)) {
+ status = BAD_VALUE;
+ } else {
+ mDevices = device;
+ status = mHardware->doRouting(this);
+ }
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 AudioHardware::AudioStreamInVoip::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8(AudioParameter::keyRouting);
+
+ if (param.get(key, value) == NO_ERROR) {
+ ALOGV("get routing %x", mDevices);
+ param.addInt(key, (int)mDevices);
+ }
+
+ ALOGV("AudioStreamInVoip::getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+// getActiveInput_l() must be called with mLock held
+AudioHardware::AudioStreamInVoip*AudioHardware::getActiveVoipInput_l()
+{
+ for (size_t i = 0; i < mVoipInputs.size(); i++) {
+ // return first input found not being in standby mode
+ // as only one input can be in this state
+ if (mVoipInputs[i]->state() > AudioStreamInVoip::AUDIO_INPUT_CLOSED) {
+ return mVoipInputs[i];
+ }
+ }
+
+ return NULL;
+}
+// ---------------------------------------------------------------------------
+// VOIP stream class end
+#endif
+
+extern "C" AudioHardwareInterface* createAudioHardware(void) {
+ return new AudioHardware();
+}
+
+}; // namespace android_audio_legacy
diff --git a/msm8660/AudioHardware.h b/msm8660/AudioHardware.h
new file mode 100644
index 0000000..d66d941
--- /dev/null
+++ b/msm8660/AudioHardware.h
@@ -0,0 +1,581 @@
+/*
+** Copyright 2008, The Android Open-Source Project
+** Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+**
+** 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 ANDROID_AUDIO_HARDWARE_H
+#define ANDROID_AUDIO_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/List.h>
+
+#include <utils/threads.h>
+#include <sys/prctl.h>
+#include <utils/SortedVector.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+extern "C" {
+#include <linux/msm_audio.h>
+#include <linux/ion.h>
+#include <linux/msm_audio_aac.h>
+}
+namespace android_audio_legacy {
+using android::List;
+using android::SortedVector;
+using android::Mutex;
+using android::Condition;
+
+// ----------------------------------------------------------------------------
+// Kernel driver interface
+//
+
+#define SAMP_RATE_INDX_8000 0
+#define SAMP_RATE_INDX_11025 1
+#define SAMP_RATE_INDX_12000 2
+#define SAMP_RATE_INDX_16000 3
+#define SAMP_RATE_INDX_22050 4
+#define SAMP_RATE_INDX_24000 5
+#define SAMP_RATE_INDX_32000 6
+#define SAMP_RATE_INDX_44100 7
+#define SAMP_RATE_INDX_48000 8
+
+#define EQ_MAX_BAND_NUM 12
+
+#define ADRC_ENABLE 0x0001
+#define ADRC_DISABLE 0x0000
+#define EQ_ENABLE 0x0002
+#define EQ_DISABLE 0x0000
+#define RX_IIR_ENABLE 0x0004
+#define RX_IIR_DISABLE 0x0000
+#define LPA_BUFFER_SIZE 512*1024
+#define BUFFER_COUNT 2
+#define MONO_CHANNEL_MODE 1
+
+#ifdef HTC_ACOUSTIC_AUDIO
+ #define MOD_PLAY 1
+ #define MOD_REC 2
+ #define MOD_TX 3
+ #define MOD_RX 4
+
+ #define ACDB_ID_HEADSET_PLAYBACK 10
+ #define ACDB_ID_ALT_SPKR_PLAYBACK 601
+
+ #define ACDB_ID_HAC_HANDSET_MIC 107
+ #define ACDB_ID_HAC_HANDSET_SPKR 207
+ #define ACDB_ID_EXT_MIC_REC 307
+ #define ACDB_ID_HEADSET_RINGTONE_PLAYBACK 408
+ #define ACDB_ID_INT_MIC_REC 507
+ #define ACDB_ID_CAMCORDER 508
+ #define ACDB_ID_INT_MIC_VR 509
+ #define ACDB_ID_SPKR_PLAYBACK 607
+
+ struct msm_bt_endpoint {
+ int tx;
+ int rx;
+ char name[64];
+ };
+#endif
+
+struct eq_filter_type {
+ int16_t gain;
+ uint16_t freq;
+ uint16_t type;
+ uint16_t qf;
+};
+
+struct eqalizer {
+ uint16_t bands;
+ uint16_t params[132];
+};
+
+struct rx_iir_filter {
+ uint16_t num_bands;
+ uint16_t iir_params[48];
+};
+
+enum tty_modes {
+ TTY_OFF = 0,
+ TTY_VCO = 1,
+ TTY_HCO = 2,
+ TTY_FULL = 3
+};
+
+#define CODEC_TYPE_PCM 0
+#define AUDIO_HW_NUM_OUT_BUF 2 // Number of buffers in audio driver for output
+// TODO: determine actual audio DSP and hardware latency
+#define AUDIO_HW_OUT_LATENCY_MS 0 // Additionnal latency introduced by audio DSP and hardware in ms
+
+#define AUDIO_HW_IN_SAMPLERATE 8000 // Default audio input sample rate
+#define AUDIO_HW_IN_CHANNELS (AudioSystem::CHANNEL_IN_MONO) // Default audio input channel mask
+#define AUDIO_HW_IN_BUFFERSIZE 480 * 4 // Default audio input buffer size
+#define AUDIO_HW_IN_FORMAT (AudioSystem::PCM_16_BIT) // Default audio input sample format
+#ifdef QCOM_VOIP_ENABLED
+#define AUDIO_HW_VOIP_BUFFERSIZE_8K 320
+#define AUDIO_HW_VOIP_BUFFERSIZE_16K 640
+#define AUDIO_HW_VOIP_SAMPLERATE_8K 8000
+#define AUDIO_HW_VOIP_SAMPLERATE_16K 16000
+#endif
+
+class AudioHardware : public AudioHardwareBase
+{
+ class AudioStreamOutMSM8x60;
+ class AudioSessionOutLPA;
+ class AudioStreamInMSM8x60;
+#ifdef QCOM_VOIP_ENABLED
+ class AudioStreamOutDirect;
+ class AudioStreamInVoip;
+#endif
+
+public:
+ AudioHardware();
+ virtual ~AudioHardware();
+ virtual status_t initCheck();
+
+ virtual status_t setVoiceVolume(float volume);
+ virtual status_t setMasterVolume(float volume);
+#ifdef QCOM_FM_ENABLED
+ virtual status_t setFmVolume(float volume);
+#endif
+ virtual status_t setMode(int mode);
+
+ // mic mute
+ virtual status_t setMicMute(bool state);
+ virtual status_t getMicMute(bool* state);
+
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+
+ // create I/O streams
+ virtual AudioStreamOut* openOutputStream(
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
+ status_t *status=0);
+ virtual AudioStreamIn* openInputStream(
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
+ status_t *status,
+ AudioSystem::audio_in_acoustics acoustics);
+
+ virtual void closeOutputStream(AudioStreamOut* out);
+ virtual void closeInputStream(AudioStreamIn* in);
+
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+ void clearCurDevice() { mCurSndDevice = -1; }
+
+protected:
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+
+ status_t doAudioRouteOrMute(uint32_t device);
+ status_t setMicMute_nosync(bool state);
+ status_t checkMicMute();
+ status_t dumpInternals(int fd, const Vector<String16>& args);
+ uint32_t getInputSampleRate(uint32_t sampleRate);
+ bool checkOutputStandby();
+#ifdef HTC_ACOUSTIC_AUDIO
+ status_t get_mMode();
+ status_t set_mRecordState(bool onoff);
+ status_t get_mRecordState();
+ status_t get_snd_dev();
+#endif
+ status_t doRouting(AudioStreamInMSM8x60 *input);
+#ifdef HTC_ACOUSTIC_AUDIO
+ void getACDB(uint32_t device);
+ status_t do_aic3254_control(uint32_t device);
+ bool isAic3254Device(uint32_t device);
+ status_t aic3254_config(uint32_t device);
+ int aic3254_ioctl(int cmd, const int argc);
+ void aic3254_powerdown();
+#endif
+#ifdef QCOM_FM_ENABLED
+ status_t enableFM(int sndDevice);
+#endif
+ status_t enableComboDevice(uint32_t sndDevice, bool enableOrDisable);
+#ifdef QCOM_FM_ENABLED
+ status_t disableFM();
+#endif
+ AudioStreamInMSM8x60* getActiveInput_l();
+#ifdef QCOM_VOIP_ENABLED
+ AudioStreamInVoip* getActiveVoipInput_l();
+#endif
+ class AudioStreamOutMSM8x60 : public AudioStreamOut {
+ public:
+ AudioStreamOutMSM8x60();
+ virtual ~AudioStreamOutMSM8x60();
+ status_t set(AudioHardware* mHardware,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate);
+ virtual uint32_t sampleRate() const { return 44100; }
+ // must be 32-bit aligned - driver only seems to like 4800
+ virtual size_t bufferSize() const { return 4800; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ virtual uint32_t latency() const { return (1000*AUDIO_HW_NUM_OUT_BUF*(bufferSize()/frameSize()))/sampleRate()+AUDIO_HW_OUT_LATENCY_MS; }
+ virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; }
+ virtual ssize_t write(const void* buffer, size_t bytes);
+ virtual status_t standby();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ bool checkStandby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ uint32_t devices() { return mDevices; }
+ virtual status_t getRenderPosition(uint32_t *dspFrames);
+
+ private:
+ AudioHardware* mHardware;
+ int mFd;
+ int mStartCount;
+ int mRetryCount;
+ bool mStandby;
+ uint32_t mDevices;
+ };
+#ifdef QCOM_VOIP_ENABLED
+ class AudioStreamOutDirect : public AudioStreamOut {
+ public:
+ AudioStreamOutDirect();
+ virtual ~AudioStreamOutDirect();
+ status_t set(AudioHardware* mHardware,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate);
+ virtual uint32_t sampleRate() const { return mSampleRate; }
+ virtual size_t bufferSize() const { return mBufferSize; }
+ virtual uint32_t channels() const { return mChannels; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ virtual uint32_t latency() const { return (1000*AUDIO_HW_NUM_OUT_BUF*(bufferSize()/frameSize()))/sampleRate()+AUDIO_HW_OUT_LATENCY_MS; }
+ virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; }
+ virtual ssize_t write(const void* buffer, size_t bytes);
+ virtual status_t standby();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ bool checkStandby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ uint32_t devices() { return mDevices; }
+ virtual status_t getRenderPosition(uint32_t *dspFrames);
+
+ private:
+ AudioHardware* mHardware;
+ int mFd;
+ int mStartCount;
+ int mRetryCount;
+ bool mStandby;
+ uint32_t mDevices;
+ uint32_t mChannels;
+ uint32_t mSampleRate;
+ size_t mBufferSize;
+ int mFormat;
+ };
+#endif
+
+class AudioSessionOutLPA : public AudioStreamOut
+{
+public:
+ AudioSessionOutLPA(AudioHardware* mHardware,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t samplingRate,
+ int type,
+ status_t *status);
+ virtual ~AudioSessionOutLPA();
+
+ virtual uint32_t sampleRate() const
+ {
+ return mSampleRate;
+ }
+
+ virtual size_t bufferSize() const
+ {
+ return mBufferSize;
+ }
+
+ virtual uint32_t channels() const
+ {
+ return mChannels;
+ }
+
+ virtual int format() const
+ {
+ return mFormat;
+ }
+
+ virtual uint32_t latency() const;
+
+ virtual ssize_t write(const void *buffer, size_t bytes);
+
+ virtual status_t start( );
+ virtual status_t pause();
+ virtual status_t flush();
+ virtual status_t stop();
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ status_t setVolume(float left, float right);
+
+ virtual status_t standby();
+
+ virtual status_t setParameters(const String8& keyValuePairs);
+
+ virtual String8 getParameters(const String8& keys);
+
+
+ // return the number of audio frames written by the audio dsp to DAC since
+ // the output has exited standby
+ virtual status_t getRenderPosition(uint32_t *dspFrames);
+
+ virtual status_t getNextWriteTimestamp(int64_t *timestamp);
+ virtual status_t setObserver(void *observer);
+ virtual status_t getBufferInfo(buf_info **buf);
+ virtual status_t isBufferAvailable(int *isAvail);
+
+ void* memBufferAlloc(int nSize, int32_t *ion_fd);
+
+private:
+ Mutex mLock;
+ uint32_t mFrameCount;
+ uint32_t mSampleRate;
+ uint32_t mChannels;
+ size_t mBufferSize;
+ int mFormat;
+ uint32_t mStreamVol;
+
+ bool mPaused;
+ bool mIsDriverStarted;
+ bool mSeeking;
+ bool mReachedEOS;
+ bool mSkipWrite;
+ bool mEosEventReceived;
+ uint32_t mDevices;
+ AudioHardware* mHardware;
+ AudioEventObserver *mObserver;
+
+ void createEventThread();
+ void bufferAlloc();
+ void bufferDeAlloc();
+ bool isReadyToPostEOS(int errPoll, void *fd);
+ status_t drain();
+ status_t openAudioSessionDevice();
+ // make sure the event thread also exited
+ void requestAndWaitForEventThreadExit();
+ int32_t writeToDriver(char *buffer, int bytes);
+ static void * eventThreadWrapper(void *me);
+ void eventThreadEntry();
+//?? status_t pause_l();
+//?? status_t resume_l();
+ void reset();
+
+ //Structure to hold ion buffer information
+ class BuffersAllocated {
+ /* overload BuffersAllocated constructor to support both ion and pmem memory allocation */
+ public:
+ BuffersAllocated(void *buf1, void *buf2, int32_t nSize, int32_t fd) :
+ localBuf(buf1), memBuf(buf2), memBufsize(nSize), memFd(fd)
+ {}
+ BuffersAllocated(void *buf1, void *buf2, int32_t nSize, int32_t share_fd, struct ion_handle *handle) :
+ ion_handle(handle), localBuf(buf1), memBuf(buf2), memBufsize(nSize), memFd(share_fd)
+ {}
+ struct ion_handle *ion_handle;
+ void* localBuf;
+ void* memBuf;
+ int32_t memBufsize;
+ int32_t memFd;
+ uint32_t bytesToWrite;
+ };
+ List<BuffersAllocated> mEmptyQueue;
+ List<BuffersAllocated> mFilledQueue;
+ List<BuffersAllocated> mBufPool;
+
+ //Declare all the threads
+ pthread_t mEventThread;
+
+ //Declare the condition Variables and Mutex
+ Mutex mEmptyQueueMutex;
+ Mutex mFilledQueueMutex;
+
+ Condition mWriteCv;
+ Condition mEventCv;
+ pthread_mutex_t event_mutex;
+ bool mKillEventThread;
+ bool mEventThreadAlive;
+ int mInputBufferSize;
+ int mInputBufferCount;
+ int64_t timePlayed;
+ int64_t timeStarted;
+
+ //event fd to signal the EOS and Kill from the userspace
+ int efd;
+ int afd;
+ int ionfd;
+};
+
+
+ class AudioStreamInMSM8x60 : public AudioStreamIn {
+ public:
+ enum input_state {
+ AUDIO_INPUT_CLOSED,
+ AUDIO_INPUT_OPENED,
+ AUDIO_INPUT_STARTED
+ };
+
+ AudioStreamInMSM8x60();
+ virtual ~AudioStreamInMSM8x60();
+ status_t set(AudioHardware* mHardware,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate,
+ AudioSystem::audio_in_acoustics acoustics);
+ virtual size_t bufferSize() const { return mBufferSize; }
+ virtual uint32_t channels() const { return mChannels; }
+ virtual int format() const { return mFormat; }
+ virtual uint32_t sampleRate() const { return mSampleRate; }
+ virtual status_t setGain(float gain) { return INVALID_OPERATION; }
+ virtual ssize_t read(void* buffer, ssize_t bytes);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t standby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual unsigned int getInputFramesLost() const { return 0; }
+ uint32_t devices() { return mDevices; }
+ int state() const { return mState; }
+ virtual status_t addAudioEffect(effect_interface_s**) { return 0;}
+ virtual status_t removeAudioEffect(effect_interface_s**) { return 0;}
+ virtual int isForVR() const { return mForVR; }
+
+ private:
+ AudioHardware* mHardware;
+ int mState;
+ int mRetryCount;
+ int mFormat;
+ uint32_t mChannels;
+ uint32_t mSampleRate;
+ size_t mBufferSize;
+ AudioSystem::audio_in_acoustics mAcoustics;
+ uint32_t mDevices;
+ bool mFirstread;
+ uint32_t mFmRec;
+ int mForVR;
+ };
+#ifdef QCOM_VOIP_ENABLED
+ class AudioStreamInVoip : public AudioStreamInMSM8x60 {
+ public:
+ enum input_state {
+ AUDIO_INPUT_CLOSED,
+ AUDIO_INPUT_OPENED,
+ AUDIO_INPUT_STARTED
+ };
+
+ AudioStreamInVoip();
+ virtual ~AudioStreamInVoip();
+ status_t set(AudioHardware* mHardware,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate,
+ AudioSystem::audio_in_acoustics acoustics);
+ virtual size_t bufferSize() const { return mBufferSize; }
+ virtual uint32_t channels() const { return mChannels; }
+ virtual int format() const { return AUDIO_HW_IN_FORMAT; }
+ virtual uint32_t sampleRate() const { return mSampleRate; }
+ virtual status_t setGain(float gain) { return INVALID_OPERATION; }
+ virtual ssize_t read(void* buffer, ssize_t bytes);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t standby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual unsigned int getInputFramesLost() const { return 0; }
+ uint32_t devices() { return mDevices; }
+ int state() const { return mState; }
+ virtual int isForVR() const { return 0; }
+
+ private:
+ AudioHardware* mHardware;
+ int mFd;
+ int mState;
+ int mRetryCount;
+ int mFormat;
+ uint32_t mChannels;
+ uint32_t mSampleRate;
+ size_t mBufferSize;
+ AudioSystem::audio_in_acoustics mAcoustics;
+ uint32_t mDevices;
+ bool mFirstread;
+ uint32_t mFmRec;
+ };
+#endif
+ static const uint32_t inputSamplingRates[];
+ bool mInit;
+ bool mMicMute;
+ int mFmFd;
+ bool mBluetoothNrec;
+ bool mBluetoothVGS;
+ uint32_t mBluetoothId;
+#ifdef HTC_ACOUSTIC_AUDIO
+ bool mHACSetting;
+ uint32_t mBluetoothIdTx;
+ uint32_t mBluetoothIdRx;
+#endif
+ AudioStreamOutMSM8x60* mOutput;
+#ifdef QCOM_VOIP_ENABLED
+ AudioStreamOutDirect* mDirectOutput;
+#endif
+ AudioSessionOutLPA* mOutputLPA;
+ SortedVector <AudioStreamInMSM8x60*> mInputs;
+#ifdef QCOM_VOIP_ENABLED
+ SortedVector <AudioStreamInVoip*> mVoipInputs;
+#endif
+#ifdef HTC_ACOUSTIC_AUDIO
+ msm_bt_endpoint *mBTEndpoints;
+ int mNumBTEndpoints;
+#endif
+ int mCurSndDevice;
+#ifdef HTC_ACOUSTIC_AUDIO
+ float mVoiceVolume;
+#endif
+ int mTtyMode;
+ int mNumPcmRec;
+ Mutex mLock;
+#ifdef QCOM_VOIP_ENABLED
+ int mVoipFd;
+ int mNumVoipStreams;
+#endif
+#ifdef HTC_ACOUSTIC_AUDIO
+ int mNoiseSuppressionState;
+ bool mDualMicEnabled;
+ bool mRecordState;
+ char mCurDspProfile[22];
+ bool mEffectEnabled;
+ char mActiveAP[10];
+ char mEffect[10];
+#endif
+
+};
+
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_MSM72XX_H
diff --git a/msm8660/AudioPolicyManager.cpp b/msm8660/AudioPolicyManager.cpp
new file mode 100644
index 0000000..429faf0
--- /dev/null
+++ b/msm8660/AudioPolicyManager.cpp
@@ -0,0 +1,939 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2010-2012, Code Aurora Forum. All rights reserved.
+ *
+ * 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 "AudioPolicyManager"
+
+//#define LOG_NDEBUG 0
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#include <utils/Log.h>
+#include "AudioPolicyManager.h"
+#include <media/mediarecorder.h>
+#include <hardware/audio.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManager for msm8660 platform
+// ----------------------------------------------------------------------------
+audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy, bool fromCache)
+{
+ uint32_t device = 0;
+
+ if (fromCache) {
+ ALOGV("getDeviceForStrategy() from cache strategy %d, device %x",
+ strategy, mDeviceForStrategy[strategy]);
+ return mDeviceForStrategy[strategy];
+ }
+
+ switch (strategy) {
+
+ case STRATEGY_SONIFICATION_RESPECTFUL:
+ if (isInCall()) {
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+ } else if (isStreamActive(AudioSystem::MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+ // while media is playing (or has recently played), use the same device
+ device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+ } else {
+ // when media is not playing anymore, fall back on the sonification behavior
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+ }
+
+ break;
+
+ case STRATEGY_DTMF:
+ if (!isInCall()) {
+ // when off call, DTMF strategy follows the same rules as MEDIA strategy
+ device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+ break;
+ }
+ // when in call, DTMF and PHONE strategies follow the same rules
+ // FALL THROUGH
+
+ case STRATEGY_PHONE:
+ // for phone strategy, we first consider the forced use and then the available devices by order
+ // of priority
+ switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) {
+ case AudioSystem::FORCE_BT_SCO:
+ if (!isInCall() || strategy != STRATEGY_DTMF) {
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO;
+ if (device) break;
+ // if SCO device is requested but no SCO device is available, fall back to default case
+ // FALL THROUGH
+
+ default: // FORCE_NONE
+ // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
+ if (mHasA2dp && !isInCall() &&
+ (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+ (getA2dpOutput() != 0) && !mA2dpSuspended) {
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
+ if (device) break;
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADSET;
+ if (device) break;
+#endif
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE;
+ if (device) break;
+ device = mDefaultOutputDevice;
+ if (device == 0) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
+ }
+ break;
+
+ case AudioSystem::FORCE_SPEAKER:
+ // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
+ // A2DP speaker when forcing to speaker output
+ if (mHasA2dp && !isInCall() &&
+ (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+ (getA2dpOutput() != 0) && !mA2dpSuspended) {
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+ if (device) break;
+ device = mDefaultOutputDevice;
+ if (device == 0) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
+ }
+ break;
+ }
+#ifdef QCOM_FM_ENABLED
+ if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_FM) {
+ device |= AudioSystem::DEVICE_OUT_FM;
+ }
+#endif
+ break;
+
+ case STRATEGY_SONIFICATION:
+
+ // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
+ // handleIncallSonification().
+ if (isInCall()) {
+ device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/);
+ break;
+ }
+ // FALL THROUGH
+
+ case STRATEGY_ENFORCED_AUDIBLE:
+ // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION
+ // except:
+ // - when in call where it doesn't default to STRATEGY_PHONE behavior
+ // - in countries where not enforced in which case it follows STRATEGY_MEDIA
+
+ if (strategy == STRATEGY_SONIFICATION ||
+ !mStreams[AUDIO_STREAM_ENFORCED_AUDIBLE].mCanBeMuted) {
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+ if (device == 0) {
+ ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION");
+ }
+ }
+ // The second device used for sonification is the same as the device used by media strategy
+ // FALL THROUGH
+
+ case STRATEGY_MEDIA: {
+ //To route FM stream to speaker when headset is connected, a new switch case is added.
+ //case AudioSystem::FORCE_SPEAKER for STRATEGY_MEDIA will come only when we need to route
+ //FM stream to speaker.
+ switch (mForceUse[AudioSystem::FOR_MEDIA]) {
+ default:{
+ uint32_t device2 = 0;
+ if ((mHasA2dp && (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+ (getA2dpOutput() != 0) && !mA2dpSuspended )) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ }
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
+ }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADSET;
+ }
+#endif
+#ifdef QCOM_FM_ENABLED
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_FM_TX;
+ }
+#endif
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+ }
+
+ // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
+ // STRATEGY_ENFORCED_AUDIBLE, 0 otherwise
+ device |= device2;
+ if (device) break;
+ device = mDefaultOutputDevice;
+ }
+ break;
+ case AudioSystem::FORCE_SPEAKER:
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+ break;
+ }
+#ifdef QCOM_FM_ENABLED
+ if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_FM) {
+ device |= AudioSystem::DEVICE_OUT_FM;
+ }
+#endif
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADSET) {
+ device |= AudioSystem::DEVICE_OUT_ANC_HEADSET;
+ }
+ if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE) {
+ device |= AudioSystem::DEVICE_OUT_ANC_HEADPHONE;
+ }
+#endif
+ // Do not play media stream if in call and the requested device would change the hardware
+ // output routing
+ if (mPhoneState == AudioSystem::MODE_IN_CALL &&
+ !AudioSystem::isA2dpDevice((AudioSystem::audio_devices)device) &&
+ device != getDeviceForStrategy(STRATEGY_PHONE)) {
+ device = getDeviceForStrategy(STRATEGY_PHONE);
+ ALOGV("getDeviceForStrategy() incompatible media and phone devices");
+ }
+ if (device == 0) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA");
+ }
+ } break;
+
+ default:
+ ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
+ break;
+ }
+
+ ALOGV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
+ return (audio_devices_t)device;
+}
+
+
+status_t AudioPolicyManager::setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address)
+{
+ SortedVector <audio_io_handle_t> outputs;
+
+ ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);
+
+ // connect/disconnect only 1 device at a time
+ if (AudioSystem::popCount(device) != 1) return BAD_VALUE;
+
+ if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
+ ALOGE("setDeviceConnectionState() invalid address: %s", device_address);
+ return BAD_VALUE;
+ }
+
+ // handle output devices
+ if (AudioSystem::isOutputDevice(device)) {
+
+ if (!mHasA2dp && AudioSystem::isA2dpDevice(device)) {
+ ALOGE("setDeviceConnectionState() invalid device: %x", device);
+ return BAD_VALUE;
+ }
+ if (!mHasUsb && audio_is_usb_device((audio_devices_t)device)) {
+ ALOGE("setDeviceConnectionState() invalid device: %x", device);
+ return BAD_VALUE;
+ }
+
+ switch (state)
+ {
+ // handle output device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE:
+
+ if (mAvailableOutputDevices & device) {
+ ALOGW("setDeviceConnectionState() device already connected: %x", device);
+ return INVALID_OPERATION;
+ }
+ ALOGV("setDeviceConnectionState() connecting device %x", device);
+
+ if (checkOutputsForDevice((audio_devices_t)device, state, outputs) != NO_ERROR) {
+ return INVALID_OPERATION;
+ }
+ ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %d outputs",
+ outputs.size());
+ // register new device as available
+ mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | device);
+ ALOGV("setDeviceConnectionState() connecting device %x", mAvailableOutputDevices);
+
+ if (!outputs.isEmpty()) {
+ String8 paramStr;
+ if (mHasA2dp && AudioSystem::isA2dpDevice(device)) {
+ // handle A2DP device connection
+ AudioParameter param;
+ param.add(String8(AUDIO_PARAMETER_A2DP_SINK_ADDRESS), String8(device_address));
+ paramStr = param.toString();
+ mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ mA2dpSuspended = false;
+ } else if (AudioSystem::isBluetoothScoDevice(device)) {
+ // handle SCO device connection
+ mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ } else if (mHasUsb && audio_is_usb_device((audio_devices_t)device)) {
+ // handle USB device connection
+ mUsbCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ paramStr = mUsbCardAndDevice;
+ }
+ if (!paramStr.isEmpty()) {
+ for (size_t i = 0; i < outputs.size(); i++) {
+ mpClientInterface->setParameters(outputs[i], paramStr);
+ }
+ }
+ }
+ break;
+ // handle output device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+ if (!(mAvailableOutputDevices & device)) {
+ ALOGW("setDeviceConnectionState() device not connected: %x", device);
+ return INVALID_OPERATION;
+ }
+
+ ALOGV("setDeviceConnectionState() disconnecting device %x", device);
+ // remove device from available output devices
+ mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device);
+
+ checkOutputsForDevice((audio_devices_t)device, state, outputs);
+ if (mHasA2dp && AudioSystem::isA2dpDevice(device)) {
+ // handle A2DP device disconnection
+ mA2dpDeviceAddress = "";
+ mA2dpSuspended = false;
+ } else if (AudioSystem::isBluetoothScoDevice(device)) {
+ // handle SCO device disconnection
+ mScoDeviceAddress = "";
+ } else if (mHasUsb && audio_is_usb_device((audio_devices_t)device)) {
+ // handle USB device disconnection
+ mUsbCardAndDevice = "";
+ }
+ } break;
+
+ default:
+ ALOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+
+ audio_devices_t NewDevice = AudioPolicyManagerBase::getNewDevice(mPrimaryOutput, false /*fromCache*/);
+#ifdef QCOM_FM_ENABLED
+ if (device == AudioSystem::DEVICE_OUT_FM) {
+ if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
+ mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::FM, 1);
+ }
+ else {
+ mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::FM, -1);
+ }
+ }
+#endif
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ if(device == AudioSystem::DEVICE_OUT_ANC_HEADPHONE ||
+ device == AudioSystem::DEVICE_OUT_ANC_HEADSET) {
+ if(NewDevice == 0){
+ NewDevice = getDeviceForStrategy(STRATEGY_MEDIA, false);
+ }
+ }
+#endif
+
+ checkA2dpSuspend();
+ AudioPolicyManagerBase::checkOutputForAllStrategies();
+ // outputs must be closed after checkOutputForAllStrategies() is executed
+ if (!outputs.isEmpty()) {
+ for (size_t i = 0; i < outputs.size(); i++) {
+ // close unused outputs after device disconnection or direct outputs that have been
+ // opened by checkOutputsForDevice() to query dynamic parameters
+ if ((state == AudioSystem::DEVICE_STATE_UNAVAILABLE) ||
+ (mOutputs.valueFor(outputs[i])->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
+ closeOutput(outputs[i]);
+ }
+ }
+ }
+
+ //updateDeviceForStrategy();
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ setOutputDevice(mOutputs.keyAt(i), getNewDevice(mOutputs.keyAt(i), true /*fromCache*/));
+ }
+
+ if (device == AudioSystem::DEVICE_OUT_WIRED_HEADSET) {
+ device = AudioSystem::DEVICE_IN_WIRED_HEADSET;
+ } else if (device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO ||
+ device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
+ device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
+ device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ } else if (device == AudioSystem::DEVICE_OUT_ANC_HEADSET) {
+ device = AudioSystem::DEVICE_IN_ANC_HEADSET; //wait for actual ANC device
+#endif
+ }else {
+ return NO_ERROR;
+ }
+ }
+ // handle input devices
+ if (AudioSystem::isInputDevice(device)) {
+
+ switch (state)
+ {
+ // handle input device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE: {
+ if (mAvailableInputDevices & device) {
+ ALOGW("setDeviceConnectionState() device already connected: %d", device);
+ return INVALID_OPERATION;
+ }
+ mAvailableInputDevices = (audio_devices_t)(mAvailableInputDevices | device);
+ }
+ break;
+
+ // handle input device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+ if (!(mAvailableInputDevices & device)) {
+ ALOGW("setDeviceConnectionState() device not connected: %d", device);
+ return INVALID_OPERATION;
+ }
+ mAvailableInputDevices = (audio_devices_t) (mAvailableInputDevices & ~device);
+ } break;
+
+ default:
+ ALOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+
+ audio_io_handle_t activeInput = getActiveInput();
+ if (activeInput != 0) {
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+ audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+ if ((newDevice != 0) && (newDevice != inputDesc->mDevice)) {
+ ALOGV("setDeviceConnectionState() changing device from %x to %x for input %d",
+ inputDesc->mDevice, newDevice, activeInput);
+ inputDesc->mDevice = newDevice;
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+ mpClientInterface->setParameters(activeInput, param.toString());
+ }
+ }
+
+ return NO_ERROR;
+ }
+
+ ALOGW("setDeviceConnectionState() invalid device: %x", device);
+ return BAD_VALUE;
+}
+
+status_t AudioPolicyManager::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session)
+{
+ ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ ALOGW("startOutput() unknow output %d", output);
+ return BAD_VALUE;
+ }
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+ // increment usage count for this stream on the requested output:
+ // NOTE that the usage count is the same for duplicated output and hardware output which is
+ // necessary for a correct control of hardware output routing by startOutput() and stopOutput()
+ outputDesc->changeRefCount(stream, 1);
+
+ if (outputDesc->mRefCount[stream] == 1) {
+ audio_devices_t prevDevice = outputDesc->device();
+ audio_devices_t newDevice = AudioPolicyManagerBase::getNewDevice(output, false /*fromCache*/);
+ routing_strategy strategy = AudioPolicyManagerBase::getStrategy(stream);
+ bool shouldWait = (strategy == STRATEGY_SONIFICATION) ||
+ (strategy == STRATEGY_SONIFICATION_RESPECTFUL);
+ uint32_t waitMs = 0;
+ bool force = false;
+ uint32_t muteWaitMs;
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+ if (desc != outputDesc) {
+ // force a device change if any other output is managed by the same hw
+ // module and has a current device selection that differs from selected device.
+ // In this case, the audio HAL must receive the new device selection so that it can
+ // change the device currently selected by the other active output.
+ if (outputDesc->sharesHwModuleWith(desc) &&
+ desc->device() != newDevice) {
+ force = true;
+ }
+ // wait for audio on other active outputs to be presented when starting
+ // a notification so that audio focus effect can propagate.
+ if (shouldWait && (desc->refCount() != 0) && (waitMs < desc->latency())) {
+ waitMs = desc->latency();
+ }
+ }
+ }
+
+ setOutputDevice(output, AudioPolicyManagerBase::getNewDevice((output), true));
+
+ // handle special case for sonification while in call
+ if (isInCall()) {
+ AudioPolicyManagerBase::handleIncallSonification(stream, true, false);
+ }
+
+ // apply volume rules for current stream and device if necessary
+ checkAndSetVolume(stream,
+ mStreams[stream].getVolumeIndex((audio_devices_t)newDevice),
+ output,
+ newDevice);
+
+ // update the outputs if starting an output with a stream that can affect notification
+ // routing
+ handleNotificationRoutingForStream(stream);
+ if (waitMs > muteWaitMs) {
+ usleep((waitMs - muteWaitMs) * 2 * 1000);
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session)
+{
+ ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ ALOGW("stopOutput() unknow output %d", output);
+ return BAD_VALUE;
+ }
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+ // handle special case for sonification while in call
+ if (isInCall()) {
+ handleIncallSonification(stream, false, false);
+ }
+
+ if (outputDesc->mRefCount[stream] > 0) {
+ // decrement usage count of this stream on the output
+ outputDesc->changeRefCount(stream, -1);
+ // store time at which the stream was stopped - see isStreamActive()
+ if (outputDesc->mRefCount[stream] == 0) {
+ if (stream == AudioSystem::MUSIC) {
+ outputDesc->mStopTime[stream] = systemTime();
+ }
+ audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+ // delay the device switch by twice the latency because stopOutput() is executed when
+ // the track stop() command is received and at that time the audio track buffer can
+ // still contain data that needs to be drained. The latency only covers the audio HAL
+ // and kernel buffers. Also the latency does not always include additional delay in the
+ // audio path (audio DSP, CODEC ...)
+ setOutputDevice(output, newDevice, false, outputDesc->mLatency*2);
+
+ // force restoring the device selection on other active outputs if it differs from the
+ // one being selected for this output
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ audio_io_handle_t curOutput = mOutputs.keyAt(i);
+ AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+ if (curOutput != output &&
+ desc->refCount() != 0 &&
+ outputDesc->sharesHwModuleWith(desc) &&
+ newDevice != desc->device()) {
+ setOutputDevice(curOutput,
+ getNewDevice(curOutput, false /*fromCache*/),
+ true,
+ outputDesc->mLatency*2);
+ }
+ }
+ // update the outputs if stopping one with a stream that can affect notification routing
+ handleNotificationRoutingForStream(stream);
+ }
+ return NO_ERROR;
+ } else {
+ ALOGW("stopOutput() refcount is already 0 for output %d", output);
+ return INVALID_OPERATION;
+ }
+}
+
+status_t AudioPolicyManager::stopInput(audio_io_handle_t input)
+{
+ ALOGV("stopInput() input %d", input);
+ uint32_t newDevice = NULL;
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ ALOGW("stopInput() unknow input %d", input);
+ return BAD_VALUE;
+ }
+ AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+ if (inputDesc->mRefCount == 0) {
+ ALOGW("stopInput() input %d already stopped", input);
+ return INVALID_OPERATION;
+ } else {
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyRouting), 0);
+ ALOGV("stopInput string to setParam %s\n", param.toString().string());
+ mpClientInterface->setParameters(input, param.toString());
+ inputDesc->mRefCount = 0;
+
+ newDevice = AudioPolicyManagerBase::getNewDevice(mPrimaryOutput, false);
+ param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+ mpClientInterface->setParameters(mPrimaryOutput, param.toString());
+ return NO_ERROR;
+ }
+ return NO_ERROR;
+}
+
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManager
+// ----------------------------------------------------------------------------
+
+// --- class factory
+
+
+extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+{
+ return new AudioPolicyManager(clientInterface);
+}
+
+extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
+{
+ delete interface;
+}
+
+// ---
+
+uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output, audio_devices_t device, bool force, int delayMs)
+{
+ ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs);
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+ AudioParameter param;
+ uint32_t muteWaitMs = 0;
+
+ if (outputDesc->isDuplicated()) {
+ muteWaitMs = setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
+ muteWaitMs += setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
+ return muteWaitMs;
+ }
+ // filter devices according to output selected
+ device = (audio_devices_t)(device & outputDesc->mProfile->mSupportedDevices);
+
+ audio_devices_t prevDevice = outputDesc->mDevice;
+
+ ALOGV("setOutputDevice() prevDevice %04x", prevDevice);
+
+ if (device != 0) {
+ outputDesc->mDevice = device;
+ }
+ muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+
+ // Do not change the routing if:
+ // - the requested device is 0
+ // - the requested device is the same as current device and force is not specified.
+ // Doing this check here allows the caller to call setOutputDevice() without conditions
+ if ((device == 0 || device == prevDevice) && !force) {
+ ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output);
+ return muteWaitMs;
+ }
+
+ ALOGV("setOutputDevice() changing device");
+ // do the routing
+ param.addInt(String8(AudioParameter::keyRouting), (int)device);
+ mpClientInterface->setParameters(output, param.toString(), delayMs);
+
+ // update stream volumes according to new device
+ applyStreamVolumes(output, device, delayMs);
+
+ return muteWaitMs;
+}
+
+status_t AudioPolicyManager::checkAndSetVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device, int delayMs, bool force)
+{
+ // do not change actual stream volume if the stream is muted
+ if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) {
+ ALOGVV("checkAndSetVolume() stream %d muted count %d",
+ stream, mOutputs.valueFor(output)->mMuteCount[stream]);
+ return NO_ERROR;
+ }
+
+ // do not change in call volume if bluetooth is connected and vice versa
+ if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+ (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
+ ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
+ stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
+ return INVALID_OPERATION;
+ }
+
+ float volume = computeVolume(stream, index, output, device);
+ // We actually change the volume if:
+ // - the float value returned by computeVolume() changed
+ // - the force flag is set
+ if (volume != mOutputs.valueFor(output)->mCurVolume[stream]
+#ifdef QCOM_FM_ENABLED
+ || (stream == AudioSystem::FM)
+#endif
+ || force) {
+ mOutputs.valueFor(output)->mCurVolume[stream] = volume;
+ ALOGVV("checkAndSetVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
+ if (stream == AudioSystem::VOICE_CALL ||
+ stream == AudioSystem::DTMF ||
+ stream == AudioSystem::BLUETOOTH_SCO) {
+ float voiceVolume = -1.0;
+ // offset value to reflect actual hardware volume that never reaches 0
+ // 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java)
+ volume = 0.01 + 0.99 * volume;
+ if (stream == AudioSystem::VOICE_CALL) {
+ voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+ } else if (stream == AudioSystem::BLUETOOTH_SCO) {
+ voiceVolume = 1.0;
+ }
+ if (voiceVolume >= 0 && output == mPrimaryOutput) {
+ mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+ }
+#ifdef QCOM_FM_ENABLED
+ } else if (stream == AudioSystem::FM) {
+ float fmVolume = -1.0;
+ fmVolume = computeVolume(stream, index, output, device);
+ if (fmVolume >= 0) {
+ if(output == mPrimaryOutput)
+ mpClientInterface->setFmVolume(fmVolume, delayMs);
+ else if(mHasA2dp && output == getA2dpOutput())
+ mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
+ }
+ return NO_ERROR;
+#endif
+ }
+ mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
+ }
+ return NO_ERROR;
+}
+
+void AudioPolicyManager::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+{
+ ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);
+
+ bool forceVolumeReeval = false;
+ switch(usage) {
+ case AudioSystem::FOR_COMMUNICATION:
+ if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO &&
+ config != AudioSystem::FORCE_NONE) {
+ ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
+ return;
+ }
+ forceVolumeReeval = true;
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_MEDIA:
+ if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP &&
+ config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_ANALOG_DOCK &&
+ config != AudioSystem::FORCE_DIGITAL_DOCK && config != AudioSystem::FORCE_NONE &&
+ config != AudioSystem::FORCE_NO_BT_A2DP &&
+ config != AudioSystem::FORCE_SPEAKER) {
+ ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
+ return;
+ }
+ mForceUse[usage] = config;
+ {
+ audio_devices_t device = getDeviceForStrategy(STRATEGY_MEDIA);
+ setOutputDevice(mPrimaryOutput, device);
+ }
+ break;
+ case AudioSystem::FOR_RECORD:
+ if (config != AudioSystem::FORCE_BT_SCO && config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_NONE) {
+ ALOGW("setForceUse() invalid config %d for FOR_RECORD", config);
+ return;
+ }
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_DOCK:
+ if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK &&
+ config != AudioSystem::FORCE_BT_DESK_DOCK &&
+ config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_ANALOG_DOCK &&
+ config != AudioSystem::FORCE_DIGITAL_DOCK) {
+ ALOGW("setForceUse() invalid config %d for FOR_DOCK", config);
+ }
+ forceVolumeReeval = true;
+ mForceUse[usage] = config;
+ break;
+ default:
+ ALOGW("setForceUse() invalid usage %d", usage);
+ break;
+ }
+
+ // check for device and output changes triggered by new force usage
+ checkA2dpSuspend();
+ checkOutputForAllStrategies();
+ //updateDeviceForStrategy();
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ audio_io_handle_t output = mOutputs.keyAt(i);
+ audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/);
+ setOutputDevice(output, newDevice, (newDevice != 0));
+ if (forceVolumeReeval && (newDevice != 0)) {
+ applyStreamVolumes(output, newDevice, 0, true);
+ }
+ }
+
+ audio_io_handle_t activeInput = getActiveInput();
+ if (activeInput != 0) {
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+ audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+ if ((newDevice != 0) && (newDevice != inputDesc->mDevice)) {
+ ALOGV("setForceUse() changing device from %x to %x for input %d",
+ inputDesc->mDevice, newDevice, activeInput);
+ inputDesc->mDevice = newDevice;
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+ mpClientInterface->setParameters(activeInput, param.toString());
+ }
+ }
+}
+
+audio_devices_t AudioPolicyManager::getDeviceForInputSource(int inputSource)
+{
+ uint32_t device = 0;
+
+ switch(inputSource) {
+ case AUDIO_SOURCE_DEFAULT:
+ case AUDIO_SOURCE_MIC:
+ case AUDIO_SOURCE_VOICE_RECOGNITION:
+ if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO &&
+ mAvailableInputDevices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_WIRED_HEADSET) {
+ device = AudioSystem::DEVICE_IN_WIRED_HEADSET;
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_ANC_HEADSET) {
+ device = AudioSystem::DEVICE_IN_ANC_HEADSET;
+#endif
+ } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_BUILTIN_MIC) {
+ device = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+ case AUDIO_SOURCE_VOICE_COMMUNICATION:
+ device = AudioSystem::DEVICE_IN_COMMUNICATION;
+ break;
+ case AUDIO_SOURCE_CAMCORDER:
+ if (mAvailableInputDevices & AudioSystem::DEVICE_IN_BACK_MIC) {
+ device = AudioSystem::DEVICE_IN_BACK_MIC;
+ } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_BUILTIN_MIC) {
+ device = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+ case AUDIO_SOURCE_VOICE_UPLINK:
+ case AUDIO_SOURCE_VOICE_DOWNLINK:
+ case AUDIO_SOURCE_VOICE_CALL:
+ if (mAvailableInputDevices & AudioSystem::DEVICE_IN_VOICE_CALL) {
+ device = AudioSystem::DEVICE_IN_VOICE_CALL;
+ }
+ break;
+#ifdef QCOM_FM_ENABLED
+ case AUDIO_SOURCE_FM_RX:
+ device = AudioSystem::DEVICE_IN_FM_RX;
+ break;
+ case AUDIO_SOURCE_FM_RX_A2DP:
+ device = AudioSystem::DEVICE_IN_FM_RX_A2DP;
+ break;
+#endif
+ default:
+ ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
+ break;
+ }
+ ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
+ return (audio_devices_t)device;
+}
+
+/*
+Overwriting this function from base class to allow 2 acitve AudioRecord clients in case of FM.
+One for FM A2DP playbck and other for FM recording.
+*/
+status_t AudioPolicyManager::startInput(audio_io_handle_t input)
+{
+ ALOGV("startInput() input %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ ALOGW("startInput() unknow input %d", input);
+ return BAD_VALUE;
+ }
+ AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice);
+ // use Voice Recognition mode or not for this input based on input source
+ int vr_enabled = inputDesc->mInputSource == AUDIO_SOURCE_VOICE_RECOGNITION ? 1 : 0;
+ param.addInt(String8("vr_mode"), vr_enabled);
+ ALOGV("AudioPolicyManager::startInput(%d), setting vr_mode to %d", inputDesc->mInputSource, vr_enabled);
+ mpClientInterface->setParameters(input, param.toString());
+ inputDesc->mRefCount = 1;
+ return NO_ERROR;
+}
+
+//private function, no changes from AudioPolicyManagerBase
+void AudioPolicyManager::handleNotificationRoutingForStream(AudioSystem::stream_type stream) {
+ switch(stream) {
+ case AudioSystem::MUSIC:
+ checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
+ updateDevicesAndOutputs();
+ break;
+ default:
+ break;
+ }
+}
+}; // namespace android_audio_legacy
diff --git a/msm8660/AudioPolicyManager.h b/msm8660/AudioPolicyManager.h
new file mode 100755
index 0000000..5468a91
--- /dev/null
+++ b/msm8660/AudioPolicyManager.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2010-2012, Code Aurora Forum. All rights reserved.
+ *
+ * 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.
+ */
+
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Timers.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <hardware_legacy/AudioPolicyManagerBase.h>
+
+namespace android_audio_legacy {
+
+class AudioPolicyManager: public AudioPolicyManagerBase
+{
+
+public:
+ AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+ : AudioPolicyManagerBase(clientInterface) {
+ }
+
+ virtual ~AudioPolicyManager() {}
+
+ // AudioPolicyInterface
+ virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address);
+
+ // return appropriate device for streams handled by the specified strategy according to current
+ // phone state, connected devices...
+ // if fromCache is true, the device is returned from mDeviceForStrategy[], otherwise it is determined
+ // by current state (device connected, phone state, force use, a2dp output...)
+ // This allows to:
+ // 1 speed up process when the state is stable (when starting or stopping an output)
+ // 2 access to either current device selection (fromCache == true) or
+ // "future" device selection (fromCache == false) when called from a context
+ // where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
+ // before updateDeviceForStrategy() is called.
+ virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy, bool fromCache = true);
+ virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session = 0);
+ virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session = 0);
+ virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
+ // indicates to the audio policy manager that the input starts being used.
+ virtual status_t startInput(audio_io_handle_t input);
+
+protected:
+ // change the route of the specified output
+ uint32_t setOutputDevice(audio_io_handle_t output, audio_devices_t device, bool force = false, int delayMs = 0);
+ // check that volume change is permitted, compute and send new volume to audio hardware
+ status_t checkAndSetVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false);
+ // select input device corresponding to requested audio source
+ virtual audio_devices_t getDeviceForInputSource(int inputSource);
+ // Mute or unmute the stream on the specified output
+ status_t stopInput(audio_io_handle_t input);
+
+private:
+ void handleNotificationRoutingForStream(AudioSystem::stream_type stream);
+};
+};
diff --git a/msm8660/acdb.h b/msm8660/acdb.h
new file mode 100644
index 0000000..43b93e8
--- /dev/null
+++ b/msm8660/acdb.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod 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 __MSM_ACDB_CONTROL
+#define __MSM_ACDB_CONTROL
+
+__BEGIN_DECLS
+
+int acdb_loader_send_anc_cal(int id);
+void acdb_loader_send_audio_cal(int id, int capability);
+void acdb_loader_send_voice_cal(int tx_id, int rx_id);
+void acdb_mapper_get_acdb_id_from_dev_name(char *name, int *id);
+int acdb_loader_init_ACDB();
+void acdb_loader_deallocate_ACDB();
+
+__END_DECLS
+
+#endif
diff --git a/msm8660/audio_hw_hal.cpp b/msm8660/audio_hw_hal.cpp
new file mode 100644
index 0000000..4975737
--- /dev/null
+++ b/msm8660/audio_hw_hal.cpp
@@ -0,0 +1,717 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * 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.primary.msm8660"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <hardware/audio.h>
+
+#include <hardware_legacy/AudioHardwareInterface.h>
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+namespace android_audio_legacy {
+
+extern "C" {
+
+struct qcom_audio_module {
+ struct audio_module module;
+};
+
+struct qcom_audio_device {
+ struct audio_hw_device device;
+
+ struct AudioHardwareInterface *hwif;
+};
+
+struct qcom_stream_out {
+ struct audio_stream_out stream;
+
+ AudioStreamOut *qcom_out;
+};
+
+struct qcom_stream_in {
+ struct audio_stream_in stream;
+
+ AudioStreamIn *qcom_in;
+};
+
+/** audio_stream_out implementation **/
+static uint32_t out_get_sample_rate(const struct audio_stream *stream)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ return out->qcom_out->sampleRate();
+}
+
+static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+ struct qcom_stream_out *out =
+ reinterpret_cast<struct qcom_stream_out *>(stream);
+
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement this */
+ return 0;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream *stream)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ return out->qcom_out->bufferSize();
+}
+
+static audio_channel_mask_t out_get_channels(const struct audio_stream *stream)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ return out->qcom_out->channels();
+}
+
+static audio_format_t out_get_format(const struct audio_stream *stream)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ return (audio_format_t)out->qcom_out->format();
+}
+
+static int out_set_format(struct audio_stream *stream, audio_format_t format)
+{
+ struct qcom_stream_out *out =
+ reinterpret_cast<struct qcom_stream_out *>(stream);
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement me */
+ return 0;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+ struct qcom_stream_out *out =
+ reinterpret_cast<struct qcom_stream_out *>(stream);
+ return out->qcom_out->standby();
+}
+
+static int out_dump(const struct audio_stream *stream, int fd)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ Vector<String16> args;
+ return out->qcom_out->dump(fd, args);
+}
+
+static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+ struct qcom_stream_out *out =
+ reinterpret_cast<struct qcom_stream_out *>(stream);
+ return out->qcom_out->setParameters(String8(kvpairs));
+}
+
+static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ String8 s8;
+ s8 = out->qcom_out->getParameters(String8(keys));
+ return strdup(s8.string());
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ return out->qcom_out->latency();
+}
+
+static int out_set_volume(struct audio_stream_out *stream, float left,
+ float right)
+{
+ struct qcom_stream_out *out =
+ reinterpret_cast<struct qcom_stream_out *>(stream);
+ return out->qcom_out->setVolume(left, right);
+}
+
+static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
+ size_t bytes)
+{
+ struct qcom_stream_out *out =
+ reinterpret_cast<struct qcom_stream_out *>(stream);
+ usleep(5);
+ return out->qcom_out->write(buffer, bytes);
+}
+
+static int out_get_render_position(const struct audio_stream_out *stream,
+ uint32_t *dsp_frames)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ return out->qcom_out->getRenderPosition(dsp_frames);
+}
+
+static int out_set_observer(const struct audio_stream_out *stream,
+ void *observer)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ return out->qcom_out->setObserver(observer);
+}
+
+static int out_get_buffer_info(const struct audio_stream_out *stream,
+ buf_info ** buf)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ return out->qcom_out->getBufferInfo(buf);
+}
+
+static int out_is_buffer_available(const struct audio_stream_out *stream,
+ int *isAvail)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ return out->qcom_out->isBufferAvailable(isAvail);
+}
+
+static status_t out_start(struct audio_stream_out *stream)
+{
+ struct qcom_stream_out *out =
+ reinterpret_cast<struct qcom_stream_out *>(stream);
+ return out->qcom_out->start();
+}
+
+static status_t out_pause(struct audio_stream_out *stream)
+{
+ struct qcom_stream_out *out =
+ reinterpret_cast<struct qcom_stream_out *>(stream);
+ return out->qcom_out->pause();
+}
+
+static status_t out_flush(struct audio_stream_out *stream)
+{
+ struct qcom_stream_out *out =
+ reinterpret_cast<struct qcom_stream_out *>(stream);
+ return out->qcom_out->flush();
+}
+
+static status_t out_stop(struct audio_stream_out *stream)
+{
+ struct qcom_stream_out *out =
+ reinterpret_cast<struct qcom_stream_out *>(stream);
+ return out->qcom_out->stop();
+}
+
+static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ return 0;
+}
+
+static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ return 0;
+}
+
+static int out_get_next_write_timestamp(const struct audio_stream_out *stream,
+ int64_t *timestamp)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ return out->qcom_out->getNextWriteTimestamp(timestamp);
+}
+
+/** audio_stream_in implementation **/
+static uint32_t in_get_sample_rate(const struct audio_stream *stream)
+{
+ const struct qcom_stream_in *in =
+ reinterpret_cast<const struct qcom_stream_in *>(stream);
+ return in->qcom_in->sampleRate();
+}
+
+static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+ struct qcom_stream_in *in =
+ reinterpret_cast<struct qcom_stream_in *>(stream);
+
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement this */
+ return 0;
+}
+
+static size_t in_get_buffer_size(const struct audio_stream *stream)
+{
+ const struct qcom_stream_in *in =
+ reinterpret_cast<const struct qcom_stream_in *>(stream);
+ return in->qcom_in->bufferSize();
+}
+
+static audio_channel_mask_t in_get_channels(const struct audio_stream *stream)
+{
+ const struct qcom_stream_in *in =
+ reinterpret_cast<const struct qcom_stream_in *>(stream);
+ return in->qcom_in->channels();
+}
+
+static audio_format_t in_get_format(const struct audio_stream *stream)
+{
+ const struct qcom_stream_in *in =
+ reinterpret_cast<const struct qcom_stream_in *>(stream);
+ return (audio_format_t)in->qcom_in->format();
+}
+
+static int in_set_format(struct audio_stream *stream, audio_format_t format)
+{
+ struct qcom_stream_in *in =
+ reinterpret_cast<struct qcom_stream_in *>(stream);
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement me */
+ return 0;
+}
+
+static int in_standby(struct audio_stream *stream)
+{
+ struct qcom_stream_in *in = reinterpret_cast<struct qcom_stream_in *>(stream);
+ return in->qcom_in->standby();
+}
+
+static int in_dump(const struct audio_stream *stream, int fd)
+{
+ const struct qcom_stream_in *in =
+ reinterpret_cast<const struct qcom_stream_in *>(stream);
+ Vector<String16> args;
+ return in->qcom_in->dump(fd, args);
+}
+
+static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+ struct qcom_stream_in *in =
+ reinterpret_cast<struct qcom_stream_in *>(stream);
+ return in->qcom_in->setParameters(String8(kvpairs));
+}
+
+static char * in_get_parameters(const struct audio_stream *stream,
+ const char *keys)
+{
+ const struct qcom_stream_in *in =
+ reinterpret_cast<const struct qcom_stream_in *>(stream);
+ String8 s8;
+ s8 = in->qcom_in->getParameters(String8(keys));
+ return strdup(s8.string());
+}
+
+static int in_set_gain(struct audio_stream_in *stream, float gain)
+{
+ struct qcom_stream_in *in =
+ reinterpret_cast<struct qcom_stream_in *>(stream);
+ return in->qcom_in->setGain(gain);
+}
+
+static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
+ size_t bytes)
+{
+ struct qcom_stream_in *in =
+ reinterpret_cast<struct qcom_stream_in *>(stream);
+ return in->qcom_in->read(buffer, bytes);
+}
+
+static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
+{
+ struct qcom_stream_in *in =
+ reinterpret_cast<struct qcom_stream_in *>(stream);
+ return in->qcom_in->getInputFramesLost();
+}
+
+static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ const struct qcom_stream_in *in =
+ reinterpret_cast<const struct qcom_stream_in *>(stream);
+ return in->qcom_in->addAudioEffect(effect);
+}
+
+static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ const struct qcom_stream_in *in =
+ reinterpret_cast<const struct qcom_stream_in *>(stream);
+ return in->qcom_in->removeAudioEffect(effect);
+}
+
+/** audio_hw_device implementation **/
+static inline struct qcom_audio_device * to_ladev(struct audio_hw_device *dev)
+{
+ return reinterpret_cast<struct qcom_audio_device *>(dev);
+}
+
+static inline const struct qcom_audio_device * to_cladev(const struct audio_hw_device *dev)
+{
+ return reinterpret_cast<const struct qcom_audio_device *>(dev);
+}
+
+static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev)
+{
+ /* XXX: The old AudioHardwareInterface interface is not smart enough to
+ * tell us this, so we'll lie and basically tell AF that we support the
+ * below input/output devices and cross our fingers. To do things properly,
+ * audio hardware interfaces that need advanced features (like this) should
+ * convert to the new HAL interface and not use this wrapper. */
+ return (/* OUT */
+ AUDIO_DEVICE_OUT_EARPIECE |
+ AUDIO_DEVICE_OUT_SPEAKER |
+ AUDIO_DEVICE_OUT_WIRED_HEADSET |
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+ AUDIO_DEVICE_OUT_AUX_DIGITAL |
+ AUDIO_DEVICE_OUT_ALL_SCO |
+ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ AUDIO_DEVICE_OUT_ANC_HEADSET |
+ AUDIO_DEVICE_OUT_ANC_HEADPHONE |
+#endif
+#ifdef QCOM_FM_ENABLED
+ AUDIO_DEVICE_OUT_FM |
+#endif
+#ifdef QCOM_FM_TX_ENABLED
+ AUDIO_DEVICE_OUT_FM_TX |
+#endif
+ AUDIO_DEVICE_OUT_DEFAULT |
+ /* IN */
+ AUDIO_DEVICE_IN_VOICE_CALL |
+ AUDIO_DEVICE_IN_COMMUNICATION |
+ AUDIO_DEVICE_IN_AMBIENT |
+ AUDIO_DEVICE_IN_BUILTIN_MIC |
+ AUDIO_DEVICE_IN_WIRED_HEADSET |
+ AUDIO_DEVICE_IN_AUX_DIGITAL |
+ AUDIO_DEVICE_IN_BACK_MIC |
+ AUDIO_DEVICE_IN_ALL_SCO |
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ AUDIO_DEVICE_IN_ANC_HEADSET |
+#endif
+#ifdef QCOM_FM_ENABLED
+ AUDIO_DEVICE_IN_FM_RX |
+ AUDIO_DEVICE_IN_FM_RX_A2DP |
+#endif
+ AUDIO_DEVICE_IN_DEFAULT);
+}
+
+static int adev_init_check(const struct audio_hw_device *dev)
+{
+ const struct qcom_audio_device *qadev = to_cladev(dev);
+
+ return qadev->hwif->initCheck();
+}
+
+static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
+{
+ struct qcom_audio_device *qadev = to_ladev(dev);
+ return qadev->hwif->setVoiceVolume(volume);
+}
+
+static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
+{
+ struct qcom_audio_device *qadev = to_ladev(dev);
+ return qadev->hwif->setMasterVolume(volume);
+}
+
+static int adev_get_master_volume(struct audio_hw_device *dev, float *volume) {
+
+ struct qcom_audio_device *qadev = to_ladev(dev);
+ return qadev->hwif->getMasterVolume(volume);
+}
+
+#ifdef QCOM_FM_ENABLED
+static int adev_set_fm_volume(struct audio_hw_device *dev, float volume)
+{
+ struct qcom_audio_device *qadev = to_ladev(dev);
+ return qadev->hwif->setFmVolume(volume);
+}
+#endif
+
+static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
+{
+ struct qcom_audio_device *qadev = to_ladev(dev);
+ return qadev->hwif->setMode(mode);
+}
+
+static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
+{
+ struct qcom_audio_device *qadev = to_ladev(dev);
+ return qadev->hwif->setMicMute(state);
+}
+
+static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
+{
+ const struct qcom_audio_device *qadev = to_cladev(dev);
+ return qadev->hwif->getMicMute(state);
+}
+
+static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
+{
+ struct qcom_audio_device *qadev = to_ladev(dev);
+ return qadev->hwif->setParameters(String8(kvpairs));
+}
+
+static char * adev_get_parameters(const struct audio_hw_device *dev,
+ const char *keys)
+{
+ const struct qcom_audio_device *qadev = to_cladev(dev);
+ String8 s8;
+
+ s8 = qadev->hwif->getParameters(String8(keys));
+ return strdup(s8.string());
+}
+
+static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
+ const struct audio_config *config)
+{
+ const struct qcom_audio_device *qadev = to_cladev(dev);
+ return qadev->hwif->getInputBufferSize(config->sample_rate, config->format, popcount(config->channel_mask));
+}
+
+
+static int adev_open_output_stream(struct audio_hw_device *dev,
+ audio_io_handle_t handle,
+ audio_devices_t devices,
+ audio_output_flags_t flags,
+ struct audio_config *config,
+ struct audio_stream_out **stream_out)
+{
+ struct qcom_audio_device *qadev = to_ladev(dev);
+ status_t status;
+ struct qcom_stream_out *out;
+ int ret;
+
+ out = (struct qcom_stream_out *)calloc(1, sizeof(*out));
+ if (!out)
+ return -ENOMEM;
+
+ status = static_cast<audio_output_flags_t> (flags);
+
+ out->qcom_out = qadev->hwif->openOutputStream(devices,
+ (int *)&config->format,
+ &config->channel_mask,
+ &config->sample_rate,
+ &status);
+ if (!out->qcom_out) {
+ ret = status;
+ goto err_open;
+ }
+
+ out->stream.common.get_sample_rate = out_get_sample_rate;
+ out->stream.common.set_sample_rate = out_set_sample_rate;
+ out->stream.common.get_buffer_size = out_get_buffer_size;
+ out->stream.common.get_channels = out_get_channels;
+ out->stream.common.get_format = out_get_format;
+ out->stream.common.set_format = out_set_format;
+ out->stream.common.standby = out_standby;
+ out->stream.common.dump = out_dump;
+ out->stream.common.set_parameters = out_set_parameters;
+ out->stream.common.get_parameters = out_get_parameters;
+ out->stream.common.add_audio_effect = out_add_audio_effect;
+ out->stream.common.remove_audio_effect = out_remove_audio_effect;
+ out->stream.get_latency = out_get_latency;
+ out->stream.set_volume = out_set_volume;
+ out->stream.write = out_write;
+ out->stream.get_render_position = out_get_render_position;
+ out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
+ out->stream.start = out_start;
+ out->stream.pause = out_pause;
+ out->stream.flush = out_flush;
+ out->stream.stop = out_stop;
+ out->stream.set_observer = out_set_observer;
+ out->stream.get_buffer_info = out_get_buffer_info;
+ out->stream.is_buffer_available = out_is_buffer_available;
+
+ *stream_out = &out->stream;
+ return 0;
+
+err_open:
+ free(out);
+ *stream_out = NULL;
+ return ret;
+}
+
+static void adev_close_output_stream(struct audio_hw_device *dev,
+ struct audio_stream_out* stream)
+{
+ struct qcom_audio_device *qadev = to_ladev(dev);
+ struct qcom_stream_out *out = reinterpret_cast<struct qcom_stream_out *>(stream);
+
+ qadev->hwif->closeOutputStream(out->qcom_out);
+ free(out);
+}
+
+/** This method creates and opens the audio hardware input stream */
+static int adev_open_input_stream(struct audio_hw_device *dev,
+ audio_io_handle_t handle,
+ audio_devices_t devices,
+ audio_config *config,
+ audio_stream_in **stream_in)
+{
+ struct qcom_audio_device *qadev = to_ladev(dev);
+ status_t status;
+ struct qcom_stream_in *in;
+ int ret;
+
+ in = (struct qcom_stream_in *)calloc(1, sizeof(*in));
+ if (!in)
+ return -ENOMEM;
+
+ in->qcom_in = qadev->hwif->openInputStream(devices, (int *)&config->format,
+ &config->channel_mask,
+ &config->sample_rate,
+ &status,
+ (AudioSystem::audio_in_acoustics)0);
+ if (!in->qcom_in) {
+ ret = status;
+ goto err_open;
+ }
+
+ 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;
+ in->stream.common.get_channels = in_get_channels;
+ in->stream.common.get_format = in_get_format;
+ in->stream.common.set_format = in_set_format;
+ in->stream.common.standby = in_standby;
+ in->stream.common.dump = in_dump;
+ in->stream.common.set_parameters = in_set_parameters;
+ in->stream.common.get_parameters = in_get_parameters;
+ in->stream.common.add_audio_effect = in_add_audio_effect;
+ in->stream.common.remove_audio_effect = in_remove_audio_effect;
+ in->stream.set_gain = in_set_gain;
+ in->stream.read = in_read;
+ in->stream.get_input_frames_lost = in_get_input_frames_lost;
+
+ *stream_in = &in->stream;
+ return 0;
+
+err_open:
+ free(in);
+ *stream_in = NULL;
+ return ret;
+}
+
+static void adev_close_input_stream(struct audio_hw_device *dev,
+ struct audio_stream_in *stream)
+{
+ struct qcom_audio_device *qadev = to_ladev(dev);
+ struct qcom_stream_in *in =
+ reinterpret_cast<struct qcom_stream_in *>(stream);
+
+ qadev->hwif->closeInputStream(in->qcom_in);
+ free(in);
+}
+
+static int adev_dump(const struct audio_hw_device *dev, int fd)
+{
+ const struct qcom_audio_device *qadev = to_cladev(dev);
+ Vector<String16> args;
+
+ return qadev->hwif->dumpState(fd, args);
+}
+
+static int qcom_adev_close(hw_device_t* device)
+{
+ struct audio_hw_device *hwdev =
+ reinterpret_cast<struct audio_hw_device *>(device);
+ struct qcom_audio_device *qadev = to_ladev(hwdev);
+
+ if (!qadev)
+ return 0;
+
+ if (qadev->hwif)
+ delete qadev->hwif;
+
+ free(qadev);
+ return 0;
+}
+
+static int qcom_adev_open(const hw_module_t* module, const char* name,
+ hw_device_t** device)
+{
+ struct qcom_audio_device *qadev;
+ int ret;
+
+ if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
+ return -EINVAL;
+
+ qadev = (struct qcom_audio_device *)calloc(1, sizeof(*qadev));
+ if (!qadev)
+ return -ENOMEM;
+
+ qadev->device.common.tag = HARDWARE_DEVICE_TAG;
+ qadev->device.common.version = AUDIO_DEVICE_API_VERSION_1_0;
+ qadev->device.common.module = const_cast<hw_module_t*>(module);
+ qadev->device.common.close = qcom_adev_close;
+
+ qadev->device.get_supported_devices = adev_get_supported_devices;
+ qadev->device.init_check = adev_init_check;
+ qadev->device.set_voice_volume = adev_set_voice_volume;
+ qadev->device.set_master_volume = adev_set_master_volume;
+ qadev->device.get_master_volume = adev_get_master_volume;
+#ifdef QCOM_FM_ENABLED
+ qadev->device.set_fm_volume = adev_set_fm_volume;
+#endif
+ qadev->device.set_mode = adev_set_mode;
+ qadev->device.set_mic_mute = adev_set_mic_mute;
+ qadev->device.get_mic_mute = adev_get_mic_mute;
+ qadev->device.set_parameters = adev_set_parameters;
+ qadev->device.get_parameters = adev_get_parameters;
+ qadev->device.get_input_buffer_size = adev_get_input_buffer_size;
+ qadev->device.open_output_stream = adev_open_output_stream;
+ qadev->device.close_output_stream = adev_close_output_stream;
+ qadev->device.open_input_stream = adev_open_input_stream;
+ qadev->device.close_input_stream = adev_close_input_stream;
+ qadev->device.dump = adev_dump;
+
+ qadev->hwif = createAudioHardware();
+ if (!qadev->hwif) {
+ ret = -EIO;
+ goto err_create_audio_hw;
+ }
+
+ *device = &qadev->device.common;
+
+ return 0;
+
+err_create_audio_hw:
+ free(qadev);
+ return ret;
+}
+
+static struct hw_module_methods_t qcom_audio_module_methods = {
+ open: qcom_adev_open
+};
+
+struct qcom_audio_module HAL_MODULE_INFO_SYM = {
+ module: {
+ common: {
+ tag: HARDWARE_MODULE_TAG,
+ version_major: 1,
+ version_minor: 0,
+ id: AUDIO_HARDWARE_MODULE_ID,
+ name: "QCOM Audio HW HAL",
+ author: "Code Aurora Forum",
+ methods: &qcom_audio_module_methods,
+ dso : NULL,
+ reserved : {0},
+ },
+ },
+};
+
+}; // extern "C"
+
+}; // namespace android_audio_legacy
diff --git a/msm8660/audio_policy.conf b/msm8660/audio_policy.conf
new file mode 100644
index 0000000..cbe793e
--- /dev/null
+++ b/msm8660/audio_policy.conf
@@ -0,0 +1,77 @@
+#
+# Audio policy configuration for generic device builds (goldfish audio HAL - emulator)
+#
+
+# Global configuration section: lists input and output devices always present on the device
+# as well as the output device selected by default.
+# Devices are designated by a string that corresponds to the enum in audio.h
+
+global_configuration {
+ attached_output_devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_EARPIECE
+ default_output_device AUDIO_DEVICE_OUT_SPEAKER
+ attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_VOICE_CALL
+}
+
+# audio hardware module section: contains descriptors for all audio hw modules present on the
+# device. Each hw module node is named after the corresponding hw module library base name.
+# For instance, "primary" corresponds to audio.primary.<device>.so.
+# The "primary" module is mandatory and must include at least one output with
+# AUDIO_OUTPUT_FLAG_PRIMARY flag.
+# Each module descriptor contains one or more output profile descriptors and zero or more
+# input profile descriptors. Each profile lists all the parameters supported by a given output
+# or input stream category.
+# The "channel_masks", "formats", "devices" and "flags" are specified using strings corresponding
+# to enums in audio.h and audio_policy.h. They are concatenated by use of "|" without space or "\n".
+
+audio_hw_modules {
+ primary {
+ outputs {
+ primary {
+ sampling_rates 44100
+ channel_masks AUDIO_CHANNEL_OUT_STEREO
+ formats AUDIO_FORMAT_PCM_16_BIT
+ devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_EARPIECE|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_ANC_HEADSET|AUDIO_DEVICE_OUT_ANC_HEADPHONE|AUDIO_DEVICE_OUT_ALL_SCO|AUDIO_DEVICE_OUT_AUX_DIGITAL|AUDIO_DEVICE_OUT_FM|AUDIO_DEVICE_OUT_FM_TX
+ flags AUDIO_OUTPUT_FLAG_PRIMARY
+ }
+ lpa {
+ sampling_rates 8000|11025|12000|16000|22050|24000|32000|44100|48000
+ channel_masks AUDIO_CHANNEL_OUT_STEREO|AUDIO_CHANNEL_OUT_MONO
+ formats AUDIO_FORMAT_PCM_16_BIT
+ devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_EARPIECE|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_ALL_SCO|AUDIO_DEVICE_OUT_AUX_DIGITAL
+ flags AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_LPA
+ }
+ voipout {
+ sampling_rates 8000|16000
+ channel_masks AUDIO_CHANNEL_OUT_MONO
+ formats AUDIO_FORMAT_PCM_16_BIT|AUDIO_FORMAT_AMR_NB|AUDIO_FORMAT_AMR_WB|AUDIO_FORMAT_QCELP|AUDIO_FORMAT_EVRC|AUDIO_FORMAT_EVRCB|AUDIO_FORMAT_EVRCWB
+ devices AUDIO_DEVICE_OUT_EARPIECE|AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE
+ flags AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_VOIP_RX
+ }
+ }
+ inputs {
+ primary {
+ sampling_rates 8000|11025|12000|16000|22050|24000|32000|44100|48000
+ channel_masks AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO|AUDIO_CHANNEL_IN_VOICE_CALL_MONO|AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO|AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO
+ formats AUDIO_FORMAT_PCM_16_BIT
+ devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_WIRED_HEADSET|AUDIO_DEVICE_IN_ANC_HEADSET|AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET|AUDIO_DEVICE_IN_AUX_DIGITAL|AUDIO_DEVICE_IN_VOICE_CALL
+ }
+ voipin {
+ sampling_rates 8000|16000
+ channel_masks AUDIO_CHANNEL_IN_MONO
+ formats AUDIO_FORMAT_PCM_16_BIT|AUDIO_FORMAT_AMR_NB|AUDIO_FORMAT_AMR_WB|AUDIO_FORMAT_QCELP|AUDIO_FORMAT_EVRC|AUDIO_FORMAT_EVRCB|AUDIO_FORMAT_EVRCWB
+ devices AUDIO_DEVICE_IN_COMMUNICATION
+ }
+ }
+ }
+ a2dp {
+ outputs {
+ primary {
+ sampling_rates 44100
+ channel_masks AUDIO_CHANNEL_OUT_STEREO
+ formats AUDIO_FORMAT_PCM_16_BIT
+ devices AUDIO_DEVICE_OUT_ALL_A2DP
+ flags AUDIO_OUTPUT_FLAG_PRIMARY
+ }
+ }
+ }
+}
diff --git a/msm8660/audio_policy_hal.cpp b/msm8660/audio_policy_hal.cpp
new file mode 100644
index 0000000..307dcc9
--- /dev/null
+++ b/msm8660/audio_policy_hal.cpp
@@ -0,0 +1,492 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * 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_policy.msm8660"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <hardware/audio_policy.h>
+
+#include <hardware_legacy/AudioPolicyInterface.h>
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+#include "AudioPolicyCompatClient.h"
+
+namespace android_audio_legacy {
+//using android_audio_legacy::AudioSystem;
+
+extern "C" {
+
+struct qcom_ap_module {
+ struct audio_policy_module module;
+};
+
+struct qcom_ap_device {
+ struct audio_policy_device device;
+};
+
+struct qcom_audio_policy {
+ struct audio_policy policy;
+
+ void *service;
+ struct audio_policy_service_ops *aps_ops;
+ AudioPolicyCompatClient *service_client;
+ AudioPolicyInterface *apm;
+};
+
+static inline struct qcom_audio_policy * to_qap(struct audio_policy *pol)
+{
+ return reinterpret_cast<struct qcom_audio_policy *>(pol);
+}
+
+static inline const struct qcom_audio_policy * to_cqap(const struct audio_policy *pol)
+{
+ return reinterpret_cast<const struct qcom_audio_policy *>(pol);
+}
+
+
+static int ap_set_device_connection_state(struct audio_policy *pol,
+ audio_devices_t device,
+ audio_policy_dev_state_t state,
+ const char *device_address)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ return qap->apm->setDeviceConnectionState(
+ (AudioSystem::audio_devices)device,
+ (AudioSystem::device_connection_state)state,
+ device_address);
+}
+
+static audio_policy_dev_state_t ap_get_device_connection_state(
+ const struct audio_policy *pol,
+ audio_devices_t device,
+ const char *device_address)
+{
+ const struct qcom_audio_policy *qap = to_cqap(pol);
+ return (audio_policy_dev_state_t)qap->apm->getDeviceConnectionState(
+ (AudioSystem::audio_devices)device,
+ device_address);
+}
+
+static void ap_set_phone_state(struct audio_policy *pol, audio_mode_t state)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ qap->apm->setPhoneState(state);
+}
+
+ /* force using a specific device category for the specified usage */
+static void ap_set_force_use(struct audio_policy *pol,
+ audio_policy_force_use_t usage,
+ audio_policy_forced_cfg_t config)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ qap->apm->setForceUse((AudioSystem::force_use)usage,
+ (AudioSystem::forced_config)config);
+}
+
+ /* retreive current device category forced for a given usage */
+static audio_policy_forced_cfg_t ap_get_force_use(
+ const struct audio_policy *pol,
+ audio_policy_force_use_t usage)
+{
+ const struct qcom_audio_policy *qap = to_cqap(pol);
+ return (audio_policy_forced_cfg_t)qap->apm->getForceUse(
+ (AudioSystem::force_use)usage);
+}
+
+/* if can_mute is true, then audio streams that are marked ENFORCED_AUDIBLE
+ * can still be muted. */
+static void ap_set_can_mute_enforced_audible(struct audio_policy *pol,
+ bool can_mute)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ qap->apm->setSystemProperty("ro.camera.sound.forced", can_mute ? "0" : "1");
+}
+
+static int ap_init_check(const struct audio_policy *pol)
+{
+ const struct qcom_audio_policy *qap = to_cqap(pol);
+ return qap->apm->initCheck();
+}
+
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+static audio_io_handle_t ap_get_session(struct audio_policy *pol,
+ audio_stream_type_t stream,
+ audio_format_t format,
+ audio_policy_output_flags_t flags,
+ int sessionId,
+ uint32_t samplingRate,
+ uint32_t channels)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+
+ ALOGV("%s: tid %d", __func__, gettid());
+ return qap->apm->getSession((AudioSystem::stream_type)stream,
+ format, (AudioSystem::output_flags)flags,
+ sessionId,
+ samplingRate,
+ channels);
+}
+
+static void ap_pause_session(struct audio_policy *pol, audio_io_handle_t output,
+ audio_stream_type_t stream)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ qap->apm->pauseSession(output, (AudioSystem::stream_type)stream);
+}
+
+static void ap_resume_session(struct audio_policy *pol, audio_io_handle_t output,
+ audio_stream_type_t stream)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ qap->apm->resumeSession(output, (AudioSystem::stream_type)stream);
+}
+
+static void ap_release_session(struct audio_policy *pol, audio_io_handle_t output)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ qap->apm->releaseSession(output);
+}
+#endif
+
+static audio_io_handle_t ap_get_output(struct audio_policy *pol,
+ audio_stream_type_t stream,
+ uint32_t sampling_rate,
+ audio_format_t format,
+ uint32_t channels,
+ audio_output_flags_t flags)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+
+ ALOGV("%s: tid %d", __func__, gettid());
+ return qap->apm->getOutput((AudioSystem::stream_type)stream,
+ sampling_rate, format, channels,
+ (AudioSystem::output_flags)flags);
+}
+
+static int ap_start_output(struct audio_policy *pol, audio_io_handle_t output,
+ audio_stream_type_t stream, int session)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ return qap->apm->startOutput(output, (AudioSystem::stream_type)stream,
+ session);
+}
+
+static int ap_stop_output(struct audio_policy *pol, audio_io_handle_t output,
+ audio_stream_type_t stream, int session)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ return qap->apm->stopOutput(output, (AudioSystem::stream_type)stream,
+ session);
+}
+
+static void ap_release_output(struct audio_policy *pol,
+ audio_io_handle_t output)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ qap->apm->releaseOutput(output);
+}
+
+static audio_io_handle_t ap_get_input(struct audio_policy *pol, audio_source_t inputSource,
+ uint32_t sampling_rate,
+ audio_format_t format,
+ uint32_t channels,
+ audio_in_acoustics_t acoustics)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ return qap->apm->getInput(inputSource, sampling_rate, format, channels,
+ (AudioSystem::audio_in_acoustics)acoustics);
+}
+
+static int ap_start_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ return qap->apm->startInput(input);
+}
+
+static int ap_stop_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ return qap->apm->stopInput(input);
+}
+
+static void ap_release_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ qap->apm->releaseInput(input);
+}
+
+static void ap_init_stream_volume(struct audio_policy *pol,
+ audio_stream_type_t stream, int index_min,
+ int index_max)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ qap->apm->initStreamVolume((AudioSystem::stream_type)stream, index_min,
+ index_max);
+}
+
+static int ap_set_stream_volume_index(struct audio_policy *pol,
+ audio_stream_type_t stream,
+ int index)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ return qap->apm->setStreamVolumeIndex((AudioSystem::stream_type)stream,
+ index,
+ AUDIO_DEVICE_OUT_DEFAULT);
+}
+
+static int ap_get_stream_volume_index(const struct audio_policy *pol,
+ audio_stream_type_t stream,
+ int *index)
+{
+ const struct qcom_audio_policy *qap = to_cqap(pol);
+ return qap->apm->getStreamVolumeIndex((AudioSystem::stream_type)stream,
+ index,
+ AUDIO_DEVICE_OUT_DEFAULT);
+}
+
+static uint32_t ap_get_strategy_for_stream(const struct audio_policy *pol,
+ audio_stream_type_t stream)
+{
+ const struct qcom_audio_policy *qap = to_cqap(pol);
+ return qap->apm->getStrategyForStream((AudioSystem::stream_type)stream);
+}
+
+static int ap_set_stream_volume_index_for_device(struct audio_policy *pol,
+ audio_stream_type_t stream,
+ int index,
+ audio_devices_t device)
+{
+ const struct qcom_audio_policy *qap = to_cqap(pol);
+ return qap->apm->setStreamVolumeIndex((AudioSystem::stream_type)stream,
+ index,
+ device);
+}
+
+static int ap_get_stream_volume_index_for_device(const struct audio_policy *pol,
+ audio_stream_type_t stream,
+ int *index,
+ audio_devices_t device)
+{
+ const struct qcom_audio_policy *qap = to_cqap(pol);
+ return qap->apm->getStreamVolumeIndex((AudioSystem::stream_type)stream,
+ index,
+ AUDIO_DEVICE_OUT_DEFAULT);
+}
+
+static audio_devices_t ap_get_devices_for_stream(const struct audio_policy *pol,
+ audio_stream_type_t stream)
+{
+ const struct qcom_audio_policy *qap = to_cqap(pol);
+ return qap->apm->getDevicesForStream((AudioSystem::stream_type)stream);
+}
+
+static audio_io_handle_t ap_get_output_for_effect(struct audio_policy *pol,
+ const struct effect_descriptor_s *desc)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ return qap->apm->getOutputForEffect(desc);
+}
+
+static int ap_register_effect(struct audio_policy *pol,
+ const struct effect_descriptor_s *desc,
+ audio_io_handle_t io,
+ uint32_t strategy,
+ int session,
+ int id)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ return qap->apm->registerEffect(desc, io, strategy, session, id);
+}
+
+static int ap_unregister_effect(struct audio_policy *pol, int id)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ return qap->apm->unregisterEffect(id);
+}
+
+static int ap_set_effect_enabled(struct audio_policy *pol, int id, bool enabled)
+{
+ struct qcom_audio_policy *qap = to_qap(pol);
+ return qap->apm->setEffectEnabled(id, enabled);
+}
+
+static bool ap_is_stream_active(const struct audio_policy *pol,
+ audio_stream_type_t stream,
+ uint32_t in_past_ms)
+{
+ const struct qcom_audio_policy *qap = to_cqap(pol);
+ return qap->apm->isStreamActive(stream, in_past_ms);
+}
+
+static int ap_dump(const struct audio_policy *pol, int fd)
+{
+ const struct qcom_audio_policy *qap = to_cqap(pol);
+ return qap->apm->dump(fd);
+}
+
+static int create_qcom_ap(const struct audio_policy_device *device,
+ struct audio_policy_service_ops *aps_ops,
+ void *service,
+ struct audio_policy **ap)
+{
+ struct qcom_audio_policy *qap;
+ int ret;
+
+ if (!service || !aps_ops)
+ return -EINVAL;
+
+ qap = (struct qcom_audio_policy *)calloc(1, sizeof(*qap));
+ if (!qap)
+ return -ENOMEM;
+
+ qap->policy.set_device_connection_state = ap_set_device_connection_state;
+ qap->policy.get_device_connection_state = ap_get_device_connection_state;
+ qap->policy.set_phone_state = ap_set_phone_state;
+ qap->policy.set_force_use = ap_set_force_use;
+ qap->policy.get_force_use = ap_get_force_use;
+ qap->policy.set_can_mute_enforced_audible =
+ ap_set_can_mute_enforced_audible;
+ qap->policy.init_check = ap_init_check;
+ qap->policy.get_output = ap_get_output;
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+ qap->policy.get_session = ap_get_session;
+ qap->policy.pause_session = ap_pause_session;
+ qap->policy.resume_session = ap_resume_session;
+ qap->policy.release_session = ap_release_session;
+#endif
+ qap->policy.start_output = ap_start_output;
+ qap->policy.stop_output = ap_stop_output;
+ qap->policy.release_output = ap_release_output;
+ qap->policy.get_input = ap_get_input;
+ qap->policy.start_input = ap_start_input;
+ qap->policy.stop_input = ap_stop_input;
+ qap->policy.release_input = ap_release_input;
+ qap->policy.init_stream_volume = ap_init_stream_volume;
+ qap->policy.set_stream_volume_index = ap_set_stream_volume_index;
+ qap->policy.get_stream_volume_index = ap_get_stream_volume_index;
+ qap->policy.set_stream_volume_index_for_device = ap_set_stream_volume_index_for_device;
+ qap->policy.get_stream_volume_index_for_device = ap_get_stream_volume_index_for_device;
+ qap->policy.get_strategy_for_stream = ap_get_strategy_for_stream;
+ qap->policy.get_devices_for_stream = ap_get_devices_for_stream;
+ qap->policy.get_output_for_effect = ap_get_output_for_effect;
+ qap->policy.register_effect = ap_register_effect;
+ qap->policy.unregister_effect = ap_unregister_effect;
+ qap->policy.set_effect_enabled = ap_set_effect_enabled;
+ qap->policy.is_stream_active = ap_is_stream_active;
+ qap->policy.dump = ap_dump;
+
+ qap->service = service;
+ qap->aps_ops = aps_ops;
+ qap->service_client =
+ new AudioPolicyCompatClient(aps_ops, service);
+ if (!qap->service_client) {
+ ret = -ENOMEM;
+ goto err_new_compat_client;
+ }
+
+ qap->apm = createAudioPolicyManager(qap->service_client);
+ if (!qap->apm) {
+ ret = -ENOMEM;
+ goto err_create_apm;
+ }
+
+ *ap = &qap->policy;
+ return 0;
+
+err_create_apm:
+ delete qap->service_client;
+err_new_compat_client:
+ free(qap);
+ *ap = NULL;
+ return ret;
+}
+
+static int destroy_qcom_ap(const struct audio_policy_device *ap_dev,
+ struct audio_policy *ap)
+{
+ struct qcom_audio_policy *qap = to_qap(ap);
+
+ if (!qap)
+ return 0;
+
+ if (qap->apm)
+ destroyAudioPolicyManager(qap->apm);
+ if (qap->service_client)
+ delete qap->service_client;
+ free(qap);
+ return 0;
+}
+
+static int qcom_ap_dev_close(hw_device_t* device)
+{
+ if (device)
+ free(device);
+ return 0;
+}
+
+static int qcom_ap_dev_open(const hw_module_t* module, const char* name,
+ hw_device_t** device)
+{
+ struct qcom_ap_device *dev;
+
+ if (strcmp(name, AUDIO_POLICY_INTERFACE) != 0)
+ return -EINVAL;
+
+ dev = (struct qcom_ap_device *)calloc(1, sizeof(*dev));
+ if (!dev)
+ return -ENOMEM;
+
+ dev->device.common.tag = HARDWARE_DEVICE_TAG;
+ dev->device.common.version = 0;
+ dev->device.common.module = const_cast<hw_module_t*>(module);
+ dev->device.common.close = qcom_ap_dev_close;
+ dev->device.create_audio_policy = create_qcom_ap;
+ dev->device.destroy_audio_policy = destroy_qcom_ap;
+
+ *device = &dev->device.common;
+
+ return 0;
+}
+
+static struct hw_module_methods_t qcom_ap_module_methods = {
+ open: qcom_ap_dev_open
+};
+
+struct qcom_ap_module HAL_MODULE_INFO_SYM = {
+ module: {
+ common: {
+ tag: HARDWARE_MODULE_TAG,
+ version_major: 1,
+ version_minor: 0,
+ id: AUDIO_POLICY_HARDWARE_MODULE_ID,
+ name: "QCOM Audio Policy HAL",
+ author: "Code Aurora Forum",
+ methods: &qcom_ap_module_methods,
+ dso : NULL,
+ reserved : {0},
+ },
+ },
+};
+
+}; // extern "C"
+
+}; // namespace android_audio_legacy
diff --git a/msm8660/control.h b/msm8660/control.h
new file mode 100644
index 0000000..f21b59b
--- /dev/null
+++ b/msm8660/control.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2009 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 __MSM_AUDIO_ALSA_CONTROL
+#define __MSM_AUDIO_ALSA_CONTROL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern const char **msm_get_device_list(void);
+extern int msm_mixer_count(void);
+extern int msm_mixer_open(const char *name, int id);
+extern void msm_mixer_close(void);
+extern int msm_get_device(const char *name);
+extern int msm_en_device(int device, short enable);
+extern int msm_route_stream(int dir, int dec_id, int dev_id, int set);
+extern int msm_route_voice(int tx, int rx, int set);
+extern int msm_set_volume(int dec_id, float vol);
+extern int msm_get_device_class(int dev_id);
+extern int msm_get_device_capability(int dev_id);
+extern int msm_get_device_count(void);
+extern void msm_start_voice(void);
+extern int msm_end_voice(void);
+extern void msm_set_voice_tx_mute(int mute);
+extern int msm_set_voice_rx_vol(int volume);
+extern void msm_set_device_volume(int dev_id, int volume);
+extern void msm_device_mute(int dev_id, int mute);
+extern int msm_reset_all_device(void);
+extern int msm_enable_anc(int dev_id, int enable);
+
+#ifndef LEGACY_QCOM_VOICE
+int msm_get_voc_session(const char *name);
+int msm_start_voice_ext(int id);
+int msm_end_voice_ext(int id);
+int msm_set_voice_tx_mute_ext(int mute, int id);
+int msm_set_voice_rx_vol_ext(int volume, int id);
+#endif
+
+__END_DECLS
+
+#endif