Merge "Check for the DEVICE_POWER permission in userActivity." into gingerbread
diff --git a/location/Android.mk b/location/Android.mk
new file mode 100644
index 0000000..12db2f746
--- /dev/null
+++ b/location/Android.mk
@@ -0,0 +1,19 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(TARGET_BUILD_APPS),)
+include $(call all-makefiles-under, $(LOCAL_PATH))
+endif
diff --git a/location/lib/Android.mk b/location/lib/Android.mk
new file mode 100644
index 0000000..a06478a
--- /dev/null
+++ b/location/lib/Android.mk
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)
+
+# the library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= com.android.location.provider
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+            $(call all-subdir-java-files)
+
+include $(BUILD_JAVA_LIBRARY)
+
+
+# ====  com.google.location.xml lib def  ========================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := com.android.location.provider.xml
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_CLASS := ETC
+
+# This will install the file in /system/etc/permissions
+#
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
diff --git a/location/lib/com.android.location.provider.xml b/location/lib/com.android.location.provider.xml
new file mode 100644
index 0000000..000e68f
--- /dev/null
+++ b/location/lib/com.android.location.provider.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<permissions>
+    <library name="com.android.location.provider"
+            file="/system/framework/com.android.location.provider.jar" />
+</permissions>
diff --git a/location/lib/java/com/android/location/provider/GeocodeProvider.java b/location/lib/java/com/android/location/provider/GeocodeProvider.java
new file mode 100644
index 0000000..666bb02
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/GeocodeProvider.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.location.provider;
+
+import android.os.IBinder;
+
+import android.location.Address;
+import android.location.GeocoderParams;
+import android.location.IGeocodeProvider;
+
+import java.util.List;
+
+/**
+ * An abstract superclass for geocode providers that are implemented
+ * outside of the core android platform.
+ * Geocode providers can be implemented as services and return the result of
+ * {@link GeocodeProvider#getBinder()} in its getBinder() method.
+ *
+ * @hide
+ */
+public abstract class GeocodeProvider {
+
+    private IGeocodeProvider.Stub mProvider = new IGeocodeProvider.Stub() {
+        public String getFromLocation(double latitude, double longitude, int maxResults,
+                GeocoderParams params, List<Address> addrs) {
+            return GeocodeProvider.this.onGetFromLocation(latitude, longitude, maxResults,
+                    params, addrs);
+        }
+
+        public String getFromLocationName(String locationName,
+                double lowerLeftLatitude, double lowerLeftLongitude,
+                double upperRightLatitude, double upperRightLongitude, int maxResults,
+                GeocoderParams params, List<Address> addrs) {
+            return GeocodeProvider.this.onGetFromLocationName(locationName, lowerLeftLatitude,
+                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
+                    maxResults, params, addrs);
+        }
+    };
+
+    /**
+     * This method is overridden to implement the
+     * {@link android.location.Geocoder#getFromLocation(double, double, int)} method.
+     * Classes implementing this method should not hold a reference to the params parameter.
+     */
+    public abstract String onGetFromLocation(double latitude, double longitude, int maxResults,
+            GeocoderParams params, List<Address> addrs);
+
+    /**
+     * This method is overridden to implement the
+     * {@link android.location.Geocoder#getFromLocationName(String, int, double, double, double, double)} method.
+     * Classes implementing this method should not hold a reference to the params parameter.
+     */
+    public abstract String onGetFromLocationName(String locationName,
+            double lowerLeftLatitude, double lowerLeftLongitude,
+            double upperRightLatitude, double upperRightLongitude, int maxResults,
+            GeocoderParams params, List<Address> addrs);
+
+    /**
+     * Returns the Binder interface for the geocode provider.
+     * This is intended to be used for the onBind() method of
+     * a service that implements a geocoder service.
+     *
+     * @return the IBinder instance for the provider
+     */
+    public IBinder getBinder() {
+        return mProvider;
+    }
+}
diff --git a/location/lib/java/com/android/location/provider/LocationProvider.java b/location/lib/java/com/android/location/provider/LocationProvider.java
new file mode 100644
index 0000000..3714f40
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/LocationProvider.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.location.provider;
+
+import android.content.Context;
+import android.net.NetworkInfo;
+import android.location.Criteria;
+import android.location.ILocationManager;
+import android.location.ILocationProvider;
+import android.location.Location;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.WorkSource;
+import android.util.Log;
+
+/**
+ * An abstract superclass for location providers that are implemented
+ * outside of the core android platform.
+ * Location providers can be implemented as services and return the result of
+ * {@link LocationProvider#getBinder()} in its getBinder() method.
+ *
+ * @hide
+ */
+public abstract class LocationProvider {
+
+    private static final String TAG = "LocationProvider";
+
+    private ILocationManager mLocationManager;
+
+    private ILocationProvider.Stub mProvider = new ILocationProvider.Stub() {
+
+        public boolean requiresNetwork() {
+            return LocationProvider.this.onRequiresNetwork();
+        }
+
+        public boolean requiresSatellite() {
+            return LocationProvider.this.onRequiresSatellite();
+        }
+
+        public boolean requiresCell() {
+            return LocationProvider.this.onRequiresCell();
+        }
+
+        public boolean hasMonetaryCost() {
+            return LocationProvider.this.onHasMonetaryCost();
+        }
+
+        public boolean supportsAltitude() {
+            return LocationProvider.this.onSupportsAltitude();
+        }
+
+        public boolean supportsSpeed() {
+            return LocationProvider.this.onSupportsSpeed();
+        }
+
+        public boolean supportsBearing() {
+            return LocationProvider.this.onSupportsBearing();
+        }
+
+        public int getPowerRequirement() {
+            return LocationProvider.this.onGetPowerRequirement();
+        }
+
+        public boolean meetsCriteria(Criteria criteria) {
+            return LocationProvider.this.onMeetsCriteria(criteria);
+        }
+
+        public int getAccuracy() {
+            return LocationProvider.this.onGetAccuracy();
+        }
+
+        public void enable() {
+            LocationProvider.this.onEnable();
+        }
+
+        public void disable() {
+            LocationProvider.this.onDisable();
+        }
+
+        public int getStatus(Bundle extras) {
+            return LocationProvider.this.onGetStatus(extras);
+        }
+
+        public long getStatusUpdateTime() {
+            return LocationProvider.this.onGetStatusUpdateTime();
+        }
+
+        public String getInternalState() {
+            return LocationProvider.this.onGetInternalState();
+        }
+
+        public void enableLocationTracking(boolean enable) {
+            LocationProvider.this.onEnableLocationTracking(enable);
+        }
+
+        public void setMinTime(long minTime, WorkSource ws) {
+            LocationProvider.this.onSetMinTime(minTime, ws);
+        }
+
+        public void updateNetworkState(int state, NetworkInfo info) {
+            LocationProvider.this.onUpdateNetworkState(state, info);
+        }
+
+        public void updateLocation(Location location) {
+            LocationProvider.this.onUpdateLocation(location);
+        }
+
+        public boolean sendExtraCommand(String command, Bundle extras) {
+            return LocationProvider.this.onSendExtraCommand(command, extras);
+        }
+
+        public void addListener(int uid) {
+            LocationProvider.this.onAddListener(uid, new WorkSource(uid));
+        }
+
+        public void removeListener(int uid) {
+            LocationProvider.this.onRemoveListener(uid, new WorkSource(uid));
+        }
+    };
+
+    public LocationProvider() {
+        IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
+        mLocationManager = ILocationManager.Stub.asInterface(b);
+    }
+
+    /**
+     * {@hide}
+     */
+    /* package */ ILocationProvider getInterface() {
+        return mProvider;
+    }
+
+    /**
+     * Returns the Binder interface for the location provider.
+     * This is intended to be used for the onBind() method of
+     * a service that implements a location provider service.
+     *
+     * @return the IBinder instance for the provider
+     */
+    public IBinder getBinder() {
+        return mProvider;
+    }
+
+    /**
+     * Used by the location provider to report new locations.
+     *
+     * @param location new Location to report
+     *
+     * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
+     */
+    public void reportLocation(Location location) {
+        try {
+            mLocationManager.reportLocation(location, false);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in reportLocation: ", e);
+        }
+    }
+
+    /**
+     * Returns true if the provider requires access to a
+     * data network (e.g., the Internet), false otherwise.
+     */
+    public abstract boolean onRequiresNetwork();
+
+    /**
+     * Returns true if the provider requires access to a
+     * satellite-based positioning system (e.g., GPS), false
+     * otherwise.
+     */
+    public abstract boolean onRequiresSatellite();
+
+    /**
+     * Returns true if the provider requires access to an appropriate
+     * cellular network (e.g., to make use of cell tower IDs), false
+     * otherwise.
+     */
+    public abstract boolean onRequiresCell();
+
+    /**
+     * Returns true if the use of this provider may result in a
+     * monetary charge to the user, false if use is free.  It is up to
+     * each provider to give accurate information.
+     */
+    public abstract boolean onHasMonetaryCost();
+
+    /**
+     * Returns true if the provider is able to provide altitude
+     * information, false otherwise.  A provider that reports altitude
+     * under most circumstances but may occassionally not report it
+     * should return true.
+     */
+    public abstract boolean onSupportsAltitude();
+
+    /**
+     * Returns true if the provider is able to provide speed
+     * information, false otherwise.  A provider that reports speed
+     * under most circumstances but may occassionally not report it
+     * should return true.
+     */
+    public abstract boolean onSupportsSpeed();
+
+    /**
+     * Returns true if the provider is able to provide bearing
+     * information, false otherwise.  A provider that reports bearing
+     * under most circumstances but may occassionally not report it
+     * should return true.
+     */
+    public abstract boolean onSupportsBearing();
+
+    /**
+     * Returns the power requirement for this provider.
+     *
+     * @return the power requirement for this provider, as one of the
+     * constants Criteria.POWER_REQUIREMENT_*.
+     */
+    public abstract int onGetPowerRequirement();
+
+    /**
+     * Returns true if this provider meets the given criteria,
+     * false otherwise.
+     */
+    public abstract boolean onMeetsCriteria(Criteria criteria);
+
+    /**
+     * Returns a constant describing horizontal accuracy of this provider.
+     * If the provider returns finer grain or exact location,
+     * {@link Criteria#ACCURACY_FINE} is returned, otherwise if the
+     * location is only approximate then {@link Criteria#ACCURACY_COARSE}
+     * is returned.
+     */
+    public abstract int onGetAccuracy();
+
+    /**
+     * Enables the location provider
+     */
+    public abstract void onEnable();
+
+    /**
+     * Disables the location provider
+     */
+    public abstract void onDisable();
+
+    /**
+     * Returns a information on the status of this provider.
+     * {@link android.location.LocationProvider#OUT_OF_SERVICE} is returned if the provider is
+     * out of service, and this is not expected to change in the near
+     * future; {@link android.location.LocationProvider#TEMPORARILY_UNAVAILABLE} is returned if
+     * the provider is temporarily unavailable but is expected to be
+     * available shortly; and {@link android.location.LocationProvider#AVAILABLE} is returned
+     * if the provider is currently available.
+     *
+     * <p> If extras is non-null, additional status information may be
+     * added to it in the form of provider-specific key/value pairs.
+     */
+    public abstract int onGetStatus(Bundle extras);
+
+    /**
+     * Returns the time at which the status was last updated. It is the
+     * responsibility of the provider to appropriately set this value using
+     * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()}.
+     * there is a status update that it wishes to broadcast to all its
+     * listeners. The provider should be careful not to broadcast
+     * the same status again.
+     *
+     * @return time of last status update in millis since last reboot
+     */
+    public abstract long onGetStatusUpdateTime();
+
+    /**
+     * Returns debugging information about the location provider.
+     *
+     * @return string describing the internal state of the location provider, or null.
+     */
+    public abstract String onGetInternalState();
+
+    /**
+     * Notifies the location provider that clients are listening for locations.
+     * Called with enable set to true when the first client is added and
+     * called with enable set to false when the last client is removed.
+     * This allows the provider to prepare for receiving locations,
+     * and to shut down when no clients are remaining.
+     *
+     * @param enable true if location tracking should be enabled.
+     */
+    public abstract void onEnableLocationTracking(boolean enable);
+
+    /**
+     * Notifies the location provider of the smallest minimum time between updates amongst
+     * all clients that are listening for locations.  This allows the provider to reduce
+     * the frequency of updates to match the requested frequency.
+     *
+     * @param minTime the smallest minTime value over all listeners for this provider.
+     * @param ws the source this work is coming from.
+     */
+    public abstract void onSetMinTime(long minTime, WorkSource ws);
+
+    /**
+     * Updates the network state for the given provider. This function must
+     * be overwritten if {@link android.location.LocationProvider#requiresNetwork} returns true.
+     * The state is {@link android.location.LocationProvider#TEMPORARILY_UNAVAILABLE} (disconnected)
+     * OR {@link android.location.LocationProvider#AVAILABLE} (connected or connecting).
+     *
+     * @param state data state
+     */
+    public abstract void onUpdateNetworkState(int state, NetworkInfo info);
+
+    /**
+     * Informs the provider when a new location has been computed by a different
+     * location provider.  This is intended to be used as aiding data for the
+     * receiving provider.
+     *
+     * @param location new location from other location provider
+     */
+    public abstract void onUpdateLocation(Location location);
+
+    /**
+     * Implements addditional location provider specific additional commands.
+     *
+     * @param command name of the command to send to the provider.
+     * @param extras optional arguments for the command (or null).
+     * The provider may optionally fill the extras Bundle with results from the command.
+     *
+     * @return true if the command succeeds.
+     */
+    public abstract boolean onSendExtraCommand(String command, Bundle extras);
+
+    /**
+     * Notifies the location provider when a new client is listening for locations.
+     *
+     * @param uid user ID of the new client.
+     * @param ws a WorkSource representation of the client.
+     */
+    public abstract void onAddListener(int uid, WorkSource ws);
+
+    /**
+     * Notifies the location provider when a client is no longer listening for locations.
+     *
+     * @param uid user ID of the client no longer listening.
+     * @param ws a WorkSource representation of the client.
+     */
+    public abstract void onRemoveListener(int uid, WorkSource ws);
+}
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 8f40130..ebe3302 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -63,7 +63,6 @@
 
 // Flag to allow a one time init of global memory, only happens on first call ever
 int LvmInitFlag = LVM_FALSE;
