Promotion of audio-userspace.lnx.2.2-00019.

CRs      Change ID                                   Subject
--------------------------------------------------------------------------------------------------------------
1081424   I2877239e61d3841e6ae90af2d39fb0b93cc2b6db   audio: Changes to support Aptx decoder in offload mode
1116977   I62193c26731f115695cff4386b96917b672eeec6   hal: audio: correct ANC headphone path
1111827   I217f72be4471fbe998f7d684b3c08399729725a3   hal: parse wav header based on chunksize
1081424   Ia287a27c86f63fea16cdb35d553de6e2e853b4e9   audio: Add support for multiple metainfo keys update
1081424   Ie7913d5a0b0091ce50d9066b7d85100e7f884f83   qahw: test: Add support to test aptx decoder
1071692   I326cb9e906268566ecc4a7639804f06585b4004b   hal: audio: Add support to pick 32KHz and 144KHz samplin

Change-Id: Ic126658515dc6436c23e51f366f0f1f82141ca77
CRs-Fixed: 1071692, 1111827, 1116977, 1081424
diff --git a/configs/msm8998/audio_platform_info.xml b/configs/msm8998/audio_platform_info.xml
index 3bc8c11..d6ac0d5 100644
--- a/configs/msm8998/audio_platform_info.xml
+++ b/configs/msm8998/audio_platform_info.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="ISO-8859-1"?>
-<!-- Copyright (c) 2014, 2016, The Linux Foundation. All rights reserved.   -->
+<!-- Copyright (c) 2014, 2016-2017, The Linux Foundation. All rights reserved.   -->
 <!--                                                                        -->
 <!-- Redistribution and use in source and binary forms, with or without     -->
 <!-- modification, are permitted provided that the following conditions are -->
@@ -95,11 +95,14 @@
         <device name="SND_DEVICE_OUT_BT_A2DP" backend="bt-a2dp" interface="SLIMBUS_7_RX"/>
         <device name="SND_DEVICE_OUT_LINE" backend="headphones" interface="SLIMBUS_6_RX"/>
         <device name="SND_DEVICE_OUT_ANC_HEADSET" backend="headphones" interface="SLIMBUS_6_RX"/>
+        <device name="SND_DEVICE_OUT_ANC_FB_HEADSET" backend="headphones" interface="SLIMBUS_6_RX"/>
         <device name="SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES" backend="speaker-and-headphones" interface="SLIMBUS_0_RX-and-SLIMBUS_6_RX"/>
         <device name="SND_DEVICE_OUT_SPEAKER_AND_LINE" backend="speaker-and-headphones" interface="SLIMBUS_0_RX-and-SLIMBUS_6_RX"/>
         <device name="SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET" backend="speaker-and-headphones" interface="SLIMBUS_0_RX-and-SLIMBUS_6_RX"/>
+        <device name="SND_DEVICE_OUT_SPEAKER_AND_ANC_FB_HEADSET" backend="speaker-and-headphones" interface="SLIMBUS_0_RX-and-SLIMBUS_6_RX"/>
         <device name="SND_DEVICE_OUT_VOICE_HEADPHONES" backend="headphones" interface="SLIMBUS_6_RX"/>
         <device name="SND_DEVICE_OUT_VOICE_ANC_HEADSET" backend="headphones" interface="SLIMBUS_6_RX"/>
+        <device name="SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET" backend="headphones" interface="SLIMBUS_6_RX"/>
         <device name="SND_DEVICE_OUT_VOICE_LINE" backend="headphones" interface="SLIMBUS_6_RX"/>
         <device name="SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES" backend="headphones" interface="SLIMBUS_6_RX"/>
         <device name="SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES" backend="headphones" interface="SLIMBUS_6_RX"/>
diff --git a/configs/msm8998/mixer_paths_tavil.xml b/configs/msm8998/mixer_paths_tavil.xml
index b2c6fd9..7fbef34 100644
--- a/configs/msm8998/mixer_paths_tavil.xml
+++ b/configs/msm8998/mixer_paths_tavil.xml
@@ -347,8 +347,8 @@
     <ctl name="RX7 Digital Volume" value="84" />
     <ctl name="ADC1 Volume" value="12" />
     <ctl name="ADC2 Volume" value="12" />
-    <ctl name="ADC3 Volume" value="12" />
-    <ctl name="ADC4 Volume" value="12" />
+    <ctl name="ADC3 Volume" value="0" />
+    <ctl name="ADC4 Volume" value="0" />
     <ctl name="DEC0 Volume" value="84" />
     <ctl name="DEC1 Volume" value="84" />
     <ctl name="DEC2 Volume" value="84" />
@@ -406,6 +406,7 @@
     <ctl name="AMIC MUX12" value="ZERO" />
     <ctl name="AMIC MUX13" value="ZERO" />
 
+    <ctl name="AMIC4_5 SEL" value="AMIC4" />
     <!-- CDC_IF and SLIM controls -->
     <ctl name="SLIM RX0 MUX" value="ZERO" />
     <ctl name="SLIM RX1 MUX" value="ZERO" />
@@ -525,6 +526,8 @@
     <ctl name="ANC OUT EAR Enable Switch" value="0" />
     <ctl name="ANC OUT EAR SPKR Enable Switch" value="0" />
     <ctl name="ANC SPKR PA Enable Switch" value="0" />
+    <ctl name="ANC OUT HPHL Enable Switch" value="0" />
+    <ctl name="ANC OUT HPHR Enable Switch" value="0" />
 
     <!-- vbat related data -->
     <!-- vbat related data end -->
@@ -2145,7 +2148,27 @@
     </path>
 
     <path name="anc-headphones">
-        <path name="headphones" />
+        <ctl name="COMP1 Switch" value="0" />
+        <ctl name="COMP2 Switch" value="0" />
+        <ctl name="ANC Function" value="ON" />
+        <ctl name="ANC Slot" value="0" />
+        <ctl name="SLIM RX2 MUX" value="AIF4_PB" />
+        <ctl name="SLIM RX3 MUX" value="AIF4_PB" />
+        <ctl name="SLIM_6_RX Channels" value="Two" />
+        <ctl name="ADC MUX10" value="AMIC" />
+        <ctl name="AMIC MUX10" value="ADC3" />
+        <ctl name="ADC MUX12" value="AMIC" />
+        <ctl name="AMIC MUX12" value="ADC4" />
+        <ctl name="ANC0 FB MUX" value="ANC_IN_HPHL" />
+        <ctl name="ANC1 FB MUX" value="ANC_IN_HPHR" />
+        <ctl name="ADC3 Volume" value="8" />
+        <ctl name="ADC4 Volume" value="8" />
+        <ctl name="RX INT1_1 MIX1 INP0" value="RX2" />
+        <ctl name="RX INT2_1 MIX1 INP0" value="RX3" />
+        <ctl name="RX1 Digital Volume" value="81" />
+        <ctl name="RX2 Digital Volume" value="81" />
+        <ctl name="ANC OUT HPHL Enable Switch" value="1" />
+        <ctl name="ANC OUT HPHR Enable Switch" value="1" />
     </path>
 
     <path name="speaker-and-anc-headphones">
@@ -2155,6 +2178,7 @@
 
     <path name="anc-fb-headphones">
         <path name="anc-headphones" />
+        <ctl name="ANC Slot" value="1" />
     </path>
 
     <path name="speaker-and-anc-fb-headphones">
@@ -2163,11 +2187,11 @@
     </path>
 
     <path name="voice-anc-headphones">
-        <path name="voice-headphones" />
+        <path name="anc-headphones" />
     </path>
 
     <path name="voice-anc-fb-headphones">
