audio: added support for dual mic capture

Added support for simultaneous capture of front and back mic.

Added device definitions for dual mic config for voice recognition use
case: no pre processing enabled.

stream->channels() reports actual channel mask instead of recontructing
it from channel count.

TODO: check if ACDB settings copied from single mic voice recognition
are correct.

Change-Id: I41282d0af5deb256ef68ec17ee34f5aae7807a6f
diff --git a/alsa_sound/ALSAStreamOps.cpp b/alsa_sound/ALSAStreamOps.cpp
index 4e534fd..c7c0ca1 100644
--- a/alsa_sound/ALSAStreamOps.cpp
+++ b/alsa_sound/ALSAStreamOps.cpp
@@ -101,42 +101,32 @@
         if (mHandle->channels != popCount(*channels))
             return BAD_VALUE;
     } else if (channels) {
-        *channels = 0;
         if (mHandle->devices & AudioSystem::DEVICE_OUT_ALL) {
-            switch(mHandle->channels) {
-                case 6:
-                case 5:
-                    *channels |= audio_channel_out_mask_from_count(mHandle->channels);
+            switch(*channels) {
+                case AUDIO_CHANNEL_OUT_5POINT1: // 5.0
+                case (AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER): // 5.1
+                case AUDIO_CHANNEL_OUT_QUAD:
+                case AUDIO_CHANNEL_OUT_STEREO:
+                case AUDIO_CHANNEL_OUT_MONO:
                     break;
-                    // Do not fall through
-                case 4:
-                    *channels |= AudioSystem::CHANNEL_OUT_BACK_LEFT;
-                    *channels |= AudioSystem::CHANNEL_OUT_BACK_RIGHT;
-                    // Fall through...
                 default:
-                case 2:
-                    *channels |= AudioSystem::CHANNEL_OUT_FRONT_RIGHT;
-                    // Fall through...
-                case 1:
-                    *channels |= AudioSystem::CHANNEL_OUT_FRONT_LEFT;
-                    break;
+                    *channels = AUDIO_CHANNEL_OUT_STEREO;
+                    return BAD_VALUE;
             }
         } else {
-            switch(mHandle->channels) {
+            switch(*channels) {
 #ifdef QCOM_SSR_ENABLED
                 // For 5.1 recording
-                case 6 :
-                    *channels |= AudioSystem::CHANNEL_IN_5POINT1;
-                    break;
+                case AudioSystem::CHANNEL_IN_5POINT1:
 #endif
                     // Do not fall through...
-                default:
-                case 2:
-                    *channels |= AudioSystem::CHANNEL_IN_RIGHT;
-                    // Fall through...
-                case 1:
-                    *channels |= AudioSystem::CHANNEL_IN_LEFT;
+                case AUDIO_CHANNEL_IN_MONO:
+                case AUDIO_CHANNEL_IN_STEREO:
+                case AUDIO_CHANNEL_IN_FRONT_BACK:
                     break;
+                default:
+                    *channels = AUDIO_CHANNEL_IN_MONO;
+                    return BAD_VALUE;
             }
         }
     }
@@ -352,47 +342,7 @@
 
 uint32_t ALSAStreamOps::channels() const
 {
-    unsigned int count = mHandle->channels;
-    uint32_t channels = 0;
-
-    if (mDevices & AudioSystem::DEVICE_OUT_ALL)
-        switch(count) {
-            case 6:
-            case 5:
-                channels |=audio_channel_out_mask_from_count(count);
-                break;
-                // Do not fall through
-            case 4:
-                channels |= AudioSystem::CHANNEL_OUT_BACK_LEFT;
-                channels |= AudioSystem::CHANNEL_OUT_BACK_RIGHT;
-                // Fall through...
-            default:
-            case 2:
-                channels |= AudioSystem::CHANNEL_OUT_FRONT_RIGHT;
-                // Fall through...
-            case 1:
-                channels |= AudioSystem::CHANNEL_OUT_FRONT_LEFT;
-                break;
-        }
-    else
-        switch(count) {
-#ifdef QCOM_SSR_ENABLED
-            // For 5.1 recording
-            case 6 :
-                channels |= AudioSystem::CHANNEL_IN_5POINT1;
-                break;
-                // Do not fall through...
-#endif
-            default:
-            case 2:
-                channels |= AudioSystem::CHANNEL_IN_RIGHT;
-                // Fall through...
-            case 1:
-                channels |= AudioSystem::CHANNEL_IN_LEFT;
-                break;
-        }
-
-    return channels;
+    return mHandle->channelMask;
 }
 
 void ALSAStreamOps::close()
diff --git a/alsa_sound/AudioHardwareALSA.cpp b/alsa_sound/AudioHardwareALSA.cpp
index 4050777..508418c 100644
--- a/alsa_sound/AudioHardwareALSA.cpp
+++ b/alsa_sound/AudioHardwareALSA.cpp
@@ -779,6 +779,7 @@
           else
               alsa_handle.format = *format;
           alsa_handle.channels = VOIP_DEFAULT_CHANNEL_MODE;
+          alsa_handle.channelMask = AUDIO_CHANNEL_IN_MONO;
           alsa_handle.sampleRate = *sampleRate;
           alsa_handle.latency = VOIP_PLAYBACK_LATENCY;
           alsa_handle.rxHandle = 0;
@@ -857,6 +858,8 @@
         } else {
             alsa_handle.channels = AudioSystem::popCount(*channels);
         }
+        alsa_handle.channelMask = *channels;
+
         if (6 == alsa_handle.channels) {
             alsa_handle.bufferSize = DEFAULT_MULTI_CHANNEL_BUF_SIZE;
         } else {
@@ -916,6 +919,7 @@
       alsa_handle.handle = 0;
       alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
       alsa_handle.channels = DEFAULT_CHANNEL_MODE;
+      alsa_handle.channelMask = AUDIO_CHANNEL_OUT_STEREO;
       alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
       alsa_handle.latency = PLAYBACK_LATENCY;
       alsa_handle.rxHandle = 0;
@@ -1014,6 +1018,7 @@
     alsa_handle.handle = 0;
     alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
     alsa_handle.channels = DEFAULT_CHANNEL_MODE;
+    alsa_handle.channelMask = AUDIO_CHANNEL_OUT_STEREO;
     alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
     alsa_handle.latency = VOICE_LATENCY;
     alsa_handle.rxHandle = 0;
@@ -1142,6 +1147,7 @@
           else
               alsa_handle.format = *format;
            alsa_handle.channels = VOIP_DEFAULT_CHANNEL_MODE;
+           alsa_handle.channelMask = AUDIO_CHANNEL_IN_MONO;
            alsa_handle.sampleRate = *sampleRate;
            alsa_handle.latency = VOIP_RECORD_LATENCY;
            alsa_handle.rxHandle = 0;
@@ -1209,6 +1215,7 @@
         alsa_handle.handle = 0;
         alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
         alsa_handle.channels = VOICE_CHANNEL_MODE;
+        alsa_handle.channelMask = AUDIO_CHANNEL_IN_MONO;
         alsa_handle.sampleRate = android::AudioRecord::DEFAULT_SAMPLE_RATE;
         alsa_handle.latency = RECORD_LATENCY;
         alsa_handle.rxHandle = 0;
@@ -1307,8 +1314,10 @@
 #ifdef QCOM_SSR_ENABLED
                        | AudioSystem::CHANNEL_IN_5POINT1
 #endif
-                       ));
-            ALOGV("updated channel info: channels=%d", it->channels);
+                       | AUDIO_CHANNEL_IN_FRONT_BACK));
+            it->channelMask = *channels;
+            ALOGV("updated channel info: channels=%d channelMask %08x",
+                  it->channels, it->channelMask);
         }
         if (devices == AudioSystem::DEVICE_IN_VOICE_CALL){
            /* Add current devices info to devices to do route */
@@ -1336,7 +1345,6 @@
                 mALSADevice->route(&(*it), devices, mode());
             }
         }
