resolved conflicts for merge of dd206093 to master

Change-Id: I21dd2321a4839d034d49092baccbf40986f17dae
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 194f23a..9fd905f 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -168,6 +168,15 @@
         TX_DISABLE    = 0
     };
 
+    // special audio session values
+    enum audio_sessions {
+        SESSION_OUTPUT_STAGE = -1, // session for effects attached to a particular output stream
+                                   // (value must be less than 0)
+        SESSION_OUTPUT_MIX = 0,    // session for effects applied to output mix. These effects can
+                                   // be moved by audio policy manager to another output stream
+                                   // (value must be 0)
+    };
+
     /* These are static methods to control the system-wide AudioFlinger
      * only privileged processes can have access to them
      */
@@ -353,8 +362,12 @@
                                         uint32_t format = FORMAT_DEFAULT,
                                         uint32_t channels = CHANNEL_OUT_STEREO,
                                         output_flags flags = OUTPUT_FLAG_INDIRECT);
-    static status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
-    static status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+    static status_t startOutput(audio_io_handle_t output,
+                                AudioSystem::stream_type stream,
+                                int session = 0);
+    static status_t stopOutput(audio_io_handle_t output,
+                               AudioSystem::stream_type stream,
+                               int session = 0);
     static void releaseOutput(audio_io_handle_t output);
     static audio_io_handle_t getInput(int inputSource,
                                     uint32_t samplingRate = 0,
@@ -370,6 +383,16 @@
     static status_t setStreamVolumeIndex(stream_type stream, int index);
     static status_t getStreamVolumeIndex(stream_type stream, int *index);
 
+    static uint32_t getStrategyForStream(stream_type stream);
+
+    static audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc);
+    static status_t registerEffect(effect_descriptor_t *desc,
+                                    audio_io_handle_t output,
+                                    uint32_t strategy,
+                                    int session,
+                                    int id);
+    static status_t unregisterEffect(int id);
+
     static const sp<IAudioPolicyService>& get_audio_policy_service();
 
     // ----------------------------------------------------------------------------
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 5814fd6..70e505e 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -161,6 +161,8 @@
                                     status_t *status,
                                     int *id,
                                     int *enabled) = 0;
+
+    virtual status_t moveEffects(int session, int srcOutput, int dstOutput) = 0;
 };
 
 
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 4804bbd..49eee59 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -53,8 +53,12 @@
                                         uint32_t format = AudioSystem::FORMAT_DEFAULT,
                                         uint32_t channels = 0,
                                         AudioSystem::output_flags flags = AudioSystem::OUTPUT_FLAG_INDIRECT) = 0;
-    virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) = 0;
-    virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) = 0;
+    virtual status_t startOutput(audio_io_handle_t output,
+                                 AudioSystem::stream_type stream,
+                                 int session = 0) = 0;
+    virtual status_t stopOutput(audio_io_handle_t output,
+                                AudioSystem::stream_type stream,
+                                int session = 0) = 0;
     virtual void releaseOutput(audio_io_handle_t output) = 0;
     virtual audio_io_handle_t getInput(int inputSource,
                                     uint32_t samplingRate = 0,
@@ -69,6 +73,14 @@
                                       int indexMax) = 0;
     virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index) = 0;
     virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index) = 0;
+    virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream) = 0;
+    virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc) = 0;
+    virtual status_t registerEffect(effect_descriptor_t *desc,
+                                    audio_io_handle_t output,
+                                    uint32_t strategy,
+                                    int session,
+                                    int id) = 0;
+    virtual status_t unregisterEffect(int id) = 0;
 };
 
 
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index edd6184..0be280c 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -31,7 +31,7 @@
 static list_elem_t *gCurEffect; // current effect in enumeration process
 static uint32_t gCurEffectIdx;       // current effect index in enumeration process
 
-static const char * const gEffectLibPath = "/system/lib/soundfx"; // path to built-in effect libraries
+const char * const gEffectLibPath = "/system/lib/soundfx"; // path to built-in effect libraries
 static int gInitDone; // true is global initialization has been preformed
 static int gNextLibId; // used by loadLibrary() to allocate unique library handles
 static int gCanQueryEffect; // indicates that call to EffectQueryEffect() is valid, i.e. that the list of effects
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 3bbcf55..9e39e79 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -18,7 +18,7 @@
 #define LOG_TAG "Bundle"
 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
 #define LVM_BUNDLE                // Include all the bundle code
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <cutils/log.h>
 #include <assert.h>
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 372a927..9c2a8ba 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -590,18 +590,22 @@
     return output;
 }
 
-status_t AudioSystem::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+status_t AudioSystem::startOutput(audio_io_handle_t output,
+                                  AudioSystem::stream_type stream,
+                                  int session)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
-    return aps->startOutput(output, stream);
+    return aps->startOutput(output, stream, session);
 }
 
-status_t AudioSystem::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+status_t AudioSystem::stopOutput(audio_io_handle_t output,
+                                 AudioSystem::stream_type stream,
+                                 int session)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
-    return aps->stopOutput(output, stream);
+    return aps->stopOutput(output, stream, session);
 }
 
 void AudioSystem::releaseOutput(audio_io_handle_t output)
@@ -666,6 +670,38 @@
     return aps->getStreamVolumeIndex(stream, index);
 }
 
+uint32_t AudioSystem::getStrategyForStream(AudioSystem::stream_type stream)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return 0;
+    return aps->getStrategyForStream(stream);
+}
+
+audio_io_handle_t AudioSystem::getOutputForEffect(effect_descriptor_t *desc)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->getOutputForEffect(desc);
+}
+
+status_t AudioSystem::registerEffect(effect_descriptor_t *desc,
+                                audio_io_handle_t output,
+                                uint32_t strategy,
+                                int session,
+                                int id)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->registerEffect(desc, output, strategy, session, id);
+}
+
+status_t AudioSystem::unregisterEffect(int id)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->unregisterEffect(id);
+}
+
 // ---------------------------------------------------------------------------
 
 void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who) {
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 7d6a5d3..3a89e25 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -69,7 +69,8 @@
     QUERY_NUM_EFFECTS,
     QUERY_EFFECT,
     GET_EFFECT_DESCRIPTOR,
-    CREATE_EFFECT
+    CREATE_EFFECT,
+    MOVE_EFFECTS
 };
 
 class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -676,6 +677,17 @@
 
         return effect;
     }
+
+    virtual status_t moveEffects(int session, int srcOutput, int dstOutput)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(session);
+        data.writeInt32(srcOutput);
+        data.writeInt32(dstOutput);
+        remote()->transact(MOVE_EFFECTS, data, &reply);
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -1024,6 +1036,14 @@
             reply->write(&desc, sizeof(effect_descriptor_t));
             return NO_ERROR;
         } break;
+        case MOVE_EFFECTS: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int session = data.readInt32();
+            int srcOutput = data.readInt32();
+            int dstOutput = data.readInt32();
+            reply->writeInt32(moveEffects(session, srcOutput, dstOutput));
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 18dd173..950c213 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -44,7 +44,11 @@
     RELEASE_INPUT,
     INIT_STREAM_VOLUME,
     SET_STREAM_VOLUME,
-    GET_STREAM_VOLUME
+    GET_STREAM_VOLUME,
+    GET_STRATEGY_FOR_STREAM,
+    GET_OUTPUT_FOR_EFFECT,
+    REGISTER_EFFECT,
+    UNREGISTER_EFFECT
 };
 
 class BpAudioPolicyService : public BpInterface<IAudioPolicyService>
@@ -137,22 +141,28 @@
         return static_cast <audio_io_handle_t> (reply.readInt32());
     }
 
-    virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+    virtual status_t startOutput(audio_io_handle_t output,
+                                 AudioSystem::stream_type stream,
+                                 int session)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
         data.writeInt32(output);
         data.writeInt32(stream);
+        data.writeInt32(session);
         remote()->transact(START_OUTPUT, data, &reply);
         return static_cast <status_t> (reply.readInt32());
     }
 
-    virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+    virtual status_t stopOutput(audio_io_handle_t output,
+                                AudioSystem::stream_type stream,
+                                int session)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
         data.writeInt32(output);
         data.writeInt32(stream);
+        data.writeInt32(session);
         remote()->transact(STOP_OUTPUT, data, &reply);
         return static_cast <status_t> (reply.readInt32());
     }
@@ -242,6 +252,51 @@
         if (index) *index = lIndex;
         return static_cast <status_t> (reply.readInt32());
     }
+
+    virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(static_cast <uint32_t>(stream));
+        remote()->transact(GET_STRATEGY_FOR_STREAM, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(desc, sizeof(effect_descriptor_t));
+        remote()->transact(GET_OUTPUT_FOR_EFFECT, data, &reply);
+        return static_cast <audio_io_handle_t> (reply.readInt32());
+    }
+
+    virtual status_t registerEffect(effect_descriptor_t *desc,
+                                        audio_io_handle_t output,
+                                        uint32_t strategy,
+                                        int session,
+                                        int id)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(desc, sizeof(effect_descriptor_t));
+        data.writeInt32(output);
+        data.writeInt32(strategy);
+        data.writeInt32(session);
+        data.writeInt32(id);
+        remote()->transact(REGISTER_EFFECT, data, &reply);
+        return static_cast <status_t> (reply.readInt32());
+    }
+
+    virtual status_t unregisterEffect(int id)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(id);
+        remote()->transact(UNREGISTER_EFFECT, data, &reply);
+        return static_cast <status_t> (reply.readInt32());
+    }
+
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -255,18 +310,24 @@
     switch(code) {
         case SET_DEVICE_CONNECTION_STATE: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            AudioSystem::audio_devices device = static_cast <AudioSystem::audio_devices>(data.readInt32());
-            AudioSystem::device_connection_state state = static_cast <AudioSystem::device_connection_state>(data.readInt32());
+            AudioSystem::audio_devices device =
+                    static_cast <AudioSystem::audio_devices>(data.readInt32());
+            AudioSystem::device_connection_state state =
+                    static_cast <AudioSystem::device_connection_state>(data.readInt32());
             const char *device_address = data.readCString();
-            reply->writeInt32(static_cast <uint32_t>(setDeviceConnectionState(device, state, device_address)));
+            reply->writeInt32(static_cast<uint32_t> (setDeviceConnectionState(device,
+                                                                              state,
+                                                                              device_address)));
             return NO_ERROR;
         } break;
 
         case GET_DEVICE_CONNECTION_STATE: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            AudioSystem::audio_devices device = static_cast <AudioSystem::audio_devices>(data.readInt32());
