Merge "fix for issue  4142219 Don't hard code platform-specific limitations-jni/java part"
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/include/media/mediascanner.h b/include/media/mediascanner.h
index 765c039..803bffb 100644
--- a/include/media/mediascanner.h
+++ b/include/media/mediascanner.h
@@ -23,23 +23,33 @@
 #include <utils/Errors.h>
 #include <pthread.h>
 
+struct dirent;
+
 namespace android {
 
 class MediaScannerClient;
 class StringArray;
 
+enum MediaScanResult {
+    // This file or directory was scanned successfully.
+    MEDIA_SCAN_RESULT_OK,
+    // This file or directory was skipped because it was not found, could
+    // not be opened, was of an unsupported type, or was malfored in some way.
+    MEDIA_SCAN_RESULT_SKIPPED,
+    // The scan should be aborted due to a fatal error such as out of memory
+    // or an exception.
+    MEDIA_SCAN_RESULT_ERROR,
+};
+
 struct MediaScanner {
     MediaScanner();
     virtual ~MediaScanner();
 
-    virtual status_t processFile(
-            const char *path, const char *mimeType,
-            MediaScannerClient &client) = 0;
+    virtual MediaScanResult processFile(
+            const char *path, const char *mimeType, MediaScannerClient &client) = 0;
 
-    typedef bool (*ExceptionCheck)(void* env);
-    virtual status_t processDirectory(
-            const char *path, MediaScannerClient &client,
-            ExceptionCheck exceptionCheck, void *exceptionEnv);
+    virtual MediaScanResult processDirectory(
+            const char *path, MediaScannerClient &client);
 
     void setLocale(const char *locale);
 
@@ -53,9 +63,11 @@
     // current locale (like "ja_JP"), created/destroyed with strdup()/free()
     char *mLocale;
 
-    status_t doProcessDirectory(
-            char *path, int pathRemaining, MediaScannerClient &client,
-            bool noMedia, ExceptionCheck exceptionCheck, void *exceptionEnv);
+    MediaScanResult doProcessDirectory(
+            char *path, int pathRemaining, MediaScannerClient &client, bool noMedia);
+    MediaScanResult doProcessDirectoryEntry(
+            char *path, int pathRemaining, MediaScannerClient &client, bool noMedia,
+            struct dirent* entry, char* fileSpot);
 
     MediaScanner(const MediaScanner &);
     MediaScanner &operator=(const MediaScanner &);
@@ -68,13 +80,13 @@
     virtual ~MediaScannerClient();
     void setLocale(const char* locale);
     void beginFile();
-    bool addStringTag(const char* name, const char* value);
+    status_t addStringTag(const char* name, const char* value);
     void endFile();
 
-    virtual bool scanFile(const char* path, long long lastModified,
+    virtual status_t scanFile(const char* path, long long lastModified,
             long long fileSize, bool isDirectory, bool noMedia) = 0;
-    virtual bool handleStringTag(const char* name, const char* value) = 0;
-    virtual bool setMimeType(const char* mimeType) = 0;
+    virtual status_t handleStringTag(const char* name, const char* value) = 0;
+    virtual status_t setMimeType(const char* mimeType) = 0;
 
 protected:
     void convertValues(uint32_t encoding);
diff --git a/include/media/stagefright/StagefrightMediaScanner.h b/include/media/stagefright/StagefrightMediaScanner.h
index 108acb4..6510a59 100644
--- a/include/media/stagefright/StagefrightMediaScanner.h
+++ b/include/media/stagefright/StagefrightMediaScanner.h
@@ -26,7 +26,7 @@
     StagefrightMediaScanner();
     virtual ~StagefrightMediaScanner();
 
-    virtual status_t processFile(
+    virtual MediaScanResult processFile(
             const char *path, const char *mimeType,
             MediaScannerClient &client);
 
@@ -35,6 +35,10 @@
 private:
     StagefrightMediaScanner(const StagefrightMediaScanner &);
     StagefrightMediaScanner &operator=(const StagefrightMediaScanner &);
+
+    MediaScanResult processFileInternal(
+            const char *path, const char *mimeType,
+            MediaScannerClient &client);
 };
 
 }  // namespace android
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/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index 45bdff4..41f8593 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -47,16 +47,15 @@
     return mLocale;
 }
 
-status_t MediaScanner::processDirectory(
-        const char *path, MediaScannerClient &client,
-        ExceptionCheck exceptionCheck, void *exceptionEnv) {
+MediaScanResult MediaScanner::processDirectory(
+        const char *path, MediaScannerClient &client) {
     int pathLength = strlen(path);
     if (pathLength >= PATH_MAX) {
-        return UNKNOWN_ERROR;
+        return MEDIA_SCAN_RESULT_SKIPPED;
     }
     char* pathBuffer = (char *)malloc(PATH_MAX + 1);
     if (!pathBuffer) {
-        return UNKNOWN_ERROR;
+        return MEDIA_SCAN_RESULT_ERROR;
     }
 
     int pathRemaining = PATH_MAX - pathLength;
@@ -69,21 +68,18 @@
 
     client.setLocale(locale());
 
-    status_t result =
-        doProcessDirectory(pathBuffer, pathRemaining, client, false, exceptionCheck, exceptionEnv);
+    MediaScanResult result = doProcessDirectory(pathBuffer, pathRemaining, client, false);
 
     free(pathBuffer);
 
     return result;
 }
 
-status_t MediaScanner::doProcessDirectory(
-        char *path, int pathRemaining, MediaScannerClient &client,
-        bool noMedia, ExceptionCheck exceptionCheck, void *exceptionEnv) {
+MediaScanResult MediaScanner::doProcessDirectory(
+        char *path, int pathRemaining, MediaScannerClient &client, bool noMedia) {
     // place to copy file or directory name
     char* fileSpot = path + strlen(path);
     struct dirent* entry;
-    struct stat statbuf;
 
     // Treat all files as non-media in directories that contain a  ".nomedia" file
     if (pathRemaining >= 8 /* strlen(".nomedia") */ ) {
@@ -99,76 +95,88 @@
 
     DIR* dir = opendir(path);
     if (!dir) {
-        LOGD("opendir %s failed, errno: %d", path, errno);
-        return UNKNOWN_ERROR;
+        LOGW("Error opening directory '%s', skipping: %s.", path, strerror(errno));
+        return MEDIA_SCAN_RESULT_SKIPPED;
     }
 
+    MediaScanResult result = MEDIA_SCAN_RESULT_OK;
     while ((entry = readdir(dir))) {
-        const char* name = entry->d_name;
-
-        // ignore "." and ".."
-        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
-            continue;
+        if (doProcessDirectoryEntry(path, pathRemaining, client, noMedia, entry, fileSpot)
+                == MEDIA_SCAN_RESULT_ERROR) {
+            result = MEDIA_SCAN_RESULT_ERROR;
+            break;
         }
+    }
+    closedir(dir);
+    return result;
+}
 
-        int nameLength = strlen(name);
-        if (nameLength + 1 > pathRemaining) {
-            // path too long!
-            continue;
+MediaScanResult MediaScanner::doProcessDirectoryEntry(
+        char *path, int pathRemaining, MediaScannerClient &client, bool noMedia,
+        struct dirent* entry, char* fileSpot) {
+    struct stat statbuf;
+    const char* name = entry->d_name;
+
+    // ignore "." and ".."
+    if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
+        return MEDIA_SCAN_RESULT_SKIPPED;
+    }
+
+    int nameLength = strlen(name);
+    if (nameLength + 1 > pathRemaining) {
+        // path too long!
+        return MEDIA_SCAN_RESULT_SKIPPED;
+    }
+    strcpy(fileSpot, name);
+
+    int type = entry->d_type;
+    if (type == DT_UNKNOWN) {
+        // If the type is unknown, stat() the file instead.
+        // This is sometimes necessary when accessing NFS mounted filesystems, but
+        // could be needed in other cases well.
+        if (stat(path, &statbuf) == 0) {
+            if (S_ISREG(statbuf.st_mode)) {
+                type = DT_REG;
+            } else if (S_ISDIR(statbuf.st_mode)) {
+                type = DT_DIR;
+            }
+        } else {
+            LOGD("stat() failed for %s: %s", path, strerror(errno) );
         }
-        strcpy(fileSpot, name);
+    }
+    if (type == DT_DIR) {
+        bool childNoMedia = noMedia;
+        // set noMedia flag on directories with a name that starts with '.'
+        // for example, the Mac ".Trashes" directory
+        if (name[0] == '.')
+            childNoMedia = true;
 
-        int type = entry->d_type;
-        if (type == DT_UNKNOWN) {
-            // If the type is unknown, stat() the file instead.
-            // This is sometimes necessary when accessing NFS mounted filesystems, but
-            // could be needed in other cases well.
-            if (stat(path, &statbuf) == 0) {
-                if (S_ISREG(statbuf.st_mode)) {
-                    type = DT_REG;
-                } else if (S_ISDIR(statbuf.st_mode)) {
-                    type = DT_DIR;
-                }
-            } else {
-                LOGD("stat() failed for %s: %s", path, strerror(errno) );
+        // report the directory to the client
+        if (stat(path, &statbuf) == 0) {
+            status_t status = client.scanFile(path, statbuf.st_mtime, 0,
+                    true /*isDirectory*/, childNoMedia);
+            if (status) {
+                return MEDIA_SCAN_RESULT_ERROR;
             }
         }
-        if (type == DT_REG || type == DT_DIR) {
-            if (type == DT_DIR) {
-                bool childNoMedia = noMedia;
-                // set noMedia flag on directories with a name that starts with '.'
-                // for example, the Mac ".Trashes" directory
-                if (name[0] == '.')
-                    childNoMedia = true;
 
-                // report the directory to the client
-                if (stat(path, &statbuf) == 0) {
-                    client.scanFile(path, statbuf.st_mtime, 0, true, childNoMedia);
-                }
-
-                // and now process its contents
-                strcat(fileSpot, "/");
-                int err = doProcessDirectory(path, pathRemaining - nameLength - 1, client,
-                        childNoMedia, exceptionCheck, exceptionEnv);
-                if (err) {
-                    // pass exceptions up - ignore other errors
-                    if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure;
-                    LOGE("Error processing '%s' - skipping\n", path);
-                    continue;
-                }
-            } else {
-                stat(path, &statbuf);
-                client.scanFile(path, statbuf.st_mtime, statbuf.st_size, false, noMedia);
-                if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure;
-            }
+        // and now process its contents
+        strcat(fileSpot, "/");
+        MediaScanResult result = doProcessDirectory(path, pathRemaining - nameLength - 1,
+                client, childNoMedia);
+        if (result == MEDIA_SCAN_RESULT_ERROR) {
+            return MEDIA_SCAN_RESULT_ERROR;
+        }
+    } else if (type == DT_REG) {
+        stat(path, &statbuf);
+        status_t status = client.scanFile(path, statbuf.st_mtime, statbuf.st_size,
+                false /*isDirectory*/, noMedia);
+        if (status) {
+            return MEDIA_SCAN_RESULT_ERROR;
         }
     }
 
-    closedir(dir);
-    return OK;
-failure:
-    closedir(dir);
-    return -1;
+    return MEDIA_SCAN_RESULT_OK;
 }
 
 }  // namespace android
diff --git a/media/libmedia/MediaScannerClient.cpp b/media/libmedia/MediaScannerClient.cpp
index bd3596e..7a7aeb6 100644
--- a/media/libmedia/MediaScannerClient.cpp
+++ b/media/libmedia/MediaScannerClient.cpp
@@ -62,7 +62,7 @@
     mValues = new StringArray;
 }
 
-bool MediaScannerClient::addStringTag(const char* name, const char* value)
+status_t MediaScannerClient::addStringTag(const char* name, const char* value)
 {
     if (mLocaleEncoding != kEncodingNone) {
         // don't bother caching strings that are all ASCII.
@@ -212,8 +212,10 @@
 
         // finally, push all name/value pairs to the client
         for (int i = 0; i < mNames->size(); i++) {
-            if (!handleStringTag(mNames->getEntry(i), mValues->getEntry(i)))
+            status_t status = handleStringTag(mNames->getEntry(i), mValues->getEntry(i));
+            if (status) {
                 break;
+            }
         }
     }
     // else addStringTag() has done all the work so we have nothing to do
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 178039c..ed6e3c7 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -84,6 +84,8 @@
     if (p != 0) {
         p->disconnect();
     }
+
+    disconnectNativeWindow();
 }
 
 // always call with lock held
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 1bc2fb9..de66d99 100755
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -179,9 +179,6 @@
     if (camera == 0) {
         mCamera = Camera::connect(cameraId);
         if (mCamera == 0) return -EBUSY;
-        // If proxy is not passed in by applications, still use the proxy of
-        // our own Camera to simplify the code.
-        mCameraRecordingProxy = mCamera->getRecordingProxy();
         mCameraFlags &= ~FLAGS_HOT_CAMERA;
     } else {
         // We get the proxy from Camera, not ICamera. We need to get the proxy
@@ -192,12 +189,12 @@
         if (mCamera == 0) return -EBUSY;
         mCameraRecordingProxy = proxy;
         mCameraFlags |= FLAGS_HOT_CAMERA;
+        mDeathNotifier = new DeathNotifier();
+        // isBinderAlive needs linkToDeath to work.
+        mCameraRecordingProxy->asBinder()->linkToDeath(mDeathNotifier);
     }
 
     mCamera->lock();
-    mDeathNotifier = new DeathNotifier();
-    // isBinderAlive needs linkToDeath to work.
-    mCameraRecordingProxy->asBinder()->linkToDeath(mDeathNotifier);
 
     return OK;
 }
@@ -292,7 +289,7 @@
         CameraParameters* params,
         int32_t width, int32_t height,
         int32_t frameRate) {
-
+    LOGV("configureCamera");
     Vector<Size> sizes;
     bool isSetVideoSizeSupportedByCamera = true;
     getSupportedVideoSizes(*params, &isSetVideoSizeSupportedByCamera, sizes);
@@ -368,6 +365,7 @@
         const CameraParameters& params,
         int32_t width, int32_t height) {
 
+    LOGV("checkVideoSize");
     // The actual video size is the same as the preview size
     // if the camera hal does not support separate video and
     // preview output. In this case, we retrieve the video
@@ -419,6 +417,7 @@
         const CameraParameters& params,
         int32_t frameRate) {
 
+    LOGV("checkFrameRate");
     int32_t frameRateActual = params.getPreviewFrameRate();
     if (frameRateActual < 0) {
         LOGE("Failed to retrieve preview frame rate (%d)", frameRateActual);
@@ -464,6 +463,7 @@
         int32_t frameRate,
         bool storeMetaDataInVideoBuffers) {
 
+    LOGV("init");
     status_t err = OK;
     int64_t token = IPCThreadState::self()->clearCallingIdentity();
     err = initWithCameraAccess(camera, proxy, cameraId,
@@ -480,6 +480,7 @@
         Size videoSize,
         int32_t frameRate,
         bool storeMetaDataInVideoBuffers) {
+    LOGV("initWithCameraAccess");
     status_t err = OK;
 
     if ((err = isCameraAvailable(camera, proxy, cameraId)) != OK) {
@@ -552,17 +553,25 @@
 }
 
 void CameraSource::startCameraRecording() {
+    LOGV("startCameraRecording");
     // Reset the identity to the current thread because media server owns the
     // camera and recording is started by the applications. The applications
     // will connect to the camera in ICameraRecordingProxy::startRecording.
     int64_t token = IPCThreadState::self()->clearCallingIdentity();
-    mCamera->unlock();
-    mCamera.clear();
+    if (mCameraFlags & FLAGS_HOT_CAMERA) {
+        mCamera->unlock();
+        mCamera.clear();
+        CHECK_EQ(OK, mCameraRecordingProxy->startRecording(new ProxyListener(this)));
+    } else {
+        mCamera->setListener(new CameraSourceListener(this));
+        mCamera->startRecording();
+        CHECK(mCamera->recordingEnabled());
+    }
     IPCThreadState::self()->restoreCallingIdentity(token);
-    CHECK_EQ(OK, mCameraRecordingProxy->startRecording(new ProxyListener(this)));
 }
 
 status_t CameraSource::start(MetaData *meta) {
+    LOGV("start");
     CHECK(!mStarted);
     if (mInitCheck != OK) {
         LOGE("CameraSource is not initialized yet");
@@ -588,7 +597,13 @@
 }
 
 void CameraSource::stopCameraRecording() {
-    mCameraRecordingProxy->stopRecording();
+    LOGV("stopCameraRecording");
+    if (mCameraFlags & FLAGS_HOT_CAMERA) {
+        mCameraRecordingProxy->stopRecording();
+    } else {
+        mCamera->setListener(NULL);
+        mCamera->stopRecording();
+    }
 }
 
 void CameraSource::releaseCamera() {
@@ -599,11 +614,10 @@
             LOGV("Camera was cold when we started, stopping preview");
             mCamera->stopPreview();
             mCamera->disconnect();
-        } else {
-            // Unlock the camera so the application can lock it back.
-            mCamera->unlock();
         }
+        mCamera->unlock();
         mCamera.clear();
+        mCamera = 0;
         IPCThreadState::self()->restoreCallingIdentity(token);
     }
     if (mCameraRecordingProxy != 0) {
@@ -646,8 +660,13 @@
 }
 
 void CameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
+    LOGV("releaseRecordingFrame");
     if (mCameraRecordingProxy != NULL) {
         mCameraRecordingProxy->releaseRecordingFrame(frame);
+    } else {
+        int64_t token = IPCThreadState::self()->clearCallingIdentity();
+        mCamera->releaseRecordingFrame(frame);
+        IPCThreadState::self()->restoreCallingIdentity(token);
     }
 }
 
@@ -707,7 +726,8 @@
         while (mStarted && mFramesReceived.empty()) {
             if (NO_ERROR !=
                 mFrameAvailableCondition.waitRelative(mLock, 1000000000LL)) {
-                if (!mCameraRecordingProxy->asBinder()->isBinderAlive()) {
+                if (mCameraRecordingProxy != 0 &&
+                    !mCameraRecordingProxy->asBinder()->isBinderAlive()) {
                     LOGW("camera recording proxy is gone");
                     return ERROR_END_OF_STREAM;
                 }
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 89faff7..571e8be 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -52,13 +52,13 @@
     return false;
 }
 
-static status_t HandleMIDI(
+static MediaScanResult HandleMIDI(
         const char *filename, MediaScannerClient *client) {
     // get the library configuration and do sanity check
     const S_EAS_LIB_CONFIG* pLibConfig = EAS_Config();
     if ((pLibConfig == NULL) || (LIB_VERSION != pLibConfig->libVersion)) {
         LOGE("EAS library/header mismatch\n");
-        return UNKNOWN_ERROR;
+        return MEDIA_SCAN_RESULT_ERROR;
     }
     EAS_I32 temp;
 
@@ -88,34 +88,41 @@
     }
 
     if (result != EAS_SUCCESS) {
-        return UNKNOWN_ERROR;
+        return MEDIA_SCAN_RESULT_SKIPPED;
     }
 
     char buffer[20];
     sprintf(buffer, "%ld", temp);
-    if (!client->addStringTag("duration", buffer)) return UNKNOWN_ERROR;
-
-    return OK;
+    status_t status = client->addStringTag("duration", buffer);
+    if (status) {
+        return MEDIA_SCAN_RESULT_ERROR;
+    }
+    return MEDIA_SCAN_RESULT_OK;
 }
 
-status_t StagefrightMediaScanner::processFile(
+MediaScanResult StagefrightMediaScanner::processFile(
         const char *path, const char *mimeType,
         MediaScannerClient &client) {
     LOGV("processFile '%s'.", path);
 
     client.setLocale(locale());
     client.beginFile();
+    MediaScanResult result = processFileInternal(path, mimeType, client);
+    client.endFile();
+    return result;
+}
 
+MediaScanResult StagefrightMediaScanner::processFileInternal(
+        const char *path, const char *mimeType,
+        MediaScannerClient &client) {
     const char *extension = strrchr(path, '.');
 
     if (!extension) {
-        return UNKNOWN_ERROR;
+        return MEDIA_SCAN_RESULT_SKIPPED;
     }
 
     if (!FileHasAcceptableExtension(extension)) {
-        client.endFile();
-
-        return UNKNOWN_ERROR;
+        return MEDIA_SCAN_RESULT_SKIPPED;
     }
 
     if (!strcasecmp(extension, ".mid")
@@ -127,53 +134,57 @@
             || !strcasecmp(extension, ".rtx")
             || !strcasecmp(extension, ".ota")
             || !strcasecmp(extension, ".mxmf")) {
-        status_t status = HandleMIDI(path, &client);
-        if (status != OK) {
-            return status;
+        return HandleMIDI(path, &client);
+    }
+
+    sp<MediaMetadataRetriever> mRetriever(new MediaMetadataRetriever);
+
+    status_t status = mRetriever->setDataSource(path);
+    if (status) {
+        return MEDIA_SCAN_RESULT_ERROR;
+    }
+
+    const char *value;
+    if ((value = mRetriever->extractMetadata(
+                    METADATA_KEY_MIMETYPE)) != NULL) {
+        status = client.setMimeType(value);
+        if (status) {
+            return MEDIA_SCAN_RESULT_ERROR;
         }
-    } else {
-        sp<MediaMetadataRetriever> mRetriever(new MediaMetadataRetriever);
+    }
 
-         if (mRetriever->setDataSource(path) == OK) {
-            const char *value;
-            if ((value = mRetriever->extractMetadata(
-                            METADATA_KEY_MIMETYPE)) != NULL) {
-                client.setMimeType(value);
-            }
+    struct KeyMap {
+        const char *tag;
+        int key;
+    };
+    static const KeyMap kKeyMap[] = {
+        { "tracknumber", METADATA_KEY_CD_TRACK_NUMBER },
+        { "discnumber", METADATA_KEY_DISC_NUMBER },
+        { "album", METADATA_KEY_ALBUM },
+        { "artist", METADATA_KEY_ARTIST },
+        { "albumartist", METADATA_KEY_ALBUMARTIST },
+        { "composer", METADATA_KEY_COMPOSER },
+        { "genre", METADATA_KEY_GENRE },
+        { "title", METADATA_KEY_TITLE },
+        { "year", METADATA_KEY_YEAR },
+        { "duration", METADATA_KEY_DURATION },
+        { "writer", METADATA_KEY_WRITER },
+        { "compilation", METADATA_KEY_COMPILATION },
+        { "isdrm", METADATA_KEY_IS_DRM },
+    };
+    static const size_t kNumEntries = sizeof(kKeyMap) / sizeof(kKeyMap[0]);
 
-            struct KeyMap {
-                const char *tag;
-                int key;
-            };
-            static const KeyMap kKeyMap[] = {
-                { "tracknumber", METADATA_KEY_CD_TRACK_NUMBER },
-                { "discnumber", METADATA_KEY_DISC_NUMBER },
-                { "album", METADATA_KEY_ALBUM },
-                { "artist", METADATA_KEY_ARTIST },
-                { "albumartist", METADATA_KEY_ALBUMARTIST },
-                { "composer", METADATA_KEY_COMPOSER },
-                { "genre", METADATA_KEY_GENRE },
-                { "title", METADATA_KEY_TITLE },
-                { "year", METADATA_KEY_YEAR },
-                { "duration", METADATA_KEY_DURATION },
-                { "writer", METADATA_KEY_WRITER },
-                { "compilation", METADATA_KEY_COMPILATION },
-                { "isdrm", METADATA_KEY_IS_DRM },
-            };
-            static const size_t kNumEntries = sizeof(kKeyMap) / sizeof(kKeyMap[0]);
-
-            for (size_t i = 0; i < kNumEntries; ++i) {
-                const char *value;
-                if ((value = mRetriever->extractMetadata(kKeyMap[i].key)) != NULL) {
-                    client.addStringTag(kKeyMap[i].tag, value);
-                }
+    for (size_t i = 0; i < kNumEntries; ++i) {
+        const char *value;
+        if ((value = mRetriever->extractMetadata(kKeyMap[i].key)) != NULL) {
+            status = client.addStringTag(kKeyMap[i].tag, value);
+            if (status) {
+                return MEDIA_SCAN_RESULT_ERROR;
             }
         }
     }
 
-    client.endFile();
-
-    return OK;
+    return MEDIA_SCAN_RESULT_OK;
 }
 
 char *StagefrightMediaScanner::extractAlbumArt(int fd) {
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