alsa_sound: Add support for multichannel hdmi

- Multichannel audio support for HDMI for AAC
format with 5.1 channels max.

Bug: 7156174
Change-Id: I42e92fa2b14d35a5882cc6d84c6651a6a4d5092a
Signed-off-by: Iliyan Malchev <malchev@google.com>
diff --git a/alsa_sound/ALSAStreamOps.cpp b/alsa_sound/ALSAStreamOps.cpp
index f38b35e..aafc736 100644
--- a/alsa_sound/ALSAStreamOps.cpp
+++ b/alsa_sound/ALSAStreamOps.cpp
@@ -104,6 +104,11 @@
         *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);
+                    break;
+                    // Do not fall through
                 case 4:
                     *channels |= AudioSystem::CHANNEL_OUT_BACK_LEFT;
                     *channels |= AudioSystem::CHANNEL_OUT_BACK_RIGHT;
@@ -348,6 +353,11 @@
 
     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;
diff --git a/alsa_sound/AudioHardwareALSA.cpp b/alsa_sound/AudioHardwareALSA.cpp
index 2a08fac..a53f161 100644
--- a/alsa_sound/AudioHardwareALSA.cpp
+++ b/alsa_sound/AudioHardwareALSA.cpp
@@ -42,6 +42,7 @@
 #ifdef QCOM_USBAUDIO_ENABLED
 #include "AudioUsbALSA.h"
 #endif
+#include "AudioUtil.h"
 
 extern "C"
 {
@@ -813,7 +814,76 @@
       return out;
     } else
 #endif