-int LvmSessionsActive = 0;
 SessionContext GlobalSessionMemory[LVM_MAX_SESSIONS];
 
 int SessionIndex[LVM_MAX_SESSIONS];
@@ -189,16 +188,19 @@
                             int32_t             sessionId,
                             int32_t             ioId,
                             effect_interface_t  *pInterface){
-    int ret;
+    int ret = 0;
     int sessionNo;
     int i;
-    EffectContext *pContext = new EffectContext;
+    EffectContext *pContext = NULL;
+    bool newBundle = false;
+    SessionContext *pSessionContext;
 
     LOGV("\n\tEffectCreate start session %d", sessionId);
 
     if (pInterface == NULL || uuid == NULL){
         LOGV("\tLVM_ERROR : EffectCreate() called with NULL pointer");
-        return -EINVAL;
+        ret = -EINVAL;
+        goto exit;
     }
 
     if(LvmInitFlag == LVM_FALSE){
@@ -207,8 +209,6 @@
         LvmGlobalBundle_init();
     }
 
-    LOGV("\tEffectCreate: There are %d LVM sessions acive\n", LvmSessionsActive);
-
     // Find next available sessionNo
     for(i=0; i<LVM_MAX_SESSIONS; i++){
         if((SessionIndex[i] == LVM_UNUSED_SESSION)||(SessionIndex[i] == sessionId)){
@@ -221,23 +221,20 @@
 
     if(i==LVM_MAX_SESSIONS){
         LOGV("\tLVM_ERROR : Cannot find memory to allocate for current session");
-        return -EINVAL;
+        ret = -EINVAL;
+        goto exit;
     }
+
+    pContext = new EffectContext;
+
     // If this is the first create in this session
     if(GlobalSessionMemory[sessionNo].bBundledEffectsEnabled == LVM_FALSE){
         LOGV("\tEffectCreate - This is the first effect in current sessionId %d sessionNo %d",
                 sessionId, sessionNo);
 
-        LvmSessionsActive++;
-
-        if(LvmSessionsActive >= LVM_MAX_SESSIONS){
-            LOGV("\tLVM_ERROR : Number of active session is greater than LVM_MAX_SESSIONS (%d)",
-                  LVM_MAX_SESSIONS);
-            return -EINVAL;
-        }
-
         GlobalSessionMemory[sessionNo].bBundledEffectsEnabled = LVM_TRUE;
         GlobalSessionMemory[sessionNo].pBundledContext        = new BundledEffectContext;
+        newBundle = true;
 
         pContext->pBundledContext = GlobalSessionMemory[sessionNo].pBundledContext;
         pContext->pBundledContext->SessionNo                = sessionNo;
@@ -251,17 +248,16 @@
         pContext->pBundledContext->bVirtualizerTempDisabled = LVM_FALSE;
         pContext->pBundledContext->NumberEffectsEnabled     = 0;
         pContext->pBundledContext->NumberEffectsCalled      = 0;
-        pContext->pBundledContext->frameCount               = 0;
         pContext->pBundledContext->firstVolume              = LVM_TRUE;
 
         #ifdef LVM_PCM
-
         char fileName[256];
         snprintf(fileName, 256, "/data/tmp/bundle_%p_pcm_in.pcm", pContext->pBundledContext);
         pContext->pBundledContext->PcmInPtr = fopen(fileName, "w");
         if (pContext->pBundledContext->PcmInPtr == NULL) {
             LOGV("cannot open %s", fileName);
-           return -EINVAL;
+            ret = -EINVAL;
+            goto exit;
         }
 
         snprintf(fileName, 256, "/data/tmp/bundle_%p_pcm_out.pcm", pContext->pBundledContext);
@@ -270,7 +266,8 @@
             LOGV("cannot open %s", fileName);
             fclose(pContext->pBundledContext->PcmInPtr);
            pContext->pBundledContext->PcmInPtr = NULL;
-           return -EINVAL;
+           ret = -EINVAL;
+           goto exit;
         }
         #endif
 
@@ -285,15 +282,18 @@
         pContext->pBundledContext->bMuteEnabled             = LVM_FALSE;
         pContext->pBundledContext->bStereoPositionEnabled   = LVM_FALSE;
         pContext->pBundledContext->positionSaved            = 0;
+        pContext->pBundledContext->workBuffer               = NULL;
+        pContext->pBundledContext->frameCount               = -1;
+        pContext->pBundledContext->SamplesToExitCountVirt   = 0;
+        pContext->pBundledContext->SamplesToExitCountBb     = 0;
+        pContext->pBundledContext->SamplesToExitCountEq     = 0;
 
         LOGV("\tEffectCreate - Calling LvmBundle_init");
         ret = LvmBundle_init(pContext);
 
         if (ret < 0){
             LOGV("\tLVM_ERROR : EffectCreate() Bundle init failed");
-            delete pContext->pBundledContext;
-            delete pContext;
-            return ret;
+            goto exit;
         }
     }
     else{
@@ -304,13 +304,14 @@
     }
     LOGV("\tEffectCreate - pBundledContext is %p", pContext->pBundledContext);
 
-    SessionContext *pSessionContext = &GlobalSessionMemory[pContext->pBundledContext->SessionNo];
+    pSessionContext = &GlobalSessionMemory[pContext->pBundledContext->SessionNo];
 
     // Create each Effect
     if (memcmp(uuid, &gBassBoostDescriptor.uuid, sizeof(effect_uuid_t)) == 0){
         // Create Bass Boost
         LOGV("\tEffectCreate - Effect to be created is LVM_BASS_BOOST");
         pSessionContext->bBassInstantiated = LVM_TRUE;
+        pContext->pBundledContext->SamplesToExitCountBb = 0;
 
         pContext->itfe       = &gLvmEffectInterface;
         pContext->EffectType = LVM_BASS_BOOST;
@@ -318,6 +319,7 @@
         // Create Virtualizer
         LOGV("\tEffectCreate - Effect to be created is LVM_VIRTUALIZER");
         pSessionContext->bVirtualizerInstantiated=LVM_TRUE;
+        pContext->pBundledContext->SamplesToExitCountVirt = 0;
 
         pContext->itfe       = &gLvmEffectInterface;
         pContext->EffectType = LVM_VIRTUALIZER;
@@ -325,6 +327,7 @@
         // Create Equalizer
         LOGV("\tEffectCreate - Effect to be created is LVM_EQUALIZER");
         pSessionContext->bEqualizerInstantiated = LVM_TRUE;
+        pContext->pBundledContext->SamplesToExitCountEq = 0;
 
         pContext->itfe       = &gLvmEffectInterface;
         pContext->EffectType = LVM_EQUALIZER;
@@ -338,46 +341,77 @@
     }
     else{
         LOGV("\tLVM_ERROR : EffectCreate() invalid UUID");
-        return -EINVAL;
+        ret = -EINVAL;
+        goto exit;
     }
 
-    *pInterface = (effect_interface_t)pContext;
+exit:
+    if (ret != 0) {
+        if (pContext != NULL) {
+            if (newBundle) {
+                GlobalSessionMemory[sessionNo].bBundledEffectsEnabled = LVM_FALSE;
+                SessionIndex[sessionNo] = LVM_UNUSED_SESSION;
+                delete pContext->pBundledContext;
+            }
+            delete pContext;
+        }
+        *pInterface = (effect_interface_t)NULL;
+    } else {
+        *pInterface = (effect_interface_t)pContext;
+    }
     LOGV("\tEffectCreate end..\n\n");
-    return 0;
+    return ret;
 } /* end EffectCreate */
 
 extern "C" int EffectRelease(effect_interface_t interface){
     LOGV("\n\tEffectRelease start %p", interface);
     EffectContext * pContext = (EffectContext *)interface;
 
-    LOGV("\n\tEffectRelease start interface: %p, context %p", interface, pContext->pBundledContext);
+    LOGV("\tEffectRelease start interface: %p, context %p", interface, pContext->pBundledContext);
     if (pContext == NULL){
         LOGV("\tLVM_ERROR : EffectRelease called with NULL pointer");
         return -EINVAL;
     }
 
-
-    Effect_setEnabled(pContext, LVM_FALSE);
-
     SessionContext *pSessionContext = &GlobalSessionMemory[pContext->pBundledContext->SessionNo];
 
     // Clear the instantiated flag for the effect
+    // protect agains the case where an effect is un-instantiated without being disabled
     if(pContext->EffectType == LVM_BASS_BOOST) {
         LOGV("\tEffectRelease LVM_BASS_BOOST Clearing global intstantiated flag");
         pSessionContext->bBassInstantiated = LVM_FALSE;
+        if(pContext->pBundledContext->SamplesToExitCountBb > 0){
+            pContext->pBundledContext->NumberEffectsEnabled--;
+        }
+        pContext->pBundledContext->SamplesToExitCountBb = 0;
     } else if(pContext->EffectType == LVM_VIRTUALIZER) {
         LOGV("\tEffectRelease LVM_VIRTUALIZER Clearing global intstantiated flag");
         pSessionContext->bVirtualizerInstantiated = LVM_FALSE;
+        if(pContext->pBundledContext->SamplesToExitCountVirt > 0){
+            pContext->pBundledContext->NumberEffectsEnabled--;
+        }
+        pContext->pBundledContext->SamplesToExitCountVirt = 0;
     } else if(pContext->EffectType == LVM_EQUALIZER) {
         LOGV("\tEffectRelease LVM_EQUALIZER Clearing global intstantiated flag");
         pSessionContext->bEqualizerInstantiated =LVM_FALSE;
+        if(pContext->pBundledContext->SamplesToExitCountEq > 0){
+            pContext->pBundledContext->NumberEffectsEnabled--;
+        }
+        pContext->pBundledContext->SamplesToExitCountEq = 0;
     } else if(pContext->EffectType == LVM_VOLUME) {
         LOGV("\tEffectRelease LVM_VOLUME Clearing global intstantiated flag");
         pSessionContext->bVolumeInstantiated = LVM_FALSE;
+        if (pContext->pBundledContext->bVolumeEnabled == LVM_TRUE){
+            pContext->pBundledContext->NumberEffectsEnabled--;
+        }
     } else {
         LOGV("\tLVM_ERROR : EffectRelease : Unsupported effect\n\n\n\n\n\n\n");
     }
 
+    // Disable effect, in this case ignore errors (return codes)
+    // if an effect has already been disabled
+    Effect_setEnabled(pContext, LVM_FALSE);
+
     // if all effects are no longer instantiaed free the lvm memory and delete BundledEffectContext
     if ((pSessionContext->bBassInstantiated == LVM_FALSE) &&
             (pSessionContext->bVolumeInstantiated == LVM_FALSE) &&
@@ -395,8 +429,6 @@
         }
         #endif
 
-        LvmSessionsActive--;
-        LOGV("\tEffectRelease: There are %d LVM sessions remaining\n", LvmSessionsActive);
 
         // Clear the SessionIndex
         for(int i=0; i<LVM_MAX_SESSIONS; i++){
@@ -409,11 +441,14 @@
         }
 
         LOGV("\tEffectRelease: All effects are no longer instantiated\n");
-        pSessionContext->bBundledEffectsEnabled =LVM_FALSE;
+        pSessionContext->bBundledEffectsEnabled = LVM_FALSE;
         pSessionContext->pBundledContext = LVM_NULL;
         LOGV("\tEffectRelease: Freeing LVM Bundle memory\n");
         LvmEffect_free(pContext);
         LOGV("\tEffectRelease: Deleting LVM Bundle context %p\n", pContext->pBundledContext);
+        if (pContext->pBundledContext->workBuffer != NULL) {
+            free(pContext->pBundledContext->workBuffer);
+        }
         delete pContext->pBundledContext;
         pContext->pBundledContext = LVM_NULL;
     }
@@ -643,6 +678,14 @@
     return 0;
 }   /* end LvmBundle_init */
 
