Merge "hal: add a new key to query for decoder viability"
diff --git a/hal/Android.mk b/hal/Android.mk
index d7b7c50..f83faa5 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -231,10 +231,6 @@
     LOCAL_SRC_FILES += audio_extn/source_track.c
 endif
 
-ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AUDIOSPHERE)),true)
-    LOCAL_CFLAGS += -DAUDIOSPHERE_ENABLED
-endif
-
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
 	libcutils \
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 34da4fe..061af81 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -81,8 +81,6 @@
 /* Query offload playback instances count */
 #define AUDIO_PARAMETER_OFFLOAD_NUM_ACTIVE "offload_num_active"
 #define AUDIO_PARAMETER_HPX            "HPX"
-#define AUDIO_PARAMETER_KEY_ASPHERE_ENABLE   "asphere_enable"
-#define AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH "asphere_strength"
 
 #ifndef FM_ENABLED
 #define audio_extn_fm_set_parameters(adev, parms) (0)
@@ -558,103 +556,6 @@
     return ret;
 }
 
-#ifndef AUDIOSPHERE_ENABLED
-#define audio_extn_asphere_set_parameters(adev, parms)  (0)
-#define audio_extn_asphere_get_parameters(adev, query, reply) (0)
-#else
-int32_t audio_extn_asphere_set_parameters(const struct audio_device *adev,
-                                     struct str_parms *parms)
-{
-    int ret = 0, val[2];
-    char value[32] = {0};
-    int set_enable, set_strength;
-    int enable = -1, strength = -1;
-    struct mixer_ctl *ctl = NULL;
-    const char *mixer_ctl_name = "MSM ASphere Set Param";
-    char propValue[PROPERTY_VALUE_MAX] = {0};
-    bool asphere_prop_enabled = false;
-
-    if (property_get("audio.pp.asphere.enabled", propValue, "false")) {
-        if (!strncmp("true", propValue, 4))
-            asphere_prop_enabled = true;
-    }
-
-    if (!asphere_prop_enabled) {
-        ALOGV("%s: property not set!!! not doing anything", __func__);
-        return ret;
-    }
-
-    set_enable = str_parms_get_str(parms,
-                            AUDIO_PARAMETER_KEY_ASPHERE_ENABLE,
-                            value, sizeof(value));
-    if (set_enable > 0)
-        enable = atoi(value);
-
-    set_strength = str_parms_get_str(parms,
-                            AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH,
-                            value, sizeof(value));
-    if (set_strength > 0)
-        strength = atoi(value);
-
-    if (set_enable >= 0 || set_strength >= 0) {
-        ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
-        if (!ctl) {
-            ALOGE("%s: could not get ctl for mixer cmd - %s",
-                  __func__, mixer_ctl_name);
-            return -EINVAL;
-        }
-        ALOGD("%s: set ctl \"%s:%d,%d\"",
-              __func__, mixer_ctl_name, enable, strength);
-        val[0] = enable;
-        val[1] = strength;
-        ret = mixer_ctl_set_array(ctl, val, sizeof(val)/sizeof(val[0]));
-        if (ret)
-            ALOGE("%s: set ctl failed!!!\"%s:%d,%d\"",
-                  __func__, mixer_ctl_name, enable, strength);
-    }
-    ALOGV("%s: exit ret %d", __func__, ret);
-    return ret;
-}
-
-int32_t audio_extn_asphere_get_parameters(const struct audio_device *adev,
-                                          struct str_parms *query,
-                                          struct str_parms *reply)
-{
-    int ret = 0, val[2] = {-1, -1};
-    char value[32] = {0};
-    int get_enable, get_strength;
-    struct mixer_ctl *ctl = NULL;
-    const char *mixer_ctl_name = "MSM ASphere Set Param";
-
-    get_enable = str_parms_get_str(query,
-                                   AUDIO_PARAMETER_KEY_ASPHERE_ENABLE,
-                                   value, sizeof(value));
-    get_strength = str_parms_get_str(query,
-                                     AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH,
-                                     value, sizeof(value));
-    if (get_enable > 0 || get_strength > 0) {
-        ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
-        if (!ctl) {
-            ALOGE("%s: could not get ctl for mixer cmd - %s",
-                  __func__, mixer_ctl_name);
-            return -EINVAL;
-        }
-        ret = mixer_ctl_get_array(ctl, val, sizeof(val)/sizeof(val[0]));
-        if (ret)
-            ALOGE("%s: got ctl failed!!! \"%s:%d,%d\"",
-                   __func__, mixer_ctl_name, val[0], val[1]);
-        if (get_enable > 0)
-            str_parms_add_int(reply,
-                              AUDIO_PARAMETER_KEY_ASPHERE_ENABLE, val[0]);
-        if (get_strength > 0)
-            str_parms_add_int(reply,
-                              AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH, val[1]);
-    }
-    ALOGV("%s: exit ret %d", __func__, ret);
-    return ret;
-}
-#endif
-
 void audio_extn_set_parameters(struct audio_device *adev,
                                struct str_parms *parms)
 {
@@ -672,7 +573,8 @@
    audio_extn_hpx_set_parameters(adev, parms);
    audio_extn_pm_set_parameters(parms);
    audio_extn_source_track_set_parameters(adev, parms);
-   audio_extn_asphere_set_parameters(adev, parms);
+   if (adev->offload_effects_set_parameters != NULL)
+       adev->offload_effects_set_parameters(parms);
 }
 
 void audio_extn_get_parameters(const struct audio_device *adev,
@@ -686,7 +588,8 @@
     audio_extn_dts_eagle_get_parameters(adev, query, reply);
     audio_extn_hpx_get_parameters(query, reply);
     audio_extn_source_track_get_parameters(adev, query, reply);
-    audio_extn_asphere_get_parameters(adev, query, reply);
+    if (adev->offload_effects_get_parameters != NULL)
+        adev->offload_effects_get_parameters(query, reply);
 
     kv_pairs = str_parms_to_str(reply);
     ALOGD_IF(kv_pairs != NULL, "%s: returns %s", __func__, kv_pairs);
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
index a0588a3..a73dfa1 100644
--- a/hal/audio_extn/hfp.c
+++ b/hal/audio_extn/hfp.c
@@ -1,5 +1,5 @@
 /* hfp.c
-Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+Copyright (c) 2012-2015, 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
@@ -271,7 +271,7 @@
     }
 
     /* 2. Disable echo reference while stopping hfp */
-    platform_set_echo_reference(adev->platform, false);
+    platform_set_echo_reference(adev, false, uc_info->devices);
 
     /* 3. Get and set stream specific mixer controls */
     disable_audio_route(adev, uc_info);
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 37125f7..512a584 100755
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -177,6 +177,7 @@
     [USECASE_AUDIO_PLAYBACK_OFFLOAD8] = "compress-offload-playback8",
     [USECASE_AUDIO_PLAYBACK_OFFLOAD9] = "compress-offload-playback9",
 #endif
+    [USECASE_AUDIO_PLAYBACK_ULL] = "audio-ull-playback",
     [USECASE_AUDIO_RECORD] = "audio-record",
     [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress",
     [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
@@ -900,7 +901,7 @@
                      adev->active_input->source == AUDIO_SOURCE_MIC)) &&
                      adev->primary_output && !adev->primary_output->standby) {
                     out_device = adev->primary_output->devices;
-                    platform_set_echo_reference(adev->platform, false);
+                    platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE);
                 } else if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY) {
                     out_device = AUDIO_DEVICE_OUT_TELEPHONY_TX;
                 }
