Open second ASM loopback session in RX path. am: d517d9d
am: 22271db

* commit '22271db87d6eaadb6cb822fcd6e86bc5b4e49949':
  Open second ASM loopback session in RX path.

Change-Id: I0dbd6862b1bcc3cbc04641f55ac28f0c872f5f49
diff --git a/Android.mk b/Android.mk
index 450d9a3..f856e9e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,20 +1,22 @@
-ifneq ($(filter msm8960 msm8226 msm8x26 msm8974 msm8x74 msm8x84 msm8084 msm8992 msm8994,$(TARGET_BOARD_PLATFORM)),)
+# TODO:  Find a better way to separate build configs for ADP vs non-ADP devices
+ifneq ($(TARGET_BOARD_AUTO),true)
+  ifneq ($(filter msm8960 msm8226 msm8x26 msm8974 msm8x74 msm8x84 msm8084 msm8992 msm8994 msm8996,$(TARGET_BOARD_PLATFORM)),)
 
-MY_LOCAL_PATH := $(call my-dir)
+    MY_LOCAL_PATH := $(call my-dir)
 
-ifeq ($(BOARD_USES_LEGACY_ALSA_AUDIO),true)
-include $(MY_LOCAL_PATH)/legacy/Android.mk
-else
-include $(MY_LOCAL_PATH)/hal/Android.mk
-include $(MY_LOCAL_PATH)/voice_processing/Android.mk
-include $(MY_LOCAL_PATH)/visualizer/Android.mk
-include $(MY_LOCAL_PATH)/post_proc/Android.mk
-endif
+    ifeq ($(BOARD_USES_LEGACY_ALSA_AUDIO),true)
+      include $(MY_LOCAL_PATH)/legacy/Android.mk
+    else
+      include $(MY_LOCAL_PATH)/hal/Android.mk
+      include $(MY_LOCAL_PATH)/voice_processing/Android.mk
+      include $(MY_LOCAL_PATH)/visualizer/Android.mk
+      include $(MY_LOCAL_PATH)/post_proc/Android.mk
+    endif
+  else
+    ifneq ($(filter msm8909 ,$(TARGET_BOARD_PLATFORM)),)
+      #For msm8909 target
+      include $(call all-named-subdir-makefiles,msm8909)
+    endif
 
-else
-ifneq ($(filter msm8909 ,$(TARGET_BOARD_PLATFORM)),)
-#For msm8909 target
-include $(call all-named-subdir-makefiles,msm8909)
-
-endif
+  endif
 endif
diff --git a/hal/Android.mk b/hal/Android.mk
index 35dcbb9..28c1786 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -10,10 +10,11 @@
 ifneq ($(filter msm8960,$(TARGET_BOARD_PLATFORM)),)
   LOCAL_CFLAGS += -DMAX_TARGET_SPECIFIC_CHANNEL_CNT="2"
 endif
-ifneq ($(filter msm8974 msm8226 msm8084 msm8992 msm8994,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8974 msm8226 msm8084 msm8992 msm8994 msm8996,$(TARGET_BOARD_PLATFORM)),)
   # B-family platform uses msm8974 code base
   AUDIO_PLATFORM = msm8974
 ifneq ($(filter msm8974,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_CFLAGS := -DPLATFORM_MSM8974
   LOCAL_CFLAGS += -DMAX_TARGET_SPECIFIC_CHANNEL_CNT="2"
 endif
 ifneq ($(filter msm8226,$(TARGET_BOARD_PLATFORM)),)
@@ -34,6 +35,12 @@
   LOCAL_CFLAGS += -DMAX_TARGET_SPECIFIC_CHANNEL_CNT="4"
   LOCAL_CFLAGS += -DKPI_OPTIMIZE_ENABLED
 endif
+ifneq ($(filter msm8996,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_CFLAGS := -DPLATFORM_MSM8996
+  LOCAL_CFLAGS += -DMAX_TARGET_SPECIFIC_CHANNEL_CNT="4"
+  LOCAL_CFLAGS += -DKPI_OPTIMIZE_ENABLED
+  MULTIPLE_HW_VARIANTS_ENABLED := true
+endif
 endif
 
 LOCAL_SRC_FILES := \
@@ -44,6 +51,11 @@
 	audio_extn/audio_extn.c \
 	$(AUDIO_PLATFORM)/platform.c
 
+ifdef MULTIPLE_HW_VARIANTS_ENABLED
+  LOCAL_CFLAGS += -DHW_VARIANTS_ENABLED
+  LOCAL_SRC_FILES +=  $(AUDIO_PLATFORM)/hw_info.c
+endif
+
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
 	libcutils \
@@ -98,7 +110,7 @@
     LOCAL_SRC_FILES += audio_extn/dsm_feedback.c
 endif
 
-ifneq ($(filter msm8992 msm8994,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8992 msm8994 msm8996,$(TARGET_BOARD_PLATFORM)),)
   # push codec/mad calibration to HW dep node
   # applicable to msm8992/8994 or newer platforms
   LOCAL_CFLAGS += -DHWDEP_CAL_ENABLED
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 7583f83..e5d7db4 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -29,7 +29,62 @@
 #include "platform.h"
 #include "platform_api.h"
 
+struct snd_card_split cur_snd_card_split = {
+    .device = {0},
+    .snd_card = {0},
+    .form_factor = {0},
+};
 
+struct snd_card_split *audio_extn_get_snd_card_split()
+{
+    return &cur_snd_card_split;
+}
+
+void audio_extn_set_snd_card_split(const char* in_snd_card_name)
+{
+    /* sound card name follows below mentioned convention
+       <target name>-<sound card name>-<form factor>-snd-card
+       parse target name, sound card name and form factor
+    */
+    char *snd_card_name = strdup(in_snd_card_name);
+    char *tmp = NULL;
+    char *device = NULL;
+    char *snd_card = NULL;
+    char *form_factor = NULL;
+
+    if (in_snd_card_name == NULL) {
+        ALOGE("%s: snd_card_name passed is NULL", __func__);
+        goto on_error;
+    }
+
+    device = strtok_r(snd_card_name, "-", &tmp);
+    if (device == NULL) {
+        ALOGE("%s: called on invalid snd card name", __func__);
+        goto on_error;
+    }
+    strlcpy(cur_snd_card_split.device, device, HW_INFO_ARRAY_MAX_SIZE);
+
+    snd_card = strtok_r(NULL, "-", &tmp);
+    if (snd_card == NULL) {
+        ALOGE("%s: called on invalid snd card name", __func__);
+        goto on_error;
+    }
+    strlcpy(cur_snd_card_split.snd_card, snd_card, HW_INFO_ARRAY_MAX_SIZE);
+
+    form_factor = strtok_r(NULL, "-", &tmp);
+    if (form_factor == NULL) {
+        ALOGE("%s: called on invalid snd card name", __func__);
+        goto on_error;
+    }
+    strlcpy(cur_snd_card_split.form_factor, form_factor, HW_INFO_ARRAY_MAX_SIZE);
+
+    ALOGI("%s: snd_card_name(%s) device(%s) snd_card(%s) form_factor(%s)",
+               __func__, in_snd_card_name, device, snd_card, form_factor);
+
+on_error:
+    if (snd_card_name)
+        free(snd_card_name);
+}
 
 #ifdef KPI_OPTIMIZE_ENABLED
 typedef int (*perf_lock_acquire_t)(int, int, int*, int);
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index c518faa..715284a 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -19,11 +19,21 @@
 
 #include <cutils/str_parms.h>
 
+#define HW_INFO_ARRAY_MAX_SIZE 32
+
+struct snd_card_split {
+    char device[HW_INFO_ARRAY_MAX_SIZE];
+    char snd_card[HW_INFO_ARRAY_MAX_SIZE];
+    char form_factor[HW_INFO_ARRAY_MAX_SIZE];
+};
+
 void *audio_extn_extspk_init(struct audio_device *adev);
 void audio_extn_extspk_deinit(void *extn);
 void audio_extn_extspk_update(void* extn);
 void audio_extn_extspk_set_mode(void* extn, audio_mode_t mode);
 void audio_extn_extspk_set_voice_vol(void* extn, float vol);
+struct snd_card_split *audio_extn_get_snd_card_split();
+void audio_extn_set_snd_card_split(const char* in_snd_card_name);
 
 #ifndef SPKR_PROT_ENABLED
 #define audio_extn_spkr_prot_init(adev)       (0)
@@ -110,4 +120,16 @@
 void audio_extn_perf_lock_acquire(void);
 void audio_extn_perf_lock_release(void);
 #endif /* KPI_OPTIMIZE_ENABLED */
+
+#ifndef HW_VARIANTS_ENABLED
+#define hw_info_init(snd_card_name)                  (0)
+#define hw_info_deinit(hw_info)                      (0)
+#define hw_info_append_hw_type(hw_info,\
+        snd_device, device_name)                     (0)
+#else
+void *hw_info_init(const char *snd_card_name);
+void hw_info_deinit(void *hw_info);
+void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device,
+                             char *device_name);
+#endif /* HW_VARIANTS_ENABLED */
 #endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/ext_speaker.c b/hal/audio_extn/ext_speaker.c
index 55cbb4c..080620d 100644
--- a/hal/audio_extn/ext_speaker.c
+++ b/hal/audio_extn/ext_speaker.c
@@ -23,9 +23,9 @@
 #include <dlfcn.h>
 
 #ifdef __LP64__
-        #define LIB_SPEAKER_BUNDLE "/system/lib64/soundfx/libspeakerbundle.so"
+#define LIB_SPEAKER_BUNDLE "/system/lib64/soundfx/libspeakerbundle.so"
 #else
-        #define LIB_SPEAKER_BUNDLE "/system/lib/soundfx/libspeakerbundle.so"
+#define LIB_SPEAKER_BUNDLE "/system/lib/soundfx/libspeakerbundle.so"
 #endif
 
 typedef void (*set_mode_t)(int);
diff --git a/hal/audio_extn/soundtrigger.c b/hal/audio_extn/soundtrigger.c
index b5475a1..32b7b85 100644
--- a/hal/audio_extn/soundtrigger.c
+++ b/hal/audio_extn/soundtrigger.c
@@ -31,6 +31,12 @@
 #define XSTR(x) STR(x)
 #define STR(x) #x
 
+#ifdef __LP64__
+#define SOUND_TRIGGER_LIBRARY_PATH "/system/vendor/lib64/hw/sound_trigger.primary.%s.so"
+#else
+#define SOUND_TRIGGER_LIBRARY_PATH "/system/vendor/lib/hw/sound_trigger.primary.%s.so"
+#endif
+
 struct sound_trigger_info  {
     struct sound_trigger_session_info st_ses;
     bool lab_stopped;
@@ -193,7 +199,7 @@
             in->channel_mask = audio_channel_in_mask_from_count(in->config.channels);
             in->is_st_session = true;
             in->is_st_session_active = true;
-            ALOGD("%s: capture_handle %d is sound trigger", __func__, in->capture_handle);
+            ALOGV("%s: capture_handle %d is sound trigger", __func__, in->capture_handle);
             break;
         }
     }
@@ -222,7 +228,7 @@
         return;
     }
 
