Merge "hal: audio_extn: fix pop noise when FM is interrupted by voice call"
diff --git a/hal/Android.mk b/hal/Android.mk
index e7ba38f..e457b83 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -161,10 +161,6 @@
 endif
 endif
 
-ifeq ($(strip $(AUDIO_FEATURE_ENABLED_MULTIPLE_TUNNEL)), true)
-    LOCAL_CFLAGS += -DMULTIPLE_OFFLOAD_ENABLED
-endif
-
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_FLAC_DECODER)),true)
     LOCAL_CFLAGS += -DFLAC_OFFLOAD_ENABLED
     LOCAL_CFLAGS += -DCOMPRESS_METADATA_NEEDED
@@ -256,6 +252,14 @@
     LOCAL_SRC_FILES += audio_extn/listen.c
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXT_HDMI)),true)
+    LOCAL_CFLAGS += -DAUDIO_EXTERNAL_HDMI_ENABLED
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HDMI_PASSTHROUGH)),true)
+    LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-parsers
+    LOCAL_SHARED_LIBRARIES += libaudioparsers
+endif
+endif
+
 ifeq ($(strip $(BOARD_SUPPORTS_SOUND_TRIGGER)),true)
     LOCAL_CFLAGS += -DSOUND_TRIGGER_ENABLED
     LOCAL_CFLAGS += -DSOUND_TRIGGER_PLATFORM_NAME=$(TARGET_BOARD_PLATFORM)
diff --git a/hal/audio_extn/audio_defs.h b/hal/audio_extn/audio_defs.h
index 9d80112..1c5da54 100644
--- a/hal/audio_extn/audio_defs.h
+++ b/hal/audio_extn/audio_defs.h
@@ -101,4 +101,6 @@
 /* Query if Proxy can be Opend */
 #define AUDIO_PARAMETER_KEY_CAN_OPEN_PROXY "can_open_proxy"
 
+#define AUDIO_PARAMETER_IS_HW_DECODER_SESSION_ALLOWED  "is_hw_dec_session_allowed"
+
 #endif /* AUDIO_DEFS_H */
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 39ad4d1..ce8f965 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -874,9 +874,7 @@
 static perf_lock_acquire_t perf_lock_acq;
 static perf_lock_release_t perf_lock_rel;
 
-static int perf_lock_handle;
 char opt_lib_path[512] = {0};
-int perf_lock_opts[1] = {0x20E};
 
 int audio_extn_perf_lock_init(void)
 {
@@ -914,19 +912,30 @@
     return ret;
 }
 
-void audio_extn_perf_lock_acquire(void)
+void audio_extn_perf_lock_acquire(int *handle, int duration,
+                                 int *perf_lock_opts, int size)
 {
-    if (perf_lock_acq)
-        perf_lock_handle = perf_lock_acq(perf_lock_handle, 0, perf_lock_opts, 1);
-    else
-        ALOGE("%s: Perf lock acquire error \n", __func__);
+
+    if (!perf_lock_opts || !size || !perf_lock_acq || !handle)
+        return -EINVAL;
+    /*
+     * Acquire performance lock for 1 sec during device path bringup.
+     * Lock will be released either after 1 sec or when perf_lock_release
+     * function is executed.
+     */
+    *handle = perf_lock_acq(*handle, duration, perf_lock_opts, size);
+    if (*handle <= 0)
+        ALOGE("%s: Failed to acquire perf lock, err: %d\n",
+              __func__, *handle);
 }
 
-void audio_extn_perf_lock_release(void)
+void audio_extn_perf_lock_release(int *handle)
 {
-    if (perf_lock_rel && perf_lock_handle)
-        perf_lock_rel(perf_lock_handle);
-    else
+    if (perf_lock_rel && handle && (*handle > 0)) {
+        perf_lock_rel(*handle);
+        *handle = 0;
+    } else {
         ALOGE("%s: Perf lock release error \n", __func__);
+    }
 }
 #endif /* KPI_OPTIMIZE_ENABLED */
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index dca965a..b4848a4 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -503,11 +503,19 @@
 
 #ifndef KPI_OPTIMIZE_ENABLED
 #define audio_extn_perf_lock_init() (0)
-#define audio_extn_perf_lock_acquire() (0)
-#define audio_extn_perf_lock_release() (0)
+#define audio_extn_perf_lock_acquire(handle, duration, opts, size) (0)
+#define audio_extn_perf_lock_release(handle) (0)
 #else
 int audio_extn_perf_lock_init(void);
-void audio_extn_perf_lock_acquire(void);
-void audio_extn_perf_lock_release(void);
+void audio_extn_perf_lock_acquire(int *handle, int duration,
+                                 int *opts, int size);
+void audio_extn_perf_lock_release(int *handle);
+
 #endif /* KPI_OPTIMIZE_ENABLED */
+
+#ifndef AUDIO_EXTERNAL_HDMI_ENABLED
+#define audio_utils_set_hdmi_channel_status(out, buffer, bytes) (0)
+#else
+void audio_utils_set_hdmi_channel_status(struct stream_out *out, char * buffer, size_t bytes);
+#endif
 #endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
index a73dfa1..3e09e55 100644
--- a/hal/audio_extn/hfp.c
+++ b/hal/audio_extn/hfp.c
@@ -47,6 +47,8 @@
 
 #ifdef PLATFORM_MSM8994
 #define HFP_RX_VOLUME     "SEC AUXPCM LOOPBACK Volume"
+#elif defined PLATFORM_MSM8996
+#define HFP_RX_VOLUME     "PRI AUXPCM LOOPBACK Volume"
 #else
 #define HFP_RX_VOLUME     "Internal HFP RX Volume"
 #endif
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index b9e2a40..a114b30 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -35,6 +35,12 @@
 #include "audio_extn.h"
 #include "voice.h"
 
+#ifdef AUDIO_EXTERNAL_HDMI_ENABLED
+#ifdef HDMI_PASSTHROUGH_ENABLED
+#include "audio_parsers.h"
+#endif
+#endif
+
 #define AUDIO_OUTPUT_POLICY_VENDOR_CONFIG_FILE "/vendor/etc/audio_output_policy.conf"
 
 #define OUTPUTS_TAG "outputs"
@@ -52,6 +58,21 @@
 #define BASE_TABLE_SIZE 64
 #define MAX_BASEINDEX_LEN 256
 
+#ifdef AUDIO_EXTERNAL_HDMI_ENABLED
+#define PROFESSIONAL        (1<<0)      /* 0 = consumer, 1 = professional */
+#define NON_LPCM            (1<<1)      /* 0 = audio, 1 = non-audio */
+#define SR_44100            (0<<0)      /* 44.1kHz */
+#define SR_NOTID            (1<<0)      /* non indicated */
+#define SR_48000            (2<<0)      /* 48kHz */
+#define SR_32000            (3<<0)      /* 32kHz */
+#define SR_22050            (4<<0)      /* 22.05kHz */
+#define SR_24000            (6<<0)      /* 24kHz */
+#define SR_88200            (8<<0)      /* 88.2kHz */
+#define SR_96000            (10<<0)     /* 96kHz */
+#define SR_176400           (12<<0)     /* 176.4kHz */
+#define SR_192000           (14<<0)     /* 192kHz */
+
+#endif
 struct string_to_enum {
     const char *name;
     uint32_t value;
@@ -566,14 +587,13 @@
     } else if (usecase->type == PCM_PLAYBACK) {
         if ((24 == usecase->stream.out->bit_width) &&
             (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER)) {
-            sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+            usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
         } else if ((snd_device != SND_DEVICE_OUT_HEADPHONES_44_1 &&
             usecase->stream.out->sample_rate == OUTPUT_SAMPLING_RATE_44100) ||
             (usecase->stream.out->sample_rate < OUTPUT_SAMPLING_RATE_44100)) {
-            sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
-        } else {
-            sample_rate = usecase->stream.out->app_type_cfg.sample_rate;
+            usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
         }
+        sample_rate = usecase->stream.out->app_type_cfg.sample_rate;
 
         app_type_cfg[len++] = usecase->stream.out->app_type_cfg.app_type;
         app_type_cfg[len++] = acdb_dev_id;
@@ -765,3 +785,136 @@
     outp[k] = '\0';
     return k;
 }