-
         if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC) ||
            !strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC) ||
 #ifdef QCOM_FM_ENABLED
@@ -1444,6 +1452,7 @@
         alsa_handle.handle = 0;
         alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
         alsa_handle.channels = DEFAULT_CHANNEL_MODE;
+        alsa_handle.channelMask = AUDIO_CHANNEL_OUT_STEREO;
         alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
         alsa_handle.latency = VOICE_LATENCY;
         alsa_handle.rxHandle = 0;
@@ -1539,6 +1548,7 @@
     alsa_handle.handle = 0;
     alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
     alsa_handle.channels = VOICE_CHANNEL_MODE;
+    alsa_handle.channelMask = AUDIO_CHANNEL_IN_MONO;
     alsa_handle.sampleRate = VOICE_SAMPLING_RATE;
     alsa_handle.latency = VOICE_LATENCY;
     alsa_handle.rxHandle = 0;
diff --git a/alsa_sound/AudioHardwareALSA.h b/alsa_sound/AudioHardwareALSA.h
index 932b18f..4ef878b 100644
--- a/alsa_sound/AudioHardwareALSA.h
+++ b/alsa_sound/AudioHardwareALSA.h
@@ -170,6 +170,7 @@
     struct pcm *        handle;
     snd_pcm_format_t    format;
     uint32_t            channels;
+    audio_channel_mask_t channelMask;
     uint32_t            sampleRate;
     unsigned int        latency;         // Delay in usec
     unsigned int        bufferSize;      // Size of sample buffer
diff --git a/alsa_sound/AudioStreamInALSA.cpp b/alsa_sound/AudioStreamInALSA.cpp
index 3b66c24..4771d42 100644
--- a/alsa_sound/AudioStreamInALSA.cpp
+++ b/alsa_sound/AudioStreamInALSA.cpp
@@ -239,6 +239,9 @@
                     }
             }
         }
