Merge "hal: Provide support to enable/disable EC/NS in BT"
diff --git a/hal/Android.mk b/hal/Android.mk
index d6f07fa..32b9275 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -141,6 +141,11 @@
     LOCAL_CFLAGS += -DQTI_FLAC_DECODER
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_DEV_ARBI)),true)
+    LOCAL_CFLAGS += -DDEV_ARBI_ENABLED
+    LOCAL_SRC_FILES += audio_extn/dev_arbi.c
+endif
+
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
 	libcutils \
@@ -148,8 +153,7 @@
 	libtinycompress \
 	libaudioroute \
 	libdl \
-	libexpat \
-        libmdmdetect
+	libexpat
 
 LOCAL_C_INCLUDES += \
 	external/tinyalsa/include \
@@ -159,8 +163,7 @@
 	$(call include-path-for, audio-effects) \
 	$(LOCAL_PATH)/$(AUDIO_PLATFORM) \
 	$(LOCAL_PATH)/audio_extn \
-	$(LOCAL_PATH)/voice_extn \
-        $(TARGET_OUT_HEADERS)/libmdmdetect/inc
+	$(LOCAL_PATH)/voice_extn
 
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_LISTEN)),true)
     LOCAL_CFLAGS += -DAUDIO_LISTEN_ENABLED
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 7ce1c3a..5eb650c 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -192,7 +192,7 @@
 #define audio_extn_spkr_prot_stop_processing()     (0)
 #define audio_extn_spkr_prot_is_enabled() (false)
 #define audio_extn_spkr_prot_get_acdb_id(snd_device)         (-EINVAL)
-#define audio_extn_get_spkr_prot_snd_device(snd_device) (SND_DEVICE_OUT_SPEAKER)
+#define audio_extn_get_spkr_prot_snd_device(snd_device) (snd_device)
 #else
 void audio_extn_spkr_prot_init(void *adev);
 int audio_extn_spkr_prot_start_processing(snd_device_t snd_device);
@@ -260,6 +260,18 @@
 audio_usecase_t audio_extn_hfp_get_usecase();
 #endif
 
+#ifndef DEV_ARBI_ENABLED
+#define audio_extn_dev_arbi_init()                  (0)
+#define audio_extn_dev_arbi_deinit()                (0)
+#define audio_extn_dev_arbi_acquire(snd_device)     (0)
+#define audio_extn_dev_arbi_release(snd_device)     (0)
+#else
+int audio_extn_dev_arbi_init();
+int audio_extn_dev_arbi_deinit();
+int audio_extn_dev_arbi_acquire(snd_device_t snd_device);
+int audio_extn_dev_arbi_release(snd_device_t snd_device);
+#endif
+
 void audio_extn_utils_update_streams_output_cfg_list(void *platform,
                                   struct mixer *mixer,
                                   struct listnode *streams_output_cfg_list);