+
+#ifdef AUDIO_EXTERNAL_HDMI_ENABLED
+
+void get_default_compressed_channel_status(
+                                  unsigned char *channel_status)
+{
+     int32_t status = 0;
+     unsigned char bit_index;
+     memset(channel_status,0,24);
+
+     /* block start bit in preamble bit 3 */
+     channel_status[0] |= PROFESSIONAL;
+     //compre out
+     channel_status[0] |= NON_LPCM;
+     // sample rate; fixed 48K for default/transcode
+     channel_status[3] |= SR_48000;
+}
+
+#ifdef HDMI_PASSTHROUGH_ENABLED
+int32_t get_compressed_channel_status(void *audio_stream_data,
+                                                   uint32_t audio_frame_size,
+                                                   unsigned char *channel_status,
+                                                   enum audio_parser_code_type codec_type)
+                                                   // codec_type - AUDIO_PARSER_CODEC_AC3
+                                                   //            - AUDIO_PARSER_CODEC_DTS
+{
+     unsigned char *stream;
+     int ret = 0;
+     stream = (unsigned char *)audio_stream_data;
+
+     if (audio_stream_data == NULL || audio_frame_size == 0) {
+         ALOGW("no buffer to get channel status, return default for compress");
+         get_default_compressed_channel_status(channel_status);
+         return ret;
+     }
+
+     memset(channel_status,0,24);
+     if(init_audio_parser(stream, audio_frame_size, codec_type) == -1)
+     {
+         ALOGE("init audio parser failed");
+         return -1;
+     }
+     ret = get_channel_status(channel_status, codec_type);
+     return ret;
+
+}
+
+#endif
+
+void get_lpcm_channel_status(uint32_t sampleRate,
+                                                  unsigned char *channel_status)
+{
+     int32_t status = 0;
+     unsigned char bit_index;
+     memset(channel_status,0,24);
+     /* block start bit in preamble bit 3 */
+     channel_status[0] |= PROFESSIONAL;
+     //LPCM OUT
+     channel_status[0] &= ~NON_LPCM;
+
+     switch (sampleRate) {
+         case 8000:
+         case 11025:
+         case 12000:
+         case 16000:
+         case 22050:
+             channel_status[3] |= SR_NOTID;
+         case 24000:
+             channel_status[3] |= SR_24000;
+             break;
+         case 32000:
+             channel_status[3] |= SR_32000;
+             break;
+         case 44100:
+             channel_status[3] |= SR_44100;
+             break;
+         case 48000:
+             channel_status[3] |= SR_48000;
+             break;
+         case 88200:
+             channel_status[3] |= SR_88200;
+             break;
+         case 96000:
+             channel_status[3] |= SR_96000;
+             break;
+         case 176400:
+             channel_status[3] |= SR_176400;
+             break;
+         case 192000:
+            channel_status[3] |= SR_192000;
+             break;
+         default:
+             ALOGV("Invalid sample_rate %u\n", sampleRate);
+             status = -1;
+             break;
+     }
+}
+
+void audio_utils_set_hdmi_channel_status(struct stream_out *out, char * buffer, size_t bytes)
+{
+    unsigned char channel_status[24]={0};
+    struct snd_aes_iec958 iec958;
+    const char *mixer_ctl_name = "IEC958 Playback PCM Stream";
+    struct mixer_ctl *ctl;
+    int i=0;
+#ifdef HDMI_PASSTHROUGH_ENABLED
+    if (audio_extn_is_dolby_format(out->format) &&
+        /*TODO:Extend code to support DTS passthrough*/
+        /*set compressed channel status bits*/
+        audio_extn_dolby_is_passthrough_stream(out->flags)){
+        get_compressed_channel_status(buffer, bytes, channel_status, AUDIO_PARSER_CODEC_AC3);
+    } else
+#endif
+    {
+        /*set channel status bit for LPCM*/
+        get_lpcm_channel_status(out->sample_rate, channel_status);
+    }
+
+    memcpy(iec958.status, channel_status,sizeof(iec958.status));
+    ctl = mixer_get_ctl_by_name(out->dev->mixer, mixer_ctl_name);
+    if (!ctl) {
+            ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                  __func__, mixer_ctl_name);
+            return;
+    }
+    if (mixer_ctl_set_array(ctl, &iec958, sizeof(iec958)) < 0) {
+        ALOGE("%s: Could not set channel status for ext HDMI ",
+              __func__);
+        return;
+    }
+
+}
+#endif
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index d5db25b..e6fbc5f 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -168,7 +168,7 @@
     [USECASE_AUDIO_PLAYBACK_ULL]         = "audio-ull-playback",
     [USECASE_AUDIO_PLAYBACK_MULTI_CH]    = "multi-channel-playback",
     [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
-#ifdef MULTIPLE_OFFLOAD_ENABLED
+    //Enabled for Direct_PCM
     [USECASE_AUDIO_PLAYBACK_OFFLOAD2] = "compress-offload-playback2",
     [USECASE_AUDIO_PLAYBACK_OFFLOAD3] = "compress-offload-playback3",
     [USECASE_AUDIO_PLAYBACK_OFFLOAD4] = "compress-offload-playback4",
@@ -177,8 +177,6 @@
     [USECASE_AUDIO_PLAYBACK_OFFLOAD7] = "compress-offload-playback7",
     [USECASE_AUDIO_PLAYBACK_OFFLOAD8] = "compress-offload-playback8",
     [USECASE_AUDIO_PLAYBACK_OFFLOAD9] = "compress-offload-playback9",
-#endif
-    [USECASE_AUDIO_DIRECT_PCM_OFFLOAD] = "compress-offload-playback2",
 
     [USECASE_AUDIO_RECORD] = "audio-record",
     [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress",
@@ -214,7 +212,6 @@
 
 static const audio_usecase_t offload_usecases[] = {
     USECASE_AUDIO_PLAYBACK_OFFLOAD,
-#ifdef MULTIPLE_OFFLOAD_ENABLED
     USECASE_AUDIO_PLAYBACK_OFFLOAD2,
     USECASE_AUDIO_PLAYBACK_OFFLOAD3,
     USECASE_AUDIO_PLAYBACK_OFFLOAD4,
@@ -223,8 +220,6 @@
     USECASE_AUDIO_PLAYBACK_OFFLOAD7,
     USECASE_AUDIO_PLAYBACK_OFFLOAD8,
     USECASE_AUDIO_PLAYBACK_OFFLOAD9,
-#endif
-    USECASE_AUDIO_DIRECT_PCM_OFFLOAD,
 };
 
 #define STRING_TO_ENUM(string) { #string, string }
@@ -453,8 +448,8 @@
     audio_extn_dolby_ds2_set_endpoint(adev);
     audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_BUSY);
     audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_BUSY);
-    audio_extn_utils_send_audio_calibration(adev, usecase);
     audio_extn_utils_send_app_type_cfg(adev, usecase);
+    audio_extn_utils_send_audio_calibration(adev, usecase);
     strcpy(mixer_path, use_case_table[usecase->id]);
     platform_add_backend_name(mixer_path, snd_device, usecase);
     ALOGD("%s: apply mixer and update path: %s", __func__, mixer_path);
@@ -601,6 +596,9 @@
             audio_route_reset_and_update_path(adev->audio_route, device_name);
         }
 
+        if (snd_device == SND_DEVICE_OUT_HDMI)
+            adev->is_channel_status_set = false;
+
         audio_extn_dev_arbi_release(snd_device);
         audio_extn_sound_trigger_update_device_status(snd_device,
                                         ST_EVENT_SND_DEVICE_FREE);
@@ -1126,7 +1124,9 @@
     uc_info->out_snd_device = SND_DEVICE_NONE;
 
     list_add_tail(&adev->usecase_list, &uc_info->list);
-    audio_extn_perf_lock_acquire();
+    audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
+                                 adev->perf_lock_opts,
+                                 adev->perf_lock_opts_size);
     select_devices(adev, in->usecase);
 
     ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
@@ -1168,16 +1168,14 @@
         goto error_open;
     }
 
-    audio_extn_perf_lock_release();
-
+    audio_extn_perf_lock_release(&adev->perf_lock_handle);
     ALOGD("%s: exit", __func__);
 
     return ret;
 
 error_open:
+    audio_extn_perf_lock_release(&adev->perf_lock_handle);
     stop_input_stream(in);
-    audio_extn_perf_lock_release();
-
 error_config:
     adev->active_input = NULL;
     /*
@@ -1190,6 +1188,20 @@
     return ret;
 }
 
+void lock_input_stream(struct stream_in *in)
+{
+    pthread_mutex_lock(&in->pre_lock);
+    pthread_mutex_lock(&in->lock);
+    pthread_mutex_unlock(&in->pre_lock);
+}
+
+void lock_output_stream(struct stream_out *out)
+{
+    pthread_mutex_lock(&out->pre_lock);
+    pthread_mutex_lock(&out->lock);
+    pthread_mutex_unlock(&out->pre_lock);
+}
+
 /* must be called with out->lock locked */
 static int send_offload_cmd_l(struct stream_out* out, int command)
 {
@@ -1232,35 +1244,50 @@
     return false;
 }
 