+        if (mHandle->channelMask == AUDIO_CHANNEL_IN_FRONT_BACK) {
+            mHandle->module->setFlags(mParent->mDevSettingsFlag | DMIC_FLAG);
+        }
         free(use_case);
         if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
             (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
@@ -596,6 +599,10 @@
     mParent->closeUsbRecordingIfNothingActive();
 #endif
 
+    if (mHandle->channelMask == AUDIO_CHANNEL_IN_FRONT_BACK) {
+        mHandle->module->setFlags(mParent->mDevSettingsFlag);
+    }
+
     return NO_ERROR;
 }
 
diff --git a/alsa_sound/alsa_default.cpp b/alsa_sound/alsa_default.cpp
index 55fe32d..2f043bb 100644
--- a/alsa_sound/alsa_default.cpp
+++ b/alsa_sound/alsa_default.cpp
@@ -1423,10 +1423,11 @@
     } else {
         if (!(mDevSettingsFlag & TTY_OFF) &&
             (callMode == AudioSystem::MODE_IN_CALL) &&
-            ((devices & AudioSystem::DEVICE_IN_WIRED_HEADSET))) {
+            ((devices & AudioSystem::DEVICE_IN_WIRED_HEADSET)
 #ifdef QCOM_ANC_HEADSET_ENABLED
-            ||(devices & AudioSystem::DEVICE_IN_ANC_HEADSET))) {
+              || (devices & AudioSystem::DEVICE_IN_ANC_HEADSET)
 #endif
+            )) {
              if (mDevSettingsFlag & TTY_HCO) {
                  return strdup(SND_USE_CASE_DEV_TTY_HEADSET_TX);
              } else if (mDevSettingsFlag & TTY_FULL) {
@@ -1443,8 +1444,8 @@
                 return strdup(SND_USE_CASE_DEV_HANDSET); /* HANDSET TX */
             } else {
                 if (mDevSettingsFlag & DMIC_FLAG) {
-#ifdef USES_FLUENCE_INCALL
                     if(callMode == AudioSystem::MODE_IN_CALL) {
+#ifdef USES_FLUENCE_INCALL
                         if (fluence_mode == FLUENCE_MODE_ENDFIRE) {
                             if(is_tmus)
                                 return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_TMUS); /* DUALMIC EF TX */
@@ -1455,26 +1456,42 @@
                         } else {
                             return strdup(SND_USE_CASE_DEV_HANDSET); /* BUILTIN-MIC TX */
                         }
+#endif
                     }
-#else
                     if (((rxDevice != NULL) &&
                         !strncmp(rxDevice, SND_USE_CASE_DEV_SPEAKER,
                         (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) ||
                         !strncmp(curRxUCMDevice, SND_USE_CASE_DEV_SPEAKER,
                         (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) {
                         if (fluence_mode == FLUENCE_MODE_ENDFIRE) {
-                            return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */
+                            if (input_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
+// TODO: check if different ACDB settings are needed when speaker is enabled
+                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_VREC);
+                            } else {
+                                return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE);
+                            }
                         } else if (fluence_mode == FLUENCE_MODE_BROADSIDE) {
-                            return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */
+                            if (input_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
+                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE_VREC);
+                            } else {
+                                return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_BROADSIDE);
+                            }
                         }
                     } else {
                         if (fluence_mode == FLUENCE_MODE_ENDFIRE) {
-                            return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */
+                            if (input_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
+                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_VREC);
+                            } else {
+                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE);
+                            }
                         } else if (fluence_mode == FLUENCE_MODE_BROADSIDE) {
-                            return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */
+                            if (input_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
+                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE_VREC);
+                            } else {
+                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE);
+                            }
                         }
                     }
-#endif
                 } else if (mDevSettingsFlag & QMIC_FLAG){
                     return strdup(SND_USE_CASE_DEV_QUAD_MIC);
                 }
diff --git a/libalsa-intf/msm8960_use_cases.h b/libalsa-intf/msm8960_use_cases.h
index 103b508..4c37cd0 100644
--- a/libalsa-intf/msm8960_use_cases.h
+++ b/libalsa-intf/msm8960_use_cases.h
@@ -232,8 +232,10 @@
 #define SND_USE_CASE_DEV_TTY_HANDSET_TX  "TTY Handset Tx"
 #define SND_USE_CASE_DEV_TTY_HANDSET_ANALOG_TX  "TTY Handset Analog Tx"
 #define SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE "DMIC Broadside"
+#define SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE_VREC "DMIC Broadside Voice Rec"
 #define SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE "DMIC Endfire"
 #define SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_TMUS "DMIC Endfire TMUS"
+#define SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_VREC "DMIC Endfire Voice Rec"
 #define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_BROADSIDE "Speaker DMIC Broadside"
 #define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE "Speaker DMIC Endfire"
 #define SND_USE_CASE_DEV_HDMI_TX             "HDMI Tx"