+            AudioSystem::audio_devices device =
+                    static_cast<AudioSystem::audio_devices> (data.readInt32());
             const char *device_address = data.readCString();
-            reply->writeInt32(static_cast <uint32_t>(getDeviceConnectionState(device, device_address)));
+            reply->writeInt32(static_cast<uint32_t> (getDeviceConnectionState(device,
+                                                                              device_address)));
             return NO_ERROR;
         } break;
 
@@ -287,7 +348,8 @@
         case SET_FORCE_USE: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             AudioSystem::force_use usage = static_cast <AudioSystem::force_use>(data.readInt32());
-            AudioSystem::forced_config config = static_cast <AudioSystem::forced_config>(data.readInt32());
+            AudioSystem::forced_config config =
+                    static_cast <AudioSystem::forced_config>(data.readInt32());
             reply->writeInt32(static_cast <uint32_t>(setForceUse(usage, config)));
             return NO_ERROR;
         } break;
@@ -301,11 +363,13 @@
 
         case GET_OUTPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
+            AudioSystem::stream_type stream =
+                    static_cast <AudioSystem::stream_type>(data.readInt32());
             uint32_t samplingRate = data.readInt32();
             uint32_t format = data.readInt32();
             uint32_t channels = data.readInt32();
-            AudioSystem::output_flags flags = static_cast <AudioSystem::output_flags>(data.readInt32());
+            AudioSystem::output_flags flags =
+                    static_cast <AudioSystem::output_flags>(data.readInt32());
 
             audio_io_handle_t output = getOutput(stream,
                                                  samplingRate,
@@ -320,7 +384,10 @@
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
             uint32_t stream = data.readInt32();
-            reply->writeInt32(static_cast <uint32_t>(startOutput(output, (AudioSystem::stream_type)stream)));
+            int session = data.readInt32();
+            reply->writeInt32(static_cast <uint32_t>(startOutput(output,
+                                                                 (AudioSystem::stream_type)stream,
+                                                                 session)));
             return NO_ERROR;
         } break;
 
@@ -328,7 +395,10 @@
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
             uint32_t stream = data.readInt32();
-            reply->writeInt32(static_cast <uint32_t>(stopOutput(output, (AudioSystem::stream_type)stream)));
+            int session = data.readInt32();
+            reply->writeInt32(static_cast <uint32_t>(stopOutput(output,
+                                                                (AudioSystem::stream_type)stream,
+                                                                session)));
             return NO_ERROR;
         } break;
 
@@ -345,7 +415,8 @@
             uint32_t samplingRate = data.readInt32();
             uint32_t format = data.readInt32();
             uint32_t channels = data.readInt32();
-            AudioSystem::audio_in_acoustics acoustics = static_cast <AudioSystem::audio_in_acoustics>(data.readInt32());
+            AudioSystem::audio_in_acoustics acoustics =
+                    static_cast <AudioSystem::audio_in_acoustics>(data.readInt32());
             audio_io_handle_t input = getInput(inputSource,
                                                samplingRate,
                                                format,
@@ -378,7 +449,8 @@
 
         case INIT_STREAM_VOLUME: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
+            AudioSystem::stream_type stream =
+                    static_cast <AudioSystem::stream_type>(data.readInt32());
             int indexMin = data.readInt32();
             int indexMax = data.readInt32();
             reply->writeInt32(static_cast <uint32_t>(initStreamVolume(stream, indexMin,indexMax)));
@@ -387,7 +459,8 @@
 
         case SET_STREAM_VOLUME: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
+            AudioSystem::stream_type stream =
+                    static_cast <AudioSystem::stream_type>(data.readInt32());
             int index = data.readInt32();
             reply->writeInt32(static_cast <uint32_t>(setStreamVolumeIndex(stream, index)));
             return NO_ERROR;
@@ -395,7 +468,8 @@
 
         case GET_STREAM_VOLUME: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
+            AudioSystem::stream_type stream =
+                    static_cast <AudioSystem::stream_type>(data.readInt32());
             int index;
             status_t status = getStreamVolumeIndex(stream, &index);
             reply->writeInt32(index);
@@ -403,6 +477,46 @@
             return NO_ERROR;
         } break;
 
+        case GET_STRATEGY_FOR_STREAM: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            AudioSystem::stream_type stream =
+                    static_cast <AudioSystem::stream_type>(data.readInt32());
+            reply->writeInt32(getStrategyForStream(stream));
+            return NO_ERROR;
+        } break;
+
+        case GET_OUTPUT_FOR_EFFECT: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            effect_descriptor_t desc;
+            data.read(&desc, sizeof(effect_descriptor_t));
+            audio_io_handle_t output = getOutputForEffect(&desc);
+            reply->writeInt32(static_cast <int>(output));
+            return NO_ERROR;
+        } break;
+
+        case REGISTER_EFFECT: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            effect_descriptor_t desc;
+            data.read(&desc, sizeof(effect_descriptor_t));
+            audio_io_handle_t output = data.readInt32();
+            uint32_t strategy = data.readInt32();
+            int session = data.readInt32();
+            int id = data.readInt32();
+            reply->writeInt32(static_cast <int32_t>(registerEffect(&desc,
+                                                                   output,
+                                                                   strategy,
+                                                                   session,
+                                                                   id)));
+            return NO_ERROR;
+        } break;
+
+        case UNREGISTER_EFFECT: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            int id = data.readInt32();
+            reply->writeInt32(static_cast <int32_t>(unregisterEffect(id)));
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index b38a5c8..b88e69d 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -63,6 +63,8 @@
 
 // ----------------------------------------------------------------------------
 
+extern const char * const gEffectLibPath;
+
 namespace android {
 
 static const char* kDeadlockedString = "AudioFlinger may be deadlocked\n";
@@ -127,8 +129,7 @@
 
 AudioFlinger::AudioFlinger()
     : BnAudioFlinger(),
-        mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),
-        mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0)
+        mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1)
 {
     mHardwareStatus = AUDIO_HW_IDLE;
 
@@ -321,13 +322,19 @@
             mClients.add(pid, client);
         }
 
-        // If no audio session id is provided, create one here
-        // TODO: enforce same stream type for all tracks in same audio session?
-        // TODO: prevent same audio session on different output threads
         LOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId);
-        if (sessionId != NULL && *sessionId != 0) {
+        if (sessionId != NULL && *sessionId != AudioSystem::SESSION_OUTPUT_MIX) {
+            // prevent same audio session on different output threads
+            for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+                if (mPlaybackThreads.keyAt(i) != output &&
+                        mPlaybackThreads.valueAt(i)->hasAudioSession(*sessionId)) {
+                    lStatus = BAD_VALUE;
+                    goto Exit;
+                }
+            }
             lSessionId = *sessionId;
         } else {
+            // if no audio session id is provided, create one here
             lSessionId = nextUniqueId();
             if (sessionId != NULL) {
                 *sessionId = lSessionId;
@@ -1141,6 +1148,23 @@
 
     { // scope for mLock
         Mutex::Autolock _l(mLock);
+
+        // all tracks in same audio session must share the same routing strategy otherwise
+        // conflicts will happen when tracks are moved from one output to another by audio policy
+        // manager
+        uint32_t strategy =
+                AudioSystem::getStrategyForStream((AudioSystem::stream_type)streamType);
+        for (size_t i = 0; i < mTracks.size(); ++i) {
+            sp<Track> t = mTracks[i];
+            if (t != 0) {
+                if (sessionId == t->sessionId() &&
+                        strategy != AudioSystem::getStrategyForStream((AudioSystem::stream_type)t->type())) {
+                    lStatus = BAD_VALUE;
+                    goto Exit;
+                }
+            }
+        }
+
         track = new Track(this, client, streamType, sampleRate, format,
                 channelCount, frameCount, sharedBuffer, sessionId);
         if (track->getCblk() == NULL || track->name() < 0) {
@@ -1153,6 +1177,7 @@
         if (chain != 0) {
             LOGV("createTrack_l() setting main buffer %p", chain->inBuffer());
             track->setMainBuffer(chain->inBuffer());
+            chain->setStrategy(AudioSystem::getStrategyForStream((AudioSystem::stream_type)track->type()));
         }
     }
     lStatus = NO_ERROR;
@@ -1344,7 +1369,16 @@
     mMixBuffer = new int16_t[mFrameCount * 2];
     memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
 
-    //TODO handle effects reconfig
+    // force reconfiguration of effect chains and engines to take new buffer size and audio
+    // parameters into account
+    // Note that mLock is not held when readOutputParameters() is called from the constructor
+    // but in this case nothing is done below as no audio sessions have effect yet so it doesn't
+    // matter.
+    // create a copy of mEffectChains as calling moveEffectChain_l() can reorder some effect chains
+    Vector< sp<EffectChain> > effectChains = mEffectChains;
+    for (size_t i = 0; i < effectChains.size(); i ++) {
+        mAudioFlinger->moveEffectChain_l(effectChains[i]->sessionId(), this, this);
+    }
 }
 
 status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames)
@@ -1369,7 +1403,8 @@
 
     for (size_t i = 0; i < mTracks.size(); ++i) {
         sp<Track> track = mTracks[i];
-        if (sessionId == track->sessionId()) {
+        if (sessionId == track->sessionId() &&
+                !(track->mCblk->flags & CBLK_INVALID_MSK)) {
             return true;
         }
     }
@@ -1377,6 +1412,23 @@
     return false;
 }
 
+uint32_t AudioFlinger::PlaybackThread::getStrategyForSession_l(int sessionId)
+{
+    // session AudioSystem::SESSION_OUTPUT_MIX is placed in same strategy as MUSIC stream so that
+    // it is moved to correct output by audio policy manager when A2DP is connected or disconnected
+    if (sessionId == AudioSystem::SESSION_OUTPUT_MIX) {
+        return AudioSystem::getStrategyForStream(AudioSystem::MUSIC);
+    }
+    for (size_t i = 0; i < mTracks.size(); i++) {
+        sp<Track> track = mTracks[i];
+        if (sessionId == track->sessionId() &&
+                !(track->mCblk->flags & CBLK_INVALID_MSK)) {
+            return AudioSystem::getStrategyForStream((AudioSystem::stream_type) track->type());
+        }
+    }
+    return AudioSystem::getStrategyForStream(AudioSystem::MUSIC);
+}
+
 sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain(int sessionId)
 {
     Mutex::Autolock _l(mLock);
@@ -1503,8 +1555,7 @@
             // prevent any changes in effect chain list and in each effect chain
             // during mixing and effect process as the audio buffers could be deleted
             // or modified if an effect is created or deleted
-            lockEffectChains_l();
-            effectChains = mEffectChains;
+            lockEffectChains_l(effectChains);
        }
 
         if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
@@ -1540,7 +1591,7 @@
                  effectChains[i]->process_l();
              }
              // enable changes in effect chain