@@ -1139,7 +1140,10 @@
     }
     audio_extn_perf_lock_release();
 
+    ALOGV("%s: pcm_prepare start", __func__);
+    pcm_prepare(in->pcm);
     ALOGV("%s: exit", __func__);
+
     return ret;
 
 error_open:
@@ -1607,8 +1611,14 @@
             }
             break;
         }
+
         platform_set_stream_channel_map(adev->platform, out->channel_mask,
                                     out->pcm_device_id);
+
+        ALOGV("%s: pcm_prepare start", __func__);
+        if (pcm_is_ready(out->pcm))
+            pcm_prepare(out->pcm);
+
     } else {
         platform_set_stream_channel_map(adev->platform, out->channel_mask,
                                     out->pcm_device_id);
@@ -1651,7 +1661,9 @@
             audio_extn_check_and_set_dts_hpx_state(adev);
         }
     }
+
     ALOGV("%s: exit", __func__);
+
     return 0;
 error_open:
     stop_output_stream(out);
@@ -1787,6 +1799,9 @@
 
     pthread_mutex_lock(&out->lock);
     if (!out->standby) {
+        if (adev->adm_deregister_stream)
+            adev->adm_deregister_stream(adev->adm_data, out->handle);
+
         pthread_mutex_lock(&adev->lock);
         out->standby = true;
         if (!is_offload_usecase(out->usecase)) {
@@ -2139,6 +2154,8 @@
             out->standby = true;
             goto exit;
         }
+        if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD && adev->adm_register_output_stream)
+            adev->adm_register_output_stream(adev->adm_data, out->handle, out->flags);
     }
 
     if (adev->mChannelStatusSet == false && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)){
@@ -2184,15 +2201,24 @@
         if (out->pcm) {
             if (out->muted)
                 memset((void *)buffer, 0, bytes);
+
             ALOGVV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes);
+
+            if (adev->adm_request_focus)
+                adev->adm_request_focus(adev->adm_data, out->handle);
+
             if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY)
                 ret = pcm_mmap_write(out->pcm, (void *)buffer, bytes);
             else
                 ret = pcm_write(out->pcm, (void *)buffer, bytes);
+
             if (ret < 0)
                 ret = -errno;
             else if (ret == 0)
                 out->written += bytes / (out->config.channels * sizeof(short));
+
+            if (adev->adm_abandon_focus)
+                adev->adm_abandon_focus(adev->adm_data, out->handle);
         }
     }
 
@@ -2508,6 +2534,9 @@
     }
 
     if (!in->standby) {
+        if (adev->adm_deregister_stream)
+            adev->adm_deregister_stream(adev->adm_data, in->capture_handle);
+
         pthread_mutex_lock(&adev->lock);
         in->standby = true;
         if (in->pcm) {
@@ -2653,8 +2682,13 @@
             goto exit;
         }
         in->standby = 0;
+        if (adev->adm_register_input_stream)
+            adev->adm_register_input_stream(adev->adm_data, in->capture_handle, in->flags);
     }
 
+    if (adev->adm_request_focus)
+        adev->adm_request_focus(adev->adm_data, in->capture_handle);
+
     if (in->pcm) {
         if (audio_extn_ssr_get_enabled() &&
                 audio_channel_count_from_in_mask(in->channel_mask) == 6)
@@ -2669,6 +2703,9 @@
             ret = -errno;
     }
 
+    if (adev->adm_abandon_focus)
+        adev->adm_abandon_focus(adev->adm_data, in->capture_handle);
+
     /*
      * Instead of writing zeroes here, we could trust the hardware
      * to always provide zeroes when muted.
@@ -2988,6 +3025,10 @@
         out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
         out->config = pcm_config_afe_proxy_playback;
         adev->voice_tx_output = out;
+    } else if (out->flags & AUDIO_OUTPUT_FLAG_RAW) {
+        out->usecase = USECASE_AUDIO_PLAYBACK_ULL;
+        out->config = pcm_config_low_latency;
+        out->sample_rate = out->config.rate;
     } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
         format = AUDIO_FORMAT_PCM_16_BIT;
         out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
@@ -3457,6 +3498,7 @@
     in->standby = 1;
     in->channel_mask = config->channel_mask;
     in->capture_handle = handle;
+    in->flags = flags;
 
     /* Update config params with the requested sample rate and channels */
     in->usecase = USECASE_AUDIO_RECORD;
@@ -3552,7 +3594,7 @@
     ALOGD("%s: enter:stream_handle(%p)",__func__, in);
 
     /* Disable echo reference while closing input stream */
-    platform_set_echo_reference(adev->platform, false);
+    platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE);
 
     if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
         pthread_mutex_lock(&adev->lock);
@@ -3599,10 +3641,13 @@
         audio_route_free(adev->audio_route);
         free(adev->snd_dev_ref_cnt);
         platform_deinit(adev->platform);
+        if (adev->adm_deinit)
+            adev->adm_deinit(adev->adm_data);
         free(device);
         adev = NULL;
     }
     pthread_mutex_unlock(&adev_init_lock);
+
     return 0;
 }
 