-    ALOGI("%s: device 0x%x of type %d for Event %d",
+    ALOGV("%s: device 0x%x of type %d for Event %d",
         __func__, snd_device, device_type, event);
     if (device_type == PCM_CAPTURE) {
         switch(event) {
@@ -293,7 +299,7 @@
     char sound_trigger_lib[100];
     void *lib_handle;
 
-    ALOGI("%s: Enter", __func__);
+    ALOGV("%s: Enter", __func__);
 
     st_dev = (struct sound_trigger_audio_device*)
                         calloc(1, sizeof(struct sound_trigger_audio_device));
@@ -303,7 +309,7 @@
     }
 
     snprintf(sound_trigger_lib, sizeof(sound_trigger_lib),
-             "/system/vendor/lib/hw/sound_trigger.primary.%s.so",
+             SOUND_TRIGGER_LIBRARY_PATH,
               XSTR(SOUND_TRIGGER_PLATFORM_NAME));
 
     st_dev->lib_handle = dlopen(sound_trigger_lib, RTLD_NOW);
@@ -314,7 +320,7 @@
         status = -EINVAL;
         goto cleanup;
     }
-    ALOGI("%s: DLOPEN successful for %s", __func__, sound_trigger_lib);
+    ALOGV("%s: DLOPEN successful for %s", __func__, sound_trigger_lib);
 
     st_dev->st_callback = (sound_trigger_hw_call_back_t)
               dlsym(st_dev->lib_handle, "sound_trigger_hw_call_back");
@@ -341,7 +347,7 @@
 
 void audio_extn_sound_trigger_deinit(struct audio_device *adev)
 {
-    ALOGI("%s: Enter", __func__);
+    ALOGV("%s: Enter", __func__);
     if (st_dev && (st_dev->adev == adev) && st_dev->lib_handle) {
         dlclose(st_dev->lib_handle);
         free(st_dev);
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index 4d8b233..8afb0dc 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -33,6 +33,8 @@
 #include "audio_extn.h"
 #include <linux/msm_audio_calibration.h>
 
+#define THERMAL_CLIENT_LIBRARY_PATH "libthermalclient.so"
+
 #ifdef SPKR_PROT_ENABLED
 
 /*Range of spkr temparatures -30C to 80C*/
@@ -710,7 +712,7 @@
     pthread_mutex_init(&handle.mutex_spkr_prot, NULL);
     pthread_mutex_init(&handle.spkr_calib_cancelack_mutex, NULL);
     pthread_mutex_init(&handle.spkr_prot_thermalsync_mutex, NULL);
-    handle.thermal_handle = dlopen("/vendor/lib/libthermalclient.so",
+    handle.thermal_handle = dlopen(THERMAL_CLIENT_LIBRARY_PATH,
             RTLD_NOW);
     if (!handle.thermal_handle) {
         ALOGE("%s: DLOPEN for thermal client failed", __func__);
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 6747b05..d907e82 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 The Android Open Source Project
+ * Copyright (C) 2013-2016 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.
@@ -172,6 +172,8 @@
     [USECASE_VOLTE_CALL] = "volte-call",
     [USECASE_QCHAT_CALL] = "qchat-call",
     [USECASE_VOWLAN_CALL] = "vowlan-call",
+    [USECASE_VOICEMMODE1_CALL] = "voicemmode1-call",
+    [USECASE_VOICEMMODE2_CALL] = "voicemmode2-call",
 
     [USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib",
     [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record",
@@ -270,7 +272,7 @@
 
     strcpy(mixer_path, use_case_table[usecase->id]);
     platform_add_backend_name(adev->platform, mixer_path, snd_device);
-    ALOGD("%s: apply and update mixer path: %s", __func__, mixer_path);
+    ALOGV("%s: apply and update mixer path: %s", __func__, mixer_path);
     audio_route_apply_and_update_path(adev->audio_route, mixer_path);
 
     ALOGV("%s: exit", __func__);
@@ -293,7 +295,7 @@
         snd_device = usecase->out_snd_device;
     strcpy(mixer_path, use_case_table[usecase->id]);
     platform_add_backend_name(adev->platform, mixer_path, snd_device);
-    ALOGD("%s: reset and update mixer path: %s", __func__, mixer_path);
+    ALOGV("%s: reset and update mixer path: %s", __func__, mixer_path);
     audio_route_reset_and_update_path(adev->audio_route, mixer_path);
 
     ALOGV("%s: exit", __func__);
@@ -305,20 +307,19 @@
 {
     int i, num_devices = 0;
     snd_device_t new_snd_devices[2];
-
+    int ret_val = -EINVAL;
     if (snd_device < SND_DEVICE_MIN ||
         snd_device >= SND_DEVICE_MAX) {
         ALOGE("%s: Invalid sound device %d", __func__, snd_device);
-        return -EINVAL;
+        goto on_error;
     }
 
     platform_send_audio_calibration(adev->platform, snd_device);
 
-    adev->snd_dev_ref_cnt[snd_device]++;
-    if (adev->snd_dev_ref_cnt[snd_device] > 1) {
+    if (adev->snd_dev_ref_cnt[snd_device] >= 1) {
         ALOGV("%s: snd_device(%d: %s) is already active",
               __func__, snd_device, platform_get_snd_device_name(snd_device));
-        return 0;
+        goto on_success;
     }
 
     /* due to the possibility of calibration overwrite between listen
@@ -335,12 +336,11 @@
         snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) &&
         audio_extn_spkr_prot_is_enabled()) {
         if (audio_extn_spkr_prot_get_acdb_id(snd_device) < 0) {
-            adev->snd_dev_ref_cnt[snd_device]--;
-            return -EINVAL;
+            goto on_error;
         }
         if (audio_extn_spkr_prot_start_processing(snd_device)) {
             ALOGE("%s: spkr_start_processing failed", __func__);
-            return -EINVAL;
+            goto on_error;
         }
     } else if (platform_can_split_snd_device(snd_device, &num_devices, new_snd_devices)) {
         for (i = 0; i < num_devices; i++) {
@@ -348,12 +348,20 @@
         }
         platform_set_speaker_gain_in_combo(adev, snd_device, true);
     } else {
-        const char * dev_path = platform_get_snd_device_name(snd_device);
-        ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, dev_path);
-        audio_route_apply_and_update_path(adev->audio_route, dev_path);
-    }
+        char device_name[DEVICE_NAME_MAX_SIZE] = {0};
+        if (platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0 ) {
+            ALOGE(" %s: Invalid sound device returned", __func__);
+            goto on_error;
+        }
 
-    return 0;
+        ALOGV("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
+        audio_route_apply_and_update_path(adev->audio_route, device_name);
+    }
+on_success:
+    adev->snd_dev_ref_cnt[snd_device]++;
+    ret_val = 0;
+on_error:
+    return ret_val;
 }
 
 int disable_snd_device(struct audio_device *adev,
@@ -373,9 +381,6 @@
     }
     adev->snd_dev_ref_cnt[snd_device]--;
     if (adev->snd_dev_ref_cnt[snd_device] == 0) {
-        const char * dev_path = platform_get_snd_device_name(snd_device);
-        ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, dev_path);
-
         audio_extn_dsm_feedback_enable(adev, snd_device, false);
         if ((snd_device == SND_DEVICE_OUT_SPEAKER ||
             snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) &&
@@ -387,7 +392,14 @@
             }
             platform_set_speaker_gain_in_combo(adev, snd_device, false);
         } else {
-            audio_route_reset_and_update_path(adev->audio_route, dev_path);
+            char device_name[DEVICE_NAME_MAX_SIZE] = {0};
+            if (platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0 ) {
+                ALOGE(" %s: Invalid sound device returned", __func__);
+                return -EINVAL;
+            }
+
+            ALOGV("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
+            audio_route_reset_and_update_path(adev->audio_route, device_name);
         }
         audio_extn_sound_trigger_update_device_status(snd_device,
                                         ST_EVENT_SND_DEVICE_FREE);
@@ -674,9 +686,36 @@
         return 0;
     }
 
-    ALOGD("%s: out_snd_device(%d: %s) in_snd_device(%d: %s)", __func__,
-          out_snd_device, platform_get_snd_device_name(out_snd_device),
-          in_snd_device,  platform_get_snd_device_name(in_snd_device));
+    if (out_snd_device != SND_DEVICE_NONE &&
+            out_snd_device != adev->last_logged_snd_device[uc_id][0]) {
+        ALOGD("%s: changing use case %s output device from(%d: %s, acdb %d) to (%d: %s, acdb %d)",
+              __func__,
+              use_case_table[uc_id],
+              adev->last_logged_snd_device[uc_id][0],
+              platform_get_snd_device_name(adev->last_logged_snd_device[uc_id][0]),
+              adev->last_logged_snd_device[uc_id][0] != SND_DEVICE_NONE ?
+                      platform_get_snd_device_acdb_id(adev->last_logged_snd_device[uc_id][0]) :
+                      -1,
+              out_snd_device,
+              platform_get_snd_device_name(out_snd_device),
+              platform_get_snd_device_acdb_id(out_snd_device));
+        adev->last_logged_snd_device[uc_id][0] = out_snd_device;
+    }
+    if (in_snd_device != SND_DEVICE_NONE &&
+            in_snd_device != adev->last_logged_snd_device[uc_id][1]) {
+        ALOGD("%s: changing use case %s input device from(%d: %s, acdb %d) to (%d: %s, acdb %d)",
+              __func__,
+              use_case_table[uc_id],
+              adev->last_logged_snd_device[uc_id][1],
+              platform_get_snd_device_name(adev->last_logged_snd_device[uc_id][1]),
+              adev->last_logged_snd_device[uc_id][1] != SND_DEVICE_NONE ?
+                      platform_get_snd_device_acdb_id(adev->last_logged_snd_device[uc_id][1]) :
+                      -1,
+              in_snd_device,
+              platform_get_snd_device_name(in_snd_device),
+              platform_get_snd_device_acdb_id(in_snd_device));
+        adev->last_logged_snd_device[uc_id][1] = in_snd_device;
+    }
 
     /*
      * Limitation: While in call, to do a device switch we need to disable
@@ -817,7 +856,7 @@
     ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
           __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
 
-    unsigned int flags = PCM_IN;
+    unsigned int flags = PCM_IN | PCM_MONOTONIC;
     unsigned int pcm_open_retry_count = 0;
 
     if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) {
@@ -844,8 +883,14 @@
         break;
     }
 
-    ALOGV("%s: pcm_prepare start", __func__);
-    pcm_prepare(in->pcm);
+    ALOGV("%s: pcm_prepare", __func__);
+    ret = pcm_prepare(in->pcm);
+    if (ret < 0) {
+        ALOGE("%s: pcm_prepare returned %d", __func__, ret);
+        pcm_close(in->pcm);
+        in->pcm = NULL;
+        goto error_open;
+    }
 
     audio_extn_perf_lock_release();
 
@@ -859,7 +904,7 @@
 
 error_config:
     adev->active_input = NULL;
-    ALOGD("%s: exit: status(%d)", __func__, ret);
+    ALOGW("%s: exit: status(%d)", __func__, ret);
 
     return ret;
 }
@@ -1036,12 +1081,12 @@
              * max channels of remaining use cases.
              */
             if (usecase->id == USECASE_VOICE_CALL) {
-                ALOGD("%s: voice call is active, no change in HDMI channels",
+                ALOGV("%s: voice call is active, no change in HDMI channels",
                       __func__);
                 ret = false;
                 break;
             } else if (usecase->id == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
-                ALOGD("%s: multi channel playback is active, "
+                ALOGV("%s: multi channel playback is active, "
                       "no change in HDMI channels", __func__);
                 ret = false;
                 break;
@@ -1062,7 +1107,7 @@
         return 0;
 
     if (channels == adev->cur_hdmi_channels) {
-        ALOGD("%s: Requested channels are same as current", __func__);
+        ALOGV("%s: Requested channels are same as current", __func__);
         return 0;
     }
 
@@ -1203,10 +1248,16 @@
             }
             break;
         }
-        ALOGV("%s: pcm_prepare start", __func__);
-        if (pcm_is_ready(out->pcm))
-            pcm_prepare(out->pcm);
-
+        ALOGV("%s: pcm_prepare", __func__);
+        if (pcm_is_ready(out->pcm)) {
+            ret = pcm_prepare(out->pcm);
+            if (ret < 0) {
+                ALOGE("%s: pcm_prepare returned %d", __func__, ret);
+                pcm_close(out->pcm);
+                out->pcm = NULL;
+                goto error_open;
+            }
+        }
     } else {
         out->pcm = NULL;
         out->compr = compress_open(adev->snd_card, out->pcm_device_id,
@@ -1431,7 +1482,7 @@
     bool select_new_device = false;
     int status = 0;
 
-    ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s",
+    ALOGV("%s: enter: usecase(%d: %s) kvpairs: %s",
           __func__, out->usecase, use_case_table[out->usecase], kvpairs);
     parms = str_parms_create_str(kvpairs);
     ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
@@ -1638,13 +1689,28 @@
             compress_set_gapless_metadata(out->compr, &out->gapless_mdata);
             out->send_new_metadata = 0;
         }
+        unsigned int avail;
+        struct timespec tstamp;
+        ret = compress_get_hpointer(out->compr, &avail, &tstamp);
+        /* Do not limit write size if the available frames count is unknown */
+        if (ret != 0) {
+            avail = bytes;
+        }
+        if (avail == 0) {
+            ret = 0;
+        } else {
+            if (avail > bytes) {
+                avail = bytes;
+            }
+            ret = compress_write(out->compr, buffer, avail);
+            ALOGVV("%s: writing buffer (%d bytes) to compress device returned %zd",
+                   __func__, avail, ret);
+        }
 
-        ret = compress_write(out->compr, buffer, bytes);
-        ALOGVV("%s: writing buffer (%d bytes) to compress device returned %d", __func__, bytes, ret);
         if (ret >= 0 && ret < (ssize_t)bytes) {
             send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
         }
-        if (!out->playback_started) {
+        if (ret > 0 && !out->playback_started) {
             compress_start(out->compr);
             out->playback_started = 1;
             out->offload_state = OFFLOAD_STATE_PLAYING;
@@ -1695,8 +1761,10 @@
     if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) {
         lock_output_stream(out);
         if (out->compr != NULL) {
-            compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
-                    &out->sample_rate);
+            unsigned long frames = 0;
+            // TODO: check return value
+            compress_get_tstamp(out->compr, &frames, &out->sample_rate);
+            *dsp_frames = (uint32_t)frames;
             ALOGVV("%s rendered frames %d sample_rate %d",
                    __func__, *dsp_frames, out->sample_rate);
         }
@@ -1728,13 +1796,14 @@
                                    uint64_t *frames, struct timespec *timestamp)
 {
     struct stream_out *out = (struct stream_out *)stream;
-    int ret = -1;
+    int ret = -EINVAL;
     unsigned long dsp_frames;
 
     lock_output_stream(out);
 
     if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
         if (out->compr != NULL) {
+            // TODO: check return value
             compress_get_tstamp(out->compr, &dsp_frames,
                     &out->sample_rate);
             ALOGVV("%s rendered frames %ld sample_rate %d",
@@ -1892,7 +1961,7 @@
     lock_input_stream(in);
 
     if (!in->standby && in->is_st_session) {
-        ALOGD("%s: sound trigger pcm stop lab", __func__);
+        ALOGV("%s: sound trigger pcm stop lab", __func__);
         audio_extn_sound_trigger_stop_lab(in);
         in->standby = true;
     }
@@ -2037,6 +2106,10 @@
         ALOGV("%s: read failed - sleeping for buffer duration", __func__);
         usleep(bytes * 1000000 / audio_stream_in_frame_size(stream) /
                in_get_sample_rate(&in->stream.common));
+        memset(buffer, 0, bytes); // clear return data
+    }
+    if (bytes > 0) {
+        in->frames_read += bytes / audio_stream_in_frame_size(stream);
     }
     return bytes;
 }
@@ -2046,6 +2119,29 @@
     return 0;
 }
 
+static int in_get_capture_position(const struct audio_stream_in *stream,
+                                   int64_t *frames, int64_t *time)
+{
+    if (stream == NULL || frames == NULL || time == NULL) {
+        return -EINVAL;
+    }
+    struct stream_in *in = (struct stream_in *)stream;
+    int ret = -ENOSYS;
+
+    lock_input_stream(in);
+    if (in->pcm) {
+        struct timespec timestamp;
+        unsigned int avail;
+        if (pcm_get_htimestamp(in->pcm, &avail, &timestamp) == 0) {
+            *frames = in->frames_read + avail;
+            *time = timestamp.tv_sec * 1000000000LL + timestamp.tv_nsec;
+            ret = 0;
+        }
+    }
+    pthread_mutex_unlock(&in->lock);
+    return ret;
+}
+
 static int add_remove_audio_effect(const struct audio_stream *stream,
                                    effect_handle_t effect,
                                    bool enable)
@@ -2150,9 +2246,12 @@
             config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
         if (config->channel_mask == 0)
             config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
+        if (config->format == AUDIO_FORMAT_DEFAULT)
+            config->format = AUDIO_FORMAT_PCM_16_BIT;
 
         out->channel_mask = config->channel_mask;
         out->sample_rate = config->sample_rate;
+        out->format = config->format;
         out->usecase = USECASE_AUDIO_PLAYBACK_MULTI_CH;
         out->config = pcm_config_hdmi_multi;
         out->config.rate = config->sample_rate;
@@ -2325,7 +2424,7 @@
 error_open:
     free(out);
     *stream_out = NULL;
-    ALOGD("%s: exit: ret %d", __func__, ret);
+    ALOGW("%s: exit: ret %d", __func__, ret);
     return ret;
 }
 
@@ -2363,7 +2462,7 @@
     int ret;
     int status = 0;
 
-    ALOGD("%s: enter: %s", __func__, kvpairs);
+    ALOGV("%s: enter: %s", __func__, kvpairs);
 
     pthread_mutex_lock(&adev->lock);
 
@@ -2492,7 +2591,7 @@
 
     pthread_mutex_lock(&adev->lock);
     if (adev->mode != mode) {
-        ALOGD("%s: mode %d\n", __func__, mode);
+        ALOGD("%s: mode %d", __func__, (int)mode);
         adev->mode = mode;
         if ((mode == AUDIO_MODE_NORMAL || mode == AUDIO_MODE_IN_COMMUNICATION) &&
                 voice_is_in_call(adev)) {
@@ -2512,7 +2611,7 @@
     int ret;
     struct audio_device *adev = (struct audio_device *)dev;
 
-    ALOGD("%s: state %d\n", __func__, state);
+    ALOGD("%s: state %d", __func__, (int)state);
     pthread_mutex_lock(&adev->lock);
     ret = voice_set_mic_mute(adev, state);
     adev->mic_muted = state;
@@ -2576,6 +2675,7 @@
     in->stream.set_gain = in_set_gain;
     in->stream.read = in_read;
     in->stream.get_input_frames_lost = in_get_input_frames_lost;
+    in->stream.get_capture_position = in_get_capture_position;
 
     in->device = devices;
     in->source = source;
@@ -2584,6 +2684,7 @@
     in->channel_mask = config->channel_mask;
     in->capture_handle = handle;
     in->flags = flags;
+    // in->frames_read = 0;
 
     /* Update config params with the requested sample rate and channels */
     if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
@@ -2770,7 +2871,6 @@
                     ALOGV("%s: (%s) card %d  device %d", __func__,
                             dir ? "input" : "output", card_id, device_id);
                     pcm_params_to_string(*pparams, info, ARRAY_SIZE(info));
-                    ALOGV(info); /* print parameters */
                 } else {
                     ALOGV("%s: cannot locate card %d  device %d", __func__, card_id, device_id);
                 }
@@ -2910,59 +3010,53 @@
     adev->extspk = audio_extn_extspk_init(adev);
     audio_extn_sound_trigger_init(adev);
 
-    if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) {
-        adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW);
-        if (adev->visualizer_lib == NULL) {
-            ALOGE("%s: DLOPEN failed for %s", __func__, VISUALIZER_LIBRARY_PATH);
-        } else {
-            ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH);
-            adev->visualizer_start_output =
-                        (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
-                                                        "visualizer_hal_start_output");
-            adev->visualizer_stop_output =
-                        (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
-                                                        "visualizer_hal_stop_output");
-        }
+    adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW);
+    if (adev->visualizer_lib == NULL) {
+        ALOGW("%s: DLOPEN failed for %s", __func__, VISUALIZER_LIBRARY_PATH);
+    } else {
+        ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH);
+        adev->visualizer_start_output =
+                    (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
+                                                    "visualizer_hal_start_output");
+        adev->visualizer_stop_output =
+                    (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
+                                                    "visualizer_hal_stop_output");
     }
 
-    if (access(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, R_OK) == 0) {
-        adev->offload_effects_lib = dlopen(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, RTLD_NOW);
-        if (adev->offload_effects_lib == NULL) {
-            ALOGE("%s: DLOPEN failed for %s", __func__,
-                  OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
-        } else {
-            ALOGV("%s: DLOPEN successful for %s", __func__,
-                  OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
-            adev->offload_effects_start_output =
-                        (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
-                                         "offload_effects_bundle_hal_start_output");
-            adev->offload_effects_stop_output =
-                        (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
-                                         "offload_effects_bundle_hal_stop_output");
-        }
+    adev->offload_effects_lib = dlopen(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, RTLD_NOW);
+    if (adev->offload_effects_lib == NULL) {
+        ALOGW("%s: DLOPEN failed for %s", __func__,
+              OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
+    } else {
+        ALOGV("%s: DLOPEN successful for %s", __func__,
+              OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
+        adev->offload_effects_start_output =
+                    (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
+                                     "offload_effects_bundle_hal_start_output");
+        adev->offload_effects_stop_output =
+                    (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
+                                     "offload_effects_bundle_hal_stop_output");
     }
 
-    if (access(ADM_LIBRARY_PATH, R_OK) == 0) {
-        adev->adm_lib = dlopen(ADM_LIBRARY_PATH, RTLD_NOW);
-        if (adev->adm_lib == NULL) {
-            ALOGE("%s: DLOPEN failed for %s", __func__, ADM_LIBRARY_PATH);
-        } else {
-            ALOGV("%s: DLOPEN successful for %s", __func__, ADM_LIBRARY_PATH);
-            adev->adm_init = (adm_init_t)
-                                    dlsym(adev->adm_lib, "adm_init");
-            adev->adm_deinit = (adm_deinit_t)
-                                    dlsym(adev->adm_lib, "adm_deinit");
-            adev->adm_register_input_stream = (adm_register_input_stream_t)
-                                    dlsym(adev->adm_lib, "adm_register_input_stream");
-            adev->adm_register_output_stream = (adm_register_output_stream_t)
-                                    dlsym(adev->adm_lib, "adm_register_output_stream");
-            adev->adm_deregister_stream = (adm_deregister_stream_t)
-                                    dlsym(adev->adm_lib, "adm_deregister_stream");
-            adev->adm_request_focus = (adm_request_focus_t)
-                                    dlsym(adev->adm_lib, "adm_request_focus");
-            adev->adm_abandon_focus = (adm_abandon_focus_t)
-                                    dlsym(adev->adm_lib, "adm_abandon_focus");
-        }
+    adev->adm_lib = dlopen(ADM_LIBRARY_PATH, RTLD_NOW);
+    if (adev->adm_lib == NULL) {
+        ALOGW("%s: DLOPEN failed for %s", __func__, ADM_LIBRARY_PATH);
+    } else {
+        ALOGV("%s: DLOPEN successful for %s", __func__, ADM_LIBRARY_PATH);
+        adev->adm_init = (adm_init_t)
+                                dlsym(adev->adm_lib, "adm_init");
+        adev->adm_deinit = (adm_deinit_t)
+                                dlsym(adev->adm_lib, "adm_deinit");
+        adev->adm_register_input_stream = (adm_register_input_stream_t)
+                                dlsym(adev->adm_lib, "adm_register_input_stream");
+        adev->adm_register_output_stream = (adm_register_output_stream_t)
+                                dlsym(adev->adm_lib, "adm_register_output_stream");
+        adev->adm_deregister_stream = (adm_deregister_stream_t)
+                                dlsym(adev->adm_lib, "adm_deregister_stream");
+        adev->adm_request_focus = (adm_request_focus_t)
+                                dlsym(adev->adm_lib, "adm_request_focus");
+        adev->adm_abandon_focus = (adm_abandon_focus_t)
+                                dlsym(adev->adm_lib, "adm_abandon_focus");
     }
 
     adev->bt_wb_speech_enabled = false;
@@ -2999,7 +3093,7 @@
 
     audio_extn_perf_lock_init();
 
-    ALOGV("%s: exit", __func__);
+    ALOGD("%s: exit", __func__);
     return 0;
 }
 
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 8c07b6d..1a1e0ef 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 The Android Open Source Project
+ * Copyright (C) 2013-2016 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.
@@ -27,9 +27,15 @@
 #include <audio_route/audio_route.h>
 #include "voice.h"
 
+// dlopen() does not go through default library path search if there is a "/" in the library name.
+#ifdef __LP64__
+#define VISUALIZER_LIBRARY_PATH "/system/lib64/soundfx/libqcomvisualizer.so"
+#define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/system/lib64/soundfx/libqcompostprocbundle.so"
+#else
 #define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so"
 #define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/system/lib/soundfx/libqcompostprocbundle.so"
-#define ADM_LIBRARY_PATH "/system/vendor/lib/libadm.so"
+#endif
+#define ADM_LIBRARY_PATH "libadm.so"
 
 /* Flags used to initialize acdb_settings variable that goes to ACDB library */
 #define DMIC_FLAG       0x00000002
@@ -45,8 +51,6 @@
 #define MAX_SUPPORTED_CHANNEL_MASKS 2
 #define DEFAULT_HDMI_OUT_CHANNELS   2
 
-typedef int snd_device_t;
-
 /* These are the supported use cases by the hardware.
  * Each usecase is mapped to a specific PCM device.
  * Refer to pcm_device_table[].
@@ -69,13 +73,29 @@
     USECASE_AUDIO_RECORD,
     USECASE_AUDIO_RECORD_LOW_LATENCY,
 
-    USECASE_VOICE_CALL,
+    /* Voice extension usecases
+     *
+     * Following usecase are specific to voice session names created by
+     * MODEM and APPS on 8992/8994/8084/8974 platforms.
+     */
+    USECASE_VOICE_CALL,  /* Usecase setup for voice session on first subscription for DSDS/DSDA */
+    USECASE_VOICE2_CALL, /* Usecase setup for voice session on second subscription for DSDS/DSDA */
+    USECASE_VOLTE_CALL,  /* Usecase setup for VoLTE session on first subscription */
+    USECASE_QCHAT_CALL,  /* Usecase setup for QCHAT session */
+    USECASE_VOWLAN_CALL, /* Usecase setup for VoWLAN session */
 
-    /* Voice extension usecases */
-    USECASE_VOICE2_CALL,
-    USECASE_VOLTE_CALL,
-    USECASE_QCHAT_CALL,
-    USECASE_VOWLAN_CALL,
+    /*
+     * Following usecase are specific to voice session names created by
+     * MODEM and APPS on 8996 platforms.
+     */
+
+    USECASE_VOICEMMODE1_CALL, /* Usecase setup for Voice/VoLTE/VoWLAN sessions on first
+                               * subscription for DSDS/DSDA
+                               */
+    USECASE_VOICEMMODE2_CALL, /* Usecase setup for voice/VoLTE/VoWLAN sessions on second
+                               * subscription for DSDS/DSDA
+                               */
+
     USECASE_INCALL_REC_UPLINK,
     USECASE_INCALL_REC_DOWNLINK,
     USECASE_INCALL_REC_UPLINK_AND_DOWNLINK,
@@ -175,6 +195,7 @@
     audio_usecase_t usecase;
     bool enable_aec;
     bool enable_ns;
+    int64_t frames_read; /* total frames read, not cleared when entering standby */
 
     audio_io_handle_t capture_handle;
     audio_input_flags_t flags;
@@ -264,6 +285,10 @@
     adm_deregister_stream_t adm_deregister_stream;
     adm_request_focus_t adm_request_focus;
     adm_abandon_focus_t adm_abandon_focus;
+
+    /* logging */
+    snd_device_t last_logged_snd_device[AUDIO_USECASE_MAX][2]; /* [out, in] */
+
 };
 
 int select_devices(struct audio_device *adev,
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 0ffe8a9..b2d4e04 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1087,3 +1087,12 @@
 {
     return true;
 }
+
+int platform_get_snd_device_name_extn(void *platform __unused,
+                                      snd_device_t snd_device,
+                                      char *device_name)
+{
+    device_name = platform_get_snd_device_name(snd_device);
+    return 0;
+}
+
diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c
new file mode 100644
index 0000000..6723362
--- /dev/null
+++ b/hal/msm8974/hw_info.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2016 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 "hardware_info"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <cutils/log.h>
+#include "audio_hw.h"
+#include "platform.h"
+#include "audio_extn.h"
+
+struct hardware_info {
+    char name[HW_INFO_ARRAY_MAX_SIZE];
+    char type[HW_INFO_ARRAY_MAX_SIZE];
+    /* variables for handling target variants */
+    uint32_t num_snd_devices;
+    char dev_extn[HW_INFO_ARRAY_MAX_SIZE];
+    snd_device_t  *snd_devices;
+};
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+
+static const snd_device_t tasha_db_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER
+};
+
+static const snd_device_t tasha_fluid_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HDMI,
+    SND_DEVICE_OUT_SPEAKER_PROTECTED,
+    SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED,
+};
+
+static const snd_device_t tasha_liquid_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_IN_SPEAKER_MIC,
+    SND_DEVICE_IN_HEADSET_MIC,
+    SND_DEVICE_IN_VOICE_DMIC,
+    SND_DEVICE_IN_VOICE_SPEAKER_DMIC,
+    SND_DEVICE_IN_VOICE_REC_DMIC_STEREO,
+    SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+    SND_DEVICE_IN_QUAD_MIC,
+};
+
+static void  update_hardware_info_8996(struct hardware_info *hw_info)
+{
+    struct snd_card_split *tmp_handle = audio_extn_get_snd_card_split();
+    ALOGV("%s: device %s snd_card %s form_factor %s",
+               __func__, tmp_handle->device, tmp_handle->snd_card, tmp_handle->form_factor);
+
+    strlcpy(hw_info->name, tmp_handle->device, sizeof(hw_info->name));
+    snprintf(hw_info->type, sizeof(hw_info->type), " %s", tmp_handle->form_factor);
+    snprintf(hw_info->dev_extn, sizeof(hw_info->dev_extn), "-%s", tmp_handle->form_factor);
+
+    if (!strncmp(tmp_handle->form_factor, "fluid", sizeof("fluid"))) {
+        hw_info->snd_devices = (snd_device_t *)tasha_fluid_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tasha_fluid_variant_devices);
+    } else if (!strncmp(tmp_handle->form_factor, "liquid", sizeof("liquid"))) {
+        hw_info->snd_devices = (snd_device_t *)tasha_liquid_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tasha_liquid_variant_devices);
+    } else if (!strncmp(tmp_handle->form_factor, "db", sizeof("db"))) {
+        hw_info->snd_devices = (snd_device_t *)tasha_db_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tasha_db_variant_devices);
+    } else {
+        ALOGW("%s: %s form factor doesnt need mixer path over ride", __func__, tmp_handle->form_factor);
+    }
+
+    ALOGV("name %s type %s dev_extn %s", hw_info->name, hw_info->type, hw_info->dev_extn);
+}
+
+
+void *hw_info_init(const char *snd_card_name)
+{
+    struct hardware_info *hw_info = NULL;
+    bool hw_supported = false;
+
+    if (strstr(snd_card_name, "msm8996")) {
+        ALOGD("8996 - variant soundcard");
+        hw_supported = true;
+    } else {
+        ALOGE("%s: Unsupported target %s:",__func__, snd_card_name);
+    }
+
+    if (hw_supported) {
+        hw_info = malloc(sizeof(struct hardware_info));
+        if (!hw_info) {
+            ALOGE("failed to allocate mem for hardware info");
+            goto on_finish;
+        }
+
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "", sizeof(hw_info->name));
+        update_hardware_info_8996(hw_info);
+    }
+
+on_finish:
+    return hw_info;
+}
+
+void hw_info_deinit(void *hw_info)
+{
+    free(hw_info);
+}
+
+void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device,
+                            char *device_name)
+{
+    struct hardware_info *my_data = (struct hardware_info*) hw_info;
+    uint32_t i = 0;
+
+    if (my_data == NULL)
+        return;
+
+    snd_device_t *snd_devices =
+            (snd_device_t *) my_data->snd_devices;
+
+    if (snd_devices != NULL) {
+        for (i = 0; i <  my_data->num_snd_devices; i++) {
+            if (snd_device == (snd_device_t)snd_devices[i]) {
+                ALOGV("extract dev_extn device %d, device_name %s extn = %s ",
+                        (snd_device_t)snd_devices[i], device_name,  my_data->dev_extn);
+                CHECK(strlcat(device_name,  my_data->dev_extn,
+                        DEVICE_NAME_MAX_SIZE) < DEVICE_NAME_MAX_SIZE);
+                break;
+            }
+        }
+    }
+    ALOGD("%s : device_name = %s", __func__,device_name);
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index ab836bd..89b6de5 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 The Android Open Source Project
+ * Copyright (C) 2013-2016 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.
@@ -28,12 +28,16 @@
 #include "audio_extn.h"
 #include <linux/msm_audio.h>
 
-#define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
-#define MIXER_XML_PATH_WCD9330 "/system/etc/mixer_paths_wcd9330.xml"
+#define MIXER_XML_DEFAULT_PATH "/system/etc/mixer_paths.xml"
+#define MIXER_XML_BASE_STRING "/system/etc/mixer_paths"
+#define TOMTOM_8226_SND_CARD_NAME "msm8226-tomtom-snd-card"
+#define TOMTOM_MIXER_FILE_SUFFIX "wcd9330"
+
 #define LIB_ACDB_LOADER "libacdbloader.so"
 #define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID"
 #define CVD_VERSION_MIXER_CTL "CVD Version"
 
+#define min(a, b) ((a) < (b) ? (a) : (b))
 
 /*
  * This file will have a maximum of 38 bytes:
@@ -94,7 +98,7 @@
 
 /* Audio calibration related functions */
 typedef void (*acdb_deallocate_t)();
-typedef int  (*acdb_init_v2_cvd_t)(char *, char *);
+typedef int  (*acdb_init_v2_cvd_t)(char *, char *, int);
 typedef int  (*acdb_init_v2_t)(char *);
 typedef int  (*acdb_init_t)();
 typedef void (*acdb_send_audio_cal_t)(int, int);
@@ -126,6 +130,8 @@
     char *snd_card_name;
     int max_vol_index;
     int max_mic_count;
+
+    void *hw_info;
 };
 
 static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
@@ -153,6 +159,11 @@
     [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE},
     [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE},
     [USECASE_VOWLAN_CALL] = {VOWLAN_CALL_PCM_DEVICE, VOWLAN_CALL_PCM_DEVICE},
+    [USECASE_VOICEMMODE1_CALL] = {VOICEMMODE1_CALL_PCM_DEVICE,
+                                  VOICEMMODE1_CALL_PCM_DEVICE},
+    [USECASE_VOICEMMODE2_CALL] = {VOICEMMODE2_CALL_PCM_DEVICE,
+                                  VOICEMMODE2_CALL_PCM_DEVICE},
+
     [USECASE_INCALL_REC_UPLINK] = {AUDIO_RECORD_PCM_DEVICE,
                                    AUDIO_RECORD_PCM_DEVICE},
     [USECASE_INCALL_REC_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE,
@@ -251,6 +262,9 @@
     [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence",
     [SND_DEVICE_IN_VOICE_REC_HEADSET_MIC] = "headset-mic",
 
+    [SND_DEVICE_IN_UNPROCESSED_MIC] = "unprocessed-mic",
+    [SND_DEVICE_IN_UNPROCESSED_HEADSET_MIC] = "headset-mic",
+
     [SND_DEVICE_IN_VOICE_RX] = "voice-rx",
 
     [SND_DEVICE_IN_THREE_MIC] = "three-mic",
@@ -311,7 +325,7 @@
     [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS] = 117,
     [SND_DEVICE_IN_SPEAKER_DMIC_STEREO] = 35,
 
-    [SND_DEVICE_IN_HEADSET_MIC] = 8,
+    [SND_DEVICE_IN_HEADSET_MIC] = ACDB_ID_HEADSET_MIC_AEC,
     [SND_DEVICE_IN_HEADSET_MIC_AEC] = ACDB_ID_HEADSET_MIC_AEC,
 
     [SND_DEVICE_IN_HDMI_MIC] = 4,
@@ -326,16 +340,19 @@
     [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11,
     [SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP] = 11,
     [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 43,
-    [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8,
+    [SND_DEVICE_IN_VOICE_HEADSET_MIC] = ACDB_ID_HEADSET_MIC_AEC,
     [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16,
     [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36,
     [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16,
 
-    [SND_DEVICE_IN_VOICE_REC_MIC] = 62,
+    [SND_DEVICE_IN_VOICE_REC_MIC] = ACDB_ID_VOICE_REC_MIC,
     [SND_DEVICE_IN_VOICE_REC_MIC_NS] = 113,
     [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = 35,
     [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 43,
-    [SND_DEVICE_IN_VOICE_REC_HEADSET_MIC] = 8,
+    [SND_DEVICE_IN_VOICE_REC_HEADSET_MIC] = ACDB_ID_HEADSET_MIC_AEC,
+
+    [SND_DEVICE_IN_UNPROCESSED_MIC] = ACDB_ID_VOICE_REC_MIC,
+    [SND_DEVICE_IN_UNPROCESSED_HEADSET_MIC] = ACDB_ID_HEADSET_MIC_AEC,
 
     [SND_DEVICE_IN_VOICE_RX] = 44,
 
@@ -430,6 +447,9 @@
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE)},
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_HEADSET_MIC)},
 
+    {TO_NAME_INDEX(SND_DEVICE_IN_UNPROCESSED_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_UNPROCESSED_HEADSET_MIC)},
+
     {TO_NAME_INDEX(SND_DEVICE_IN_THREE_MIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_QUAD_MIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)},
@@ -638,7 +658,7 @@
             platform_add_backend_name(adev->platform, my_data->ec_ref_mixer_path, snd_device);
         }
 
-        ALOGD("%s: enabling %s", __func__, my_data->ec_ref_mixer_path);
+        ALOGV("%s: enabling %s", __func__, my_data->ec_ref_mixer_path);
         audio_route_apply_and_update_path(adev->audio_route, my_data->ec_ref_mixer_path);
     }
 }
@@ -907,12 +927,16 @@
 void *platform_init(struct audio_device *adev)
 {
     char value[PROPERTY_VALUE_MAX];
-    struct platform_data *my_data;
-    int retry_num = 0, snd_card_num = 0;
-    bool dual_mic_config = false;
+    struct platform_data *my_data = NULL;
+    int retry_num = 0, snd_card_num = 0, key = 0, ret = 0;
+    bool dual_mic_config = false, use_default_mixer_path = true;
     const char *snd_card_name;
     char *cvd_version = NULL;
-
+    char *snd_internal_name = NULL;
+    char *tmp = NULL;
+    char mixer_xml_file[MIXER_PATH_MAX_LENGTH]= {0};
+    char platform_info_file[MIXER_PATH_MAX_LENGTH]= {0};
+    struct snd_card_split *snd_split_handle = NULL;
     my_data = calloc(1, sizeof(struct platform_data));
 
     my_data->adev = adev;
@@ -921,9 +945,6 @@
 
     set_platform_defaults(my_data);
 
-    /* Initialize platform specific ids and/or backends*/
-    platform_info_init(my_data);
-
     while (snd_card_num < MAX_SND_CARD) {
         adev->mixer = mixer_open(snd_card_num);
 
@@ -942,27 +963,94 @@
         }
 
         snd_card_name = mixer_get_name(adev->mixer);
+        my_data->hw_info = hw_info_init(snd_card_name);
 
-        /* validate the sound card name */
+        audio_extn_set_snd_card_split(snd_card_name);
+        snd_split_handle = audio_extn_get_snd_card_split();
+
+        /* Get the codec internal name from the sound card and/or form factor
+         * name and form the mixer paths and platfor info file name dynamically.
+         * This is generic way of picking any codec and forma factor name based
+         * mixer and platform info files in future with no code change.
+
+         * current code extends and looks for any of the exteneded mixer path and
+         * platform info file present based on codec and form factor.
+
+         * order of picking appropriate file is
+         * <i>   mixer_paths_<codec_name>_<form_factor>.xml, if file not present
+         * <ii>  mixer_paths_<codec_name>.xml, if file not present
+         * <iii> mixer_paths.xml
+
+         * same order is followed for audio_platform_info.xml as well
+         */
+
+        // need to carryforward old file name
+        if (!strncmp(snd_card_name, TOMTOM_8226_SND_CARD_NAME,
+                     min(strlen(TOMTOM_8226_SND_CARD_NAME), strlen(snd_card_name)))) {
+            snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s.xml",
+                             MIXER_XML_BASE_STRING, TOMTOM_MIXER_FILE_SUFFIX );
+        } else {
+
+            snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s_%s.xml",
+                             MIXER_XML_BASE_STRING, snd_split_handle->snd_card,
+                             snd_split_handle->form_factor);
+
+            if (F_OK != access(mixer_xml_file, 0)) {
+                memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
+                snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s.xml",
+                             MIXER_XML_BASE_STRING, snd_split_handle->snd_card);
+
+                if (F_OK != access(mixer_xml_file, 0)) {
+                    memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
+                    strlcpy(mixer_xml_file, MIXER_XML_DEFAULT_PATH, MIXER_PATH_MAX_LENGTH);
+                }
+            }
+
+            snprintf(platform_info_file, sizeof(platform_info_file), "%s_%s_%s.xml",
+                             PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card,
+                             snd_split_handle->form_factor);
+
+            if (F_OK != access(platform_info_file, 0)) {
+                memset(platform_info_file, 0, sizeof(platform_info_file));
+                snprintf(platform_info_file, sizeof(platform_info_file), "%s_%s.xml",
+                             PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card);
+
+                if (F_OK != access(platform_info_file, 0)) {
+                    memset(platform_info_file, 0, sizeof(platform_info_file));
+                    strlcpy(platform_info_file, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH);
+                }
+            }
+        }
+
+        /* Initialize platform specific ids and/or backends*/
+        platform_info_init(platform_info_file, my_data);
+
+        /* validate the sound card name
+         * my_data->snd_card_name can contain
+         *     <a> complete sound card name, i.e. <device>-<codec>-<form_factor>-snd-card
+         *         example: msm8994-tomtom-mtp-snd-card
+         *     <b> or sub string of the card name, i.e. <device>-<codec>
+         *         example: msm8994-tomtom
+         * snd_card_name is truncated to 32 charaters as per mixer_get_name() implementation
+         * so use min of my_data->snd_card_name and snd_card_name length for comparison
+         */
+
         if (my_data->snd_card_name != NULL &&
-                strncmp(snd_card_name, my_data->snd_card_name, MAX_SND_CARD_NAME_LEN) != 0) {
+                strncmp(snd_card_name, my_data->snd_card_name,
+                        min(strlen(snd_card_name), strlen(my_data->snd_card_name))) != 0) {
             ALOGI("%s: found valid sound card %s, but not primary sound card %s",
                    __func__, snd_card_name, my_data->snd_card_name);
             retry_num = 0;
             snd_card_num++;
+            hw_info_deinit(my_data->hw_info);
+            my_data->hw_info = NULL;
             continue;
         }
+        ALOGI("%s: found sound card %s, primary sound card expeted is %s",
+              __func__, snd_card_name, my_data->snd_card_name);
 
-        ALOGD("%s: snd_card_name: %s", __func__, snd_card_name);
-
-        if (!strncmp(snd_card_name, "msm8226-tomtom-snd-card",
-                     sizeof("msm8226-tomtom-snd-card"))) {
-            ALOGD("%s: Call MIXER_XML_PATH_WCD9330", __func__);
-            adev->audio_route = audio_route_init(snd_card_num,
-                                                 MIXER_XML_PATH_WCD9330);
-        } else {
-            adev->audio_route = audio_route_init(snd_card_num, MIXER_XML_PATH);
-        }
+        ALOGD("%s: Loading mixer file: %s", __func__, mixer_xml_file);
+        adev->audio_route = audio_route_init(snd_card_num, mixer_xml_file);
 
         if (!adev->audio_route) {
             ALOGE("%s: Failed to init audio route controls, aborting.", __func__);
@@ -1084,7 +1172,7 @@
             ALOGV("%s: Could not find the symbol acdb_loader_send_gain_dep_cal from %s",
                   __func__, LIB_ACDB_LOADER);
 
-#if defined (PLATFORM_MSM8994)
+#if defined (PLATFORM_MSM8994) || (PLATFORM_MSM8996)
         acdb_init_v2_cvd_t acdb_init;
         acdb_init = (acdb_init_v2_cvd_t)dlsym(my_data->acdb_handle,
                                               "acdb_loader_init_v2");
@@ -1098,7 +1186,7 @@
         if (!cvd_version)
             ALOGE("failed to allocate cvd_version");
         else
-            acdb_init((char *)snd_card_name, cvd_version);
+            acdb_init((char *)snd_card_name, cvd_version, 0);
         free(cvd_version);
 #elif defined (PLATFORM_MSM8084)
         acdb_init_v2_t acdb_init;
@@ -1147,6 +1235,8 @@
     struct platform_data *my_data = (struct platform_data *)platform;
     close_csd_client(my_data->csd);
 
+    hw_info_deinit(my_data->hw_info);
+
     for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
         if (backend_tag_table[dev])
             free(backend_tag_table[dev]);
@@ -1191,6 +1281,29 @@
         return "none";
 }
 
+int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device,
+                                      char *device_name)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (platform == NULL || device_name == NULL) {
+        ALOGW("%s: something wrong, use legacy get_snd_device name", __func__);
+        device_name = platform_get_snd_device_name(snd_device);
+    } else if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) {
+        if (operator_specific_device_table[snd_device] != NULL) {
+            strlcpy(device_name, get_operator_specific_device_mixer_path(snd_device),
+                    DEVICE_NAME_MAX_SIZE);
+        } else {
+            strlcpy(device_name, device_table[snd_device], DEVICE_NAME_MAX_SIZE);
+        }
+        hw_info_append_hw_type(my_data->hw_info, snd_device, device_name);
+    } else {
+        strlcpy(device_name, "none", DEVICE_NAME_MAX_SIZE);
+    }
+
+    return 0;
+}
+
 void platform_add_backend_name(void *platform, char *mixer_path,
                                snd_device_t snd_device)
 {
@@ -1311,7 +1424,7 @@
 
     list_add_tail(operator_specific_device_table[snd_device], &device->list);
 
-    ALOGD("%s : deivce[%s] -> operator[%s] mixer_path[%s] acdb_id [%d]", __func__,
+    ALOGD("%s: device[%s] -> operator[%s] mixer_path[%s] acdb_id[%d]", __func__,
             platform_get_snd_device_name(snd_device), operator, mixer_path, acdb_id);
 
 }
@@ -1359,7 +1472,7 @@
         return -EINVAL;
     }
     if (my_data->acdb_send_audio_cal) {
-        ALOGD("%s: sending audio calibration for snd_device(%d) acdb_id(%d)",
+        ALOGV("%s: sending audio calibration for snd_device(%d) acdb_id(%d)",
               __func__, snd_device, acdb_dev_id);
         if (snd_device >= SND_DEVICE_OUT_BEGIN &&
                 snd_device < SND_DEVICE_OUT_END)
@@ -1968,8 +2081,14 @@
         } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
             snd_device = SND_DEVICE_IN_VOICE_REC_HEADSET_MIC;
         }
+    } else if (source == AUDIO_SOURCE_UNPROCESSED) {
+        if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            snd_device = SND_DEVICE_IN_UNPROCESSED_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+            snd_device = SND_DEVICE_IN_UNPROCESSED_HEADSET_MIC;
+        }
     } else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
