hal: Add support for turning fluence on/off

- To turn on/off fluence we need to change the build prop
file and changes will take effect after reboot. There is no
option to turn it on/off without rebooting the target.
- Add set_params support to turn it on and off.
An option is given to user to select the dualmic fluence
based on which set_parms is invoked.

Change-Id: I51d580af820d8e0b1bd1384c941ffba3f96813ca
CRs-Fixed: 605087
diff --git a/hal/Android.mk b/hal/Android.mk
index d3d909d..6522bec 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -41,6 +41,10 @@
     LOCAL_CFLAGS += -DANC_HEADSET_ENABLED
 endif
 
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_FLUENCE)),true)
+    LOCAL_CFLAGS += -DFLUENCE_ENABLED
+endif
+
 ifneq ($(strip $(AUDIO_FEATURE_DISABLED_PROXY_DEVICE)),true)
     LOCAL_CFLAGS += -DAFE_PROXY_ENABLED
 endif
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 31a6353..d0caccb 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -28,6 +28,8 @@
 
 #include "audio_hw.h"
 #include "audio_extn.h"
+#include "platform.h"
+#include "platform_api.h"
 
 #define MAX_SLEEP_RETRY 100
 #define WIFI_INIT_WAIT_SLEEP 50
@@ -173,6 +175,60 @@
 }
 #endif /* ANC_HEADSET_ENABLED */
 
+#ifndef FLUENCE_ENABLED
+#define audio_extn_set_fluence_parameters(adev, parms) (0)
+#define audio_extn_get_fluence_parameters(adev, query, reply) (0)
+#else
+void audio_extn_set_fluence_parameters(struct audio_device *adev,
+                                            struct str_parms *parms)
+{
+    int ret = 0, err;
+    char value[32];
+    struct listnode *node;
+    struct audio_usecase *usecase;
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_FLUENCE,
+                                 value, sizeof(value));
+    ALOGV_IF(err >= 0, "%s: Set Fluence Type to %s", __func__, value);
+    if (err >= 0) {
+        ret = platform_set_fluence_type(adev->platform, value);
+        if (ret != 0) {
+            ALOGE("platform_set_fluence_type returned error: %d", ret);
+        } else {
+            /*
+             *If the fluence is manually set/reset, devices
+             *need to get updated for all the usecases
+             *i.e. audio and voice.
+             */
+             list_for_each(node, &adev->usecase_list) {
+                 usecase = node_to_item(node, struct audio_usecase, list);
+                 select_devices(adev, usecase->id);
+             }
+        }
+    }
+}
+
+int audio_extn_get_fluence_parameters(struct audio_device *adev,
+                       struct str_parms *query, struct str_parms *reply)
+{
+    int ret = 0, err;
+    char value[256] = {0};
+
+    err = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FLUENCE, value,
+                                                          sizeof(value));
+    if (err >= 0) {
+        ret = platform_get_fluence_type(adev->platform, value, sizeof(value));
+        if (ret >= 0) {
+            ALOGV("%s: Fluence Type is %s", __func__, value);
+            str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FLUENCE, value);
+        } else
+            goto done;
+    }
+done:
+    return ret;
+}
+#endif /* FLUENCE_ENABLED */
+
 #ifndef AFE_PROXY_ENABLED
 #define audio_extn_set_afe_proxy_parameters(adev, parms)  (0)
 #define audio_extn_get_afe_proxy_parameters(query, reply) (0)