@@ -3614,6 +3659,7 @@
 {
     switch (period_size) {
     case 160:
+    case 192:
     case 240:
     case 320:
     case 480:
@@ -3737,6 +3783,36 @@
             adev->offload_effects_set_hpx_state =
                         (int (*)(bool))dlsym(adev->offload_effects_lib,
                                          "offload_effects_bundle_set_hpx_state");
+            adev->offload_effects_get_parameters =
+                        (void (*)(struct str_parms *, struct str_parms *))
+                                         dlsym(adev->offload_effects_lib,
+                                         "offload_effects_bundle_get_parameters");
+            adev->offload_effects_set_parameters =
+                        (void (*)(struct str_parms *))dlsym(adev->offload_effects_lib,
+                                         "offload_effects_bundle_set_parameters");
+        }
+    }
+
+    if (access(ADM_LIBRARY_PATH, R_OK) == 0) {
+        adev->adm_lib = dlopen(ADM_LIBRARY_PATH, RTLD_NOW);
+        if (adev->adm_lib == NULL) {
+            ALOGE("%s: DLOPEN failed for %s", __func__, ADM_LIBRARY_PATH);
+        } else {
+            ALOGV("%s: DLOPEN successful for %s", __func__, ADM_LIBRARY_PATH);
+            adev->adm_init = (adm_init_t)
+                                    dlsym(adev->adm_lib, "adm_init");
+            adev->adm_deinit = (adm_deinit_t)
+                                    dlsym(adev->adm_lib, "adm_deinit");
+            adev->adm_register_input_stream = (adm_register_input_stream_t)
+                                    dlsym(adev->adm_lib, "adm_register_input_stream");
+            adev->adm_register_output_stream = (adm_register_output_stream_t)
+                                    dlsym(adev->adm_lib, "adm_register_output_stream");
+            adev->adm_deregister_stream = (adm_deregister_stream_t)
+                                    dlsym(adev->adm_lib, "adm_deregister_stream");
+            adev->adm_request_focus = (adm_request_focus_t)
+                                    dlsym(adev->adm_lib, "adm_request_focus");
+            adev->adm_abandon_focus = (adm_abandon_focus_t)
+                                    dlsym(adev->adm_lib, "adm_abandon_focus");
         }
     }
 
@@ -3770,6 +3846,9 @@
 
     pthread_mutex_unlock(&adev_init_lock);
 
+    if (adev->adm_init)
+        adev->adm_data = adev->adm_init();
+
     ALOGV("%s: exit", __func__);
     return 0;
 }
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 45e90b7..983a89e 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -49,6 +49,7 @@
 
 #define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so"
 #define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/system/lib/soundfx/libqcompostprocbundle.so"
+#define ADM_LIBRARY_PATH "/system/vendor/lib/libadm.so"
 
 /* Flags used to initialize acdb_settings variable that goes to ACDB library */
 #define NONE_FLAG            0x00000000
@@ -93,6 +94,7 @@
     USECASE_AUDIO_PLAYBACK_OFFLOAD8,
     USECASE_AUDIO_PLAYBACK_OFFLOAD9,
 #endif
+    USECASE_AUDIO_PLAYBACK_ULL,
 
     /* FM usecase */
     USECASE_AUDIO_PLAYBACK_FM,
@@ -233,6 +235,7 @@
     bool enable_ns;
     audio_format_t format;
     audio_io_handle_t capture_handle;
+    audio_input_flags_t flags;
     bool is_st_session;
     bool is_st_session_active;
 
@@ -285,6 +288,14 @@
     struct stream_app_type_cfg app_type_cfg;
 };
 
+typedef void* (*adm_init_t)();
+typedef void (*adm_deinit_t)(void *);
+typedef void (*adm_register_output_stream_t)(void *, audio_io_handle_t, audio_output_flags_t);
+typedef void (*adm_register_input_stream_t)(void *, audio_io_handle_t, audio_input_flags_t);
+typedef void (*adm_deregister_stream_t)(void *, audio_io_handle_t);
+typedef void (*adm_request_focus_t)(void *, audio_io_handle_t);
+typedef void (*adm_abandon_focus_t)(void *, audio_io_handle_t);
+
 struct audio_device {
     struct audio_hw_device device;
     pthread_mutex_t lock; /* see note below on mutex acquisition order */
@@ -323,6 +334,19 @@
 
     struct sound_card_status snd_card_status;
     int (*offload_effects_set_hpx_state)(bool);
+    void (*offload_effects_get_parameters)(struct str_parms *,
+                                           struct str_parms *);
+    void (*offload_effects_set_parameters)(struct str_parms *);
+
+    void *adm_data;
+    void *adm_lib;
+    adm_init_t adm_init;
+    adm_deinit_t adm_deinit;
+    adm_register_input_stream_t adm_register_input_stream;
+    adm_register_output_stream_t adm_register_output_stream;
+    adm_deregister_stream_t adm_deregister_stream;
+    adm_request_focus_t adm_request_focus;
+    adm_abandon_focus_t adm_abandon_focus;
 };
 
 int select_devices(struct audio_device *adev,
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index fc7d038..63adaa1 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -247,6 +247,7 @@
     void *edid_info;
     bool edid_valid;
     codec_backend_cfg_t current_backend_cfg[MAX_CODEC_BACKENDS];
+    char ec_ref_mixer_path[64];
 };
 
 static bool is_external_codec = false;
@@ -280,6 +281,7 @@
     [USECASE_AUDIO_PLAYBACK_OFFLOAD8] = {-1, -1},
     [USECASE_AUDIO_PLAYBACK_OFFLOAD9] = {-1, -1},
 #endif
+    [USECASE_AUDIO_PLAYBACK_ULL] = {MULTIMEDIA3_PCM_DEVICE, MULTIMEDIA3_PCM_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,
@@ -663,6 +665,7 @@
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD8)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD9)},
 #endif
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_ULL)},
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)},
     {TO_NAME_INDEX(USECASE_VOICE_CALL)},
@@ -968,6 +971,41 @@
     }
 }
 
+void platform_set_echo_reference(struct audio_device *adev, bool enable,
+    audio_devices_t out_device)
+{
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+    snd_device_t snd_device = SND_DEVICE_NONE;
+    struct stream_out out;
+
+    out.devices = out_device;
+
+    if (strcmp(my_data->ec_ref_mixer_path, "")) {
+        ALOGV("%s: disabling %s", __func__, my_data->ec_ref_mixer_path);
+        audio_route_reset_and_update_path(adev->audio_route,
+            my_data->ec_ref_mixer_path);
+    }
+
+    if (enable) {
+        snd_device = platform_get_output_snd_device(adev->platform, &out);
+
+        if (adev->snd_dev_ref_cnt[SND_DEVICE_OUT_HEADPHONES_44_1] > 0)
+            strlcpy(my_data->ec_ref_mixer_path, "echo-reference headphones-44.1",
+                sizeof(my_data->ec_ref_mixer_path));
+        else if ((snd_device == SND_DEVICE_OUT_SPEAKER_VBAT) ||
+                 (snd_device == SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT))
+            strlcpy(my_data->ec_ref_mixer_path, "vbat-speaker echo-reference",
+                sizeof(my_data->ec_ref_mixer_path));
+        else
+            strlcpy(my_data->ec_ref_mixer_path, "echo-reference",
+                sizeof(my_data->ec_ref_mixer_path));
+
+
+        ALOGD("%s: enabling %s", __func__, my_data->ec_ref_mixer_path);
+        audio_route_apply_and_update_path(adev->audio_route,
+            my_data->ec_ref_mixer_path);
+    }
+}
 void platform_set_gsm_mode(void *platform, bool enable)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
