Merge "hal: avoid dereferencing null pointer"
diff --git a/configs/msm8909/audio_platform_info.xml b/configs/msm8909/audio_platform_info.xml
index a0d5728..bed8c4d 100644
--- a/configs/msm8909/audio_platform_info.xml
+++ b/configs/msm8909/audio_platform_info.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="ISO-8859-1"?>
-<!-- Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.         -->
+<!-- Copyright (c) 2015-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 -->
@@ -26,6 +26,13 @@
 <!-- OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -->
 <!-- IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                          -->
 <audio_platform_info>
+    <pcm_ids>
+        <usecase name="USECASE_VOICEMMODE1_CALL" type="in" id="34"/>
+        <usecase name="USECASE_VOICEMMODE1_CALL" type="out" id="34"/>
+        <usecase name="USECASE_VOICEMMODE2_CALL" type="in" id="35"/>
+        <usecase name="USECASE_VOICEMMODE2_CALL" type="out" id="35"/>
+    </pcm_ids>
+
     <interface_names>
         <device name="AUDIO_DEVICE_IN_BUILTIN_MIC" interface="QUATERNARY_MI2S" codec_type="external"/>
         <device name="AUDIO_DEVICE_IN_BACK_MIC" interface="QUATERNARY_MI2S" codec_type="external"/>
diff --git a/configs/msm8909/msm8909.mk b/configs/msm8909/msm8909.mk
index 19ab156..cfd71ef 100755
--- a/configs/msm8909/msm8909.mk
+++ b/configs/msm8909/msm8909.mk
@@ -4,7 +4,6 @@
 BOARD_USES_ALSA_AUDIO := true
 
 #TODO move this cchange to device/qcom/msm8909
-TARGET_USES_AOSP_FOR_AUDIO := true
 
 ifneq ($(TARGET_USES_AOSP_FOR_AUDIO), true)
 USE_CUSTOM_AUDIO_POLICY := 1
@@ -22,6 +21,7 @@
 #AUDIO_FEATURE_ENABLED_PM_SUPPORT := true
 AUDIO_FEATURE_ENABLED_DS2_DOLBY_DAP := true
 MM_AUDIO_ENABLED_SAFX := true
+DOLBY_ENABLE := false
 
 endif
 USE_XML_AUDIO_POLICY_CONF := 1
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 7bc5d2a..a6510e5 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -93,6 +93,10 @@
                                       AUDIO_FORMAT_AAC_SUB_HE_V2)
 #endif
 
+#ifndef AUDIO_OUTPUT_FLAG_TIMESTAMP
+#define AUDIO_OUTPUT_FLAG_TIMESTAMP 0x10000
+#endif
+
 #ifndef COMPRESS_METADATA_NEEDED
 #define audio_extn_parse_compress_metadata(out, parms) (0)
 #else
@@ -108,6 +112,11 @@
 #define compress_set_next_track_param(compress, codec_options) (0)
 #endif
 
+#ifndef AUDIO_HW_EXTN_API_ENABLED
+#define compress_set_metadata(compress, metadata) (0)
+#define compress_get_metadata(compress, metadata) (0)
+#endif
+
 #define MAX_LENGTH_MIXER_CONTROL_IN_INT                  (128)
 
 void audio_extn_set_parameters(struct audio_device *adev,
@@ -823,4 +832,6 @@
 int audio_extn_utils_get_avt_device_drift(
                 struct audio_usecase *usecase,
                 struct audio_avt_device_drift_param *drift_param);
+int audio_extn_utils_compress_get_dsp_latency(struct stream_out *out);
+int audio_extn_utils_compress_set_render_mode(struct stream_out *out);
 #endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/pm.c b/hal/audio_extn/pm.c
index c52508e..69e19cb 100644
--- a/hal/audio_extn/pm.c
+++ b/hal/audio_extn/pm.c
@@ -32,6 +32,7 @@
 
 #include "pm.h"
 #include <cutils/log.h>
+#include <cutils/str_parms.h>
 
 /* Device state*/
 #define AUDIO_PARAMETER_KEY_DEV_SHUTDOWN "dev_shutdown"
@@ -98,7 +99,7 @@
     }
 }
 