-            mode == AUDIO_MODE_IN_COMMUNICATION) {
+               mode == AUDIO_MODE_IN_COMMUNICATION) {
         if (out_device & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE))
             in_device = AUDIO_DEVICE_IN_BACK_MIC;
         if (adev->active_input) {
@@ -2356,7 +2475,7 @@
         info->mccmnc = strdup(str + strlen(name) + 1);
 
         list_add_tail(&operator_info_list, &info->list);
-        ALOGD("%s: add operator[%s] mccmnc[%s]", __func__, info->name, info->mccmnc);
+        ALOGV("%s: add operator[%s] mccmnc[%s]", __func__, info->name, info->mccmnc);
     }
 
     memset(value, 0, sizeof(value));
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index dcd763a..53474f6 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 The Android Open Source Project
+ * Copyright (C) 2013-2016 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.
@@ -132,6 +132,9 @@
     SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
     SND_DEVICE_IN_VOICE_REC_HEADSET_MIC,
 
+    SND_DEVICE_IN_UNPROCESSED_MIC,
+    SND_DEVICE_IN_UNPROCESSED_HEADSET_MIC,
+
     SND_DEVICE_IN_VOICE_RX,
 
     SND_DEVICE_IN_THREE_MIC,
@@ -146,6 +149,9 @@
 
 };
 