@@ -986,27 +1024,7 @@
     }
 }
 
-void platform_set_echo_reference(void *platform, bool enable)
-{
-    struct platform_data *my_data = (struct platform_data *)platform;
-    struct audio_device *adev = my_data->adev;
-    char *mixer_path_name = "echo-reference";
 
-    if(my_data->is_vbat_speaker)
-       mixer_path_name = "vbat-speaker echo-reference";
-
-    if (my_data->ec_ref_enabled) {
-        my_data->ec_ref_enabled = false;
-        ALOGV("%s: disabling echo-reference", __func__);
-        audio_route_reset_and_update_path(adev->audio_route, mixer_path_name);
-    }
-
-    if (enable) {
-         my_data->ec_ref_enabled = true;
-         ALOGD("%s: enabling echo-reference", __func__);
-         audio_route_apply_and_update_path(adev->audio_route, mixer_path_name);
-    }
-}
 
 static struct csd_data *open_csd_client()
 {
@@ -1283,6 +1301,10 @@
                ALOGE("%s error in sending vbat adc data to acdb", __func__);
 	}
 
+        /* MAD calibration is handled by sound trigger HAL, skip here */
+        if (type == WCD9XXX_MAD_CAL)
+            continue;
+
         calib.get_size = 1;
         ret = acdb_loader_get_calibration(cal_name_info[type], sizeof(struct param_data),
                                                                  &calib);
@@ -2679,7 +2701,7 @@
                 my_data->fluence_in_voice_call == false) {
                 snd_device = SND_DEVICE_IN_HANDSET_MIC;
                 if (audio_extn_hfp_is_active(adev))
-                    platform_set_echo_reference(adev->platform, true);
+                    platform_set_echo_reference(adev, true, out_device);
             } else {
                 snd_device = SND_DEVICE_IN_VOICE_DMIC;
                 adev->acdb_settings |= DMIC_FLAG;
@@ -2687,7 +2709,7 @@
         } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
             snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC;
             if (audio_extn_hfp_is_active(adev))
-                platform_set_echo_reference(adev->platform, true);
+                platform_set_echo_reference(adev, true, out_device);
         } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
             if (adev->bt_wb_speech_enabled) {
                 if (adev->bluetooth_nrec)
@@ -2717,7 +2739,7 @@
             } else {
                 snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
                 if (audio_extn_hfp_is_active(adev))
-                    platform_set_echo_reference(adev->platform, true);
+                    platform_set_echo_reference(adev, true, out_device);
             }
         } else if (out_device & AUDIO_DEVICE_OUT_TELEPHONY_TX)
             snd_device = SND_DEVICE_IN_VOICE_RX;
@@ -2775,7 +2797,7 @@
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
                 }
-                platform_set_echo_reference(adev->platform, true);
+                platform_set_echo_reference(adev, true, out_device);
             } else if (my_data->fluence_type != FLUENCE_NONE &&
                        adev->active_input->enable_aec) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
@@ -2800,7 +2822,7 @@
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
                 }
-                platform_set_echo_reference(adev->platform, true);
+                platform_set_echo_reference(adev, true, out_device);
             } else if (my_data->fluence_type != FLUENCE_NONE &&
                        adev->active_input->enable_ns) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
@@ -2825,9 +2847,9 @@
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
                 }
-                platform_set_echo_reference(adev->platform,false);
+                platform_set_echo_reference(adev, false, out_device);
             } else
-                platform_set_echo_reference(adev->platform, false);
+                platform_set_echo_reference(adev, false, out_device);
         }
     } else if (source == AUDIO_SOURCE_MIC) {
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC &&
@@ -2835,10 +2857,10 @@
             if(my_data->fluence_in_audio_rec) {
                 if(my_data->fluence_type & FLUENCE_QUAD_MIC) {
                     snd_device = SND_DEVICE_IN_HANDSET_QMIC;
-                    platform_set_echo_reference(adev->platform, true);
+                    platform_set_echo_reference(adev, true, out_device);
                 } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
                     snd_device = SND_DEVICE_IN_HANDSET_DMIC;
-                    platform_set_echo_reference(adev->platform, true);
+                    platform_set_echo_reference(adev, true, out_device);
                 }
             }
         }
@@ -3931,9 +3953,11 @@
     ALOGI("%s Codec selected backend: %d current bit width: %d and sample rate: %d",
                __func__, backend_idx, bit_width, sample_rate);
 
-    // For voice calls use default configuration
+    // For voice calls use default configuration i.e. 16b/48K, only applicable to
+    // default backend
     // force routing is not required here, caller will do it anyway
-    if (voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
+    if ((voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
+        backend_idx == DEFAULT_CODEC_BACKEND) {
         ALOGW("%s:Use default bw and sr for voice/voip calls ",__func__);
         bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
         sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index bf5e834..5d0ad2d 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -236,6 +236,7 @@
 #define DEEP_BUFFER_PCM_DEVICE 0
 #define AUDIO_RECORD_PCM_DEVICE 0
 #define MULTIMEDIA2_PCM_DEVICE 1
+#define MULTIMEDIA3_PCM_DEVICE 4
 #define FM_PLAYBACK_PCM_DEVICE 5
 #define FM_CAPTURE_PCM_DEVICE  6
 #define HFP_PCM_RX 5
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 175a3a6..d519764 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -226,6 +226,7 @@
     struct csd_data *csd;
     void *edid_info;
     bool edid_valid;
+    char ec_ref_mixer_path[64];
     codec_backend_cfg_t current_backend_cfg[MAX_CODEC_BACKENDS];
 };
 
@@ -235,7 +236,7 @@
     [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
                                            LOWLATENCY_PCM_DEVICE},
     [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTIMEDIA2_PCM_DEVICE,
-                                        MULTIMEDIA2_PCM_DEVICE},
+                                         MULTIMEDIA2_PCM_DEVICE},
     [USECASE_AUDIO_PLAYBACK_OFFLOAD] =
                      {PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE},
 #ifdef MULTIPLE_OFFLOAD_ENABLED
@@ -256,6 +257,9 @@
     [USECASE_AUDIO_PLAYBACK_OFFLOAD9] =
                      {PLAYBACK_OFFLOAD_DEVICE9, PLAYBACK_OFFLOAD_DEVICE9},
 #endif
+    [USECASE_AUDIO_PLAYBACK_ULL] = {MULTIMEDIA3_PCM_DEVICE,
+                                    MULTIMEDIA3_PCM_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,
@@ -607,6 +611,7 @@
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD8)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD9)},
 #endif
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_ULL)},
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)},
     {TO_NAME_INDEX(USECASE_VOICE_CALL)},
@@ -710,23 +715,39 @@
 #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
 #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
 
