merge in jb-mr1-release history after reset to jb-mr1-dev
diff --git a/alsa_sound/ALSAStreamOps.cpp b/alsa_sound/ALSAStreamOps.cpp
index 1cd75cb..4e534fd 100644
--- a/alsa_sound/ALSAStreamOps.cpp
+++ b/alsa_sound/ALSAStreamOps.cpp
@@ -33,12 +33,16 @@
 #include <cutils/properties.h>
 #include <media/AudioRecord.h>
 #include <hardware_legacy/power.h>
-
+#include "AudioUtil.h"
 #include "AudioHardwareALSA.h"
 
 namespace android_audio_legacy
 {
 
+// unused 'enumVal;' is to catch error at compile time if enumVal ever changes
+// or applied on a non-existent enum
+#define ENUM_TO_STRING(var, enumVal) {var = #enumVal; enumVal;}
+
 // ----------------------------------------------------------------------------
 
 ALSAStreamOps::ALSAStreamOps(AudioHardwareALSA *parent, alsa_handle_t *handle) :
@@ -100,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;
@@ -205,12 +214,16 @@
 
     if (param.getInt(key, device) == NO_ERROR) {
         // Ignore routing if device is 0.
-        ALOGD("setParameters(): keyRouting with device %d", device);
+        ALOGD("setParameters(): keyRouting with device 0x%x", device);
         // reset to speaker when disconnecting HDMI to avoid timeout due to write errors
         if ((device == 0) && (mDevices == AudioSystem::DEVICE_OUT_AUX_DIGITAL)) {
             device = AudioSystem::DEVICE_OUT_SPEAKER;
         }
-        mDevices = device;
+        if (device)
+            mDevices = device;
+        else
+            ALOGV("must not change mDevices to 0");
+
         if(device) {
             mParent->doRouting(device);
         }
@@ -254,6 +267,37 @@
         }
 #endif
     }
+    key = String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS);
+    if (param.get(key, value) == NO_ERROR) {
+        EDID_AUDIO_INFO info = { 0 };
+        bool first = true;
+        value = String8();
+        if (AudioUtil::getHDMIAudioSinkCaps(&info)) {
+            for (int i = 0; i < info.nAudioBlocks && i < MAX_EDID_BLOCKS; i++) {
+                String8 append;
+                switch (info.AudioBlocksArray[i].nChannels) {
+                //Do not handle stereo output in Multi-channel cases
+                //Stereo case is handled in normal playback path
+                case 6:
+                    ENUM_TO_STRING(append, AUDIO_CHANNEL_OUT_5POINT1);
+                    break;
+                case 8:
+                    ENUM_TO_STRING(append, AUDIO_CHANNEL_OUT_7POINT1);
+                    break;
+                default:
+                    ALOGD("Unsupported number of channels %d", info.AudioBlocksArray[i].nChannels);
+                    break;
+                }
+                if (!append.isEmpty()) {
+                    value += (first ? append : String8("|") + append);
+                    first = false;
+                }
+            }
+        } else {
+            ALOGE("Failed to get HDMI sink capabilities");
+        }
+        param.add(key, value);
+    }
     ALOGV("getParameters() %s", param.toString().string());
     return param.toString();
 }
@@ -313,6 +357,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/Android.mk b/alsa_sound/Android.mk
index 5edd233..738b969 100644
--- a/alsa_sound/Android.mk
+++ b/alsa_sound/Android.mk
@@ -28,7 +28,8 @@
   AudioStreamInALSA.cpp 	\
   ALSAStreamOps.cpp		\
   audio_hw_hal.cpp \
-  AudioUsbALSA.cpp
+  AudioUsbALSA.cpp \
+  AudioUtil.cpp
 
 LOCAL_STATIC_LIBRARIES := \
     libmedia_helper \
@@ -127,7 +128,8 @@
 
 LOCAL_SRC_FILES:= \
     alsa_default.cpp \