diff --git a/hal/audio_extn/dev_arbi.c b/hal/audio_extn/dev_arbi.c
new file mode 100644
index 0000000..d3c01c5
--- /dev/null
+++ b/hal/audio_extn/dev_arbi.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "audio_hw_dev_arbi"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <cutils/log.h>
+#include <fcntl.h>
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/properties.h>
+#include "audio_extn.h"
+
+#ifdef DEV_ARBI_ENABLED
+
+typedef int (init_fn_t)();
+typedef int (deinit_fn_t)();
+typedef int (acquire_fn_t)(audio_devices_t aud_dev);
+typedef int (release_fn_t)(audio_devices_t aud_dev);
+
+typedef struct {
+    snd_device_t snd_device;
+    audio_devices_t aud_device;
+} snd_aud_dev_mapping_t;
+
+static void* lib_handle = NULL;
+
+static init_fn_t *init_fp = NULL;
+static deinit_fn_t *deinit_fp = NULL;
+static acquire_fn_t *acquire_fp = NULL;
+static release_fn_t *release_fp = NULL;
+
+static int load_dev_arbi_lib()
+{
+    int rc = -EINVAL;
+
+    if (lib_handle != NULL) {
+        ALOGE("%s: library already loaded", __func__);
+        return rc;
+    }
+
+    lib_handle = dlopen("libaudiodevarb.so", RTLD_NOW);
+    if (lib_handle != NULL) {
+        init_fp = (init_fn_t*)dlsym(lib_handle, "aud_dev_arbi_server_init");
+        deinit_fp = (deinit_fn_t*)dlsym(lib_handle, "aud_dev_arbi_server_deinit");
+        acquire_fp = (acquire_fn_t*)dlsym(lib_handle, "aud_dev_arbi_server_acquire");
+        release_fp = (release_fn_t*)dlsym(lib_handle, "aud_dev_arbi_server_release");
+
+        if ((init_fp == NULL) ||
+            (deinit_fp == NULL) ||
+            (acquire_fp == NULL) ||
+            (release_fp == NULL)) {
+
+            ALOGE("%s: error loading symbols from library", __func__);
+
+            init_fp = NULL;
+            deinit_fp = NULL;
+            acquire_fp = NULL;
+            release_fp = NULL;
+        } else
+            return 0;
+    }
+
+    return rc;
+}
+
+int audio_extn_dev_arbi_init()
+{
+    int rc = load_dev_arbi_lib();
+    if (!rc)
+        rc = init_fp();
+
+    return rc;
+}
+
+int audio_extn_dev_arbi_deinit()
+{
+    int rc = -EINVAL;
+
+    if(deinit_fp != NULL) {
+        rc = deinit_fp();
+
+        init_fp = NULL;
+        deinit_fp = NULL;
+        acquire_fp = NULL;
+        release_fp = NULL;
+
+        dlclose(lib_handle);
+        lib_handle = NULL;
+    }
+
+    return rc;
+}
+
+static audio_devices_t get_audio_device(snd_device_t snd_device)
+{
+    static snd_aud_dev_mapping_t snd_aud_dev_map[] = {
+        {SND_DEVICE_OUT_HANDSET, AUDIO_DEVICE_OUT_EARPIECE},
+        {SND_DEVICE_OUT_VOICE_HANDSET, AUDIO_DEVICE_OUT_EARPIECE}
+    };
+
+    audio_devices_t aud_device = AUDIO_DEVICE_NONE;
+    uint32_t ind = 0;
+
+    for (ind = 0; ind < ARRAY_SIZE(snd_aud_dev_map); ++ind) {
+        if (snd_device == snd_aud_dev_map[ind].snd_device) {
+            aud_device = snd_aud_dev_map[ind].aud_device;
+            break;
+        }
+    }
+
+    return aud_device;
+}
+
+int audio_extn_dev_arbi_acquire(snd_device_t snd_device)
+{
+    int rc = -EINVAL;
+    audio_devices_t audio_device = get_audio_device(snd_device);
+
+    if ((acquire_fp != NULL) && (audio_device != AUDIO_DEVICE_NONE))
+        rc = acquire_fp(audio_device);
+
+    return rc;
+}
+
+int audio_extn_dev_arbi_release(snd_device_t snd_device)
+{
+    int rc = -EINVAL;
+    audio_devices_t audio_device = get_audio_device(snd_device);
+
+    if ((release_fp != NULL) && (audio_device != AUDIO_DEVICE_NONE))
+        rc = release_fp(audio_device);
+
+    return rc;
+}
+
+#endif /*DEV_ARBI_ENABLED*/
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 31aa222..dcf3b93 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -379,6 +379,7 @@
                                         LISTEN_EVENT_SND_DEVICE_FREE);
             return -EINVAL;
         }
+        audio_extn_dev_arbi_acquire(snd_device);
         audio_route_apply_and_update_path(adev->audio_route, device_name);
     }
     return 0;
@@ -422,9 +423,10 @@
             snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) &&
             audio_extn_spkr_prot_is_enabled()) {
             audio_extn_spkr_prot_stop_processing();
-        } else
+        } else {
             audio_route_reset_and_update_path(adev->audio_route, device_name);
-
+            audio_extn_dev_arbi_release(snd_device);
+        }
         audio_extn_listen_update_device_status(snd_device,
                                         LISTEN_EVENT_SND_DEVICE_FREE);
     }
@@ -1848,7 +1850,9 @@
         if (out->pcm)
             ALOGE("%s: error %d - %s", __func__, ret, pcm_get_error(out->pcm));
         if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