-static audio_usecase_t get_offload_usecase(struct audio_device *adev)
+static audio_usecase_t get_offload_usecase(struct audio_device *adev, bool is_direct_pcm)
 {
-    audio_usecase_t ret = USECASE_AUDIO_PLAYBACK_OFFLOAD;
-    unsigned int i, num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
-    char value[PROPERTY_VALUE_MAX] = {0};
+    audio_usecase_t ret_uc = USECASE_INVALID;
+    unsigned int offload_uc_index;
+    int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
+    if (!adev->multi_offload_enable) {
+        if (is_direct_pcm)
+            ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD2;
+        else
+            ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD;
 
-    property_get("audio.offload.multiple.enabled", value, NULL);
-    if (!(atoi(value) || !strncmp("true", value, 4)))
-        num_usecase = 1; /* If prop is not set, limit the num of offload usecases to 1 */
+        pthread_mutex_lock(&adev->lock);
+        if (get_usecase_from_list(adev, ret_uc) != NULL)
+           ret_uc = USECASE_INVALID;
+        pthread_mutex_unlock(&adev->lock);
+
+        return ret_uc;
+    }
 
     ALOGV("%s: num_usecase: %d", __func__, num_usecase);
-    for (i = 0; i < num_usecase; i++) {
-        if (!(adev->offload_usecases_state & (0x1<<i))) {
-            adev->offload_usecases_state |= 0x1 << i;
-            ret = offload_usecases[i];
+    for (offload_uc_index = 0; offload_uc_index < num_usecase; offload_uc_index++) {
+        if (!(adev->offload_usecases_state & (0x1 << offload_uc_index))) {
+            adev->offload_usecases_state |= 0x1 << offload_uc_index;
+            ret_uc = offload_usecases[offload_uc_index];
             break;
         }
     }
-    ALOGV("%s: offload usecase is %d", __func__, ret);
-    return ret;
+
+    ALOGV("%s: offload usecase is %d", __func__, ret_uc);
+    return ret_uc;
 }
 
 static void free_offload_usecase(struct audio_device *adev,
                                  audio_usecase_t uc_id)
 {
-    unsigned int i;
-    for (i = 0; i < sizeof(offload_usecases)/sizeof(offload_usecases[0]); i++) {
-        if (offload_usecases[i] == uc_id) {
-            adev->offload_usecases_state &= ~(0x1<<i);
+    unsigned int offload_uc_index;
+    int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
+
+    if (!adev->multi_offload_enable)
+        return;
+
+    for (offload_uc_index = 0; offload_uc_index < num_usecase; offload_uc_index++) {
+        if (offload_usecases[offload_uc_index] == uc_id) {
+            adev->offload_usecases_state &= ~(0x1 << offload_uc_index);
             break;
         }
     }
@@ -1278,7 +1305,7 @@
     prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
 
     ALOGV("%s", __func__);
-    pthread_mutex_lock(&out->lock);
+    lock_output_stream(out);
     for (;;) {
         struct offload_cmd *cmd = NULL;
         stream_callback_event_t event;
@@ -1357,7 +1384,7 @@
             ALOGE("%s unknown command received: %d", __func__, cmd->cmd);
             break;
         }
-        pthread_mutex_lock(&out->lock);
+        lock_output_stream(out);
         out->offload_thread_blocked = false;
         pthread_cond_signal(&out->cond);
         if (send_callback && out->offload_callback) {
@@ -1389,7 +1416,7 @@
 
 static int destroy_offload_callback_thread(struct stream_out *out)
 {
-    pthread_mutex_lock(&out->lock);
+    lock_output_stream(out);
     stop_compressed_output_l(out);
     send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
 
@@ -1617,6 +1644,9 @@
     }
     list_add_tail(&adev->usecase_list, &uc_info->list);
 
+    audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
+                                 adev->perf_lock_opts,
+                                 adev->perf_lock_opts_size);
     select_devices(adev, out->usecase);
 
     ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)",
@@ -1707,11 +1737,12 @@
             audio_extn_check_and_set_dts_hpx_state(adev);
         }
     }
-
+    audio_extn_perf_lock_release(&adev->perf_lock_handle);
     ALOGD("%s: exit", __func__);
 
     return 0;
 error_open:
+    audio_extn_perf_lock_release(&adev->perf_lock_handle);
     stop_output_stream(out);
 error_config:
     /*
@@ -1848,7 +1879,7 @@
         return 0;
     }
 
-    pthread_mutex_lock(&out->lock);
+    lock_output_stream(out);
     if (!out->standby) {
         if (adev->adm_deregister_stream)
             adev->adm_deregister_stream(adev->adm_data, out->handle);
@@ -1937,7 +1968,7 @@
     err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
     if (err >= 0) {
         val = atoi(value);
-        pthread_mutex_lock(&out->lock);
+        lock_output_stream(out);
         pthread_mutex_lock(&adev->lock);
 
         /*
@@ -2001,7 +2032,7 @@
         pthread_mutex_unlock(&adev->lock);
     }
     if (is_offload_usecase(out->usecase)) {
-        pthread_mutex_lock(&out->lock);
+        lock_output_stream(out);
         parse_compress_metadata(out, parms);
 
         audio_extn_dts_create_state_notifier_node(out->usecase);
@@ -2157,7 +2188,7 @@
     int snd_scard_state = get_snd_card_state(adev);
     ssize_t ret = 0;
 
-    pthread_mutex_lock(&out->lock);
+    lock_output_stream(out);
 
     if (SND_CARD_STATE_OFFLINE == snd_scard_state) {
         // increase written size during SSR to avoid mismatch
@@ -2190,10 +2221,15 @@
             out->standby = true;
             goto exit;
         }
-        if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD && adev->adm_register_output_stream)
+        if (!is_offload_usecase(out->usecase) && adev->adm_register_output_stream)
             adev->adm_register_output_stream(adev->adm_data, out->handle, out->flags);
     }
 
+    if (adev->is_channel_status_set == false && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)){
+        audio_utils_set_hdmi_channel_status(out, buffer, bytes);
+        adev->is_channel_status_set = true;
+    }
+
     if (is_offload_usecase(out->usecase)) {
         ALOGVV("copl(%p): writing buffer (%zu bytes) to compress device", out, bytes);
         if (out->send_new_metadata) {
@@ -2297,7 +2333,7 @@
     *dsp_frames = 0;
     if (is_offload_usecase(out->usecase)) {
         ssize_t ret = 0;
-        pthread_mutex_lock(&out->lock);
+        lock_output_stream(out);
         if (out->compr != NULL) {
             ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
                     &out->sample_rate);
@@ -2356,7 +2392,7 @@
     int ret = -1;
     unsigned long dsp_frames;
 
-    pthread_mutex_lock(&out->lock);
+    lock_output_stream(out);
 
     if (is_offload_usecase(out->usecase)) {
         if (out->compr != NULL) {
@@ -2408,7 +2444,7 @@
     struct stream_out *out = (struct stream_out *)stream;
 
     ALOGV("%s", __func__);
-    pthread_mutex_lock(&out->lock);
+    lock_output_stream(out);
     out->offload_callback = callback;
     out->offload_cookie = cookie;
     pthread_mutex_unlock(&out->lock);
@@ -2422,7 +2458,7 @@
     ALOGV("%s", __func__);
     if (is_offload_usecase(out->usecase)) {
         ALOGD("copl(%p):pause compress driver", out);
-        pthread_mutex_lock(&out->lock);
+        lock_output_stream(out);
         if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
             struct audio_device *adev = out->dev;
             int snd_scard_state = get_snd_card_state(adev);
@@ -2450,7 +2486,7 @@
     if (is_offload_usecase(out->usecase)) {
         ALOGD("copl(%p):resume compress driver", out);
         status = 0;
-        pthread_mutex_lock(&out->lock);
+        lock_output_stream(out);
         if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) {
             struct audio_device *adev = out->dev;
             int snd_scard_state = get_snd_card_state(adev);
@@ -2475,7 +2511,7 @@
     int status = -ENOSYS;
     ALOGV("%s", __func__);
     if (is_offload_usecase(out->usecase)) {
-        pthread_mutex_lock(&out->lock);
+        lock_output_stream(out);
         if (type == AUDIO_DRAIN_EARLY_NOTIFY)
             status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN);
         else
@@ -2491,7 +2527,7 @@
     ALOGV("%s", __func__);
     if (is_offload_usecase(out->usecase)) {
         ALOGD("copl(%p):calling compress flush", out);
-        pthread_mutex_lock(&out->lock);
+        lock_output_stream(out);
         stop_compressed_output_l(out);
         pthread_mutex_unlock(&out->lock);
         ALOGD("copl(%p):out of compress flush", out);
@@ -2563,7 +2599,7 @@
         return status;
     }
 
-    pthread_mutex_lock(&in->lock);
+    lock_input_stream(in);
     if (!in->standby && in->is_st_session) {
         ALOGD("%s: sound trigger pcm stop lab", __func__);
         audio_extn_sound_trigger_stop_lab(in);
@@ -2608,7 +2644,7 @@
 
     if (!parms)
         goto error;
-    pthread_mutex_lock(&in->lock);
+    lock_input_stream(in);
     pthread_mutex_lock(&adev->lock);
 
     err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value));
@@ -2692,7 +2728,7 @@
     int i, ret = -1;
     int snd_scard_state = get_snd_card_state(adev);
 
-    pthread_mutex_lock(&in->lock);
+    lock_input_stream(in);
 
     if (in->is_st_session) {
         ALOGVV(" %s: reading on st session bytes=%zu", __func__, bytes);
@@ -2792,7 +2828,7 @@
     if (status != 0)
         return status;
 
-    pthread_mutex_lock(&in->lock);
+    lock_input_stream(in);
     pthread_mutex_lock(&in->dev->lock);
     if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
             in->enable_aec != enable &&
@@ -2860,6 +2896,7 @@
     }
 
     pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
+    pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL);
     pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL);
 
     if (devices == AUDIO_DEVICE_NONE)
@@ -2951,18 +2988,24 @@
         }
 
         if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) {
-            ALOGV("%s:: inserting DIRECT_PCM _USECASE", __func__);
-            out->usecase = USECASE_AUDIO_DIRECT_PCM_OFFLOAD;
+            out->usecase = get_offload_usecase(adev, true);
+            ALOGV("DIRECT_PCM usecase ... usecase selected %d ", out->usecase);
         } else {
-            ALOGV("%s:: inserting OFFLOAD_USECASE", __func__);
-            out->usecase = get_offload_usecase(adev);
-
             out->stream.set_callback = out_set_callback;
             out->stream.pause = out_pause;
             out->stream.resume = out_resume;
             out->stream.drain = out_drain;
             out->stream.flush = out_flush;
+            out->usecase = get_offload_usecase(adev, false);
+            ALOGV("Compress Offload usecase .. usecase selected %d", out->usecase);
         }
+
+        if (out->usecase == USECASE_INVALID) {
+            ALOGE("%s: Max allowed OFFLOAD usecase reached ... ");
+            ret = -EEXIST;
+            goto error_open;
+        }
+
         if (config->offload_info.channel_mask)
             out->channel_mask = config->offload_info.channel_mask;
         else if (config->channel_mask) {
@@ -3524,6 +3567,7 @@
         devices, &in->stream, handle, source);
 
     pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
+    pthread_mutex_init(&in->pre_lock, (const pthread_mutexattr_t *) NULL);
 
     in->stream.common.get_sample_rate = in_get_sample_rate;
     in->stream.common.set_sample_rate = in_set_sample_rate;
@@ -3621,7 +3665,6 @@
     /* This stream could be for sound trigger lab,
        get sound trigger pcm if present */
     audio_extn_sound_trigger_check_and_get_session(in);
-    audio_extn_perf_lock_init();
 
     *stream_in = &in->stream;
     ALOGV("%s: exit", __func__);
@@ -3781,6 +3824,10 @@
     list_init(&adev->usecase_list);
     adev->cur_wfd_channels = 2;
     adev->offload_usecases_state = 0;
+    adev->is_channel_status_set = false;
+    adev->perf_lock_opts[0] = 0x101;
+    adev->perf_lock_opts[1] = 0x20E;
+    adev->perf_lock_opts_size = 2;
 
     pthread_mutex_init(&adev->snd_card_status.lock, (const pthread_mutexattr_t *) NULL);
     adev->snd_card_status.state = SND_CARD_STATE_OFFLINE;
@@ -3892,11 +3939,13 @@
         }
     }
 