-             unlockEffectChains();
+             unlockEffectChains(effectChains);
 #ifdef LVMX
             int audioOutputType = LifeVibes::getMixerType(mId, mType);
             if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) {
@@ -1571,7 +1622,7 @@
             mStandby = false;
         } else {
             // enable changes in effect chain
-            unlockEffectChains();
+            unlockEffectChains(effectChains);
             usleep(sleepTime);
         }
 
@@ -1625,7 +1676,7 @@
     }
 #endif
     // Delegate master volume control to effect in output mix effect chain if needed
-    sp<EffectChain> chain = getEffectChain_l(0);
+    sp<EffectChain> chain = getEffectChain_l(AudioSystem::SESSION_OUTPUT_MIX);
     if (chain != 0) {
         uint32_t v = (uint32_t)(masterVolume * (1 << 24));
         chain->setVolume_l(&v, &v);
@@ -1814,8 +1865,10 @@
 
 void AudioFlinger::MixerThread::invalidateTracks(int streamType)
 {
-    LOGV ("MixerThread::invalidateTracks() mixer %p, streamType %d, mTracks.size %d", this,  streamType, mTracks.size());
+    LOGV ("MixerThread::invalidateTracks() mixer %p, streamType %d, mTracks.size %d",
+            this,  streamType, mTracks.size());
     Mutex::Autolock _l(mLock);
+
     size_t size = mTracks.size();
     for (size_t i = 0; i < size; i++) {
         sp<Track> t = mTracks[i];
@@ -2070,7 +2123,6 @@
     // hardware resources as soon as possible
     nsecs_t standbyDelay = microseconds(activeSleepTime*2);
 
-
     while (!exitPending())
     {
         bool rampVolume;
@@ -2246,7 +2298,8 @@
             if (UNLIKELY(trackToRemove != 0)) {
                 mActiveTracks.remove(trackToRemove);
                 if (!effectChains.isEmpty()) {
-                    LOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(), trackToRemove->sessionId());
+                    LOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(),
+                            trackToRemove->sessionId());
                     effectChains[0]->stopTrack();
                 }
                 if (trackToRemove->isTerminated()) {
@@ -2255,7 +2308,7 @@
                 }
             }
 
-            lockEffectChains_l();
+            lockEffectChains_l(effectChains);
        }
 
         if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
@@ -2301,7 +2354,7 @@
             for (size_t i = 0; i < effectChains.size(); i ++) {
                 effectChains[i]->process_l();
             }
-            unlockEffectChains();
+            unlockEffectChains(effectChains);
 
             mLastWriteTime = systemTime();
             mInWrite = true;
@@ -2312,7 +2365,7 @@
             mInWrite = false;
             mStandby = false;
         } else {
-            unlockEffectChains();
+            unlockEffectChains(effectChains);
             usleep(sleepTime);
         }
 
@@ -2505,8 +2558,7 @@
             // prevent any changes in effect chain list and in each effect chain
             // during mixing and effect process as the audio buffers could be deleted
             // or modified if an effect is created or deleted
-            lockEffectChains_l();
-            effectChains = mEffectChains;
+            lockEffectChains_l(effectChains);
         }
 
         if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
@@ -2547,7 +2599,7 @@
                 effectChains[i]->process_l();
             }
             // enable changes in effect chain
-            unlockEffectChains();
+            unlockEffectChains(effectChains);
 
             standbyTime = systemTime() + kStandbyTimeInNsecs;
             for (size_t i = 0; i < outputTracks.size(); i++) {
@@ -2557,7 +2609,7 @@
             mBytesWritten += mixBufferSize;
         } else {
             // enable changes in effect chain
-            unlockEffectChains();
+            unlockEffectChains(effectChains);
             usleep(sleepTime);
         }
 
@@ -2859,7 +2911,9 @@
         if (thread != 0) {
             if (!isOutputTrack()) {
                 if (mState == ACTIVE || mState == RESUMING) {
-                    AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType);
+                    AudioSystem::stopOutput(thread->id(),
+                                            (AudioSystem::stream_type)mStreamType,
+                                            mSessionId);
                 }
                 AudioSystem::releaseOutput(thread->id());
             }
@@ -2966,7 +3020,9 @@
 
         if (!isOutputTrack() && state != ACTIVE && state != RESUMING) {
             thread->mLock.unlock();
-            status = AudioSystem::startOutput(thread->id(), (AudioSystem::stream_type)mStreamType);
+            status = AudioSystem::startOutput(thread->id(),
+                                              (AudioSystem::stream_type)mStreamType,
+                                              mSessionId);
             thread->mLock.lock();
         }
         if (status == NO_ERROR) {
@@ -2999,7 +3055,9 @@
         }
         if (!isOutputTrack() && (state == ACTIVE || state == RESUMING)) {
             thread->mLock.unlock();
-            AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType);
+            AudioSystem::stopOutput(thread->id(),
+                                    (AudioSystem::stream_type)mStreamType,
+                                    mSessionId);
             thread->mLock.lock();
         }
     }
@@ -3016,7 +3074,9 @@
             LOGV("ACTIVE/RESUMING => PAUSING (%d) on thread %p", mName, thread.get());
             if (!isOutputTrack()) {
                 thread->mLock.unlock();
-                AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType);
+                AudioSystem::stopOutput(thread->id(),
+                                        (AudioSystem::stream_type)mStreamType,
+                                        mSessionId);
                 thread->mLock.lock();
             }
         }
@@ -3585,7 +3645,7 @@
         }
 
         // If no audio session id is provided, create one here
-        if (sessionId != NULL && *sessionId != 0) {
+        if (sessionId != NULL && *sessionId != AudioSystem::SESSION_OUTPUT_MIX) {
             lSessionId = *sessionId;
         } else {
             lSessionId = nextUniqueId();
@@ -4416,8 +4476,8 @@
             thread->type() != PlaybackThread::DIRECT) {
             MixerThread *srcThread = (MixerThread *)thread;
             srcThread->invalidateTracks(stream);
-            }
         }
+    }
 
     return NO_ERROR;
 }
@@ -4472,12 +4532,26 @@
 
 status_t AudioFlinger::loadEffectLibrary(const char *libPath, int *handle)
 {
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    // only allow libraries loaded from /system/lib/soundfx for now
+    if (strncmp(gEffectLibPath, libPath, strlen(gEffectLibPath)) != 0) {
+        return PERMISSION_DENIED;
+    }
+
     Mutex::Autolock _l(mLock);
     return EffectLoadLibrary(libPath, handle);
 }
 
 status_t AudioFlinger::unloadEffectLibrary(int handle)
 {
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+
     Mutex::Autolock _l(mLock);
     return EffectUnloadLibrary(handle);
 }
@@ -4522,7 +4596,8 @@
     sp<Client> client;
     wp<Client> wclient;
 