+            pthread_mutex_lock(&adev->lock);
             voice_extn_compress_voip_close_output_stream(&out->stream.common);
+            pthread_mutex_unlock(&adev->lock);
             out->standby = true;
         }
         out_standby(&out->stream.common);
@@ -2264,7 +2268,9 @@
 
     if (ret != 0) {
         if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
+            pthread_mutex_lock(&adev->lock);
             voice_extn_compress_voip_close_input_stream(&in->stream.common);
+            pthread_mutex_unlock(&adev->lock);
             in->standby = true;
         }
         in_standby(&in->stream.common);
@@ -2601,7 +2607,9 @@
     ALOGD("%s: enter:stream_handle(%p)",__func__, out);
 
     if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
+        pthread_mutex_lock(&adev->lock);
         ret = voice_extn_compress_voip_close_output_stream(&stream->common);
+        pthread_mutex_unlock(&adev->lock);
         if(ret != 0)
             ALOGE("%s: Compress voip output cannot be closed, error:%d",
                   __func__, ret);
@@ -2949,10 +2957,14 @@
 {
     int ret;
     struct stream_in *in = (struct stream_in *)stream;
+    struct audio_device *adev = in->dev;
+
     ALOGD("%s: enter:stream_handle(%p)",__func__, in);
 
     if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
+        pthread_mutex_lock(&adev->lock);
         ret = voice_extn_compress_voip_close_input_stream(&stream->common);
+        pthread_mutex_unlock(&adev->lock);
         if (ret != 0)
             ALOGE("%s: Compress voip input cannot be closed, error:%d",
                   __func__, ret);
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index a8035f4..949753d 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -33,7 +33,6 @@
 #include "audio_extn.h"
 #include "voice_extn.h"
 #include "sound/compress_params.h"
-#include "mdm_detect.h"
 
 #define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
 #define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
@@ -44,6 +43,7 @@
 
 #define LIB_ACDB_LOADER "libacdbloader.so"
 #define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID"
+#define CVD_VERSION_MIXER_CTL "CVD Version"
 
 #define MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE (256 * 1024)
 #define MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE (2 * 1024)
@@ -72,6 +72,8 @@
 #define MAX_SAD_BLOCKS      10
 #define SAD_BLOCK_SIZE      3
 
+#define MAX_CVD_VERSION_STRING_SIZE    100
+
 /* EDID format ID for LPCM audio */
 #define EDID_FORMAT_LPCM    1
 
@@ -109,7 +111,7 @@
 
 /* Audio calibration related functions */
 typedef void (*acdb_deallocate_t)();
-typedef int  (*acdb_init_t)(char *);
+typedef int  (*acdb_init_t)(char *, char *);
 typedef void (*acdb_send_audio_cal_t)(int, int, int , int);
 typedef void (*acdb_send_voice_cal_t)(int, int);
 typedef int (*acdb_reload_vocvoltable_t)(int);
@@ -653,26 +655,6 @@
     }
 }
 
-static void platform_csd_init(struct platform_data *plat_data)
-{
-    struct dev_info mdm_detect_info;
-    int ret = 0;
-
-    /* Call ESOC API to get the number of modems.
-     * If the number of modems is not zero, load CSD Client specific
-     * symbols. Voice call is handled by MDM and apps processor talks to
-     * MDM through CSD Client
-     */
-    ret = get_system_info(&mdm_detect_info);
-    if (ret > 0) {
-        ALOGE("%s: Failed to get system info, ret %d", __func__, ret);
-    }
-    ALOGD("%s: num_modems %d\n", __func__, mdm_detect_info.num_modems);
-
-    if (mdm_detect_info.num_modems > 0)
-        plat_data->csd = open_csd_client(plat_data->is_i2s_ext_modem);
-}
-
 static bool platform_is_i2s_ext_modem(const char *snd_card_name,
                                       struct platform_data *plat_data)
 {
@@ -715,12 +697,42 @@
     backend_table[SND_DEVICE_OUT_TRANSMISSION_FM] = strdup("transmission-fm");
 }
 