+#define DEVICE_NAME_MAX_SIZE   128
+#define HW_INFO_ARRAY_MAX_SIZE 32
+
 #define DEFAULT_OUTPUT_SAMPLING_RATE 48000
 
 #define ALL_SESSION_VSID                0xFFFFFFFF
@@ -158,6 +164,7 @@
 #define ACDB_ID_VOICE_HANDSET_TMUS 88
 #define ACDB_ID_VOICE_DMIC_EF_TMUS 89
 #define ACDB_ID_HEADSET_MIC_AEC 8
+#define ACDB_ID_VOICE_REC_MIC 62
 
 #define MAX_VOL_INDEX 5
 #define MIN_VOL_INDEX 0
@@ -218,6 +225,12 @@
 #define VOLTE_CALL_PCM_DEVICE 21
 #define QCHAT_CALL_PCM_DEVICE 33
 #define VOWLAN_CALL_PCM_DEVICE -1
+#elif PLATFORM_MSM8996
+#define VOICE_CALL_PCM_DEVICE 40
+#define VOICE2_CALL_PCM_DEVICE 41
+#define VOLTE_CALL_PCM_DEVICE 14
+#define QCHAT_CALL_PCM_DEVICE 20
+#define VOWLAN_CALL_PCM_DEVICE 33
 #else
 #define VOICE_CALL_PCM_DEVICE 2
 #define VOICE2_CALL_PCM_DEVICE 22