-void platform_set_echo_reference(void *platform, bool enable)
+void platform_set_echo_reference(struct audio_device *adev, bool enable,
+    audio_devices_t out_device)
 {
-    struct platform_data *my_data = (struct platform_data *)platform;
-    struct audio_device *adev = my_data->adev;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+    snd_device_t snd_device = SND_DEVICE_NONE;
+    struct stream_out out;
 
-    if (my_data->ec_ref_enabled) {
-        my_data->ec_ref_enabled = false;
-        ALOGV("%s: disabling echo-reference", __func__);
-        audio_route_reset_and_update_path(adev->audio_route, "echo-reference");
+    out.devices = out_device;
+
+    if (strcmp(my_data->ec_ref_mixer_path, "")) {
+        ALOGV("%s: disabling %s", __func__, my_data->ec_ref_mixer_path);
+        audio_route_reset_and_update_path(adev->audio_route,
+            my_data->ec_ref_mixer_path);
     }
 
     if (enable) {
-         my_data->ec_ref_enabled = true;
-         ALOGD("%s: enabling echo-reference", __func__);
-         audio_route_apply_and_update_path(adev->audio_route, "echo-reference");
-    }
+        strlcpy(my_data->ec_ref_mixer_path, "echo-reference",
+            sizeof(my_data->ec_ref_mixer_path));
+        snd_device = platform_get_output_snd_device(adev->platform, &out);
+        /*
+         * If native audio device reference count > 0, then apply codec EC otherwise
+         * fallback to headphones if so or default
+         */
+        if (adev->snd_dev_ref_cnt[SND_DEVICE_OUT_HEADPHONES_44_1] > 0)
+            platform_add_backend_name(my_data->ec_ref_mixer_path,
+                SND_DEVICE_OUT_HEADPHONES_44_1);
+        else
+            platform_add_backend_name(my_data->ec_ref_mixer_path, snd_device);
 
+        ALOGD("%s: enabling %s", __func__, my_data->ec_ref_mixer_path);
+        audio_route_apply_and_update_path(adev->audio_route,
+            my_data->ec_ref_mixer_path);
+    }
 }
 
 static struct csd_data *open_csd_client(bool i2s_ext_modem)
@@ -993,6 +1014,10 @@
         struct wcdcal_ioctl_buffer codec_buffer;
         struct param_data calib;
 
+        /* MAD calibration is handled by sound trigger HAL, skip here */
+        if (type == WCD9XXX_MAD_CAL)
+            continue;
+
         calib.get_size = 1;
         ret = acdb_loader_get_calibration(cal_name_info[type], sizeof(struct param_data),
                                                                  &calib);
@@ -2270,14 +2295,14 @@
                 my_data->fluence_in_voice_call == false) {
                 snd_device = SND_DEVICE_IN_HANDSET_MIC;
                 if (audio_extn_hfp_is_active(adev))
-                    platform_set_echo_reference(adev->platform, true);
+                    platform_set_echo_reference(adev, true, out_device);
             } else {
                 snd_device = SND_DEVICE_IN_VOICE_DMIC;
             }
         } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
             snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC;
             if (audio_extn_hfp_is_active(adev))
-                platform_set_echo_reference(adev->platform, true);
+                platform_set_echo_reference(adev, true, out_device);
         } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
             if (adev->bt_wb_speech_enabled) {
                 if (adev->bluetooth_nrec)
@@ -2305,7 +2330,7 @@
             } else {
                 snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
                 if (audio_extn_hfp_is_active(adev))
-                    platform_set_echo_reference(adev->platform, true);
+                    platform_set_echo_reference(adev, true, out_device);
             }
         } else if (out_device & AUDIO_DEVICE_OUT_TELEPHONY_TX)
             snd_device = SND_DEVICE_IN_VOICE_RX;
@@ -2353,7 +2378,7 @@
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
                 }
-                platform_set_echo_reference(adev->platform, true);
+                platform_set_echo_reference(adev, true, out_device);
             } else if (adev->active_input->enable_aec) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
                     if (my_data->fluence_in_spkr_mode) {
@@ -2375,7 +2400,7 @@
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
                 }
-                platform_set_echo_reference(adev->platform, true);
+                platform_set_echo_reference(adev, true, out_device);
             } else if (adev->active_input->enable_ns) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
                     if (my_data->fluence_in_spkr_mode) {
@@ -2397,9 +2422,9 @@
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
                 }
-                platform_set_echo_reference(adev->platform, false);
+                platform_set_echo_reference(adev, false, out_device);
             } else
-                platform_set_echo_reference(adev->platform, false);
+                platform_set_echo_reference(adev, false, out_device);
         }
     } else if (source == AUDIO_SOURCE_MIC) {
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC &&
@@ -2407,10 +2432,10 @@
             if(my_data->fluence_in_audio_rec) {
                 if(my_data->fluence_type & FLUENCE_QUAD_MIC) {
                     snd_device = SND_DEVICE_IN_HANDSET_QMIC;
-                    platform_set_echo_reference(adev->platform, true);
+                    platform_set_echo_reference(adev, true, out_device);
                 } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
                     snd_device = SND_DEVICE_IN_HANDSET_DMIC;
-                    platform_set_echo_reference(adev->platform, true);
+                    platform_set_echo_reference(adev, true, out_device);
                 }
             }
         }
@@ -3404,9 +3429,12 @@
 
     ALOGI("%s Codec selected backend: %d current bit width: %d and sample rate: %d",
                __func__, backend_idx, bit_width, sample_rate);
-    // For voice calls use default configuration
+
+    // For voice calls use default configuration i.e. 16b/48K, only applicable to
+    // default backend
     // force routing is not required here, caller will do it anyway
-    if (voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
+    if ((voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
+        backend_idx == DEFAULT_CODEC_BACKEND) {
         ALOGW("%s:Use default bw and sr for voice/voip calls ",__func__);
         bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
         sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 79e0816..4787b86 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -217,6 +217,7 @@
 #define DEEP_BUFFER_PCM_DEVICE 0
 #define AUDIO_RECORD_PCM_DEVICE 0
 #define MULTIMEDIA2_PCM_DEVICE 1
+#define MULTIMEDIA3_PCM_DEVICE 4
 #define FM_PLAYBACK_PCM_DEVICE 5
 #define FM_CAPTURE_PCM_DEVICE  6
 #define HFP_PCM_RX 5
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 53ddb48..9430721 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -101,7 +101,7 @@
                    struct audio_usecase *usecase, snd_device_t snd_device);
 int platform_get_usecase_index(const char * usecase);
 int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id);
-void platform_set_echo_reference(void *platform, bool enable);
+void platform_set_echo_reference(struct audio_device *adev, bool enable, audio_devices_t out_device);
 void platform_get_device_to_be_id_map(int **be_id_map, int *length);
 
 int platform_set_channel_allocation(void *platform, int channel_alloc);
diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp
index a638c1d..17b7135 100644
--- a/policy_hal/AudioPolicyManager.cpp
+++ b/policy_hal/AudioPolicyManager.cpp
@@ -907,6 +907,53 @@
         mLimitRingtoneVolume = false;
     }
 }