+
+static inline int16_t clamp16(int32_t sample)
+{
+    if ((sample>>15) ^ (sample>>31))
+        sample = 0x7FFF ^ (sample>>31);
+    return sample;
+}
+
 //----------------------------------------------------------------------------
 // LvmBundle_process()
 //----------------------------------------------------------------------------
@@ -668,39 +711,25 @@
 
     LVM_ControlParams_t     ActiveParams;                           /* Current control Parameters */
     LVM_ReturnStatus_en     LvmStatus = LVM_SUCCESS;                /* Function call status */
-
     LVM_INT16               *pOutTmp;
+
     if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE){
         pOutTmp = pOut;
     }else if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
-        pOutTmp = (LVM_INT16 *)malloc(frameCount * sizeof(LVM_INT16) * 2);
-        if(pOutTmp == NULL){
-            LOGV("\tLVM_ERROR : LvmBundle_process failed to allocate memory for "
-            "EFFECT_BUFFER_ACCESS_ACCUMULATE mode");
-            return -EINVAL;
+        if (pContext->pBundledContext->frameCount != frameCount) {
+            if (pContext->pBundledContext->workBuffer != NULL) {
+                free(pContext->pBundledContext->workBuffer);
+            }
+            pContext->pBundledContext->workBuffer =
+                    (LVM_INT16 *)malloc(frameCount * sizeof(LVM_INT16) * 2);
+            pContext->pBundledContext->frameCount = frameCount;
         }
+        pOutTmp = pContext->pBundledContext->workBuffer;
     }else{
         LOGV("LVM_ERROR : LvmBundle_process invalid access mode");
         return -EINVAL;
     }
 
