audio_hal: Add support for multi voice sessions

Update HAL to add multi SIM voice support. Seperate
out voice features to voice files.

Add getprop/setprop for BT sample rate, Fluence and Slow talk.

Change-Id: Ief61466f78c7b915549981a28fc7ff32731607a5
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 02940b4..ee069d7 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -25,6 +25,7 @@
 #include <dlfcn.h>
 #include <cutils/log.h>
 #include <cutils/properties.h>
+#include <cutils/str_parms.h>
 #include <audio_hw.h>
 #include <platform_api.h>
 #include "platform.h"
@@ -51,10 +52,17 @@
 #define RETRY_NUMBER 10
 #define RETRY_US 500000
 
+#define SAMPLE_RATE_8KHZ  8000
+#define SAMPLE_RATE_16KHZ 16000
+
 #define MAX_VOL_INDEX 5
 #define MIN_VOL_INDEX 0
 #define percent_to_index(val, min, max) \
-                ((val) * ((max) - (min)) * 0.01 + (min) + .5)
+            ((val) * ((max) - (min)) * 0.01 + (min) + .5)
+
+#define AUDIO_PARAMETER_KEY_FLUENCE_TYPE  "fluence"
+#define AUDIO_PARAMETER_KEY_BTSCO         "bt_samplerate"
+#define AUDIO_PARAMETER_KEY_SLOWTALK      "st_enable"
 
 struct audio_block_header
 {
@@ -74,6 +82,8 @@
     bool fluence_in_voice_call;
     bool fluence_in_voice_rec;
     int  fluence_type;
+    int  btsco_sample_rate;
+    bool slowtalk;
 
     void *acdb_handle;
     acdb_init_t acdb_init;
@@ -92,8 +102,11 @@
     [USECASE_AUDIO_RECORD] = {DEEP_BUFFER_PCM_DEVICE, DEEP_BUFFER_PCM_DEVICE},
     [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
                                           LOWLATENCY_PCM_DEVICE},
-    [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE},
     [USECASE_AUDIO_PLAYBACK_FM] = {FM_PLAYBACK_PCM_DEVICE, FM_CAPTURE_PCM_DEVICE},
+    [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE},
+    [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE},
+    [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE},
+    [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE},
 };
 
 /* Array to store sound devices */