+    adev->multi_offload_enable = property_get_bool("audio.offload.multiple.enabled", false);
     pthread_mutex_unlock(&adev_init_lock);
 
     if (adev->adm_init)
         adev->adm_data = adev->adm_init();
 
+    audio_extn_perf_lock_init();
     ALOGV("%s: exit", __func__);
     return 0;
 }
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 5c1ea1d..fd19211 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -74,6 +74,8 @@
 #define SND_CARD_STATE_OFFLINE 0
 #define SND_CARD_STATE_ONLINE 1
 
+#define MAX_PERF_LOCK_OPTS 20
+
 /* These are the supported use cases by the hardware.
  * Each usecase is mapped to a specific PCM device.
  * Refer to pcm_device_table[].
@@ -85,7 +87,6 @@
     USECASE_AUDIO_PLAYBACK_LOW_LATENCY,
     USECASE_AUDIO_PLAYBACK_MULTI_CH,
     USECASE_AUDIO_PLAYBACK_OFFLOAD,
-#ifdef MULTIPLE_OFFLOAD_ENABLED
     USECASE_AUDIO_PLAYBACK_OFFLOAD2,
     USECASE_AUDIO_PLAYBACK_OFFLOAD3,
     USECASE_AUDIO_PLAYBACK_OFFLOAD4,
@@ -94,11 +95,8 @@
     USECASE_AUDIO_PLAYBACK_OFFLOAD7,
     USECASE_AUDIO_PLAYBACK_OFFLOAD8,
     USECASE_AUDIO_PLAYBACK_OFFLOAD9,
-#endif
     USECASE_AUDIO_PLAYBACK_ULL,
 
-    USECASE_AUDIO_DIRECT_PCM_OFFLOAD,
-
     /* FM usecase */
     USECASE_AUDIO_PLAYBACK_FM,
 
@@ -184,6 +182,7 @@
 struct stream_out {
     struct audio_stream_out stream;
     pthread_mutex_t lock; /* see note below on mutex acquisition order */
+    pthread_mutex_t pre_lock; /* acquire before lock to avoid DOS by playback thread */
     pthread_cond_t  cond;
     struct pcm_config config;
     struct compr_config compr_config;
@@ -228,6 +227,7 @@
 struct stream_in {
     struct audio_stream_in stream;
     pthread_mutex_t lock; /* see note below on mutex acquisition order */
+    pthread_mutex_t pre_lock; /* acquire before lock to avoid DOS by playback thread */
     struct pcm_config config;
     struct pcm *pcm;
     int standby;
@@ -327,6 +327,7 @@
     int snd_card;
     unsigned int cur_codec_backend_samplerate;
     unsigned int cur_codec_backend_bit_width;
+    bool is_channel_status_set;
     void *platform;
     unsigned int offload_usecases_state;
     void *visualizer_lib;
@@ -352,6 +353,11 @@
     void (*offload_effects_get_parameters)(struct str_parms *,
                                            struct str_parms *);
     void (*offload_effects_set_parameters)(struct str_parms *);
+
+    bool multi_offload_enable;
+    int perf_lock_handle;
+    int perf_lock_opts[MAX_PERF_LOCK_OPTS];
+    int perf_lock_opts_size;
 };
 
 int select_devices(struct audio_device *adev,
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index baec1e0..a478f93 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -138,6 +138,17 @@
 
 #define AUDIO_PARAMETER_KEY_REC_PLAY_CONC "rec_play_conc_on"
 
+#define  AUDIO_PARAMETER_IS_HW_DECODER_SESSION_ALLOWED  "is_hw_dec_session_allowed"
+
+char * dsp_only_decoders_mime[] = {
+    "audio/x-ms-wma" /* wma*/ ,
+    "audio/x-ms-wma-lossless" /* wma lossless */ ,
+    "audio/x-ms-wma-pro" /* wma prop */ ,
+    "audio/amr-wb-plus" /* amr wb plus */ ,
+    "audio/alac"  /*alac */ ,
+    "audio/x-ape" /*ape */,
+};
+
 enum {
 	VOICE_FEATURE_SET_DEFAULT,
 	VOICE_FEATURE_SET_VOLUME_BOOST
@@ -257,7 +268,6 @@
                                         MULTIMEDIA2_PCM_DEVICE},
     [USECASE_AUDIO_PLAYBACK_OFFLOAD] =
                      {PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE},
-#ifdef MULTIPLE_OFFLOAD_ENABLED
     /* Below entries are initialized with invalid values
      * Valid values should be updated from fnc platform_info_init()
      * based on pcm ids defined in audio_platform_info.xml.
@@ -270,9 +280,6 @@
     [USECASE_AUDIO_PLAYBACK_OFFLOAD7] = {-1, -1},
     [USECASE_AUDIO_PLAYBACK_OFFLOAD8] = {-1, -1},
     [USECASE_AUDIO_PLAYBACK_OFFLOAD9] = {-1, -1},
-#endif
-    [USECASE_AUDIO_DIRECT_PCM_OFFLOAD] =
-                     {PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE},
     [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE},
     [USECASE_AUDIO_RECORD_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, COMPRESS_CAPTURE_DEVICE},
     [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
@@ -648,7 +655,6 @@
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_LOW_LATENCY)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MULTI_CH)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD)},
-#ifdef MULTIPLE_OFFLOAD_ENABLED
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD2)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD3)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD4)},
@@ -657,8 +663,6 @@
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD7)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD8)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD9)},
-#endif
-    {TO_NAME_INDEX(USECASE_AUDIO_DIRECT_PCM_OFFLOAD)},
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)},
     {TO_NAME_INDEX(USECASE_VOICE_CALL)},
@@ -3435,6 +3439,8 @@
     char value[512] = {0};
     int ret;
     char *kv_pairs = NULL;
+    char propValue[PROPERTY_VALUE_MAX]={0};
+    bool prop_playback_enabled = false;
 
     ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SLOWTALK,
                             value, sizeof(value));
@@ -3463,6 +3469,37 @@
     }
     native_audio_get_params(query, reply, value, sizeof(value));
 
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_IS_HW_DECODER_SESSION_ALLOWED,
+                                    value, sizeof(value));
+    if (ret >= 0) {
+        int isallowed = 1; /*true*/
+
+        if (property_get("voice.playback.conc.disabled", propValue, NULL)) {
+            prop_playback_enabled = atoi(propValue) ||
+                !strncmp("true", propValue, 4);
+        }
+
+        if (prop_playback_enabled && (voice_is_in_call(my_data->adev) ||
+             (SND_CARD_STATE_OFFLINE == get_snd_card_state(my_data->adev)))) {
+            char *decoder_mime_type = value;
+
+            //check if unsupported mime type or not
+            if(decoder_mime_type) {
+                int i = 0;
+                for (i = 0; i < sizeof(dsp_only_decoders_mime)/sizeof(dsp_only_decoders_mime[0]); i++) {
+                    if (!strncmp(decoder_mime_type, dsp_only_decoders_mime[i],
+                    strlen(dsp_only_decoders_mime[i]))) {
+                       ALOGD("Rejecting request for DSP only session from HAL during voice call/SSR state");
+                       isallowed = 0;
+                       break;
+                    }
+                }
+            }
+        }
+        str_parms_add_int(reply, AUDIO_PARAMETER_IS_HW_DECODER_SESSION_ALLOWED, isallowed);
+    }
+
+
     /* Handle audio calibration keys */
     kv_pairs = str_parms_to_str(reply);
     ALOGV("%s: exit: returns - %s", __func__, kv_pairs);
@@ -3513,7 +3550,6 @@
     case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER:
     case USECASE_AUDIO_PLAYBACK_MULTI_CH:
     case USECASE_AUDIO_PLAYBACK_OFFLOAD:
-    case USECASE_AUDIO_DIRECT_PCM_OFFLOAD:
         needs_event = true;
         break;
     /* concurrent playback in low latency allowed */
@@ -3577,7 +3613,6 @@
     case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER:
     case USECASE_AUDIO_PLAYBACK_MULTI_CH:
     case USECASE_AUDIO_PLAYBACK_OFFLOAD:
-    case USECASE_AUDIO_DIRECT_PCM_OFFLOAD:
         needs_event = true;
         break;
     /* concurrent playback in low latency allowed */
@@ -4146,15 +4181,12 @@
     }
     edid_data[0] = count;
     memcpy(&edid_data[1], block, count);