-        <path name="voice-headphones" />
+        <path name="anc-fb-headphones" />
     </path>
 
     <path name="speaker-and-anc-headphones-liquid">
diff --git a/configure.ac b/configure.ac
index 694697c..16544a3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -106,6 +106,7 @@
 AM_CONDITIONAL([COMPRESS_PASSTHROUGH], [test x$AUDIO_FEATURE_ENABLED_HDMI_PASSTHROUGH = xtrue])
 AM_CONDITIONAL([KEEP_ALIVE], [test x$AUDIO_FEATURE_ENABLED_KEEP_ALIVE = xtrue])
 AM_CONDITIONAL([GEF], [test x$AUDIO_FEATURE_ENABLED_GEF_SUPPORT = xtrue])
+AM_CONDITIONAL([APTX_DECODER], [test x$AUDIO_FEATURE_ENABLED_APTX_DECODER = xtrue])
 
 AC_CONFIG_FILES([ \
         Makefile \
diff --git a/hal/Makefile.am b/hal/Makefile.am
index ba53446..e72d350 100644
--- a/hal/Makefile.am
+++ b/hal/Makefile.am
@@ -148,6 +148,10 @@
 c_sources += audio_extn/gef.c
 endif
 
+if APTX_DECODER
+AM_CFLAGS += -DAPTX_DECODER_ENABLED
+endif
+
 h_sources = audio_extn/audio_defs.h \
             audio_extn/audio_extn.h \
             audio_hw.h \
diff --git a/hal/audio_extn/audio_defs.h b/hal/audio_extn/audio_defs.h
index 94b43ba..ae90cb3 100644
--- a/hal/audio_extn/audio_defs.h
+++ b/hal/audio_extn/audio_defs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -128,14 +128,26 @@
     uint16_t  gain_step;
 };
 
+struct aptx_dec_bt_addr {
+    uint32_t nap;
+    uint32_t uap;
+    uint32_t lap;
+};
+
+struct aptx_dec_param {
+   struct aptx_dec_bt_addr bt_addr;
+};
+
 typedef union {
     struct source_tracking_param st_params;
     struct sound_focus_param sf_params;
+    struct aptx_dec_param aptx_params;
 } audio_extn_param_payload;
 
 typedef enum {
     AUDIO_EXTN_PARAM_SOURCE_TRACK,
-    AUDIO_EXTN_PARAM_SOUND_FOCUS
+    AUDIO_EXTN_PARAM_SOUND_FOCUS,
+    AUDIO_EXTN_PARAM_APTX_DEC
 } audio_extn_param_id;
 
 #endif /* AUDIO_DEFS_H */
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index d2e5434..5a244e5 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -66,6 +66,7 @@
     bool vbat_enabled;
     bool hifi_audio_enabled;
     bool ras_enabled;
+    struct aptx_dec_bt_addr addr;
 };
 
 static struct audio_extn_module aextnmod;
@@ -77,6 +78,7 @@
 /* Query offload playback instances count */
 #define AUDIO_PARAMETER_OFFLOAD_NUM_ACTIVE "offload_num_active"
 #define AUDIO_PARAMETER_HPX            "HPX"
+#define AUDIO_PARAMETER_APTX_DEC_BT_ADDR "bt_addr"
 
 /*
 * update sysfs node hdmi_audio_cb to enable notification acknowledge feature
@@ -762,7 +764,7 @@
     return ret;
 }
 
-void audio_extn_init(void)
+void audio_extn_init(struct audio_device *adev)
 {
     aextnmod.anc_enabled = 0;
     aextnmod.aanc_enabled = 0;
@@ -771,6 +773,12 @@
     aextnmod.hpx_enabled = 0;
     aextnmod.vbat_enabled = 0;
     aextnmod.hifi_audio_enabled = 0;
+    aextnmod.addr.nap = 0;
+    aextnmod.addr.uap = 0;
+    aextnmod.addr.lap = 0;
+
+    audio_extn_dolby_set_license(adev);
+    audio_extn_aptx_dec_set_license(adev);
 }
 
 void audio_extn_set_parameters(struct audio_device *adev,
@@ -798,6 +806,7 @@
    audio_extn_qaf_set_parameters(adev, parms);
    if (adev->offload_effects_set_parameters != NULL)
        adev->offload_effects_set_parameters(parms);
+   audio_extn_set_aptx_dec_bt_addr(adev, parms);
 }
 
 void audio_extn_get_parameters(const struct audio_device *adev,
@@ -1217,3 +1226,83 @@
                                                 update_params);
     }
 }
+
+#ifdef APTX_DECODER_ENABLED
+static void audio_extn_aptx_dec_set_license(struct audio_device *adev)
+{
+    int ret, key = 0;
+    char value[128] = {0};
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "APTX Dec License";
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return;
+    }
+    key = platform_get_meta_info_key_from_list(adev->platform, "aptx");
+
+    ALOGD("%s Setting APTX License with key:0x%x",__func__, key);
+    ret = mixer_ctl_set_value(ctl, 0, key);
+    if (ret)
+        ALOGE("%s: cannot set license, error:%d",__func__, ret);
+}
+
+static void audio_extn_set_aptx_dec_bt_addr(struct audio_device *adev, struct str_parms *parms)
+{
+    int ret = 0;
+    char value[256];
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_APTX_DEC_BT_ADDR, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        audio_extn_parse_aptx_dec_bt_addr(value);
+    }
+}
+
+int audio_extn_set_aptx_dec_params(struct aptx_dec_param *payload)
+{
+    struct aptx_dec_param *aptx_cfg = payload;
+
+    aextnmod.addr.nap = aptx_cfg->bt_addr.nap;
+    aextnmod.addr.uap = aptx_cfg->bt_addr.uap;
+    aextnmod.addr.lap = aptx_cfg->bt_addr.lap;
+}
+
+static void audio_extn_parse_aptx_dec_bt_addr(char *value)
+{
+    int ba[6];
+    char *str, *tok;
+    uint32_t addr[3];
+    int i = 0;
+
+    ALOGV("%s: value %s", __func__, value);
+    tok = strtok_r(value, ":", &str);
+    while (tok != NULL) {
+        ba[i] = strtol(tok, NULL, 16);
+        i++;
+        tok = strtok_r(NULL, ":", &str);
+    }
+    addr[0] = (ba[0] << 8) | ba[1];
+    addr[1] = ba[2];
+    addr[2] = (ba[3] << 16) | (ba[4] << 8) | ba[5];
+
+    aextnmod.addr.nap = addr[0];
+    aextnmod.addr.uap = addr[1];
+    aextnmod.addr.lap = addr[2];
+}
+
+void audio_extn_send_aptx_dec_bt_addr_to_dsp(struct stream_out *out)
+{
+    char mixer_ctl_name[128];
+    struct mixer_ctl *ctl;
+    uint32_t addr[3];
+
+    ALOGV("%s", __func__);
+    out->compr_config.codec->options.aptx_dec.nap = aextnmod.addr.nap;
+    out->compr_config.codec->options.aptx_dec.uap = aextnmod.addr.uap;
+    out->compr_config.codec->options.aptx_dec.lap = aextnmod.addr.lap;
+}
+
+#endif //APTX_DECODER_ENABLED
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 9a2f825..dab53ed 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -531,7 +531,7 @@
 void audio_extn_pm_unvote(void);
 #endif
 
-void audio_extn_init(void);
+void audio_extn_init(struct audio_device *adev);
 void audio_extn_utils_update_streams_cfg_lists(void *platform,
                                   struct mixer *mixer,
                                   struct listnode *streams_output_cfg_list,
@@ -801,4 +801,18 @@
                                    struct sound_focus_param *payload);
 #endif
 
+#ifndef APTX_DECODER_ENABLED
+#define audio_extn_aptx_dec_set_license(adev); (0)
+#define audio_extn_set_aptx_dec_bt_addr(adev, parms); (0)
+#define audio_extn_send_aptx_dec_bt_addr_to_dsp(out); (0)
+#define audio_extn_parse_aptx_dec_bt_addr(value); (0)
+#define audio_extn_set_aptx_dec_params(payload); (0)
+#else
+static void audio_extn_aptx_dec_set_license(struct audio_device *adev);
+static void audio_extn_set_aptx_dec_bt_addr(struct audio_device *adev, struct str_parms *parms);
+void audio_extn_send_aptx_dec_bt_addr_to_dsp(struct stream_out *out);
+static void audio_extn_parse_aptx_dec_bt_addr(char *value);
+int audio_extn_set_aptx_dec_params(struct aptx_dec_param *payload);
+#endif
+
 #endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c
index b958bf6..fee0543 100644
--- a/hal/audio_extn/dolby.c
+++ b/hal/audio_extn/dolby.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2010 The Android Open Source Project
@@ -445,7 +445,6 @@
 void audio_extn_dolby_set_license(struct audio_device *adev)
 {
     int ret, key=0;
-    char value[128] = {0};
     struct mixer_ctl *ctl;
     const char *mixer_ctl_name = "DS1 License";
 
@@ -456,9 +455,8 @@
         return;
     }
 
-    property_get("audio.ds1.metainfo.key",value,"0");
 #ifdef DOLBY_ACDB_LICENSE
-    key = atoi(value);
+    key = platform_get_meta_info_key_from_list(adev->platform, "dolby");
 #else
     key = 0;
 #endif
@@ -598,14 +596,12 @@
 void audio_extn_dolby_set_license(struct audio_device *adev __unused)
 {
     int i_key=0;
-    char c_key[128] = {0};
     char c_dmid[128] = {0};
     int i_dmid;
     struct dolby_param_license dolby_license;
 
 #ifdef DOLBY_ACDB_LICENSE
-    property_get("audio.ds1.metainfo.key",c_key,"0");
-    i_key = atoi(c_key);
+    i_key = platform_get_meta_info_key_from_list(adev->platform, "dolby");
 #else
     /* As ACDB based license mechanism is disabled, force set the license key to 0*/
     i_key = 0;
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 17fe4c9..7a4a0ed 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -151,6 +151,7 @@
     STRING_TO_ENUM(AUDIO_FORMAT_AAC_LATM_LC),
     STRING_TO_ENUM(AUDIO_FORMAT_AAC_LATM_HE_V1),
     STRING_TO_ENUM(AUDIO_FORMAT_AAC_LATM_HE_V2),