-    LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, output %d", pid, effectClient.get(), priority, sessionId, output);
+    LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, output %d",
+            pid, effectClient.get(), priority, sessionId, output);
 
     if (pDesc == NULL) {
         lStatus = BAD_VALUE;
@@ -4577,7 +4652,7 @@
                     // an auxiliary version of this effect type is available
                     found = true;
                     memcpy(&d, &desc, sizeof(effect_descriptor_t));
-                    if (sessionId != 0 ||
+                    if (sessionId != AudioSystem::SESSION_OUTPUT_MIX ||
                             (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
                         break;
                     }
@@ -4590,22 +4665,23 @@
             }
             // For same effect type, chose auxiliary version over insert version if
             // connect to output mix (Compliance to OpenSL ES)
-            if (sessionId == 0 &&
+            if (sessionId == AudioSystem::SESSION_OUTPUT_MIX &&
                     (d.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) {
                 memcpy(&desc, &d, sizeof(effect_descriptor_t));
             }
         }
 
         // Do not allow auxiliary effects on a session different from 0 (output mix)
-        if (sessionId != 0 &&
+        if (sessionId != AudioSystem::SESSION_OUTPUT_MIX &&
              (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
             lStatus = INVALID_OPERATION;
             goto Exit;
         }
 
-        // Session -1 is reserved for output stage effects that can only be created
-        // by audio policy manager (running in same process)
-        if (sessionId == -1 && getpid() != IPCThreadState::self()->getCallingPid()) {
+        // Session AudioSystem::SESSION_OUTPUT_STAGE is reserved for output stage effects
+        // that can only be created by audio policy manager (running in same process)
+        if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE &&
+                getpid() != IPCThreadState::self()->getCallingPid()) {
             lStatus = INVALID_OPERATION;
             goto Exit;
         }
@@ -4617,13 +4693,14 @@
         // output threads.
         // TODO: allow attachment of effect to inputs
         if (output == 0) {
-            if (sessionId <= 0) {
-                // default to first output
-                // TODO: define criteria to choose output when not specified. Or
-                // receive output from audio policy manager
-                if (mPlaybackThreads.size() != 0) {
-                    output = mPlaybackThreads.keyAt(0);
-                }
+            if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE) {
+                // output must be specified by AudioPolicyManager when using session
+                // AudioSystem::SESSION_OUTPUT_STAGE
+                lStatus = BAD_VALUE;
+                goto Exit;
+            } else if (sessionId == AudioSystem::SESSION_OUTPUT_MIX) {
+                output = AudioSystem::getOutputForEffect(&desc);
+                LOGV("createEffect() got output %d for effect %s", output, desc.name);
             } else {
                  // look for the thread where the specified audio session is present
                 for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
@@ -4636,7 +4713,7 @@
         }
         PlaybackThread *thread = checkPlaybackThread_l(output);
         if (thread == NULL) {
-            LOGE("unknown output thread");
+            LOGE("createEffect() unknown output thread");
             lStatus = BAD_VALUE;
             goto Exit;
         }
@@ -4651,7 +4728,8 @@
         }
 
         // create effect on selected output trhead
-        handle = thread->createEffect_l(client, effectClient, priority, sessionId, &desc, enabled, &lStatus);
+        handle = thread->createEffect_l(client, effectClient, priority, sessionId,
+                &desc, enabled, &lStatus);
         if (handle != 0 && id != NULL) {
             *id = handle->id();
         }
@@ -4664,31 +4742,64 @@
     return handle;
 }
 
-status_t AudioFlinger::registerEffectResource_l(effect_descriptor_t *desc) {
-    if (mTotalEffectsCpuLoad + desc->cpuLoad > MAX_EFFECTS_CPU_LOAD) {
-        LOGW("registerEffectResource() CPU Load limit exceeded for Fx %s, CPU %f MIPS",
-                desc->name, (float)desc->cpuLoad/10);
-        return INVALID_OPERATION;
+status_t AudioFlinger::moveEffects(int session, int srcOutput, int dstOutput)
+{
+    LOGV("moveEffects() session %d, srcOutput %d, dstOutput %d",
+            session, srcOutput, dstOutput);
+    Mutex::Autolock _l(mLock);
+    if (srcOutput == dstOutput) {
+        LOGW("moveEffects() same dst and src outputs %d", dstOutput);
+        return NO_ERROR;
     }
-    if (mTotalEffectsMemory + desc->memoryUsage > MAX_EFFECTS_MEMORY) {
-        LOGW("registerEffectResource() memory limit exceeded for Fx %s, Memory %d KB",
-                desc->name, desc->memoryUsage);
-        return INVALID_OPERATION;
+    PlaybackThread *srcThread = checkPlaybackThread_l(srcOutput);
+    if (srcThread == NULL) {
+        LOGW("moveEffects() bad srcOutput %d", srcOutput);
+        return BAD_VALUE;
     }
-    mTotalEffectsCpuLoad += desc->cpuLoad;
-    mTotalEffectsMemory += desc->memoryUsage;
-    LOGV("registerEffectResource_l() effect %s, CPU %d, memory %d",
-            desc->name, desc->cpuLoad, desc->memoryUsage);
-    LOGV("  total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory);
+    PlaybackThread *dstThread = checkPlaybackThread_l(dstOutput);
+    if (dstThread == NULL) {
+        LOGW("moveEffects() bad dstOutput %d", dstOutput);
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _dl(dstThread->mLock);
+    Mutex::Autolock _sl(srcThread->mLock);
+    moveEffectChain_l(session, srcThread, dstThread);
+
     return NO_ERROR;
 }
 
-void AudioFlinger::unregisterEffectResource_l(effect_descriptor_t *desc) {
-    mTotalEffectsCpuLoad -= desc->cpuLoad;
-    mTotalEffectsMemory -= desc->memoryUsage;
-    LOGV("unregisterEffectResource_l() effect %s, CPU %d, memory %d",
-            desc->name, desc->cpuLoad, desc->memoryUsage);
-    LOGV("  total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory);
+// moveEffectChain_l mustbe called with both srcThread and dstThread mLocks held
+status_t AudioFlinger::moveEffectChain_l(int session,
+                                   AudioFlinger::PlaybackThread *srcThread,
+                                   AudioFlinger::PlaybackThread *dstThread)
+{
+    LOGV("moveEffectChain_l() session %d from thread %p to thread %p",
+            session, srcThread, dstThread);
+
+    sp<EffectChain> chain = srcThread->getEffectChain_l(session);
+    if (chain == 0) {
+        LOGW("moveEffectChain_l() effect chain for session %d not on source thread %p",
+                session, srcThread);
+        return INVALID_OPERATION;
+    }
+
+    // remove chain first. This is usefull only if reconfiguring effect chain on same output thread,
+    // so that a new chain is created with correct parameters when first effect is added. This is
+    // otherwise unecessary as removeEffect_l() will remove the chain when last effect is
+    // removed.
+    srcThread->removeEffectChain_l(chain);
+
+    // transfer all effects one by one so that new effect chain is created on new thread with
+    // correct buffer sizes and audio parameters and effect engines reconfigured accordingly
+    sp<EffectModule> effect = chain->getEffectFromId_l(0);
+    while (effect != 0) {
+        srcThread->removeEffect_l(effect);
+        dstThread->addEffect_l(effect);
+        effect = chain->getEffectFromId_l(0);
+    }
+
+    return NO_ERROR;
 }
 
 // PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held
@@ -4707,6 +4818,7 @@
     status_t lStatus;
     sp<Track> track;
     sp<EffectChain> chain;
+    bool chainCreated = false;
     bool effectCreated = false;
     bool effectRegistered = false;
 
@@ -4718,16 +4830,18 @@
 
     // Do not allow auxiliary effect on session other than 0
     if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY &&
-        sessionId != 0) {
-        LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId);
+        sessionId != AudioSystem::SESSION_OUTPUT_MIX) {
+        LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d",
+                desc->name, sessionId);
         lStatus = BAD_VALUE;
         goto Exit;
     }
 
     // Do not allow effects with session ID 0 on direct output or duplicating threads
     // TODO: add rule for hw accelerated effects on direct outputs with non PCM format
-    if (sessionId == 0 && mType != MIXER) {
-        LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId);
+    if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && mType != MIXER) {
+        LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d",
+                desc->name, sessionId);
         lStatus = BAD_VALUE;
         goto Exit;
     }
@@ -4744,6 +4858,8 @@
             LOGV("createEffect_l() new effect chain for session %d", sessionId);
             chain = new EffectChain(this, sessionId);
             addEffectChain_l(chain);
+            chain->setStrategy(getStrategyForSession_l(sessionId));
+            chainCreated = true;
         } else {
             effect = chain->getEffectFromDesc_l(desc);
         }
@@ -4751,14 +4867,15 @@
         LOGV("createEffect_l() got effect %p on chain %p", effect == 0 ? 0 : effect.get(), chain.get());
 
         if (effect == 0) {
+            int id = mAudioFlinger->nextUniqueId();
             // Check CPU and memory usage
-            lStatus = mAudioFlinger->registerEffectResource_l(desc);
+            lStatus = AudioSystem::registerEffect(desc, mId, chain->strategy(), sessionId, id);
             if (lStatus != NO_ERROR) {
                 goto Exit;
             }
             effectRegistered = true;
             // create a new effect module if none present in the chain
-            effect = new EffectModule(this, chain, desc, mAudioFlinger->nextUniqueId(), sessionId);
+            effect = new EffectModule(this, chain, desc, id, sessionId);
             lStatus = effect->status();
             if (lStatus != NO_ERROR) {
                 goto Exit;
@@ -4782,14 +4899,15 @@
 
 Exit:
     if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
+        Mutex::Autolock _l(mLock);
         if (effectCreated) {
-            Mutex::Autolock _l(mLock);
-            if (chain->removeEffect_l(effect) == 0) {
-                removeEffectChain_l(chain);
-            }
+            chain->removeEffect_l(effect);
         }
         if (effectRegistered) {
-            mAudioFlinger->unregisterEffectResource_l(desc);
+            AudioSystem::unregisterEffect(effect->id());
+        }
+        if (chainCreated) {
+            removeEffectChain_l(chain);
         }
         handle.clear();
     }
@@ -4800,26 +4918,71 @@
     return handle;
 }
 
-void AudioFlinger::PlaybackThread::disconnectEffect(const sp< EffectModule>& effect,
-                                                    const wp<EffectHandle>& handle) {
+// PlaybackThread::addEffect_l() must be called with AudioFlinger::mLock and
+// PlaybackThread::mLock held
+status_t AudioFlinger::PlaybackThread::addEffect_l(const sp<EffectModule>& effect)
+{
+    // check for existing effect chain with the requested audio session
+    int sessionId = effect->sessionId();
+    sp<EffectChain> chain = getEffectChain_l(sessionId);
+    bool chainCreated = false;
+
+    if (chain == 0) {
+        // create a new chain for this session
+        LOGV("addEffect_l() new effect chain for session %d", sessionId);
+        chain = new EffectChain(this, sessionId);
+        addEffectChain_l(chain);
+        chain->setStrategy(getStrategyForSession_l(sessionId));
+        chainCreated = true;
+    }
+    LOGV("addEffect_l() %p chain %p effect %p", this, chain.get(), effect.get());
+
+    if (chain->getEffectFromId_l(effect->id()) != 0) {
+        LOGW("addEffect_l() %p effect %s already present in chain %p",
+                this, effect->desc().name, chain.get());
+        return BAD_VALUE;
+    }
+
+    status_t status = chain->addEffect_l(effect);
+    if (status != NO_ERROR) {
+        if (chainCreated) {
+            removeEffectChain_l(chain);
+        }
+        return status;
+    }
+
+    effect->setDevice(mDevice);
+    effect->setMode(mAudioFlinger->getMode());
+    return NO_ERROR;
+}
+
+void AudioFlinger::PlaybackThread::removeEffect_l(const sp<EffectModule>& effect) {
+
+    LOGV("removeEffect_l() %p effect %p", this, effect.get());
     effect_descriptor_t desc = effect->desc();
+    if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+        detachAuxEffect_l(effect->id());
+    }
+
+    sp<EffectChain> chain = effect->chain().promote();
+    if (chain != 0) {
+        // remove effect chain if removing last effect
+        if (chain->removeEffect_l(effect) == 0) {
+            removeEffectChain_l(chain);
+        }
+    } else {
+        LOGW("removeEffect_l() %p cannot promote chain for effect %p", this, effect.get());
+    }
+}
+
+void AudioFlinger::PlaybackThread::disconnectEffect(const sp<EffectModule>& effect,
+                                                    const wp<EffectHandle>& handle) {
     Mutex::Autolock _l(mLock);
+    LOGV("disconnectEffect() %p effect %p", this, effect.get());
     // delete the effect module if removing last handle on it
     if (effect->removeHandle(handle) == 0) {
-        if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
-            detachAuxEffect_l(effect->id());
-        }
-        sp<EffectChain> chain = effect->chain().promote();
-        if (chain != 0) {
-            // remove effect chain if remove last effect
-            if (chain->removeEffect_l(effect) == 0) {
-                removeEffectChain_l(chain);
-            }
-        }
-        mLock.unlock();
-        mAudioFlinger->mLock.lock();
-        mAudioFlinger->unregisterEffectResource_l(&desc);
-        mAudioFlinger->mLock.unlock();
+        removeEffect_l(effect);
+        AudioSystem::unregisterEffect(effect->id());
     }
 }
 
@@ -4863,13 +5026,16 @@
 
     chain->setInBuffer(buffer, ownsBuffer);
     chain->setOutBuffer(mMixBuffer);
-    // Effect chain for session -1 is inserted at end of effect chains list
-    // in order to be processed last as it contains output stage effects
-    // Effect chain for session 0 is inserted before session -1 to be processed
+    // Effect chain for session AudioSystem::SESSION_OUTPUT_STAGE is inserted at end of effect
+    // chains list in order to be processed last as it contains output stage effects
+    // Effect chain for session AudioSystem::SESSION_OUTPUT_MIX is inserted before
+    // session AudioSystem::SESSION_OUTPUT_STAGE to be processed
     // after track specific effects and before output stage
-    // Effect chain for session other than 0 is inserted at beginning of effect
-    // chains list to be processed before output mix effects. Relative order between
-    // sessions other than 0 is not important
+    // It is therefore mandatory that AudioSystem::SESSION_OUTPUT_MIX == 0 and
+    // that AudioSystem::SESSION_OUTPUT_STAGE < AudioSystem::SESSION_OUTPUT_MIX
+    // Effect chain for other sessions are inserted at beginning of effect
+    // chains list to be processed before output mix effects. Relative order between other
+    // sessions is not important
     size_t size = mEffectChains.size();
     size_t i = 0;
     for (i = 0; i < size; i++) {
@@ -4896,26 +5062,30 @@
                     track->setMainBuffer(mMixBuffer);
                 }
             }
+            break;
         }
     }
     return mEffectChains.size();
 }
 