-
-#ifdef AUDIO_FEATURE_ENABLED_HDMI_EDID
     if (!edid_get_sink_caps(info, edid_data)) {
         ALOGE("%s: Failed to get HDMI sink capabilities", __func__);
         goto fail;
     }
     my_data->edid_valid = true;
     return 0;
-#endif
 fail:
     if (my_data->edid_info) {
         free(my_data->edid_info);
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index b72cae9..8d5004d 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -374,7 +374,7 @@
 }
 
 void platform_add_backend_name(char *mixer_path, snd_device_t snd_device,
-                               struct audio_usecase *usecase)
+                               struct audio_usecase *usecase __unused)
 {
     if (snd_device == SND_DEVICE_IN_BT_SCO_MIC)
         strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
@@ -1172,3 +1172,8 @@
 {
     return 0;
 }
+
+void platform_set_gsm_mode(void *platform __unused, bool enable __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 5cb18fd..cc48b9e 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -118,6 +118,7 @@
 #define AUDIO_PARAMETER_KEY_AUD_CALDATA   "cal_data"
 #define AUDIO_PARAMETER_KEY_AUD_CALRESULT "cal_result"
 
+#define AUDIO_PARAMETER_KEY_PERF_LOCK_OPTS "perf_lock_opts"
 
 /* Query external audio device connection status */
 #define AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE "ext_audio_device"
@@ -133,6 +134,18 @@
         [WCD9XXX_VBAT_CAL] = "vbat_cal",
 };
 
+#define  AUDIO_PARAMETER_IS_HW_DECODER_SESSION_ALLOWED  "is_hw_dec_session_allowed"
+
+char * dsp_only_decoders_mime[] = {
+    "audio/x-ms-wma" /* wma*/ ,
+    "audio/x-ms-wma-lossless" /* wma lossless */ ,
+    "audio/x-ms-wma-pro" /* wma prop */ ,
+    "audio/amr-wb-plus" /* amr wb plus */ ,
+    "audio/alac"  /*alac */ ,
+    "audio/x-ape" /*ape */,
+};
+
+
 enum {
 	VOICE_FEATURE_SET_DEFAULT,
 	VOICE_FEATURE_SET_VOLUME_BOOST
@@ -245,7 +258,6 @@
                                          MULTIMEDIA2_PCM_DEVICE},
     [USECASE_AUDIO_PLAYBACK_OFFLOAD] =
                      {PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE},
-#ifdef MULTIPLE_OFFLOAD_ENABLED
     [USECASE_AUDIO_PLAYBACK_OFFLOAD2] =
                      {PLAYBACK_OFFLOAD_DEVICE2, PLAYBACK_OFFLOAD_DEVICE2},
     [USECASE_AUDIO_PLAYBACK_OFFLOAD3] =
@@ -262,10 +274,7 @@
                      {PLAYBACK_OFFLOAD_DEVICE8, PLAYBACK_OFFLOAD_DEVICE8},
     [USECASE_AUDIO_PLAYBACK_OFFLOAD9] =
                      {PLAYBACK_OFFLOAD_DEVICE9, PLAYBACK_OFFLOAD_DEVICE9},
-#endif
 
-    [USECASE_AUDIO_DIRECT_PCM_OFFLOAD] =
-                     {PLAYBACK_OFFLOAD_DEVICE2, PLAYBACK_OFFLOAD_DEVICE2},
 
     [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE},
     [USECASE_AUDIO_RECORD_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, COMPRESS_CAPTURE_DEVICE},
@@ -324,13 +333,16 @@
     [SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse",
     [SND_DEVICE_OUT_HEADPHONES] = "headphones",
     [SND_DEVICE_OUT_HEADPHONES_44_1] = "headphones-44.1",
+    [SND_DEVICE_OUT_LINE] = "line",
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones",
+    [SND_DEVICE_OUT_SPEAKER_AND_LINE] = "speaker-and-line",
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1] = "speaker-and-headphones-ext-1",
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2] = "speaker-and-headphones-ext-2",
     [SND_DEVICE_OUT_VOICE_HANDSET] = "voice-handset",
     [SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker",
     [SND_DEVICE_OUT_VOICE_SPEAKER_VBAT] = "voice-speaker-vbat",
     [SND_DEVICE_OUT_VOICE_HEADPHONES] = "voice-headphones",
+    [SND_DEVICE_OUT_VOICE_LINE] = "voice-line",
     [SND_DEVICE_OUT_HDMI] = "hdmi",
     [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi",
     [SND_DEVICE_OUT_BT_SCO] = "bt-sco-headset",
@@ -424,15 +436,18 @@
     [SND_DEVICE_OUT_SPEAKER_EXTERNAL_2] = 130,
     [SND_DEVICE_OUT_SPEAKER_VBAT] = 14,
     [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14,
+    [SND_DEVICE_OUT_LINE] = 10,
     [SND_DEVICE_OUT_HEADPHONES] = 10,
     [SND_DEVICE_OUT_HEADPHONES_44_1] = 10,
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10,
+    [SND_DEVICE_OUT_SPEAKER_AND_LINE] = 10,
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1] = 130,
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2] = 130,
     [SND_DEVICE_OUT_VOICE_HANDSET] = 7,
     [SND_DEVICE_OUT_VOICE_SPEAKER] = 14,
     [SND_DEVICE_OUT_VOICE_SPEAKER_VBAT] = 14,
     [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10,
+    [SND_DEVICE_OUT_VOICE_LINE] = 10,
     [SND_DEVICE_OUT_HDMI] = 18,
     [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14,
     [SND_DEVICE_OUT_BT_SCO] = 22,
@@ -530,13 +545,16 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_REVERSE)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_HEADPHONES)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_HEADPHONES_44_1)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_LINE)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_LINE)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_VBAT)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_LINE)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_HDMI)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HDMI)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_BT_SCO)},
@@ -621,7 +639,6 @@
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_ULL)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MULTI_CH)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD)},
-#ifdef MULTIPLE_OFFLOAD_ENABLED
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD2)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD3)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD4)},
@@ -630,8 +647,6 @@
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD7)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD8)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD9)},
-#endif
-    {TO_NAME_INDEX(USECASE_AUDIO_DIRECT_PCM_OFFLOAD)},
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)},
     {TO_NAME_INDEX(USECASE_VOICE_CALL)},
@@ -1148,7 +1163,7 @@
 
         ret = 0;
 