+    STRING_TO_ENUM(AUDIO_FORMAT_APTX),
 #endif
 };
 
@@ -1160,6 +1161,9 @@
     case AUDIO_FORMAT_DSD:
         id = SND_AUDIOCODEC_DSD;
         break;
+    case AUDIO_FORMAT_APTX:
+        id = SND_AUDIOCODEC_APTX;
+        break;
     default:
         ALOGE("%s: Unsupported audio format :%x", __func__, format);
     }
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 71c05df..dc933d3 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -521,7 +521,8 @@
         format == AUDIO_FORMAT_DSD ||
         format == AUDIO_FORMAT_VORBIS ||
         format == AUDIO_FORMAT_WMA ||
-        format == AUDIO_FORMAT_WMA_PRO)
+        format == AUDIO_FORMAT_WMA_PRO ||
+        format == AUDIO_FORMAT_APTX)
            return true;
 
     return false;
@@ -3986,7 +3987,11 @@
         out->compr_config.codec->ch_in =
                 audio_channel_count_from_out_mask(out->channel_mask);
         out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
-        out->bit_width = AUDIO_OUTPUT_BIT_WIDTH;
+        /* Update bit width only for non passthrough usecases.
+         * For passthrough usecases, the output will always be opened @16 bit
+         */
+        if (!audio_extn_passthru_is_passthrough_stream(out))
+            out->bit_width = AUDIO_OUTPUT_BIT_WIDTH;
         /*TODO: Do we need to change it for passthrough */
         out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
 
@@ -4052,6 +4057,10 @@
         if (config->offload_info.format == AUDIO_FORMAT_FLAC)
             out->compr_config.codec->options.flac_dec.sample_size = AUDIO_OUTPUT_BIT_WIDTH;
 
+        if (config->offload_info.format == AUDIO_FORMAT_APTX) {
+            audio_extn_send_aptx_dec_bt_addr_to_dsp(out);
+        }
+
         if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
             out->non_blocking = 1;
 
@@ -5069,7 +5078,7 @@
                                                         "visualizer_hal_stop_output");
         }
     }
-    audio_extn_init();
+    audio_extn_init(adev);
     audio_extn_listen_init(adev, adev->snd_card);
     audio_extn_sound_trigger_init(adev);
     audio_extn_gef_init(adev);
diff --git a/hal/audio_hw_extn_api.c b/hal/audio_hw_extn_api.c
index 39d81fb..f36d85d 100644
--- a/hal/audio_hw_extn_api.c
+++ b/hal/audio_hw_extn_api.c
@@ -104,6 +104,9 @@
               ret = audio_extn_set_soundfocus_data(dev,
                      (struct sound_focus_param *)payload);
               break;
+        case AUDIO_EXTN_PARAM_APTX_DEC:
+              audio_extn_set_aptx_dec_params((struct aptx_dec_param *)payload);
+              break;
        default:
              ALOGE("%s::INVALID PARAM ID:%d\n",__func__,param_id);
              ret = -EINVAL;
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index d9c7642..fad2c04 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -38,6 +38,8 @@
 #include "sound/msmcal-hwdep.h"
 #include <dirent.h>
 #include <linux/msm_audio.h>
+#include "linux/msm_audio_calibration.h"
+
 #define SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID (100)
 #define MAX_MIXER_XML_PATH  100
 #define MIXER_XML_PATH_QRD_SKUH "/system/etc/mixer_paths_qrd_skuh.xml"
@@ -212,6 +214,7 @@
 /* Audio calibration related functions */
 typedef void (*acdb_deallocate_t)();
 typedef int  (*acdb_init_t)(const char *, char *, int);
+typedef int  (*acdb_init_v3_t)(const char *, char *, struct listnode *);
 typedef void (*acdb_send_audio_cal_t)(int, int, int , int);
 typedef void (*acdb_send_voice_cal_t)(int, int);
 typedef int (*acdb_reload_vocvoltable_t)(int);
@@ -224,6 +227,7 @@
 typedef int (*acdb_set_codec_data_t) (void *, char *);
 typedef int (*acdb_reload_t) (char *, char *, char *, int);
 typedef int (*acdb_send_gain_dep_cal_t)(int, int, int, int, int);