-void AudioFlinger::PlaybackThread::lockEffectChains_l()
+void AudioFlinger::PlaybackThread::lockEffectChains_l(
+        Vector<sp <AudioFlinger::EffectChain> >& effectChains)
 {
+    effectChains = mEffectChains;
     for (size_t i = 0; i < mEffectChains.size(); i++) {
         mEffectChains[i]->lock();
     }
 }
 
-void AudioFlinger::PlaybackThread::unlockEffectChains()
+void AudioFlinger::PlaybackThread::unlockEffectChains(
+        Vector<sp <AudioFlinger::EffectChain> >& effectChains)
 {
-    Mutex::Autolock _l(mLock);
-    for (size_t i = 0; i < mEffectChains.size(); i++) {
-        mEffectChains[i]->unlock();
+    for (size_t i = 0; i < effectChains.size(); i++) {
+        effectChains[i]->unlock();
     }
 }
 
+
 sp<AudioFlinger::EffectModule> AudioFlinger::PlaybackThread::getEffect_l(int sessionId, int effectId)
 {
     sp<EffectModule> effect;
@@ -4927,21 +5097,23 @@
     return effect;
 }
 
-status_t AudioFlinger::PlaybackThread::attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
+status_t AudioFlinger::PlaybackThread::attachAuxEffect(
+        const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
 {
     Mutex::Autolock _l(mLock);
     return attachAuxEffect_l(track, EffectId);
 }
 
-status_t AudioFlinger::PlaybackThread::attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
+status_t AudioFlinger::PlaybackThread::attachAuxEffect_l(
+        const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
 {
     status_t status = NO_ERROR;
 
     if (EffectId == 0) {
         track->setAuxBuffer(0, NULL);
     } else {
-        // Auxiliary effects are always in audio session 0
-        sp<EffectModule> effect = getEffect_l(0, EffectId);
+        // Auxiliary effects are always in audio session AudioSystem::SESSION_OUTPUT_MIX
+        sp<EffectModule> effect = getEffect_l(AudioSystem::SESSION_OUTPUT_MIX, EffectId);
         if (effect != 0) {
             if ((effect->desc().flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
                 track->setAuxBuffer(EffectId, (int32_t *)effect->inBuffer());
@@ -5137,7 +5309,7 @@
         if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
             AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32,
                                         mConfig.inputCfg.buffer.s32,
-                                        mConfig.inputCfg.buffer.frameCount);
+                                        mConfig.inputCfg.buffer.frameCount/2);
         }
 
         // do the actual processing in the effect engine
@@ -5214,7 +5386,8 @@
     mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
     mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
     // Insert effect:
-    // - in session 0 or -1, always overwrites output buffer: input buffer == output buffer
+    // - in session AudioSystem::SESSION_OUTPUT_MIX or AudioSystem::SESSION_OUTPUT_STAGE,
+    // always overwrites output buffer: input buffer == output buffer
     // - in other sessions:
     //      last effect in the chain accumulates in output buffer: input buffer != output buffer
     //      other effect: overwrites output buffer: input buffer == output buffer
@@ -5231,6 +5404,9 @@
     mConfig.inputCfg.buffer.frameCount = thread->frameCount();
     mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount;
 
+    LOGV("configure() %p thread %p buffer %p framecount %d",
+            this, thread.get(), mConfig.inputCfg.buffer.raw, mConfig.inputCfg.buffer.frameCount);
+
     status_t cmdStatus;
     int size = sizeof(int);
     status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_CONFIGURE, sizeof(effect_config_t), &mConfig, &size, &cmdStatus);
@@ -5753,7 +5929,7 @@
             mVolumeCtrlIdx(-1), mLeftVolume(0), mRightVolume(0),
             mNewLeftVolume(0), mNewRightVolume(0)
 {
-
+    mStrategy = AudioSystem::getStrategyForStream(AudioSystem::MUSIC);
 }
 
 AudioFlinger::EffectChain::~EffectChain()
@@ -5786,7 +5962,8 @@
     size_t size = mEffects.size();
 
     for (size_t i = 0; i < size; i++) {
-        if (mEffects[i]->id() == id) {
+        // by convention, return first effect if id provided is 0 (0 is never a valid id)
+        if (id == 0 || mEffects[i]->id() == id) {
             effect = mEffects[i];
             break;
         }
@@ -5816,21 +5993,24 @@
 }
 
 // addEffect_l() must be called with PlaybackThread::mLock held
-status_t AudioFlinger::EffectChain::addEffect_l(sp<EffectModule>& effect)
+status_t AudioFlinger::EffectChain::addEffect_l(const sp<EffectModule>& effect)
 {
     effect_descriptor_t desc = effect->desc();
     uint32_t insertPref = desc.flags & EFFECT_FLAG_INSERT_MASK;
 
     Mutex::Autolock _l(mLock);
+    effect->setChain(this);
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread == 0) {
+        return NO_INIT;
+    }
+    effect->setThread(thread);
 
     if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
         // Auxiliary effects are inserted at the beginning of mEffects vector as
         // they are processed first and accumulated in chain input buffer
         mEffects.insertAt(effect, 0);
-        sp<ThreadBase> thread = mThread.promote();
-        if (thread == 0) {
-            return NO_INIT;
-        }
+
         // the input buffer for auxiliary effect contains mono samples in
         // 32 bit format. This is to avoid saturation in AudoMixer
         // accumulation stage. Saturation is done in EffectModule::process() before
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 99816f9..a8c9a92 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -168,8 +168,7 @@
                         int *id,
                         int *enabled);
 
-            status_t registerEffectResource_l(effect_descriptor_t *desc);
-            void     unregisterEffectResource_l(effect_descriptor_t *desc);
+    virtual status_t moveEffects(int session, int srcOutput, int dstOutput);
 
     enum hardware_call_state {
         AUDIO_HW_IDLE = 0,
@@ -619,15 +618,22 @@
                     sp<EffectChain> getEffectChain_l(int sessionId);
                     status_t addEffectChain_l(const sp<EffectChain>& chain);
                     size_t removeEffectChain_l(const sp<EffectChain>& chain);
-                    void lockEffectChains_l();
-                    void unlockEffectChains();
+                    void lockEffectChains_l(Vector<sp <EffectChain> >& effectChains);
+                    void unlockEffectChains(Vector<sp <EffectChain> >& effectChains);
 
                     sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId);
                     void detachAuxEffect_l(int effectId);
-                    status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);
-                    status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);
+                    status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track,
+                            int EffectId);
+                    status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track,
+                            int EffectId);
                     void setMode(uint32_t mode);
 
+                    status_t addEffect_l(const sp< EffectModule>& effect);
+                    void removeEffect_l(const sp< EffectModule>& effect);
+
+                    uint32_t getStrategyForSession_l(int sessionId);
+
         struct  stream_type_t {
             stream_type_t()
                 :   volume(1.0f),
@@ -690,7 +696,10 @@
 
     class MixerThread : public PlaybackThread {
     public:
-        MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
+        MixerThread (const sp<AudioFlinger>& audioFlinger,
+                     AudioStreamOut* output,
+                     int id,
+                     uint32_t device);
         virtual             ~MixerThread();
 
         // Thread virtuals
@@ -701,7 +710,8 @@
         virtual     status_t    dumpInternals(int fd, const Vector<String16>& args);
 
     protected:
-                    uint32_t    prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove);
+                    uint32_t    prepareTracks_l(const SortedVector< wp<Track> >& activeTracks,
+                                                Vector< sp<Track> > *tracksToRemove);
         virtual     int         getTrackName_l();
         virtual     void        deleteTrackName_l(int name);
         virtual     uint32_t    activeSleepTimeUs();
@@ -764,6 +774,9 @@
               void audioConfigChanged_l(int event, int ioHandle, void *param2);
 
               int  nextUniqueId();
+              status_t moveEffectChain_l(int session,
+                                     AudioFlinger::PlaybackThread *srcThread,
+                                     AudioFlinger::PlaybackThread *dstThread);
 
     friend class AudioBuffer;
 
@@ -931,6 +944,9 @@
         uint32_t status() {
             return mStatus;
         }
+        int sessionId() {
+            return mSessionId;
+        }
         status_t    setEnabled(bool enabled);
         bool isEnabled();
 
@@ -938,6 +954,8 @@
         int16_t     *inBuffer() { return mConfig.inputCfg.buffer.s16; }
         void        setOutBuffer(int16_t *buffer) { mConfig.outputCfg.buffer.s16 = buffer; }
         int16_t     *outBuffer() { return mConfig.outputCfg.buffer.s16; }
+        void        setChain(const wp<EffectChain>& chain) { mChain = chain; }
+        void        setThread(const wp<ThreadBase>& thread) { mThread = thread; }
 
         status_t addHandle(sp<EffectHandle>& handle);
         void disconnect(const wp<EffectHandle>& handle);
@@ -1061,19 +1079,19 @@
             mLock.unlock();
         }
 