-        if((plat_data->is_vbat_speaker) && (WCD9XXX_VBAT_CAL == type)) {
+        if ((plat_data->is_vbat_speaker) && (WCD9XXX_VBAT_CAL == type)) {
            ret = send_vbat_adc_data_to_acdb(plat_data, cal_name_info[type]);
            if (ret < 0)
                ALOGE("%s error in sending vbat adc data to acdb", __func__);
@@ -1255,7 +1270,7 @@
     char value[PROPERTY_VALUE_MAX];
     struct platform_data *my_data = NULL;
     int retry_num = 0, snd_card_num = 0, key = 0;
-    const char *snd_card_name;
+    const char *snd_card_name = NULL;
     char *cvd_version = NULL;
     char *snd_internal_name = NULL;
     char *tmp = NULL;
@@ -1286,7 +1301,12 @@
             continue;
         }
 
-        snd_card_name = mixer_get_name(adev->mixer);
+        snd_card_name = strdup(mixer_get_name(adev->mixer));
+        if (!snd_card_name) {
+            ALOGE("failed to allocate memory for snd_card_name\n");
+            free(my_data);
+            return NULL;
+        }
         ALOGV("%s: snd_card_name: %s", __func__, snd_card_name);
 
         my_data->hw_info = hw_info_init(snd_card_name);
@@ -1348,6 +1368,7 @@
                 ALOGE("%s: Failed to init audio route controls, aborting.",
                        __func__);
                 free(my_data);
+                free(snd_card_name);
                 return NULL;
             }
             adev->snd_card = snd_card_num;
@@ -1361,6 +1382,8 @@
     if (snd_card_num >= MAX_SND_CARD) {
         ALOGE("%s: Unable to find correct sound card, aborting.", __func__);
         free(my_data);
+        if (snd_card_name)
+            free(snd_card_name);
         return NULL;
     }
 
@@ -1559,6 +1582,7 @@
         strdup("SLIM_5_RX SampleRate");
 
     my_data->edid_info = NULL;
+    free(snd_card_name);
     return my_data;
 }
 
@@ -1649,7 +1673,7 @@
         return;
     }
 
-    if((snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT) &&
+    if ((snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT) &&
         !(usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)) {
         ALOGI("%s: Not adding vbat speaker device to non voice use cases", __func__);
         return;
@@ -2284,6 +2308,9 @@
                 snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2;
             else
                 snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
+        } else if (devices == (AUDIO_DEVICE_OUT_LINE |
+                               AUDIO_DEVICE_OUT_SPEAKER)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_AND_LINE;
         } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL |
                                AUDIO_DEVICE_OUT_SPEAKER)) {
             snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI;
@@ -2307,7 +2334,8 @@
     if ((mode == AUDIO_MODE_IN_CALL) ||
         voice_extn_compress_voip_is_active(adev)) {
         if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
-            devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+            devices & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+            devices & AUDIO_DEVICE_OUT_LINE) {
             if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
                 !voice_extn_compress_voip_is_active(adev)) {
                 switch (adev->voice.tty_mode) {
@@ -2324,6 +2352,8 @@
                     ALOGE("%s: Invalid TTY mode (%#x)",
                           __func__, adev->voice.tty_mode);
                 }
+            } else if (devices & AUDIO_DEVICE_OUT_LINE) {
+                snd_device = SND_DEVICE_OUT_VOICE_LINE;
             } else if (audio_extn_get_anc_enabled()) {
                 if (audio_extn_should_use_fb_anc())
                     snd_device = SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET;
@@ -2373,6 +2403,8 @@
                 snd_device = SND_DEVICE_OUT_HEADPHONES_44_1;
           else
                 snd_device = SND_DEVICE_OUT_HEADPHONES;
+    } else if (devices & AUDIO_DEVICE_OUT_LINE) {
+        snd_device = SND_DEVICE_OUT_LINE;
     } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
         if (my_data->external_spk_1)
             snd_device = SND_DEVICE_OUT_SPEAKER_EXTERNAL_1;
@@ -2452,7 +2484,8 @@
         if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
             !voice_extn_compress_voip_is_active(adev)) {
             if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
-                out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+                out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+                out_device & AUDIO_DEVICE_OUT_LINE) {
                 switch (adev->voice.tty_mode) {
                 case TTY_MODE_FULL:
                     snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC;
@@ -2470,7 +2503,8 @@
             }
         }
         if (out_device & AUDIO_DEVICE_OUT_EARPIECE ||
-            out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+            out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+                out_device & AUDIO_DEVICE_OUT_LINE) {
             if (out_device & AUDIO_DEVICE_OUT_EARPIECE &&
                 audio_extn_should_use_handset_anc(channel_count)) {
                 snd_device = SND_DEVICE_IN_AANC_HANDSET_MIC;
@@ -2686,7 +2720,8 @@
                 snd_device = SND_DEVICE_IN_SPEAKER_STEREO_DMIC;
             else
                 snd_device = SND_DEVICE_IN_SPEAKER_MIC;
-        } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+        } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+                        out_device & AUDIO_DEVICE_OUT_LINE) {
             snd_device = SND_DEVICE_IN_HANDSET_MIC;
         } else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) {
             if (adev->bt_wb_speech_enabled) {
@@ -2987,6 +3022,44 @@
         free(dptr);
 }
 
+static void perf_lock_set_params(struct platform_data *platform,
+                          struct str_parms *parms,
+                          char *value, int len)
+{
+    int err = 0, i = 0, num_opts = 0;
+    char *test_r = NULL;
+    char *opts = NULL;
+    char *opts_size = NULL;
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_PERF_LOCK_OPTS,
+                            value, len);
+    if (err >= 0) {
+        opts_size = strtok_r(value, ", ", &test_r);
+        if (opts_size == NULL) {
+            ALOGE("%s: incorrect perf lock opts\n", __func__);
+            return;
+        }
+        num_opts = atoi(opts_size);
+        if (num_opts > 0) {
+            if (num_opts > MAX_PERF_LOCK_OPTS) {
+                ALOGD("%s: num_opts %d exceeds max %d, setting to max\n",
+                      __func__, num_opts, MAX_PERF_LOCK_OPTS);
+                num_opts = MAX_PERF_LOCK_OPTS;
+            }
+            for (i = 0; i < num_opts; i++) {
+                opts = strtok_r(NULL, ", ", &test_r);
+                if (opts == NULL) {
+                    ALOGE("%s: incorrect perf lock opts\n", __func__);
+                    break;
+                }
+                platform->adev->perf_lock_opts[i] = strtoul(opts, NULL, 16);
+            }
+            platform->adev->perf_lock_opts_size = i;
+        }
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_PERF_LOCK_OPTS);
+    }
+}
+
 int platform_set_parameters(void *platform, struct str_parms *parms)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
@@ -3080,6 +3153,7 @@
     set_audiocal(platform, parms, value, len);
     native_audio_set_params(platform, parms, value, len);
     audio_extn_spkr_prot_set_parameters(parms, value, len);
+    perf_lock_set_params(platform, parms, value, len);
 done:
     ALOGV("%s: exit with code(%d)", __func__, ret);
     if(kv_pairs != NULL)
@@ -3293,6 +3367,8 @@
     char value[512] = {0};
     int ret;
     char *kv_pairs = NULL;
+    char propValue[PROPERTY_VALUE_MAX]={0};
+    bool prop_playback_enabled = false;
 
     ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SLOWTALK,
                             value, sizeof(value));