-    ALSAControl.cpp
+    ALSAControl.cpp \
+    AudioUtil.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
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..d047cd4 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);
@@ -165,11 +178,10 @@
             mHandle->module->route(mHandle, mDevices , mParent->mode());
 #endif
         } else {
-            if (!mDevices)
-               mDevices = mParent->mCurDevice;
             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/AudioUtil.cpp b/alsa_sound/AudioUtil.cpp
new file mode 100644
index 0000000..3549f24
--- /dev/null
+++ b/alsa_sound/AudioUtil.cpp
@@ -0,0 +1,279 @@
+/* AudioUtil.cpp
+ *
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioUtil"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "AudioUtil.h"
+
+int AudioUtil::printFormatFromEDID(unsigned char format) {
+    switch (format) {
+    case LPCM:
+        ALOGV("Format:LPCM");
+        break;
+    case AC3:
+        ALOGV("Format:AC-3");
+        break;
+    case MPEG1:
+        ALOGV("Format:MPEG1 (Layers 1 & 2)");
+        break;
+    case MP3:
+        ALOGV("Format:MP3 (MPEG1 Layer 3)");
+        break;
+    case MPEG2_MULTI_CHANNEL:
+        ALOGV("Format:MPEG2 (multichannel)");
+        break;
+    case AAC:
+        ALOGV("Format:AAC");
+        break;
+    case DTS:
+        ALOGV("Format:DTS");
+        break;
+    case ATRAC:
+        ALOGV("Format:ATRAC");
+        break;
+    case SACD:
+        ALOGV("Format:One-bit audio aka SACD");
+        break;
+    case DOLBY_DIGITAL_PLUS:
+        ALOGV("Format:Dolby Digital +");
+        break;
+    case DTS_HD:
+        ALOGV("Format:DTS-HD");
+        break;
+    case MAT:
+        ALOGV("Format:MAT (MLP)");
+        break;
+    case DST:
+        ALOGV("Format:DST");
+        break;
+    case WMA_PRO:
+        ALOGV("Format:WMA Pro");
+        break;
+    default:
+        ALOGV("Invalid format ID....");
+        break;
+    }
+    return format;
+}
+
+int AudioUtil::getSamplingFrequencyFromEDID(unsigned char byte) {
+    int nFreq = 0;
+
+    if (byte & BIT(6)) {
+        ALOGV("192kHz");
+        nFreq = 192000;
+    } else if (byte & BIT(5)) {
+        ALOGV("176kHz");
+        nFreq = 176000;
+    } else if (byte & BIT(4)) {
+        ALOGV("96kHz");
+        nFreq = 96000;
+    } else if (byte & BIT(3)) {
+        ALOGV("88.2kHz");
+        nFreq = 88200;
+    } else if (byte & BIT(2)) {
+        ALOGV("48kHz");
+        nFreq = 48000;
+    } else if (byte & BIT(1)) {
+        ALOGV("44.1kHz");
+        nFreq = 44100;
+    } else if (byte & BIT(0)) {
+        ALOGV("32kHz");
+        nFreq = 32000;
+    }
+    return nFreq;
+}
+
+int AudioUtil::getBitsPerSampleFromEDID(unsigned char byte,
+    unsigned char format) {
+    int nBitsPerSample = 0;
+    if (format == 1) {
+        if (byte & BIT(2)) {
+            ALOGV("24bit");
+            nBitsPerSample = 24;
+        } else if (byte & BIT(1)) {
+            ALOGV("20bit");
+            nBitsPerSample = 20;
+        } else if (byte & BIT(0)) {
+            ALOGV("16bit");
+            nBitsPerSample = 16;
+        }
+    } else {
+        ALOGV("not lpcm format, return 0");
+        return 0;
+    }
+    return nBitsPerSample;
+}
+
+bool AudioUtil::getHDMIAudioSinkCaps(EDID_AUDIO_INFO* pInfo) {
+    unsigned char channels[16];
+    unsigned char formats[16];
+    unsigned char frequency[16];
+    unsigned char bitrate[16];
+    unsigned char* data = NULL;
+    unsigned char* original_data_ptr = NULL;
+    int count = 0;
+    bool bRet = false;
+    const char* file = "/sys/class/graphics/fb1/audio_data_block";
+    FILE* fpaudiocaps = fopen(file, "rb");
+    if (fpaudiocaps) {
+        ALOGV("opened audio_caps successfully...");
+        fseek(fpaudiocaps, 0, SEEK_END);
+        long size = ftell(fpaudiocaps);
+        ALOGV("audiocaps size is %ld\n",size);
+        data = (unsigned char*) malloc(size);
+        if (data) {
+            fseek(fpaudiocaps, 0, SEEK_SET);
+            original_data_ptr = data;
+            fread(data, 1, size, fpaudiocaps);
+        }
+        fclose(fpaudiocaps);
+    } else {
+        ALOGE("failed to open audio_caps");
+    }
+
+    if (pInfo && data) {
+        int length = 0;
+        memcpy(&count,  data, sizeof(int));
+        data+= sizeof(int);
+        ALOGV("#Audio Block Count is %d",count);
+        memcpy(&length, data, sizeof(int));
+        data += sizeof(int);
+        ALOGV("Total length is %d",length);
+        unsigned int sad[MAX_SHORT_AUDIO_DESC_CNT];
+        int nblockindex = 0;
+        int nCountDesc = 0;
+        while (length >= MIN_AUDIO_DESC_LENGTH && count < MAX_SHORT_AUDIO_DESC_CNT) {
+            sad[nblockindex] = (unsigned int)data[0] + ((unsigned int)data[1] << 8)
+                               + ((unsigned int)data[2] << 16);
+            nblockindex+=1;
+            nCountDesc++;
+            length -= MIN_AUDIO_DESC_LENGTH;
+            data += MIN_AUDIO_DESC_LENGTH;
+        }
+        memset(pInfo, 0, sizeof(EDID_AUDIO_INFO));
+        pInfo->nAudioBlocks = nCountDesc;
+        ALOGV("Total # of audio descriptors %d",nCountDesc);
+        int nIndex = 0;
+        while (nCountDesc--) {
+              channels [nIndex]   = (sad[nIndex] & 0x7) + 1;
+              formats  [nIndex]   = (sad[nIndex] & 0xFF) >> 3;
+              frequency[nIndex]   = (sad[nIndex] >> 8) & 0xFF;
+              bitrate  [nIndex]   = (sad[nIndex] >> 16) & 0xFF;
+              nIndex++;
+        }
+        bRet = true;
+        for (int i = 0; i < pInfo->nAudioBlocks; i++) {
+            ALOGV("AUDIO DESC BLOCK # %d\n",i);
+
+            pInfo->AudioBlocksArray[i].nChannels = channels[i];
+            ALOGV("pInfo->AudioBlocksArray[i].nChannels %d\n", pInfo->AudioBlocksArray[i].nChannels);
+
+            ALOGV("Format Byte %d\n", formats[i]);
+            pInfo->AudioBlocksArray[i].nFormatId = (EDID_AUDIO_FORMAT_ID)printFormatFromEDID(formats[i]);
+            ALOGV("pInfo->AudioBlocksArray[i].nFormatId %d",pInfo->AudioBlocksArray[i].nFormatId);
+
+            ALOGV("Frequency Byte %d\n", frequency[i]);
+            pInfo->AudioBlocksArray[i].nSamplingFreq = getSamplingFrequencyFromEDID(frequency[i]);
+            ALOGV("pInfo->AudioBlocksArray[i].nSamplingFreq %d",pInfo->AudioBlocksArray[i].nSamplingFreq);
+
+            ALOGV("BitsPerSample Byte %d\n", bitrate[i]);
+            pInfo->AudioBlocksArray[i].nBitsPerSample = getBitsPerSampleFromEDID(bitrate[i],formats[i]);
+            ALOGV("pInfo->AudioBlocksArray[i].nBitsPerSample %d",pInfo->AudioBlocksArray[i].nBitsPerSample);
+        }
+            getSpeakerAllocation(pInfo);
+    }
+    if (original_data_ptr)
+        free(original_data_ptr);
+
+    return bRet;
+}
+
+bool AudioUtil::getSpeakerAllocation(EDID_AUDIO_INFO* pInfo) {
+    int count = 0;
+    bool bRet = false;
+    unsigned char* data = NULL;
+    unsigned char* original_data_ptr = NULL;
+    const char* spkrfile = "/sys/class/graphics/fb1/spkr_alloc_data_block";
+    FILE* fpspkrfile = fopen(spkrfile, "rb");
+    if(fpspkrfile) {
+        ALOGV("opened spkr_alloc_data_block successfully...");
+        fseek(fpspkrfile,0,SEEK_END);
+        long size = ftell(fpspkrfile);
+        ALOGV("fpspkrfile size is %ld\n",size);
+        data = (unsigned char*)malloc(size);
+        if(data) {
+            original_data_ptr = data;
+            fseek(fpspkrfile,0,SEEK_SET);
+            fread(data,1,size,fpspkrfile);
+        }
+        fclose(fpspkrfile);
+    } else {
+        ALOGE("failed to open fpspkrfile");
+    }
+
+    if(pInfo && data) {
+        int length = 0;
+        memcpy(&count,  data, sizeof(int));
+        ALOGV("Count is %d",count);
+        data += sizeof(int);
+        memcpy(&length, data, sizeof(int));
+        ALOGV("Total length is %d",length);
+        data+= sizeof(int);
+        ALOGV("Total speaker allocation Block count # %d\n",count);
+        bRet = true;
+        for (int i = 0; i < count; i++) {
+            ALOGV("Speaker Allocation BLOCK # %d\n",i);
+            pInfo->nSpeakerAllocation[0] = data[0];
+            pInfo->nSpeakerAllocation[1] = data[1];
+            pInfo->nSpeakerAllocation[2] = data[2];
+            ALOGV("pInfo->nSpeakerAllocation %x %x %x\n", data[0],data[1],data[2]);
+
+
+            if (pInfo->nSpeakerAllocation[0] & BIT(7)) {
+                 ALOGV("FLW/FRW");
+            } else if (pInfo->nSpeakerAllocation[0] & BIT(6)) {
+                 ALOGV("RLC/RRC");
+            } else if (pInfo->nSpeakerAllocation[0] & BIT(5)) {
+                 ALOGV("FLC/FRC");
+            } else if (pInfo->nSpeakerAllocation[0] & BIT(4)) {
+                ALOGV("RC");
+            } else if (pInfo->nSpeakerAllocation[0] & BIT(3)) {
+                ALOGV("RL/RR");
+            } else if (pInfo->nSpeakerAllocation[0] & BIT(2)) {
+                ALOGV("FC");
+            } else if (pInfo->nSpeakerAllocation[0] & BIT(1)) {
+                ALOGV("LFE");
+            } else if (pInfo->nSpeakerAllocation[0] & BIT(0)) {
+                ALOGV("FL/FR");
+            }
+
+            if (pInfo->nSpeakerAllocation[1] & BIT(2)) {
+                ALOGV("FCH");
+            } else if (pInfo->nSpeakerAllocation[1] & BIT(1)) {
+                ALOGV("TC");
+            } else if (pInfo->nSpeakerAllocation[1] & BIT(0)) {
+                ALOGV("FLH/FRH");
+            }
+        }
+    }
+    if (original_data_ptr)
+        free(original_data_ptr);
+    return bRet;
+}
diff --git a/alsa_sound/AudioUtil.h b/alsa_sound/AudioUtil.h
new file mode 100644
index 0000000..6575315
--- /dev/null
+++ b/alsa_sound/AudioUtil.h
@@ -0,0 +1,71 @@
+/* AudioUtil.h
+ *
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ALSA_SOUND_AUDIO_UTIL_H
+#define ALSA_SOUND_AUDIO_UTIL_H
+
+#define BIT(nr)     (1UL << (nr))
+#define MAX_EDID_BLOCKS 10
+#define MAX_SHORT_AUDIO_DESC_CNT        30
+#define MIN_AUDIO_DESC_LENGTH           3
+#define MIN_SPKR_ALLOCATION_DATA_LENGTH 3
+
+typedef enum EDID_AUDIO_FORMAT_ID {
+    LPCM = 1,
+    AC3,
+    MPEG1,
+    MP3,
+    MPEG2_MULTI_CHANNEL,
+    AAC,
+    DTS,
+    ATRAC,
+    SACD,
+    DOLBY_DIGITAL_PLUS,
+    DTS_HD,
+    MAT,
+    DST,
+    WMA_PRO
+} EDID_AUDIO_FORMAT_ID;
+
+typedef struct EDID_AUDIO_BLOCK_INFO {
+    EDID_AUDIO_FORMAT_ID nFormatId;
+    int nSamplingFreq;
+    int nBitsPerSample;
+    int nChannels;
+} EDID_AUDIO_BLOCK_INFO;
+
+typedef struct EDID_AUDIO_INFO {
+    int nAudioBlocks;
+    unsigned char nSpeakerAllocation[MIN_SPKR_ALLOCATION_DATA_LENGTH];
+    EDID_AUDIO_BLOCK_INFO AudioBlocksArray[MAX_EDID_BLOCKS];
+} EDID_AUDIO_INFO;
+
+class AudioUtil {
+public:
+
+    //Parses EDID audio block when if HDMI is connected to determine audio sink capabilities.
+    static bool getHDMIAudioSinkCaps(EDID_AUDIO_INFO*);
+
+private:
+    static int printFormatFromEDID(unsigned char format);
+    static int getSamplingFrequencyFromEDID(unsigned char byte);
+    static int getBitsPerSampleFromEDID(unsigned char byte,
+        unsigned char format);
+    static bool getSpeakerAllocation(EDID_AUDIO_INFO* pInfo);
+};
+
+#endif /* ALSA_SOUND_AUDIO_UTIL_H */
diff --git a/alsa_sound/alsa_default.cpp b/alsa_sound/alsa_default.cpp
index eaa2343..18a28d2 100644
--- a/alsa_sound/alsa_default.cpp
+++ b/alsa_sound/alsa_default.cpp
@@ -22,6 +22,7 @@
 #include <utils/Log.h>
 #include <cutils/properties.h>
 #include <linux/ioctl.h>
+#include "AudioUtil.h"
 #include "AudioHardwareALSA.h"
 #include <media/AudioRecord.h>
 #include <dlfcn.h>
@@ -46,6 +47,7 @@
 #define BTSCO_RATE_16KHZ 16000
 #define USECASE_TYPE_RX 1
 #define USECASE_TYPE_TX 2
+#define MAX_HDMI_CHANNEL_CNT 6
 
 namespace android_audio_legacy
 {
@@ -96,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;
 
@@ -226,6 +227,36 @@
     return ret;
 }
 
+status_t setHDMIChannelCount()
+{
+    status_t err = NO_ERROR;
+    int channel_count = 0;
+    const char *channel_cnt_str = NULL;
+    EDID_AUDIO_INFO info = { 0 };
+
+    ALSAControl control("/dev/snd/controlC0");
+    if (AudioUtil::getHDMIAudioSinkCaps(&info)) {
+        for (int i = 0; i < info.nAudioBlocks && i < MAX_EDID_BLOCKS; i++) {
+            if (info.AudioBlocksArray[i].nChannels > channel_count &&
+                  info.AudioBlocksArray[i].nChannels <= MAX_HDMI_CHANNEL_CNT) {
+                channel_count = info.AudioBlocksArray[i].nChannels;
+            }
+        }
+    }
+
+    switch (channel_count) {
+    case 6: channel_cnt_str = "Six"; break;
+    case 5: channel_cnt_str = "Five"; break;
+    case 4: channel_cnt_str = "Four"; break;
+    case 3: channel_cnt_str = "Three"; break;
+    default: channel_cnt_str = "Two"; break;
+    }
+    ALOGD("HDMI channel count: %s", channel_cnt_str);
+    control.set("HDMI_RX Channels", channel_cnt_str);
+
+    return err;
+}
+
 status_t setHardwareParams(alsa_handle_t *handle)
 {
     struct snd_pcm_hw_params *params;
@@ -342,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;
@@ -549,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;
         }
 
@@ -568,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;
     }