-    {
+    if ((flag & AUDIO_OUTPUT_FLAG_DIRECT) &&
+        (devices == AudioSystem::DEVICE_OUT_AUX_DIGITAL)) {
+        ALOGD("Multi channel PCM");
+        alsa_handle_t alsa_handle;
+        EDID_AUDIO_INFO info = { 0 };
+
+        alsa_handle.module = mALSADevice;
+        alsa_handle.devices = devices;
+        alsa_handle.handle = 0;
+        alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
+
+        if (!AudioUtil::getHDMIAudioSinkCaps(&info)) {
+            ALOGE("openOutputStream: Failed to get HDMI sink capabilities");
+            return NULL;
+        }
+        if (0 == *channels) {
+            alsa_handle.channels = info.AudioBlocksArray[info.nAudioBlocks-1].nChannels;
+            if (alsa_handle.channels > 6) {
+                alsa_handle.channels = 6;
+            }
+            *channels = audio_channel_out_mask_from_count(alsa_handle.channels);
+        } else {
+            alsa_handle.channels = AudioSystem::popCount(*channels);
+        }
+        if (6 == alsa_handle.channels) {
+            alsa_handle.bufferSize = DEFAULT_MULTI_CHANNEL_BUF_SIZE;
+        } else {
+            alsa_handle.bufferSize = DEFAULT_BUFFER_SIZE;
+        }
+        if (0 == *sampleRate) {
+            alsa_handle.sampleRate = info.AudioBlocksArray[info.nAudioBlocks-1].nSamplingFreq;
+            *sampleRate = alsa_handle.sampleRate;
+        } else {
+            alsa_handle.sampleRate = *sampleRate;
+        }
+        alsa_handle.latency = PLAYBACK_LATENCY;
+        alsa_handle.rxHandle = 0;
+        alsa_handle.ucMgr = mUcMgr;
+        ALOGD("alsa_handle.channels %d alsa_handle.sampleRate %d",alsa_handle.channels,alsa_handle.sampleRate);
+
+        char *use_case;
+        snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
+        if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
+            strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI2 , sizeof(alsa_handle.useCase));
+        } else {
+            strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_MUSIC2, sizeof(alsa_handle.useCase));
+        }
+        free(use_case);
+        mDeviceList.push_back(alsa_handle);
+        ALSAHandleList::iterator it = mDeviceList.end();
+        it--;
+        ALOGD("it->useCase %s", it->useCase);
+        mALSADevice->route(&(*it), devices, mode());
+        if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI2)) {
+            snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI2 );
+        } else {
+            snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_MUSIC2);
+        }
+        ALOGD("channels: %d", AudioSystem::popCount(*channels));
+        err = mALSADevice->open(&(*it));
+
+        if (err) {
+            ALOGE("Device open failed err:%d",err);
+        } else {
+            out = new AudioStreamOutALSA(this, &(*it));
+            err = out->set(format, channels, sampleRate, devices);
+        }
+        if (status) *status = err;
+        return out;
+    } else {
 
       alsa_handle_t alsa_handle;
       unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
diff --git a/alsa_sound/AudioHardwareALSA.h b/alsa_sound/AudioHardwareALSA.h
index 957bf75..932b18f 100644
--- a/alsa_sound/AudioHardwareALSA.h
+++ b/alsa_sound/AudioHardwareALSA.h
@@ -63,6 +63,8 @@
 #define RECORD_LATENCY        96000
 #define VOICE_LATENCY         85333
 #define DEFAULT_BUFFER_SIZE   4096
+//4032 = 336(kernel buffer size) * 2(bytes pcm_16) * 6(number of channels)
+#define DEFAULT_MULTI_CHANNEL_BUF_SIZE    4032
 #define DEFAULT_VOICE_BUFFER_SIZE   2048
 #define PLAYBACK_LOW_LATENCY_BUFFER_SIZE   1024
 #define PLAYBACK_LOW_LATENCY  22000
diff --git a/alsa_sound/AudioStreamOutALSA.cpp b/alsa_sound/AudioStreamOutALSA.cpp
index 49c0581..64492ba 100644
--- a/alsa_sound/AudioStreamOutALSA.cpp
+++ b/alsa_sound/AudioStreamOutALSA.cpp
@@ -125,22 +125,35 @@
          (strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
         mParent->mLock.lock();
 
+        ALOGD("mHandle->useCase: %s", mHandle->useCase);
         snd_use_case_get(mHandle->ucMgr, "_verb", (const char **)&use_case);
         if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
-            if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)){
-                 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL,sizeof(mHandle->useCase));
-            } else if (mHandle->isDeepbufferOutput){
-                       strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI, sizeof(mHandle->useCase));
-            } else {
-                       strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC, sizeof(mHandle->useCase));
+            if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)){
+                strlcpy(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL,
+                        sizeof(SND_USE_CASE_VERB_IP_VOICECALL));
+            } else if(!strcmp(mHandle->useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) {
+                strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI2,
+                        sizeof(SND_USE_CASE_MOD_PLAY_MUSIC2));
+            } else if (!strcmp(mHandle->useCase,SND_USE_CASE_MOD_PLAY_MUSIC)){
+                strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI,
+                        sizeof(SND_USE_CASE_MOD_PLAY_MUSIC));
+            } else if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) {
+                strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC,
+                        sizeof(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC));
             }
         } else {
-            if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)) {
-                strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP,sizeof(mHandle->useCase));
-            } else if (mHandle->isDeepbufferOutput){
-                       strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC, sizeof(mHandle->useCase));
-            } else {
-                       strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC, sizeof(mHandle->useCase));
+            if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)){
+                strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP,
+                        sizeof(SND_USE_CASE_MOD_PLAY_VOIP));
+            } else if(!strcmp(mHandle->useCase,SND_USE_CASE_VERB_HIFI2)) {
+                strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
+                        sizeof(SND_USE_CASE_MOD_PLAY_MUSIC2));
+            } else if (!strcmp(mHandle->useCase,SND_USE_CASE_VERB_HIFI)){
+                strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
+                        sizeof(SND_USE_CASE_MOD_PLAY_MUSIC));
+            } else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) {
+                strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC,
+                        sizeof(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC));
             }
         }
         free(use_case);
@@ -170,6 +183,7 @@
             mHandle->module->route(mHandle, mDevices , mParent->mode());
         }
         if (!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI) ||
+            !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI2) ||
             !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC) ||
             !strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
             snd_use_case_set(mHandle->ucMgr, "_verb", mHandle->useCase);