@@ -226,6 +239,14 @@
 #define VOWLAN_CALL_PCM_DEVICE 36
 #endif
 
+#ifdef PLATFORM_MSM8996
+#define VOICEMMODE1_CALL_PCM_DEVICE 2
+#define VOICEMMODE2_CALL_PCM_DEVICE 22
+#else
+#define VOICEMMODE1_CALL_PCM_DEVICE 44
+#define VOICEMMODE2_CALL_PCM_DEVICE 45
+#endif
+
 #define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
 #define AFE_PROXY_RECORD_PCM_DEVICE 8
 
@@ -285,4 +306,6 @@
     get_sample_rate_t get_sample_rate;
 };
 
+#define PLATFORM_INFO_XML_PATH          "/system/etc/audio_platform_info.xml"
+#define PLATFORM_INFO_XML_BASE_STRING   "/system/etc/audio_platform_info"
 #endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 1e41358..9bd55b1 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -20,6 +20,8 @@
 void *platform_init(struct audio_device *adev);
 void platform_deinit(void *platform);
 const char *platform_get_snd_device_name(snd_device_t snd_device);
+int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device,
+                                      char *device_name);
 void platform_add_backend_name(void *platform, char *mixer_path,
                                                     snd_device_t snd_device);
 bool platform_send_gain_dep_cal(void *platform, int level);