@@ -608,6 +625,13 @@
     unsigned flags = 0;
     int err = NO_ERROR;
 
+    if(handle->devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
+        err = setHDMIChannelCount();
+        if(err != OK) {
+            ALOGE("setHDMIChannelCount err = %d", err);
+            return err;
+        }
+    }
     /* No need to call s_close for LPA as pcm device open and close is handled by LPAPlayer in stagefright */
     if((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA))
     ||(!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) || (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
@@ -633,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;
@@ -644,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;
     }
@@ -1158,65 +1186,75 @@
 {
     ALOGD("use case is %s\n", useCase);
     if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI,
-           strlen(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,
-           strlen(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,
-            strlen(SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
-            strlen(SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI2)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_DIGITAL_RADIO,
-            strlen(SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
+            MAX_LEN(useCase,SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
-            strlen(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,
-            strlen(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,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LPA,
-            strlen(SND_USE_CASE_MOD_PLAY_LPA)) ||
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LPA)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
-            strlen(SND_USE_CASE_MOD_PLAY_TUNNEL)) ||
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_FM,
-            strlen(SND_USE_CASE_MOD_PLAY_FM))) {
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))) {
         return USECASE_TYPE_RX;
     } else if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC,
-            strlen(SND_USE_CASE_VERB_HIFI_REC)) ||
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC,
-            strlen(SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC)) ||
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_FM_REC,
-            strlen(SND_USE_CASE_VERB_FM_REC)) ||
+            MAX_LEN(useCase,SND_USE_CASE_VERB_FM_REC)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_FM_A2DP_REC,
-            strlen(SND_USE_CASE_VERB_FM_A2DP_REC)) ||
+            MAX_LEN(useCase,SND_USE_CASE_VERB_FM_A2DP_REC)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC,
-            strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC)) ||
+            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC,
-            strlen(SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC)) ||
+            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_FM,
-            strlen(SND_USE_CASE_MOD_CAPTURE_FM)) ||
+            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_FM)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM,
-            strlen(SND_USE_CASE_MOD_CAPTURE_A2DP_FM))) {
+            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_A2DP_FM))) {
         return USECASE_TYPE_TX;
     } else if (!strncmp(useCase, SND_USE_CASE_VERB_VOICECALL,
-            strlen(SND_USE_CASE_VERB_VOICECALL)) ||
+            MAX_LEN(useCase,SND_USE_CASE_VERB_VOICECALL)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_IP_VOICECALL,
-            strlen(SND_USE_CASE_VERB_IP_VOICECALL)) ||
+            MAX_LEN(useCase,SND_USE_CASE_VERB_IP_VOICECALL)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_DL_REC,
-            strlen(SND_USE_CASE_VERB_DL_REC)) ||
+            MAX_LEN(useCase,SND_USE_CASE_VERB_DL_REC)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_UL_DL_REC,
-            strlen(SND_USE_CASE_VERB_UL_DL_REC)) ||
+            MAX_LEN(useCase,SND_USE_CASE_VERB_UL_DL_REC)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_INCALL_REC,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_INCALL_REC)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE,
-            strlen(SND_USE_CASE_MOD_PLAY_VOICE)) ||
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOIP,
-            strlen(SND_USE_CASE_MOD_PLAY_VOIP)) ||
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
-            strlen(SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) ||
+            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
-            strlen(SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) ||
+            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
-            strlen(SND_USE_CASE_MOD_CAPTURE_VOICE)) ||
+            MAX_LEN(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_VOLTE,
-            strlen(SND_USE_CASE_VERB_VOLTE)) ||
+            MAX_LEN(useCase,SND_USE_CASE_VERB_VOLTE)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
-            strlen(SND_USE_CASE_MOD_PLAY_VOLTE))) {
+            MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_VOLTE))) {
         return (USECASE_TYPE_RX | USECASE_TYPE_TX);
     } else {
         ALOGE("unknown use case %s\n", useCase);
@@ -1432,8 +1470,6 @@
 #ifdef SEPERATED_AUDIO_INPUT
                 if(input_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
                     return strdup(SND_USE_CASE_DEV_VOICE_RECOGNITION ); /* VOICE RECOGNITION TX */
-                } else if(input_source == AUDIO_SOURCE_CAMCORDER) {
-                    return strdup(SND_USE_CASE_DEV_CAMCORDER_TX ); /* CAMCORDER TX */
                 }
 #endif
                 else {
@@ -1485,6 +1521,10 @@
             } else {
                 if (callMode == AudioSystem::MODE_IN_CALL) {
                     return strdup(SND_USE_CASE_DEV_VOC_LINE); /* Voice BUILTIN-MIC TX */
+#ifdef SEPERATED_AUDIO_INPUT
+                } else if(input_source == AUDIO_SOURCE_CAMCORDER) {
+                    return strdup(SND_USE_CASE_DEV_CAMCORDER_TX ); /* CAMCORDER TX */
+#endif
                 } else
                     return strdup(SND_USE_CASE_DEV_LINE); /* BUILTIN-MIC TX */
             }