@@ -3324,6 +3400,36 @@
     get_audiocal(platform, query, reply);
     native_audio_get_params(query, reply, value, sizeof(value));
 
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_IS_HW_DECODER_SESSION_ALLOWED,
+                                    value, sizeof(value));
+    if (ret >= 0) {
+        int isallowed = 1; /*true*/
+
+        if (property_get("voice.playback.conc.disabled", propValue, NULL)) {
+            prop_playback_enabled = atoi(propValue) ||
+                !strncmp("true", propValue, 4);
+        }
+
+        if (prop_playback_enabled && (voice_is_in_call(my_data->adev) ||
+             (SND_CARD_STATE_OFFLINE == get_snd_card_state(my_data->adev)))) {
+            char *decoder_mime_type = value;
+
+            //check if unsupported mime type or not
+            if(decoder_mime_type) {
+                int i = 0;
+                for (i = 0; i < sizeof(dsp_only_decoders_mime)/sizeof(dsp_only_decoders_mime[0]); i++) {
+                    if (!strncmp(decoder_mime_type, dsp_only_decoders_mime[i],
+                    strlen(dsp_only_decoders_mime[i]))) {
+                       ALOGD("Rejecting request for DSP only session from HAL during voice call/SSR state");
+                       isallowed = 0;
+                       break;
+                    }
+                }
+            }
+        }
+        str_parms_add_int(reply, AUDIO_PARAMETER_IS_HW_DECODER_SESSION_ALLOWED, isallowed);
+    }
+
 done:
     kv_pairs = str_parms_to_str(reply);
     ALOGV_IF(kv_pairs != NULL, "%s: exit: returns - %s", __func__, kv_pairs);
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 54406b6..a2c6304 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -43,7 +43,8 @@
  */
 #define AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND \
     (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | \
-     AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE)
+     AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE | \
+     AUDIO_DEVICE_OUT_LINE)
 
 /*
  * Below are the input devices for which back end is same, SLIMBUS_0_TX.
@@ -70,15 +71,18 @@
     SND_DEVICE_OUT_SPEAKER_EXTERNAL_2,
     SND_DEVICE_OUT_SPEAKER_REVERSE,
     SND_DEVICE_OUT_SPEAKER_VBAT,
+    SND_DEVICE_OUT_LINE,
     SND_DEVICE_OUT_HEADPHONES,
     SND_DEVICE_OUT_HEADPHONES_44_1,
     SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_LINE,
     SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1,
     SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2,
     SND_DEVICE_OUT_VOICE_HANDSET,
     SND_DEVICE_OUT_VOICE_SPEAKER,
     SND_DEVICE_OUT_VOICE_SPEAKER_VBAT,
     SND_DEVICE_OUT_VOICE_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_LINE,
     SND_DEVICE_OUT_HDMI,
     SND_DEVICE_OUT_SPEAKER_AND_HDMI,
     SND_DEVICE_OUT_BT_SCO,
@@ -248,9 +252,12 @@
 #endif
 #define PLAYBACK_OFFLOAD_DEVICE 9
 
-#ifdef MULTIPLE_OFFLOAD_ENABLED
-#ifdef PLATFORM_APQ8084
+// Direct_PCM
+#if defined (PLATFORM_MSM8994) || defined (PLATFORM_MSM8996) || defined (PLATFORM_APQ8084)
 #define PLAYBACK_OFFLOAD_DEVICE2 17
+#endif
+
+#ifdef PLATFORM_APQ8084
 #define PLAYBACK_OFFLOAD_DEVICE3 18
 #define PLAYBACK_OFFLOAD_DEVICE4 34
 #define PLAYBACK_OFFLOAD_DEVICE5 35
@@ -260,7 +267,6 @@
 #define PLAYBACK_OFFLOAD_DEVICE9 39
 #endif
 #if defined (PLATFORM_MSM8994) || defined (PLATFORM_MSM8996)
-#define PLAYBACK_OFFLOAD_DEVICE2 17
 #define PLAYBACK_OFFLOAD_DEVICE3 18
 #define PLAYBACK_OFFLOAD_DEVICE4 37
 #define PLAYBACK_OFFLOAD_DEVICE5 38
@@ -269,10 +275,6 @@
 #define PLAYBACK_OFFLOAD_DEVICE8 41
 #define PLAYBACK_OFFLOAD_DEVICE9 42
 #endif
-#endif
-
-// for DIRECT_PCM
-#define PLAYBACK_OFFLOAD_DEVICE2 17
 
 #define COMPRESS_VOIP_CALL_PCM_DEVICE 3
 
diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp
index b0707d7..7cbc760 100644
--- a/policy_hal/AudioPolicyManager.cpp
+++ b/policy_hal/AudioPolicyManager.cpp
@@ -397,6 +397,13 @@
         return false;
     }
 
+    // Check if offload has been disabled
+    bool offloadDisabled = property_get_bool("audio.offload.disable", false);
+    if (offloadDisabled) {
+        ALOGI("offload disabled by audio.offload.disable=%d", offloadDisabled);
+        return false;
+    }
+
     char propValue[PROPERTY_VALUE_MAX];
     bool pcmOffload = false;
 #ifdef PCM_OFFLOAD_ENABLED
@@ -426,13 +433,13 @@
     }
 #endif
     if (!pcmOffload) {
-        // Check if offload has been disabled
-        if (property_get("audio.offload.disable", propValue, "0")) {
-            if (atoi(propValue) != 0) {
-                ALOGV("offload disabled by audio.offload.disable=%s", propValue );
-                return false;
-            }
+
+        bool compressedOffloadDisabled = property_get_bool("audio.offload.compress.disable", false);
+        if (compressedOffloadDisabled) {
+            ALOGI("compressed offload disabled by audio.offload.compress.disable=%d", compressedOffloadDisabled);
+            return false;
         }
+
         //check if it's multi-channel AAC (includes sub formats) and FLAC format
         if ((popcount(offloadInfo.channel_mask) > 2) &&
            (((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC) ||
@@ -460,6 +467,14 @@
             ALOGV("isOffloadSupported: has_video == true, returning false");
             return false;
         }
+
+        const bool allowOffloadStreamingWithVideo = property_get_bool("av.streaming.offload.enable",
+                                                                   false /*default value*/);
+        if(offloadInfo.has_video && offloadInfo.is_streaming && !allowOffloadStreamingWithVideo) {
+            ALOGW("offload disabled by av.streaming.offload.enable = %s ", propValue );
+            return false;
+        }
+
     }
 
     //If duration is less than minimum value defined in property, return false
@@ -954,18 +969,22 @@
 
 }
 
-status_t AudioPolicyManagerCustom::stopSource(sp<SwAudioOutputDescriptor> outputDesc,
+status_t AudioPolicyManagerCustom::stopSource(sp<AudioOutputDescriptor> outputDesc,
                                             audio_stream_type_t stream,
                                             bool forceDeviceUpdate)
 {
+    if (stream < 0 || stream >= AUDIO_STREAM_CNT) {
+        ALOGW("stopSource() invalid stream %d", stream);
+        return INVALID_OPERATION;
+    }
     // always handle stream stop, check which stream type is stopping
     handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT);
 
     // handle special case for sonification while in call
     if (isInCall() && (outputDesc->mRefCount[stream] == 1)) {
         if (outputDesc->isDuplicated()) {
-            handleIncallSonification(stream, false, false, outputDesc->mOutput1->mIoHandle);
-            handleIncallSonification(stream, false, false, outputDesc->mOutput2->mIoHandle);
+            handleIncallSonification(stream, false, false, outputDesc->subOutput1()->mIoHandle);
+            handleIncallSonification(stream, false, false, outputDesc->subOutput2()->mIoHandle);
         }
         handleIncallSonification(stream, false, false, outputDesc->mIoHandle);
     }
@@ -977,6 +996,7 @@
         // store time at which the stream was stopped - see isStreamActive()
         if (outputDesc->mRefCount[stream] == 0 || forceDeviceUpdate) {
             outputDesc->mStopTime[stream] = systemTime();
+            audio_devices_t prevDevice = outputDesc->device();
             audio_devices_t newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
             // delay the device switch by twice the latency because stopOutput() is executed when
             // the track stop() command is received and at that time the audio track buffer can
@@ -995,10 +1015,16 @@
                         outputDesc->sharesHwModuleWith(desc) &&
                         (newDevice != desc->device())) {
                         audio_devices_t dev = getNewOutputDevice(mOutputs.valueFor(curOutput), false /*fromCache*/);
+                        uint32_t delayMs;
+                        if (dev == prevDevice) {
+                            delayMs = 0;
+                        } else {
+                            delayMs = outputDesc->latency()*2;
+                        }
                         setOutputDevice(desc,
                                     dev,
                                     true,
-                                    outputDesc->latency()*2);
+                                    delayMs);
                 }
             }
             // update the outputs if stopping one with a stream that can affect notification routing
@@ -1010,7 +1036,7 @@
         return INVALID_OPERATION;
     }
 }