-        status_t addEffect_l(sp<EffectModule>& handle);
+        status_t addEffect_l(const sp<EffectModule>& handle);
         size_t removeEffect_l(const sp<EffectModule>& handle);
 
         int sessionId() {
             return mSessionId;
         }
+
         sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor);
         sp<EffectModule> getEffectFromId_l(int id);
         bool setVolume_l(uint32_t *left, uint32_t *right);
         void setDevice_l(uint32_t device);
         void setMode_l(uint32_t mode);
 
-
         void setInBuffer(int16_t *buffer, bool ownsBuffer = false) {
             mInBuffer = buffer;
             mOwnInBuffer = ownsBuffer;
@@ -1092,6 +1110,10 @@
         void stopTrack() {mActiveTrackCnt--;}
         int activeTracks() { return mActiveTrackCnt;}
 
+        uint32_t strategy() { return mStrategy; }
+        void setStrategy(uint32_t strategy)
+                 { mStrategy = strategy; }
+
         status_t dump(int fd, const Vector<String16>& args);
 
     protected:
@@ -1112,7 +1134,7 @@
         uint32_t mRightVolume;      // previous volume on right channel
         uint32_t mNewLeftVolume;       // new volume on left channel
         uint32_t mNewRightVolume;      // new volume on right channel
-
+        uint32_t mStrategy; // strategy for this effect chain
     };
 
     friend class RecordThread;
@@ -1142,12 +1164,6 @@
 #endif
                 uint32_t mMode;
 
-                // Maximum CPU load allocated to audio effects in 0.1 MIPS (ARMv5TE, 0 WS memory) units
-                static const uint32_t MAX_EFFECTS_CPU_LOAD = 1000;
-                // Maximum memory allocated to audio effects in KB
-                static const uint32_t MAX_EFFECTS_MEMORY = 512;
-                uint32_t mTotalEffectsCpuLoad; // current CPU load used by effects
-                uint32_t mTotalEffectsMemory;  // current memory used by effects
 };
 
 // ----------------------------------------------------------------------------
diff --git a/services/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp
index 549d661..4614c8d 100644
--- a/services/audioflinger/AudioPolicyManagerBase.cpp
+++ b/services/audioflinger/AudioPolicyManagerBase.cpp
@@ -538,9 +538,11 @@
     return output;
 }
 
-status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output,
+                                             AudioSystem::stream_type stream,
+                                             int session)
 {
-    LOGV("startOutput() output %d, stream %d", output, stream);
+    LOGV("startOutput() output %d, stream %d, session %d", output, stream, session);
     ssize_t index = mOutputs.indexOfKey(output);
     if (index < 0) {
         LOGW("startOutput() unknow output %d", output);
@@ -574,9 +576,11 @@
     return NO_ERROR;
 }
 
-status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output,
+                                            AudioSystem::stream_type stream,
+                                            int session)
 {
-    LOGV("stopOutput() output %d, stream %d", output, stream);
+    LOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
     ssize_t index = mOutputs.indexOfKey(output);
     if (index < 0) {
         LOGW("stopOutput() unknow output %d", output);
@@ -602,8 +606,12 @@
         setOutputDevice(output, getNewDevice(output));
 
 #ifdef WITH_A2DP
-        if (mA2dpOutput != 0 && !a2dpUsedForSonification() && strategy == STRATEGY_SONIFICATION) {
-            setStrategyMute(STRATEGY_MEDIA, false, mA2dpOutput, mOutputs.valueFor(mHardwareOutput)->mLatency*2);
+        if (mA2dpOutput != 0 && !a2dpUsedForSonification() &&
+                strategy == STRATEGY_SONIFICATION) {
+            setStrategyMute(STRATEGY_MEDIA,
+                            false,
+                            mA2dpOutput,
+                            mOutputs.valueFor(mHardwareOutput)->mLatency*2);
         }
 #endif
         if (output != mHardwareOutput) {
@@ -826,6 +834,85 @@
     return NO_ERROR;
 }
 
+audio_io_handle_t AudioPolicyManagerBase::getOutputForEffect(effect_descriptor_t *desc)
+{
+    LOGV("getOutputForEffect()");
+    // apply simple rule where global effects are attached to the same output as MUSIC streams
+    return getOutput(AudioSystem::MUSIC);
+}
+
+status_t AudioPolicyManagerBase::registerEffect(effect_descriptor_t *desc,
+                                audio_io_handle_t output,
+                                uint32_t strategy,
+                                int session,
+                                int id)
+{
+    ssize_t index = mOutputs.indexOfKey(output);
+    if (index < 0) {
+        LOGW("registerEffect() unknown output %d", output);
+        return INVALID_OPERATION;
+    }
+
+    if (mTotalEffectsCpuLoad + desc->cpuLoad > getMaxEffectsCpuLoad()) {
+        LOGW("registerEffect() CPU Load limit exceeded for Fx %s, CPU %f MIPS",
+                desc->name, (float)desc->cpuLoad/10);
+        return INVALID_OPERATION;
+    }
+    if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) {
+        LOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB",
+                desc->name, desc->memoryUsage);
+        return INVALID_OPERATION;
+    }
+    mTotalEffectsCpuLoad += desc->cpuLoad;
+    mTotalEffectsMemory += desc->memoryUsage;
+    LOGV("registerEffect() effect %s, output %d, strategy %d session %d id %d",
+            desc->name, output, strategy, session, id);
+
+    LOGV("registerEffect() CPU %d, memory %d", desc->cpuLoad, desc->memoryUsage);
+    LOGV("  total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory);
+
+    EffectDescriptor *pDesc = new EffectDescriptor();
+    memcpy (&pDesc->mDesc, desc, sizeof(effect_descriptor_t));
+    pDesc->mOutput = output;
+    pDesc->mStrategy = (routing_strategy)strategy;
+    pDesc->mSession = session;
+    mEffects.add(id, pDesc);
+
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::unregisterEffect(int id)
+{
+    ssize_t index = mEffects.indexOfKey(id);
+    if (index < 0) {
+        LOGW("unregisterEffect() unknown effect ID %d", id);
+        return INVALID_OPERATION;
+    }
+
+    EffectDescriptor *pDesc = mEffects.valueAt(index);
+
+    if (mTotalEffectsCpuLoad < pDesc->mDesc.cpuLoad) {
+        LOGW("unregisterEffect() CPU load %d too high for total %d",
+                pDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad);
+        pDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad;
+    }
+    mTotalEffectsCpuLoad -= pDesc->mDesc.cpuLoad;
+    if (mTotalEffectsMemory < pDesc->mDesc.memoryUsage) {
+        LOGW("unregisterEffect() memory %d too big for total %d",
+                pDesc->mDesc.memoryUsage, mTotalEffectsMemory);
+        pDesc->mDesc.memoryUsage = mTotalEffectsMemory;
+    }
+    mTotalEffectsMemory -= pDesc->mDesc.memoryUsage;
+    LOGV("unregisterEffect() effect %s, ID %d, CPU %d, memory %d",
+            pDesc->mDesc.name, id, pDesc->mDesc.cpuLoad, pDesc->mDesc.memoryUsage);
+    LOGV("  total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory);
+
+    mEffects.removeItem(id);
+    delete pDesc;
+
+    return NO_ERROR;
+}
+
 status_t AudioPolicyManagerBase::dump(int fd)
 {
     const size_t SIZE = 256;
@@ -890,6 +977,19 @@
         write(fd, buffer, strlen(buffer));
     }
 
+    snprintf(buffer, SIZE, "\nTotal Effects CPU: %f MIPS, Total Effects memory: %d KB\n",
+            (float)mTotalEffectsCpuLoad/10, mTotalEffectsMemory);
+    write(fd, buffer, strlen(buffer));
+
+    snprintf(buffer, SIZE, "Registered effects:\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < mEffects.size(); i++) {
+        snprintf(buffer, SIZE, "- Effect %d dump:\n", mEffects.keyAt(i));
+        write(fd, buffer, strlen(buffer));
+        mEffects.valueAt(i)->dump(fd);
+    }
+
+
     return NO_ERROR;
 }
 
@@ -903,7 +1003,7 @@
     Thread(false),
 #endif //AUDIO_POLICY_TEST
     mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0), mLimitRingtoneVolume(false),
-    mLastVoiceVolume(-1.0f)
+    mLastVoiceVolume(-1.0f), mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0)
 {
     mpClientInterface = clientInterface;
 
@@ -939,6 +1039,7 @@
     } else {
         addOutput(mHardwareOutput, outputDesc);
         setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true);
+        //TODO: configure audio effect output stage here
     }
 
     updateDeviceForStrategy();