+
+void AudioPolicyManagerCustom::setForceUse(audio_policy_force_use_t usage,
+                                         audio_policy_forced_cfg_t config)
+{
+    ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mEngine->getPhoneState());
+
+    if (mEngine->setForceUse(usage, config) != NO_ERROR) {
+        ALOGW("setForceUse() could not set force cfg %d for usage %d", config, usage);
+        return;
+    }
+    bool forceVolumeReeval = (usage == AUDIO_POLICY_FORCE_FOR_COMMUNICATION) ||
+            (usage == AUDIO_POLICY_FORCE_FOR_DOCK) ||
+            (usage == AUDIO_POLICY_FORCE_FOR_SYSTEM);
+
+    // check for device and output changes triggered by new force usage
+    checkA2dpSuspend();
+    checkOutputForAllStrategies();
+    updateDevicesAndOutputs();
+    if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
+        audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, true /*fromCache*/);
+        updateCallRouting(newDevice);
+    }
+    // Use reverse loop to make sure any low latency usecases (generally tones)
+    // are not routed before non LL usecases (generally music).
+    // We can safely assume that LL output would always have lower index,
+    // and use this work-around to avoid routing of output with music stream
+    // from the context of short lived LL output.
+    // Note: in case output's share backend(HAL sharing is implicit) all outputs
+    //       gets routing update while processing first output itself.
+    for (size_t i = mOutputs.size(); i > 0; i--) {
+        sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(i-1);
+        audio_devices_t newDevice = getNewOutputDevice(outputDesc, true /*fromCache*/);
+        if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || outputDesc != mPrimaryOutput) {
+            setOutputDevice(outputDesc, newDevice, (newDevice != AUDIO_DEVICE_NONE));
+        }
+        if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) {
+            applyStreamVolumes(outputDesc, newDevice, 0, true);
+        }
+    }
+
+    audio_io_handle_t activeInput = mInputs.getActiveInput();
+    if (activeInput != 0) {
+        setInputDevice(activeInput, getNewInputDevice(activeInput));
+    }
+
+}
+
 status_t AudioPolicyManagerCustom::stopSource(sp<SwAudioOutputDescriptor> outputDesc,
                                             audio_stream_type_t stream,
                                             bool forceDeviceUpdate)
@@ -1816,6 +1863,32 @@
     return status;
 }
 
+void AudioPolicyManagerCustom::closeAllInputs() {
+    bool patchRemoved = false;
+
+    for(size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+        sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(input_index);
+        ssize_t patch_index = mAudioPatches.indexOfKey(inputDesc->mPatchHandle);
+        if (patch_index >= 0) {
+            sp<AudioPatch> patchDesc = mAudioPatches.valueAt(patch_index);
+            status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+            mAudioPatches.removeItemsAt(patch_index);
+            patchRemoved = true;
+        }
+        if ((inputDesc->mIsSoundTrigger) && (mInputs.size() == 1)) {
+            ALOGD("Do not close sound trigger input handle");
+        } else {
+            mpClientInterface->closeInput(mInputs.keyAt(input_index));
+            mInputs.removeItem(mInputs.keyAt(input_index));
+        }
+    }
+    nextAudioPortGeneration();
+
+    if (patchRemoved) {
+        mpClientInterface->onAudioPatchListUpdate();
+    }
+}
+
 AudioPolicyManagerCustom::AudioPolicyManagerCustom(AudioPolicyClientInterface *clientInterface)
     : AudioPolicyManager(clientInterface),
       mHdmiAudioDisabled(false),
diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h
index 53c9a1b..66f9c38 100644
--- a/policy_hal/AudioPolicyManager.h
+++ b/policy_hal/AudioPolicyManager.h
@@ -54,6 +54,8 @@
                                           const char *device_address,
                                           const char *device_name);
         virtual void setPhoneState(audio_mode_t state);
+        virtual void setForceUse(audio_policy_force_use_t usage,
+                                 audio_policy_forced_cfg_t config);
 
         virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo);
 
@@ -73,6 +75,7 @@
         // indicates to the audio policy manager that the input stops being used.
         virtual status_t stopInput(audio_io_handle_t input,
                                    audio_session_t session);
+        virtual void closeAllInputs();
 
 protected:
 
diff --git a/post_proc/Android.mk b/post_proc/Android.mk
index ed46f17..3b9787c 100644
--- a/post_proc/Android.mk
+++ b/post_proc/Android.mk
@@ -21,6 +21,11 @@
     LOCAL_SRC_FILES += hw_accelerator.c
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AUDIOSPHERE)),true)
+    LOCAL_CFLAGS += -DAUDIOSPHERE_ENABLED
+    LOCAL_SRC_FILES += asphere.c
+endif
+
 LOCAL_CFLAGS+= -O2 -fvisibility=hidden
 
 ifneq ($(strip $(AUDIO_FEATURE_DISABLED_DTS_EAGLE)),true)
