Audio framework: support for audio pre processing

Audio effect framework is extended to suport effects on
output and input audio path.

AudioFlinger: Support for audio effects and effect chains is
moved from PlaybackThread class to ThreadBase class so that
RecordThread can manage effects.
Effects of type pre processing are allowed on record thread
only. When a pre processing is enabled, the effect interface handle is
passed down to the input stream so that the audio HAL can call the
process function. The record thread loop calls the effect chain process
function that will only manage the effect state and commands and skip the
process function.

AudioRecord: The audio session is allocated before calling getInput() into
audio policy serice so that the session is known before the input theead is
created and pre processings can be created on the correct session.

AudioPolicyService: default pre processing for a given input source are
loaded from audio_effects.conf file.
When an input is created, corresponding effects are created and enabled.

Change-Id: Id17119e0979b4dcf189b5c7957fec30dc3478790
diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h
index dd93fd8..496b23e 100644
--- a/include/media/AudioEffect.h
+++ b/include/media/AudioEffect.h
@@ -188,7 +188,7 @@
      * sessionID:   audio session this effect is associated to. If 0, the effect will be global to
      *      the output mix. If not 0, the effect will be applied to all players
      *      (AudioTrack or MediaPLayer) within the same audio session.
-     * output:  HAL audio output stream to which this effect must be attached. Leave at 0 for
+     * io:  HAL audio output or input stream to which this effect must be attached. Leave at 0 for
      *      automatic output selection by AudioFlinger.
      */
 
@@ -198,7 +198,7 @@
                   effect_callback_t cbf = 0,
                   void* user = 0,
                   int sessionId = 0,