@@ -1153,6 +1254,9 @@
     if (mA2dpOutput) {
         // add A2DP output descriptor
         addOutput(mA2dpOutput, outputDesc);
+
+        //TODO: configure audio effect output stage here
+
         // set initial stream volume for A2DP device
         applyStreamVolumes(mA2dpOutput, device);
         if (a2dpUsedForSonification()) {
@@ -1270,6 +1374,7 @@
         AudioParameter param;
         param.add(String8("closing"), String8("true"));
         mpClientInterface->setParameters(mA2dpOutput, param.toString());
+
         mpClientInterface->closeOutput(mA2dpOutput);
         delete mOutputs.valueFor(mA2dpOutput);
         mOutputs.removeItem(mA2dpOutput);
@@ -1283,48 +1388,54 @@
     uint32_t curDevice = getDeviceForStrategy(strategy, false);
     bool a2dpWasUsed = AudioSystem::isA2dpDevice((AudioSystem::audio_devices)(prevDevice & ~AudioSystem::DEVICE_OUT_SPEAKER));
     bool a2dpIsUsed = AudioSystem::isA2dpDevice((AudioSystem::audio_devices)(curDevice & ~AudioSystem::DEVICE_OUT_SPEAKER));
-    AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput);
-    AudioOutputDescriptor *a2dpOutputDesc;
+    audio_io_handle_t srcOutput = 0;
+    audio_io_handle_t dstOutput = 0;
 
     if (a2dpWasUsed && !a2dpIsUsed) {
         bool dupUsed = a2dpUsedForSonification() && a2dpWasUsed && (AudioSystem::popCount(prevDevice) == 2);
-
+        dstOutput = mHardwareOutput;
         if (dupUsed) {
-            LOGV("checkOutputForStrategy() moving strategy %d to duplicated", strategy);
-            a2dpOutputDesc = mOutputs.valueFor(mDuplicatedOutput);
+            LOGV("checkOutputForStrategy() moving strategy %d from duplicated", strategy);
+            srcOutput = mDuplicatedOutput;
         } else {
-            LOGV("checkOutputForStrategy() moving strategy %d to a2dp", strategy);
-            a2dpOutputDesc = mOutputs.valueFor(mA2dpOutput);
+            LOGV("checkOutputForStrategy() moving strategy %d from a2dp", strategy);
+            srcOutput = mA2dpOutput;
         }
 
-        for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
-            if (getStrategy((AudioSystem::stream_type)i) == strategy) {
-                mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, mHardwareOutput);
-            }
-        }
         // do not change newDevice if it was already set before this call by a previous call to
         // getNewDevice() or checkOutputForStrategy() for a strategy with higher priority
-        if (newDevice == 0 && hwOutputDesc->isUsedByStrategy(strategy)) {
+        if (newDevice == 0 && mOutputs.valueFor(mHardwareOutput)->isUsedByStrategy(strategy)) {
             newDevice = getDeviceForStrategy(strategy, false);
         }
     }
     if (a2dpIsUsed && !a2dpWasUsed) {
         bool dupUsed = a2dpUsedForSonification() && a2dpIsUsed && (AudioSystem::popCount(curDevice) == 2);
-        audio_io_handle_t a2dpOutput;
-
+        srcOutput = mHardwareOutput;
         if (dupUsed) {
-            LOGV("checkOutputForStrategy() moving strategy %d from duplicated", strategy);
-            a2dpOutputDesc = mOutputs.valueFor(mDuplicatedOutput);
-            a2dpOutput = mDuplicatedOutput;
+            LOGV("checkOutputForStrategy() moving strategy %d to duplicated", strategy);
+            dstOutput = mDuplicatedOutput;
         } else {
-            LOGV("checkOutputForStrategy() moving strategy %d from a2dp", strategy);
-            a2dpOutputDesc = mOutputs.valueFor(mA2dpOutput);
-            a2dpOutput = mA2dpOutput;
+            LOGV("checkOutputForStrategy() moving strategy %d to a2dp", strategy);
+            dstOutput = mA2dpOutput;
         }
+    }
 
+    if (srcOutput != 0 && dstOutput != 0) {
+        // Move effects associated to this strategy from previous output to new output
+        for (size_t i = 0; i < mEffects.size(); i++) {
+            EffectDescriptor *desc = mEffects.valueAt(i);
+            if (desc->mSession != AudioSystem::SESSION_OUTPUT_STAGE &&
+                    desc->mStrategy == strategy &&
+                    desc->mOutput == srcOutput) {
+                LOGV("checkOutputForStrategy() moving effect %d to output %d", mEffects.keyAt(i), dstOutput);
+                mpClientInterface->moveEffects(desc->mSession, srcOutput, dstOutput);
+                desc->mOutput = dstOutput;
+            }
+        }
+        // Move tracks associated to this strategy from previous output to new output
         for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
             if (getStrategy((AudioSystem::stream_type)i) == strategy) {
-                mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, a2dpOutput);
+                mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, dstOutput);
             }
         }
     }
@@ -1372,8 +1483,12 @@
     return device;
 }
 
-AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy(AudioSystem::stream_type stream)
-{
+uint32_t AudioPolicyManagerBase::getStrategyForStream(AudioSystem::stream_type stream) {
+    return (uint32_t)getStrategy(stream);
+}
+
+AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy(
+        AudioSystem::stream_type stream) {
     // stream to strategy mapping
     switch (stream) {
     case AudioSystem::VOICE_CALL:
@@ -1846,6 +1961,16 @@
           (format !=0 && !AudioSystem::isLinearPCM(format)));
 }
 
+uint32_t AudioPolicyManagerBase::getMaxEffectsCpuLoad()
+{
+    return MAX_EFFECTS_CPU_LOAD;
+}
+
+uint32_t AudioPolicyManagerBase::getMaxEffectsMemory()
+{
+    return MAX_EFFECTS_MEMORY;
+}
+
 // --- AudioOutputDescriptor class implementation
 
 AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor()
@@ -1979,5 +2104,27 @@
             mCanBeMuted);
 }
 
+// --- EffectDescriptor class implementation
+
+status_t AudioPolicyManagerBase::EffectDescriptor::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, " Output: %d\n", mOutput);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Strategy: %d\n", mStrategy);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Session: %d\n", mSession);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Name: %s\n",  mDesc.name);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+
+    return NO_ERROR;
+}
+
+
 
 }; // namespace android
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index bb3905c..f24e08e 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -119,7 +119,8 @@
     if (!AudioSystem::isOutputDevice(device) && !AudioSystem::isInputDevice(device)) {
         return BAD_VALUE;
     }
-    if (state != AudioSystem::DEVICE_STATE_AVAILABLE && state != AudioSystem::DEVICE_STATE_UNAVAILABLE) {
+    if (state != AudioSystem::DEVICE_STATE_AVAILABLE &&
+            state != AudioSystem::DEVICE_STATE_UNAVAILABLE) {
         return BAD_VALUE;
     }
 
@@ -128,8 +129,9 @@
     return mpPolicyManager->setDeviceConnectionState(device, state, device_address);
 }
 
-AudioSystem::device_connection_state AudioPolicyService::getDeviceConnectionState(AudioSystem::audio_devices device,
-                                                  const char *device_address)
+AudioSystem::device_connection_state AudioPolicyService::getDeviceConnectionState(
+                                                              AudioSystem::audio_devices device,
+                                                              const char *device_address)
 {
     if (mpPolicyManager == NULL) {
         return AudioSystem::DEVICE_STATE_UNAVAILABLE;
@@ -175,7 +177,8 @@
     return NO_ERROR;
 }
 
-status_t AudioPolicyService::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+status_t AudioPolicyService::setForceUse(AudioSystem::force_use usage,
+                                         AudioSystem::forced_config config)
 {
     if (mpPolicyManager == NULL) {
         return NO_INIT;
@@ -223,24 +226,28 @@
     return mpPolicyManager->getOutput(stream, samplingRate, format, channels, flags);
 }
 
-status_t AudioPolicyService::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+status_t AudioPolicyService::startOutput(audio_io_handle_t output,
+                                         AudioSystem::stream_type stream,
+                                         int session)
 {
     if (mpPolicyManager == NULL) {
         return NO_INIT;
     }
     LOGV("startOutput() tid %d", gettid());
     Mutex::Autolock _l(mLock);
-    return mpPolicyManager->startOutput(output, stream);
+    return mpPolicyManager->startOutput(output, stream, session);
 }
 
-status_t AudioPolicyService::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+status_t AudioPolicyService::stopOutput(audio_io_handle_t output,
+                                        AudioSystem::stream_type stream,
+                                        int session)
 {
     if (mpPolicyManager == NULL) {
         return NO_INIT;
     }
     LOGV("stopOutput() tid %d", gettid());
     Mutex::Autolock _l(mLock);
-    return mpPolicyManager->stopOutput(output, stream);
+    return mpPolicyManager->stopOutput(output, stream, session);
 }
 
 void AudioPolicyService::releaseOutput(audio_io_handle_t output)
@@ -339,8 +346,46 @@
     return mpPolicyManager->getStreamVolumeIndex(stream, index);
 }
 
+uint32_t AudioPolicyService::getStrategyForStream(AudioSystem::stream_type stream)
+{
+    if (mpPolicyManager == NULL) {
+        return 0;
+    }
+    return mpPolicyManager->getStrategyForStream(stream);
+}
+
+audio_io_handle_t AudioPolicyService::getOutputForEffect(effect_descriptor_t *desc)
+{
+    if (mpPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    return mpPolicyManager->getOutputForEffect(desc);
+}
+
+status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc,
+                                audio_io_handle_t output,
+                                uint32_t strategy,
+                                int session,
+                                int id)
+{
+    if (mpPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    return mpPolicyManager->registerEffect(desc, output, strategy, session, id);
+}
+
+status_t AudioPolicyService::unregisterEffect(int id)
+{
+    if (mpPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    return mpPolicyManager->unregisterEffect(id);
+}
+
 void AudioPolicyService::binderDied(const wp<IBinder>& who) {
-    LOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
+    LOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(),
+            IPCThreadState::self()->getCallingPid());
 }
 
 static bool tryLock(Mutex& mutex)
@@ -447,10 +492,16 @@
         return 0;
     }
 
-    return af->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, pLatencyMs, flags);
+    return af->openOutput(pDevices,
+                          pSamplingRate,
+                          (uint32_t *)pFormat,
+                          pChannels,
+                          pLatencyMs,
+                          flags);
 }
 
-audio_io_handle_t AudioPolicyService::openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2)
+audio_io_handle_t AudioPolicyService::openDuplicateOutput(audio_io_handle_t output1,
+                                                          audio_io_handle_t output2)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af == 0) {
@@ -514,12 +565,16 @@
     return af->closeInput(input);
 }
 