diff --git a/post_proc/asphere.c b/post_proc/asphere.c
new file mode 100644
index 0000000..bbf1056
--- /dev/null
+++ b/post_proc/asphere.c
@@ -0,0 +1,301 @@
+/* Copyright (c) 2015, 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
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_TAG "audio_pp_asphere"
+/*#define LOG_NDEBUG 0*/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <cutils/log.h>
+#include <cutils/list.h>
+#include <cutils/str_parms.h>
+#include <cutils/properties.h>
+#include <hardware/audio_effect.h>
+#include "bundle.h"
+#include "equalizer.h"
+#include "bass_boost.h"
+#include "virtualizer.h"
+#include "reverb.h"
+#include "asphere.h"
+
+#define ASPHERE_MIXER_NAME  "MSM ASphere Set Param"
+
+#define AUDIO_PARAMETER_KEY_ASPHERE_STATUS  "asphere_status"
+#define AUDIO_PARAMETER_KEY_ASPHERE_ENABLE   "asphere_enable"
+#define AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH "asphere_strength"
+
+#define AUDIO_ASPHERE_EVENT_NODE "/data/misc/audio_pp/event_node"
+
+enum {
+    ASPHERE_ACTIVE = 0,
+    ASPHERE_SUSPENDED,
+    ASPHERE_ERROR
+};
+
+struct asphere_module {
+    bool enabled;
+    int status;
+    int strength;
+    pthread_mutex_t lock;
+    int init_status;
+};
+
+static struct asphere_module asphere;
+pthread_once_t asphere_once = PTHREAD_ONCE_INIT;
+
+static int asphere_create_app_notification_node(void)
+{
+    int fd;
+    if ((fd = open(AUDIO_ASPHERE_EVENT_NODE, O_CREAT|O_TRUNC|O_WRONLY,
+                            S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
+        ALOGE("creating notification node failed %d", errno);
+        return -EINVAL;
+    }
+    chmod(AUDIO_ASPHERE_EVENT_NODE, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH);
+    close(fd);
+    ALOGD("%s: successfully created notification node %s",
+                               __func__, AUDIO_ASPHERE_EVENT_NODE);
+    return 0;
+}
+
+static int asphere_notify_app(void)
+{
+    int fd;
+    if ((fd = open(AUDIO_ASPHERE_EVENT_NODE, O_TRUNC|O_WRONLY)) < 0) {
+        ALOGE("opening notification node failed %d", errno);
+        return -EINVAL;
+    }
+    close(fd);
+    ALOGD("%s: successfully opened notification node", __func__);
+    return 0;
+}
+
+static int asphere_get_values_from_mixer(void)
+{
+    int ret = 0, val[2] = {-1, -1};
+    struct mixer_ctl *ctl = NULL;
+    struct mixer *mixer = mixer_open(MIXER_CARD);
+    if (mixer)
+        ctl = mixer_get_ctl_by_name(mixer, ASPHERE_MIXER_NAME);
+    if (!ctl) {
+        ALOGE("%s: could not get ctl for mixer cmd - %s",
+              __func__, ASPHERE_MIXER_NAME);
+        return -EINVAL;
+    }
+    ret = mixer_ctl_get_array(ctl, val, sizeof(val)/sizeof(val[0]));
+    if (!ret) {
+        asphere.enabled = (val[0] == 0) ? false : true;
+        asphere.strength = val[1];
+    }
+    ALOGD("%s: returned %d, enabled:%d, strength:%d",
+          __func__, ret, val[0], val[1]);
+
+    return ret;
+}
+
+static int asphere_set_values_to_mixer(void)
+{
+    int ret = 0, val[2] = {-1, -1};
+    struct mixer_ctl *ctl = NULL;
+    struct mixer *mixer = mixer_open(MIXER_CARD);
+    if (mixer)
+        ctl = mixer_get_ctl_by_name(mixer, ASPHERE_MIXER_NAME);
+    if (!ctl) {
+        ALOGE("%s: could not get ctl for mixer cmd - %s",
+              __func__, ASPHERE_MIXER_NAME);
+        return -EINVAL;
+    }
+    val[0] = ((asphere.status == ASPHERE_ACTIVE) && asphere.enabled) ? 1 : 0;
+    val[1] = asphere.strength;
+
+    ret = mixer_ctl_set_array(ctl, val, sizeof(val)/sizeof(val[0]));
+    ALOGD("%s: returned %d, enabled:%d, strength:%d",
+          __func__, ret, val[0], val[1]);
+
+    return ret;
+}
+
+static void asphere_init_once() {
+    ALOGD("%s", __func__);
+    pthread_mutex_init(&asphere.lock, NULL);
+    asphere.init_status = 1;
+    asphere_get_values_from_mixer();
+    asphere_create_app_notification_node();
+}
+
+static int asphere_init() {
+    pthread_once(&asphere_once, asphere_init_once);
+    return asphere.init_status;
+}
+
+void asphere_set_parameters(struct str_parms *parms)
+{
+    int ret = 0;
+    bool enable = false;
+    int strength = -1;
+    char value[32] = {0};
+    char propValue[PROPERTY_VALUE_MAX] = {0};
+    bool set_enable = false, set_strength = false;
+
+    if (!property_get("audio.pp.asphere.enabled", propValue, "false") ||
+        (strncmp("true", propValue, 4) != 0)) {
+        ALOGV("%s: property not set!!! not doing anything", __func__);
+        return;
+    }
+    if (asphere_init() != 1) {
+        ALOGW("%s: init check failed!!!", __func__);
+        return;
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_ASPHERE_ENABLE,
+                                                  value, sizeof(value));
+    if (ret > 0) {
+        enable = (atoi(value) == 1) ? true : false;
+        set_enable = true;
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH,
+                                                   value, sizeof(value));
+    if (ret > 0) {
+        strength = atoi(value);
+        if (strength >= 0 && strength <= 1000)
+            set_strength = true;
+    }
+
+    if (set_enable || set_strength) {
+        pthread_mutex_lock(&asphere.lock);
+        asphere.enabled = set_enable ? enable : asphere.enabled;
+        asphere.strength = set_strength ? strength : asphere.strength;
+        ret = asphere_set_values_to_mixer();
+        pthread_mutex_unlock(&asphere.lock);
+        ALOGV("%s: exit ret %d", __func__, ret);
+    }
+}
+
+void asphere_get_parameters(struct str_parms *query,
+                                      struct str_parms *reply)
+{
+    char value[32] = {0};
+    char propValue[PROPERTY_VALUE_MAX] = {0};
+    int get_status, get_enable, get_strength, ret;
+
+    if (!property_get("audio.pp.asphere.enabled", propValue, "false") ||
+        (strncmp("true", propValue, 4) != 0)) {
+        ALOGV("%s: property not set!!! not doing anything", __func__);
+        return;
+    }
+    if (asphere_init() != 1) {
+        ALOGW("%s: init check failed!!!", __func__);
+        return;
+    }
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ASPHERE_STATUS,
+                                                 value, sizeof(value));
+    if (ret >= 0) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_ASPHERE_STATUS,
+                                                     asphere.status);
+    }
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ASPHERE_ENABLE,
+                                                 value, sizeof(value));
+    if (ret >= 0) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_ASPHERE_ENABLE,
+                                              asphere.enabled ? 1 : 0);
+    }
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH,
+                                                  value, sizeof(value));
+    if (ret >= 0) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH,
+                                                     asphere.strength);
+    }
+}
+
+static bool effect_needs_asphere_concurrency_handling(effect_context_t *context)
+{
+    if (memcmp(&context->desc->type,
+                &equalizer_descriptor.type, sizeof(effect_uuid_t)) == 0 ||
+        memcmp(&context->desc->type,
+                &bassboost_descriptor.type, sizeof(effect_uuid_t)) == 0 ||
+        memcmp(&context->desc->type,
+                &virtualizer_descriptor.type, sizeof(effect_uuid_t)) == 0 ||
+        memcmp(&context->desc->type,
+                &ins_preset_reverb_descriptor.type, sizeof(effect_uuid_t)) == 0 ||
+        memcmp(&context->desc->type,
+                &ins_env_reverb_descriptor.type, sizeof(effect_uuid_t)) == 0)
+        return true;
+
+    return false;
+}
+
+void handle_asphere_on_effect_enabled(bool enable,
+                                      effect_context_t *context,
+                                      struct listnode *created_effects)
+{
+    struct listnode *node;
+    char propValue[PROPERTY_VALUE_MAX] = {0};
+
+    ALOGV("%s: effect %0x", __func__, context->desc->type.timeLow);
+    if (!property_get("audio.pp.asphere.enabled", propValue, "false") ||
+        (strncmp("true", propValue, 4) != 0)) {
+        ALOGV("%s: property not set!!! not doing anything", __func__);
+        return;
+    }
+    if (asphere_init() != 1) {
+        ALOGW("%s: init check failed!!!", __func__);
+        return;
+    }
+
+    if (!effect_needs_asphere_concurrency_handling(context)) {
+        ALOGV("%s: effect %0x, do not need concurrency handling",
+                                 __func__, context->desc->type.timeLow);
+        return;
+    }
+
+    list_for_each(node, created_effects) {
+        effect_context_t *fx_ctxt = node_to_item(node,
+                                                 effect_context_t,
+                                                 effects_list_node);
+        if (fx_ctxt != NULL &&
+            effect_needs_asphere_concurrency_handling(fx_ctxt) == true &&
+            fx_ctxt != context && effect_is_active(fx_ctxt) == true) {
+            ALOGV("%s: found another effect %0x, skip processing %0x", __func__,
+                      fx_ctxt->desc->type.timeLow, context->desc->type.timeLow);
+            return;
+        }
+    }
+    pthread_mutex_lock(&asphere.lock);
+    asphere.status = enable ? ASPHERE_SUSPENDED : ASPHERE_ACTIVE;
+    asphere_set_values_to_mixer();
+    asphere_notify_app();
+    pthread_mutex_unlock(&asphere.lock);
+}
diff --git a/post_proc/asphere.h b/post_proc/asphere.h
new file mode 100644
index 0000000..d0e6830
--- /dev/null
+++ b/post_proc/asphere.h
@@ -0,0 +1,50 @@
+/* Copyright (c) 2015, 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
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef OFFLOAD_ASPHERE_H_
+#define OFFLOAD_ASPHERE_H_
+
+#include <cutils/str_parms.h>
+#include <cutils/list.h>
+#include "bundle.h"
+
+#ifdef AUDIOSPHERE_ENABLED
+void asphere_get_parameters(struct str_parms *query,
+                            struct str_parms *reply);
+void asphere_set_parameters(struct str_parms *reply);
+void handle_asphere_on_effect_enabled(bool enable,
+                                      effect_context_t *context,
+                                      struct listnode *created_effects);
+#else
+#define asphere_get_parameters(query, reply) (0)
+#define asphere_set_parameters(parms)  (0)
+#define handle_asphere_on_effect_enabled(enable, context, created_effects) (0)
+#endif /* AUDIOSPHERE_ENABLED */
+
+#endif /* OFFLOAD_ASPHERE_H_ */
diff --git a/post_proc/bundle.c b/post_proc/bundle.c
index b33f2d1..8df93cb 100644
--- a/post_proc/bundle.c
+++ b/post_proc/bundle.c
@@ -50,6 +50,7 @@
 #include "bass_boost.h"
 #include "virtualizer.h"
 #include "reverb.h"