@@ -69,7 +71,7 @@
                                     const char * hw_interface);
 
 /* From platform_info.c */
-int platform_info_init(void *);
+int platform_info_init(const char *filename, void *);
 
 int platform_get_usecase_index(const char * usecase);
 int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id);
diff --git a/hal/platform_info.c b/hal/platform_info.c
index 4556294..7432230 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -25,8 +25,6 @@
 #include "platform_api.h"
 #include <platform.h>
 
-#define PLATFORM_INFO_XML_PATH      "/system/etc/audio_platform_info.xml"
-
 typedef enum {
     ROOT,
     ACDB,
@@ -344,7 +342,7 @@
     }
 }
 
-int platform_info_init(void *platform)
+int platform_info_init(const char *filename, void *platform)
 {
     XML_Parser      parser;
     FILE            *file;
@@ -352,13 +350,22 @@
     int             bytes_read;
     void            *buf;
     static const uint32_t kBufSize = 1024;
-
+    char   platform_info_file_name[MIXER_PATH_MAX_LENGTH]= {0};
     section = ROOT;
 
-    file = fopen(PLATFORM_INFO_XML_PATH, "r");
+    if (filename == NULL) {
+        strlcpy(platform_info_file_name, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH);
+    } else {
+        strlcpy(platform_info_file_name, filename, MIXER_PATH_MAX_LENGTH);
+    }
+
+    ALOGV("%s: platform info file name is %s", __func__, platform_info_file_name);
+
+    file = fopen(platform_info_file_name, "r");
+
     if (!file) {
         ALOGD("%s: Failed to open %s, using defaults.",
-            __func__, PLATFORM_INFO_XML_PATH);
+            __func__, platform_info_file_name);
         ret = -ENODEV;
         goto done;
     }