+void get_cvd_version(char *cvd_version, struct audio_device *adev)
+{
+    struct mixer_ctl *ctl;
+    int count;
+    int ret = 0;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, CVD_VERSION_MIXER_CTL);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",  __func__, CVD_VERSION_MIXER_CTL);
+        goto done;
+    }
+    mixer_ctl_update(ctl);
+
+    count = mixer_ctl_get_num_values(ctl);
+    if (count > MAX_CVD_VERSION_STRING_SIZE)
+        count = MAX_CVD_VERSION_STRING_SIZE;
+
+    ret = mixer_ctl_get_array(ctl, cvd_version, count);
+    if (ret != 0) {
+        ALOGE("%s: ERROR! mixer_ctl_get_array() failed to get CVD Version", __func__);
+        goto done;
+    }
+
+done:
+    return;
+}
+
 void *platform_init(struct audio_device *adev)
 {
+    char platform[PROPERTY_VALUE_MAX];
+    char baseband[PROPERTY_VALUE_MAX];
     char value[PROPERTY_VALUE_MAX];
     struct platform_data *my_data = NULL;
     int retry_num = 0, snd_card_num = 0;
     const char *snd_card_name;
+    char *cvd_version = NULL;
 
     my_data = calloc(1, sizeof(struct platform_data));
 
@@ -869,12 +881,24 @@
 
         my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_init_v2");
-        if (my_data->acdb_init == NULL)
+        if (my_data->acdb_init == NULL) {
             ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__, dlerror());
+            goto acdb_init_fail;
+        }
+
+        cvd_version = calloc(1, MAX_CVD_VERSION_STRING_SIZE);
+        if (!cvd_version)
+            ALOGE("failed to allocate cvd_version");
         else
-            my_data->acdb_init(snd_card_name);
+            get_cvd_version(cvd_version, adev);
+
+        my_data->acdb_init(snd_card_name, cvd_version);
+        if (cvd_version)
+            free(cvd_version);
     }
 
+acdb_init_fail:
+
     set_platform_defaults(my_data);
 
     /* Initialize ACDB ID's */
@@ -883,8 +907,18 @@
     else
         platform_info_init(PLATFORM_INFO_XML_PATH);
 
-    /* load csd client */
-    platform_csd_init(my_data);
+    /* If platform is apq8084 and baseband is MDM, load CSD Client specific
+     * symbols. Voice call is handled by MDM and apps processor talks to
+     * MDM through CSD Client
+     */
+    property_get("ro.board.platform", platform, "");
+    property_get("ro.baseband", baseband, "");
+    if (!strncmp("apq8084", platform, sizeof("apq8084")) &&
+        !strncmp("mdm", baseband, (sizeof("mdm")-1))) {
+         my_data->csd = open_csd_client(my_data->is_i2s_ext_modem);
+    } else {
+         my_data->csd = NULL;
+    }
 
     /* init usb */
     audio_extn_usb_init(adev);
@@ -897,6 +931,9 @@
 
     audio_extn_dolby_set_license(adev);
 
+    /* init audio device arbitration */
+    audio_extn_dev_arbi_init();
+
     return my_data;
 }
 
@@ -915,6 +952,9 @@
         }
     }
 
+    /* deinit audio device arbitration */
+    audio_extn_dev_arbi_deinit();
+
     free(platform);
     /* deinit usb */
     audio_extn_usb_deinit();
diff --git a/hal/voice.c b/hal/voice.c
index 33e0d2c..a5826e6 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -410,12 +410,20 @@
     ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
 
     ret = voice_extn_set_parameters(adev, parms);
-    if (ret != 0)
-        goto done;
+    if (ret != 0) {
+        if (ret == -ENOSYS)
+            ret = 0;
+        else
+            goto done;
+    }
 
     ret = voice_extn_compress_voip_set_parameters(adev, parms);
-    if (ret != 0)
-        goto done;
+    if (ret != 0) {
+        if (ret == -ENOSYS)
+            ret = 0;
+        else
+            goto done;
+    }
 
     err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value));
     if (err >= 0) {
@@ -450,7 +458,7 @@
             platform_start_incall_music_usecase(adev->platform);
         else
             platform_stop_incall_music_usecase(adev->platform);
-     }
+    }
 
 done:
     ALOGV("%s: exit with code(%d)", __func__, ret);