-void audio_extn_pm_event_notifier(void *client_data, enum pm_event event)
+void audio_extn_pm_event_notifier(void *client_data __unused, enum pm_event event)
 {
 
     int err, intfd;
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
index 32af216..3a34685 100644
--- a/hal/audio_extn/qaf.c
+++ b/hal/audio_extn/qaf.c
@@ -1580,6 +1580,59 @@
     property_get("audio.qaf.library", value, NULL);
     snprintf(lib_name, PROPERTY_VALUE_MAX, "%s", value);
 
+    qaf_mod->qaf_lib = dlopen(lib_name, RTLD_NOW);
+    if (qaf_mod->qaf_lib == NULL) {
+        ALOGE("%s: DLOPEN failed for %s", __func__, lib_name);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    ALOGV("%s: DLOPEN successful for %s", __func__, lib_name);
+    qaf_mod->qaf_audio_session_open =
+                (int (*)(audio_session_handle_t* session_handle, void *p_data, void* license_data))dlsym(qaf_mod->qaf_lib,
+                                                                 "audio_session_open");
+    qaf_mod->qaf_audio_session_close =
+                (int (*)(audio_session_handle_t session_handle))dlsym(qaf_mod->qaf_lib,
+                                                                 "audio_session_close");
+    qaf_mod->qaf_audio_stream_open =
+                (int (*)(audio_session_handle_t session_handle, audio_stream_handle_t* stream_handle,
+                 audio_stream_config_t input_config, audio_devices_t devices, stream_type_t flags))dlsym(qaf_mod->qaf_lib,
+                                                                 "audio_stream_open");
+    qaf_mod->qaf_audio_stream_close =
+                (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
+                                                                 "audio_stream_close");
+    qaf_mod->qaf_audio_stream_set_param =
+                (int (*)(audio_stream_handle_t stream_handle, const char* kv_pairs))dlsym(qaf_mod->qaf_lib,
+                                                                 "audio_stream_set_param");
+    qaf_mod->qaf_audio_session_set_param =
+                (int (*)(audio_session_handle_t handle, const char* kv_pairs))dlsym(qaf_mod->qaf_lib,
+                                                                 "audio_session_set_param");
+    qaf_mod->qaf_audio_stream_get_param =
+                (char* (*)(audio_stream_handle_t stream_handle, const char* key))dlsym(qaf_mod->qaf_lib,
+                                                                 "audio_stream_get_param");
+    qaf_mod->qaf_audio_session_get_param =
+                (char* (*)(audio_session_handle_t handle, const char* key))dlsym(qaf_mod->qaf_lib,
+                                                                 "audio_session_get_param");
+    qaf_mod->qaf_audio_stream_start =
+                (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
+                                                                 "audio_stream_start");
+    qaf_mod->qaf_audio_stream_stop =
+                (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
+                                                                 "audio_stream_stop");
+    qaf_mod->qaf_audio_stream_pause =
+                (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
+                                                                 "audio_stream_pause");
+    qaf_mod->qaf_audio_stream_flush =
+                (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
+                                                                 "audio_stream_flush");
+    qaf_mod->qaf_audio_stream_write =
+                (int (*)(audio_stream_handle_t stream_handle, const void* buf, int size))dlsym(qaf_mod->qaf_lib,
+                                                                 "audio_stream_write");
+    qaf_mod->qaf_register_event_callback =
+                (void (*)(audio_session_handle_t session_handle, void *priv_data, notify_event_callback_t event_callback,
+                 audio_event_id_t event_id))dlsym(qaf_mod->qaf_lib,
+                                                                 "register_event_callback");
+
     license_data = platform_get_license((struct audio_hw_device *)(qaf_mod->adev->platform), &size);
     if (!license_data) {
         ALOGE("License is not present");
@@ -1618,6 +1671,10 @@
         lic_config = NULL;
     }
     if (ret != 0) {
+        if (qaf_mod->qaf_lib != NULL) {
+            dlclose(qaf_mod->qaf_lib);
+            qaf_mod->qaf_lib = NULL;
+        }
         if (qaf_mod != NULL) {
             free(qaf_mod);
             qaf_mod = NULL;
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index ad67881..050dcd6 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -29,13 +29,15 @@
 #include <cutils/log.h>
 #include <cutils/misc.h>
 
+
 #include "audio_hw.h"
 #include "platform.h"
 #include "platform_api.h"
 #include "audio_extn.h"
 #include "voice.h"
-#include "sound/compress_params.h"
-
+#include <sound/compress_params.h>
+#include <sound/compress_offload.h>
+#include <tinycompress/tinycompress.h>
 #ifdef AUDIO_EXTERNAL_HDMI_ENABLED
 #ifdef HDMI_PASSTHROUGH_ENABLED
 #include "audio_parsers.h"
@@ -82,6 +84,10 @@
 #define SR_192000           (14<<0)     /* 192kHz */
 
 #endif
+
+/* ToDo: Check and update a proper value in msec */
+#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 50
+
 struct string_to_enum {
     const char *name;
     uint32_t value;
@@ -1650,3 +1656,88 @@
 done:
     return ret;
 }
+
+#ifdef SNDRV_COMPRESS_PATH_DELAY
+int audio_extn_utils_compress_get_dsp_latency(struct stream_out *out)
+{
+    int ret = -EINVAL;
+    struct snd_compr_metadata metadata;
+    int delay_ms = COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
+
+    if (property_get_bool("audio.playback.dsp.pathdelay", false)) {
+        ALOGD("%s:: Quering DSP delay %d",__func__, __LINE__);
+        if (!(is_offload_usecase(out->usecase))) {
+            ALOGE("%s:: not supported for non offload session", __func__);
+            goto exit;
+        }
+
+        if (!out->compr) {
+            ALOGD("%s:: Invalid compress handle,returning default dsp latency",
+                    __func__);
+            goto exit;
+        }
+
+        metadata.key = SNDRV_COMPRESS_PATH_DELAY;
+        ret = compress_get_metadata(out->compr, &metadata);
+        if(ret) {
+            ALOGE("%s::error %s", __func__, compress_get_error(out->compr));
+            goto exit;
+        }
+        delay_ms = metadata.value[0] / 1000; /*convert to ms*/
+    } else {
+        ALOGD("%s:: Using Fix DSP delay",__func__);
+    }
+
+exit:
+    ALOGD("%s:: delay in ms is %d",__func__, delay_ms);
+    return delay_ms;
+}
+#else
+int audio_extn_utils_compress_get_dsp_latency(struct stream_out *out __unused)
+{
+    return COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
+}
+#endif
+
+#ifdef SNDRV_COMPRESS_RENDER_MODE
+int audio_extn_utils_compress_set_render_mode(struct stream_out *out)
+{
+    struct snd_compr_metadata metadata;
+    int ret = -EINVAL;
+
+    if (!(is_offload_usecase(out->usecase))) {
+        ALOGE("%s:: not supported for non offload session", __func__);
+        goto exit;
+    }
+
+    if (!out->compr) {
+        ALOGD("%s:: Invalid compress handle",
+                __func__);
+        goto exit;
+    }
+
+    ALOGD("%s:: render mode %d", __func__, out->render_mode);
+
+    metadata.key = SNDRV_COMPRESS_RENDER_MODE;
+    if (out->render_mode == RENDER_MODE_AUDIO_MASTER) {
+        metadata.value[0] = SNDRV_COMPRESS_RENDER_MODE_AUDIO_MASTER;
+    } else if (out->render_mode == RENDER_MODE_AUDIO_STC_MASTER) {
+        metadata.value[0] = SNDRV_COMPRESS_RENDER_MODE_STC_MASTER;
+    } else {
+        ret = 0;
+        goto exit;
+    }
+    ret = compress_set_metadata(out->compr, &metadata);
+    if(ret) {
+        ALOGE("%s::error %s", __func__, compress_get_error(out->compr));
+    }
+exit:
+    return ret;
+}
+#else
+int audio_extn_utils_compress_set_render_mode(struct stream_out *out __unused)
+{
+    ALOGD("%s:: configuring render mode not supported", __func__);
+    return 0;
+}
+#endif
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 4d476da..eaa67b5 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -79,8 +79,6 @@
 #define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4
 /*DIRECT PCM has same buffer sizes as DEEP Buffer*/
 #define DIRECT_PCM_NUM_FRAGMENTS 2
-/* ToDo: Check and update a proper value in msec */
-#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 50
 #define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
 #define DSD_VOLUME_MIN_DB (-110)
 
@@ -2365,6 +2363,8 @@
             compress_set_max_poll_wait(out->compr, 1000);
         }
 
+        audio_extn_utils_compress_set_render_mode(out);
+
         audio_extn_dts_create_state_notifier_node(out->usecase);
         audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
                                              popcount(out->channel_mask),
@@ -2961,7 +2961,9 @@
     uint32_t latency = 0;
 
     if (is_offload_usecase(out->usecase)) {
-        latency = COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
+        lock_output_stream(out);
+        latency = audio_extn_utils_compress_get_dsp_latency(out);
+        pthread_mutex_unlock(&out->lock);
     } else if (out->realtime) {
         // since the buffer won't be filled up faster than realtime,
         // return a smaller number
@@ -4133,6 +4135,14 @@
         if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
             out->non_blocking = 1;
 
+        if ((flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) &&
+            (flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC)) {
+            out->render_mode = RENDER_MODE_AUDIO_STC_MASTER;
+        } else if(flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) {
+            out->render_mode = RENDER_MODE_AUDIO_MASTER;
+        } else {
+            out->render_mode = RENDER_MODE_AUDIO_NO_TIMESTAMP;
+        }
 
         out->send_new_metadata = 1;
         out->send_next_track_params = false;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 28ae060..89e68d1 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -196,6 +196,12 @@
     int data[];
 };
 
+typedef enum render_mode {
+    RENDER_MODE_AUDIO_NO_TIMESTAMP = 0,
+    RENDER_MODE_AUDIO_MASTER,
+    RENDER_MODE_AUDIO_STC_MASTER,
+} render_mode_t;
+
 struct stream_app_type_cfg {
     int sample_rate;
     uint32_t bit_width;
@@ -252,11 +258,14 @@
     bool realtime;
     int af_period_multiplier;
     struct audio_device *dev;
+
     void* qaf_stream_handle;
     pthread_cond_t qaf_offload_cond;
     pthread_t qaf_offload_thread;
     struct listnode qaf_offload_cmd_list;
     uint32_t platform_latency;
+    render_mode_t render_mode;
+
     audio_offload_info_t info;
 };
 
diff --git a/hal/msm8916/hw_info.c b/hal/msm8916/hw_info.c
index 5060c77..652afab 100644
--- a/hal/msm8916/hw_info.c
+++ b/hal/msm8916/hw_info.c
@@ -170,6 +170,8 @@
         strlcpy(hw_info->name, "apq8009", sizeof(hw_info->name));
     } else if (!strcmp(snd_card_name, "mdm9607-tomtom-i2s-snd-card")) {
         strlcpy(hw_info->name, "mdm9607", sizeof(hw_info->name));
+    } else if (!strcmp(snd_card_name, "mdm-tasha-i2s-snd-card")) {
+        strlcpy(hw_info->name, "mdm-tasha", sizeof(hw_info->name));
     } else if (!strcmp(snd_card_name, "msm8909-skuq-snd-card")) {
         strlcpy(hw_info->type, "skuq", sizeof(hw_info->type));
         strlcpy(hw_info->name, "msm8909", sizeof(hw_info->name));
@@ -202,7 +204,7 @@
         strstr(snd_card_name, "msm8937") || strstr(snd_card_name, "msm8917") ||
         strstr(snd_card_name, "msm8940") || strstr(snd_card_name, "msm8920") ||
         strstr(snd_card_name, "sdm660") || strstr(snd_card_name, "apq8009") ||
-		strstr(snd_card_name, "mdm9607")) {
+        strstr(snd_card_name, "mdm9607") || strstr(snd_card_name, "mdm-tasha")) {
         ALOGV("8x16 - variant soundcard");
         update_hardware_info_8x16(hw_info, snd_card_name);
     } else {
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index a8b4d93..125f7c3 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -76,6 +76,7 @@
 #define PLATFORM_INFO_XML_PATH      "/etc/audio_platform_info.xml"
 #define MIXER_XML_PATH_WCD9326_I2S "/etc/mixer_paths_wcd9326_i2s.xml"
 #define MIXER_XML_PATH_WCD9330_I2S "/etc/mixer_paths_wcd9330_i2s.xml"
+#define MIXER_XML_PATH_WCD9335_I2S "/etc/mixer_paths_wcd9335_i2s.xml"
 #define MIXER_XML_PATH_SBC "/etc/mixer_paths_sbc.xml"
 #else
 #define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
@@ -88,8 +89,9 @@
 #define MIXER_XML_PATH_WCD9335 "/system/etc/mixer_paths_wcd9335.xml"
 #define MIXER_XML_PATH_SKUN "/system/etc/mixer_paths_qrd_skun.xml"
 #define PLATFORM_INFO_XML_PATH      "/system/etc/audio_platform_info.xml"
-#define MIXER_XML_PATH_WCD9326_I2S  "/system/etc/mixer_paths_wcd9326_i2s.xml"
+#define MIXER_XML_PATH_WCD9326_I2S "/system/etc/mixer_paths_wcd9326_i2s.xml"
 #define MIXER_XML_PATH_WCD9330_I2S "/system/etc/mixer_paths_wcd9330_i2s.xml"
+#define MIXER_XML_PATH_WCD9335_I2S "/system/etc/mixer_paths_wcd9335_i2s.xml"
 #define MIXER_XML_PATH_SBC "/system/etc/mixer_paths_sbc.xml"
 #endif
 #define MIXER_XML_PATH_SKUN "/system/etc/mixer_paths_qrd_skun.xml"
@@ -261,6 +263,7 @@
     bool fluence_in_voice_call;
     bool fluence_in_voice_rec;
     bool fluence_in_audio_rec;
+    bool fluence_in_hfp_call;
     bool external_spk_1;
     bool external_spk_2;
     bool external_mic;
@@ -945,6 +948,8 @@
                   sizeof("apq8009-tashalite-snd-card")) ||
          !strncmp(snd_card_name, "mdm9607-tomtom-i2s-snd-card",
                   sizeof("mdm9607-tomtom-i2s-snd-card")) ||
+         !strncmp(snd_card_name, "mdm-tasha-i2s-snd-card",
+                  sizeof("mdm-tasha-i2s-snd-card")) ||
          !strncmp(snd_card_name, "sdm660-tashalite-snd-card",
                   sizeof("sdm660-tashalite-snd-card")) ||
          !strncmp(snd_card_name, "sdm660-tasha-skus-snd-card",
@@ -1323,6 +1328,13 @@
         msm_device_to_be_id = msm_device_to_be_id_external_codec;
         msm_be_id_array_len  =
             sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_external_codec[0]);
+   } else if (!strncmp(snd_card_name, "mdm-tasha-i2s-snd-card",
+                       sizeof("mdm-tasha-i2s-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_WCD9335_I2S,
+                sizeof(MIXER_XML_PATH_WCD9335_I2S));
+        msm_device_to_be_id = msm_device_to_be_id_external_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_external_codec[0]);
     } else {
         strlcpy(mixer_xml_path, MIXER_XML_PATH,
                 sizeof(MIXER_XML_PATH));
@@ -2126,6 +2138,7 @@
     my_data->fluence_in_voice_call = false;
     my_data->fluence_in_voice_rec = false;
     my_data->fluence_in_audio_rec = false;
+    my_data->fluence_in_hfp_call = false;
     my_data->external_spk_1 = false;
     my_data->external_spk_2 = false;
     my_data->external_mic = false;
@@ -2175,6 +2188,11 @@
         if (!strncmp("broadside", value, sizeof("broadside"))) {
             my_data->fluence_mode = FLUENCE_BROADSIDE;
         }
+
+        property_get("persist.audio.fluence.hfpcall",value,"");
+        if (!strncmp("true", value, sizeof("true"))) {
+            my_data->fluence_in_hfp_call = true;
+        }
     }
 
     if (check_and_get_wsa_info((char *)snd_card_name, &wsaCount, &is_wsa_combo_supported)) {
@@ -2362,10 +2380,10 @@
     /* obtain source mic type from max mic count*/
     get_source_mic_type(my_data);
     ALOGD("%s: Fluence_Type(%d) max_mic_count(%d) mic_type(0x%x) fluence_in_voice_call(%d)"
-          " fluence_in_voice_rec(%d) fluence_in_spkr_mode(%d) ",
+          " fluence_in_voice_rec(%d) fluence_in_spkr_mode(%d) fluence_in_hfp_call(%d) ",
           __func__, my_data->fluence_type, my_data->max_mic_count, my_data->source_mic_type,
           my_data->fluence_in_voice_call, my_data->fluence_in_voice_rec,
-          my_data->fluence_in_spkr_mode);
+          my_data->fluence_in_spkr_mode, my_data->fluence_in_hfp_call);
 
     /* init usb */
     audio_extn_usb_init(adev);
@@ -3946,7 +3964,8 @@
                 snd_device = SND_DEVICE_IN_AANC_HANDSET_MIC;
                 adev->acdb_settings |= ANC_FLAG;
             } else if (my_data->fluence_type == FLUENCE_NONE ||
-                my_data->fluence_in_voice_call == false) {
+                my_data->fluence_in_voice_call == false ||
+                my_data->fluence_in_hfp_call == false) {
                 snd_device = SND_DEVICE_IN_HANDSET_MIC;
                 if (audio_extn_hfp_is_active(adev))
                     platform_set_echo_reference(adev, true, out_device);
@@ -3972,7 +3991,8 @@
             }
         } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
             if (my_data->fluence_type != FLUENCE_NONE &&
-                my_data->fluence_in_voice_call &&
+                (my_data->fluence_in_voice_call ||
+                 my_data->fluence_in_hfp_call) &&
                 my_data->fluence_in_spkr_mode) {
                 if((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
                    (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
@@ -6216,12 +6236,12 @@
     char mixer_ctl_name[44] = {0}; // max length of name is 44 as defined
     int ret;
     unsigned int i;
-    int set_values[8] = {0};
+    int set_values[FCC_8] = {0};
     struct platform_data *my_data = (struct platform_data *)platform;
     struct audio_device *adev = my_data->adev;
     ALOGV("%s channel_count:%d",__func__, ch_count);
-    if (NULL == ch_map) {
-        ALOGE("%s: Invalid channel mapping used", __func__);
+    if (NULL == ch_map || (ch_count < 1) || (ch_count > FCC_8)) {
+        ALOGE("%s: Invalid channel mapping or channel count value", __func__);
         return -EINVAL;
     }
 
@@ -6243,7 +6263,7 @@
               __func__, mixer_ctl_name);
         return -EINVAL;
     }
-    for (i = 0; i< ARRAY_SIZE(set_values); i++) {
+    for (i = 0; i < (unsigned int)ch_count; i++) {
         set_values[i] = ch_map[i];
     }
 
@@ -6251,7 +6271,7 @@
         set_values[0], set_values[1], set_values[2], set_values[3], set_values[4],
         set_values[5], set_values[6], set_values[7], ch_count);
 
-    ret = mixer_ctl_set_array(ctl, set_values, ch_count);
+    ret = mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
     if (ret < 0) {
         ALOGE("%s: Could not set ctl, error:%d ch_count:%d",
               __func__, ret, ch_count);
@@ -6586,6 +6606,24 @@
         return 0;
 }
 
+static bool can_enable_mbdrc_on_device(snd_device_t snd_device)
+{
+    bool ret = false;
+
+    if (snd_device == SND_DEVICE_OUT_SPEAKER ||
+        snd_device == SND_DEVICE_OUT_SPEAKER_WSA ||
+        snd_device == SND_DEVICE_OUT_SPEAKER_VBAT ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2 ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_WSA ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2_WSA) {
+        ret = true;
+    }
+    return ret;
+}
+
 bool platform_send_gain_dep_cal(void *platform,
                                 int level )
 {
@@ -6613,16 +6651,24 @@
 
             if (usecase != NULL &&
                 usecase->type == PCM_PLAYBACK &&
-                usecase->stream.out->devices == AUDIO_DEVICE_OUT_SPEAKER) {
+                usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+                int new_snd_device[2] = {0};
+                int i, num_devices = 1;
 
                 ALOGV("%s: out device is %d", __func__,  usecase->out_snd_device);
                 app_type = usecase->stream.out->app_type_cfg.app_type;
 
-                if (audio_extn_spkr_prot_is_enabled()) {
-                    acdb_dev_id = platform_get_spkr_prot_acdb_id(usecase->out_snd_device);
-                } else {
-                    acdb_dev_id = acdb_device_table[usecase->out_snd_device];
-                }
+                if (platform_split_snd_device(my_data, usecase->out_snd_device,
+                                              &num_devices, new_snd_device) < 0)
+                    new_snd_device[0] = usecase->out_snd_device;
+
+                for (i = 0; i < num_devices; i++)
+                    if (can_enable_mbdrc_on_device(new_snd_device[i])) {
+                        if (audio_extn_spkr_prot_is_enabled())
+                            acdb_dev_id = platform_get_spkr_prot_acdb_id(new_snd_device[i]);
+                        else
+                            acdb_dev_id = acdb_device_table[new_snd_device[i]];
+                    }
 
                 if (!my_data->acdb_send_gain_dep_cal(acdb_dev_id, app_type,
                                                      acdb_dev_type, mode, level)) {
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index b40f472..cc2438d 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -233,6 +233,7 @@
     bool fluence_in_voice_call;
     bool fluence_in_voice_rec;
     bool fluence_in_audio_rec;
+    bool fluence_in_hfp_call;
     bool external_spk_1;
     bool external_spk_2;
     bool external_mic;
@@ -914,6 +915,24 @@
 #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
 #define ULL_PLATFORM_DELAY         (6*1000LL)
 
+static bool can_enable_mbdrc_on_device(snd_device_t snd_device)
+{
+    bool ret = false;
+
+    if (snd_device == SND_DEVICE_OUT_SPEAKER ||
+        snd_device == SND_DEVICE_OUT_SPEAKER_WSA ||
+        snd_device == SND_DEVICE_OUT_SPEAKER_VBAT ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2 ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_WSA ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2_WSA) {
+        ret = true;
+    }
+    return ret;
+}
+
 bool platform_send_gain_dep_cal(void *platform, int level) {
     bool ret_val = false;
     struct platform_data *my_data = (struct platform_data *)platform;
@@ -939,16 +958,24 @@
 
             if (usecase != NULL &&
                 usecase->type == PCM_PLAYBACK &&
-                usecase->stream.out->devices == AUDIO_DEVICE_OUT_SPEAKER) {
+                usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+                int new_snd_device[2] = {0};
+                int i, num_devices = 1;
 
                 ALOGV("%s: out device is %d", __func__,  usecase->out_snd_device);
                 app_type = usecase->stream.out->app_type_cfg.app_type;
 
-                if (audio_extn_spkr_prot_is_enabled()) {
-                    acdb_dev_id = platform_get_spkr_prot_acdb_id(usecase->out_snd_device);
-                } else {
-                    acdb_dev_id = acdb_device_table[usecase->out_snd_device];
-                }
+                if (platform_split_snd_device(my_data, usecase->out_snd_device,
+                                              &num_devices, new_snd_device) < 0)
+                    new_snd_device[0] = usecase->out_snd_device;
+
+                for (i = 0; i < num_devices; i++)
+                    if (can_enable_mbdrc_on_device(new_snd_device[i])) {
+                        if (audio_extn_spkr_prot_is_enabled())
+                            acdb_dev_id = platform_get_spkr_prot_acdb_id(new_snd_device[i]);
+                        else
+                            acdb_dev_id = acdb_device_table[new_snd_device[i]];
+                    }
 
                 if (!my_data->acdb_send_gain_dep_cal(acdb_dev_id, app_type,
                                                      acdb_dev_type, mode, level)) {
@@ -1859,6 +1886,7 @@
     my_data->fluence_in_voice_call = false;
     my_data->fluence_in_voice_rec = false;
     my_data->fluence_in_audio_rec = false;
+    my_data->fluence_in_hfp_call = false;
     my_data->external_spk_1 = false;
     my_data->external_spk_2 = false;
     my_data->external_mic = false;
@@ -1907,6 +1935,11 @@
         if (!strncmp("broadside", value, sizeof("broadside"))) {
             my_data->fluence_mode = FLUENCE_BROADSIDE;
         }
+
+        property_get("persist.audio.fluence.hfpcall",value,"");
+        if (!strncmp("true", value, sizeof("true"))) {
+            my_data->fluence_in_hfp_call = true;
+        }
     }
 
     /* Check if Vbat speaker enabled property is set, this should be done before acdb init */
@@ -2068,10 +2101,10 @@
     /* obtain source mic type from max mic count*/
     get_source_mic_type(my_data);
     ALOGD("%s: Fluence_Type(%d) max_mic_count(%d) mic_type(0x%x) fluence_in_voice_call(%d)"
-          " fluence_in_voice_rec(%d) fluence_in_spkr_mode(%d) ",
+          " fluence_in_voice_rec(%d) fluence_in_spkr_mode(%d) fluence_in_hfp_call(%d) ",
           __func__, my_data->fluence_type, my_data->max_mic_count, my_data->source_mic_type,
           my_data->fluence_in_voice_call, my_data->fluence_in_voice_rec,
-          my_data->fluence_in_spkr_mode);
+          my_data->fluence_in_spkr_mode, my_data->fluence_in_hfp_call);
 
     /* init usb */
     audio_extn_usb_init(adev);
@@ -3554,7 +3587,8 @@
                 }
                 adev->acdb_settings |= ANC_FLAG;
             } else if (my_data->fluence_type == FLUENCE_NONE ||
-                my_data->fluence_in_voice_call == false) {
+                my_data->fluence_in_voice_call == false ||
+                my_data->fluence_in_hfp_call == false) {
                 snd_device = SND_DEVICE_IN_HANDSET_MIC;
                 if (audio_extn_hfp_is_active(adev))
                     platform_set_echo_reference(adev, true, out_device);
@@ -3579,7 +3613,8 @@
             }
         } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
             if (my_data->fluence_type != FLUENCE_NONE &&
-                my_data->fluence_in_voice_call &&
+                (my_data->fluence_in_voice_call ||
+                 my_data->fluence_in_hfp_call) &&
                 my_data->fluence_in_spkr_mode) {
                 if((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
                    (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
@@ -5870,12 +5905,12 @@
     char mixer_ctl_name[44] = {0}; // max length of name is 44 as defined
     int ret;
     unsigned int i;
-    int set_values[8] = {0};
+    int set_values[FCC_8] = {0};
     struct platform_data *my_data = (struct platform_data *)platform;
     struct audio_device *adev = my_data->adev;
     ALOGV("%s channel_count:%d",__func__, ch_count);
-    if (NULL == ch_map) {
-        ALOGE("%s: Invalid channel mapping used", __func__);
+    if (NULL == ch_map || (ch_count < 1) || (ch_count > FCC_8)) {
+        ALOGE("%s: Invalid channel mapping or channel count value", __func__);
         return -EINVAL;
     }
 
@@ -5897,7 +5932,7 @@
               __func__, mixer_ctl_name);
         return -EINVAL;
     }
-    for (i = 0; i< ARRAY_SIZE(set_values); i++) {
+    for (i = 0; i < (unsigned int)ch_count; i++) {
         set_values[i] = ch_map[i];
     }
 
@@ -5905,7 +5940,7 @@
         set_values[0], set_values[1], set_values[2], set_values[3], set_values[4],
         set_values[5], set_values[6], set_values[7], ch_count);
 
-    ret = mixer_ctl_set_array(ctl, set_values, ch_count);
+    ret = mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
     if (ret < 0) {
         ALOGE("%s: Could not set ctl, error:%d ch_count:%d",
               __func__, ret, ch_count);
diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp
index c258a39..26fe51e 100644
--- a/policy_hal/AudioPolicyManager.cpp
+++ b/policy_hal/AudioPolicyManager.cpp
@@ -719,15 +719,19 @@
                        case  AUDIO_SOURCE_VOICE_COMMUNICATION:
                             if(prop_voip_enabled) {
                                 ALOGD("voice_conc:CLOSING VoIP input source on call setup :%d ",activeInput->inputSource());
-                                stopInput(activeInput->mIoHandle, activeDesc->mSessions.itemAt(0));
-                                releaseInput(activeInput->mIoHandle, activeDesc->mSessions.itemAt(0));
+                                AudioSessionCollection activeSessions = activeInput->getAudioSessions(true);
+                                audio_session_t activeSession = activeSessions.keyAt(0);
+                                stopInput(activeInput->mIoHandle, activeSession);
+                                releaseInput(activeInput->mIoHandle, activeSession);
                             }
                        break;
 
                        default:
                            ALOGD("voice_conc:CLOSING input on call setup  for inputSource: %d",activeInput->inputSource());
-                           stopInput(activeInput->mIoHandle, activeDesc->mSessions.itemAt(0));
-                           releaseInput(activeInput->mIoHandle, activeDesc->mSessions.itemAt(0));
+                           AudioSessionCollection activeSessions = activeInput->getAudioSessions(true);
+                           audio_session_t activeSession = activeSessions.keyAt(0);
+                           stopInput(activeInput->mIoHandle, activeSession);
+                           releaseInput(activeInput->mIoHandle, activeSession);
                        break;
                    }
                }
@@ -739,8 +743,10 @@
                     sp<AudioInputDescriptor> activeInput = activeInputs[i];
                     if (AUDIO_SOURCE_VOICE_COMMUNICATION == activeInput->inputSource()) {
                         ALOGD("voice_conc:CLOSING VoIP on call setup : %d",activeInput->inputSource());
-                        stopInput(activeInput->mIoHandle, activeInput->mSessions.itemAt(0));
-                        releaseInput(activeInput->mIoHandle, activeInput->mSessions.itemAt(0));
+                        AudioSessionCollection activeSessions = activeInput->getAudioSessions(true);
+                        audio_session_t activeSession = activeSessions.keyAt(0);
+                        stopInput(activeInput->mIoHandle, activeSession);
+                        releaseInput(activeInput->mIoHandle, activeSession);
                     }
                 }
             }
@@ -770,33 +776,33 @@
             }
 
             bool isFastFallBackNeeded =
-               ((AUDIO_OUTPUT_FLAG_DEEP_BUFFER | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT_PCM) & outputDesc->mProfile->mFlags);
+               ((AUDIO_OUTPUT_FLAG_DEEP_BUFFER | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT_PCM) & outputDesc->mProfile->getFlags());
 
             if ((AUDIO_OUTPUT_FLAG_FAST == mFallBackflag) && isFastFallBackNeeded) {
-                if (((!outputDesc->isDuplicated() && outputDesc->mProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY))
+                if (((!outputDesc->isDuplicated() && outputDesc->mProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY))
                             && prop_playback_enabled) {
                     ALOGD("voice_conc:calling suspendOutput on call mode for primary output");
                     mpClientInterface->suspendOutput(mOutputs.keyAt(i));
                 } //Close compress all sessions
-                else if ((outputDesc->mProfile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
+                else if ((outputDesc->mProfile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
                                 &&  prop_playback_enabled) {
                     ALOGD("voice_conc:calling closeOutput on call mode for COMPRESS output");
                     closeOutput(mOutputs.keyAt(i));
                 }
-                else if ((outputDesc->mProfile->mFlags & AUDIO_OUTPUT_FLAG_VOIP_RX)
+                else if ((outputDesc->mProfile->getFlags() & AUDIO_OUTPUT_FLAG_VOIP_RX)
                                 && prop_voip_enabled) {
                     ALOGD("voice_conc:calling closeOutput on call mode for DIRECT  output");
                     closeOutput(mOutputs.keyAt(i));
                 }
             } else if (AUDIO_OUTPUT_FLAG_DEEP_BUFFER == mFallBackflag) {
-                if (outputDesc->mProfile->mFlags & AUDIO_OUTPUT_FLAG_VOIP_RX) {
+                if (outputDesc->mProfile->getFlags() & AUDIO_OUTPUT_FLAG_VOIP_RX) {
                     if (prop_voip_enabled) {
                         ALOGD("voice_conc:calling closeOutput on call mode for DIRECT  output");
                         closeOutput(mOutputs.keyAt(i));
                     }
                 }
                 else if (prop_playback_enabled
-                           && (outputDesc->mProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
+                           && (outputDesc->mProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT)) {
                     ALOGD("voice_conc:calling closeOutput on call mode for COMPRESS output");
                     closeOutput(mOutputs.keyAt(i));
                 }
@@ -820,7 +826,7 @@
                    ALOGD("voice_conc:ouput desc / profile is NULL");
                    continue;
                 }
-                if (!outputDesc->isDuplicated() && outputDesc->mProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+                if (!outputDesc->isDuplicated() && outputDesc->mProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
                     ALOGD("voice_conc:calling restoreOutput after call mode for primary output");
                     mpClientInterface->restoreOutput(mOutputs.keyAt(i));
                 }
@@ -885,7 +891,7 @@
                    continue;
                 }
 
-                if (outputDesc->mProfile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+                if (outputDesc->mProfile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
                     ALOGD("calling closeOutput on call mode for COMPRESS output");
                     closeOutput(mOutputs.keyAt(i));
                 }
@@ -2059,7 +2065,7 @@
                ALOGD("ouput desc / profile is NULL");
                continue;
             }
-            if (outputDesc->mProfile->mFlags
+            if (outputDesc->mProfile->getFlags()
                             & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
                 // close compress  sessions
                 ALOGD("calling closeOutput on record conc for COMPRESS output");
diff --git a/post_proc/volume_listener.c b/post_proc/volume_listener.c
index c4894ca..b8aa893 100644
--- a/post_proc/volume_listener.c
+++ b/post_proc/volume_listener.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 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
@@ -462,7 +462,7 @@
 
         // After changing the state and if device is speaker
         // recalculate gain dep cal level
-        if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) {
+        if (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) {
                 check_and_set_gain_dep_cal();
         }
 
@@ -489,7 +489,7 @@
 
         // After changing the state and if device is speaker
         // recalculate gain dep cal level
-        if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) {
+        if (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) {
             check_and_set_gain_dep_cal();
         }
 
@@ -520,8 +520,8 @@
                    __func__, context->dev_id, new_device);
 
             // check if old or new device is speaker
-            if ((context->dev_id ==  AUDIO_DEVICE_OUT_SPEAKER) ||
-                (new_device == AUDIO_DEVICE_OUT_SPEAKER)) {
+            if ((context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) ||
+                (new_device & AUDIO_DEVICE_OUT_SPEAKER)) {
                 recompute_gain_dep_cal_Level = true;
             }
 
@@ -546,7 +546,7 @@
                 goto exit;
             }
 
-            if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) {
+            if (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) {
                 recompute_gain_dep_cal_Level = true;
             }
 
@@ -771,7 +771,7 @@
             ALOGV("--- Found something to remove ---");
             list_remove(node);
             PRINT_STREAM_TYPE(context->stream_type);
-            if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) {
+            if (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) {
                 recompute_flag = true;
             }
             list_remove(&context->effect_list_node);
diff --git a/qahw_api/test/qahw_playback_test.c b/qahw_api/test/qahw_playback_test.c
index ef44fae..e316fd9 100644
--- a/qahw_api/test/qahw_playback_test.c
+++ b/qahw_api/test/qahw_playback_test.c
@@ -545,6 +545,7 @@
     size_t bytes_read = 0;
     char  *data_ptr = NULL;
     bool exit = false;
+    int32_t latency;
 
     if (is_offload) {
         fprintf(log_file, "stream %d: set callback for offload stream for playback usecase\n", params->stream_index);
@@ -634,6 +635,9 @@
         pthread_exit(0);
     }
 
+    latency = qahw_out_get_latency(params->out_handle);
+    fprintf(log_file, "playback latency before starting a session %dms!!\n",
+            latency);
     while (!exit && !stop_playback) {
         if (!bytes_remaining) {
             fprintf(log_file, "\nstream %d: reading bytes %zd\n", params->stream_index, bytes_wanted);
@@ -662,8 +666,10 @@
                 params->stream_index, bytes_remaining, offset, write_length);
         bytes_written = write_to_hal(params->out_handle, data_ptr+offset, bytes_remaining, params);
         bytes_remaining -= bytes_written;
-        fprintf(log_file, "stream %d: bytes_written %zd, bytes_remaining %zd\n",
-                params->stream_index, bytes_written, bytes_remaining);
+
+        latency = qahw_out_get_latency(params->out_handle);
+        fprintf(log_file, "stream %d: bytes_written %zd, bytes_remaining %zd latency %d\n",
+                params->stream_index, bytes_written, bytes_remaining, latency);
     }
 
     if (params->ethread_data != nullptr) {
diff --git a/visualizer/offload_visualizer.c b/visualizer/offload_visualizer.c
index 30e9e79..6c9a01f 100644
--- a/visualizer/offload_visualizer.c
+++ b/visualizer/offload_visualizer.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2017 The Android Open Source Project
+ * Copyright (C) 2013 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.