@@ -111,6 +124,7 @@
     [SND_DEVICE_OUT_HDMI] = "hdmi",
     [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi",
     [SND_DEVICE_OUT_BT_SCO] = "bt-sco-headset",
+    [SND_DEVICE_OUT_BT_SCO_WB] = "bt-sco-headset-wb",
     [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = "voice-handset-tmus",
     [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones",
     [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones",
@@ -134,6 +148,7 @@
     [SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic",
     [SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic",
     [SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic",
+    [SND_DEVICE_IN_BT_SCO_MIC_WB] = "bt-sco-mic-wb",
     [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic",
     [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef",
     [SND_DEVICE_IN_VOICE_DMIC_TMUS] = "voice-dmic-ef-tmus",
@@ -162,6 +177,7 @@
     [SND_DEVICE_OUT_HDMI] = 18,
     [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 15,
     [SND_DEVICE_OUT_BT_SCO] = 22,
+    [SND_DEVICE_OUT_BT_SCO_WB] = 39,
     [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = 88,
     [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
     [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
@@ -184,6 +200,7 @@
     [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8,
     [SND_DEVICE_IN_HDMI_MIC] = 4,
     [SND_DEVICE_IN_BT_SCO_MIC] = 21,
+    [SND_DEVICE_IN_BT_SCO_MIC_WB] = 38,
     [SND_DEVICE_IN_CAMCORDER_MIC] = 61,
     [SND_DEVICE_IN_VOICE_DMIC] = 41,
     [SND_DEVICE_IN_VOICE_DMIC_TMUS] = 89,
@@ -225,24 +242,6 @@
     return is_tmus;
 }
 
-static int set_volume_values(int type, int volume, int* values)
-{
-    values[0] = volume;
-    values[1] = ALL_SESSION_VSID;
-
-    switch(type) {
-    case VOLUME_SET:
-        values[2] = DEFAULT_VOLUME_RAMP_DURATION_MS;
-        break;
-    case MUTE_SET:
-        values[2] = DEFAULT_MUTE_RAMP_DURATION;
-        break;
-    default:
-        return -EINVAL;
-    }
-    return 0;
-}
-
 static int set_echo_reference(struct mixer *mixer, const char* ec_ref)
 {
     struct mixer_ctl *ctl;
@@ -287,6 +286,7 @@
     my_data = calloc(1, sizeof(struct platform_data));
 
     my_data->adev = adev;
+    my_data->btsco_sample_rate = SAMPLE_RATE_8KHZ;
     my_data->fluence_in_spkr_mode = false;
     my_data->fluence_in_voice_call = false;
     my_data->fluence_in_voice_rec = false;
@@ -359,11 +359,15 @@
 void platform_add_backend_name(char *mixer_path, snd_device_t snd_device)
 {
     if (snd_device == SND_DEVICE_IN_BT_SCO_MIC)
-        strcat(mixer_path, " bt-sco");
+        strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
+    else if (snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB)
+        strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
     else if(snd_device == SND_DEVICE_OUT_BT_SCO)
-        strcat(mixer_path, " bt-sco");
+        strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
+    else if(snd_device == SND_DEVICE_OUT_BT_SCO_WB)
+        strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
     else if (snd_device == SND_DEVICE_OUT_HDMI)
-        strcat(mixer_path, " hdmi");
+        strlcat(mixer_path, " hdmi", MIXER_PATH_MAX_LENGTH);
     else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI)
         strcat(mixer_path, " speaker-and-hdmi");
     else if (snd_device == SND_DEVICE_IN_CAPTURE_FM)
@@ -450,13 +454,16 @@
     struct audio_device *adev = my_data->adev;
     struct mixer_ctl *ctl;
     const char *mixer_ctl_name = "Voice Rx Gain";
-    int values[VOLUME_CTL_PARAM_NUM];
-    int ret = 0;
+    int vol_index = 0;
+    uint32_t set_values[ ] = {0,
+                              ALL_SESSION_VSID,
+                              DEFAULT_VOLUME_RAMP_DURATION_MS};
 
     // Voice volume levels are mapped to adsp volume levels as follows.
     // 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1  0 -> 0
     // But this values don't changed in kernel. So, below change is need.
-    volume = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX);
+    vol_index = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX);
+    set_values[0] = vol_index;
 
     ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
     if (!ctl) {
@@ -464,16 +471,8 @@
               __func__, mixer_ctl_name);
         return -EINVAL;
     }
-    ret = set_volume_values(VOLUME_SET, volume, values);
-    if (ret < 0) {
-        ALOGV("%s: failed setting volume by incorrect type", __func__);
-        return -EINVAL;
-    }
-    ret = mixer_ctl_set_array(ctl, values, sizeof(values)/sizeof(int));
-    if (ret < 0) {
-        ALOGV("%s: failed set mixer ctl by %d", __func__, ret);
-        return -EINVAL;
-    }
+    ALOGV("Setting voice volume index: %d", set_values[0]);
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
 
     return 0;
 }
@@ -484,27 +483,20 @@
     struct audio_device *adev = my_data->adev;
     struct mixer_ctl *ctl;
     const char *mixer_ctl_name = "Voice Tx Mute";
-    int values[VOLUME_CTL_PARAM_NUM];
-    int ret = 0;
+    uint32_t set_values[ ] = {0,
+                              ALL_SESSION_VSID,
+                              DEFAULT_VOLUME_RAMP_DURATION_MS};
 
     if (adev->mode == AUDIO_MODE_IN_CALL) {
+        set_values[0] = state;
         ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
         if (!ctl) {
             ALOGE("%s: Could not get ctl for mixer cmd - %s",
                   __func__, mixer_ctl_name);
             return -EINVAL;
         }
-        ALOGV("Setting mic mute: %d", state);
-        ret = set_volume_values(MUTE_SET, state, values);
-        if (ret < 0) {
-            ALOGV("%s: failed setting mute by incorrect type", __func__);
-            return -EINVAL;
-        }
-        ret = mixer_ctl_set_array(ctl, values, sizeof(values)/sizeof(int));
-        if (ret < 0) {
-            ALOGV("%s: failed set mixer ctl by %d", __func__, ret);
-            return -EINVAL;
-        }
+        ALOGV("Setting voice mute state: %d", state);
+        mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
     }
 
     return 0;
@@ -536,22 +528,25 @@
     if (mode == AUDIO_MODE_IN_CALL) {
         if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
             devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
-            if (adev->tty_mode == TTY_MODE_FULL)
+            if (adev->voice.tty_mode == TTY_MODE_FULL) {
                 snd_device = SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES;
-            else if (adev->tty_mode == TTY_MODE_VCO)
+            } else if (adev->voice.tty_mode == TTY_MODE_VCO) {
                 snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES;
-            else if (adev->tty_mode == TTY_MODE_HCO)
+            } else if (adev->voice.tty_mode == TTY_MODE_HCO) {
                 snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET;
-            else if (audio_extn_get_anc_enabled()) {
+            } else if (audio_extn_get_anc_enabled()) {
                 if (audio_extn_should_use_fb_anc())
                     snd_device = SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET;
                 else
                     snd_device = SND_DEVICE_OUT_VOICE_ANC_HEADSET;
-           }
-            else
+            } else {
                 snd_device = SND_DEVICE_OUT_VOICE_HEADPHONES;
+            }
         } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
-            snd_device = SND_DEVICE_OUT_BT_SCO;
+            if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ)
+                snd_device = SND_DEVICE_OUT_BT_SCO_WB;
+            else
+                snd_device = SND_DEVICE_OUT_BT_SCO;
         } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
             snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
         } else if (devices & AUDIO_DEVICE_OUT_FM_TX) {
@@ -613,7 +608,10 @@
         else
             snd_device = SND_DEVICE_OUT_SPEAKER;
     } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
-        snd_device = SND_DEVICE_OUT_BT_SCO;
+        if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ)
+            snd_device = SND_DEVICE_OUT_BT_SCO_WB;
+        else
+            snd_device = SND_DEVICE_OUT_BT_SCO;
     } else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
         snd_device = SND_DEVICE_OUT_HDMI ;
     } else if (devices & AUDIO_DEVICE_OUT_FM_TX) {
@@ -651,10 +649,10 @@
             ALOGE("%s: No output device set for voice call", __func__);
             goto exit;
         }
-        if (adev->tty_mode != TTY_MODE_OFF) {
+        if (adev->voice.tty_mode != TTY_MODE_OFF) {
             if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
                 out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
-                switch (adev->tty_mode) {
+                switch (adev->voice.tty_mode) {
                 case TTY_MODE_FULL:
                     snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC;
                     break;
@@ -665,7 +663,8 @@
                     snd_device = SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC;
                     break;
                 default:
-                    ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->tty_mode);
+                    ALOGE("%s: Invalid TTY mode (%#x)",
+                          __func__, adev->voice.tty_mode);
                 }
                 goto exit;
             }
@@ -688,7 +687,10 @@
         } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
             snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC;
         } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
-            snd_device = SND_DEVICE_IN_BT_SCO_MIC ;
+            if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ)
+                snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+            else
+                snd_device = SND_DEVICE_IN_BT_SCO_MIC;
         } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
             if (my_data->fluence_type != FLUENCE_NONE &&
                 my_data->fluence_in_voice_call &&
@@ -760,7 +762,10 @@
         } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
             snd_device = SND_DEVICE_IN_HEADSET_MIC;
         } else if (in_device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
-            snd_device = SND_DEVICE_IN_BT_SCO_MIC ;
+            if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ)
+                snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+            else
+                snd_device = SND_DEVICE_IN_BT_SCO_MIC;
         } else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) {
             snd_device = SND_DEVICE_IN_HDMI_MIC;
         } else if (in_device & AUDIO_DEVICE_IN_FM_RX) {
@@ -780,7 +785,10 @@
         } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
             snd_device = SND_DEVICE_IN_HANDSET_MIC;
         } else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) {
-            snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+            if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ)
+                snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+            else
+                snd_device = SND_DEVICE_IN_BT_SCO_MIC;
         } else if (out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
             snd_device = SND_DEVICE_IN_HDMI_MIC;
         } else {
@@ -882,3 +890,89 @@
 
     return max_channels;
 }