-                  audio_io_handle_t output = 0
+                  audio_io_handle_t io = 0
                   );
 
     /* Constructor.
@@ -210,7 +210,7 @@
                     effect_callback_t cbf = 0,
                     void* user = 0,
                     int sessionId = 0,
-                    audio_io_handle_t output = 0
+                    audio_io_handle_t io = 0
                     );
 
     /* Terminates the AudioEffect and unregisters it from AudioFlinger.
@@ -232,7 +232,7 @@
                             effect_callback_t cbf = 0,
                             void* user = 0,
                             int sessionId = 0,
-                            audio_io_handle_t output = 0
+                            audio_io_handle_t io = 0
                             );
 
     /* Result of constructing the AudioEffect. This must be checked
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 89213b7..f20e234 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -160,7 +160,8 @@
                                     uint32_t samplingRate = 0,
                                     uint32_t format = AUDIO_FORMAT_DEFAULT,
                                     uint32_t channels = AUDIO_CHANNEL_IN_MONO,
-                                    audio_in_acoustics_t acoustics = (audio_in_acoustics_t)0);
+                                    audio_in_acoustics_t acoustics = (audio_in_acoustics_t)0,
+                                    int sessionId = 0);
     static status_t startInput(audio_io_handle_t input);
     static status_t stopInput(audio_io_handle_t input);
     static void releaseInput(audio_io_handle_t input);
@@ -175,7 +176,7 @@
 
     static audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc);
     static status_t registerEffect(effect_descriptor_t *desc,
-                                    audio_io_handle_t output,
+                                    audio_io_handle_t io,
                                     uint32_t strategy,
                                     int session,
                                     int id);
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 0fc8dbf..86b9f85 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -65,7 +65,8 @@
                                     uint32_t samplingRate = 0,
                                     uint32_t format = AUDIO_FORMAT_DEFAULT,
                                     uint32_t channels = 0,
-                                    audio_in_acoustics_t acoustics = (audio_in_acoustics_t)0) = 0;
+                                    audio_in_acoustics_t acoustics = (audio_in_acoustics_t)0,
+                                    int audioSession = 0) = 0;
     virtual status_t startInput(audio_io_handle_t input) = 0;
     virtual status_t stopInput(audio_io_handle_t input) = 0;
     virtual void releaseInput(audio_io_handle_t input) = 0;
@@ -78,7 +79,7 @@
     virtual uint32_t getDevicesForStream(audio_stream_type_t 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,
+                                    audio_io_handle_t io,
                                     uint32_t strategy,
                                     int session,
                                     int id) = 0;
diff --git a/media/libeffects/data/audio_effects.conf b/media/libeffects/data/audio_effects.conf
index e6a7b37..b8fa487 100644
--- a/media/libeffects/data/audio_effects.conf
+++ b/media/libeffects/data/audio_effects.conf
@@ -1,5 +1,10 @@
 # List of effect libraries to load. Each library element must contain a "path" element
 # giving the full path of the library .so file.
+#    libraries {
+#        <lib name> {
+#          path <lib path>
+#        }
+#    }
 libraries {
   bundle {
     path /system/lib/soundfx/libbundlewrapper.so
@@ -10,6 +15,9 @@
   visualizer {
     path /system/lib/soundfx/libvisualizer.so
   }
+  pre_processing {
+    path /system/lib/soundfx/libaudiopreprocessing.so
+  }
 }
 
 # list of effects to load. Each effect element must contain a "library" and a "uuid" element.
@@ -17,6 +25,16 @@
 # "libraries" element.
 # The name of the effect element is indicative, only the value of the "uuid" element
 # designates the effect.
+# The uuid is the implementation specific UUID as specified by the effect vendor. This is not the
+# generic effect type UUID.
+#    effects {
+#        <fx name> {
+#            library <lib name>
+#            uuid <effect uuid>
+#        }
+#        ...
+#    }
+
 effects {
   bassboost {
     library bundle
@@ -54,4 +72,55 @@
     library visualizer
     uuid d069d9e0-8329-11df-9168-0002a5d5c51b
   }
+  agc {
+    library pre_processing
+    uuid aa8130e0-66fc-11e0-bad0-0002a5d5c51b
+  }
+  aec {
+    library pre_processing
+    uuid bb392ec0-8d4d-11e0-a896-0002a5d5c51b
+  }
+  ns {
+    library pre_processing
+    uuid c06c8400-8e06-11e0-9cb6-0002a5d5c51b
+  }
 }
+# Audio preprocessor configurations.
+# The pre processor configuration consists in a list of elements each describing
+# pre processor settings for a given input source. Valid input source names are:
+# "mic", "camcorder", "voice_recognition", "voice_communication"
+# Each input source element contains a list of effects elements. The name of the effect
+# element must be the name of one of the effects in the "effects" list of the file.
+# Each effect element may optionally contain a list of parameters and their
+# default value to apply when the pre processor effect is created.
+# A parameter is defined by a "param" element and a "value" element. Each of these elements
+# consists in one or more elements specifying a type followed by a value.
+# The types defined are: "int", "short", "float", "bool" and "string"
+# When both "param" and "value" are a single int, a simple form is allowed where just
+# the param and value pair is present in the parameter description
+#    pre_processing {
+#        <input source name> {
+#            <fx name> {
+#                <param 1 name> {
+#                    param {
+#                        int|short|float|bool|string <value>
+#                        [ int|short|float|bool|string <value> ]
+#                        ...
+#                    }
+#                    value {
+#                        int|short|float|bool|string <value>
+#                        [ int|short|float|bool|string <value> ]
+#                        ...
+#                    }
+#                }
+#                <param 2 name > {<param> <value>}
+#                ...
+#            }
+#            ...
+#        }
+#        ...
+#    }
+
+#
+# TODO: add default audio pre processor configurations after debug and tuning phase
+#
diff --git a/media/libeffects/factory/Android.mk b/media/libeffects/factory/Android.mk
index 26265ae..2f2b974 100644
--- a/media/libeffects/factory/Android.mk
+++ b/media/libeffects/factory/Android.mk
@@ -14,4 +14,7 @@
 
 LOCAL_SHARED_LIBRARIES += libdl
 
+LOCAL_C_INCLUDES := \
+    system/media/audio_effects/include
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index a9689bc..d333510 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -24,6 +24,7 @@
 
 #include <cutils/misc.h>
 #include <cutils/config_utils.h>
+#include <audio_effects/audio_effects_conf.h>
 
 static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects
 static list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries
diff --git a/media/libeffects/factory/EffectsFactory.h b/media/libeffects/factory/EffectsFactory.h
index fcc0dba..c1d4319 100644
--- a/media/libeffects/factory/EffectsFactory.h
+++ b/media/libeffects/factory/EffectsFactory.h
@@ -26,13 +26,6 @@
 extern "C" {
 #endif
 
-#define AUDIO_EFFECT_DEFAULT_CONFIG_FILE "/system/etc/audio_effects.conf"
-#define AUDIO_EFFECT_VENDOR_CONFIG_FILE "/vendor/etc/audio_effects.conf"
-#define EFFECTS_TAG "effects"
-#define LIBRARIES_TAG "libraries"
-#define PATH_TAG "path"
-#define LIBRARY_TAG "library"
-#define UUID_TAG "uuid"
 
 typedef struct list_elem_s {
     void *object;
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 8d98900..3919551 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -47,11 +47,11 @@
                 effect_callback_t cbf,
                 void* user,
                 int sessionId,
-                audio_io_handle_t output
+                audio_io_handle_t io
                 )
     : mStatus(NO_INIT)
 {
-    mStatus = set(type, uuid, priority, cbf, user, sessionId, output);
+    mStatus = set(type, uuid, priority, cbf, user, sessionId, io);
 }
 
 AudioEffect::AudioEffect(const char *typeStr,
@@ -60,7 +60,7 @@
                 effect_callback_t cbf,
                 void* user,
                 int sessionId,
-                audio_io_handle_t output
+                audio_io_handle_t io
                 )
     : mStatus(NO_INIT)
 {
@@ -83,7 +83,7 @@
         }
     }
 
-    mStatus = set(pType, pUuid, priority, cbf, user, sessionId, output);
+    mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io);
 }
 
 status_t AudioEffect::set(const effect_uuid_t *type,
@@ -92,13 +92,13 @@
                 effect_callback_t cbf,
                 void* user,
                 int sessionId,
-                audio_io_handle_t output)
+                audio_io_handle_t io)
 {
     sp<IEffect> iEffect;
     sp<IMemory> cblk;
     int enabled;
 
-    LOGV("set %p mUserData: %p", this, user);
+    LOGV("set %p mUserData: %p uuid: %p timeLow %08x", this, user, type, type ? type->timeLow : 0);
 
     if (mIEffect != 0) {
         LOGW("Effect already in use");
@@ -135,7 +135,7 @@
     mIEffectClient = new EffectClient(this);
 
     iEffect = audioFlinger->createEffect(getpid(), (effect_descriptor_t *)&mDescriptor,
-            mIEffectClient, priority, output, mSessionId, &mStatus, &mId, &enabled);
+            mIEffectClient, priority, io, mSessionId, &mStatus, &mId, &enabled);
 
     if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
         LOGE("set(): AudioFlinger could not create effect, status: %d", mStatus);
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 4c4aad0..1ec596e 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -162,8 +162,19 @@
 
     int channelCount = popcount(channelMask);
 
+    if (sessionId == 0 ) {
+        mSessionId = AudioSystem::newAudioSessionId();
+    } else {
+        mSessionId = sessionId;
+    }
+    LOGV("set(): mSessionId %d", mSessionId);
+
     audio_io_handle_t input = AudioSystem::getInput(inputSource,
-                                    sampleRate, format, channelMask, (audio_in_acoustics_t)flags);
+                                                    sampleRate,
+                                                    format,
+                                                    channelMask,
+                                                    (audio_in_acoustics_t)flags,
+                                                    mSessionId);
     if (input == 0) {
         LOGE("Could not get audio input for record source %d", inputSource);
         return BAD_VALUE;
@@ -187,8 +198,6 @@
         notificationFrames = frameCount/2;
     }
 
-    mSessionId = sessionId;
-
     // create the IAudioRecord
     status = openRecord_l(sampleRate, format, channelMask,
                         frameCount, flags, input);
@@ -589,8 +598,10 @@
 {
     mInput = AudioSystem::getInput(mInputSource,
                                 mCblk->sampleRate,
-                                mFormat, mChannelMask,
-                                (audio_in_acoustics_t)mFlags);
+                                mFormat,
+                                mChannelMask,
+                                (audio_in_acoustics_t)mFlags,
+                                mSessionId);
     return mInput;
 }
 
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 6cb3847..5009957 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -605,11 +605,12 @@
                                     uint32_t samplingRate,
                                     uint32_t format,
                                     uint32_t channels,
-                                    audio_in_acoustics_t acoustics)
+                                    audio_in_acoustics_t acoustics,
+                                    int sessionId)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return 0;
-    return aps->getInput(inputSource, samplingRate, format, channels, acoustics);
+    return aps->getInput(inputSource, samplingRate, format, channels, acoustics, sessionId);
 }
 
 status_t AudioSystem::startInput(audio_io_handle_t input)
@@ -678,14 +679,14 @@
 }
 
 status_t AudioSystem::registerEffect(effect_descriptor_t *desc,
-                                audio_io_handle_t output,
+                                audio_io_handle_t io,
                                 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);
+    return aps->registerEffect(desc, io, strategy, session, id);
 }
 
 status_t AudioSystem::unregisterEffect(int id)
@@ -695,9 +696,11 @@
     return aps->unregisterEffect(id);
 }
 
-status_t AudioSystem::isStreamActive(int stream, bool* state, uint32_t inPastMs) {
+status_t AudioSystem::isStreamActive(int stream, bool* state, uint32_t inPastMs)
+{
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
+    if (state == NULL) return BAD_VALUE;
     *state = aps->isStreamActive(stream, inPastMs);
     return NO_ERROR;
 }
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 9fbcee0..49d410f 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -184,7 +184,8 @@
                                     uint32_t samplingRate,
                                     uint32_t format,
                                     uint32_t channels,
-                                    audio_in_acoustics_t acoustics)
+                                    audio_in_acoustics_t acoustics,
+                                    int audioSession)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
@@ -193,6 +194,7 @@
         data.writeInt32(static_cast <uint32_t>(format));
         data.writeInt32(channels);
         data.writeInt32(static_cast <uint32_t>(acoustics));
+        data.writeInt32(audioSession);
         remote()->transact(GET_INPUT, data, &reply);
         return static_cast <audio_io_handle_t> (reply.readInt32());
     }
@@ -285,7 +287,7 @@
     }
 
     virtual status_t registerEffect(effect_descriptor_t *desc,
-                                        audio_io_handle_t output,
+                                        audio_io_handle_t io,
                                         uint32_t strategy,
                                         int session,
                                         int id)
@@ -293,7 +295,7 @@
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
         data.write(desc, sizeof(effect_descriptor_t));
-        data.writeInt32(output);
+        data.writeInt32(io);
         data.writeInt32(strategy);
         data.writeInt32(session);
         data.writeInt32(id);
@@ -439,11 +441,13 @@
             uint32_t channels = data.readInt32();
             audio_in_acoustics_t acoustics =
                     static_cast <audio_in_acoustics_t>(data.readInt32());
+            int audioSession = data.readInt32();
             audio_io_handle_t input = getInput(inputSource,
                                                samplingRate,
                                                format,
                                                channels,
-                                               acoustics);
+                                               acoustics,
+                                               audioSession);
             reply->writeInt32(static_cast <int>(input));
             return NO_ERROR;
         } break;
@@ -528,12 +532,12 @@
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             effect_descriptor_t desc;
             data.read(&desc, sizeof(effect_descriptor_t));
-            audio_io_handle_t output = data.readInt32();
+            audio_io_handle_t io = data.readInt32();
             uint32_t strategy = data.readInt32();
             int session = data.readInt32();
             int id = data.readInt32();
             reply->writeInt32(static_cast <int32_t>(registerEffect(&desc,
-                                                                   output,
+                                                                   io,
                                                                    strategy,
                                                                    session,
                                                                    id)));
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 86d4cc3..482336b 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -81,6 +81,8 @@
 
 static const nsecs_t kWarningThrottle = seconds(5);
 
+// RecordThread loop sleep time upon application overrun or audio HAL read error
+static const int kRecordThreadSleepUs = 5000;
 
 // ----------------------------------------------------------------------------
 
@@ -417,7 +419,7 @@
             lSessionId = *sessionId;
         } else {
             // if no audio session id is provided, create one here
-            lSessionId = nextUniqueId_l();
+            lSessionId = nextUniqueId();
             if (sessionId != NULL) {
                 *sessionId = lSessionId;
             }
@@ -725,6 +727,15 @@
         thread = checkPlaybackThread_l(ioHandle);
         if (thread == NULL) {
             thread = checkRecordThread_l(ioHandle);
+        } else if (thread.get() == primaryPlaybackThread_l()) {
+            // indicate output device change to all input threads for pre processing
+            AudioParameter param = AudioParameter(keyValuePairs);
+            int value;
+            if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
+                for (size_t i = 0; i < mRecordThreads.size(); i++) {
+                    mRecordThreads.valueAt(i)->setParameters(keyValuePairs);
+                }
+            }
         }
     }
     if (thread != NULL) {
@@ -873,10 +884,10 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id)
+AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id, uint32_t device)
     :   Thread(false),
         mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0),
-        mFrameSize(1), mFormat(0), mStandby(false), mId(id), mExiting(false)
+        mFrameSize(1), mFormat(0), mStandby(false), mId(id), mExiting(false), mDevice(device)
 {
 }
 
@@ -1032,14 +1043,15 @@
     return NO_ERROR;
 }
 
-
 // ----------------------------------------------------------------------------
 
-AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
-    :   ThreadBase(audioFlinger, id),
+AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
+                                             AudioStreamOut* output,
+                                             int id,
+                                             uint32_t device)
+    :   ThreadBase(audioFlinger, id, device),
         mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output),
-        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
-        mDevice(device)
+        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)
 {
     readOutputParameters();
 
@@ -1199,9 +1211,9 @@
         }
     }
 
-    if (mOutput == 0) {
+    lStatus = initCheck();
+    if (lStatus != NO_ERROR) {
         LOGE("Audio driver not initialized.");
-        lStatus = NO_INIT;
         goto Exit;
     }
 
@@ -1423,7 +1435,7 @@
     if (halFrames == 0 || dspFrames == 0) {
         return BAD_VALUE;
     }
-    if (mOutput == 0) {
+    if (initCheck() != NO_ERROR) {
         return INVALID_OPERATION;
     }
     *halFrames = mBytesWritten / audio_stream_frame_size(&mOutput->stream->common);
@@ -1468,34 +1480,6 @@
     return AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
 }
 
-sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain(int sessionId)
-{
-    Mutex::Autolock _l(mLock);
-    return getEffectChain_l(sessionId);
-}
-
-sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain_l(int sessionId)
-{
-    sp<EffectChain> chain;
-
-    size_t size = mEffectChains.size();
-    for (size_t i = 0; i < size; i++) {
-        if (mEffectChains[i]->sessionId() == sessionId) {
-            chain = mEffectChains[i];
-            break;
-        }
-    }
-    return chain;
-}
-
-void AudioFlinger::PlaybackThread::setMode(uint32_t mode)
-{
-    Mutex::Autolock _l(mLock);
-    size_t size = mEffectChains.size();
-    for (size_t i = 0; i < size; i++) {
-        mEffectChains[i]->setMode_l(mode);
-    }
-}
 
 // ----------------------------------------------------------------------------
 
@@ -1503,7 +1487,7 @@
     :   PlaybackThread(audioFlinger, output, id, device),
         mAudioMixer(0)
 {
-    mType = PlaybackThread::MIXER;
+    mType = ThreadBase::MIXER;
     mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
 
     // FIXME - Current mixer implementation only supports stereo output
@@ -2072,7 +2056,7 @@
 AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
     :   PlaybackThread(audioFlinger, output, id, device)
 {
-    mType = PlaybackThread::DIRECT;
+    mType = ThreadBase::DIRECT;
 }
 
 AudioFlinger::DirectOutputThread::~DirectOutputThread()
@@ -2551,7 +2535,7 @@
 AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread, int id)
     :   MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->device()), mWaitTimeMs(UINT_MAX)
 {
-    mType = PlaybackThread::DUPLICATING;
+    mType = ThreadBase::DUPLICATING;
     addOutputTrack(mainThread);
 }
 
@@ -3751,21 +3735,26 @@
         if (sessionId != NULL && *sessionId != AUDIO_SESSION_OUTPUT_MIX) {
             lSessionId = *sessionId;
         } else {
-            lSessionId = nextUniqueId_l();
+            lSessionId = nextUniqueId();
             if (sessionId != NULL) {
                 *sessionId = lSessionId;
             }
         }
         // create new record track. The record track uses one track in mHardwareMixerThread by convention.
-        recordTrack = new RecordThread::RecordTrack(thread, client, sampleRate,
-                                                   format, channelMask, frameCount, flags, lSessionId);
+        recordTrack = thread->createRecordTrack_l(client,
+                                                sampleRate,
+                                                format,
+                                                channelMask,
+                                                frameCount,
+                                                flags,
+                                                lSessionId,
+                                                &lStatus);
     }
-    if (recordTrack->getCblk() == NULL) {
+    if (lStatus != NO_ERROR) {
         // remove local strong reference to Client before deleting the RecordTrack so that the Client
         // destructor is called by the TrackBase destructor with mLock held
         client.clear();
         recordTrack.clear();
-        lStatus = NO_MEMORY;
         goto Exit;
     }
 
@@ -3814,10 +3803,16 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, AudioStreamIn *input, uint32_t sampleRate, uint32_t channels, int id) :
-    ThreadBase(audioFlinger, id),
-    mInput(input), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0)
+AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
+                                         AudioStreamIn *input,
+                                         uint32_t sampleRate,
+                                         uint32_t channels,
+                                         int id,
+                                         uint32_t device) :
+    ThreadBase(audioFlinger, id, device),
+    mInput(input), mTrack(NULL), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0)
 {
+    mType = ThreadBase::RECORD;
     mReqChannelCount = popcount(channels);
     mReqSampleRate = sampleRate;
     readInputParameters();
@@ -3847,6 +3842,7 @@
 {
     AudioBufferProvider::Buffer buffer;
     sp<RecordTrack> activeTrack;
+    Vector< sp<EffectChain> > effectChains;
 
     nsecs_t lastWarning = 0;
 
@@ -3897,14 +3893,22 @@
                     mStandby = false;
                 }
             }
+            lockEffectChains_l(effectChains);
         }
 
         if (mActiveTrack != 0) {
             if (mActiveTrack->mState != TrackBase::ACTIVE &&
                 mActiveTrack->mState != TrackBase::RESUMING) {
-                usleep(5000);
+                unlockEffectChains(effectChains);
+                usleep(kRecordThreadSleepUs);
                 continue;
             }
+            for (size_t i = 0; i < effectChains.size(); i ++) {
+                effectChains[i]->process_l();
+            }
+            // enable changes in effect chain
+            unlockEffectChains(effectChains);
+
             buffer.frameCount = mFrameCount;
             if (LIKELY(mActiveTrack->getNextBuffer(&buffer) == NO_ERROR)) {
                 size_t framesOut = buffer.frameCount;
@@ -3953,7 +3957,7 @@
                                     // Force input into standby so that it tries to
                                     // recover at next read attempt
                                     mInput->stream->common.standby(&mInput->stream->common);
-                                    usleep(5000);
+                                    usleep(kRecordThreadSleepUs);
                                 }
                                 mRsmpInIndex = mFrameCount;
                                 framesOut = 0;
@@ -4001,9 +4005,12 @@
                 // Release the processor for a while before asking for a new buffer.
                 // This will give the application more chance to read from the buffer and
                 // clear the overflow.
-                usleep(5000);
+                usleep(kRecordThreadSleepUs);
             }
+        } else {
+            unlockEffectChains(effectChains);
         }
+        effectChains.clear();
     }
 
     if (!mStandby) {
@@ -4017,6 +4024,49 @@
     return false;
 }
 
+
+sp<AudioFlinger::RecordThread::RecordTrack>  AudioFlinger::RecordThread::createRecordTrack_l(
+        const sp<AudioFlinger::Client>& client,
+        uint32_t sampleRate,
+        int format,
+        int channelMask,
+        int frameCount,
+        uint32_t flags,
+        int sessionId,
+        status_t *status)
+{
+    sp<RecordTrack> track;
+    status_t lStatus;
+
+    lStatus = initCheck();
+    if (lStatus != NO_ERROR) {
+        LOGE("Audio driver not initialized.");
+        goto Exit;
+    }
+
+    { // scope for mLock
+        Mutex::Autolock _l(mLock);
+
+        track = new RecordTrack(this, client, sampleRate,
+                      format, channelMask, frameCount, flags, sessionId);
+
+        if (track->getCblk() == NULL) {
+            lStatus = NO_MEMORY;
+            goto Exit;
+        }
+
+        mTrack = track.get();
+
+    }
+    lStatus = NO_ERROR;
+
+Exit:
+    if (status) {
+        *status = lStatus;
+    }
+    return track;
+}
+
 status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack)
 {
     LOGV("RecordThread::start");
@@ -4146,7 +4196,7 @@
                 // Force input into standby so that it tries to
                 // recover at next read attempt
                 mInput->stream->common.standby(&mInput->stream->common);
-                usleep(5000);
+                usleep(kRecordThreadSleepUs);
             }
             buffer->raw = 0;
             buffer->frameCount = 0;
@@ -4211,6 +4261,23 @@
                 reconfig = true;
             }
         }
+        if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
+            // forward device change to effects that have requested to be
+            // aware of attached audio device.
+            for (size_t i = 0; i < mEffectChains.size(); i++) {
+                mEffectChains[i]->setDevice_l(value);
+            }
+            // store input device and output device but do not forward output device to audio HAL.
+            // Note that status is ignored by the caller for output device
+            // (see AudioFlinger::setParameters()
+            if (value & AUDIO_DEVICE_OUT_ALL) {
+                mDevice &= (uint32_t)~(value & AUDIO_DEVICE_OUT_ALL);
+                status = BAD_VALUE;
+            } else {
+                mDevice &= (uint32_t)~(value & AUDIO_DEVICE_IN_ALL);
+            }
+            mDevice |= (uint32_t)value;
+        }
         if (status == NO_ERROR) {
             status = mInput->stream->common.set_parameters(&mInput->stream->common, keyValuePair.string());
             if (status == INVALID_OPERATION) {
@@ -4320,6 +4387,21 @@
     return mInput->stream->get_input_frames_lost(mInput->stream);
 }
 
+uint32_t AudioFlinger::RecordThread::hasAudioSession(int sessionId)
+{
+    Mutex::Autolock _l(mLock);
+    uint32_t result = 0;
+    if (getEffectChain_l(sessionId) != 0) {
+        result = EFFECT_SESSION;
+    }
+
+    if (mTrack != NULL && sessionId == mTrack->sessionId()) {
+        result |= TRACK_SESSION;
+    }
+
+    return result;
+}
+
 // ----------------------------------------------------------------------------
 
 int AudioFlinger::openOutput(uint32_t *pDevices,
@@ -4368,7 +4450,7 @@
     mHardwareStatus = AUDIO_HW_IDLE;
     if (outStream != NULL) {
         AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream);
-        int id = nextUniqueId_l();
+        int id = nextUniqueId();
 
         if ((flags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT) ||
             (format != AUDIO_FORMAT_PCM_16_BIT) ||
@@ -4405,7 +4487,7 @@
         return 0;
     }
 
-    int id = nextUniqueId_l();
+    int id = nextUniqueId();
     DuplicatingThread *thread = new DuplicatingThread(this, thread1, id);
     thread->addOutputTrack(thread2);
     mPlaybackThreads.add(id, thread);
@@ -4428,9 +4510,9 @@
 
         LOGV("closeOutput() %d", output);
 
-        if (thread->type() == PlaybackThread::MIXER) {
+        if (thread->type() == ThreadBase::MIXER) {
             for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-                if (mPlaybackThreads.valueAt(i)->type() == PlaybackThread::DUPLICATING) {
+                if (mPlaybackThreads.valueAt(i)->type() == ThreadBase::DUPLICATING) {
                     DuplicatingThread *dupThread = (DuplicatingThread *)mPlaybackThreads.valueAt(i).get();
                     dupThread->removeOutputTrack((MixerThread *)thread.get());
                 }
@@ -4442,7 +4524,7 @@
     }
     thread->exit();
 
-    if (thread->type() != PlaybackThread::DUPLICATING) {
+    if (thread->type() != ThreadBase::DUPLICATING) {
         AudioStreamOut *out = thread->getOutput();
         out->hwDev->close_output_stream(out->hwDev, out->stream);
         delete out;
@@ -4537,9 +4619,17 @@
     if (inStream != NULL) {
         AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream);
 
-        int id = nextUniqueId_l();
-         // Start record thread
-        thread = new RecordThread(this, input, reqSamplingRate, reqChannels, id);
+        int id = nextUniqueId();
+        // Start record thread
+        // RecorThread require both input and output device indication to forward to audio
+        // pre processing modules
+        uint32_t device = (*pDevices) | primaryOutputDevice_l();
+        thread = new RecordThread(this,
+                                  input,
+                                  reqSamplingRate,
+                                  reqChannels,
+                                  id,
+                                  device);
         mRecordThreads.add(id, thread);
         LOGV("openInput() created record thread: ID %d thread %p", id, thread);
         if (pSamplingRate) *pSamplingRate = reqSamplingRate;
@@ -4597,7 +4687,7 @@
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
         PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
         if (thread != dstThread &&
-            thread->type() != PlaybackThread::DIRECT) {
+            thread->type() != ThreadBase::DIRECT) {
             MixerThread *srcThread = (MixerThread *)thread;
             srcThread->invalidateTracks(stream);
         }
@@ -4609,8 +4699,7 @@
 
 int AudioFlinger::newAudioSessionId()
 {
-    AutoMutex _l(mLock);
-    return nextUniqueId_l();
+    return nextUniqueId();
 }
 
 // checkPlaybackThread_l() must be called with AudioFlinger::mLock held
@@ -4628,7 +4717,7 @@
 {
     PlaybackThread *thread = checkPlaybackThread_l(output);
     if (thread != NULL) {
-        if (thread->type() == PlaybackThread::DIRECT) {
+        if (thread->type() == ThreadBase::DIRECT) {
             thread = NULL;
         }
     }
@@ -4645,12 +4734,34 @@
     return thread;
 }
 
-// nextUniqueId_l() must be called with AudioFlinger::mLock held
-int AudioFlinger::nextUniqueId_l()
+uint32_t AudioFlinger::nextUniqueId()
 {
-    return mNextUniqueId++;
+    return android_atomic_inc(&mNextUniqueId);
 }
 
+AudioFlinger::PlaybackThread *AudioFlinger::primaryPlaybackThread_l()
+{
+    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+        PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
+        if (thread->getOutput()->hwDev == mPrimaryHardwareDev) {
+            return thread;
+        }
+    }
+    return NULL;
+}
+
+uint32_t AudioFlinger::primaryOutputDevice_l()
+{
+    PlaybackThread *thread = primaryPlaybackThread_l();
+
+    if (thread == NULL) {
+        return 0;
+    }
+
+    return thread->device();
+}
+
+
 // ----------------------------------------------------------------------------
 //  Effect management
 // ----------------------------------------------------------------------------
@@ -4683,7 +4794,7 @@
         effect_descriptor_t *pDesc,
         const sp<IEffectClient>& effectClient,
         int32_t priority,
-        int output,
+        int io,
         int sessionId,
         status_t *status,
         int *id,
@@ -4695,8 +4806,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, io %d",
+            pid, effectClient.get(), priority, sessionId, io);
 
     if (pDesc == NULL) {
         lStatus = BAD_VALUE;
@@ -4724,7 +4835,7 @@
         goto Exit;
     }
 
-    if (output == 0) {
+    if (io == 0) {
         if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
             // output must be specified by AudioPolicyManager when using session
             // AUDIO_SESSION_OUTPUT_STAGE
@@ -4732,9 +4843,9 @@
             goto Exit;
         } else if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
             // if the output returned by getOutputForEffect() is removed before we lock the
-            // mutex below, the call to checkPlaybackThread_l(output) below will detect it
+            // mutex below, the call to checkPlaybackThread_l(io) below will detect it
             // and we will exit safely
-            output = AudioSystem::getOutputForEffect(&desc);
+            io = AudioSystem::getOutputForEffect(&desc);
         }
     }
 
@@ -4811,30 +4922,40 @@
         // output threads.
         // If output is 0 here, sessionId is neither SESSION_OUTPUT_STAGE nor SESSION_OUTPUT_MIX
         // because of code checking output when entering the function.
-        if (output == 0) {
+        // Note: io is never 0 when creating an effect on an input
+        if (io == 0) {
              // look for the thread where the specified audio session is present
             for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
                 if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
-                    output = mPlaybackThreads.keyAt(i);
+                    io = mPlaybackThreads.keyAt(i);
                     break;
                 }
             }
+            if (io == 0) {
+               for (size_t i = 0; i < mRecordThreads.size(); i++) {
+                   if (mRecordThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
+                       io = mRecordThreads.keyAt(i);
+                       break;
+                   }
+               }
+            }
             // If no output thread contains the requested session ID, default to
             // first output. The effect chain will be moved to the correct output
             // thread when a track with the same session ID is created
-            if (output == 0 && mPlaybackThreads.size()) {
-                output = mPlaybackThreads.keyAt(0);
+            if (io == 0 && mPlaybackThreads.size()) {
+                io = mPlaybackThreads.keyAt(0);
+            }
+            LOGV("createEffect() got io %d for effect %s", io, desc.name);
+        }
+        ThreadBase *thread = checkRecordThread_l(io);
+        if (thread == NULL) {
+            thread = checkPlaybackThread_l(io);
+            if (thread == NULL) {
+                LOGE("createEffect() unknown output thread");
+                lStatus = BAD_VALUE;
+                goto Exit;
             }
         }
-        LOGV("createEffect() got output %d for effect %s", output, desc.name);
-        PlaybackThread *thread = checkPlaybackThread_l(output);
-        if (thread == NULL) {
-            LOGE("createEffect() unknown output thread");
-            lStatus = BAD_VALUE;
-            goto Exit;
-        }
-
-        // TODO: allow attachment of effect to inputs
 
         wclient = mClients.valueFor(pid);
 
@@ -4943,8 +5064,9 @@
     return NO_ERROR;
 }
 
+
 // PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held
-sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
+sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
         const sp<AudioFlinger::Client>& client,
         const sp<IEffectClient>& effectClient,
         int32_t priority,
@@ -4957,24 +5079,14 @@
     sp<EffectModule> effect;
     sp<EffectHandle> handle;
     status_t lStatus;
-    sp<Track> track;
     sp<EffectChain> chain;
     bool chainCreated = false;
     bool effectCreated = false;
     bool effectRegistered = false;
 
-    if (mOutput == 0) {
+    lStatus = initCheck();
+    if (lStatus != NO_ERROR) {
         LOGW("createEffect_l() Audio driver not initialized.");
-        lStatus = NO_INIT;
-        goto Exit;
-    }
-
-    // Do not allow auxiliary effect on session other than 0
-    if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY &&
-        sessionId != AUDIO_SESSION_OUTPUT_MIX) {
-        LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d",
-                desc->name, sessionId);
-        lStatus = BAD_VALUE;
         goto Exit;
     }
 
@@ -4986,6 +5098,16 @@
         lStatus = BAD_VALUE;
         goto Exit;
     }
+    // Only Pre processor effects are allowed on input threads and only on input threads
+    if ((mType == RECORD &&
+            (desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC) ||
+            (mType != RECORD &&
+                    (desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC)) {
+        LOGW("createEffect_l() effect %s (flags %08x) created on wrong thread type %d",
+                desc->name, desc->flags, mType);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
 
     LOGV("createEffect_l() thread %p effect %s on session %d", this, desc->name, sessionId);
 
@@ -5008,7 +5130,7 @@
         LOGV("createEffect_l() got effect %p on chain %p", effect == 0 ? 0 : effect.get(), chain.get());
 
         if (effect == 0) {
-            int id = mAudioFlinger->nextUniqueId_l();
+            int id = mAudioFlinger->nextUniqueId();
             // Check CPU and memory usage
             lStatus = AudioSystem::registerEffect(desc, mId, chain->strategy(), sessionId, id);
             if (lStatus != NO_ERROR) {
@@ -5059,9 +5181,20 @@
     return handle;
 }
 
+sp<AudioFlinger::EffectModule> AudioFlinger::ThreadBase::getEffect_l(int sessionId, int effectId)
+{
+    sp<EffectModule> effect;
+
+    sp<EffectChain> chain = getEffectChain_l(sessionId);
+    if (chain != 0) {
+        effect = chain->getEffectFromId_l(effectId);
+    }
+    return effect;
+}
+
 // PlaybackThread::addEffect_l() must be called with AudioFlinger::mLock and
 // PlaybackThread::mLock held
-status_t AudioFlinger::PlaybackThread::addEffect_l(const sp<EffectModule>& effect)
+status_t AudioFlinger::ThreadBase::addEffect_l(const sp<EffectModule>& effect)
 {
     // check for existing effect chain with the requested audio session
     int sessionId = effect->sessionId();
@@ -5097,7 +5230,7 @@
     return NO_ERROR;
 }
 
-void AudioFlinger::PlaybackThread::removeEffect_l(const sp<EffectModule>& effect) {
+void AudioFlinger::ThreadBase::removeEffect_l(const sp<EffectModule>& effect) {
 
     LOGV("removeEffect_l() %p effect %p", this, effect.get());
     effect_descriptor_t desc = effect->desc();
@@ -5116,7 +5249,53 @@
     }
 }
 
-void AudioFlinger::PlaybackThread::disconnectEffect(const sp<EffectModule>& effect,
+void AudioFlinger::ThreadBase::lockEffectChains_l(
+        Vector<sp <AudioFlinger::EffectChain> >& effectChains)
+{
+    effectChains = mEffectChains;
+    for (size_t i = 0; i < mEffectChains.size(); i++) {
+        mEffectChains[i]->lock();
+    }
+}
+
+void AudioFlinger::ThreadBase::unlockEffectChains(
+        Vector<sp <AudioFlinger::EffectChain> >& effectChains)
+{
+    for (size_t i = 0; i < effectChains.size(); i++) {
+        effectChains[i]->unlock();
+    }
+}
+
+sp<AudioFlinger::EffectChain> AudioFlinger::ThreadBase::getEffectChain(int sessionId)
+{
+    Mutex::Autolock _l(mLock);
+    return getEffectChain_l(sessionId);
+}
+
+sp<AudioFlinger::EffectChain> AudioFlinger::ThreadBase::getEffectChain_l(int sessionId)
+{
+    sp<EffectChain> chain;
+
+    size_t size = mEffectChains.size();
+    for (size_t i = 0; i < size; i++) {
+        if (mEffectChains[i]->sessionId() == sessionId) {
+            chain = mEffectChains[i];
+            break;
+        }
+    }
+    return chain;
+}
+
+void AudioFlinger::ThreadBase::setMode(uint32_t mode)
+{
+    Mutex::Autolock _l(mLock);
+    size_t size = mEffectChains.size();
+    for (size_t i = 0; i < size; i++) {
+        mEffectChains[i]->setMode_l(mode);
+    }
+}
+
+void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect,
                                                     const wp<EffectHandle>& handle) {
     Mutex::Autolock _l(mLock);
     LOGV("disconnectEffect() %p effect %p", this, effect.get());
@@ -5222,35 +5401,6 @@
     return mEffectChains.size();
 }
 
-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(
-        Vector<sp <AudioFlinger::EffectChain> >& effectChains)
-{
-    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;
-
-    sp<EffectChain> chain = getEffectChain_l(sessionId);
-    if (chain != 0) {
-        effect = chain->getEffectFromId_l(effectId);
-    }
-    return effect;
-}
-
 status_t AudioFlinger::PlaybackThread::attachAuxEffect(
         const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
 {
@@ -5291,6 +5441,34 @@
     }
 }
 
+status_t AudioFlinger::RecordThread::addEffectChain_l(const sp<EffectChain>& chain)
+{
+    // only one chain per input thread
+    if (mEffectChains.size() != 0) {
+        return INVALID_OPERATION;
+    }
+    LOGV("addEffectChain_l() %p on thread %p", chain.get(), this);
+
+    chain->setInBuffer(NULL);
+    chain->setOutBuffer(NULL);
+
+    mEffectChains.add(chain);
+
+    return NO_ERROR;
+}
+
+size_t AudioFlinger::RecordThread::removeEffectChain_l(const sp<EffectChain>& chain)
+{
+    LOGV("removeEffectChain_l() %p from thread %p", chain.get(), this);
+    LOGW_IF(mEffectChains.size() != 1,
+            "removeEffectChain_l() %p invalid chain size %d on thread %p",
+            chain.get(), mEffectChains.size(), this);
+    if (mEffectChains.size() == 1) {
+        mEffectChains.removeAt(0);
+    }
+    return 0;
+}
+
 // ----------------------------------------------------------------------------
 //  EffectModule implementation
 // ----------------------------------------------------------------------------
@@ -5312,12 +5490,11 @@
     if (thread == 0) {
         return;
     }
-    PlaybackThread *p = (PlaybackThread *)thread.get();
 
     memcpy(&mDescriptor, desc, sizeof(effect_descriptor_t));
 
     // create effect engine from effect factory
-    mStatus = EffectCreate(&desc->uuid, sessionId, p->id(), &mEffectInterface);
+    mStatus = EffectCreate(&desc->uuid, sessionId, thread->id(), &mEffectInterface);
 
     if (mStatus != NO_ERROR) {
         return;
@@ -5340,6 +5517,13 @@
 {
     LOGV("Destructor %p", this);
     if (mEffectInterface != NULL) {
+        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
+                (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
+            sp<ThreadBase> thread = mThread.promote();
+            if (thread != 0) {
+                thread->stream()->remove_audio_effect(thread->stream(), mEffectInterface);
+            }
+        }
         // release effect engine
         EffectRelease(mEffectInterface);
     }
@@ -5415,8 +5599,7 @@
     {
         sp<ThreadBase> thread = mThread.promote();
         if (thread != 0) {
-            PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
-            playbackThread->disconnectEffect(keep, handle);
+            thread->disconnectEffect(keep, handle);
         }
     }
 }
@@ -5626,6 +5809,14 @@
     if (status == 0) {
         status = cmdStatus;
     }
+    if (status == 0 &&
+            ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
+             (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC)) {
+        sp<ThreadBase> thread = mThread.promote();
+        if (thread != 0) {
+            thread->stream()->add_audio_effect(thread->stream(), mEffectInterface);
+        }
+    }
     return status;
 }
 
@@ -5645,6 +5836,14 @@
     if (status == 0) {
         status = cmdStatus;
     }
+    if (status == 0 &&
+            ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
+             (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC)) {
+        sp<ThreadBase> thread = mThread.promote();
+        if (thread != 0) {
+            thread->stream()->remove_audio_effect(thread->stream(), mEffectInterface);
+        }
+    }
     return status;
 }
 
@@ -5784,17 +5983,41 @@
 {
     Mutex::Autolock _l(mLock);
     status_t status = NO_ERROR;
-    if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) {
-        status_t cmdStatus;
-        uint32_t size = sizeof(status_t);
-        status = (*mEffectInterface)->command(mEffectInterface,
-                                              EFFECT_CMD_SET_DEVICE,
-                                              sizeof(uint32_t),
-                                              &device,
-                                              &size,
-                                              &cmdStatus);
-        if (status == NO_ERROR) {
-            status = cmdStatus;
+    if (device && (mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) {
+        // audio pre processing modules on RecordThread can receive both output and
+        // input device indication in the same call
+        uint32_t dev = device & AUDIO_DEVICE_OUT_ALL;
+        if (dev) {
+            status_t cmdStatus;
+            uint32_t size = sizeof(status_t);
+
+            status = (*mEffectInterface)->command(mEffectInterface,
+                                                  EFFECT_CMD_SET_DEVICE,
+                                                  sizeof(uint32_t),
+                                                  &dev,
+                                                  &size,
+                                                  &cmdStatus);
+            if (status == NO_ERROR) {
+                status = cmdStatus;
+            }
+        }
+        dev = device & AUDIO_DEVICE_IN_ALL;
+        if (dev) {
+            status_t cmdStatus;
+            uint32_t size = sizeof(status_t);
+
+            status_t status2 = (*mEffectInterface)->command(mEffectInterface,
+                                                  EFFECT_CMD_SET_INPUT_DEVICE,
+                                                  sizeof(uint32_t),
+                                                  &dev,
+                                                  &size,
+                                                  &cmdStatus);
+            if (status2 == NO_ERROR) {
+                status2 = cmdStatus;
+            }
+            if (status == NO_ERROR) {
+                status = status2;
+            }
         }
     }
     return status;
@@ -6168,7 +6391,6 @@
         LOGW("process_l(): cannot promote mixer thread");
         return;
     }
-    PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
     bool isGlobalSession = (mSessionId == AUDIO_SESSION_OUTPUT_MIX) ||
             (mSessionId == AUDIO_SESSION_OUTPUT_STAGE);
     bool tracksOnSession = false;
@@ -6180,7 +6402,7 @@
     // will not do it
     if (tracksOnSession &&
             activeTrackCnt() == 0) {
-        size_t numSamples = playbackThread->frameCount() * playbackThread->channelCount();
+        size_t numSamples = thread->frameCount() * thread->channelCount();
         memset(mInBuffer, 0, numSamples * sizeof(int16_t));
     }
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 1fad987..fff4f06 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -157,7 +157,7 @@
                         effect_descriptor_t *pDesc,
                         const sp<IEffectClient>& effectClient,
                         int32_t priority,
-                        int output,
+                        int io,
                         int sessionId,
                         status_t *status,
                         int *id,
@@ -273,9 +273,17 @@
 
     class ThreadBase : public Thread {
     public:
-        ThreadBase (const sp<AudioFlinger>& audioFlinger, int id);
+        ThreadBase (const sp<AudioFlinger>& audioFlinger, int id, uint32_t device);
         virtual             ~ThreadBase();
 
+
+        enum type {
+            MIXER,              // Thread class is MixerThread
+            DIRECT,             // Thread class is DirectOutputThread
+            DUPLICATING,        // Thread class is DuplicatingThread
+            RECORD              // Thread class is RecordThread
+        };
+
         status_t dumpBase(int fd, const Vector<String16>& args);
 
         // base for record and playback
@@ -377,6 +385,8 @@
             int mParam;
         };
 
+        virtual     status_t    initCheck() const = 0;
+                    int         type() const { return mType; }
                     uint32_t    sampleRate() const;
                     int         channelCount() const;
                     uint32_t    format() const;
@@ -392,6 +402,60 @@
                     void        processConfigEvents();
                     int         id() const { return mId;}
                     bool        standby() { return mStandby; }
+                    uint32_t    device() { return mDevice; }
+        virtual     audio_stream_t* stream() = 0;
+
+                    sp<EffectHandle> createEffect_l(
+                                        const sp<AudioFlinger::Client>& client,
+                                        const sp<IEffectClient>& effectClient,
+                                        int32_t priority,
+                                        int sessionId,
+                                        effect_descriptor_t *desc,
+                                        int *enabled,
+                                        status_t *status);
+                    void disconnectEffect(const sp< EffectModule>& effect,
+                                          const wp<EffectHandle>& handle);
+
+                    // return values for hasAudioSession (bit field)
+                    enum effect_state {
+                        EFFECT_SESSION = 0x1,   // the audio session corresponds to at least one
+                                                // effect
+                        TRACK_SESSION = 0x2     // the audio session corresponds to at least one
+                                                // track
+                    };
+
+                    // get effect chain corresponding to session Id.
+                    sp<EffectChain> getEffectChain(int sessionId);
+                    // same as getEffectChain() but must be called with ThreadBase mutex locked
+                    sp<EffectChain> getEffectChain_l(int sessionId);
+                    // add an effect chain to the chain list (mEffectChains)
+        virtual     status_t addEffectChain_l(const sp<EffectChain>& chain) = 0;
+                    // remove an effect chain from the chain list (mEffectChains)
+        virtual     size_t removeEffectChain_l(const sp<EffectChain>& chain) = 0;
+                    // lock mall effect chains Mutexes. Must be called before releasing the
+                    // ThreadBase mutex before processing the mixer and effects. This guarantees the
+                    // integrity of the chains during the process.
+                    void lockEffectChains_l(Vector<sp <EffectChain> >& effectChains);
+                    // unlock effect chains after process
+                    void unlockEffectChains(Vector<sp <EffectChain> >& effectChains);
+                    // set audio mode to all effect chains
+                    void setMode(uint32_t mode);
+                    // get effect module with corresponding ID on specified audio session
+                    sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId);
+                    // add and effect module. Also creates the effect chain is none exists for
+                    // the effects audio session
+                    status_t addEffect_l(const sp< EffectModule>& effect);
+                    // remove and effect module. Also removes the effect chain is this was the last
+                    // effect
+                    void removeEffect_l(const sp< EffectModule>& effect);
+                    // detach all tracks connected to an auxiliary effect
+        virtual     void detachAuxEffect_l(int effectId) {}
+                    // returns either EFFECT_SESSION if effects on this audio session exist in one
+                    // chain, or TRACK_SESSION if tracks on this audio session exist, or both
+                    virtual uint32_t hasAudioSession(int sessionId) = 0;
+                    // the value returned by default implementation is not important as the
+                    // strategy is only meaningful for PlaybackThread which implements this method
+                    virtual uint32_t getStrategyForSession_l(int sessionId) { return 0; }
 
         mutable     Mutex                   mLock;
 
@@ -406,6 +470,7 @@
         friend class RecordThread;
         friend class RecordTrack;
 
+                    int                     mType;
                     Condition               mWaitWorkCV;
                     sp<AudioFlinger>        mAudioFlinger;
                     uint32_t                mSampleRate;
@@ -421,18 +486,15 @@
                     bool                    mStandby;
                     int                     mId;
                     bool                    mExiting;
+                    Vector< sp<EffectChain> > mEffectChains;
+                    uint32_t                mDevice;    // output device for PlaybackThread
+                                                        // input + output devices for RecordThread
     };
 
     // --- PlaybackThread ---
     class PlaybackThread : public ThreadBase {
     public:
 
-        enum type {
-            MIXER,
-            DIRECT,
-            DUPLICATING
-        };
-
         enum mixer_state {
             MIXER_IDLE,
             MIXER_TRACKS_ENABLED,
@@ -569,6 +631,8 @@
         virtual     status_t    readyToRun();
         virtual     void        onFirstRef();
 
+        virtual     status_t    initCheck() const { return (mOutput == 0) ? NO_INIT : NO_ERROR; }
+
         virtual     uint32_t    latency() const;
 
         virtual     status_t    setMasterVolume(float value);
@@ -595,8 +659,8 @@
                                     status_t *status);
 
                     AudioStreamOut* getOutput() { return mOutput; }
+                    virtual audio_stream_t* stream() { return &mOutput->stream->common; }
 
-        virtual     int         type() const { return mType; }
                     void        suspend() { mSuspended++; }
                     void        restore() { if (mSuspended) mSuspended--; }
                     bool        isSuspended() { return (mSuspended != 0); }
@@ -605,45 +669,16 @@
         virtual     status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
                     int16_t     *mixBuffer() { return mMixBuffer; };
 
-                    sp<EffectHandle> createEffect_l(
-                                        const sp<AudioFlinger::Client>& client,
-                                        const sp<IEffectClient>& effectClient,
-                                        int32_t priority,
-                                        int sessionId,
-                                        effect_descriptor_t *desc,
-                                        int *enabled,
-                                        status_t *status);
-                    void disconnectEffect(const sp< EffectModule>& effect,
-                                          const wp<EffectHandle>& handle);
-
-                    // return values for hasAudioSession (bit field)
-                    enum effect_state {
-                        EFFECT_SESSION = 0x1,   // the audio session corresponds to at least one
-                                                // effect
-                        TRACK_SESSION = 0x2     // the audio session corresponds to at least one
-                                                // track
-                    };
-
-                    uint32_t hasAudioSession(int sessionId);
-                    sp<EffectChain> getEffectChain(int sessionId);
-                    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(Vector<sp <EffectChain> >& effectChains);
-                    void unlockEffectChains(Vector<sp <EffectChain> >& effectChains);
-
-                    sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId);
-                    void detachAuxEffect_l(int effectId);
+        virtual     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);
-                    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);
+                    virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
+                    virtual size_t removeEffectChain_l(const sp<EffectChain>& chain);
+                    virtual uint32_t hasAudioSession(int sessionId);
+                    virtual uint32_t getStrategyForSession_l(int sessionId);
 
         struct  stream_type_t {
             stream_type_t()
@@ -656,7 +691,6 @@
         };
 
     protected:
-        int                             mType;
         int16_t*                        mMixBuffer;
         int                             mSuspended;
         int                             mBytesWritten;
@@ -688,8 +722,6 @@
 
         void        readOutputParameters();
 
-        uint32_t    device() { return mDevice; }
-
         virtual status_t    dumpInternals(int fd, const Vector<String16>& args);
         status_t    dumpTracks(int fd, const Vector<String16>& args);
         status_t    dumpEffectChains(int fd, const Vector<String16>& args);
@@ -703,8 +735,6 @@
         int                             mNumWrites;
         int                             mNumDelayedWrites;
         bool                            mInWrite;
-        Vector< sp<EffectChain> >       mEffectChains;
-        uint32_t                        mDevice;
     };
 
     class MixerThread : public PlaybackThread {
@@ -788,11 +818,13 @@
               float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }
               void audioConfigChanged_l(int event, int ioHandle, void *param2);
 
-              int  nextUniqueId_l();
+              uint32_t nextUniqueId();
               status_t moveEffectChain_l(int session,
                                      AudioFlinger::PlaybackThread *srcThread,
                                      AudioFlinger::PlaybackThread *dstThread,
                                      bool reRegister);
+              PlaybackThread *primaryPlaybackThread_l();
+              uint32_t primaryOutputDevice_l();
 
     friend class AudioBuffer;
 
@@ -864,18 +896,33 @@
                         AudioStreamIn *input,
                         uint32_t sampleRate,
                         uint32_t channels,
-                        int id);
+                        int id,
+                        uint32_t device);
                 ~RecordThread();
 
         virtual bool        threadLoop();
         virtual status_t    readyToRun() { return NO_ERROR; }
         virtual void        onFirstRef();
 
+        virtual status_t    initCheck() const { return (mInput == 0) ? NO_INIT : NO_ERROR; }
+                sp<AudioFlinger::RecordThread::RecordTrack>  createRecordTrack_l(
+                        const sp<AudioFlinger::Client>& client,
+                        uint32_t sampleRate,
+                        int format,
+                        int channelMask,
+                        int frameCount,
+                        uint32_t flags,
+                        int sessionId,
+                        status_t *status);
+
                 status_t    start(RecordTrack* recordTrack);
                 void        stop(RecordTrack* recordTrack);
                 status_t    dump(int fd, const Vector<String16>& args);
                 AudioStreamIn* getInput() { return mInput; }
+                virtual audio_stream_t* stream() { return &mInput->stream->common; }
 
+
+                void        setTrack(RecordTrack *recordTrack) { mTrack = recordTrack; }
         virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer);
         virtual void        releaseBuffer(AudioBufferProvider::Buffer* buffer);
         virtual bool        checkForNewParameters_l();
@@ -884,9 +931,14 @@
                 void        readInputParameters();
         virtual unsigned int  getInputFramesLost();
 
+        virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
+        virtual size_t removeEffectChain_l(const sp<EffectChain>& chain);
+        virtual uint32_t hasAudioSession(int sessionId);
+
     private:
                 RecordThread();
                 AudioStreamIn                       *mInput;
+                RecordTrack*                        mTrack;
                 sp<RecordTrack>                     mActiveTrack;
                 Condition                           mStartStopCond;
                 AudioResampler                      *mResampler;
@@ -1103,9 +1155,8 @@
         status_t addEffect_l(const sp<EffectModule>& handle);
         size_t removeEffect_l(const sp<EffectModule>& handle);
 
-        int sessionId() {
-            return mSessionId;
-        }
+        int sessionId() { return mSessionId; }
+        void setSessionId(int sessionId) { mSessionId = sessionId; }
 
         sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor);
         sp<EffectModule> getEffectFromId_l(int id);
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 8e16d94..dd1e153 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -33,11 +33,14 @@
 #include <cutils/properties.h>
 #include <dlfcn.h>
 #include <hardware_legacy/power.h>
+#include <media/AudioEffect.h>
+#include <media/EffectsFactoryApi.h>
 
 #include <hardware/hardware.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
 #include <hardware/audio_policy.h>
+#include <audio_effects/audio_effects_conf.h>
 
 namespace android {
 
@@ -101,6 +104,13 @@
     mpAudioPolicy->set_can_mute_enforced_audible(mpAudioPolicy, !forced_val);
 
     LOGI("Loaded audio policy from %s (%s)", module->name, module->id);
+
+    // load audio pre processing modules
+    if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
+        loadPreProcessorConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE);
+    } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {
+        loadPreProcessorConfig(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);
+    }
 }
 
 AudioPolicyService::~AudioPolicyService()
@@ -110,6 +120,31 @@
     mAudioCommandThread->exit();
     mAudioCommandThread.clear();
 
+
+    // release audio pre processing resources
+    for (size_t i = 0; i < mInputSources.size(); i++) {
+        InputSourceDesc *source = mInputSources.valueAt(i);
+        Vector <EffectDesc *> effects = source->mEffects;
+        for (size_t j = 0; j < effects.size(); j++) {
+            delete effects[j]->mName;
+            Vector <effect_param_t *> params = effects[j]->mParams;
+            for (size_t k = 0; k < params.size(); k++) {
+                delete params[k];
+            }
+            params.clear();
+            delete effects[j];
+        }
+        effects.clear();
+        delete source;
+    }
+    mInputSources.clear();
+
+    for (size_t i = 0; i < mInputs.size(); i++) {
+        mInputs.valueAt(i)->mEffects.clear();
+        delete mInputs.valueAt(i);
+    }
+    mInputs.clear();
+
     if (mpAudioPolicy && mpAudioPolicyDev)
         mpAudioPolicyDev->destroy_audio_policy(mpAudioPolicyDev, mpAudioPolicy);
     if (mpAudioPolicyDev)
@@ -276,13 +311,51 @@
                                     uint32_t samplingRate,
                                     uint32_t format,
                                     uint32_t channels,
-                                    audio_in_acoustics_t acoustics)
+                                    audio_in_acoustics_t acoustics,
+                                    int audioSession)
 {
     if (mpAudioPolicy == NULL) {
         return 0;
     }
     Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate, format, channels, acoustics);
+    audio_io_handle_t input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate,
+                                                       format, channels, acoustics);
+
+    if (input == 0) {
+        return input;
+    }
+    // create audio pre processors according to input source
+    ssize_t index = mInputSources.indexOfKey((audio_source_t)inputSource);
+    if (index < 0) {
+        return input;
+    }
+    ssize_t idx = mInputs.indexOfKey(input);
+    InputDesc *inputDesc;
+    if (idx < 0) {
+        inputDesc = new InputDesc();
+        inputDesc->mSessionId = audioSession;
+        mInputs.add(input, inputDesc);
+    } else {
+        inputDesc = mInputs.valueAt(idx);
+    }
+
+    Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
+    for (size_t i = 0; i < effects.size(); i++) {
+        EffectDesc *effect = effects[i];
+        sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0, audioSession, input);
+        status_t status = fx->initCheck();
+        if (status != NO_ERROR && status != ALREADY_EXISTS) {
+            LOGW("Failed to create Fx %s on input %d", effect->mName, input);
+            // fx goes out of scope and strong ref on AudioEffect is released
+            continue;
+        }
+        for (size_t j = 0; j < effect->mParams.size(); j++) {
+            fx->setParameter(effect->mParams[j]);
+        }
+        inputDesc->mEffects.add(fx);
+    }
+    setPreProcessorEnabled(inputDesc, true);
+    return input;
 }
 
 status_t AudioPolicyService::startInput(audio_io_handle_t input)
@@ -291,6 +364,7 @@
         return NO_INIT;
     }
     Mutex::Autolock _l(mLock);
+
     return mpAudioPolicy->start_input(mpAudioPolicy, input);
 }
 
@@ -300,6 +374,7 @@
         return NO_INIT;
     }
     Mutex::Autolock _l(mLock);
+
     return mpAudioPolicy->stop_input(mpAudioPolicy, input);
 }
 
@@ -310,6 +385,16 @@
     }
     Mutex::Autolock _l(mLock);
     mpAudioPolicy->release_input(mpAudioPolicy, input);
+
+    ssize_t index = mInputs.indexOfKey(input);
+    if (index < 0) {
+        return;
+    }
+    InputDesc *inputDesc = mInputs.valueAt(index);
+    setPreProcessorEnabled(inputDesc, false);
+    inputDesc->mEffects.clear();
+    delete inputDesc;
+    mInputs.removeItemsAt(index);
 }
 
 status_t AudioPolicyService::initStreamVolume(audio_stream_type_t stream,
@@ -384,7 +469,7 @@
 }
 
 status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc,
-                                audio_io_handle_t output,
+                                audio_io_handle_t io,
                                 uint32_t strategy,
                                 int session,
                                 int id)
@@ -392,7 +477,7 @@
     if (mpAudioPolicy == NULL) {
         return NO_INIT;
     }
-    return mpAudioPolicy->register_effect(mpAudioPolicy, desc, output, strategy, session, id);
+    return mpAudioPolicy->register_effect(mpAudioPolicy, desc, io, strategy, session, id);
 }
 
 status_t AudioPolicyService::unregisterEffect(int id)
@@ -489,6 +574,15 @@
     return NO_ERROR;
 }
 
+void AudioPolicyService::setPreProcessorEnabled(InputDesc *inputDesc, bool enabled)
+{
+    Vector<sp<AudioEffect> > fxVector = inputDesc->mEffects;
+    for (size_t i = 0; i < fxVector.size(); i++) {
+        sp<AudioEffect> fx = fxVector.itemAt(i);
+        fx->setEnabled(enabled);
+    }
+}
+
 status_t AudioPolicyService::onTransact(
         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -918,6 +1012,300 @@
     return (int)mAudioCommandThread->voiceVolumeCommand(volume, delayMs);
 }
 
+// ----------------------------------------------------------------------------
+// Audio pre-processing configuration
+// ----------------------------------------------------------------------------
+
+const char *AudioPolicyService::kInputSourceNames[AUDIO_SOURCE_CNT -1] = {
+    MIC_SRC_TAG,
+    VOICE_UL_SRC_TAG,
+    VOICE_DL_SRC_TAG,
+    VOICE_CALL_SRC_TAG,
+    CAMCORDER_SRC_TAG,
+    VOICE_REC_SRC_TAG,
+    VOICE_COMM_SRC_TAG
+};
+
+// returns the audio_source_t enum corresponding to the input source name or
+// AUDIO_SOURCE_CNT is no match found
+audio_source_t AudioPolicyService::inputSourceNameToEnum(const char *name)
+{
+    int i;
+    for (i = AUDIO_SOURCE_MIC; i < AUDIO_SOURCE_CNT; i++) {
+        if (strcmp(name, kInputSourceNames[i - AUDIO_SOURCE_MIC]) == 0) {
+            LOGV("inputSourceNameToEnum found source %s %d", name, i);
+            break;
+        }
+    }
+    return (audio_source_t)i;
+}
+
+size_t AudioPolicyService::growParamSize(char *param,
+                                         size_t size,
+                                         size_t *curSize,
+                                         size_t *totSize)
+{
+    // *curSize is at least sizeof(effect_param_t) + 2 * sizeof(int)
+    size_t pos = ((*curSize - 1 ) / size + 1) * size;
+
+    if (pos + size > *totSize) {
+        while (pos + size > *totSize) {
+            *totSize += ((*totSize + 7) / 8) * 4;
+        }
+        param = (char *)realloc(param, *totSize);
+    }
+    *curSize = pos + size;
+    return pos;
+}
+
+size_t AudioPolicyService::readParamValue(cnode *node,
+                                          char *param,
+                                          size_t *curSize,
+                                          size_t *totSize)
+{
+    if (strncmp(node->name, SHORT_TAG, sizeof(SHORT_TAG) + 1) == 0) {
+        size_t pos = growParamSize(param, sizeof(short), curSize, totSize);
+        *(short *)((char *)param + pos) = (short)atoi(node->value);
+        LOGV("readParamValue() reading short %d", *(short *)((char *)param + pos));
+        return sizeof(short);
+    } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) {
+        size_t pos = growParamSize(param, sizeof(int), curSize, totSize);
+        *(int *)((char *)param + pos) = atoi(node->value);
+        LOGV("readParamValue() reading int %d", *(int *)((char *)param + pos));
+        return sizeof(int);
+    } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) {
+        size_t pos = growParamSize(param, sizeof(float), curSize, totSize);
+        *(float *)((char *)param + pos) = (float)atof(node->value);
+        LOGV("readParamValue() reading float %f",*(float *)((char *)param + pos));
+        return sizeof(float);
+    } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) {
+        size_t pos = growParamSize(param, sizeof(bool), curSize, totSize);
+        if (strncmp(node->value, "false", strlen("false") + 1) == 0) {
+            *(bool *)((char *)param + pos) = false;
+        } else {
+            *(bool *)((char *)param + pos) = true;
+        }
+        LOGV("readParamValue() reading bool %s",*(bool *)((char *)param + pos) ? "true" : "false");
+        return sizeof(bool);
+    } else if (strncmp(node->name, STRING_TAG, sizeof(STRING_TAG) + 1) == 0) {
+        size_t len = strnlen(node->value, EFFECT_STRING_LEN_MAX);
+        if (*curSize + len + 1 > *totSize) {
+            *totSize = *curSize + len + 1;
+            param = (char *)realloc(param, *totSize);
+        }
+        strncpy(param + *curSize, node->value, len);
+        *curSize += len;
+        param[*curSize] = '\0';
+        LOGV("readParamValue() reading string %s", param + *curSize - len);
+        return len;
+    }
+    LOGW("readParamValue() unknown param type %s", node->name);
+    return 0;
+}
+
+effect_param_t *AudioPolicyService::loadEffectParameter(cnode *root)
+{
+    cnode *param;
+    cnode *value;
+    size_t curSize = sizeof(effect_param_t);
+    size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int);
+    effect_param_t *fx_param = (effect_param_t *)malloc(totSize);
+
+    param = config_find(root, PARAM_TAG);
+    value = config_find(root, VALUE_TAG);
+    if (param == NULL && value == NULL) {
+        // try to parse simple parameter form {int int}
+        param = root->first_child;
+        if (param) {
+            // Note: that a pair of random strings is read as 0 0
+            int *ptr = (int *)fx_param->data;
+            int *ptr2 = (int *)((char *)param + sizeof(effect_param_t));
+            LOGW("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2);
+            *ptr++ = atoi(param->name);
+            *ptr = atoi(param->value);
+            fx_param->psize = sizeof(int);
+            fx_param->vsize = sizeof(int);
+            return fx_param;
+        }
+    }
+    if (param == NULL || value == NULL) {
+        LOGW("loadEffectParameter() invalid parameter description %s", root->name);
+        goto error;
+    }
+
+    fx_param->psize = 0;
+    param = param->first_child;
+    while (param) {
+        LOGV("loadEffectParameter() reading param of type %s", param->name);
+        size_t size = readParamValue(param, (char *)fx_param, &curSize, &totSize);
+        if (size == 0) {
+            goto error;
+        }
+        fx_param->psize += size;
+        param = param->next;
+    }
+
+    // align start of value field on 32 bit boundary
+    curSize = ((curSize - 1 ) / sizeof(int) + 1) * sizeof(int);
+
+    fx_param->vsize = 0;
+    value = value->first_child;
+    while (value) {
+        LOGV("loadEffectParameter() reading value of type %s", value->name);
+        size_t size = readParamValue(value, (char *)fx_param, &curSize, &totSize);
+        if (size == 0) {
+            goto error;
+        }
+        fx_param->vsize += size;
+        value = value->next;
+    }
+
+    return fx_param;
+
+error:
+    delete fx_param;
+    return NULL;
+}
+
+void AudioPolicyService::loadEffectParameters(cnode *root, Vector <effect_param_t *>& params)
+{
+    cnode *node = root->first_child;
+    while (node) {
+        LOGV("loadEffectParameters() loading param %s", node->name);
+        effect_param_t *param = loadEffectParameter(node);
+        if (param == NULL) {
+            node = node->next;
+            continue;
+        }
+        params.add(param);
+        node = node->next;
+    }
+}
+
+AudioPolicyService::InputSourceDesc *AudioPolicyService::loadInputSource(
+                                                            cnode *root,
+                                                            const Vector <EffectDesc *>& effects)
+{
+    cnode *node = root->first_child;
+    if (node == NULL) {
+        LOGW("loadInputSource() empty element %s", root->name);
+        return NULL;
+    }
+    InputSourceDesc *source = new InputSourceDesc();
+    while (node) {
+        size_t i;
+        for (i = 0; i < effects.size(); i++) {
+            if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) {
+                LOGV("loadInputSource() found effect %s in list", node->name);
+                break;
+            }
+        }
+        if (i == effects.size()) {
+            LOGV("loadInputSource() effect %s not in list", node->name);
+            node = node->next;
+            continue;
+        }
+        EffectDesc *effect = new EffectDesc(*effects[i]);
+        loadEffectParameters(node, effect->mParams);
+        LOGV("loadInputSource() adding effect %s uuid %08x", effect->mName, effect->mUuid.timeLow);
+        source->mEffects.add(effect);
+        node = node->next;
+    }
+    if (source->mEffects.size() == 0) {
+        LOGW("loadInputSource() no valid effects found in source %s", root->name);
+        delete source;
+        return NULL;
+    }
+    return source;
+}
+
+status_t AudioPolicyService::loadInputSources(cnode *root, const Vector <EffectDesc *>& effects)
+{
+    cnode *node = config_find(root, PREPROCESSING_TAG);
+    if (node == NULL) {
+        return -ENOENT;
+    }
+    node = node->first_child;
+    while (node) {
+        audio_source_t source = inputSourceNameToEnum(node->name);
+        if (source == AUDIO_SOURCE_CNT) {
+            LOGW("loadInputSources() invalid input source %s", node->name);
+            node = node->next;
+            continue;
+        }
+        LOGV("loadInputSources() loading input source %s", node->name);
+        InputSourceDesc *desc = loadInputSource(node, effects);
+        if (desc == NULL) {
+            node = node->next;
+            continue;
+        }
+        mInputSources.add(source, desc);
+        node = node->next;
+    }
+    return NO_ERROR;
+}
+
+AudioPolicyService::EffectDesc *AudioPolicyService::loadEffect(cnode *root)
+{
+    cnode *node = config_find(root, UUID_TAG);
+    if (node == NULL) {
+        return NULL;
+    }
+    effect_uuid_t uuid;
+    if (AudioEffect::stringToGuid(node->value, &uuid) != NO_ERROR) {
+        LOGW("loadEffect() invalid uuid %s", node->value);
+        return NULL;
+    }
+    EffectDesc *effect = new EffectDesc();
+    effect->mName = strdup(root->name);
+    memcpy(&effect->mUuid, &uuid, sizeof(effect_uuid_t));
+
+    return effect;
+}
+
+status_t AudioPolicyService::loadEffects(cnode *root, Vector <EffectDesc *>& effects)
+{
+    cnode *node = config_find(root, EFFECTS_TAG);
+    if (node == NULL) {
+        return -ENOENT;
+    }
+    node = node->first_child;
+    while (node) {
+        LOGV("loadEffects() loading effect %s", node->name);
+        EffectDesc *effect = loadEffect(node);
+        if (effect == NULL) {
+            node = node->next;
+            continue;
+        }
+        effects.add(effect);
+        node = node->next;
+    }
+    return NO_ERROR;
+}
+
+status_t AudioPolicyService::loadPreProcessorConfig(const char *path)
+{
+    cnode *root;
+    char *data;
+
+    data = (char *)load_file(path, NULL);
+    if (data == NULL) {
+        return -ENODEV;
+    }
+    root = config_node("", "");
+    config_load(root, data);
+
+    Vector <EffectDesc *> effects;
+    loadEffects(root, effects);
+    loadInputSources(root, effects);
+
+    config_free(root);
+    free(root);
+    free(data);
+
+    return NO_ERROR;
+}
+
 /* implementation of the interface to the policy manager */
 extern "C" {
 
diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h
index b830120..62ad29e 100644
--- a/services/audioflinger/AudioPolicyService.h
+++ b/services/audioflinger/AudioPolicyService.h
@@ -17,14 +17,17 @@
 #ifndef ANDROID_AUDIOPOLICYSERVICE_H
 #define ANDROID_AUDIOPOLICYSERVICE_H
 
-#include <media/IAudioPolicyService.h>
-#include <media/ToneGenerator.h>
+#include <cutils/misc.h>
+#include <cutils/config_utils.h>
 #include <utils/Vector.h>
+#include <utils/SortedVector.h>
 #include <binder/BinderService.h>
-
 #include <system/audio.h>
 #include <system/audio_policy.h>
 #include <hardware/audio_policy.h>
+#include <media/IAudioPolicyService.h>
+#include <media/ToneGenerator.h>
+#include <media/AudioEffect.h>
 
 namespace android {
 
@@ -78,7 +81,8 @@
                                     uint32_t format = AUDIO_FORMAT_DEFAULT,
                                     uint32_t channels = 0,
                                     audio_in_acoustics_t acoustics =
-                                            (audio_in_acoustics_t)0);
+                                            (audio_in_acoustics_t)0,
+                                    int audioSession = 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);
@@ -93,7 +97,7 @@
 
     virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc);
     virtual status_t registerEffect(effect_descriptor_t *desc,
-                                    audio_io_handle_t output,
+                                    audio_io_handle_t io,
                                     uint32_t strategy,
                                     int session,
                                     int id);
