audio: Select device based on supported mic count

source_mic_type is obtained using max mic count. Default value
is dual mic.
If fluence is enabled, device is selected based on fluence type set
and mic count supported.
For VoiceRecognition source, channel count should be 1 to enable
fluence.
Add support for 3 and 4 channel recording.

Change-Id: I4c7229230b79830a66e25cc49d80f1e7090c0212
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index a84f310..daeacf8 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -254,6 +254,8 @@
     char cvd_version[MAX_CVD_VERSION_STRING_SIZE];
     char snd_card_name[MAX_SND_CARD_STRING_SIZE];
     int metainfo_key;
+    int source_mic_type;
+    int max_mic_count;
 };
 
 static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
@@ -433,6 +435,7 @@
     [SND_DEVICE_IN_SPEAKER_QMIC_NS] = "quad-mic",
     [SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS] = "quad-mic",
     [SND_DEVICE_IN_THREE_MIC] = "three-mic",
+    [SND_DEVICE_IN_HANDSET_TMIC] = "three-mic",
 };
 
 // Platform specific backend bit width table
@@ -538,7 +541,8 @@
     [SND_DEVICE_IN_SPEAKER_QMIC_AEC] = 126,
     [SND_DEVICE_IN_SPEAKER_QMIC_NS] = 127,
     [SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS] = 129,
-    [SND_DEVICE_IN_THREE_MIC] = 46,
+    [SND_DEVICE_IN_THREE_MIC] = 46, /* for APSS Surround Sound Recording */
+    [SND_DEVICE_IN_HANDSET_TMIC] = 125, /* for 3mic recording with fluence */
 };
 
 struct name_to_index {
@@ -643,6 +647,8 @@
     {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_AEC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_NS)},
     {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_THREE_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_TMIC)},
 };
 
 static char * backend_tag_table[SND_DEVICE_MAX] = {0};
@@ -1042,7 +1048,7 @@
     return plat_data->is_i2s_ext_modem;
 }
 