-    /* Get the current settings */
-    LvmStatus = LVM_GetControlParameters(pContext->pBundledContext->hInstance,
-                                         &ActiveParams);
-
-    LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "LvmBundle_process")
-    if(LvmStatus != LVM_SUCCESS) return -EINVAL;
-
-    pContext->pBundledContext->frameCount++;
-    if(pContext->pBundledContext->frameCount == 100)
-    {
-        //LOGV("\tBB: %d VIRT: %d EQ: %d, session (%d), context is %p\n",
-        //ActiveParams.BE_OperatingMode,
-        //ActiveParams.VirtualizerOperatingMode, ActiveParams.EQNB_OperatingMode,
-        //pContext->pBundledContext->SessionNo, pContext->pBundledContext);
-        pContext->pBundledContext->frameCount = 0;
-    }
-
     #ifdef LVM_PCM
     fwrite(pIn, frameCount*sizeof(LVM_INT16)*2, 1, pContext->pBundledContext->PcmInPtr);
     fflush(pContext->pBundledContext->PcmInPtr);
@@ -725,9 +754,8 @@
 
     if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
         for (int i=0; i<frameCount*2; i++){
-            pOut[i] +=  pOutTmp[i];
+            pOut[i] = clamp16((LVM_INT32)pOut[i] + (LVM_INT32)pOutTmp[i]);
         }