+typedef int (*acdb_reload_v2_t) (char *, char *, char *, struct listnode *);
 
 typedef struct codec_backend_cfg {
     uint32_t sample_rate;
@@ -237,6 +241,12 @@
 static native_audio_prop na_props = {0, 0, 0};
 static bool supports_true_32_bit = false;
 
+struct meta_key_list {
+    struct listnode list;
+    struct audio_cal_info_metainfo cal_info;
+    char name[ACDB_METAINFO_KEY_MODULE_NAME_LEN];
+};
+
 struct platform_data {
     struct audio_device *adev;
     bool fluence_in_spkr_mode;
@@ -263,6 +273,7 @@
     void                       *acdb_handle;
     int                        voice_feature_set;
     acdb_init_t                acdb_init;
+    acdb_init_v3_t             acdb_init_v3;
     acdb_deallocate_t          acdb_deallocate;
     acdb_send_audio_cal_t      acdb_send_audio_cal;
     acdb_set_audio_cal_t       acdb_set_audio_cal;
@@ -273,6 +284,7 @@
     acdb_send_common_top_t     acdb_send_common_top;
     acdb_set_codec_data_t      acdb_set_codec_data;
     acdb_reload_t              acdb_reload;
+    acdb_reload_v2_t           acdb_reload_v2;
 #ifdef RECORD_PLAY_CONCURRENCY
     bool rec_play_conc_set;
 #endif
@@ -288,11 +300,11 @@
     int hw_dep_fd;
     char cvd_version[MAX_CVD_VERSION_STRING_SIZE];
     char snd_card_name[MAX_SND_CARD_STRING_SIZE];
-    int metainfo_key;
     int source_mic_type;
     int max_mic_count;
     bool is_dsd_supported;
     bool is_asrc_supported;
+    struct listnode acdb_meta_key_list;
 };
 
 static bool is_external_codec = false;
@@ -1631,10 +1643,12 @@
 {
     struct platform_data *my_data = (struct platform_data *)platform;
     char *cvd_version = NULL;
-    int key = 0;
     const char *snd_card_name, *acdb_snd_card_name;
-    int result;
-    char value[PROPERTY_VALUE_MAX];
+    int result = -1;
+    struct listnode *node;
+    struct meta_key_list *key_info;
+    int key = 0;
+
     cvd_version = calloc(1, MAX_CVD_VERSION_STRING_SIZE);
     if (!cvd_version) {
         ALOGE("Failed to allocate cvd version");
@@ -1643,19 +1657,23 @@
         get_cvd_version(cvd_version, my_data->adev);
     }
 
-    property_get("audio.ds1.metainfo.key",value,"0");
-    key = atoi(value);
     snd_card_name = mixer_get_name(my_data->adev->mixer);
     acdb_snd_card_name = get_snd_card_name_for_acdb_loader(snd_card_name);
 
-    result = my_data->acdb_init(acdb_snd_card_name, cvd_version, key);
-
+    if (my_data->acdb_init_v3) {
+        result = my_data->acdb_init_v3(acdb_snd_card_name, cvd_version,
+                                           &my_data->acdb_meta_key_list);
+    } else if (my_data->acdb_init) {
+        node = list_head(&my_data->acdb_meta_key_list);
+        key_info = node_to_item(node, struct meta_key_list, list);
+        key = key_info->cal_info.nKey;
+        result = my_data->acdb_init(acdb_snd_card_name, cvd_version, key);
+    }
     /* Save these variables in platform_data. These will be used
        while reloading ACDB files during run time. */
     strlcpy(my_data->cvd_version, cvd_version, MAX_CVD_VERSION_STRING_SIZE);
     strlcpy(my_data->snd_card_name, acdb_snd_card_name,
                                                MAX_SND_CARD_STRING_SIZE);
-    my_data->metainfo_key = key;
 
     if (cvd_version)
         free(cvd_version);
@@ -1940,6 +1958,16 @@
     if (ret || is_external_codec)
         my_data->hifi_audio = true;
 
+    list_init(&my_data->acdb_meta_key_list);
+
+    set_platform_defaults(my_data);
+
+    /* Initialize ACDB and PCM ID's */
+    if (is_external_codec)
+        platform_info_init(PLATFORM_INFO_XML_PATH_EXTCODEC, my_data);
+    else
+        platform_info_init(PLATFORM_INFO_XML_PATH, my_data);
+
     my_data->voice_feature_set = VOICE_FEATURE_SET_DEFAULT;
     my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
     if (my_data->acdb_handle == NULL) {
@@ -2009,6 +2037,12 @@
             ALOGV("%s: Could not find the symbol acdb_loader_send_gain_dep_cal from %s",
                   __func__, LIB_ACDB_LOADER);
 
+        my_data->acdb_init_v3 = (acdb_init_v3_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_init_v3");
+        if (my_data->acdb_init_v3 == NULL) {
+            ALOGE("%s: dlsym error %s for acdb_loader_init_v3", __func__, dlerror());
+        }
+
         my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_init_v2");
         if (my_data->acdb_init == NULL) {
@@ -2016,12 +2050,19 @@
             goto acdb_init_fail;
         }
 
+        my_data->acdb_reload_v2 = (acdb_reload_v2_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_reload_acdb_files_v2");
+        if (my_data->acdb_reload_v2 == NULL) {
+            ALOGE("%s: dlsym error %s for acdb_loader_reload_acdb_files_v2", __func__, dlerror());
+        }
+
         my_data->acdb_reload = (acdb_reload_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_reload_acdb_files");
         if (my_data->acdb_reload == NULL) {
             ALOGE("%s: dlsym error %s for acdb_loader_reload_acdb_files", __func__, dlerror());
             goto acdb_init_fail;
         }
+
         platform_acdb_init(my_data);
     }
     audio_extn_pm_vote();
@@ -2035,14 +2076,6 @@
 
 acdb_init_fail:
 
-    set_platform_defaults(my_data);
-
-    /* Initialize ACDB and PCM ID's */
-    if (is_external_codec)
-        platform_info_init(PLATFORM_INFO_XML_PATH_EXTCODEC, my_data);
-    else
-        platform_info_init(PLATFORM_INFO_XML_PATH, my_data);
-
     if (audio_extn_can_use_ras()) {
         if (property_get_bool("persist.speaker.prot.enable", false)) {
             platform_set_snd_device_acdb_id(SND_DEVICE_OUT_SPEAKER_PROTECTED,
@@ -2075,8 +2108,6 @@
     /* init dap hal */
     audio_extn_dap_hal_init(adev->snd_card);
 
-    audio_extn_dolby_set_license(adev);
-
     /* init audio device arbitration */
     audio_extn_dev_arbi_init();
 
@@ -2497,6 +2528,45 @@
     return ret;
 }
 
+int platform_set_acdb_metainfo_key(void *platform, char *name, int key)
+{
+    struct meta_key_list *key_info;
+    struct platform_data *pdata = (struct platform_data *)platform;
+
+    key_info = (struct meta_key_list *)calloc(1, sizeof(struct meta_key_list));
+    if (!key_info) {
+        ALOGE("%s: Could not allocate memory for key %d", __func__, key);
+        return -ENOMEM;
+    }
+
+    key_info->cal_info.nKey = key;
+    strlcpy(key_info->name, name, sizeof(key_info->name));
+    list_add_tail(&pdata->acdb_meta_key_list, &key_info->list);
+    ALOGD("%s: successfully added module %s and key %d to the list", __func__,
+               key_info->name, key_info->cal_info.nKey);
+    return 0;
+}
+
+int platform_get_meta_info_key_from_list(void *platform, char *mod_name)
+{
+    struct listnode *node;
+    struct meta_key_list *key_info;
+    struct platform_data *pdata = (struct platform_data *)platform;
+    int key = 0;
+
+    ALOGV("%s: for module %s", __func__, mod_name);
+
+    list_for_each(node, &pdata->acdb_meta_key_list) {
+        key_info = node_to_item(node, struct meta_key_list, list);
+        if (strcmp(key_info->name, mod_name) == 0) {
+            key = key_info->cal_info.nKey;
+            ALOGD("%s: Found key %d for module %s", __func__, key, mod_name);
+            break;
+        }
+    }
+    return key;
+}
+
 int platform_get_default_app_type(void *platform)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
@@ -4032,6 +4102,9 @@
     int len;
     int ret = 0, err;
     char *kv_pairs = NULL;
+    struct listnode *node;
+    struct meta_key_list *key_info;
+    int key = 0;
 
     kv_pairs = str_parms_to_str(parms);
     if(!kv_pairs)
@@ -4093,9 +4166,16 @@
     if (err >= 0) {
         str_parms_del(parms, AUDIO_PARAMETER_KEY_RELOAD_ACDB);
 
-        my_data->acdb_reload(value, my_data->snd_card_name,
-                              my_data->cvd_version, my_data->metainfo_key);
-
+        if (my_data->acdb_reload_v2) {
+            my_data->acdb_reload_v2(value, my_data->snd_card_name,
+                                  my_data->cvd_version, &my_data->acdb_meta_key_list);
+        } else if (my_data->acdb_reload) {
+            node = list_head(&my_data->acdb_meta_key_list);
+            key_info = node_to_item(node, struct meta_key_list, list);
+            key = key_info->cal_info.nKey;
+            my_data->acdb_reload(value, my_data->snd_card_name,
+                                  my_data->cvd_version, key);
+        }
     }
 
     if (hw_info_is_stereo_spkr(my_data->hw_info)) {
@@ -4609,11 +4689,11 @@
      */
     // TODO: This has to be more dynamic based on policy file
 
-    if ((my_data->current_backend_cfg[backend_idx].samplerate_mixer_ctl) &&
+    if (passthrough_enabled || ((my_data->current_backend_cfg[backend_idx].samplerate_mixer_ctl) &&
         (sample_rate != my_data->current_backend_cfg[(int)backend_idx].sample_rate) &&
             (my_data->hifi_audio ||
             backend_idx == USB_AUDIO_RX_BACKEND ||
-            backend_idx == USB_AUDIO_TX_BACKEND)) {
+            backend_idx == USB_AUDIO_TX_BACKEND))) {
             /*
              * sample rate update is needed only for hifi audio enabled platforms
              */
@@ -4621,11 +4701,15 @@
             struct  mixer_ctl *ctl = NULL;
 
             switch (sample_rate) {
+            case 32000:
+                if (passthrough_enabled) {
+                    rate_str = "KHZ_32";
+                    break;
+                }
             case 8000:
             case 11025:
             case 16000:
             case 22050:
-            case 32000:
             case 48000:
                 rate_str = "KHZ_48";
                 break;
@@ -4651,6 +4735,11 @@
             case 384000:
                 rate_str = "KHZ_384";
                 break;
+            case 144000:
+                if (passthrough_enabled) {
+                    rate_str = "KHZ_144";
+                    break;
+                }
             default:
                 rate_str = "KHZ_48";
                 break;
@@ -5566,6 +5655,7 @@
         format = AAC;
         break;
     case AUDIO_FORMAT_E_AC3:
+    case AUDIO_FORMAT_E_AC3_JOC:
         ALOGV("%s:E_AC3", __func__);
         format = DOLBY_DIGITAL_PLUS;
         break;
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 31d86f4..0835329 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -1350,3 +1350,15 @@
 {
     return 0;
 }
+
+int platform_get_meta_info_key_from_list(void *platform __unused,
+                                         char *mod_name __unused)
+{
+    return 0;
+}
+
+int platform_set_acdb_metainfo_key(void *platform __unused, char *name __unused,
+                                   int key __unused)
+{
+    return 0;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 74c429b..1028e2d 100755
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -190,6 +190,7 @@
 /* Audio calibration related functions */
 typedef void (*acdb_deallocate_t)();
 typedef int  (*acdb_init_t)(const char *, char *, int);
+typedef int  (*acdb_init_v3_t)(const char *, char *, struct listnode *);
 typedef void (*acdb_send_audio_cal_t)(int, int, int , int);
 typedef void (*acdb_send_voice_cal_t)(int, int);
 typedef int (*acdb_reload_vocvoltable_t)(int);
@@ -201,6 +202,7 @@
 typedef int (*acdb_send_common_top_t) (void);
 typedef int (*acdb_set_codec_data_t) (void *, char *);
 typedef int (*acdb_reload_t) (char *, char *, char *, int);
+typedef int (*acdb_reload_v2_t) (char *, char *, char *, struct listnode *);
 
 typedef struct codec_backend_cfg {
     uint32_t sample_rate;
@@ -215,6 +217,12 @@
 static bool supports_true_32_bit = false;
 typedef int (*acdb_send_gain_dep_cal_t)(int, int, int, int, int);
 
+struct meta_key_list {
+    struct listnode list;
+    struct audio_cal_info_metainfo cal_info;
+    char name[ACDB_METAINFO_KEY_MODULE_NAME_LEN];
+};
+
 struct platform_data {
     struct audio_device *adev;
     bool fluence_in_spkr_mode;
@@ -240,6 +248,7 @@
     void                       *acdb_handle;
     int                        voice_feature_set;
     acdb_init_t                acdb_init;
+    acdb_init_v3_t             acdb_init_v3;
     acdb_deallocate_t          acdb_deallocate;
     acdb_send_audio_cal_t      acdb_send_audio_cal;
     acdb_set_audio_cal_t       acdb_set_audio_cal;
@@ -250,6 +259,7 @@
     acdb_send_common_top_t     acdb_send_common_top;
     acdb_set_codec_data_t      acdb_set_codec_data;
     acdb_reload_t              acdb_reload;
+    acdb_reload_v2_t           acdb_reload_v2;
     void *hw_info;
     acdb_send_gain_dep_cal_t   acdb_send_gain_dep_cal;
     struct csd_data *csd;
@@ -262,11 +272,11 @@
     int hw_dep_fd;
     char cvd_version[MAX_CVD_VERSION_STRING_SIZE];
     char snd_card_name[MAX_SND_CARD_STRING_SIZE];
-    int metainfo_key;
     int source_mic_type;
     int max_mic_count;
     bool is_dsd_supported;
     bool is_asrc_supported;
+    struct listnode acdb_meta_key_list;
 };
 
 static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
@@ -394,6 +404,7 @@
     [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = "voice-anc-headphones",
     [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = "voice-anc-fb-headphones",
     [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = "speaker-and-anc-headphones",
+    [SND_DEVICE_OUT_SPEAKER_AND_ANC_FB_HEADSET] = "speaker-and-anc-fb-headphones",
     [SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset",
     [SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected",
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = "voice-speaker-protected",
@@ -523,6 +534,7 @@
     [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = 26,
     [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = 27,
     [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = 26,
+    [SND_DEVICE_OUT_SPEAKER_AND_ANC_FB_HEADSET] = 27,
     [SND_DEVICE_OUT_ANC_HANDSET] = 103,
     [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 124,
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = 101,
@@ -652,6 +664,7 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_ANC_HEADSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_ANC_FB_HEADSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_ANC_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED)},
@@ -1419,10 +1432,12 @@
 {
     struct platform_data *my_data = (struct platform_data *)platform;
     char *cvd_version = NULL;
-    int key = 0;
     const char *snd_card_name;
-    int result;
-    char value[PROPERTY_VALUE_MAX];
+    int result = -1;
+    struct listnode *node;
+    struct meta_key_list *key_info;
+    int key = 0;
+
     cvd_version = calloc(1, MAX_CVD_VERSION_STRING_SIZE);
     if (!cvd_version) {
         ALOGE("Failed to allocate cvd version");
@@ -1431,17 +1446,22 @@
         get_cvd_version(cvd_version, my_data->adev);
     }
 
-    property_get("audio.ds1.metainfo.key",value,"0");
-    key = atoi(value);
     snd_card_name = mixer_get_name(my_data->adev->mixer);
-    result = my_data->acdb_init(snd_card_name, cvd_version, key);
+    if (my_data->acdb_init_v3) {
+        result = my_data->acdb_init_v3(snd_card_name, cvd_version,
+                                           &my_data->acdb_meta_key_list);
+    } else if (my_data->acdb_init) {
+        node = list_head(&my_data->acdb_meta_key_list);
+        key_info = node_to_item(node, struct meta_key_list, list);
+        key = key_info->cal_info.nKey;
+        result = my_data->acdb_init(snd_card_name, cvd_version, key);
+    }
 
     /* Save these variables in platform_data. These will be used
        while reloading ACDB files during run time. */
     strlcpy(my_data->cvd_version, cvd_version, MAX_CVD_VERSION_STRING_SIZE);
     strlcpy(my_data->snd_card_name, snd_card_name,
                                                MAX_SND_CARD_STRING_SIZE);
-    my_data->metainfo_key = key;
 
     if (cvd_version)
         free(cvd_version);
@@ -1671,6 +1691,16 @@
     if (ret)
         my_data->is_vbat_speaker = true;
 
+    list_init(&my_data->acdb_meta_key_list);
+
+    set_platform_defaults(my_data);
+
+    /* Initialize ACDB ID's */
+    if (my_data->is_i2s_ext_modem)
+        platform_info_init(PLATFORM_INFO_XML_PATH_I2S, my_data);
+    else
+        platform_info_init(PLATFORM_INFO_XML_PATH, my_data);
+
     my_data->voice_feature_set = VOICE_FEATURE_SET_DEFAULT;
     my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
     if (my_data->acdb_handle == NULL) {
@@ -1741,13 +1771,25 @@
                   __func__, LIB_ACDB_LOADER);
 
 
+        my_data->acdb_init_v3 = (acdb_init_v3_t)dlsym(my_data->acdb_handle,
+                                                     "acdb_loader_init_v3");
+        if (my_data->acdb_init_v3 == NULL) {
+            ALOGE("%s: dlsym error %s for acdb_loader_init_v3", __func__, dlerror());
+        }
+
         my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
-                                                    "acdb_loader_init_v2");
+                                                     "acdb_loader_init_v3");
         if (my_data->acdb_init == NULL) {
-            ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__, dlerror());
+            ALOGE("%s: dlsym error %s for acdb_loader_init_v3", __func__, dlerror());
             goto acdb_init_fail;
         }
 
+        my_data->acdb_reload_v2 = (acdb_reload_v2_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_reload_acdb_files_v2");
+        if (my_data->acdb_reload_v2 == NULL) {
+            ALOGE("%s: dlsym error %s for acdb_loader_reload_acdb_files_v2", __func__, dlerror());
+        }
+
         my_data->acdb_reload = (acdb_reload_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_reload_acdb_files");
         if (my_data->acdb_reload == NULL) {
@@ -1762,13 +1804,6 @@
 
 acdb_init_fail:
 
-    set_platform_defaults(my_data);
-
-    /* Initialize ACDB ID's */
-    if (my_data->is_i2s_ext_modem)
-        platform_info_init(PLATFORM_INFO_XML_PATH_I2S, my_data);
-    else
-        platform_info_init(PLATFORM_INFO_XML_PATH, my_data);
 
     if (audio_extn_can_use_ras()) {
         if (property_get_bool("persist.speaker.prot.enable", false)) {
@@ -1815,7 +1850,6 @@
     audio_extn_ssr_update_enabled();
     audio_extn_spkr_prot_init(adev);
 
-    audio_extn_dolby_set_license(adev);
 
     /* init audio device arbitration */
     audio_extn_dev_arbi_init();
@@ -2194,6 +2228,46 @@
     return ret;
 }
 
+int platform_set_acdb_metainfo_key(void *platform, char *name, int key)
+{
+    struct meta_key_list *key_info;
+    struct platform_data *pdata = (struct platform_data *)platform;
+
+    key_info = (struct meta_key_list *)calloc(1, sizeof(struct meta_key_list));
+    if (!key_info) {
+        ALOGE("%s: Could not allocate memory for key %d", __func__, key);
+        return -ENOMEM;
+    }
+
+    key_info->cal_info.nKey = key;
+    strlcpy(key_info->name, name, sizeof(key_info->name));
+    list_add_tail(&pdata->acdb_meta_key_list, &key_info->list);
+
+    ALOGD("%s: successfully added module %s and key %d to the list", __func__,
+               key_info->name, key_info->cal_info.nKey);
+    return 0;
+}
+
+int platform_get_meta_info_key_from_list(void *platform, char *mod_name)
+{
+    struct listnode *node;
+    struct meta_key_list *key_info;
+    struct platform_data *pdata = (struct platform_data *)platform;
+    int key = 0;
+
+    ALOGV("%s: for module %s", __func__, mod_name);
+
+    list_for_each(node, &pdata->acdb_meta_key_list) {
+        key_info = node_to_item(node, struct meta_key_list, list);
+        if (strcmp(key_info->name, mod_name) == 0) {
+            key = key_info->cal_info.nKey;
+            ALOGD("%s: Found key %d for module %s", __func__, key, mod_name);
+            break;
+        }
+    }
+    return key;
+}
+
 int platform_get_default_app_type(void *platform)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
@@ -2393,7 +2467,8 @@
         SND_DEVICE_OUT_SPEAKER_AND_LINE == snd_device ||
         SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1 == snd_device ||
         SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2 == snd_device ||
-        SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET == snd_device)
+        SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET == snd_device ||
+        SND_DEVICE_OUT_SPEAKER_AND_ANC_FB_HEADSET == snd_device)
         ret = true;
 
     return ret;
@@ -2901,9 +2976,12 @@
                 snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
         } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
                                AUDIO_DEVICE_OUT_SPEAKER)) {
-            if (audio_extn_get_anc_enabled())
-                snd_device = SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET;
-            else if (my_data->external_spk_1)
+            if (audio_extn_get_anc_enabled()) {
+                if (audio_extn_should_use_fb_anc())
+                    snd_device = SND_DEVICE_OUT_SPEAKER_AND_ANC_FB_HEADSET;
+                else
+                    snd_device = SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET;
+            } else if (my_data->external_spk_1)
                 snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1;
             else if (my_data->external_spk_2)
                 snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2;
@@ -3866,6 +3944,9 @@
     int len;
     int ret = 0, err;
     char *kv_pairs = str_parms_to_str(parms);
+    struct listnode *node;
+    struct meta_key_list *key_info;
+    int key = 0;
 
     if(kv_pairs == NULL) {
         ret = -ENOMEM;
@@ -3935,9 +4016,16 @@
     if (err >= 0) {
         str_parms_del(parms, AUDIO_PARAMETER_KEY_RELOAD_ACDB);
 
-        my_data->acdb_reload(value, my_data->snd_card_name,
-                              my_data->cvd_version, my_data->metainfo_key);
-
+        if (my_data->acdb_reload_v2) {
+            my_data->acdb_reload_v2(value, my_data->snd_card_name,
+                                  my_data->cvd_version, &my_data->acdb_meta_key_list);
+        } else if (my_data->acdb_reload) {
+            node = list_head(&my_data->acdb_meta_key_list);
+            key_info = node_to_item(node, struct meta_key_list, list);
+            key = key_info->cal_info.nKey;
+            my_data->acdb_reload(value, my_data->snd_card_name,
+                                  my_data->cvd_version, key);
+        }
     }
 
     if (hw_info_is_stereo_spkr(my_data->hw_info)) {
@@ -4510,17 +4598,21 @@
         ret = 0;
     }
 
-    if ((my_data->current_backend_cfg[backend_idx].samplerate_mixer_ctl) &&
-        (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate)) {
+    if (passthrough_enabled || ((my_data->current_backend_cfg[backend_idx].samplerate_mixer_ctl) &&
+        (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate))) {
             char *rate_str = NULL;
             struct  mixer_ctl *ctl = NULL;
 
             switch (sample_rate) {
+            case 32000:
+                if (passthrough_enabled) {
+                    rate_str = "KHZ_32";
+                    break;
+                }
             case 8000:
             case 11025:
             case 16000:
             case 22050:
-            case 32000:
             case 48000:
                 rate_str = "KHZ_48";
                 break;
@@ -4546,7 +4638,12 @@
             case 384000:
                 rate_str = "KHZ_384";
                 break;
-            default:
+            case 144000:
+                if (passthrough_enabled) {
+                    rate_str = "KHZ_144";
+                    break;
+                }
+           default:
                 rate_str = "KHZ_48";
                 break;
             }
@@ -5412,6 +5509,7 @@
         format = AAC;
         break;
     case AUDIO_FORMAT_E_AC3:
+    case AUDIO_FORMAT_E_AC3_JOC:
         ALOGV("%s:E_AC3", __func__);
         format = DOLBY_DIGITAL_PLUS;
         break;
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 731d81c..0018427 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -120,6 +120,7 @@
     SND_DEVICE_OUT_VOICE_ANC_HEADSET,
     SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET,
     SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_FB_HEADSET,
     SND_DEVICE_OUT_ANC_HANDSET,
     SND_DEVICE_OUT_SPEAKER_PROTECTED,
     SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED,
diff --git a/hal/platform_api.h b/hal/platform_api.h
index e274e48..82bef97 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -31,6 +31,7 @@
 #define SAMPLE_RATE_11025 11025
 #define sample_rate_multiple(sr, base) ((sr % base)== 0?true:false)
 #define MAX_VOLUME_CAL_STEPS 15
+#define ACDB_METAINFO_KEY_MODULE_NAME_LEN 100
 
 struct amp_db_and_gain_table {
     float amp;
@@ -82,6 +83,8 @@
 int platform_get_snd_device_acdb_id(snd_device_t snd_device);
 int platform_set_snd_device_bit_width(snd_device_t snd_device, unsigned int bit_width);
 int platform_get_snd_device_bit_width(snd_device_t snd_device);
+int platform_set_acdb_metainfo_key(void *platform, char *name, int key);
+int platform_get_meta_info_key_from_list(void *platform, char *mod_name);
 int platform_set_native_support(int na_mode);
 int platform_get_native_support();
 int platform_send_audio_calibration(void *platform, struct audio_usecase *usecase,
diff --git a/hal/platform_info.c b/hal/platform_info.c
index 8e12dd6..a63b215 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -51,6 +51,7 @@
     INTERFACE_NAME,
     CONFIG_PARAMS,
     GAIN_LEVEL_MAPPING,
+    ACDB_METAINFO_KEY,
 } section_t;
 
 typedef void (* section_process_fn)(const XML_Char **attr);
@@ -63,6 +64,7 @@
 static void process_config_params(const XML_Char **attr);
 static void process_root(const XML_Char **attr);
 static void process_gain_db_to_level_map(const XML_Char **attr);
+static void process_acdb_metainfo_key(const XML_Char **attr);
 
 static section_process_fn section_table[] = {
     [ROOT] = process_root,
@@ -73,6 +75,7 @@
     [INTERFACE_NAME] = process_interface_name,
     [CONFIG_PARAMS] = process_config_params,
     [GAIN_LEVEL_MAPPING] = process_gain_db_to_level_map,
+    [ACDB_METAINFO_KEY] = process_acdb_metainfo_key,
 };
 
 static section_t section;
@@ -350,6 +353,29 @@
     return;
 }
 
+/* process acdb meta info key value */
+static void process_acdb_metainfo_key(const XML_Char **attr)
+{
+    if (strcmp(attr[0], "name") != 0) {
+        ALOGE("%s: 'name' not found", __func__);
+        goto done;
+    }
+
+    if (strcmp(attr[2], "value") != 0) {
+        ALOGE("%s: 'value' not found", __func__);
+        goto done;
+    }
+
+    int key = atoi((char *)attr[3]);
+    if (platform_set_acdb_metainfo_key(my_data.platform, (char*)attr[1], key) < 0) {
+        ALOGE("%s: key %d was not set!", __func__, key);
+        goto done;
+    }
+
+done:
+    return;
+}
+
 static void start_tag(void *userdata __unused, const XML_Char *tag_name,
                       const XML_Char **attr)
 {
@@ -367,6 +393,8 @@
         section = INTERFACE_NAME;
     } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) {
         section = GAIN_LEVEL_MAPPING;
+    } else if(strcmp(tag_name, "acdb_metainfo_key") == 0) {
+        section = ACDB_METAINFO_KEY;
     } else if (strcmp(tag_name, "device") == 0) {
         if ((section != ACDB) && (section != BACKEND_NAME) && (section != BITWIDTH) &&
             (section != INTERFACE_NAME)) {
@@ -394,7 +422,7 @@
         section_process_fn fn = section_table[PCM_ID];
         fn(attr);
     } else if (strcmp(tag_name, "param") == 0) {
-        if (section != CONFIG_PARAMS) {
+        if ((section != CONFIG_PARAMS) && (section != ACDB_METAINFO_KEY)) {
             ALOGE("param tag only supported with CONFIG_PARAMS section");
             return;
         }
@@ -423,6 +451,8 @@
         section = ROOT;
     } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) {
         section = ROOT;
+    } else if (strcmp(tag_name, "acdb_metainfo_key") == 0) {
+        section = ROOT;
     }
 }
 
diff --git a/qahw_api/inc/qahw_defs.h b/qahw_api/inc/qahw_defs.h
index 8b890b9..eb500a2 100644
--- a/qahw_api/inc/qahw_defs.h
+++ b/qahw_api/inc/qahw_defs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2011 The Android Open Source Project *
@@ -233,14 +233,26 @@
     uint16_t  gain_step;
 };
 
+struct aptx_dec_bt_addr {
+    uint32_t nap;
+    uint32_t uap;
+    uint32_t lap;
+};
+
+struct qahw_aptx_dec_param {
+   struct aptx_dec_bt_addr bt_addr;
+};
+
 typedef union {
     struct qahw_source_tracking_param st_params;
     struct qahw_sound_focus_param sf_params;
+    struct qahw_aptx_dec_param aptx_params;
 } qahw_param_payload;
 
 typedef enum {
     QAHW_PARAM_SOURCE_TRACK,
-    QAHW_PARAM_SOUND_FOCUS
+    QAHW_PARAM_SOUND_FOCUS,
+    QAHW_PARAM_APTX_DEC
 } qahw_param_id;
 
 
diff --git a/qahw_api/test/qahw_playback_test.c b/qahw_api/test/qahw_playback_test.c
index 900f189..223726d 100644
--- a/qahw_api/test/qahw_playback_test.c
+++ b/qahw_api/test/qahw_playback_test.c
@@ -46,6 +46,7 @@
 #define ID_DATA 0x61746164
 
 #define FORMAT_PCM 1
+#define WAV_HEADER_LENGTH_MAX 46
 
 static thread_data_t *ethread_data = NULL;
 static cmd_data_t cmd_data;
@@ -102,7 +103,8 @@
     FILE_EAC3,
     FILE_EAC3_JOC,
     FILE_DTS,
-    FILE_MP2
+    FILE_MP2,
+    FILE_APTX
 };
 
 typedef enum {
@@ -552,6 +554,28 @@
     return rc;
 }
 
+void parse_aptx_dec_bt_addr(char *value, struct qahw_aptx_dec_param *aptx_cfg)
+{
+    int ba[6];
+    char *str, *tok;
+    uint32_t addr[3];
+    int i = 0;
+
+    tok = strtok_r(value, ":", &str);
+    while (tok != NULL) {
+        ba[i] = strtol(tok, NULL, 16);
+        i++;
+        tok = strtok_r(NULL, ":", &str);
+    }
+    addr[0] = (ba[0] << 8) | ba[1];
+    addr[1] = ba[2];
+    addr[2] = (ba[3] << 16) | (ba[4] << 8) | ba[5];
+
+    aptx_cfg->bt_addr.nap = addr[0];
+    aptx_cfg->bt_addr.uap = addr[1];
+    aptx_cfg->bt_addr.lap = addr[2];
+}
+
 void usage() {
     printf(" \n Command \n");
     printf(" \n hal_play_test -f file-path <options>   - Plays audio file from the path provided\n");
@@ -583,6 +607,7 @@
     printf("                                             file path and other file specific options would be ignored in this mode.\n\n");
     printf(" -e  --effect-type <effect type>           - Effect used for test\n");
     printf("                                             0:bassboost 1:virtualizer 2:equalizer 3:visualizer(NA) 4:reverb 5:audiosphere others:null");
+    printf(" -A  --bt-addr <bt device addr>            - Required to set bt device adress for aptx decoder\n");
     printf(" \n Examples \n");
     printf(" hal_play_test -f /etc/Anukoledenadu.wav     -> plays Wav stream with default params\n\n");
     printf(" hal_play_test -f /etc/MateRani.mp3 -t 2 -d 2 -v 0.01 -r 44100 -c 2 \n");
@@ -621,6 +646,10 @@
     printf("                                          -> kvpair(-k) values represent media-info of clip & values should be in below mentioned sequence\n");
     printf("                                          ->avg_bit_rate,sample_rate,wma_bit_per_sample,wma_block_align\n");
     printf("                                          ->wma_channel_mask,wma_encode_option,wma_format_tag\n");
+    printf(" hal_play_test -f /etc/03_Kuch_Khaas_BE.btaptx -t 9 -d 2 -v 0.2 -r 44100 -c 2 -A 00:02:5b:00:ff:03 \n");
+    printf("                                          -> Play aptx clip (-t = 9)\n");
+    printf("                                          -> 2 channels and 44100 sample rate\n");
+    printf("                                          -> BT addr: bt_addr=00:02:5b:00:ff:03\n");
     printf(" hal_play_test -K -F 4                    -> Measure latency KPIs for low latency output\n\n");
     printf(" hal_play_test -f /etc//Moto_320kbps.mp3 -t 2 -d 2 -v 0.1 -r 44100 -c 2 -e 2\n");
     printf("                                          -> plays MP3 stream(-t = 2) on speaker device(-d = 2)\n");
@@ -628,19 +657,53 @@
     printf("                                          -> sound effect equalizer enabled\n\n");
 }
 
+static int get_wav_header_length (FILE* file_stream)
+{
+    int subchunk_size = 0, wav_header_len = 0;
+
+    fseek(file_stream, 16, SEEK_SET);
+    if(fread(&subchunk_size, 4, 1, file_stream) != 1) {
+        fprintf(stdout, "Unable to read subchunk:\n");
+        exit (1);
+    }
+    if(subchunk_size < 16) {
+        fprintf(stdout, "This is not a valid wav file \n");
+    } else {
+          switch (subchunk_size) {
+          case 16:
+              fprintf(stdout, "44-byte wav header \n");
+              wav_header_len = 44;
+              break;
+          case 18:
+              fprintf(stdout, "46-byte wav header \n");
+              wav_header_len = 46;
+              break;
+          default:
+              fprintf(stdout, "Header contains extra data and is larger than 46 bytes: subchunk_size=%d \n", subchunk_size);
+              wav_header_len = subchunk_size;
+              break;
+          }
+    }
+    return wav_header_len;
+}
+
+
 int main(int argc, char* argv[]) {
 
     FILE *file_stream = NULL;
-    char header[44] = {0};
+    char header[WAV_HEADER_LENGTH_MAX] = {0};
     char* filename = nullptr;
     qahw_module_handle_t *qahw_mod_handle = NULL;
     const char *mod_name = "audio.primary";
     qahw_stream_handle_t* out_handle = nullptr;
-    int rc = 0;
+    int rc = 0, wav_header_len = 0;
     char *kvpair_values = NULL;
     char kvpair[1000] = {0};
     struct proxy_data proxy_params;
-
+    char *ba = NULL;
+    qahw_param_payload payload;
+    qahw_param_id param_id;
+    struct qahw_aptx_dec_param aptx_params;
     /*
      * Default values
      */
@@ -675,6 +738,7 @@
         {"flags",         required_argument,    0, 'F'},
         {"kpi-mode",      no_argument,          0, 'K'},
         {"effect-path",   required_argument,    0, 'e'},
+        {"bt-addr",       required_argument,    0, 'A'},
         {"help",          no_argument,          0, 'h'},
         {0, 0, 0, 0}
     };
@@ -698,7 +762,7 @@
     proxy_params.hdr.data_sz = 0;
     while ((opt = getopt_long(argc,
                               argv,
-                              "-f:r:c:b:d:v:l:t:a:w:k:D:KF:e:h",
+                              "-f:r:c:b:d:v:l:t:a:w:k:D:KF:e:A:h",
                               long_options,
                               &option_index)) != -1) {
             switch (opt) {
@@ -767,6 +831,9 @@
                     ethread_func = effect_thread_funcs[effect_index];
                 }
                 break;
+            case 'A':
+                ba = optarg;
+                break;
             case 'h':
                 usage();
                 return 0;
@@ -839,7 +906,12 @@
             /*
              * Read the wave header
              */
-            rc = fread (header, 44 , 1, file_stream);
+            if((wav_header_len = get_wav_header_length(file_stream)) <= 0) {
+                fprintf(stdout, "wav header length is invalid:%d\n", wav_header_len);
+                exit(1);
+            }
+            fseek(file_stream, 0, SEEK_SET);
+            rc = fread (header, wav_header_len, 1, file_stream);
             if (rc != 1) {
                fprintf(stdout, "Error .Fread failed\n");
                exit(0);
@@ -902,6 +974,9 @@
         case FILE_DTS:
             config.offload_info.format = AUDIO_FORMAT_DTS;
             break;
+        case FILE_APTX:
+            config.offload_info.format = AUDIO_FORMAT_APTX;
+            break;
         default:
            fprintf(stderr, "Does not support given filetype\n");
            usage();
@@ -924,6 +999,23 @@
     if (output_device & AUDIO_DEVICE_OUT_ALL_A2DP) {
         output_device = AUDIO_DEVICE_OUT_PROXY;
     }
+    if (filetype == FILE_APTX) {
+        if (ba != NULL) {
+            parse_aptx_dec_bt_addr(ba, &aptx_params);
+            payload = (qahw_param_payload)aptx_params;
+            param_id = QAHW_PARAM_APTX_DEC;
+            fprintf(log_file, "Send BT addr nap %d, uap %d lap %d to HAL\n", aptx_params.bt_addr.nap,
+                        aptx_params.bt_addr.uap, aptx_params.bt_addr.lap);
+            rc = qahw_set_param_data(qahw_mod_handle, param_id, &payload);
+            if (rc != 0)
+                 printf("Error.Failed Set BT addr\n");
+        } else {
+            fprintf(log_file, "BT addr is NULL, Need valid BT addr for aptx file playback to work\n");
+            fprintf(stderr, "BT addr is NULL, Need valid BT addr for aptx file playback to work\n");
+            goto EXIT;
+        }
+    }
+
     fprintf(log_file, "calling open_out_put_stream:\n");
     rc = qahw_open_output_stream(qahw_mod_handle,
                                  handle,