diff --git a/alsa_sound/alsa_default.cpp b/alsa_sound/alsa_default.cpp
index 3fddd28..18a28d2 100644
--- a/alsa_sound/alsa_default.cpp
+++ b/alsa_sound/alsa_default.cpp
@@ -98,7 +98,6 @@
 static uint32_t mDevSettingsFlag = TTY_OFF;
 #endif
 static int btsco_samplerate = 8000;
-static bool pflag = false;
 static ALSAUseCaseList mUseCaseList;
 static void *csd_handle;
 
@@ -374,8 +373,8 @@
           params->start_threshold = periodSize/2;
           params->stop_threshold = INT_MAX;
      } else {
-         params->avail_min = periodSize/2;
-         params->start_threshold = channels * (periodSize/4);
+         params->avail_min = periodSize/(channels * 2);
+         params->start_threshold = periodSize/(channels * 2);
          params->stop_threshold = INT_MAX;
      }
     params->silence_threshold = 0;
@@ -581,7 +580,7 @@
         rx_dev_id = snd_use_case_get(handle->ucMgr, ident, NULL);
 
         if (((rx_dev_id == DEVICE_SPEAKER_MONO_RX_ACDB_ID ) || (rx_dev_id == DEVICE_SPEAKER_STEREO_RX_ACDB_ID ))
-		 && tx_dev_id == DEVICE_HANDSET_TX_ACDB_ID) {
+         && tx_dev_id == DEVICE_HANDSET_TX_ACDB_ID) {
             tx_dev_id = DEVICE_SPEAKER_TX_ACDB_ID;
         }
 
@@ -600,20 +599,6 @@
     }
 
     if (rxDevice != NULL) {
-        if (pflag && (((!strncmp(rxDevice, DEVICE_SPEAKER_HEADSET, strlen(DEVICE_SPEAKER_HEADSET))) &&
-            ((!strncmp(curRxUCMDevice, DEVICE_HEADPHONES, strlen(DEVICE_HEADPHONES))) ||
-            (!strncmp(curRxUCMDevice, DEVICE_HEADSET, strlen(DEVICE_HEADSET))))) ||
-            (((!strncmp(curRxUCMDevice, DEVICE_SPEAKER_HEADSET, strlen(DEVICE_SPEAKER_HEADSET))) &&
-            ((!strncmp(rxDevice, DEVICE_HEADPHONES, strlen(DEVICE_HEADPHONES))) ||
-            (!strncmp(rxDevice, DEVICE_HEADSET, strlen(DEVICE_HEADSET))))))) &&
-            ((!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI, strlen(SND_USE_CASE_VERB_HIFI))) ||
-            (!strncmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC, strlen(SND_USE_CASE_MOD_PLAY_MUSIC))))) {
-            s_open(handle);
-            pflag = false;
-        }
-    }
-
-    if (rxDevice != NULL) {
         free(rxDevice);
         rxDevice = NULL;
     }
@@ -672,8 +657,10 @@
         flags |= PCM_MMAP;
         flags |= DEBUG_ON;
     } else if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI2)) ||
         (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) ||
         (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
         (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC))) {
         ALOGV("Music case");
         flags = PCM_OUT;
@@ -683,18 +670,20 @@
     if (handle->channels == 1) {
         flags |= PCM_MONO;
     }
-#ifdef QCOM_SSR_ENABLED
     else if (handle->channels == 4 ) {
         flags |= PCM_QUAD;
     } else if (handle->channels == 6 ) {
+#ifdef QCOM_SSR_ENABLED
         if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
             || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
             flags |= PCM_QUAD;
         } else {
             flags |= PCM_5POINT1;
         }
-    }
+#else
+        flags |= PCM_5POINT1;
 #endif
+    }
     else {
         flags |= PCM_STEREO;
     }
@@ -1198,6 +1187,8 @@
     ALOGD("use case is %s\n", useCase);
     if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI,
             MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
+            MAX_LEN(useCase, SND_USE_CASE_VERB_HIFI2)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC,
             MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
@@ -1210,6 +1201,8 @@
             MAX_LEN(useCase,SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
             MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
+            MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC,
             MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,