+
+static int platform_set_slowtalk(struct platform_data *my_data, bool state)
+{
+    int ret = 0;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Slowtalk Enable";
+    uint32_t set_values[ ] = {0,
+                              ALL_SESSION_VSID};
+
+    set_values[0] = state;
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        ret = -EINVAL;
+    } else {
+        ALOGV("Setting slowtalk state: %d", state);
+        ret = mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+        my_data->slowtalk = state;
+    }
+
+    return ret;
+}
+
+int platform_set_parameters(void *platform, struct str_parms *parms)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    char *str;
+    char value[32];
+    int val;
+    int ret = 0;
+
+    ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms));
+
+    ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_BTSCO, &val);
+    if (ret >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_BTSCO);
+        pthread_mutex_lock(&my_data->adev->lock);
+        my_data->btsco_sample_rate = val;
+        pthread_mutex_unlock(&my_data->adev->lock);
+    }
+
+    ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_SLOWTALK, &val);
+    if (ret >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_SLOWTALK);
+        pthread_mutex_lock(&my_data->adev->lock);
+        ret = platform_set_slowtalk(my_data, val);
+        if (ret)
+            ALOGE("%s: Failed to set slow talk err: %d", __func__, ret);
+        pthread_mutex_unlock(&my_data->adev->lock);
+    }
+
+    ALOGV("%s: exit with code(%d)", __func__, ret);
+    return ret;
+}
+
+void platform_get_parameters(void *platform,
+                            struct str_parms *query,
+                            struct str_parms *reply)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    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) {
+        pthread_mutex_lock(&my_data->adev->lock);
+        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));
+        }
+        pthread_mutex_unlock(&my_data->adev->lock);
+
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FLUENCE_TYPE, value);
+    }
+
+    ALOGV("%s: exit: returns - %s", __func__, str_parms_to_str(reply));
+}
+