+#include "asphere.h"
 
 #ifdef DTS_EAGLE
 #include "effect_util.h"
@@ -455,6 +456,24 @@
 }
 
 /*
+ * Effect Bundle Set and get param operations.
+ * currently only handles audio sphere scenario,
+ * but the interface itself can be utilized for any effect.
+ */
+__attribute__ ((visibility ("default")))
+void offload_effects_bundle_get_parameters(struct str_parms *query,
+                                           struct str_parms *reply)
+{
+    asphere_get_parameters(query, reply);
+}
+
+__attribute__ ((visibility ("default")))
+void offload_effects_bundle_set_parameters(struct str_parms *parms)
+{
+    asphere_set_parameters(parms);
+}
+
+/*
  * Effect operations
  */
 int set_config(effect_context_t *context, effect_config_t *config)
@@ -810,6 +829,7 @@
             status = -ENOSYS;
             goto exit;
         }
+        handle_asphere_on_effect_enabled(true, context, &created_effects_list);
         context->state = EFFECT_STATE_ACTIVE;
         if (context->ops.enable)
             context->ops.enable(context);
@@ -824,6 +844,7 @@
             status = -ENOSYS;
             goto exit;
         }
+        handle_asphere_on_effect_enabled(false, context, &created_effects_list);
         context->state = EFFECT_STATE_INITIALIZED;
         if (context->ops.disable)
             context->ops.disable(context);
diff --git a/visualizer/offload_visualizer.c b/visualizer/offload_visualizer.c
index d363b77..b2f0952 100644
--- a/visualizer/offload_visualizer.c
+++ b/visualizer/offload_visualizer.c
@@ -300,20 +300,40 @@
     return false;
 }
 
-int configure_proxy_capture(struct mixer *mixer, int value) {
-    const char *proxy_ctl_name = "AFE_PCM_RX Audio Mixer MultiMedia4";
+int set_control(const char* name, struct mixer *mixer, int value) {
     struct mixer_ctl *ctl;
 
+    ctl = mixer_get_ctl_by_name(mixer, name);
+    if (ctl == NULL) {
+        ALOGW("%s: could not get %s ctl", __func__, name);
+        return -EINVAL;
+    }
+    if (mixer_ctl_set_value(ctl, 0, value) != 0) {
+        ALOGW("%s: error setting value %d on %s ", __func__, value, name);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+int configure_proxy_capture(struct mixer *mixer, int value) {
+    int retval = 0;
+
     if (value && acdb_send_audio_cal)
         acdb_send_audio_cal(AFE_PROXY_ACDB_ID, ACDB_DEV_TYPE_OUT);
 
-    ctl = mixer_get_ctl_by_name(mixer, proxy_ctl_name);
-    if (ctl == NULL) {
-        ALOGW("%s: could not get %s ctl", __func__, proxy_ctl_name);
-        return -EINVAL;
-    }
-    if (mixer_ctl_set_value(ctl, 0, value) != 0)
-        ALOGW("%s: error setting value %d on %s ", __func__, value, proxy_ctl_name);
+    retval = set_control("AFE_PCM_RX Audio Mixer MultiMedia4", mixer, value);
+
+    if (retval != 0)
+        return retval;
+
+    // Extending visualizer to capture for compress2 path as well.
+    // for extending it to multiple offload either this needs to be extended
+    // or need to find better solution to enable only active offload sessions
+
+    retval = set_control("AFE_PCM_RX Audio Mixer MultiMedia7", mixer, value);
+    if (retval != 0)
+        return retval;
 
     return 0;
 }