ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/services/audio/libacm/acm/src/ac_thread.c b/marvell/services/audio/libacm/acm/src/ac_thread.c
new file mode 100644
index 0000000..23737bf
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/ac_thread.c
@@ -0,0 +1,864 @@
+/*
+ * All Rights Reserved
+ *
+ * MARVELL CONFIDENTIAL
+ * Copyright 2012 Marvell International Ltd All Rights Reserved.
+ * The source code contained or described herein and all documents related to
+ * the source code ("Material") are owned by Marvell International Ltd or its
+ * suppliers or licensors. Title to the Material remains with Marvell International Ltd
+ * or its suppliers and licensors. The Material contains trade secrets and
+ * proprietary and confidential information of Marvell or its suppliers and
+ * licensors. The Material is protected by worldwide copyright and trade secret
+ * laws and treaty provisions. No part of the Material may be used, copied,
+ * reproduced, modified, published, uploaded, posted, transmitted, distributed,
+ * or disclosed in any way without Marvell's prior express written permission.
+ *
+ * No license under any patent, copyright, trade secret or other intellectual
+ * property right is granted to or conferred upon you by disclosure or delivery
+ * of the Materials, either expressly, by implication, inducement, estoppel or
+ * otherwise. Any license under such intellectual property rights must be
+ * express and approved by Marvell in writing.
+ *
+ */
+
+/*
+ * ac_thread.c: enabled for AUDIO_CALIBRATION only
+ */
+
+#define LOG_TAG "ac_thread"
+//#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include "audioCalibration.h"
+#include "acm_aph.h"
+#include "acm_param.h"
+#include "ac_thread.h"
+#include "vcm.h"
+#include "adsp_ve.h"
+
+#define REG_BUFFER_SIZE 100
+#define PHY_VERSION_LEN 36
+static pthread_t ACM_Calibration_Server;
+
+int NVM_Calibration_IPC(AC_IPC_Package *package);
+void get_msa_gain_by_path_name(const char * out_path_name, const char * path_name, unsigned char volume,
+        signed char *ret_gain, signed char *ret_gain_wb, signed char *ret_sidetone_gain, signed char *ret_sidetone_gain_wb, bool use_extra_vol);
+ACM_ReturnCode AC_ReloadCalibrationData(AC_Digital_Gain *gain);
+void AC_EnablePath(AC_IPC_Package_Body *path_para, AC_Digital_Gain *gain);
+void AC_DisablePath(AC_IPC_Package_Body *path_para);
+void AC_MutePath(AC_IPC_Package_Body *path_para);
+void AC_SetPathVolume(AC_IPC_Package_Body *path_para, AC_Digital_Gain *gain);
+void AC_SwitchPath(AC_IPC_Package_Body *path_para, AC_Digital_Gain *gain);
+
+extern audio_mode_t ACMGetAudioMode(void);
+extern void get_pcm_config(int *p_role, int *p_rate);
+
+static int fd_server = -1;
+static int clientfd_server = -1;
+
+//client which send message to NVM server.
+int NVM_Calibration_IPC(AC_IPC_Package *package)
+{
+    int fd, len, value;
+    struct sockaddr_un   un;
+
+    /* create a UNIX domain stream socket */
+    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
+        LOGE(NVM_Calibration_IPC, "[Audio NVM Calibration][%s][%d][create socket fail]\n", __FUNCTION__, __LINE__);
+        return 1;
+    }
+
+    /* fill socket address structure with server's address */
+    memset(&un, 0, sizeof(un));
+    un.sun_family = AF_UNIX;
+    switch (package->type)
+    {
+        case AUDIO_NVM_GetGainConfigure:
+        case AUDIO_NVM_ReloadCalibrationData:
+        case AUDIO_NVM_GetVEConfigure:
+            strcpy(un.sun_path, NVM_CALIBRATION_SOCKET);
+            len = offsetof(struct sockaddr_un, sun_path) + strlen(NVM_CALIBRATION_SOCKET);
+            break;
+
+        default:
+            LOGE(NVM_Calibration_IPC, "[Audio NVM Calibration Client][%d][IPC type error]\n", __LINE__);
+            close(fd);
+            return 3;
+    }
+    if (connect(fd, (struct sockaddr *)&un, len) < 0) {
+        LOGE(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d][connect fail][error %d(%s)]\n", __LINE__,errno, strerror(errno));
+        close(fd);
+        return 4;
+    }
+
+    LOGI(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d]-[send type:%d]-[d1:%d][d2:%d][d3:%d][d4:%d]\n",
+            __LINE__,
+            package->type, package->body.d1, package->body.d2, package->body.d3, package->body.d4);
+
+    LOGI(NVM_Calibration_IPC,"NVM_Calibration_IPC:: un.sun_path=%s!", un.sun_path);
+
+    if(write(fd, package, sizeof(AC_IPC_Package)) == -1) {
+        LOGE(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d][write fail]\n", __LINE__);
+        close(fd);
+        return 5;
+    }
+
+    /* get data from server when necessary */
+    switch (package->type)
+    {
+        case AUDIO_NVM_GetGainConfigure:
+            if(read(fd, package->ptr, sizeof(ACMCodec_GainT)) == -1) {
+                LOGE(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d][read fail]\n", __LINE__);
+                close(fd);
+                return 11;
+            }
+            break;
+
+        case AUDIO_NVM_ReloadCalibrationData:
+            if(read(fd, &value, sizeof(int)) == -1) {
+                LOGE(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d][read fail]\n", __LINE__);
+                close(fd);
+                return 12;
+            }
+            else {
+                if(value == -1) {
+                    LOGI(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d][AUDIO_NVM_ReloadCalibrationData Fail: no codec compiled]\n", __LINE__);
+                }
+                else if(value == 0) {
+                    LOGI(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d][AUDIO_NVM_ReloadCalibrationData Success: reload existing file]\n", __LINE__);
+                }
+                else if(value == 1) {
+                    LOGI(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d][AUDIO_NVM_ReloadCalibrationData Success: create new file]\n", __LINE__);
+                }
+            }
+            break;
+
+        case AUDIO_NVM_GetVEConfigure:
+            if(read(fd, package->ptr, sizeof(EnhanceParmsT)) == -1) {
+                LOGE(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d][read fail]\n", __LINE__);
+                close(fd);
+                return 13;
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    close(fd);
+
+    return 0;
+}
+
+// get MSA gain from ACM NVM according to device path name
+void get_msa_gain_by_path_name(const char * out_path_name, const char * path_name, unsigned char volume,
+        signed char *ret_gain, signed char *ret_gain_wb, signed char *ret_sidetone_gain, signed char *ret_sidetone_gain_wb, bool use_extra_vol)
+{
+    int extra_volume = (use_extra_vol ? MSA_GAIN_EXTRA_MODE : MSA_GAIN_NORMAL_MODE);
+    ACM_MsaGain msa_gain = {0};
+    unsigned int size = sizeof(ACM_MsaGain);
+
+    msa_gain.volume = volume;
+    msa_gain.gain = 0;
+    msa_gain.wbGain = 0;
+    msa_gain.path_direction = 0;
+
+    // fix to VC mode here. only VC have msa gain
+    msa_gain.out_path_name = out_path_name;
+    msa_gain.path_name = path_name;
+
+    if (ACMSetParameter(ACM_MSA_GAIN_MODE, NULL, extra_volume) != ACM_RC_OK) {
+        LOGE(get_msa_gain_by_path_name, "set output msa gain mode failed, use the default normal mode ");
+    }
+
+    if (ACMGetParameter(ACM_MSA_GAIN, &msa_gain, &size) != ACM_RC_OK) {
+        LOGE(get_msa_gain_by_path_name, "get output msa gain failed, use default gain.");
+    }
+
+    *ret_gain = msa_gain.gain;
+    *ret_gain_wb = msa_gain.wbGain;
+    *ret_sidetone_gain = msa_gain.sidetone_gain;
+    *ret_sidetone_gain_wb = msa_gain.sidetone_wbGain;
+}
+
+//handle the message from NVM server, and recover the status using new config.
+ACM_ReturnCode AC_ReloadCalibrationData(AC_Digital_Gain *gain) {
+
+    int Rx_path_id = 0xFF;
+    int Tx_path_id = 0xFF;
+    int volume_Rx = 0;
+    int mute_Tx = 0;
+    const char* Rx_pathname = NULL;
+    const char* Tx_pathname = NULL;
+
+    signed char input_gain = 0;
+    signed char input_gain_wb = 0;
+    signed char output_gain = 0;
+    signed char output_gain_wb = 0;
+    signed char rx_sidetone_gain = 0;
+    signed char rx_sidetone_gain_wb = 0;
+    signed char tx_sidetone_gain = 0;
+    signed char tx_sidetone_gain_wb = 0;
+    unsigned char vc_output_vol = 0;
+    bool use_extra_vol = 0;
+
+    //Default: notify audioCalibration.c not to configure DSP gain
+    gain->path_direction_Rx = VCM_PATH_NOT_CONNECTED;
+    gain->path_direction_Tx = VCM_PATH_NOT_CONNECTED;
+
+    ACM_ReloadCalibrationData();
+
+    //get active path
+    ACM_GetEnabledPathId(&Rx_path_id, &Tx_path_id, &volume_Rx, &mute_Tx);
+
+    if ((0xFF == Rx_path_id) || (0xFF == Tx_path_id))
+    {
+        LOGE( AC_ReloadCalibrationData, "%s/L%d: no enabled path.",__FUNCTION__, __LINE__);
+        return ACM_RC_OK;
+    }
+
+    LOGI( AC_ReloadCalibrationData, "%s/L%d: Rx_path_id=%d, Tx_path_id=%d, volume_Rx=%d, mute_Tx=%d.",
+            __FUNCTION__, __LINE__, Rx_path_id, Tx_path_id, volume_Rx, mute_Tx);
+
+    //HIFI has no digital gain
+    if (ACM_RC_OK_VOICE_MATCHED != APHAudioPathCheckPathId(Rx_path_id, Tx_path_id))
+    {
+        LOGI( AC_ReloadCalibrationData, "%s/L%d: current mode is AUDIO_MODE_NORMAL.",__FUNCTION__, __LINE__);
+        return ACM_RC_OK;
+    }
+
+    Rx_pathname = ACM_GetPathName(Rx_path_id);
+    Tx_pathname = ACM_GetPathName(Tx_path_id);
+
+    if ((NULL == Rx_pathname) || (NULL == Tx_pathname))
+    {
+        LOGE( AC_ReloadCalibrationData, "%s/L%d: RX or TX pathname is NULL.",__FUNCTION__, __LINE__);
+        return ACM_RC_OK;
+    }
+
+    vc_output_vol = volume_Rx;
+
+    get_msa_gain_by_path_name(Rx_pathname, Tx_pathname, 100, &input_gain, &input_gain_wb, &tx_sidetone_gain, &tx_sidetone_gain_wb, use_extra_vol);
+    get_msa_gain_by_path_name(Rx_pathname, Rx_pathname, vc_output_vol, &output_gain, &output_gain_wb, &rx_sidetone_gain, &rx_sidetone_gain_wb, use_extra_vol);
+
+    LOGI(AC_ReloadCalibrationData, "%s/L%d: input_gain=0x%x, input_gain_wb=0x%x, output_gain=0x%x, output_gain_wb=0x%x.use_extra_vol=%d.\n",
+            __FUNCTION__, __LINE__, input_gain, input_gain_wb, output_gain, output_gain_wb, use_extra_vol);
+
+    gain->path_direction_Rx = VCM_PATH_OUT;
+    gain->digital_gain_Rx = output_gain | (output_gain_wb << 8);
+    gain->volume_Rx = vc_output_vol;
+
+    gain->path_direction_Tx = VCM_PATH_IN;
+    gain->digital_gain_Tx = input_gain |  (input_gain_wb << 8);
+    gain->volume_Tx = vc_output_vol;
+
+    gain->path_direction_SideTone = VCM_PATH_SIDETONE;
+    gain->digital_gain_SideTone = rx_sidetone_gain |  (rx_sidetone_gain_wb << 8);
+    gain->volume_SideTone = vc_output_vol;
+
+    LOGI(AC_ReloadCalibrationData, "%s/L%d: digital_gain_Rx=0x%x, volume_Rx=%d, digital_gain_Tx=0x%x, volume_Tx=%d, digital_gain_SideTone=%d.\n",
+            __FUNCTION__, __LINE__, gain->digital_gain_Rx, gain->volume_Rx, gain->digital_gain_Tx, gain->volume_Tx, gain->digital_gain_SideTone);
+
+
+    return ACM_RC_OK;
+}
+
+ACM_ReturnCode APHReloadNvm(void) {
+    AC_Digital_Gain gain;
+    ACM_ReturnCode ret;
+
+    LOGI(APHReloadNvm, "%s/L%d: ReloadCalibrationData", __FUNCTION__, __LINE__);
+    memset(&gain, 0x00, sizeof(AC_Digital_Gain));
+
+    ret = AC_ReloadCalibrationData(&gain);
+    if (ACM_RC_OK != ret) {
+        LOGI(APHReloadNvm, "%s/L%d: ReloadCalibrationData fail.", __FUNCTION__, __LINE__);
+        return ret;
+    }
+
+#ifdef PXA1826_AUDIO
+    ret = APHSetMSAGain(&gain);
+    if (ACM_RC_OK != ret) {
+        LOGI(APHReloadNvm, "%s/L%d: ReloadCalibrationData fail.", __FUNCTION__, __LINE__);
+        return ret;
+    }
+#endif
+
+    return ACM_RC_OK;
+}
+
+/*
+Function: enable the path which is disabled status.
+path_para.d1: Rx_path_id
+path_para.d2: Tx_path_id
+path_para.d3: volume
+ */
+void AC_EnablePath(AC_IPC_Package_Body *path_para, AC_Digital_Gain *gain)
+{
+    int Rx_path_id = path_para->d1;
+    int Tx_path_id = path_para->d2;
+    unsigned int Volume = path_para->d3;
+
+    signed char input_gain = 0;
+    signed char input_gain_wb = 0;
+    signed char output_gain = 0;
+    signed char output_gain_wb = 0;
+    signed char rx_sidetone_gain = 0;
+    signed char rx_sidetone_gain_wb = 0;
+    signed char tx_sidetone_gain = 0;
+    signed char tx_sidetone_gain_wb = 0;
+    unsigned char vc_output_vol = 0;
+    bool use_extra_vol = 0;
+
+    const char* Rx_pathname = ACM_GetPathName(Rx_path_id);
+    const char* Tx_pathname = ACM_GetPathName(Tx_path_id);
+
+    if ((NULL == Rx_pathname) || (NULL == Tx_pathname))
+    {
+        LOGE( AC_EnablePath, "%s/L%d: RX or TX pathname is NULL.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    vc_output_vol = Volume;
+
+    LOGI( AC_EnablePath, "%s/L%d: Rx_path_id =  %d, Rx_pathname =%s,  Tx_path_id =  %d, Tx_pathname = %s, Volume =%d",
+            __FUNCTION__, __LINE__, Rx_path_id, Rx_pathname, Tx_path_id, Tx_pathname, Volume);
+
+    if ((ACM_RC_OK_HIFI_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname))
+            && (ACM_RC_OK_VOICE_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname)))
+    {
+        LOGE( AC_EnablePath, "%s/L%d: RX is not matched with TX.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    //Disable all enabled path, otherwise there may be several enabled path.
+    APHDisableAllPath();
+
+    ACMAudioPathEnable(Rx_pathname, Volume);
+    ACMAudioPathEnable(Tx_pathname, Volume);
+
+    //get the gain for voice
+    if (ACM_RC_OK_HIFI_MATCHED == APHAudioPathCheck (Rx_pathname, Tx_pathname))
+    {
+        LOGI( AC_EnablePath, "%s/L%d: RX is matched with TX about HIFI. Not need to get digital gain.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    get_msa_gain_by_path_name(Rx_pathname, Tx_pathname, 100, &input_gain, &input_gain_wb, &tx_sidetone_gain, &tx_sidetone_gain_wb, use_extra_vol);
+    get_msa_gain_by_path_name(Rx_pathname, Rx_pathname, vc_output_vol, &output_gain, &output_gain_wb, &rx_sidetone_gain, &rx_sidetone_gain_wb, use_extra_vol);
+
+    LOGI(AC_EnablePath, "%s/L%d: input_gain= 0x%x, input_gain_wb=0x%x, output_gain=0x%x, output_gain_wb=0x%x.use_extra_vol=%d.\n",
+            __FUNCTION__, __LINE__, input_gain, input_gain_wb, output_gain, output_gain_wb, use_extra_vol);
+
+    gain->path_direction_Rx = VCM_PATH_OUT;
+    gain->digital_gain_Rx = output_gain | (output_gain_wb << 8);
+    gain->volume_Rx = vc_output_vol;
+
+    gain->path_direction_Tx = VCM_PATH_IN;
+    gain->digital_gain_Tx = input_gain |  (input_gain_wb << 8);
+    gain->volume_Tx = vc_output_vol;
+
+    gain->path_direction_SideTone = VCM_PATH_SIDETONE;
+    gain->digital_gain_SideTone = rx_sidetone_gain |  (rx_sidetone_gain_wb << 8);
+    gain->volume_SideTone = vc_output_vol;
+
+    LOGI(AC_EnablePath, "%s/L%d: digital_gain_Rx=0x%x, volume_Rx=%d, digital_gain_Tx=0x%x, volume_Tx=%d, digital_gain_SideTone=%d.\n",
+            __FUNCTION__, __LINE__, gain->digital_gain_Rx, gain->volume_Rx, gain->digital_gain_Tx, gain->volume_Tx, gain->digital_gain_SideTone);
+
+}
+
+/*
+Function: Disable the path which is enabled.
+path_para.d1: Rx_path_id
+path_para.d2: Tx_path_id
+ */
+void AC_DisablePath(AC_IPC_Package_Body *path_para) {
+    int Rx_path_id = path_para->d1;
+    int Tx_path_id = path_para->d2;
+
+    const char* Rx_pathname = ACM_GetPathName(Rx_path_id);
+    const char* Tx_pathname = ACM_GetPathName(Tx_path_id);
+
+    if ((NULL == Rx_pathname) || (NULL == Tx_pathname))
+    {
+        LOGE( AC_DisablePath, "%s/L%d: RX or TX pathname is NULL.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    if ((ACM_RC_OK_HIFI_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname))
+            && (ACM_RC_OK_VOICE_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname)))
+    {
+        LOGE( AC_DisablePath, "%s/L%d: RX is not matched with TX.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    ACMAudioPathDisable(Rx_pathname);
+    ACMAudioPathDisable(Tx_pathname);
+
+    LOGI( AC_DisablePath, "%s/L%d: Rx_path_id =  %d, Rx_pathname =%s,  Tx_path_id =  %d, Tx_pathname = %s",
+            __FUNCTION__, __LINE__, Rx_path_id, Rx_pathname, Tx_path_id, Tx_pathname);
+}
+
+/*
+Function: mute the path which is enabled and unmuted.
+path_para.d1: Rx_path_id
+path_para.d2: Tx_path_id
+path_para.d3: mute
+ */
+void AC_MutePath(AC_IPC_Package_Body *path_para) {
+    int Rx_path_id = path_para->d1;
+    int Tx_path_id = path_para->d2;
+    int mute = path_para->d3;
+
+    const char* Rx_pathname = ACM_GetPathName(Rx_path_id);
+    const char* Tx_pathname = ACM_GetPathName(Tx_path_id);
+
+    if ((NULL == Rx_pathname) || (NULL == Tx_pathname))
+    {
+        LOGE( AC_MutePath, "%s/L%d: RX or TX pathname is NULL.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    LOGI( AC_MutePath, "%s/L%d: Rx_path_id =  %d, Rx_pathname =%s,  Tx_path_id =  %d, Tx_pathname = %s, mute =%d",
+            __FUNCTION__, __LINE__, Rx_path_id, Rx_pathname, Tx_path_id, Tx_pathname, mute);
+
+    if ((ACM_RC_OK_HIFI_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname))
+            && (ACM_RC_OK_VOICE_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname)))
+    {
+        LOGE( AC_MutePath, "%s/L%d: RX is not matched with TX.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    ACMAudioPathMute(Rx_pathname, mute);
+    ACMAudioPathMute(Tx_pathname, mute);
+}
+
+/*
+Function:set the volume for enabled path.
+path_para.d1: Rx_path_id
+path_para.d2: Tx_path_id
+path_para.d3: volume
+ */
+void AC_SetPathVolume(AC_IPC_Package_Body *path_para, AC_Digital_Gain *gain) {
+    int Rx_path_id = path_para->d1;
+    int Tx_path_id = path_para->d2;
+    unsigned int Volume = path_para->d3;
+
+    signed char input_gain = 0;
+    signed char input_gain_wb = 0;
+    signed char output_gain = 0;
+    signed char output_gain_wb = 0;
+    signed char rx_sidetone_gain = 0;
+    signed char rx_sidetone_gain_wb = 0;
+    signed char tx_sidetone_gain = 0;
+    signed char tx_sidetone_gain_wb = 0;
+    unsigned char vc_output_vol = Volume;
+    bool use_extra_vol = 0;
+
+    const char* Rx_pathname = ACM_GetPathName(Rx_path_id);
+    const char* Tx_pathname = ACM_GetPathName(Tx_path_id);
+
+    if ((NULL == Rx_pathname) || (NULL == Tx_pathname))
+    {
+        LOGE( AC_SetPathVolume, "%s/L%d: RX or TX pathname is NULL.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    LOGI( AC_SetPathVolume, "%s/L%d: Rx_path_id =  %d, Rx_pathname =%s,  Tx_path_id =  %d, Tx_pathname = %s, Volume =%d",
+            __FUNCTION__, __LINE__, Rx_path_id, Rx_pathname, Tx_path_id, Tx_pathname, Volume);
+
+    if ((ACM_RC_OK_HIFI_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname))
+            && (ACM_RC_OK_VOICE_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname)))
+    {
+        LOGE( AC_SetPathVolume, "%s/L%d: RX is not matched with TX.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    ACMAudioPathVolumeSet(Rx_pathname, Volume);
+    ACMAudioPathVolumeSet(Tx_pathname, Volume);
+
+    //get the gain for voice
+    if (ACM_RC_OK_HIFI_MATCHED == APHAudioPathCheck (Rx_pathname, Tx_pathname))
+    {
+        LOGE( AC_SetPathVolume, "%s/L%d: RX is matched with TX about HIFI. Not need to get gain.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    get_msa_gain_by_path_name(Rx_pathname, Tx_pathname, 100, &input_gain, &input_gain_wb, &tx_sidetone_gain, &tx_sidetone_gain_wb, use_extra_vol);
+    get_msa_gain_by_path_name(Rx_pathname, Rx_pathname, vc_output_vol, &output_gain, &output_gain_wb, &rx_sidetone_gain, &rx_sidetone_gain_wb, use_extra_vol);
+
+    LOGI(AC_SetPathVolume, "%s/L%d: input_gain=0x%x, input_gain_wb=0x%x, output_gain=0x%x, output_gain_wb=0x%x.use_extra_vol=%d.\n",
+            __FUNCTION__, __LINE__, input_gain, input_gain_wb, output_gain, output_gain_wb, use_extra_vol);
+
+    gain->path_direction_Rx = VCM_PATH_OUT;
+    gain->digital_gain_Rx = output_gain | (output_gain_wb << 8);
+    gain->volume_Rx = vc_output_vol;
+
+    gain->path_direction_Tx = VCM_PATH_IN;
+    gain->digital_gain_Tx = input_gain |  (input_gain_wb << 8);
+    gain->volume_Tx = vc_output_vol;
+
+    gain->path_direction_SideTone = VCM_PATH_SIDETONE;
+    gain->digital_gain_SideTone = rx_sidetone_gain |  (rx_sidetone_gain_wb << 8);
+    gain->volume_SideTone = vc_output_vol;
+
+    LOGI(AC_SetPathVolume, "%s/L%d: digital_gain_Rx=0x%x, volume_Rx=%d, digital_gain_Tx=0x%x, volume_Tx=%d, digital_gain_SideTone=%d.\n",
+            __FUNCTION__, __LINE__, gain->digital_gain_Rx, gain->volume_Rx, gain->digital_gain_Tx, gain->volume_Tx, gain->digital_gain_SideTone);
+}
+
+/*
+Function: switch the path from enabled path list to another enabled path list.
+path_para.d1: Rx_path_id
+path_para.d2: Tx_path_id
+path_para.d3: Volume
+ */
+void AC_SwitchPath(AC_IPC_Package_Body *path_para, AC_Digital_Gain *gain) {
+    int Rx_path_id = path_para->d1;
+    int Tx_path_id = path_para->d2;
+    unsigned int Volume = path_para->d3;
+
+    signed char input_gain = 0;
+    signed char input_gain_wb = 0;
+    signed char output_gain = 0;
+    signed char output_gain_wb = 0;
+    signed char rx_sidetone_gain = 0;
+    signed char rx_sidetone_gain_wb = 0;
+    signed char tx_sidetone_gain = 0;
+    signed char tx_sidetone_gain_wb = 0;
+    unsigned char vc_output_vol = Volume;
+    bool use_extra_vol = 0;
+
+    //enable the pointed path
+    const char* Rx_pathname = ACM_GetPathName(Rx_path_id);
+    const char* Tx_pathname = ACM_GetPathName(Tx_path_id);
+
+    if ((NULL == Rx_pathname) || (NULL == Tx_pathname))
+    {
+        LOGE( AC_SwitchPath, "%s/L%d: RX or TX pathname is NULL.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    if ((ACM_RC_OK_HIFI_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname))
+            && (ACM_RC_OK_VOICE_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname)))
+    {
+        LOGE( AC_SwitchPath, "%s/L%d: RX is not matched with TX.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    LOGI( AC_SwitchPath, "%s/L%d: Rx_path_id =  %d, Rx_pathname =%s,  Tx_path_id =  %d, Tx_pathname = %s, Volume =%d",
+            __FUNCTION__, __LINE__, Rx_path_id, Rx_pathname, Tx_path_id, Tx_pathname, Volume);
+
+    ACMAudioPathSwitch(Rx_pathname, Tx_pathname, Volume);
+
+    //get the gain for voice
+    if (ACM_RC_OK_HIFI_MATCHED == APHAudioPathCheck (Rx_pathname, Tx_pathname))
+    {
+        LOGE( AC_SwitchPath, "%s/L%d: RX is matched with TX about HIFI. Not need to get gain.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    get_msa_gain_by_path_name(Rx_pathname, Tx_pathname, 100, &input_gain, &input_gain_wb, &tx_sidetone_gain, &tx_sidetone_gain_wb, use_extra_vol);
+    get_msa_gain_by_path_name(Rx_pathname, Rx_pathname, vc_output_vol, &output_gain, &output_gain_wb, &rx_sidetone_gain, &rx_sidetone_gain_wb, use_extra_vol);
+
+    LOGI(AC_SwitchPath, "%s/L%d: input_gain = %d, input_gain_wb=%d, output_gain = %d, output_gain_wb=%d.use_extra_vol=%d.\n",
+            __FUNCTION__, __LINE__, input_gain, input_gain_wb, output_gain, output_gain_wb, use_extra_vol);
+
+    gain->path_direction_Rx = VCM_PATH_OUT;
+    gain->digital_gain_Rx = output_gain | (output_gain_wb << 8);
+    gain->volume_Rx = vc_output_vol;
+
+    gain->path_direction_Tx = VCM_PATH_IN;
+    gain->digital_gain_Tx = input_gain |  (input_gain_wb << 8);
+    gain->volume_Tx = vc_output_vol;
+
+    gain->path_direction_SideTone = VCM_PATH_SIDETONE;
+    gain->digital_gain_SideTone = rx_sidetone_gain |  (rx_sidetone_gain_wb << 8);
+    gain->volume_SideTone = vc_output_vol;
+
+    LOGI(AC_SwitchPath, "%s/L%d: digital_gain_Rx = %d, volume_Rx=%d, digital_gain_Tx = %d, volume_Tx=%d, digital_gain_SideTone=%d.\n",
+            __FUNCTION__, __LINE__, gain->digital_gain_Rx, gain->volume_Rx, gain->digital_gain_Tx, gain->volume_Tx, gain->digital_gain_SideTone);
+
+}
+
+#ifdef TARGET_mmp_asr1901_KSTR901
+extern void ACM_SendVEtoADSP(void);
+#endif
+
+//server to handle the message from client which is from CATSTUDIO tools ....
+static void ACM_Calibration_Socket_Server_Thread(void *data) {
+    (void)data;
+    unsigned int len;
+    struct sockaddr_un un;
+    AC_IPC_Package rcv_buf;
+
+    prctl(15,"ac_thread");
+    /* create a UNIX domain stream socket */
+    if ((fd_server = socket(AF_UNIX, SOCK_SEQPACKET, 0)) < 0) {
+        LOGE(ACM_Calibration_Socket_Server_Thread, "[Audio Calibration][%s][%d][create socket fail]\n", __FUNCTION__, __LINE__);
+        return;
+    }
+
+    unlink(ACM_CALIBRATION_SOCKET);   /* in case it already exists */
+
+    /* fill in socket address structure */
+    memset(&un, 0, sizeof(un));
+    un.sun_family = AF_UNIX;
+    strcpy(un.sun_path, ACM_CALIBRATION_SOCKET);
+    len = offsetof(struct sockaddr_un, sun_path) + strlen(ACM_CALIBRATION_SOCKET);
+
+    LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: addr=%s.\n", __FUNCTION__, __LINE__, un.sun_path);
+
+    /* bind the name to the descriptor */
+    if (bind(fd_server, (struct sockaddr *)&un, len) < 0) {
+
+        LOGE(ACM_Calibration_Socket_Server_Thread, "[Audio Calibration][%s][%d][bind fail][error %d (%s)]\n" \
+                , __FUNCTION__, __LINE__,errno, strerror(errno));
+        close(fd_server);
+        return;
+    }
+
+    if (chmod(ACM_CALIBRATION_SOCKET, 0666) < 0) {
+        LOGE(ACM_Calibration_Socket_Server_Thread, "[Audio Calibration][%s][%d]FAIL to chmod ACM_CALIBRATION_SOCKET to 0666\n", __FUNCTION__, __LINE__);
+        close(fd_server);
+        return;
+    }
+    if (listen(fd_server, QLEN) < 0) { /* tell kernel we're a server */
+        LOGE(ACM_Calibration_Socket_Server_Thread, "[Audio Calibration][%s][%d][listen fail]\n", __FUNCTION__, __LINE__);
+        close(fd_server);
+        return;
+    }
+
+    while(1) {
+        len = sizeof(un);
+        //close last connection
+        if (clientfd_server >= 0) {
+            close(clientfd_server);
+            clientfd_server = -1;
+            //usleep(10000);
+        }
+
+        if ((clientfd_server = accept(fd_server, (struct sockaddr *)&un, &len)) < 0) {
+            LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Audio Calibration accept fail\n", __FUNCTION__, __LINE__);
+            continue;
+        }
+
+        if(read(clientfd_server, &rcv_buf, sizeof(rcv_buf))==-1) {
+            LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: read fail\n", __FUNCTION__, __LINE__);
+            continue;
+        }
+
+        LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: [receive type:0x%lx]-[d1:0x%lx][d2:0x%lx][d3:0x%lx][d4:0x%lx]\n",
+                __FUNCTION__, __LINE__,
+                rcv_buf.type, rcv_buf.body.d1, rcv_buf.body.d2, rcv_buf.body.d3, rcv_buf.body.d4);
+
+        switch (rcv_buf.type) {
+            case AUDIO_PHY_GetPathList:
+                {
+                    PathsList paths_list;
+                    int i = 0;
+                    const ACMAPH_AudioPathID *path_config_table = NULL;
+
+                    memset(&paths_list, 0x00, sizeof(paths_list));
+                    path_config_table = ACM_GetPathConfigTable();
+
+                    while (i < APH_PATH_ID_CNT)
+                    {
+                        strcpy(paths_list.path[paths_list.num++], (const char *)path_config_table[i].PathName);
+                        i++;
+                    }
+
+                    if(write(clientfd_server, &paths_list, sizeof(paths_list)) == -1)
+                    {
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Get paths list failed", __FUNCTION__, __LINE__);
+                        continue;
+                    }
+
+                    for(i = 0; i < paths_list.num; i++)
+                    {
+                        LOGI(ACM_Calibration_Socket_Server_Thread, "  : %s\n", paths_list.path[i]);
+                    }
+
+                    break;
+                }
+
+            case AUDIO_PHY_GetPathStatus:
+                {
+                    char tmp_buffer[PATHSTATUS_MAX] = {0};
+
+                    if (ACMGetPathStatus(tmp_buffer, PATHSTATUS_MAX) != ACM_RC_OK)
+                    {
+                        sprintf(tmp_buffer, "-> Fail to get status!\n");
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Get paths status failed", __FUNCTION__, __LINE__);
+                        continue;
+                    }
+
+                    LOGI(ACM_Calibration_Socket_Server_Thread, "%s.......", tmp_buffer);
+
+                    if(write(clientfd_server, tmp_buffer, PATHSTATUS_MAX*sizeof(char)) == -1)
+                    {
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Get paths status failed", __FUNCTION__, __LINE__);
+                        continue;
+                    }
+
+                    break;
+                }
+
+            case AUDIO_PHY_GetAudioMode:
+                {
+                    audio_mode_t mode = AUDIO_MODE_INVALID;
+                    int pcm_role = 0;
+                    int pcm_rate = 0;
+
+                    get_pcm_config(&pcm_role, &pcm_rate);
+                    LOGI(ACM_Calibration_Socket_Server_Thread, "%s: modem_is_master=%s, modem_is_wb=%s.......", __FUNCTION__, pcm_role?"TRUE":"FALSE", pcm_rate?"WB":"NB");
+
+                    mode = ACMGetAudioMode();
+
+                    if ((mode != AUDIO_MODE_NORMAL)  && (mode != AUDIO_MODE_IN_CALL))
+                    {
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "mode is not AUDIO_MODE_NORMAL and AUDIO_MODE_IN_CALL");
+                        continue;
+                    }
+
+                    LOGI(ACM_Calibration_Socket_Server_Thread, "mode = %s.......",
+                            (mode == AUDIO_MODE_NORMAL) ? "AUDIO_MODE_NORMAL" : "AUDIO_MODE_IN_CALL");
+
+                    if(write(clientfd_server, &mode, sizeof(audio_mode_t)) == -1)
+                    {
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Get mode failed", __FUNCTION__, __LINE__);
+                        continue;
+                    }
+
+                    break;
+                }
+            case AUDIO_PHY_ReloadCalibrationData:
+                {
+                    AC_Digital_Gain gain;
+
+                    LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: ReloadCalibrationData", __FUNCTION__, __LINE__);
+                    memset(&gain, 0x00, sizeof(AC_Digital_Gain));
+
+                    AC_ReloadCalibrationData(&gain);
+
+                    if(write(clientfd_server, &gain, sizeof(AC_Digital_Gain)) == -1) {
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Audio Calibration failed", __FUNCTION__, __LINE__);
+                        continue;
+                    }
+                }
+
+                LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: ReloadCalibrationData", __FUNCTION__, __LINE__);
+                break;
+
+            case AUDIO_PHY_SetPathVolume:
+                {
+                    AC_Digital_Gain gain;
+
+                    LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: SetPathVolume", __FUNCTION__, __LINE__);
+                    memset(&gain, 0x00, sizeof(AC_Digital_Gain));
+                    AC_SetPathVolume(&rcv_buf.body, &gain);
+
+                    if(write(clientfd_server, &gain, sizeof(AC_Digital_Gain)) == -1) {
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Audio Calibration  failed", __FUNCTION__, __LINE__);
+                        continue;
+                    }
+                }
+                LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: SetPathVolume", __FUNCTION__, __LINE__);
+                break;
+
+            case AUDIO_PHY_EnablePath:
+                {
+                    AC_Digital_Gain gain;
+
+                    LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: EnablePath", __FUNCTION__, __LINE__);
+                    memset(&gain, 0x00, sizeof(AC_Digital_Gain));
+                    AC_EnablePath(&rcv_buf.body, &gain);
+
+                    if(write(clientfd_server, &gain, sizeof(AC_Digital_Gain)) == -1) {
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Audio Calibration  failed", __FUNCTION__, __LINE__);
+                        continue;
+                    }
+                }
+
+                LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: EnablePath", __FUNCTION__, __LINE__);
+                break;
+
+            case AUDIO_PHY_DisablePath:
+                LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: DisablePath", __FUNCTION__, __LINE__);
+                AC_DisablePath(&rcv_buf.body);
+                break;
+
+            case AUDIO_PHY_MutePath:
+                LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: MutePath", __FUNCTION__, __LINE__);
+                AC_MutePath(&rcv_buf.body);
+                break;
+
+            case AUDIO_PHY_SwitchPath:
+                {
+                    AC_Digital_Gain gain;
+
+                    memset(&gain, 0x00, sizeof(AC_Digital_Gain));
+                    LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: SwitchPath", __FUNCTION__, __LINE__);
+                    AC_SwitchPath(&rcv_buf.body, &gain);
+
+                    if(write(clientfd_server, &gain, sizeof(AC_Digital_Gain)) == -1) {
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Audio Calibration  failed", __FUNCTION__, __LINE__);
+                        continue;
+                    }
+                }
+
+                LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: SwitchPath", __FUNCTION__, __LINE__);
+                break;
+
+#ifdef TARGET_mmp_asr1901_KSTR901
+            case AUDIO_PHY_SendVEtoADSP:
+                LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: SendVEtoADSP", __FUNCTION__, __LINE__);
+                ACM_SendVEtoADSP();
+                break;
+#endif
+
+            default:
+                continue;
+        }
+    }
+
+    unlink(ACM_CALIBRATION_SOCKET);
+    return;
+}
+
+
+void ACM_Init_Calibration_IPC(void)
+{
+    pthread_create( &ACM_Calibration_Server, NULL, (void *)ACM_Calibration_Socket_Server_Thread, NULL);
+}
+
+void ACM_Cancel_Calibration_IPC(void)
+{
+    pthread_cancel(ACM_Calibration_Server);
+
+    if (pthread_join(ACM_Calibration_Server, NULL)) {
+        LOGE(ACM_Cancel_Calibration_IPC, "%s/L%d: fail to pthread_join() ACM_Calibration_Server", __FUNCTION__, __LINE__);
+    }
+
+    if (fd_server >= 0) {
+        close(fd_server);
+        fd_server = -1;
+        LOGE(ACM_Cancel_Calibration_IPC, "%s/L%d: close fd_server.", __FUNCTION__, __LINE__);
+    }
+
+    if (clientfd_server >= 0) {
+        close(clientfd_server);
+        clientfd_server = -1;
+        LOGE(ACM_Cancel_Calibration_IPC, "%s/L%d: close clientfd_server.", __FUNCTION__, __LINE__);
+    }
+
+    return;
+}