@@ -372,6 +428,7 @@
                                struct str_parms *parms)
 {
    audio_extn_set_anc_parameters(adev, parms);
+   audio_extn_set_fluence_parameters(adev, parms);
    audio_extn_set_afe_proxy_parameters(adev, parms);
    audio_extn_fm_set_parameters(adev, parms);
    audio_extn_listen_set_parameters(adev, parms);
@@ -386,6 +443,7 @@
 {
     char *kv_pairs = NULL;
     audio_extn_get_afe_proxy_parameters(query, reply);
+    audio_extn_get_fluence_parameters(adev, query, reply);
 
     kv_pairs = str_parms_to_str(reply);
     ALOGD_IF(kv_pairs != NULL, "%s: returns %s", __func__, kv_pairs);
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index f631653..c7b0c0b 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -39,6 +39,16 @@
 bool audio_extn_should_use_handset_anc(int in_channels);
 #endif
 
+#ifndef FLUENCE_ENABLED
+#define audio_extn_set_fluence_parameters(adev, parms) (0)
+#define audio_extn_get_fluence_parameters(adev, query, reply) (0)
+#else
+void audio_extn_set_fluence_parameters(struct audio_device *adev,
+                                           struct str_parms *parms);
+int audio_extn_get_fluence_parameters(struct audio_device *adev,
+                  struct str_parms *query, struct str_parms *reply);
+#endif
+
 #ifndef AFE_PROXY_ENABLED
 #define audio_extn_set_afe_proxy_channel_mixer(adev,channel_count)     (0)
 #define audio_extn_read_afe_proxy_channel_masks(out)                   (0)
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 2108a00..e1172ef 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -32,13 +32,15 @@
 #define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/system/lib/soundfx/libqcompostprocbundle.so"
 
 /* Flags used to initialize acdb_settings variable that goes to ACDB library */
-#define DMIC_FLAG       0x00000002
-#define QMIC_FLAG       0x00000004
-#define TTY_MODE_OFF    0x00000010
-#define TTY_MODE_FULL   0x00000020
-#define TTY_MODE_VCO    0x00000040
-#define TTY_MODE_HCO    0x00000080
-#define TTY_MODE_CLEAR  0xFFFFFF0F
+#define NONE_FLAG            0x00000000
+#define DMIC_FLAG            0x00000002
+#define QMIC_FLAG            0x00000004
+#define TTY_MODE_OFF         0x00000010
+#define TTY_MODE_FULL        0x00000020
+#define TTY_MODE_VCO         0x00000040
+#define TTY_MODE_HCO         0x00000080
+#define TTY_MODE_CLEAR       0xFFFFFF0F
+#define FLUENCE_MODE_CLEAR   0xFFFFFFF0
 
 #define ACDB_DEV_TYPE_OUT 1
 #define ACDB_DEV_TYPE_IN 2
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 70e8c55..8cb2599 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -105,6 +105,7 @@
     bool fluence_in_voice_rec;
     bool fluence_in_audio_rec;
     int  fluence_type;
+    char fluence_cap[PROPERTY_VALUE_MAX];
     int  btsco_sample_rate;
     bool slowtalk;
     /* Audio calibration related functions */
@@ -605,10 +606,10 @@
     my_data->fluence_in_audio_rec = false;
     my_data->fluence_type = FLUENCE_NONE;
 
-    property_get("ro.qc.sdk.audio.fluencetype", value, "");
-    if (!strncmp("fluencepro", value, sizeof("fluencepro"))) {
+    property_get("ro.qc.sdk.audio.fluencetype", my_data->fluence_cap, "");
+    if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro"))) {
         my_data->fluence_type = FLUENCE_QUAD_MIC | FLUENCE_DUAL_MIC;
-    } else if (!strncmp("fluence", value, sizeof("fluence"))) {
+    } else if (!strncmp("fluence", my_data->fluence_cap, sizeof("fluence"))) {
         my_data->fluence_type = FLUENCE_DUAL_MIC;
     } else {
         my_data->fluence_type = FLUENCE_NONE;
@@ -787,6 +788,63 @@
     return ret;
 }
 
+int platform_set_fluence_type(void *platform, char *value)
+{
+    int ret = 0;
+    int fluence_type = FLUENCE_NONE;
+    int fluence_flag = NONE_FLAG;
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+
+    ALOGV("%s: fluence type:%d", __func__, my_data->fluence_type);
+
+    /* only dual mic turn on and off is supported as of now through setparameters */
+    if (!strncmp(AUDIO_PARAMETER_VALUE_DUALMIC,value, sizeof(AUDIO_PARAMETER_VALUE_DUALMIC))) {
+        if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro")) ||
+            !strncmp("fluence", my_data->fluence_cap, sizeof("fluence"))) {
+            ALOGV("fluence dualmic feature enabled \n");
+            fluence_type = FLUENCE_DUAL_MIC;
+            fluence_flag = DMIC_FLAG;
+        } else {
+            ALOGE("%s: Failed to set DUALMIC", __func__);
+            ret = -1;
+            goto done;
+        }
+    } else if (!strncmp(AUDIO_PARAMETER_KEY_NO_FLUENCE, value, sizeof(AUDIO_PARAMETER_KEY_NO_FLUENCE))) {
+        ALOGV("fluence disabled");
+        fluence_type = FLUENCE_NONE;
+    } else {
+        ALOGE("Invalid fluence value : %s",value);
+        ret = -1;
+        goto done;
+    }
+
+    if (fluence_type != my_data->fluence_type) {
+        ALOGV("%s: Updating fluence_type to :%d", __func__, fluence_type);
+        my_data->fluence_type = fluence_type;
+        adev->acdb_settings = (adev->acdb_settings & FLUENCE_MODE_CLEAR) | fluence_flag;
+    }
+done:
+    return ret;
+}
+
+int platform_get_fluence_type(void *platform, char *value, uint32_t len)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (my_data->fluence_type == FLUENCE_QUAD_MIC) {
+        strlcpy(value, "quadmic", len);
+    } else if (my_data->fluence_type == FLUENCE_DUAL_MIC) {
+        strlcpy(value, "dualmic", len);
+    } else if (my_data->fluence_type == FLUENCE_NONE) {
+        strlcpy(value, "none", len);
+    } else
+        ret = -1;
+
+    return ret;
+}
+
 int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id)
 {
     int ret = 0;
@@ -1708,23 +1766,7 @@
     char *str = NULL;
     char value[256] = {0};
     int ret;
-    int fluence_type;
 
-    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FLUENCE_TYPE,
-                            value, sizeof(value));
-    if (ret >= 0) {
-        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
-            strlcpy(value, "fluencepro", sizeof(value));
-        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
-            strlcpy(value, "fluence", sizeof(value));
-        } else {
-            strlcpy(value, "none", sizeof(value));
-        }
-
-        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FLUENCE_TYPE, value);
-    }
-
-    memset(value, 0, sizeof(value));
     ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SLOWTALK,
                             value, sizeof(value));
     if (ret >= 0) {
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index eea048f..4984dc8 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -113,6 +113,7 @@
     bool fluence_in_audio_rec;
     int  fluence_type;
     int  fluence_mode;
+    char fluence_cap[PROPERTY_VALUE_MAX];
     int  btsco_sample_rate;
     bool slowtalk;
     bool is_i2s_ext_modem;
@@ -681,10 +682,10 @@
     my_data->fluence_type = FLUENCE_NONE;
     my_data->fluence_mode = FLUENCE_ENDFIRE;
 
-    property_get("ro.qc.sdk.audio.fluencetype", value, "");
-    if (!strncmp("fluencepro", value, sizeof("fluencepro"))) {
+    property_get("ro.qc.sdk.audio.fluencetype", my_data->fluence_cap, "");
+    if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro"))) {
         my_data->fluence_type = FLUENCE_QUAD_MIC | FLUENCE_DUAL_MIC;
-    } else if (!strncmp("fluence", value, sizeof("fluence"))) {
+    } else if (!strncmp("fluence", my_data->fluence_cap, sizeof("fluence"))) {
         my_data->fluence_type = FLUENCE_DUAL_MIC;
     } else {
         my_data->fluence_type = FLUENCE_NONE;
@@ -874,6 +875,63 @@
     return ret;
 }
 
+int platform_set_fluence_type(void *platform, char *value)
+{
+    int ret = 0;
+    int fluence_type = FLUENCE_NONE;
+    int fluence_flag = NONE_FLAG;
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+
+    ALOGV("%s: fluence type:%d", __func__, my_data->fluence_type);
+
+    /* only dual mic turn on and off is supported as of now through setparameters */
+    if (!strncmp(AUDIO_PARAMETER_VALUE_DUALMIC,value, sizeof(AUDIO_PARAMETER_VALUE_DUALMIC))) {
+        if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro")) ||
+            !strncmp("fluence", my_data->fluence_cap, sizeof("fluence"))) {
+            ALOGV("fluence dualmic feature enabled \n");
+            fluence_type = FLUENCE_DUAL_MIC;
+            fluence_flag = DMIC_FLAG;
+        } else {
+            ALOGE("%s: Failed to set DUALMIC", __func__);
+            ret = -1;
+            goto done;
+        }
+    } else if (!strncmp(AUDIO_PARAMETER_KEY_NO_FLUENCE, value, sizeof(AUDIO_PARAMETER_KEY_NO_FLUENCE))) {
+        ALOGV("fluence disabled");
+        fluence_type = FLUENCE_NONE;
+    } else {
+        ALOGE("Invalid fluence value : %s",value);
+        ret = -1;
+        goto done;
+    }
+
+    if (fluence_type != my_data->fluence_type) {
+        ALOGV("%s: Updating fluence_type to :%d", __func__, fluence_type);
+        my_data->fluence_type = fluence_type;
+        adev->acdb_settings = (adev->acdb_settings & FLUENCE_MODE_CLEAR) | fluence_flag;
+    }
+done:
+    return ret;
+}
+
+int platform_get_fluence_type(void *platform, char *value, uint32_t len)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (my_data->fluence_type == FLUENCE_QUAD_MIC) {
+        strlcpy(value, "quadmic", len);
+    } else if (my_data->fluence_type == FLUENCE_DUAL_MIC) {
+        strlcpy(value, "dualmic", len);
+    } else if (my_data->fluence_type == FLUENCE_NONE) {
+        strlcpy(value, "none", len);
+    } else
+        ret = -1;
+
+    return ret;
+}
+
 int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id)
 {
     int ret = 0;
@@ -1824,24 +1882,8 @@
     char *str = NULL;
     char value[256] = {0};
     int ret;
-    int fluence_type;
     char *kv_pairs = NULL;
 
-    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FLUENCE_TYPE,
-                            value, sizeof(value));
-    if (ret >= 0) {
-        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
-            strlcpy(value, "fluencepro", sizeof(value));
-        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
-            strlcpy(value, "fluence", sizeof(value));
-        } else {
-            strlcpy(value, "none", sizeof(value));
-        }
-
-        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FLUENCE_TYPE, value);
-    }
-
-    memset(value, 0, sizeof(value));
     ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SLOWTALK,
                             value, sizeof(value));
     if (ret >= 0) {
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 03890e9..bf6bdcb 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -28,6 +28,8 @@
 void platform_add_backend_name(char *mixer_path, snd_device_t snd_device);
 int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type);
 int platform_get_snd_device_index(char *snd_device_index_name);
+int platform_set_fluence_type(void *platform, char *value);
+int platform_get_fluence_type(void *platform, char *value, uint32_t len);
 int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id);
 int platform_send_audio_calibration(void *platform, snd_device_t snd_device);
 int platform_switch_voice_call_device_pre(void *platform);