-        free(pOutTmp);
     }
     return 0;
 }    /* end LvmBundle_process */
@@ -813,15 +841,15 @@
         ActiveParams.BE_OperatingMode       = LVM_BE_OFF;
     }
     if(pContext->EffectType == LVM_VIRTUALIZER) {
-        LOGV("\tLvmEffect_disable : Enabling LVM_VIRTUALIZER");
+        LOGV("\tLvmEffect_disable : Disabling LVM_VIRTUALIZER");
         ActiveParams.VirtualizerOperatingMode   = LVM_MODE_OFF;
     }
     if(pContext->EffectType == LVM_EQUALIZER) {
-        LOGV("\tLvmEffect_disable : Enabling LVM_EQUALIZER");
+        LOGV("\tLvmEffect_disable : Disabling LVM_EQUALIZER");
         ActiveParams.EQNB_OperatingMode     = LVM_EQNB_OFF;
     }
     if(pContext->EffectType == LVM_VOLUME) {
-        LOGV("\tLvmEffect_disable : Enabling LVM_VOLUME");
+        LOGV("\tLvmEffect_disable : Disabling LVM_VOLUME");
     }
 
     LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams);
@@ -2406,85 +2434,114 @@
         switch (pContext->EffectType) {
             case LVM_BASS_BOOST:
                 if (pContext->pBundledContext->bBassEnabled == LVM_TRUE) {
-                     LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_BASS_BOOST is already enabled");
+                     LOGV("\tEffect_setEnabled() LVM_BASS_BOOST is already enabled");
                      return -EINVAL;
                 }
+                if(pContext->pBundledContext->SamplesToExitCountBb <= 0){
+                    pContext->pBundledContext->NumberEffectsEnabled++;
+                }
                 pContext->pBundledContext->SamplesToExitCountBb =
                      (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
                 pContext->pBundledContext->bBassEnabled = LVM_TRUE;
                 break;
             case LVM_EQUALIZER:
                 if (pContext->pBundledContext->bEqualizerEnabled == LVM_TRUE) {
-                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_EQUALIZER is already enabled");
+                    LOGV("\tEffect_setEnabled() LVM_EQUALIZER is already enabled");
                     return -EINVAL;
                 }
+                if(pContext->pBundledContext->SamplesToExitCountEq <= 0){
+                    pContext->pBundledContext->NumberEffectsEnabled++;
+                }
                 pContext->pBundledContext->SamplesToExitCountEq =
                      (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
                 pContext->pBundledContext->bEqualizerEnabled = LVM_TRUE;
                 break;
             case LVM_VIRTUALIZER:
                 if (pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE) {
-                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VIRTUALIZER is already enabled");
+                    LOGV("\tEffect_setEnabled() LVM_VIRTUALIZER is already enabled");
                     return -EINVAL;
                 }
+                if(pContext->pBundledContext->SamplesToExitCountVirt <= 0){
+                    pContext->pBundledContext->NumberEffectsEnabled++;
+                }
                 pContext->pBundledContext->SamplesToExitCountVirt =
                      (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
                 pContext->pBundledContext->bVirtualizerEnabled = LVM_TRUE;
                 break;
             case LVM_VOLUME:
                 if (pContext->pBundledContext->bVolumeEnabled == LVM_TRUE) {
-                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VOLUME is already enabled");
+                    LOGV("\tEffect_setEnabled() LVM_VOLUME is already enabled");
                     return -EINVAL;
                 }
+                pContext->pBundledContext->NumberEffectsEnabled++;
                 pContext->pBundledContext->bVolumeEnabled = LVM_TRUE;
                 break;
             default:
-                LOGV("\tLVM_ERROR : Effect_setEnabled() invalid effect type");
+                LOGV("\tEffect_setEnabled() invalid effect type");
                 return -EINVAL;
         }
-        pContext->pBundledContext->NumberEffectsEnabled++;
         LvmEffect_enable(pContext);
     } else {
         switch (pContext->EffectType) {
             case LVM_BASS_BOOST:
                 if (pContext->pBundledContext->bBassEnabled == LVM_FALSE) {
-                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_BASS_BOOST is already disabled");
+                    LOGV("\tEffect_setEnabled() LVM_BASS_BOOST is already disabled");
                     return -EINVAL;
                 }
                 pContext->pBundledContext->bBassEnabled = LVM_FALSE;
                 break;
             case LVM_EQUALIZER:
                 if (pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE) {
-                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_EQUALIZER is already disabled");
+                    LOGV("\tEffect_setEnabled() LVM_EQUALIZER is already disabled");
                     return -EINVAL;
                 }
                 pContext->pBundledContext->bEqualizerEnabled = LVM_FALSE;
                 break;
             case LVM_VIRTUALIZER:
                 if (pContext->pBundledContext->bVirtualizerEnabled == LVM_FALSE) {
-                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VIRTUALIZER is already disabled");
+                    LOGV("\tEffect_setEnabled() LVM_VIRTUALIZER is already disabled");
                     return -EINVAL;
                 }
                 pContext->pBundledContext->bVirtualizerEnabled = LVM_FALSE;
                 break;
             case LVM_VOLUME:
                 if (pContext->pBundledContext->bVolumeEnabled == LVM_FALSE) {
-                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VOLUME is already disabled");
+                    LOGV("\tEffect_setEnabled() LVM_VOLUME is already disabled");
                     return -EINVAL;
                 }
                 pContext->pBundledContext->bVolumeEnabled = LVM_FALSE;
                 break;
             default:
-                LOGV("\tLVM_ERROR : Effect_setEnabled() invalid effect type");
+                LOGV("\tEffect_setEnabled() invalid effect type");
                 return -EINVAL;
         }
-        pContext->pBundledContext->NumberEffectsEnabled--;
         LvmEffect_disable(pContext);
     }
 
     return 0;
 }
 
+//----------------------------------------------------------------------------
+// LVC_Convert_VolToDb()
+//----------------------------------------------------------------------------
+// Purpose:
+// Convery volume in Q24 to dB
+//
+// Inputs:
+//  vol:   Q.24 volume dB
+//
+//-----------------------------------------------------------------------
+
+int16_t LVC_Convert_VolToDb(uint32_t vol){
+    int16_t  dB;
+
+    dB = LVC_ToDB_s32Tos16(vol <<7);
+    dB = (dB +8)>>4;
+    dB = (dB <-96) ? -96 : dB ;
+
+    return dB;
+}
+
 } // namespace
 } // namespace
 