-status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs)
+status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream,
+                                             float volume,
+                                             audio_io_handle_t output,
+                                             int delayMs)
 {
     return mAudioCommandThread->volumeCommand((int)stream, volume, (int)output, delayMs);
 }
 
-status_t AudioPolicyService::setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output)
+status_t AudioPolicyService::setStreamOutput(AudioSystem::stream_type stream,
+                                             audio_io_handle_t output)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
@@ -527,8 +582,18 @@
     return af->setStreamOutput(stream, output);
 }
 
+status_t AudioPolicyService::moveEffects(int session, audio_io_handle_t srcOutput,
+                                               audio_io_handle_t dstOutput)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
 
-void AudioPolicyService::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs)
+    return af->moveEffects(session, (int)srcOutput, (int)dstOutput);
+}
+
+void AudioPolicyService::setParameters(audio_io_handle_t ioHandle,
+                                       const String8& keyValuePairs,
+                                       int delayMs)
 {
     mAudioCommandThread->parametersCommand((int)ioHandle, keyValuePairs, delayMs);
 }
@@ -539,7 +604,8 @@
     return result;
 }
 
-status_t AudioPolicyService::startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream)
+status_t AudioPolicyService::startTone(ToneGenerator::tone_type tone,
+                                       AudioSystem::stream_type stream)
 {
     mTonePlaybackThread->startToneCommand(tone, stream);
     return NO_ERROR;
@@ -623,8 +689,11 @@
                     }break;
                 case SET_VOLUME: {
                     VolumeData *data = (VolumeData *)command->mParam;
-                    LOGV("AudioCommandThread() processing set volume stream %d, volume %f, output %d", data->mStream, data->mVolume, data->mIO);
-                    command->mStatus = AudioSystem::setStreamVolume(data->mStream, data->mVolume, data->mIO);
+                    LOGV("AudioCommandThread() processing set volume stream %d, \
+                            volume %f, output %d", data->mStream, data->mVolume, data->mIO);
+                    command->mStatus = AudioSystem::setStreamVolume(data->mStream,
+                                                                    data->mVolume,
+                                                                    data->mIO);
                     if (command->mWaitStatus) {
                         command->mCond.signal();
                         mWaitWorkCV.wait(mLock);
@@ -633,7 +702,8 @@
                     }break;
                 case SET_PARAMETERS: {
                      ParametersData *data = (ParametersData *)command->mParam;
-                     LOGV("AudioCommandThread() processing set parameters string %s, io %d", data->mKeyValuePairs.string(), data->mIO);
+                     LOGV("AudioCommandThread() processing set parameters string %s, io %d",
+                             data->mKeyValuePairs.string(), data->mIO);
                      command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
                      if (command->mWaitStatus) {
                          command->mCond.signal();
@@ -643,7 +713,8 @@
                      }break;
                 case SET_VOICE_VOLUME: {
                     VoiceVolumeData *data = (VoiceVolumeData *)command->mParam;
-                    LOGV("AudioCommandThread() processing set voice volume volume %f", data->mVolume);
+                    LOGV("AudioCommandThread() processing set voice volume volume %f",
+                            data->mVolume);
                     command->mStatus = AudioSystem::setVoiceVolume(data->mVolume);
                     if (command->mWaitStatus) {
                         command->mCond.signal();
@@ -734,7 +805,10 @@
     mWaitWorkCV.signal();
 }
 
-status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float volume, int output, int delayMs)
+status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream,
+                                                               float volume,
+                                                               int output,
+                                                               int delayMs)
 {
     status_t status = NO_ERROR;
 
@@ -752,7 +826,8 @@
     }
     Mutex::Autolock _l(mLock);
     insertCommand_l(command, delayMs);
-    LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d", stream, volume, output);
+    LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d",
+            stream, volume, output);
     mWaitWorkCV.signal();
     if (command->mWaitStatus) {
         command->mCond.wait(mLock);
@@ -762,7 +837,9 @@
     return status;
 }
 
-status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle, const String8& keyValuePairs, int delayMs)
+status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle,
+                                                                   const String8& keyValuePairs,
+                                                                   int delayMs)
 {
     status_t status = NO_ERROR;
 
@@ -779,7 +856,8 @@
     }
     Mutex::Autolock _l(mLock);
     insertCommand_l(command, delayMs);
-    LOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d", keyValuePairs.string(), ioHandle, delayMs);
+    LOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d",
+            keyValuePairs.string(), ioHandle, delayMs);
     mWaitWorkCV.signal();
     if (command->mWaitStatus) {
         command->mCond.wait(mLock);
@@ -840,7 +918,8 @@
             ParametersData *data = (ParametersData *)command->mParam;
             ParametersData *data2 = (ParametersData *)command2->mParam;
             if (data->mIO != data2->mIO) break;
-            LOGV("Comparing parameter command %s to new command %s", data2->mKeyValuePairs.string(), data->mKeyValuePairs.string());
+            LOGV("Comparing parameter command %s to new command %s",
+                    data2->mKeyValuePairs.string(), data->mKeyValuePairs.string());
             AudioParameter param = AudioParameter(data->mKeyValuePairs);
             AudioParameter param2 = AudioParameter(data2->mKeyValuePairs);
             for (size_t j = 0; j < param.size(); j++) {
@@ -872,7 +951,8 @@
             VolumeData *data2 = (VolumeData *)command2->mParam;
             if (data->mIO != data2->mIO) break;
             if (data->mStream != data2->mStream) break;
-            LOGV("Filtering out volume command on output %d for stream %d", data->mIO, data->mStream);
+            LOGV("Filtering out volume command on output %d for stream %d",
+                    data->mIO, data->mStream);
             removedCommands.add(command2);
         } break;
         case START_TONE:
@@ -896,7 +976,8 @@
     removedCommands.clear();
 
     // insert command at the right place according to its time stamp
-    LOGV("inserting command: %d at index %d, num commands %d", command->mCommand, (int)i+1, mAudioCommands.size());
+    LOGV("inserting command: %d at index %d, num commands %d",
+            command->mCommand, (int)i+1, mAudioCommands.size());
     mAudioCommands.insertAt(command, i + 1);
 }
 
diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h
index a13d0bd..558f455 100644
--- a/services/audioflinger/AudioPolicyService.h
+++ b/services/audioflinger/AudioPolicyService.h
@@ -28,7 +28,8 @@
 
 // ----------------------------------------------------------------------------
 
-class AudioPolicyService: public BnAudioPolicyService, public AudioPolicyClientInterface, public IBinder::DeathRecipient
+class AudioPolicyService: public BnAudioPolicyService, public AudioPolicyClientInterface,
+    public IBinder::DeathRecipient
 {
 
 public:
@@ -43,8 +44,9 @@
     virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device,
                                               AudioSystem::device_connection_state state,
                                               const char *device_address);
-    virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device,
-                                                                          const char *device_address);
+    virtual AudioSystem::device_connection_state getDeviceConnectionState(
+                                                                AudioSystem::audio_devices device,
+                                                                const char *device_address);
     virtual status_t setPhoneState(int state);
     virtual status_t setRingerMode(uint32_t mode, uint32_t mask);
     virtual status_t setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
@@ -53,15 +55,21 @@
                                         uint32_t samplingRate = 0,
                                         uint32_t format = AudioSystem::FORMAT_DEFAULT,
                                         uint32_t channels = 0,
-                                        AudioSystem::output_flags flags = AudioSystem::OUTPUT_FLAG_INDIRECT);
-    virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
-    virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+                                        AudioSystem::output_flags flags =
+                                                AudioSystem::OUTPUT_FLAG_INDIRECT);
+    virtual status_t startOutput(audio_io_handle_t output,
+                                 AudioSystem::stream_type stream,
+                                 int session = 0);
+    virtual status_t stopOutput(audio_io_handle_t output,
+                                AudioSystem::stream_type stream,
+                                int session = 0);
     virtual void releaseOutput(audio_io_handle_t output);
     virtual audio_io_handle_t getInput(int inputSource,
                                     uint32_t samplingRate = 0,
                                     uint32_t format = AudioSystem::FORMAT_DEFAULT,
                                     uint32_t channels = 0,
-                                    AudioSystem::audio_in_acoustics acoustics = (AudioSystem::audio_in_acoustics)0);
+                                    AudioSystem::audio_in_acoustics acoustics =
+                                            (AudioSystem::audio_in_acoustics)0);
     virtual status_t startInput(audio_io_handle_t input);
     virtual status_t stopInput(audio_io_handle_t input);
     virtual void releaseInput(audio_io_handle_t input);
@@ -71,6 +79,16 @@
     virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index);
     virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index);
 
+    virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream);
+
+    virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc);
+    virtual status_t registerEffect(effect_descriptor_t *desc,
+                                    audio_io_handle_t output,
+                                    uint32_t strategy,
+                                    int session,
+                                    int id);
+    virtual status_t unregisterEffect(int id);
+
     virtual     status_t    onTransact(
                                 uint32_t code,
                                 const Parcel& data,
@@ -89,7 +107,8 @@
                                     uint32_t *pChannels,
                                     uint32_t *pLatencyMs,
                                     AudioSystem::output_flags flags);
-    virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2);
+    virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
+                                                  audio_io_handle_t output2);
     virtual status_t closeOutput(audio_io_handle_t output);
     virtual status_t suspendOutput(audio_io_handle_t output);
     virtual status_t restoreOutput(audio_io_handle_t output);
@@ -99,13 +118,21 @@
                                     uint32_t *pChannels,
                                     uint32_t acoustics);
     virtual status_t closeInput(audio_io_handle_t input);
-    virtual status_t setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs = 0);
+    virtual status_t setStreamVolume(AudioSystem::stream_type stream,
+                                     float volume,
+                                     audio_io_handle_t output,
+                                     int delayMs = 0);
     virtual status_t setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output);
-    virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs = 0);
+    virtual void setParameters(audio_io_handle_t ioHandle,
+                               const String8& keyValuePairs,
+                               int delayMs = 0);
     virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys);
     virtual status_t startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream);
     virtual status_t stopTone();
     virtual status_t setVoiceVolume(float volume, int delayMs = 0);
+    virtual status_t moveEffects(int session,
+                                     audio_io_handle_t srcOutput,
+                                     audio_io_handle_t dstOutput);
 
 private:
                         AudioPolicyService();