-status_t AudioPolicyManagerCustom::startSource(sp<SwAudioOutputDescriptor> outputDesc,
+status_t AudioPolicyManagerCustom::startSource(sp<AudioOutputDescriptor> outputDesc,
                                              audio_stream_type_t stream,
                                              audio_devices_t device,
                                              uint32_t *delayMs)
@@ -1018,6 +1044,11 @@
     // cannot start playback of STREAM_TTS if any other output is being used
     uint32_t beaconMuteLatency = 0;
 
+    if (stream < 0 || stream >= AUDIO_STREAM_CNT) {
+        ALOGW("startSource() invalid stream %d", stream);
+        return INVALID_OPERATION;
+    }
+
     *delayMs = 0;
     if (stream == AUDIO_STREAM_TTS) {
         ALOGV("\t found BEACON stream");
@@ -1161,10 +1192,14 @@
 }
 status_t AudioPolicyManagerCustom::checkAndSetVolume(audio_stream_type_t stream,
                                                    int index,
-                                                   const sp<SwAudioOutputDescriptor>& outputDesc,
+                                                   const sp<AudioOutputDescriptor>& outputDesc,
                                                    audio_devices_t device,
                                                    int delayMs, bool force)
 {
+    if (stream < 0 || stream >= AUDIO_STREAM_CNT) {
+        ALOGW("checkAndSetVolume() invalid stream %d", stream);
+        return INVALID_OPERATION;
+    }
     // do not change actual stream volume if the stream is muted
     if (outputDesc->mMuteCount[stream] != 0) {
         ALOGVV("checkAndSetVolume() stream %d muted count %d",
@@ -1236,7 +1271,17 @@
 {
     audio_offload_info_t tOffloadInfo = AUDIO_INFO_INITIALIZER;
 
-    bool pcmOffloadEnabled = property_get_bool("audio.offload.track.enable", false);
+    bool offloadDisabled = property_get_bool("audio.offload.disable", false);
+    bool pcmOffloadEnabled = false;
+
+    if (offloadDisabled) {
+        ALOGI("offload disabled by audio.offload.disable=%d", offloadDisabled);
+    }
+
+    //read track offload property only if the global offload switch is off.
+    if (!offloadDisabled) {
+         pcmOffloadEnabled = property_get_bool("audio.offload.track.enable", false);
+    }
 
     if (offloadInfo == NULL && pcmOffloadEnabled) {
         tOffloadInfo.sample_rate  = samplingRate;
@@ -1248,7 +1293,7 @@
             ALOGV("found attribute .. setting usage %d ", attr->usage);
             tOffloadInfo.usage = attr->usage;
         } else {
-            ALOGD("%s:: attribute is NULL .. no usage set", __func__);
+            ALOGI("%s:: attribute is NULL .. no usage set", __func__);
         }
         offloadInfo = &tOffloadInfo;
     }
@@ -1559,23 +1604,29 @@
     if (profile != 0) {
         sp<SwAudioOutputDescriptor> outputDesc = NULL;
 
-        for (size_t i = 0; i < mOutputs.size(); i++) {
-            sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
-            if (!desc->isDuplicated() && (profile == desc->mProfile)) {
-                outputDesc = desc;
-                // reuse direct output if currently open and configured with same parameters
-                if ((samplingRate == outputDesc->mSamplingRate) &&
-                        (format == outputDesc->mFormat) &&
-                        (channelMask == outputDesc->mChannelMask)) {
-                    outputDesc->mDirectOpenCount++;
-                    ALOGV("getOutput() reusing direct output %d", mOutputs.keyAt(i));
-                    return mOutputs.keyAt(i);
+        // if multiple concurrent offload decode is supported
+        // do no check for reuse and also don't close previous output if its offload
+        // previous output will be closed during track destruction
+        if (!(property_get_bool("audio.offload.multiple.enabled", false) &&
+                ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0))) {
+            for (size_t i = 0; i < mOutputs.size(); i++) {
+                sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+                if (!desc->isDuplicated() && (profile == desc->mProfile)) {
+                    outputDesc = desc;
+                    // reuse direct output if currently open and configured with same parameters
+                    if ((samplingRate == outputDesc->mSamplingRate) &&
+                            (format == outputDesc->mFormat) &&
+                            (channelMask == outputDesc->mChannelMask)) {
+                        outputDesc->mDirectOpenCount++;
+                        ALOGV("getOutput() reusing direct output %d", mOutputs.keyAt(i));
+                        return mOutputs.keyAt(i);
+                    }
                 }
             }
-        }
-        // close direct output if currently open and configured with different parameters
-        if (outputDesc != NULL) {
-            closeOutput(outputDesc->mIoHandle);
+            // close direct output if currently open and configured with different parameters
+            if (outputDesc != NULL) {
+                closeOutput(outputDesc->mIoHandle);
+            }
         }
 
         // if the selected profile is offloaded and no offload info was specified,
@@ -1920,6 +1971,37 @@
       mHdmiAudioEvent(false),
       mPrevPhoneState(0)
 {
+    char ssr_enabled[PROPERTY_VALUE_MAX] = {0};
+    bool prop_ssr_enabled = false;
+
+    if (property_get("ro.qc.sdk.audio.ssr", ssr_enabled, NULL)) {
+        prop_ssr_enabled = atoi(ssr_enabled) || !strncmp("true", ssr_enabled, 4);
+    }
+
+    for (size_t i = 0; i < mHwModules.size(); i++) {
+        ALOGV("Hw module %d", i);
+        for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++) {
+            const sp<IOProfile> inProfile = mHwModules[i]->mInputProfiles[j];
+            ALOGV("Input profile ", j);
+            for (size_t k = 0; k  < inProfile->mChannelMasks.size(); k++) {
+                audio_channel_mask_t channelMask =
+                    inProfile->mChannelMasks.itemAt(k);
+                ALOGV("Channel Mask %x size %d", channelMask,
+                    inProfile->mChannelMasks.size());
+                if (AUDIO_CHANNEL_IN_5POINT1 == channelMask) {
+                    if (!prop_ssr_enabled) {
+                        ALOGI("removing AUDIO_CHANNEL_IN_5POINT1 from"
+                            " input profile as SSR(surround sound record)"
+                            " is not supported on this chipset variant");
+                        inProfile->mChannelMasks.removeItemsAt(k, 1);
+                        ALOGV("Channel Mask size now %d",
+                            inProfile->mChannelMasks.size());
+                    }
+                }
+            }
+        }
+    }
+
 #ifdef RECORD_PLAY_CONCURRENCY
     mIsInputRequestOnProgress = false;
 #endif
diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h
index dfaad65..a7f88e4 100644
--- a/policy_hal/AudioPolicyManager.h
+++ b/policy_hal/AudioPolicyManager.h
@@ -79,7 +79,7 @@
 
          status_t checkAndSetVolume(audio_stream_type_t stream,
                                                    int index,
-                                                   const sp<SwAudioOutputDescriptor>& outputDesc,
+                                                   const sp<AudioOutputDescriptor>& outputDesc,
                                                    audio_devices_t device,
                                                    int delayMs = 0, bool force = false);
 
@@ -94,11 +94,11 @@
 
         // if argument "device" is different from AUDIO_DEVICE_NONE,  startSource() will force
         // the re-evaluation of the output device.
-        status_t startSource(sp<SwAudioOutputDescriptor> outputDesc,
+        status_t startSource(sp<AudioOutputDescriptor> outputDesc,
                              audio_stream_type_t stream,
                              audio_devices_t device,
                              uint32_t *delayMs);
-         status_t stopSource(sp<SwAudioOutputDescriptor> outputDesc,
+         status_t stopSource(sp<AudioOutputDescriptor> outputDesc,
                             audio_stream_type_t stream,
                             bool forceDeviceUpdate);
         // event is one of STARTING_OUTPUT, STARTING_BEACON, STOPPING_OUTPUT, STOPPING_BEACON
diff --git a/post_proc/volume_listener.c b/post_proc/volume_listener.c
index 51f8803..e1dd026 100644
--- a/post_proc/volume_listener.c
+++ b/post_proc/volume_listener.c
@@ -324,6 +324,13 @@
  * Effect Control Interface Implementation
  */
 
+static inline int16_t clamp16(int32_t sample)
+{
+    if ((sample>>15) ^ (sample>>31))
+        sample = 0x7FFF ^ (sample>>31);
+    return sample;
+}
+
 static int vol_effect_process(effect_handle_t self,
                               audio_buffer_t *in_buffer,
                               audio_buffer_t *out_buffer)
@@ -342,9 +349,16 @@
 
     // calculation based on channel count 2
     if (in_buffer->raw != out_buffer->raw) {
-        memcpy(out_buffer->raw, in_buffer->raw, out_buffer->frameCount * 2 * sizeof(int16_t));
+        if (context->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+            size_t i;
+            for (i = 0; i < out_buffer->frameCount*2; i++) {
+                out_buffer->s16[i] = clamp16(out_buffer->s16[i] + in_buffer->s16[i]);
+            }
+        } else {
+            memcpy(out_buffer->raw, in_buffer->raw, out_buffer->frameCount * 2 * sizeof(int16_t));
+        }
     } else {
-        ALOGW("%s: something wrong, didn't handle in_buffer and out_buffer same address case",
+        ALOGV("%s: something wrong, didn't handle in_buffer and out_buffer same address case",
               __func__);
     }
 
@@ -386,6 +400,12 @@
 
     case EFFECT_CMD_SET_CONFIG:
         ALOGV("%s :: cmd called EFFECT_CMD_SET_CONFIG", __func__);
+        if (p_cmd_data == NULL || cmd_size != sizeof(effect_config_t)
+                || p_reply_data == NULL || reply_size == NULL || *reply_size != sizeof(int)) {
+            return -EINVAL;
+        }
+        context->config = *(effect_config_t *)p_cmd_data;
+        *(int *)p_reply_data = 0;
         break;
 
     case EFFECT_CMD_GET_CONFIG:
@@ -432,7 +452,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();
         }
 
@@ -459,7 +479,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();
         }
 
@@ -490,8 +510,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;
             }
 
@@ -516,7 +536,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;
             }
 
@@ -612,7 +632,7 @@
 
 static int vol_prc_lib_create(const effect_uuid_t *uuid,
                               int32_t session_id,
-                              int32_t io_id,
+                              int32_t io_id __unused,
                               effect_handle_t *p_handle)
 {
     int itt = 0;
@@ -681,6 +701,11 @@
     bool recompute_flag = false;
     int active_stream_count = 0;
     ALOGV("%s context %p", __func__, handle);
+    if (recv_contex == NULL || recv_contex->desc == NULL) {
+        ALOGE("%s: Got invalid handle while release, DO NOTHING ", __func__);
+        return status;
+    }
+
     pthread_mutex_lock(&vol_listner_init_lock);
 
     // check if the handle/context provided is valid
@@ -690,13 +715,14 @@
             && (context->session_id == recv_contex->session_id)
             && (context->stream_type == recv_contex->stream_type)) {
             ALOGV("--- Found something to remove ---");
-            list_remove(&context->effect_list_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);
             free(context);
             status = 0;
+            break;
         } else {
             ++active_stream_count;
         }