@@ -218,6 +222,51 @@
         String8 mName;                      // string used by wake lock fo delayed commands
     };
 
+    class EffectDesc {
+    public:
+        EffectDesc() {}
+        virtual ~EffectDesc() {}
+        char *mName;
+        effect_uuid_t mUuid;
+        Vector <effect_param_t *> mParams;
+    };
+
+    class InputSourceDesc {
+    public:
+        InputSourceDesc() {}
+        virtual ~InputSourceDesc() {}
+        Vector <EffectDesc *> mEffects;
+    };
+
+
+    class InputDesc {
+    public:
+        InputDesc() {}
+        virtual ~InputDesc() {}
+        int mSessionId;
+        Vector< sp<AudioEffect> >mEffects;
+    };
+
+    static const char *kInputSourceNames[AUDIO_SOURCE_CNT -1];
+
+    void setPreProcessorEnabled(InputDesc *inputDesc, bool enabled);
+    status_t loadPreProcessorConfig(const char *path);
+    status_t loadEffects(cnode *root, Vector <EffectDesc *>& effects);
+    EffectDesc *loadEffect(cnode *root);
+    status_t loadInputSources(cnode *root, const Vector <EffectDesc *>& effects);
+    audio_source_t inputSourceNameToEnum(const char *name);
+    InputSourceDesc *loadInputSource(cnode *root, const Vector <EffectDesc *>& effects);
+    void loadEffectParameters(cnode *root, Vector <effect_param_t *>& params);
+    effect_param_t *loadEffectParameter(cnode *root);
+    size_t readParamValue(cnode *node,
+                          char *param,
+                          size_t *curSize,
+                          size_t *totSize);
+    size_t growParamSize(char *param,
+                         size_t size,
+                         size_t *curSize,
+                         size_t *totSize);
+
     // Internal dump utilities.
     status_t dumpPermissionDenial(int fd);
 
@@ -226,9 +275,10 @@
                             // device connection state  or routing
     sp <AudioCommandThread> mAudioCommandThread;    // audio commands thread
     sp <AudioCommandThread> mTonePlaybackThread;     // tone playback thread
-
     struct audio_policy_device *mpAudioPolicyDev;
     struct audio_policy *mpAudioPolicy;
+    KeyedVector< audio_source_t, InputSourceDesc* > mInputSources;
+    KeyedVector< audio_io_handle_t, InputDesc* > mInputs;
 };
 
 }; // namespace android