@@ -393,7 +400,7 @@
         if (XML_ParseBuffer(parser, bytes_read,
                             bytes_read == 0) == XML_STATUS_ERROR) {
             ALOGE("%s: XML_ParseBuffer failed, for %s",
-                __func__, PLATFORM_INFO_XML_PATH);
+                __func__, platform_info_file_name);
             ret = -EINVAL;
             goto err_free_parser;
         }
diff --git a/hal/voice.h b/hal/voice.h
index 23b9ee3..469a3b5 100644
--- a/hal/voice.h
+++ b/hal/voice.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2014-2016 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.
@@ -21,7 +21,7 @@
 #define VOICE_SESS_IDX     (BASE_SESS_IDX)
 
 #ifdef MULTI_VOICE_SESSION_ENABLED
-#define MAX_VOICE_SESSIONS 5
+#define MAX_VOICE_SESSIONS 7
 #else
 #define MAX_VOICE_SESSIONS 1
 #endif
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
index 6e92da8..edf5523 100644
--- a/hal/voice_extn/voice_extn.c
+++ b/hal/voice_extn/voice_extn.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2014-2016 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.
@@ -41,17 +41,21 @@
 
 #define VOICE_EXTN_PARAMETER_VALUE_MAX_LEN 256
 
-#define VOICE2_VSID 0x10DC1000
-#define VOLTE_VSID  0x10C02000
-#define QCHAT_VSID  0x10803000
-#define VOWLAN_VSID 0x10002000
-#define ALL_VSID    0xFFFFFFFF
+#define VOICE2_VSID              0x10DC1000
+#define VOLTE_VSID               0x10C02000
+#define QCHAT_VSID               0x10803000
+#define VOWLAN_VSID              0x10002000
+#define VOICEMMODE1_VSID         0x11C05000
+#define VOICEMMODE2_VSID         0x11DC5000
+#define ALL_VSID                 0xFFFFFFFF
 
 /* Voice Session Indices */
 #define VOICE2_SESS_IDX    (VOICE_SESS_IDX + 1)
 #define VOLTE_SESS_IDX     (VOICE_SESS_IDX + 2)
 #define QCHAT_SESS_IDX     (VOICE_SESS_IDX + 3)
 #define VOWLAN_SESS_IDX    (VOICE_SESS_IDX + 4)