-static void set_platform_defaults()
+static void set_platform_defaults(struct platform_data * my_data)
 {
     int32_t dev;
     unsigned int count = 0;
@@ -1083,6 +1089,7 @@
     hw_interface_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = strdup("SLIMBUS_0_RX-and-HDMI_RX");
     hw_interface_table[SND_DEVICE_OUT_VOICE_TX] = strdup("AFE_PCM_RX");
 
+    my_data->max_mic_count = PLATFORM_DEFAULT_MIC_COUNT;
 
      /*remove ALAC & APE from DSP decoder list based on software decoder availability*/
      for (count = 0; count < (int32_t)(sizeof(dsp_only_decoders_mime)/sizeof(dsp_only_decoders_mime[0]));
@@ -1319,6 +1326,27 @@
     return result;
 }
 
+static void get_source_mic_type(struct platform_data * my_data)
+{
+    // support max to mono, example if max count is 3, usecase supports Three, dual and mono mic
+    switch (my_data->max_mic_count) {
+        case 4:
+            my_data->source_mic_type |= SOURCE_QUAD_MIC;
+        case 3:
+            my_data->source_mic_type |= SOURCE_THREE_MIC;
+        case 2:
+            my_data->source_mic_type |= SOURCE_DUAL_MIC;
+        case 1:
+            my_data->source_mic_type |= SOURCE_MONO_MIC;
+            break;
+        default:
+            ALOGE("%s: max_mic_count (%d), is not supported, setting to default",
+                   __func__, my_data->max_mic_count);
+            my_data->source_mic_type = SOURCE_MONO_MIC | SOURCE_DUAL_MIC;
+            break;
+    }
+}
+
 void *platform_init(struct audio_device *adev)
 {
     char platform[PROPERTY_VALUE_MAX];
@@ -1599,7 +1627,7 @@
 
 acdb_init_fail:
 
-    set_platform_defaults();
+    set_platform_defaults(my_data);
 
     /* Initialize ACDB ID's */
     if (my_data->is_i2s_ext_modem)
@@ -1620,6 +1648,14 @@
          my_data->csd = NULL;
     }
 
+    /* obtain source mic type from max mic count*/
+    get_source_mic_type(my_data);
+    ALOGD("%s: Fluence_Type(%d) max_mic_count(%d) mic_type(0x%x) fluence_in_voice_call(%d)"
+          " fluence_in_voice_rec(%d) fluence_in_spkr_mode(%d) ",
+          __func__, my_data->fluence_type, my_data->max_mic_count, my_data->source_mic_type,
+          my_data->fluence_in_voice_call, my_data->fluence_in_voice_rec,
+          my_data->fluence_in_spkr_mode);
+
     /* init usb */
     audio_extn_usb_init(adev);
     /* update sound cards appropriately */
@@ -2716,8 +2752,8 @@
     snd_device_t snd_device = SND_DEVICE_NONE;
     int channel_count = popcount(channel_mask);
 
-    ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
-          __func__, out_device, in_device);
+    ALOGV("%s: enter: out_device(%#x) in_device(%#x) channel_count (%d) channel_mask (0x%x)",
+          __func__, out_device, in_device, channel_count, channel_mask);
     if (my_data->external_mic) {
         if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) ||
             voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev))) {
@@ -2762,7 +2798,8 @@
                 out_device & AUDIO_DEVICE_OUT_LINE) {
             if (out_device & AUDIO_DEVICE_OUT_EARPIECE &&
                 audio_extn_should_use_handset_anc(channel_count)) {
-                if(my_data->fluence_type != FLUENCE_NONE) {
+                if ((my_data->fluence_type != FLUENCE_NONE) &&
+                    (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
                     snd_device = SND_DEVICE_IN_VOICE_FLUENCE_DMIC_AANC;
                     adev->acdb_settings |= DMIC_FLAG;
                 } else {
@@ -2797,7 +2834,8 @@
             if (my_data->fluence_type != FLUENCE_NONE &&
                 my_data->fluence_in_voice_call &&
                 my_data->fluence_in_spkr_mode) {
-                if(my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                if((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
+                   (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
                     snd_device = SND_DEVICE_IN_VOICE_SPEAKER_QMIC;
                 } else {
                     if (my_data->fluence_mode == FLUENCE_BROADSIDE)
@@ -2819,20 +2857,34 @@
         }
     } else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) {
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-            if (channel_count == 2) {
-                snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_STEREO;
-            } else if (my_data->fluence_type != FLUENCE_NONE &&
-                     my_data->fluence_in_voice_rec) {
-                if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
-                    snd_device = SND_DEVICE_IN_HANDSET_QMIC;
-                } else {
+            if (my_data->fluence_in_voice_rec && channel_count == 1) {
+                if ((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
+                    (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
+                     snd_device = SND_DEVICE_IN_HANDSET_QMIC;
+                } else if ((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
+                    (my_data->source_mic_type & SOURCE_THREE_MIC)) {
+                    snd_device = SND_DEVICE_IN_HANDSET_TMIC;
+                } else if ((my_data->fluence_type & FLUENCE_DUAL_MIC) &&
+                    (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
                     snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE;
                 }
-                platform_set_echo_reference(adev->platform, true, out_device);
-            } else if (adev->active_input->enable_ns) {
-                snd_device = SND_DEVICE_IN_VOICE_REC_MIC_NS;
-            } else {
-                snd_device = SND_DEVICE_IN_VOICE_REC_MIC;
+                platform_set_echo_reference(adev, true, out_device);
+            } else if (((channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) ||
+                       (channel_mask == AUDIO_CHANNEL_IN_STEREO)) &&
+                       (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
+                snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_STEREO;
+            } else if (((int)channel_mask == AUDIO_CHANNEL_INDEX_MASK_3) &&
+                       (my_data->source_mic_type & SOURCE_THREE_MIC)) {
+                snd_device = SND_DEVICE_IN_THREE_MIC;
+            } else if (((int)channel_mask == AUDIO_CHANNEL_INDEX_MASK_4) &&
+                       (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
+                snd_device = SND_DEVICE_IN_QUAD_MIC;
+            }
+            if (snd_device == SND_DEVICE_NONE) {
+                if (adev->active_input->enable_ns)
+                    snd_device = SND_DEVICE_IN_VOICE_REC_MIC_NS;
+                else
+                    snd_device = SND_DEVICE_IN_VOICE_REC_MIC;
             }
         }
     } else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
@@ -2843,9 +2895,11 @@
                     adev->active_input->enable_ns) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
                     if (my_data->fluence_in_spkr_mode) {
-                        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                        if ((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
+                            (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
                             snd_device = SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS;
-                        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                        } else if ((my_data->fluence_type & FLUENCE_DUAL_MIC) &&
+                                   (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
                             if (my_data->fluence_mode == FLUENCE_BROADSIDE)
                                 snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE;
                             else
@@ -2854,9 +2908,10 @@
                     } else
                         snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
                 } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                    if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                    if ((my_data->fluence_type & FLUENCE_DUAL_MIC) &&
+                        (my_data->source_mic_type & SOURCE_DUAL_MIC))
                         snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC_NS;
-                    } else
+                    else
                         snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC_NS;
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
@@ -2865,9 +2920,11 @@
             } else if (adev->active_input->enable_aec) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
                     if (my_data->fluence_in_spkr_mode) {
-                        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                        if ((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
+                            (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
                             snd_device = SND_DEVICE_IN_SPEAKER_QMIC_AEC;
-                        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                        } else if ((my_data->fluence_type & FLUENCE_DUAL_MIC) &&
+                                   (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
                             if (my_data->fluence_mode == FLUENCE_BROADSIDE)
                                 snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE;
                             else
@@ -2876,9 +2933,10 @@
                     } else
                         snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC;
                 } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                    if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                    if ((my_data->fluence_type & FLUENCE_DUAL_MIC) &&
+                        (my_data->source_mic_type & SOURCE_DUAL_MIC))
                         snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC;
-                    } else
+                    else
                         snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC;
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
@@ -2887,9 +2945,11 @@
             } else if (adev->active_input->enable_ns) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
                     if (my_data->fluence_in_spkr_mode) {
-                        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                        if ((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
+                            (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
                             snd_device = SND_DEVICE_IN_SPEAKER_QMIC_NS;
-                        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                        } else if ((my_data->fluence_type & FLUENCE_DUAL_MIC) &&
+                                   (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
                             if (my_data->fluence_mode == FLUENCE_BROADSIDE)
                                 snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE;
                             else
@@ -2898,9 +2958,10 @@
                     } else
                         snd_device = SND_DEVICE_IN_SPEAKER_MIC_NS;
                 } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                    if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                    if ((my_data->fluence_type & FLUENCE_DUAL_MIC) &&
+                        (my_data->source_mic_type & SOURCE_DUAL_MIC))
                         snd_device = SND_DEVICE_IN_HANDSET_DMIC_NS;
-                    } else
+                    else
                         snd_device = SND_DEVICE_IN_HANDSET_MIC_NS;
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
@@ -2913,10 +2974,15 @@
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC &&
                 channel_count == 1 ) {
             if(my_data->fluence_in_audio_rec) {
-                if(my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                if ((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
+                    (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
                     snd_device = SND_DEVICE_IN_HANDSET_QMIC;
                     platform_set_echo_reference(adev, true, out_device);
-                } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                } else if ((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
+                    (my_data->source_mic_type & SOURCE_THREE_MIC)) {
+                    snd_device = SND_DEVICE_IN_HANDSET_TMIC;
+                } else if ((my_data->fluence_type & FLUENCE_DUAL_MIC) &&
+                    (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
                     snd_device = SND_DEVICE_IN_HANDSET_DMIC;
                     platform_set_echo_reference(adev, true, out_device);
                 }
@@ -2941,8 +3007,8 @@
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
             if (adev->active_input && (audio_extn_ssr_get_stream() == adev->active_input))
                 snd_device = SND_DEVICE_IN_QUAD_MIC;
-            else if (my_data->fluence_type & (FLUENCE_DUAL_MIC | FLUENCE_QUAD_MIC) &&
-                    channel_count == 2)
+            else if ((my_data->fluence_type & (FLUENCE_DUAL_MIC | FLUENCE_QUAD_MIC)) &&
+                    (channel_count == 2) && (my_data->source_mic_type & SOURCE_DUAL_MIC))
                 snd_device = SND_DEVICE_IN_HANDSET_STEREO_DMIC;
             else
                 snd_device = SND_DEVICE_IN_HANDSET_MIC;
@@ -2980,10 +3046,18 @@
         } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
             snd_device = SND_DEVICE_IN_HEADSET_MIC;
         } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
-            if (channel_count == 2)
+            if ((my_data->source_mic_type & SOURCE_DUAL_MIC) &&
+                (channel_count == 2)) {
                 snd_device = SND_DEVICE_IN_SPEAKER_STEREO_DMIC;
-            else
+            } else if ((my_data->source_mic_type & SOURCE_MONO_MIC) &&
+                       (channel_count == 1)) {
+                 snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+            } else {
+                ALOGE("%s: something wrong: source type (%d) channel_count (%d) .."
+                      " no combination found .. setting to mono", __func__,
+                      my_data->source_mic_type, channel_count);
                 snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+            }
         } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
                         out_device & AUDIO_DEVICE_OUT_LINE) {
             snd_device = SND_DEVICE_IN_HANDSET_MIC;
@@ -3426,6 +3500,14 @@
         update_external_device_status(my_data, event_name, status);
     }
 
+    err = str_parms_get_str(parms, PLATFORM_MAX_MIC_COUNT,
+                            value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, PLATFORM_MAX_MIC_COUNT);
+        my_data->max_mic_count = atoi(value);
+        ALOGV("%s: max_mic_count %d", __func__, my_data->max_mic_count);
+    }
+
     /* handle audio calibration parameters */
     set_audiocal(platform, parms, value, len);
     native_audio_set_params(platform, parms, value, len);
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 7fe7271..3cd4361 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -32,6 +32,13 @@
     FLUENCE_BROADSIDE = 0x2,
 };
 
+enum {
+    SOURCE_MONO_MIC  = 0x1,            /* Target contains 1 mic */
+    SOURCE_DUAL_MIC  = 0x2,            /* Target contains 2 mics */
+    SOURCE_THREE_MIC = 0x4,            /* Target contains 3 mics */
+    SOURCE_QUAD_MIC  = 0x8,            /* Target contains 4 mics */
+};
+
 /*
  * Below are the devices for which is back end is same, SLIMBUS_0_RX.
  * All these devices are handled by the internal HW codec. We can
@@ -171,6 +178,7 @@
     SND_DEVICE_IN_SPEAKER_QMIC_NS,
     SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS,
     SND_DEVICE_IN_THREE_MIC,
+    SND_DEVICE_IN_HANDSET_TMIC,
     SND_DEVICE_IN_END,
 
     SND_DEVICE_MAX = SND_DEVICE_IN_END,
@@ -371,6 +379,9 @@
 #define FM_RX_VOLUME "Internal FM RX Volume"
 #endif
 
+#define PLATFORM_MAX_MIC_COUNT "input_mic_max_count"
+#define PLATFORM_DEFAULT_MIC_COUNT 2
+
 #define LIB_CSD_CLIENT "libcsd-client.so"
 /* CSD-CLIENT related functions */
 typedef int (*init_t)(bool);