@@ -2493,32 +2550,31 @@
                               audio_buffer_t         *inBuffer,
                               audio_buffer_t         *outBuffer){
     EffectContext * pContext = (EffectContext *) self;
-    LVM_ControlParams_t     ActiveParams;                           /* Current control Parameters */
     LVM_ReturnStatus_en     LvmStatus = LVM_SUCCESS;                /* Function call status */
     int    status = 0;
-    int    status2Sec = 0;
     int    lvmStatus = 0;
     LVM_INT16   *in  = (LVM_INT16 *)inBuffer->raw;
     LVM_INT16   *out = (LVM_INT16 *)outBuffer->raw;
 
-//LOGV("\tEffect_process Start : Enabled = %d     Called = %d",
-//pContext->pBundledContext->NumberEffectsEnabled,pContext->pBundledContext->NumberEffectsCalled);
-//    LOGV("\tEffect_process Start : Samples left %d %d %d",
+//LOGV("\tEffect_process Start : Enabled = %d     Called = %d (%8d %8d %8d)",
+//pContext->pBundledContext->NumberEffectsEnabled,pContext->pBundledContext->NumberEffectsCalled,
 //    pContext->pBundledContext->SamplesToExitCountBb,
 //    pContext->pBundledContext->SamplesToExitCountVirt,
 //    pContext->pBundledContext->SamplesToExitCountEq);
 
-//    LvmStatus = LVM_GetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams);
-//    LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "VolumeGetStereoPosition")
-//    if(LvmStatus != LVM_SUCCESS) return -EINVAL;
-//    LOGV("\tEffect_process Internal Operating Modes: BB %d   VIRT %d    EQ %d",
-//        ActiveParams.BE_OperatingMode, ActiveParams.VirtualizerOperatingMode,
-//        ActiveParams.EQNB_OperatingMode);
-
     if (pContext == NULL){
         LOGV("\tLVM_ERROR : Effect_process() ERROR pContext == NULL");
         return -EINVAL;
     }
+
+    //if(pContext->EffectType == LVM_BASS_BOOST){
+    //  LOGV("\tEffect_process: Effect type is BASS_BOOST");
+    //}else if(pContext->EffectType == LVM_EQUALIZER){
+    //  LOGV("\tEffect_process: Effect type is LVM_EQUALIZER");
+    //}else if(pContext->EffectType == LVM_VIRTUALIZER){
+    //  LOGV("\tEffect_process: Effect type is LVM_VIRTUALIZER");
+    //}
+
     if (inBuffer == NULL  || inBuffer->raw == NULL  ||
             outBuffer == NULL || outBuffer->raw == NULL ||
             inBuffer->frameCount != outBuffer->frameCount){
@@ -2529,70 +2585,57 @@
         (pContext->EffectType == LVM_BASS_BOOST)){
         //LOGV("\tEffect_process() LVM_BASS_BOOST Effect is not enabled");
         if(pContext->pBundledContext->SamplesToExitCountBb > 0){
-            status2Sec = -ENODATA;
             pContext->pBundledContext->SamplesToExitCountBb -= outBuffer->frameCount * 2; // STEREO
             //LOGV("\tEffect_process: Waiting to turn off BASS_BOOST, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountBb);
         } else {
             status = -ENODATA;
+            pContext->pBundledContext->NumberEffectsEnabled--;
         }
     }
     if ((pContext->pBundledContext->bVolumeEnabled == LVM_FALSE)&&
         (pContext->EffectType == LVM_VOLUME)){
         //LOGV("\tEffect_process() LVM_VOLUME Effect is not enabled");
         status = -ENODATA;
+        pContext->pBundledContext->NumberEffectsEnabled--;
     }
     if ((pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE)&&
         (pContext->EffectType == LVM_EQUALIZER)){
         //LOGV("\tEffect_process() LVM_EQUALIZER Effect is not enabled");
         if(pContext->pBundledContext->SamplesToExitCountEq > 0){
-            status2Sec = -ENODATA;
             pContext->pBundledContext->SamplesToExitCountEq -= outBuffer->frameCount * 2; // STEREO
-            //LOGV("\tEffect_process: Waiting for 2 secs to turn off EQUALIZER, %d samples left",
+            //LOGV("\tEffect_process: Waiting to turn off EQUALIZER, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountEq);
         } else {
             status = -ENODATA;
+            pContext->pBundledContext->NumberEffectsEnabled--;
         }
     }
     if ((pContext->pBundledContext->bVirtualizerEnabled == LVM_FALSE)&&
         (pContext->EffectType == LVM_VIRTUALIZER)){
         //LOGV("\tEffect_process() LVM_VIRTUALIZER Effect is not enabled");
         if(pContext->pBundledContext->SamplesToExitCountVirt > 0){
-            status2Sec = -ENODATA;
             pContext->pBundledContext->SamplesToExitCountVirt -= outBuffer->frameCount * 2;// STEREO
-            //LOGV("\tEffect_process: Waiting for 2 secs to turn off VIRTUALIZER, %d samples left",
+            //LOGV("\tEffect_process: Waiting for to turn off VIRTUALIZER, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountVirt);
         } else {
             status = -ENODATA;
+            pContext->pBundledContext->NumberEffectsEnabled--;
         }
     }
 
-    // If this is the last frame of an effect process its output with no effect
-    if(status == -ENODATA){
-        if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
-            //LOGV("\tLVM_ERROR : Effect_process() accumulating last frame into output buffer");
-            //LOGV("\tLVM_ERROR : Effect_process() trying copying last frame into output buffer");
-            //LOGV("\tLVM_ERROR : Enabled = %d     Called = %d",
-            //pContext->pBundledContext->NumberEffectsEnabled,
-            //pContext->pBundledContext->NumberEffectsCalled);
-
-        }else{
-            //LOGV("\tLVM_ERROR : Effect_process() copying last frame into output buffer");
-        }
-    }
-
-    if((status2Sec != -ENODATA)&&(status != -ENODATA)){
+    if(status != -ENODATA){
         pContext->pBundledContext->NumberEffectsCalled++;
     }
 
     if(pContext->pBundledContext->NumberEffectsCalled ==
        pContext->pBundledContext->NumberEffectsEnabled){
-        //LOGV("\tEffect_process Calling process with %d effects enabled, %d called: Effect %d",
+        //LOGV("\tEffect_process     Calling process with %d effects enabled, %d called: Effect %d",
         //pContext->pBundledContext->NumberEffectsEnabled,
         //pContext->pBundledContext->NumberEffectsCalled, pContext->EffectType);
 
         if(status == -ENODATA){
-            //LOGV("\tLVM_ERROR : Effect_process() actually processing last frame");
+            LOGV("\tEffect_process() processing last frame");
         }
         pContext->pBundledContext->NumberEffectsCalled = 0;
         /* Process all the available frames, block processing is
@@ -2836,10 +2879,10 @@
         case EFFECT_CMD_SET_PARAM:{
             //LOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_PARAM start");
             if(pContext->EffectType == LVM_BASS_BOOST){
-                //LOGV("\tBassBoost_command EFFECT_CMD_SET_PARAM param %d, *replySize %d, value %d ",
-                //        *(int32_t *)((char *)pCmdData + sizeof(effect_param_t)),
-                //        *replySize,
-                //        *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t)));
+                //LOGV("\tBassBoost_command EFFECT_CMD_SET_PARAM param %d, *replySize %d, value %d",
+                //       *(int32_t *)((char *)pCmdData + sizeof(effect_param_t)),
+                //       *replySize,
+                //       *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t)));
 
                 if (pCmdData   == NULL||
                     cmdSize    != (int)(sizeof(effect_param_t) + sizeof(int32_t) +sizeof(int16_t))||
@@ -3038,30 +3081,71 @@
         }
         case EFFECT_CMD_SET_VOLUME:
         {
-            int32_t vol     = *(int32_t *)pCmdData;
-            int16_t dB;
-            int32_t vol_ret[2] = {1<<24,1<<24}; // Apply no volume
+            uint32_t leftVolume, rightVolume;
+            int16_t  leftdB, rightdB;
+            int16_t  maxdB, pandB;
+            int32_t  vol_ret[2] = {1<<24,1<<24}; // Apply no volume
+            int      status = 0;
+            LVM_ControlParams_t     ActiveParams;           /* Current control Parameters */
+            LVM_ReturnStatus_en     LvmStatus=LVM_SUCCESS;  /* Function call status */
 
             // if pReplyData is NULL, VOL_CTRL is delegated to another effect
             if(pReplyData == LVM_NULL){
                 break;
             }
 
-            if(vol==0x1000000){
-                vol -= 1;
+            if (pCmdData == NULL ||
+                cmdSize != 2 * sizeof(uint32_t)) {
+                LOGV("\tLVM_ERROR : Effect_command cmdCode Case: "
+                        "EFFECT_CMD_SET_VOLUME: ERROR");
+                return -EINVAL;
             }
-            // Convert volume linear (Q8.24) to volume dB (0->-96)
-            dB = android::LVC_ToDB_s32Tos16(vol <<7);
-            dB = (dB +8)>>4;
-            dB = (dB <-96) ? -96 : dB ;
 
-            LOGV("\tEFFECT_CMD_SET_VOLUME Session: %d, SessionID: %d VOLUME is %d dB (%d), "
-                  "effect is %d",
-            pContext->pBundledContext->SessionNo, pContext->pBundledContext->SessionId,
-            (int32_t)dB, vol<<7, pContext->EffectType);
+            leftVolume  = ((*(uint32_t *)pCmdData));
+            rightVolume = ((*((uint32_t *)pCmdData + 1)));
+
+            if(leftVolume == 0x1000000){
+                leftVolume -= 1;
+            }
+            if(rightVolume == 0x1000000){
+                rightVolume -= 1;
+            }
+
+            // Convert volume to dB
+            leftdB  = android::LVC_Convert_VolToDb(leftVolume);
+            rightdB = android::LVC_Convert_VolToDb(rightVolume);
+
+            pandB = rightdB - leftdB;
+
+            // Calculate max volume in dB
+            maxdB = leftdB;
+            if(rightdB > maxdB){
+                maxdB = rightdB;
+            }
+            //LOGV("\tEFFECT_CMD_SET_VOLUME Session: %d, SessionID: %d VOLUME is %d dB (%d), "
+            //      "effect is %d",
+            //pContext->pBundledContext->SessionNo, pContext->pBundledContext->SessionId,
+            //(int32_t)maxdB, maxVol<<7, pContext->EffectType);
+            //LOGV("\tEFFECT_CMD_SET_VOLUME: Left is %d, Right is %d", leftVolume, rightVolume);
+            //LOGV("\tEFFECT_CMD_SET_VOLUME: Left %ddB, Right %ddB, Position %ddB",
+            //        leftdB, rightdB, pandB);
 
             memcpy(pReplyData, vol_ret, sizeof(int32_t)*2);
-            android::VolumeSetVolumeLevel(pContext, (int16_t)(dB*100));
+            android::VolumeSetVolumeLevel(pContext, (int16_t)(maxdB*100));
+
+            /* Get the current settings */
+            LvmStatus =LVM_GetControlParameters(pContext->pBundledContext->hInstance,&ActiveParams);
+            LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "VolumeSetStereoPosition")
+            if(LvmStatus != LVM_SUCCESS) return -EINVAL;
+
+            /* Volume parameters */
+            ActiveParams.VC_Balance  = pandB;
+            LOGV("\t\tVolumeSetStereoPosition() (-96dB -> +96dB)-> %d\n", ActiveParams.VC_Balance );
+
+            /* Activate the initial settings */
+            LvmStatus =LVM_SetControlParameters(pContext->pBundledContext->hInstance,&ActiveParams);
+            LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "VolumeSetStereoPosition")
+            if(LvmStatus != LVM_SUCCESS) return -EINVAL;
             break;
          }
         case EFFECT_CMD_SET_AUDIO_MODE:
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
index 91963af..2b51029 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
@@ -88,12 +88,13 @@
     int                             positionSaved;
     bool                            bMuteEnabled;   /* Must store as mute = -96dB level */
     bool                            bStereoPositionEnabled;
-    int                             frameCount;
     LVM_Fs_en                       SampleRate;
     int                             SamplesPerSecond;
     int                             SamplesToExitCountEq;
     int                             SamplesToExitCountBb;
     int                             SamplesToExitCountVirt;
+    LVM_INT16                       *workBuffer;
+    int                             frameCount;
     #ifdef LVM_PCM
     FILE                            *PcmInPtr;
     FILE                            *PcmOutPtr;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 8a732ed..97b8086 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -5332,6 +5332,15 @@
         }
     }
 
+    // Release effect engine here so that it is done immediately. Otherwise it will be released
+    // by the destructor when the last strong reference on the this object is released which can
+    // happen after next process is called on this effect.
+    if (size == 0 && mEffectInterface != NULL) {
+        // release effect engine
+        EffectRelease(mEffectInterface);
+        mEffectInterface = NULL;
+    }
+
     return size;
 }
 
@@ -6145,21 +6154,36 @@
 // Must be called with EffectChain::mLock locked
 void AudioFlinger::EffectChain::process_l()
 {
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread == 0) {
+        LOGW("process_l(): cannot promote mixer thread");
+        return;
+    }
+    PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+    bool isGlobalSession = (mSessionId == AudioSystem::SESSION_OUTPUT_MIX) ||
+            (mSessionId == AudioSystem::SESSION_OUTPUT_STAGE);
+    bool tracksOnSession = false;
+    if (!isGlobalSession) {
+        tracksOnSession =
+                playbackThread->hasAudioSession(mSessionId) & PlaybackThread::TRACK_SESSION;
+    }
+
     size_t size = mEffects.size();
-    for (size_t i = 0; i < size; i++) {
-        mEffects[i]->process();
+    // do not process effect if no track is present in same audio session
+    if (isGlobalSession || tracksOnSession) {
+        for (size_t i = 0; i < size; i++) {
+            mEffects[i]->process();
+        }
     }
     for (size_t i = 0; i < size; i++) {
         mEffects[i]->updateState();
     }
     // if no track is active, input buffer must be cleared here as the mixer process
     // will not do it
-    if (mSessionId > 0 && activeTracks() == 0) {
-        sp<ThreadBase> thread = mThread.promote();
-        if (thread != 0) {
-            size_t numSamples = thread->frameCount() * thread->channelCount();
-            memset(mInBuffer, 0, numSamples * sizeof(int16_t));
-        }
+    if (tracksOnSession &&
+        activeTracks() == 0) {
+        size_t numSamples = playbackThread->frameCount() * playbackThread->channelCount();
+        memset(mInBuffer, 0, numSamples * sizeof(int16_t));
     }
 }