+#define MMODE1_SESS_IDX    (VOICE_SESS_IDX + 5)
+#define MMODE2_SESS_IDX    (VOICE_SESS_IDX + 6)
 
 /* Call States */
 #define CALL_HOLD           (BASE_CALL_STATE + 2)
@@ -84,6 +88,8 @@
         vsid == VOICE2_VSID ||
         vsid == VOLTE_VSID ||
         vsid == QCHAT_VSID ||
+        vsid == VOICEMMODE1_VSID ||
+        vsid == VOICEMMODE2_VSID ||
         vsid == VOWLAN_VSID)
         return true;
     else
@@ -115,6 +121,14 @@
         usecase_id = USECASE_VOWLAN_CALL;
         break;
 
+    case MMODE1_SESS_IDX:
+        usecase_id = USECASE_VOICEMMODE1_CALL;
+        break;
+
+    case MMODE2_SESS_IDX:
+        usecase_id = USECASE_VOICEMMODE2_CALL;
+        break;
+
     default:
         ALOGE("%s: Invalid voice session index\n", __func__);
     }
@@ -356,6 +370,8 @@
     adev->voice.session[VOLTE_SESS_IDX].vsid =  VOLTE_VSID;
     adev->voice.session[QCHAT_SESS_IDX].vsid =  QCHAT_VSID;
     adev->voice.session[VOWLAN_SESS_IDX].vsid = VOWLAN_VSID;
+    adev->voice.session[MMODE1_SESS_IDX].vsid = VOICEMMODE1_VSID;
+    adev->voice.session[MMODE2_SESS_IDX].vsid = VOICEMMODE2_VSID;
 }
 
 int voice_extn_get_session_from_use_case(struct audio_device *adev,
@@ -385,6 +401,14 @@
         *session = &adev->voice.session[VOWLAN_SESS_IDX];
         break;
 
+    case USECASE_VOICEMMODE1_CALL:
+        *session = &adev->voice.session[MMODE1_SESS_IDX];
+        break;
+
+    case USECASE_VOICEMMODE2_CALL:
+        *session = &adev->voice.session[MMODE2_SESS_IDX];
+        break;
+
     default:
         ALOGE("%s: Invalid usecase_id:%d\n", __func__, usecase_id);
         *session = NULL;
diff --git a/post_proc/Android.mk b/post_proc/Android.mk
index b8aa9fc..1a8550c 100644
--- a/post_proc/Android.mk
+++ b/post_proc/Android.mk
@@ -1,4 +1,4 @@
-ifneq ($(filter msm8974 msm8226 msm8084 msm8992 msm8994,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8974 msm8226 msm8084 msm8992 msm8994 msm8996,$(TARGET_BOARD_PLATFORM)),)
 
 LOCAL_PATH:= $(call my-dir)
 
@@ -33,7 +33,7 @@
 
 ################################################################################
 
-ifneq ($(filter msm8992 msm8994,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8992 msm8994 msm8996,$(TARGET_BOARD_PLATFORM)),)
 
 include $(CLEAR_VARS)
 
diff --git a/post_proc/volume_listener.c b/post_proc/volume_listener.c
index ef63299..107a475 100644
--- a/post_proc/volume_listener.c
+++ b/post_proc/volume_listener.c
@@ -346,9 +346,6 @@
             memcpy(out_buffer->raw, in_buffer->raw, out_buffer->frameCount * 2 * sizeof(int16_t));
         }
 
-    } else {
-        ALOGW("%s: something wrong, didn't handle in_buffer and out_buffer same address case",
-              __func__);
     }
 
 exit: