am 318cd78e: Merge "audio policy: added audio HAL version in audio_policy.conf" into lmp-preview-dev

* commit '318cd78e3b8503113919191b3711eb8be5d23d35':
  audio policy: added audio HAL version in audio_policy.conf
diff --git a/camera/VendorTagDescriptor.cpp b/camera/VendorTagDescriptor.cpp
index 59dce91..3f72f34 100644
--- a/camera/VendorTagDescriptor.cpp
+++ b/camera/VendorTagDescriptor.cpp
@@ -349,18 +349,18 @@
 
     size_t size = mTagToNameMap.size();
     if (size == 0) {
-        fdprintf(fd, "%*sDumping configured vendor tag descriptors: None set\n",
+        dprintf(fd, "%*sDumping configured vendor tag descriptors: None set\n",
                 indentation, "");
         return;
     }
 
-    fdprintf(fd, "%*sDumping configured vendor tag descriptors: %zu entries\n",
+    dprintf(fd, "%*sDumping configured vendor tag descriptors: %zu entries\n",
             indentation, "", size);
     for (size_t i = 0; i < size; ++i) {
         uint32_t tag =  mTagToNameMap.keyAt(i);
 
         if (verbosity < 1) {
-            fdprintf(fd, "%*s0x%x\n", indentation + 2, "", tag);
+            dprintf(fd, "%*s0x%x\n", indentation + 2, "", tag);
             continue;
         }
         String8 name = mTagToNameMap.valueAt(i);
@@ -369,7 +369,7 @@
         int type = mTagToTypeMap.valueFor(tag);
         const char* typeName = (type >= 0 && type < NUM_TYPES) ?
                 camera_metadata_type_names[type] : "UNKNOWN";
-        fdprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2,
+        dprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2,
             "", tag, name.string(), type, typeName, sectionName.string());
     }
 
diff --git a/include/soundtrigger/ISoundTrigger.h b/include/soundtrigger/ISoundTrigger.h
new file mode 100644
index 0000000..5fd8eb2
--- /dev/null
+++ b/include/soundtrigger/ISoundTrigger.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_ISOUNDTRIGGER_H
+#define ANDROID_HARDWARE_ISOUNDTRIGGER_H
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
+#include <system/sound_trigger.h>
+
+namespace android {
+
+class ISoundTrigger : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(SoundTrigger);
+
+    virtual void detach() = 0;
+
+    virtual status_t loadSoundModel(const sp<IMemory>& modelMemory,
+                                    sound_model_handle_t *handle) = 0;
+
+    virtual status_t unloadSoundModel(sound_model_handle_t handle) = 0;
+
+    virtual status_t startRecognition(sound_model_handle_t handle,
+                                      const sp<IMemory>& dataMemory) = 0;
+    virtual status_t stopRecognition(sound_model_handle_t handle) = 0;
+
+};
+
+// ----------------------------------------------------------------------------
+
+class BnSoundTrigger: public BnInterface<ISoundTrigger>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif //ANDROID_HARDWARE_ISOUNDTRIGGER_H
diff --git a/include/soundtrigger/ISoundTriggerClient.h b/include/soundtrigger/ISoundTriggerClient.h
new file mode 100644
index 0000000..7f86d02
--- /dev/null
+++ b/include/soundtrigger/ISoundTriggerClient.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_ISOUNDTRIGGER_CLIENT_H
+#define ANDROID_HARDWARE_ISOUNDTRIGGER_CLIENT_H
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class ISoundTriggerClient : public IInterface
+{
+public:
+
+    DECLARE_META_INTERFACE(SoundTriggerClient);
+
+    virtual void onRecognitionEvent(const sp<IMemory>& eventMemory) = 0;
+
+};
+
+// ----------------------------------------------------------------------------
+
+class BnSoundTriggerClient : public BnInterface<ISoundTriggerClient>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif //ANDROID_HARDWARE_ISOUNDTRIGGER_CLIENT_H
diff --git a/include/soundtrigger/ISoundTriggerHwService.h b/include/soundtrigger/ISoundTriggerHwService.h
new file mode 100644
index 0000000..05a764a
--- /dev/null
+++ b/include/soundtrigger/ISoundTriggerHwService.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_ISOUNDTRIGGER_SERVICE_H
+#define ANDROID_HARDWARE_ISOUNDTRIGGER_SERVICE_H
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <system/sound_trigger.h>
+
+namespace android {
+
+class ISoundTrigger;
+class ISoundTriggerClient;
+
+class ISoundTriggerHwService : public IInterface
+{
+public:
+
+    DECLARE_META_INTERFACE(SoundTriggerHwService);
+
+    virtual status_t listModules(struct sound_trigger_module_descriptor *modules,
+                                 uint32_t *numModules) = 0;
+
+    virtual status_t attach(const sound_trigger_module_handle_t handle,
+                                      const sp<ISoundTriggerClient>& client,
+                                      sp<ISoundTrigger>& module) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnSoundTriggerHwService: public BnInterface<ISoundTriggerHwService>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif //ANDROID_HARDWARE_ISOUNDTRIGGER_SERVICE_H
diff --git a/include/soundtrigger/SoundTrigger.h b/include/soundtrigger/SoundTrigger.h
new file mode 100644
index 0000000..1f7f286
--- /dev/null
+++ b/include/soundtrigger/SoundTrigger.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_H
+#define ANDROID_HARDWARE_SOUNDTRIGGER_H
+
+#include <binder/IBinder.h>
+#include <soundtrigger/SoundTriggerCallback.h>
+#include <soundtrigger/ISoundTrigger.h>
+#include <soundtrigger/ISoundTriggerHwService.h>
+#include <soundtrigger/ISoundTriggerClient.h>
+#include <system/sound_trigger.h>
+
+namespace android {
+
+class MemoryDealer;
+
+class SoundTrigger : public BnSoundTriggerClient,
+                        public IBinder::DeathRecipient
+{
+public:
+    static  status_t listModules(struct sound_trigger_module_descriptor *modules,
+                                 uint32_t *numModules);
+    static  sp<SoundTrigger> attach(const sound_trigger_module_handle_t module,
+                                       const sp<SoundTriggerCallback>& callback);
+
+            virtual ~SoundTrigger();
+
+            void detach();
+
+            status_t loadSoundModel(const sp<IMemory>& modelMemory,
+                                            sound_model_handle_t *handle);
+
+            status_t unloadSoundModel(sound_model_handle_t handle);
+
+            status_t startRecognition(sound_model_handle_t handle, const sp<IMemory>& dataMemory);
+            status_t stopRecognition(sound_model_handle_t handle);
+
+            // BpSoundTriggerClient
+            virtual void onRecognitionEvent(const sp<IMemory>& eventMemory);
+
+            //IBinder::DeathRecipient
+            virtual void binderDied(const wp<IBinder>& who);
+
+            static status_t stringToGuid(const char *str, sound_trigger_uuid_t *guid);
+            static status_t guidToString(const sound_trigger_uuid_t *guid,
+                                         char *str, size_t maxLen);
+
+private:
+            SoundTrigger(sound_trigger_module_handle_t module,
+                            const sp<SoundTriggerCallback>&);
+            static const sp<ISoundTriggerHwService>& getSoundTriggerHwService();
+
+            Mutex                               mLock;
+            sp<ISoundTrigger>                   mISoundTrigger;
+            const sound_trigger_module_handle_t mModule;
+            sp<SoundTriggerCallback>            mCallback;
+};
+
+}; // namespace android
+
+#endif //ANDROID_HARDWARE_SOUNDTRIGGER_H
diff --git a/include/soundtrigger/SoundTriggerCallback.h b/include/soundtrigger/SoundTriggerCallback.h
new file mode 100644
index 0000000..8a5ba02
--- /dev/null
+++ b/include/soundtrigger/SoundTriggerCallback.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_CALLBACK_H
+#define ANDROID_HARDWARE_SOUNDTRIGGER_CALLBACK_H
+
+#include <utils/RefBase.h>
+#include <system/sound_trigger.h>
+
+namespace android {
+
+class SoundTriggerCallback : public RefBase
+{
+public:
+
+            SoundTriggerCallback() {}
+    virtual ~SoundTriggerCallback() {}
+
+    virtual void onRecognitionEvent(struct sound_trigger_recognition_event *event) = 0;
+
+    virtual void onServiceDied() = 0;
+
+};
+
+}; // namespace android
+
+#endif //ANDROID_HARDWARE_SOUNDTRIGGER_CALLBACK_H
diff --git a/media/libcpustats/Android.mk b/media/libcpustats/Android.mk
index b506353..ee283a6 100644
--- a/media/libcpustats/Android.mk
+++ b/media/libcpustats/Android.mk
@@ -1,4 +1,4 @@
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
 
@@ -8,4 +8,6 @@
 
 LOCAL_MODULE := libcpustats
 
+LOCAL_CFLAGS := -std=gnu++11 -Werror
+
 include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libcpustats/ThreadCpuUsage.cpp b/media/libcpustats/ThreadCpuUsage.cpp
index 637402a..cfdcb51 100644
--- a/media/libcpustats/ThreadCpuUsage.cpp
+++ b/media/libcpustats/ThreadCpuUsage.cpp
@@ -21,7 +21,6 @@
 #include <stdlib.h>
 #include <time.h>
 
-#include <utils/Debug.h>
 #include <utils/Log.h>
 
 #include <cpustats/ThreadCpuUsage.h>
@@ -218,7 +217,7 @@
 #define FREQ_SIZE 64
             char freq_path[FREQ_SIZE];
 #define FREQ_DIGIT 27
-            COMPILE_TIME_ASSERT_FUNCTION_SCOPE(MAX_CPU <= 10);
+            static_assert(MAX_CPU <= 10, "MAX_CPU too large");
 #define FREQ_PATH "/sys/devices/system/cpu/cpu?/cpufreq/scaling_cur_freq"
             strlcpy(freq_path, FREQ_PATH, sizeof(freq_path));
             freq_path[FREQ_DIGIT] = cpuNum + '0';
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index a9820e0..194abbb 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -95,7 +95,8 @@
 status_t MediaRecorderClient::setVideoSource(int vs)
 {
     ALOGV("setVideoSource(%d)", vs);
-    if (!checkPermission(cameraPermission)) {
+    // Check camera permission for sources other than SURFACE
+    if (vs != VIDEO_SOURCE_SURFACE && !checkPermission(cameraPermission)) {
         return PERMISSION_DENIED;
     }
     Mutex::Autolock lock(mLock);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index d8d939a..857e703 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1376,16 +1376,15 @@
 
             sp<NuPlayerDriver> driver = mDriver.promote();
             if (driver != NULL) {
+                // notify duration first, so that it's definitely set when
+                // the app received the "prepare complete" callback.
+                int64_t durationUs;
+                if (mSource->getDuration(&durationUs) == OK) {
+                    driver->notifyDuration(durationUs);
+                }
                 driver->notifyPrepareCompleted(err);
             }
 
-            int64_t durationUs;
-            if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
-                sp<NuPlayerDriver> driver = mDriver.promote();
-                if (driver != NULL) {
-                    driver->notifyDuration(durationUs);
-                }
-            }
             break;
         }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 469c9ca..cfbf282 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -37,6 +37,7 @@
     : mNotify(notify),
       mNativeWindow(nativeWindow),
       mBufferGeneration(0),
+      mPaused(true),
       mComponentName("decoder") {
     // Every decoder has its own looper because MediaCodec operations
     // are blocking, but NuPlayer needs asynchronous operations.
@@ -112,6 +113,7 @@
             mOutputBuffers.size());
 
     requestCodecNotification();
+    mPaused = false;
 }
 
 void NuPlayer::Decoder::requestCodecNotification() {
@@ -352,6 +354,11 @@
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatFlushCompleted);
     notify->post();
+    mPaused = true;
+}
+
+void NuPlayer::Decoder::onResume() {
+    mPaused = false;
 }
 
 void NuPlayer::Decoder::onShutdown() {
@@ -380,6 +387,7 @@
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatShutdownCompleted);
     notify->post();
+    mPaused = true;
 }
 
 void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
@@ -397,7 +405,9 @@
         case kWhatCodecNotify:
         {
             if (!isStaleReply(msg)) {
-                while (handleAnInputBuffer()) {
+                if (!mPaused) {
+                    while (handleAnInputBuffer()) {
+                    }
                 }
 
                 while (handleAnOutputBuffer()) {
@@ -430,6 +440,12 @@
             break;
         }
 
+        case kWhatResume:
+        {
+            onResume();
+            break;
+        }
+
         case kWhatShutdown:
         {
             onShutdown();
@@ -447,7 +463,7 @@
 }
 
 void NuPlayer::Decoder::signalResume() {
-    // nothing to do
+    (new AMessage(kWhatResume, id()))->post();
 }
 
 void NuPlayer::Decoder::initiateShutdown() {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 94243fc..2892584 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -87,11 +87,13 @@
 
     void onConfigure(const sp<AMessage> &format);
     void onFlush();
+    void onResume();
     void onInputBufferFilled(const sp<AMessage> &msg);
     void onRenderBuffer(const sp<AMessage> &msg);
     void onShutdown();
 
     int32_t mBufferGeneration;
+    bool mPaused;
     AString mComponentName;
 
     bool supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index e4850f0..280b5af 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -284,6 +284,10 @@
         case STATE_PREPARED:
         {
             mStartupSeekTimeUs = seekTimeUs;
+            // pretend that the seek completed. It will actually happen when starting playback.
+            // TODO: actually perform the seek here, so the player is ready to go at the new
+            // location
+            notifySeekComplete();
             break;
         }
 
diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp
index 4d9a1fa..4d14904 100644
--- a/media/libnbaio/NBLog.cpp
+++ b/media/libnbaio/NBLog.cpp
@@ -438,7 +438,7 @@
 void NBLog::Reader::dumpLine(const String8& timestamp, String8& body)
 {
     if (mFd >= 0) {
-        fdprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string());
+        dprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string());
     } else {
         ALOGI("%.*s%s %s", mIndent, "", timestamp.string(), body.string());
     }
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 76546f3..297f4fc 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -482,11 +482,20 @@
     off64_t offset = 0;
     status_t err;
     while (true) {
+        off64_t orig_offset = offset;
         err = parseChunk(&offset, 0);
-        if (err == OK) {
-            continue;
-        }
 
+        if (offset <= orig_offset) {
+            // only continue parsing if the offset was advanced,
+            // otherwise we might end up in an infinite loop
+            ALOGE("did not advance: 0x%lld->0x%lld", orig_offset, offset);
+            err = ERROR_MALFORMED;
+            break;
+        } else if (err == OK) {
+            continue;
+        } else if (err != UNKNOWN_ERROR) {
+            break;
+        }
         uint32_t hdr[2];
         if (mDataSource->readAt(offset, hdr, 8) < 8) {
             break;
@@ -509,8 +518,6 @@
         } else {
             mFileMetaData->setCString(kKeyMIMEType, "audio/mp4");
         }
-
-        mInitCheck = OK;
     } else {
         mInitCheck = err;
     }
@@ -762,8 +769,25 @@
             // The smallest valid chunk is 16 bytes long in this case.
             return ERROR_MALFORMED;
         }
+    } else if (chunk_size == 0) {
+        if (depth == 0) {
+            // atom extends to end of file
+            off64_t sourceSize;
+            if (mDataSource->getSize(&sourceSize) == OK) {
+                chunk_size = (sourceSize - *offset);
+            } else {
+                // XXX could we just pick a "sufficiently large" value here?
+                ALOGE("atom size is 0, and data source has no size");
+                return ERROR_MALFORMED;
+            }
+        } else {
+            // not allowed for non-toplevel atoms, skip it
+            *offset += 4;
+            return OK;
+        }
     } else if (chunk_size < 8) {
         // The smallest valid chunk is 8 bytes long.
+        ALOGE("invalid chunk size: %d", int(chunk_size));
         return ERROR_MALFORMED;
     }
 
@@ -2486,8 +2510,9 @@
         }
     }
 
-    if (!track->sampleTable->isValid()) {
+    if (track->sampleTable == NULL || !track->sampleTable->isValid()) {
         // Make sure we have all the metadata we need.
+        ALOGE("stbl atom missing/invalid.");
         return ERROR_MALFORMED;
     }
 
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
index 11b80bf..8af0880 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -27,7 +27,6 @@
 #include <media/stagefright/MetaData.h>
 
 #include <ui/GraphicBuffer.h>
-#include <sys/atomics.h>
 
 namespace android {
 
@@ -92,7 +91,7 @@
         return;
     }
 
-    int prevCount = __atomic_dec(&mRefCount);
+    int prevCount = __sync_fetch_and_sub(&mRefCount, 1);
     if (prevCount == 1) {
         if (mObserver == NULL) {
             delete this;
@@ -112,7 +111,7 @@
 }
 
 void MediaBuffer::add_ref() {
-    (void) __atomic_inc(&mRefCount);
+    (void) __sync_fetch_and_add(&mRefCount, 1);
 }
 
 void *MediaBuffer::data() const {
diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk
index 49ff238..afb00aa 100644
--- a/media/libstagefright/codecs/aacdec/Android.mk
+++ b/media/libstagefright/codecs/aacdec/Android.mk
@@ -3,7 +3,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
-      SoftAAC2.cpp
+      SoftAAC2.cpp \
+      DrcPresModeWrap.cpp
 
 LOCAL_C_INCLUDES := \
       frameworks/av/media/libstagefright/include \
diff --git a/media/libstagefright/codecs/aacdec/DrcPresModeWrap.cpp b/media/libstagefright/codecs/aacdec/DrcPresModeWrap.cpp
new file mode 100644
index 0000000..129ad65
--- /dev/null
+++ b/media/libstagefright/codecs/aacdec/DrcPresModeWrap.cpp
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "DrcPresModeWrap.h"
+
+#include <assert.h>
+
+#define LOG_TAG "SoftAAC2_DrcWrapper"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+//#define DRC_PRES_MODE_WRAP_DEBUG
+
+#define GPM_ENCODER_TARGET_LEVEL 64
+#define MAX_TARGET_LEVEL 64
+
+CDrcPresModeWrapper::CDrcPresModeWrapper()
+{
+    mDataUpdate = true;
+
+    /* Data from streamInfo. */
+    /* Initialized to the same values as in the aac decoder */
+    mStreamPRL = -1;
+    mStreamDRCPresMode = -1;
+    mStreamNrAACChan = 0;
+    mStreamNrOutChan = 0;
+
+    /* Desired values (set by user). */
+    /* Initialized to the same values as in the aac decoder */
+    mDesTarget = -1;
+    mDesAttFactor = 0;
+    mDesBoostFactor = 0;
+    mDesHeavy = 0;
+
+    mEncoderTarget = -1;
+
+    /* Values from last time. */
+    /* Initialized to the same values as the desired values */
+    mLastTarget = -1;
+    mLastAttFactor = 0;
+    mLastBoostFactor = 0;
+    mLastHeavy = 0;
+}
+
+CDrcPresModeWrapper::~CDrcPresModeWrapper()
+{
+}
+
+void
+CDrcPresModeWrapper::setDecoderHandle(const HANDLE_AACDECODER handle)
+{
+    mHandleDecoder = handle;
+}
+
+void
+CDrcPresModeWrapper::submitStreamData(CStreamInfo* pStreamInfo)
+{
+    assert(pStreamInfo);
+
+    if (mStreamPRL != pStreamInfo->drcProgRefLev) {
+        mStreamPRL = pStreamInfo->drcProgRefLev;
+        mDataUpdate = true;
+#ifdef DRC_PRES_MODE_WRAP_DEBUG
+        ALOGV("DRC presentation mode wrapper: drcProgRefLev is %d\n", mStreamPRL);
+#endif
+    }
+
+    if (mStreamDRCPresMode != pStreamInfo->drcPresMode) {
+        mStreamDRCPresMode = pStreamInfo->drcPresMode;
+        mDataUpdate = true;
+#ifdef DRC_PRES_MODE_WRAP_DEBUG
+        ALOGV("DRC presentation mode wrapper: drcPresMode is %d\n", mStreamDRCPresMode);
+#endif
+    }
+
+    if (mStreamNrAACChan != pStreamInfo->aacNumChannels) {
+        mStreamNrAACChan = pStreamInfo->aacNumChannels;
+        mDataUpdate = true;
+#ifdef DRC_PRES_MODE_WRAP_DEBUG
+        ALOGV("DRC presentation mode wrapper: aacNumChannels is %d\n", mStreamNrAACChan);
+#endif
+    }
+
+    if (mStreamNrOutChan != pStreamInfo->numChannels) {
+        mStreamNrOutChan = pStreamInfo->numChannels;
+        mDataUpdate = true;
+#ifdef DRC_PRES_MODE_WRAP_DEBUG
+        ALOGV("DRC presentation mode wrapper: numChannels is %d\n", mStreamNrOutChan);
+#endif
+    }
+
+
+
+    if (mStreamNrOutChan<mStreamNrAACChan) {
+        mIsDownmix = true;
+    } else {
+        mIsDownmix = false;
+    }
+
+    if (mIsDownmix && (mStreamNrOutChan == 1)) {
+        mIsMonoDownmix = true;
+    } else {
+        mIsMonoDownmix = false;
+    }
+
+    if (mIsDownmix && mStreamNrOutChan == 2){
+        mIsStereoDownmix = true;
+    } else {
+        mIsStereoDownmix = false;
+    }
+
+}
+
+void
+CDrcPresModeWrapper::setParam(const DRC_PRES_MODE_WRAP_PARAM param, const int value)
+{
+    switch (param) {
+    case DRC_PRES_MODE_WRAP_DESIRED_TARGET:
+        mDesTarget = value;
+        break;
+    case DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR:
+        mDesAttFactor = value;
+        break;
+    case DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR:
+        mDesBoostFactor = value;
+        break;
+    case DRC_PRES_MODE_WRAP_DESIRED_HEAVY:
+        mDesHeavy = value;
+        break;
+    case DRC_PRES_MODE_WRAP_ENCODER_TARGET:
+        mEncoderTarget = value;
+        break;
+    default:
+        break;
+    }
+    mDataUpdate = true;
+}
+
+void
+CDrcPresModeWrapper::update()
+{
+    // Get Data from Decoder
+    int progRefLevel = mStreamPRL;
+    int drcPresMode = mStreamDRCPresMode;
+
+    // by default, do as desired
+    int newTarget         = mDesTarget;
+    int newAttFactor      = mDesAttFactor;
+    int newBoostFactor    = mDesBoostFactor;
+    int newHeavy          = mDesHeavy;
+
+    if (mDataUpdate) {
+        // sanity check
+        if (mDesTarget < MAX_TARGET_LEVEL){
+            mDesTarget = MAX_TARGET_LEVEL;  // limit target level to -16 dB or below
+            newTarget = MAX_TARGET_LEVEL;
+        }
+
+        if (mEncoderTarget != -1) {
+            if (mDesTarget<124) { // if target level > -31 dB
+                if ((mIsStereoDownmix == false) && (mIsMonoDownmix == false)) {
+                    // no stereo or mono downmixing, calculated scaling of light DRC
+                    /* use as little compression as possible */
+                    newAttFactor = 0;
+                    newBoostFactor = 0;
+                    if (mDesTarget<progRefLevel) { // if target level > PRL
+                        if (mEncoderTarget < mDesTarget) { // if mEncoderTarget > target level
+                            // mEncoderTarget > target level > PRL
+                            int calcFactor;
+                            float calcFactor_norm;
+                            // 0.0f < calcFactor_norm < 1.0f
+                            calcFactor_norm = (float)(mDesTarget - progRefLevel) /
+                                    (float)(mEncoderTarget - progRefLevel);
+                            calcFactor = (int)(calcFactor_norm*127.0f); // 0 <= calcFactor < 127
+                            // calcFactor is the lower limit
+                            newAttFactor = (calcFactor>newAttFactor) ? calcFactor : newAttFactor;
+                            // new AttFactor will be always = calcFactor, as it is set to 0 before.
+                            newBoostFactor = newAttFactor;
+                        } else {
+                            /* target level > mEncoderTarget > PRL */
+                            // newTDLimiterEnable = 1;
+                            // the time domain limiter must always be active in this case.
+                            //     It is assumed that the framework activates it by default
+                            newAttFactor = 127;
+                            newBoostFactor = 127;
+                        }
+                    } else { // target level <= PRL
+                        // no restrictions required
+                        // newAttFactor = newAttFactor;
+                    }
+                } else { // downmixing
+                    // if target level > -23 dB or mono downmix
+                    if ( (mDesTarget<92) || mIsMonoDownmix ) {
+                        newHeavy = 1;
+                    } else {
+                        // we perform a downmix, so, we need at least full light DRC
+                        newAttFactor = 127;
+                    }
+                }
+            } else { // target level <= -31 dB
+                // playback -31 dB: light DRC only needed if we perform downmixing
+                if (mIsDownmix) {   // we do downmixing
+                    newAttFactor = 127;
+                }
+            }
+        }
+        else { // handle other used encoder target levels
+
+            // Sanity check: DRC presentation mode is only specified for max. 5.1 channels
+            if (mStreamNrAACChan > 6) {
+                drcPresMode = 0;
+            }
+
+            switch (drcPresMode) {
+            case 0:
+            default: // presentation mode not indicated
+            {
+
+                if (mDesTarget<124) { // if target level > -31 dB
+                    // no stereo or mono downmixing
+                    if ((mIsStereoDownmix == false) && (mIsMonoDownmix == false)) {
+                        if (mDesTarget<progRefLevel) { // if target level > PRL
+                            // newTDLimiterEnable = 1;
+                            // the time domain limiter must always be active in this case.
+                            //    It is assumed that the framework activates it by default
+                            newAttFactor = 127; // at least, use light compression
+                        } else { // target level <= PRL
+                            // no restrictions required
+                            // newAttFactor = newAttFactor;
+                        }
+                    } else { // downmixing
+                        // newTDLimiterEnable = 1;
+                        // the time domain limiter must always be active in this case.
+                        //    It is assumed that the framework activates it by default
+
+                        // if target level > -23 dB or mono downmix
+                        if ( (mDesTarget < 92) || mIsMonoDownmix ) {
+                            newHeavy = 1;
+                        } else{
+                            // we perform a downmix, so, we need at least full light DRC
+                            newAttFactor = 127;
+                        }
+                    }
+                } else { // target level <= -31 dB
+                    if (mIsDownmix) {   // we do downmixing.
+                        // newTDLimiterEnable = 1;
+                        // the time domain limiter must always be active in this case.
+                        //    It is assumed that the framework activates it by default
+                        newAttFactor = 127;
+                    }
+                }
+            }
+            break;
+
+            // Presentation mode 1 and 2 according to ETSI TS 101 154:
+            // Digital Video Broadcasting (DVB); Specification for the use of Video and Audio Coding
+            // in Broadcasting Applications based on the MPEG-2 Transport Stream,
+            // section C.5.4., "Decoding", and Table C.33
+            // ISO DRC            -> newHeavy = 0  (Use light compression, MPEG-style)
+            // Compression_value  -> newHeavy = 1  (Use heavy compression, DVB-style)
+            // scaling restricted -> newAttFactor = 127
+
+            case 1: // presentation mode 1, Light:-31/Heavy:-23
+            {
+                if (mDesTarget < 124) { // if target level > -31 dB
+                    // playback up to -23 dB
+                    newHeavy = 1;
+                } else { // target level <= -31 dB
+                    // playback -31 dB
+                    if (mIsDownmix) {   // we do downmixing.
+                        newAttFactor = 127;
+                    }
+                }
+            }
+            break;
+
+            case 2: // presentation mode 2, Light:-23/Heavy:-23
+            {
+                if (mDesTarget < 124) { // if target level > -31 dB
+                    // playback up to -23 dB
+                    if (mIsMonoDownmix) { // if mono downmix
+                        newHeavy = 1;
+                    } else {
+                        newHeavy = 0;
+                        newAttFactor = 127;
+                    }
+                } else { // target level <= -31 dB
+                    // playback -31 dB
+                    newHeavy = 0;
+                    if (mIsDownmix) {   // we do downmixing.
+                        newAttFactor = 127;
+                    }
+                }
+            }
+            break;
+
+            } // switch()
+        } // if (mEncoderTarget  == GPM_ENCODER_TARGET_LEVEL)
+
+        // sanity again
+        if (newHeavy == 1) {
+            newBoostFactor=127; // not really needed as the same would be done by the decoder anyway
+            newAttFactor = 127;
+        }
+
+        // update the decoder
+        if (newTarget != mLastTarget) {
+            aacDecoder_SetParam(mHandleDecoder, AAC_DRC_REFERENCE_LEVEL, newTarget);
+            mLastTarget = newTarget;
+#ifdef DRC_PRES_MODE_WRAP_DEBUG
+            if (newTarget != mDesTarget)
+                ALOGV("DRC presentation mode wrapper: forced target level to %d (from %d)\n", newTarget, mDesTarget);
+            else
+                ALOGV("DRC presentation mode wrapper: set target level to %d\n", newTarget);
+#endif
+        }
+
+        if (newAttFactor != mLastAttFactor) {
+            aacDecoder_SetParam(mHandleDecoder, AAC_DRC_ATTENUATION_FACTOR, newAttFactor);
+            mLastAttFactor = newAttFactor;
+#ifdef DRC_PRES_MODE_WRAP_DEBUG
+            if (newAttFactor != mDesAttFactor)
+                ALOGV("DRC presentation mode wrapper: forced attenuation factor to %d (from %d)\n", newAttFactor, mDesAttFactor);
+            else
+                ALOGV("DRC presentation mode wrapper: set attenuation factor to %d\n", newAttFactor);
+#endif
+        }
+
+        if (newBoostFactor != mLastBoostFactor) {
+            aacDecoder_SetParam(mHandleDecoder, AAC_DRC_BOOST_FACTOR, newBoostFactor);
+            mLastBoostFactor = newBoostFactor;
+#ifdef DRC_PRES_MODE_WRAP_DEBUG
+            if (newBoostFactor != mDesBoostFactor)
+                ALOGV("DRC presentation mode wrapper: forced boost factor to %d (from %d)\n",
+                        newBoostFactor, mDesBoostFactor);
+            else
+                ALOGV("DRC presentation mode wrapper: set boost factor to %d\n", newBoostFactor);
+#endif
+        }
+
+        if (newHeavy != mLastHeavy) {
+            aacDecoder_SetParam(mHandleDecoder, AAC_DRC_HEAVY_COMPRESSION, newHeavy);
+            mLastHeavy = newHeavy;
+#ifdef DRC_PRES_MODE_WRAP_DEBUG
+            if (newHeavy != mDesHeavy)
+                ALOGV("DRC presentation mode wrapper: forced heavy compression to %d (from %d)\n",
+                        newHeavy, mDesHeavy);
+            else
+                ALOGV("DRC presentation mode wrapper: set heavy compression to %d\n", newHeavy);
+#endif
+        }
+
+#ifdef DRC_PRES_MODE_WRAP_DEBUG
+        ALOGV("DRC config: tgt_lev: %3d, cut: %3d, boost: %3d, heavy: %d\n", newTarget,
+                newAttFactor, newBoostFactor, newHeavy);
+#endif
+        mDataUpdate = false;
+
+    } // if (mDataUpdate)
+}
diff --git a/media/libstagefright/codecs/aacdec/DrcPresModeWrap.h b/media/libstagefright/codecs/aacdec/DrcPresModeWrap.h
new file mode 100644
index 0000000..f0b6cf2
--- /dev/null
+++ b/media/libstagefright/codecs/aacdec/DrcPresModeWrap.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+#include "aacdecoder_lib.h"
+
+typedef enum
+{
+    DRC_PRES_MODE_WRAP_DESIRED_TARGET         = 0x0000,
+    DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR     = 0x0001,
+    DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR   = 0x0002,
+    DRC_PRES_MODE_WRAP_DESIRED_HEAVY          = 0x0003,
+    DRC_PRES_MODE_WRAP_ENCODER_TARGET         = 0x0004
+} DRC_PRES_MODE_WRAP_PARAM;
+
+
+class CDrcPresModeWrapper {
+public:
+    CDrcPresModeWrapper();
+    ~CDrcPresModeWrapper();
+    void setDecoderHandle(const HANDLE_AACDECODER handle);
+    void setParam(const DRC_PRES_MODE_WRAP_PARAM param, const int value);
+    void submitStreamData(CStreamInfo*);
+    void update();
+
+protected:
+    HANDLE_AACDECODER mHandleDecoder;
+    int mDesTarget;
+    int mDesAttFactor;
+    int mDesBoostFactor;
+    int mDesHeavy;
+
+    int mEncoderTarget;
+
+    int mLastTarget;
+    int mLastAttFactor;
+    int mLastBoostFactor;
+    int mLastHeavy;
+
+    SCHAR mStreamPRL;
+    SCHAR mStreamDRCPresMode;
+    INT mStreamNrAACChan;
+    INT mStreamNrOutChan;
+
+    bool mIsDownmix;
+    bool mIsMonoDownmix;
+    bool mIsStereoDownmix;
+
+    bool mDataUpdate;
+};
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 532e36f..edb7448 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -25,16 +25,22 @@
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaErrors.h>
 
+#include <math.h>
+
 #define FILEREAD_MAX_LAYERS 2
 
 #define DRC_DEFAULT_MOBILE_REF_LEVEL 64  /* 64*-0.25dB = -16 dB below full scale for mobile conf */
 #define DRC_DEFAULT_MOBILE_DRC_CUT   127 /* maximum compression of dynamic range for mobile conf */
 #define DRC_DEFAULT_MOBILE_DRC_BOOST 127 /* maximum compression of dynamic range for mobile conf */
+#define DRC_DEFAULT_MOBILE_DRC_HEAVY 1   /* switch for heavy compression for mobile conf */
+#define DRC_DEFAULT_MOBILE_ENC_LEVEL -1 /* encoder target level; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */
 #define MAX_CHANNEL_COUNT            8  /* maximum number of audio channels that can be decoded */
 // names of properties that can be used to override the default DRC settings
 #define PROP_DRC_OVERRIDE_REF_LEVEL  "aac_drc_reference_level"
 #define PROP_DRC_OVERRIDE_CUT        "aac_drc_cut"
 #define PROP_DRC_OVERRIDE_BOOST      "aac_drc_boost"
+#define PROP_DRC_OVERRIDE_HEAVY      "aac_drc_heavy"
+#define PROP_DRC_OVERRIDE_ENC_LEVEL "aac_drc_enc_target_level"
 
 namespace android {
 
@@ -57,18 +63,19 @@
       mStreamInfo(NULL),
       mIsADTS(false),
       mInputBufferCount(0),
+      mOutputBufferCount(0),
       mSignalledError(false),
-      mSawInputEos(false),
-      mSignalledOutputEos(false),
-      mAnchorTimeUs(0),
-      mNumSamplesOutput(0),
       mOutputPortSettingsChange(NONE) {
+    for (unsigned int i = 0; i < kNumDelayBlocksMax; i++) {
+        mAnchorTimeUs[i] = 0;
+    }
     initPorts();
     CHECK_EQ(initDecoder(), (status_t)OK);
 }
 
 SoftAAC2::~SoftAAC2() {
     aacDecoder_Close(mAACDecoder);
+    delete mOutputDelayRingBuffer;
 }
 
 void SoftAAC2::initPorts() {
@@ -121,36 +128,72 @@
             status = OK;
         }
     }
-    mDecoderHasData = false;
 
-    // for streams that contain metadata, use the mobile profile DRC settings unless overridden
-    // by platform properties:
+    mEndOfInput = false;
+    mEndOfOutput = false;
+    mOutputDelayCompensated = 0;
+    mOutputDelayRingBufferSize = 2048 * MAX_CHANNEL_COUNT * kNumDelayBlocksMax;
+    mOutputDelayRingBuffer = new short[mOutputDelayRingBufferSize];
+    mOutputDelayRingBufferWritePos = 0;
+    mOutputDelayRingBufferReadPos = 0;
+
+    if (mAACDecoder == NULL) {
+        ALOGE("AAC decoder is null. TODO: Can not call aacDecoder_SetParam in the following code");
+    }
+
+    //aacDecoder_SetParam(mAACDecoder, AAC_PCM_LIMITER_ENABLE, 0);
+
+    //init DRC wrapper
+    mDrcWrap.setDecoderHandle(mAACDecoder);
+    mDrcWrap.submitStreamData(mStreamInfo);
+
+    // for streams that contain metadata, use the mobile profile DRC settings unless overridden by platform properties
+    // TODO: change the DRC settings depending on audio output device type (HDMI, loadspeaker, headphone)
     char value[PROPERTY_VALUE_MAX];
-    //  * AAC_DRC_REFERENCE_LEVEL
+    //  DRC_PRES_MODE_WRAP_DESIRED_TARGET
     if (property_get(PROP_DRC_OVERRIDE_REF_LEVEL, value, NULL)) {
         unsigned refLevel = atoi(value);
-        ALOGV("AAC decoder using AAC_DRC_REFERENCE_LEVEL of %d instead of %d",
-                refLevel, DRC_DEFAULT_MOBILE_REF_LEVEL);
-        aacDecoder_SetParam(mAACDecoder, AAC_DRC_REFERENCE_LEVEL, refLevel);
+        ALOGV("AAC decoder using desired DRC target reference level of %d instead of %d", refLevel,
+                DRC_DEFAULT_MOBILE_REF_LEVEL);
+        mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_TARGET, refLevel);
     } else {
-        aacDecoder_SetParam(mAACDecoder, AAC_DRC_REFERENCE_LEVEL, DRC_DEFAULT_MOBILE_REF_LEVEL);
+        mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_TARGET, DRC_DEFAULT_MOBILE_REF_LEVEL);
     }
-    //  * AAC_DRC_ATTENUATION_FACTOR
+    //  DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR
     if (property_get(PROP_DRC_OVERRIDE_CUT, value, NULL)) {
         unsigned cut = atoi(value);
-        ALOGV("AAC decoder using AAC_DRC_ATTENUATION_FACTOR of %d instead of %d",
-                        cut, DRC_DEFAULT_MOBILE_DRC_CUT);
-        aacDecoder_SetParam(mAACDecoder, AAC_DRC_ATTENUATION_FACTOR, cut);
+        ALOGV("AAC decoder using desired DRC attenuation factor of %d instead of %d", cut,
+                DRC_DEFAULT_MOBILE_DRC_CUT);
+        mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR, cut);
     } else {
-        aacDecoder_SetParam(mAACDecoder, AAC_DRC_ATTENUATION_FACTOR, DRC_DEFAULT_MOBILE_DRC_CUT);
+        mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR, DRC_DEFAULT_MOBILE_DRC_CUT);
     }
-    //  * AAC_DRC_BOOST_FACTOR (note: no default, using cut)
+    //  DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR
     if (property_get(PROP_DRC_OVERRIDE_BOOST, value, NULL)) {
         unsigned boost = atoi(value);
-        ALOGV("AAC decoder using AAC_DRC_BOOST_FACTOR of %d", boost);
-        aacDecoder_SetParam(mAACDecoder, AAC_DRC_BOOST_FACTOR, boost);
+        ALOGV("AAC decoder using desired DRC boost factor of %d instead of %d", boost,
+                DRC_DEFAULT_MOBILE_DRC_BOOST);
+        mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR, boost);
     } else {
-        aacDecoder_SetParam(mAACDecoder, AAC_DRC_BOOST_FACTOR, DRC_DEFAULT_MOBILE_DRC_BOOST);
+        mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR, DRC_DEFAULT_MOBILE_DRC_BOOST);
+    }
+    //  DRC_PRES_MODE_WRAP_DESIRED_HEAVY
+    if (property_get(PROP_DRC_OVERRIDE_HEAVY, value, NULL)) {
+        unsigned heavy = atoi(value);
+        ALOGV("AAC decoder using desried DRC heavy compression switch of %d instead of %d", heavy,
+                DRC_DEFAULT_MOBILE_DRC_HEAVY);
+        mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_HEAVY, heavy);
+    } else {
+        mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_HEAVY, DRC_DEFAULT_MOBILE_DRC_HEAVY);
+    }
+    // DRC_PRES_MODE_WRAP_ENCODER_TARGET
+    if (property_get(PROP_DRC_OVERRIDE_ENC_LEVEL, value, NULL)) {
+        unsigned encoderRefLevel = atoi(value);
+        ALOGV("AAC decoder using encoder-side DRC reference level of %d instead of %d",
+                encoderRefLevel, DRC_DEFAULT_MOBILE_ENC_LEVEL);
+        mDrcWrap.setParam(DRC_PRES_MODE_WRAP_ENCODER_TARGET, encoderRefLevel);
+    } else {
+        mDrcWrap.setParam(DRC_PRES_MODE_WRAP_ENCODER_TARGET, DRC_DEFAULT_MOBILE_ENC_LEVEL);
     }
 
     return status;
@@ -290,19 +333,101 @@
     return mInputBufferCount > 0;
 }
 
-void SoftAAC2::maybeConfigureDownmix() const {
-    if (mStreamInfo->numChannels > 2) {
-        char value[PROPERTY_VALUE_MAX];
-        if (!(property_get("media.aac_51_output_enabled", value, NULL) &&
-                (!strcmp(value, "1") || !strcasecmp(value, "true")))) {
-            ALOGI("Downmixing multichannel AAC to stereo");
-            aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, 2);
-            mStreamInfo->numChannels = 2;
-            // By default, the decoder creates a 5.1 channel downmix signal
-            // for seven and eight channel input streams. To enable 6.1 and 7.1 channel output
-            // use aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, -1)
+void SoftAAC2::configureDownmix() const {
+    char value[PROPERTY_VALUE_MAX];
+    if (!(property_get("media.aac_51_output_enabled", value, NULL)
+            && (!strcmp(value, "1") || !strcasecmp(value, "true")))) {
+        ALOGI("limiting to stereo output");
+        aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, 2);
+        // By default, the decoder creates a 5.1 channel downmix signal
+        // for seven and eight channel input streams. To enable 6.1 and 7.1 channel output
+        // use aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, -1)
+    }
+}
+
+bool SoftAAC2::outputDelayRingBufferPutSamples(INT_PCM *samples, int32_t numSamples) {
+    if (mOutputDelayRingBufferWritePos + numSamples <= mOutputDelayRingBufferSize
+            && (mOutputDelayRingBufferReadPos <= mOutputDelayRingBufferWritePos
+                    || mOutputDelayRingBufferReadPos > mOutputDelayRingBufferWritePos + numSamples)) {
+        // faster memcopy loop without checks, if the preconditions allow this
+        for (int32_t i = 0; i < numSamples; i++) {
+            mOutputDelayRingBuffer[mOutputDelayRingBufferWritePos++] = samples[i];
+        }
+
+        if (mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferSize) {
+            mOutputDelayRingBufferWritePos -= mOutputDelayRingBufferSize;
+        }
+        if (mOutputDelayRingBufferWritePos == mOutputDelayRingBufferReadPos) {
+            ALOGE("RING BUFFER OVERFLOW");
+            return false;
+        }
+    } else {
+        ALOGV("slow SoftAAC2::outputDelayRingBufferPutSamples()");
+
+        for (int32_t i = 0; i < numSamples; i++) {
+            mOutputDelayRingBuffer[mOutputDelayRingBufferWritePos] = samples[i];
+            mOutputDelayRingBufferWritePos++;
+            if (mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferSize) {
+                mOutputDelayRingBufferWritePos -= mOutputDelayRingBufferSize;
+            }
+            if (mOutputDelayRingBufferWritePos == mOutputDelayRingBufferReadPos) {
+                ALOGE("RING BUFFER OVERFLOW");
+                return false;
+            }
         }
     }
+    return true;
+}
+
+int32_t SoftAAC2::outputDelayRingBufferGetSamples(INT_PCM *samples, int32_t numSamples) {
+    if (mOutputDelayRingBufferReadPos + numSamples <= mOutputDelayRingBufferSize
+            && (mOutputDelayRingBufferWritePos < mOutputDelayRingBufferReadPos
+                    || mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferReadPos + numSamples)) {
+        // faster memcopy loop without checks, if the preconditions allow this
+        if (samples != 0) {
+            for (int32_t i = 0; i < numSamples; i++) {
+                samples[i] = mOutputDelayRingBuffer[mOutputDelayRingBufferReadPos++];
+            }
+        } else {
+            mOutputDelayRingBufferReadPos += numSamples;
+        }
+        if (mOutputDelayRingBufferReadPos >= mOutputDelayRingBufferSize) {
+            mOutputDelayRingBufferReadPos -= mOutputDelayRingBufferSize;
+        }
+    } else {
+        ALOGV("slow SoftAAC2::outputDelayRingBufferGetSamples()");
+
+        for (int32_t i = 0; i < numSamples; i++) {
+            if (mOutputDelayRingBufferWritePos == mOutputDelayRingBufferReadPos) {
+                ALOGE("RING BUFFER UNDERRUN");
+                return -1;
+            }
+            if (samples != 0) {
+                samples[i] = mOutputDelayRingBuffer[mOutputDelayRingBufferReadPos];
+            }
+            mOutputDelayRingBufferReadPos++;
+            if (mOutputDelayRingBufferReadPos >= mOutputDelayRingBufferSize) {
+                mOutputDelayRingBufferReadPos -= mOutputDelayRingBufferSize;
+            }
+        }
+    }
+    return numSamples;
+}
+
+int32_t SoftAAC2::outputDelayRingBufferSamplesAvailable() {
+    int32_t available = mOutputDelayRingBufferWritePos - mOutputDelayRingBufferReadPos;
+    if (available < 0) {
+        available += mOutputDelayRingBufferSize;
+    }
+    if (available < 0) {
+        ALOGE("FATAL RING BUFFER ERROR");
+        return 0;
+    }
+    return available;
+}
+
+int32_t SoftAAC2::outputDelayRingBufferSamplesLeft() {
+    return mOutputDelayRingBufferSize - outputDelayRingBufferSamplesAvailable();
 }
 
 void SoftAAC2::onQueueFilled(OMX_U32 portIndex) {
@@ -318,12 +443,11 @@
     List<BufferInfo *> &outQueue = getPortQueue(1);
 
     if (portIndex == 0 && mInputBufferCount == 0) {
-        ++mInputBufferCount;
-        BufferInfo *info = *inQueue.begin();
-        OMX_BUFFERHEADERTYPE *header = info->mHeader;
+        BufferInfo *inInfo = *inQueue.begin();
+        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
 
-        inBuffer[0] = header->pBuffer + header->nOffset;
-        inBufferLength[0] = header->nFilledLen;
+        inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
+        inBufferLength[0] = inHeader->nFilledLen;
 
         AAC_DECODER_ERROR decoderErr =
             aacDecoder_ConfigRaw(mAACDecoder,
@@ -331,19 +455,25 @@
                                  inBufferLength);
 
         if (decoderErr != AAC_DEC_OK) {
+            ALOGW("aacDecoder_ConfigRaw decoderErr = 0x%4.4x", decoderErr);
             mSignalledError = true;
             notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
             return;
         }
 
-        inQueue.erase(inQueue.begin());
-        info->mOwnedByUs = false;
-        notifyEmptyBufferDone(header);
+        mInputBufferCount++;
+        mOutputBufferCount++; // fake increase of outputBufferCount to keep the counters aligned
 
+        inInfo->mOwnedByUs = false;
+        inQueue.erase(inQueue.begin());
+        inInfo = NULL;
+        notifyEmptyBufferDone(inHeader);
+        inHeader = NULL;
+
+        configureDownmix();
         // Only send out port settings changed event if both sample rate
         // and numChannels are valid.
         if (mStreamInfo->sampleRate && mStreamInfo->numChannels) {
-            maybeConfigureDownmix();
             ALOGI("Initially configuring decoder: %d Hz, %d channels",
                 mStreamInfo->sampleRate,
                 mStreamInfo->numChannels);
@@ -355,146 +485,20 @@
         return;
     }
 
-    while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
-        BufferInfo *inInfo = NULL;
-        OMX_BUFFERHEADERTYPE *inHeader = NULL;
+    while ((!inQueue.empty() || mEndOfInput) && !outQueue.empty()) {
         if (!inQueue.empty()) {
-            inInfo = *inQueue.begin();
-            inHeader = inInfo->mHeader;
-        }
+            INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT];
+            BufferInfo *inInfo = *inQueue.begin();
+            OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
 
-        BufferInfo *outInfo = *outQueue.begin();
-        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
-        outHeader->nFlags = 0;
-
-        if (inHeader) {
             if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
-                mSawInputEos = true;
-            }
-
-            if (inHeader->nOffset == 0 && inHeader->nFilledLen) {
-                mAnchorTimeUs = inHeader->nTimeStamp;
-                mNumSamplesOutput = 0;
-            }
-
-            if (mIsADTS && inHeader->nFilledLen) {
-                size_t adtsHeaderSize = 0;
-                // skip 30 bits, aac_frame_length follows.
-                // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
-
-                const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;
-
-                bool signalError = false;
-                if (inHeader->nFilledLen < 7) {
-                    ALOGE("Audio data too short to contain even the ADTS header. "
-                          "Got %d bytes.", inHeader->nFilledLen);
-                    hexdump(adtsHeader, inHeader->nFilledLen);
-                    signalError = true;
-                } else {
-                    bool protectionAbsent = (adtsHeader[1] & 1);
-
-                    unsigned aac_frame_length =
-                        ((adtsHeader[3] & 3) << 11)
-                        | (adtsHeader[4] << 3)
-                        | (adtsHeader[5] >> 5);
-
-                    if (inHeader->nFilledLen < aac_frame_length) {
-                        ALOGE("Not enough audio data for the complete frame. "
-                              "Got %d bytes, frame size according to the ADTS "
-                              "header is %u bytes.",
-                              inHeader->nFilledLen, aac_frame_length);
-                        hexdump(adtsHeader, inHeader->nFilledLen);
-                        signalError = true;
-                    } else {
-                        adtsHeaderSize = (protectionAbsent ? 7 : 9);
-
-                        inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize;
-                        inBufferLength[0] = aac_frame_length - adtsHeaderSize;
-
-                        inHeader->nOffset += adtsHeaderSize;
-                        inHeader->nFilledLen -= adtsHeaderSize;
-                    }
-                }
-
-                if (signalError) {
-                    mSignalledError = true;
-
-                    notify(OMX_EventError,
-                           OMX_ErrorStreamCorrupt,
-                           ERROR_MALFORMED,
-                           NULL);
-
-                    return;
-                }
+                mEndOfInput = true;
             } else {
-                inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
-                inBufferLength[0] = inHeader->nFilledLen;
+                mEndOfInput = false;
             }
-        } else {
-            inBufferLength[0] = 0;
-        }
-
-        // Fill and decode
-        INT_PCM *outBuffer = reinterpret_cast<INT_PCM *>(
-                outHeader->pBuffer + outHeader->nOffset);
-
-        bytesValid[0] = inBufferLength[0];
-
-        int prevSampleRate = mStreamInfo->sampleRate;
-        int prevNumChannels = mStreamInfo->numChannels;
-
-        AAC_DECODER_ERROR decoderErr = AAC_DEC_NOT_ENOUGH_BITS;
-        while ((bytesValid[0] > 0 || mSawInputEos) && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
-            mDecoderHasData |= (bytesValid[0] > 0);
-            aacDecoder_Fill(mAACDecoder,
-                            inBuffer,
-                            inBufferLength,
-                            bytesValid);
-
-            decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
-                                                outBuffer,
-                                                outHeader->nAllocLen,
-                                                0 /* flags */);
-            if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
-                if (mSawInputEos && bytesValid[0] <= 0) {
-                    if (mDecoderHasData) {
-                        // flush out the decoder's delayed data by calling DecodeFrame
-                        // one more time, with the AACDEC_FLUSH flag set
-                        decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
-                                                            outBuffer,
-                                                            outHeader->nAllocLen,
-                                                            AACDEC_FLUSH);
-                        mDecoderHasData = false;
-                    }
-                    outHeader->nFlags = OMX_BUFFERFLAG_EOS;
-                    mSignalledOutputEos = true;
-                    break;
-                } else {
-                    ALOGW("Not enough bits, bytesValid %d", bytesValid[0]);
-                }
-            }
-        }
-
-        size_t numOutBytes =
-            mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
-
-        if (inHeader) {
-            if (decoderErr == AAC_DEC_OK) {
-                UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
-                inHeader->nFilledLen -= inBufferUsedLength;
-                inHeader->nOffset += inBufferUsedLength;
-            } else {
-                ALOGW("AAC decoder returned error %d, substituting silence",
-                      decoderErr);
-
-                memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes);
-
-                // Discard input buffer.
-                inHeader->nFilledLen = 0;
-
-                aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
-
-                // fall through
+            if (inHeader->nOffset == 0) { // TODO: does nOffset != 0 happen?
+                mAnchorTimeUs[mInputBufferCount % kNumDelayBlocksMax] =
+                        inHeader->nTimeStamp;
             }
 
             if (inHeader->nFilledLen == 0) {
@@ -503,54 +507,282 @@
                 inInfo = NULL;
                 notifyEmptyBufferDone(inHeader);
                 inHeader = NULL;
+            } else {
+                if (mIsADTS) {
+                    size_t adtsHeaderSize = 0;
+                    // skip 30 bits, aac_frame_length follows.
+                    // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
+
+                    const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;
+
+                    bool signalError = false;
+                    if (inHeader->nFilledLen < 7) {
+                        ALOGE("Audio data too short to contain even the ADTS header. "
+                                "Got %d bytes.", inHeader->nFilledLen);
+                        hexdump(adtsHeader, inHeader->nFilledLen);
+                        signalError = true;
+                    } else {
+                        bool protectionAbsent = (adtsHeader[1] & 1);
+
+                        unsigned aac_frame_length =
+                            ((adtsHeader[3] & 3) << 11)
+                            | (adtsHeader[4] << 3)
+                            | (adtsHeader[5] >> 5);
+
+                        if (inHeader->nFilledLen < aac_frame_length) {
+                            ALOGE("Not enough audio data for the complete frame. "
+                                    "Got %d bytes, frame size according to the ADTS "
+                                    "header is %u bytes.",
+                                    inHeader->nFilledLen, aac_frame_length);
+                            hexdump(adtsHeader, inHeader->nFilledLen);
+                            signalError = true;
+                        } else {
+                            adtsHeaderSize = (protectionAbsent ? 7 : 9);
+
+                            inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize;
+                            inBufferLength[0] = aac_frame_length - adtsHeaderSize;
+
+                            inHeader->nOffset += adtsHeaderSize;
+                            inHeader->nFilledLen -= adtsHeaderSize;
+                        }
+                    }
+
+                    if (signalError) {
+                        mSignalledError = true;
+
+                        notify(OMX_EventError,
+                               OMX_ErrorStreamCorrupt,
+                               ERROR_MALFORMED,
+                               NULL);
+
+                        return;
+                    }
+                } else {
+                    inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
+                    inBufferLength[0] = inHeader->nFilledLen;
+                }
+
+                // Fill and decode
+                bytesValid[0] = inBufferLength[0];
+
+                INT prevSampleRate = mStreamInfo->sampleRate;
+                INT prevNumChannels = mStreamInfo->numChannels;
+
+                aacDecoder_Fill(mAACDecoder,
+                                inBuffer,
+                                inBufferLength,
+                                bytesValid);
+
+                 // run DRC check
+                 mDrcWrap.submitStreamData(mStreamInfo);
+                 mDrcWrap.update();
+
+                AAC_DECODER_ERROR decoderErr =
+                    aacDecoder_DecodeFrame(mAACDecoder,
+                                           tmpOutBuffer,
+                                           2048 * MAX_CHANNEL_COUNT,
+                                           0 /* flags */);
+
+                if (decoderErr != AAC_DEC_OK) {
+                    ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
+                }
+
+                if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
+                    ALOGE("AAC_DEC_NOT_ENOUGH_BITS should never happen");
+                    mSignalledError = true;
+                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                    return;
+                }
+
+                if (bytesValid[0] != 0) {
+                    ALOGE("bytesValid[0] != 0 should never happen");
+                    mSignalledError = true;
+                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                    return;
+                }
+
+                size_t numOutBytes =
+                    mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
+
+                if (decoderErr == AAC_DEC_OK) {
+                    if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
+                            mStreamInfo->frameSize * mStreamInfo->numChannels)) {
+                        mSignalledError = true;
+                        notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+                        return;
+                    }
+                    UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
+                    inHeader->nFilledLen -= inBufferUsedLength;
+                    inHeader->nOffset += inBufferUsedLength;
+                } else {
+                    ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr);
+
+                    memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow
+
+                    if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
+                            mStreamInfo->frameSize * mStreamInfo->numChannels)) {
+                        mSignalledError = true;
+                        notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+                        return;
+                    }
+
+                    // Discard input buffer.
+                    inHeader->nFilledLen = 0;
+
+                    aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
+
+                    // fall through
+                }
+
+                /*
+                 * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
+                 * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
+                 * rate system and the sampling rate in the final output is actually
+                 * doubled compared with the core AAC decoder sampling rate.
+                 *
+                 * Explicit signalling is done by explicitly defining SBR audio object
+                 * type in the bitstream. Implicit signalling is done by embedding
+                 * SBR content in AAC extension payload specific to SBR, and hence
+                 * requires an AAC decoder to perform pre-checks on actual audio frames.
+                 *
+                 * Thus, we could not say for sure whether a stream is
+                 * AAC+/eAAC+ until the first data frame is decoded.
+                 */
+                if (mOutputBufferCount > 1) {
+                    if (mStreamInfo->sampleRate != prevSampleRate ||
+                        mStreamInfo->numChannels != prevNumChannels) {
+                        ALOGE("can not reconfigure AAC output");
+                        mSignalledError = true;
+                        notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+                        return;
+                    }
+                }
+                if (mInputBufferCount <= 2) { // TODO: <= 1
+                    if (mStreamInfo->sampleRate != prevSampleRate ||
+                        mStreamInfo->numChannels != prevNumChannels) {
+                        ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels",
+                              prevSampleRate, mStreamInfo->sampleRate,
+                              prevNumChannels, mStreamInfo->numChannels);
+
+                        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+                        mOutputPortSettingsChange = AWAITING_DISABLED;
+
+                        if (inHeader->nFilledLen == 0) {
+                            inInfo->mOwnedByUs = false;
+                            mInputBufferCount++;
+                            inQueue.erase(inQueue.begin());
+                            inInfo = NULL;
+                            notifyEmptyBufferDone(inHeader);
+                            inHeader = NULL;
+                        }
+                        return;
+                    }
+                } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) {
+                    ALOGW("Invalid AAC stream");
+                    mSignalledError = true;
+                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+                    return;
+                }
+                if (inHeader->nFilledLen == 0) {
+                    inInfo->mOwnedByUs = false;
+                    mInputBufferCount++;
+                    inQueue.erase(inQueue.begin());
+                    inInfo = NULL;
+                    notifyEmptyBufferDone(inHeader);
+                    inHeader = NULL;
+                } else {
+                    ALOGW("inHeader->nFilledLen = %d", inHeader->nFilledLen);
+                }
             }
         }
 
-        /*
-         * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
-         * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
-         * rate system and the sampling rate in the final output is actually
-         * doubled compared with the core AAC decoder sampling rate.
-         *
-         * Explicit signalling is done by explicitly defining SBR audio object
-         * type in the bitstream. Implicit signalling is done by embedding
-         * SBR content in AAC extension payload specific to SBR, and hence
-         * requires an AAC decoder to perform pre-checks on actual audio frames.
-         *
-         * Thus, we could not say for sure whether a stream is
-         * AAC+/eAAC+ until the first data frame is decoded.
-         */
-        if (mInputBufferCount <= 2) {
-            if (mStreamInfo->sampleRate != prevSampleRate ||
-                mStreamInfo->numChannels != prevNumChannels) {
-                maybeConfigureDownmix();
-                ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels",
-                      prevSampleRate, mStreamInfo->sampleRate,
-                      prevNumChannels, mStreamInfo->numChannels);
+        int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels;
 
-                notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
-                mOutputPortSettingsChange = AWAITING_DISABLED;
+        if (!mEndOfInput && mOutputDelayCompensated < outputDelay) {
+            // discard outputDelay at the beginning
+            int32_t toCompensate = outputDelay - mOutputDelayCompensated;
+            int32_t discard = outputDelayRingBufferSamplesAvailable();
+            if (discard > toCompensate) {
+                discard = toCompensate;
+            }
+            int32_t discarded = outputDelayRingBufferGetSamples(0, discard);
+            mOutputDelayCompensated += discarded;
+            continue;
+        }
+
+        if (mEndOfInput) {
+            while (mOutputDelayCompensated > 0) {
+                // a buffer big enough for MAX_CHANNEL_COUNT channels of decoded HE-AAC
+                INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT];
+ 
+                 // run DRC check
+                 mDrcWrap.submitStreamData(mStreamInfo);
+                 mDrcWrap.update();
+
+                AAC_DECODER_ERROR decoderErr =
+                    aacDecoder_DecodeFrame(mAACDecoder,
+                                           tmpOutBuffer,
+                                           2048 * MAX_CHANNEL_COUNT,
+                                           AACDEC_FLUSH);
+                if (decoderErr != AAC_DEC_OK) {
+                    ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
+                }
+
+                int32_t tmpOutBufferSamples = mStreamInfo->frameSize * mStreamInfo->numChannels;
+                if (tmpOutBufferSamples > mOutputDelayCompensated) {
+                    tmpOutBufferSamples = mOutputDelayCompensated;
+                }
+                outputDelayRingBufferPutSamples(tmpOutBuffer, tmpOutBufferSamples);
+                mOutputDelayCompensated -= tmpOutBufferSamples;
+            }
+        }
+
+        while (!outQueue.empty()
+                && outputDelayRingBufferSamplesAvailable()
+                        >= mStreamInfo->frameSize * mStreamInfo->numChannels) {
+            BufferInfo *outInfo = *outQueue.begin();
+            OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+            if (outHeader->nOffset != 0) {
+                ALOGE("outHeader->nOffset != 0 is not handled");
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                 return;
             }
-        } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) {
-            ALOGW("Invalid AAC stream");
-            mSignalledError = true;
-            notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
-            return;
-        }
 
-        if (decoderErr == AAC_DEC_OK || mNumSamplesOutput > 0) {
-            // We'll only output data if we successfully decoded it or
-            // we've previously decoded valid data, in the latter case
-            // (decode failed) we'll output a silent frame.
-            outHeader->nFilledLen = numOutBytes;
+            INT_PCM *outBuffer =
+                    reinterpret_cast<INT_PCM *>(outHeader->pBuffer + outHeader->nOffset);
+            if (outHeader->nOffset
+                    + mStreamInfo->frameSize * mStreamInfo->numChannels * sizeof(int16_t)
+                    > outHeader->nAllocLen) {
+                ALOGE("buffer overflow");
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                return;
 
-            outHeader->nTimeStamp =
-                mAnchorTimeUs
-                    + (mNumSamplesOutput * 1000000ll) / mStreamInfo->sampleRate;
+            }
+            int32_t ns = outputDelayRingBufferGetSamples(outBuffer,
+                    mStreamInfo->frameSize * mStreamInfo->numChannels); // TODO: check for overflow
+            if (ns != mStreamInfo->frameSize * mStreamInfo->numChannels) {
+                ALOGE("not a complete frame of samples available");
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                return;
+            }
 
-            mNumSamplesOutput += mStreamInfo->frameSize;
+            outHeader->nFilledLen = mStreamInfo->frameSize * mStreamInfo->numChannels
+                    * sizeof(int16_t);
+            if (mEndOfInput && !outQueue.empty() && outputDelayRingBufferSamplesAvailable() == 0) {
+                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+                mEndOfOutput = true;
+            } else {
+                outHeader->nFlags = 0;
+            }
 
+            outHeader->nTimeStamp = mAnchorTimeUs[mOutputBufferCount
+                    % kNumDelayBlocksMax];
+
+            mOutputBufferCount++;
             outInfo->mOwnedByUs = false;
             outQueue.erase(outQueue.begin());
             outInfo = NULL;
@@ -558,8 +790,48 @@
             outHeader = NULL;
         }
 
-        if (decoderErr == AAC_DEC_OK) {
-            ++mInputBufferCount;
+        if (mEndOfInput) {
+            if (outputDelayRingBufferSamplesAvailable() > 0
+                    && outputDelayRingBufferSamplesAvailable()
+                            < mStreamInfo->frameSize * mStreamInfo->numChannels) {
+                ALOGE("not a complete frame of samples available");
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                return;
+            }
+
+            if (mEndOfInput && !outQueue.empty() && outputDelayRingBufferSamplesAvailable() == 0) {
+                if (!mEndOfOutput) {
+                    // send empty block signaling EOS
+                    mEndOfOutput = true;
+                    BufferInfo *outInfo = *outQueue.begin();
+                    OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+                    if (outHeader->nOffset != 0) {
+                        ALOGE("outHeader->nOffset != 0 is not handled");
+                        mSignalledError = true;
+                        notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                        return;
+                    }
+
+                    INT_PCM *outBuffer = reinterpret_cast<INT_PCM *>(outHeader->pBuffer
+                            + outHeader->nOffset);
+                    int32_t ns = 0;
+                    outHeader->nFilledLen = 0;
+                    outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+                    outHeader->nTimeStamp = mAnchorTimeUs[mOutputBufferCount
+                            % kNumDelayBlocksMax];
+
+                    mOutputBufferCount++;
+                    outInfo->mOwnedByUs = false;
+                    outQueue.erase(outQueue.begin());
+                    outInfo = NULL;
+                    notifyFillBufferDone(outHeader);
+                    outHeader = NULL;
+                }
+                break; // if outQueue not empty but no more output
+            }
         }
     }
 }
@@ -574,34 +846,68 @@
         // but only if initialization has already happened.
         if (mInputBufferCount != 0) {
             mInputBufferCount = 1;
-            mStreamInfo->sampleRate = 0;
+            mOutputBufferCount = -1;
         }
+    } else {
+        while (outputDelayRingBufferSamplesAvailable() > 0) {
+            int32_t ns = outputDelayRingBufferGetSamples(0,
+                    mStreamInfo->frameSize * mStreamInfo->numChannels);
+            if (ns != mStreamInfo->frameSize * mStreamInfo->numChannels) {
+                ALOGE("not a complete frame of samples available");
+            }
+            mOutputBufferCount++;
+        }
+        mOutputDelayRingBufferReadPos = mOutputDelayRingBufferWritePos;
     }
 }
 
 void SoftAAC2::drainDecoder() {
-    // a buffer big enough for 6 channels of decoded HE-AAC
-    short buf [2048*6];
-    aacDecoder_DecodeFrame(mAACDecoder,
-            buf, sizeof(buf), AACDEC_FLUSH | AACDEC_CLRHIST | AACDEC_INTR);
-    aacDecoder_DecodeFrame(mAACDecoder,
-            buf, sizeof(buf), AACDEC_FLUSH | AACDEC_CLRHIST | AACDEC_INTR);
-    aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
-    mDecoderHasData = false;
+    int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels;
+
+    // flush decoder until outputDelay is compensated
+    while (mOutputDelayCompensated > 0) {
+        // a buffer big enough for MAX_CHANNEL_COUNT channels of decoded HE-AAC
+        INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT];
+
+        // run DRC check
+        mDrcWrap.submitStreamData(mStreamInfo);
+        mDrcWrap.update();
+
+        AAC_DECODER_ERROR decoderErr =
+            aacDecoder_DecodeFrame(mAACDecoder,
+                                   tmpOutBuffer,
+                                   2048 * MAX_CHANNEL_COUNT,
+                                   AACDEC_FLUSH);
+        if (decoderErr != AAC_DEC_OK) {
+            ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
+        }
+
+        int32_t tmpOutBufferSamples = mStreamInfo->frameSize * mStreamInfo->numChannels;
+        if (tmpOutBufferSamples > mOutputDelayCompensated) {
+            tmpOutBufferSamples = mOutputDelayCompensated;
+        }
+        outputDelayRingBufferPutSamples(tmpOutBuffer, tmpOutBufferSamples);
+
+        mOutputDelayCompensated -= tmpOutBufferSamples;
+    }
 }
 
 void SoftAAC2::onReset() {
     drainDecoder();
     // reset the "configured" state
     mInputBufferCount = 0;
-    mNumSamplesOutput = 0;
+    mOutputBufferCount = 0;
+    mOutputDelayCompensated = 0;
+    mOutputDelayRingBufferWritePos = 0;
+    mOutputDelayRingBufferReadPos = 0;
+    mEndOfInput = false;
+    mEndOfOutput = false;
+
     // To make the codec behave the same before and after a reset, we need to invalidate the
     // streaminfo struct. This does that:
-    mStreamInfo->sampleRate = 0;
+    mStreamInfo->sampleRate = 0; // TODO: mStreamInfo is read only
 
     mSignalledError = false;
-    mSawInputEos = false;
-    mSignalledOutputEos = false;
     mOutputPortSettingsChange = NONE;
 }
 
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h
index a7ea1e2..5cde03a 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h
@@ -20,6 +20,7 @@
 #include "SimpleSoftOMXComponent.h"
 
 #include "aacdecoder_lib.h"
+#include "DrcPresModeWrap.h"
 
 namespace android {
 
@@ -47,18 +48,19 @@
     enum {
         kNumInputBuffers        = 4,
         kNumOutputBuffers       = 4,
+        kNumDelayBlocksMax      = 8,
     };
 
     HANDLE_AACDECODER mAACDecoder;
     CStreamInfo *mStreamInfo;
     bool mIsADTS;
-    bool mDecoderHasData;
+    bool mIsFirst;
     size_t mInputBufferCount;
+    size_t mOutputBufferCount;
     bool mSignalledError;
-    bool mSawInputEos;
-    bool mSignalledOutputEos;
-    int64_t mAnchorTimeUs;
-    int64_t mNumSamplesOutput;
+    int64_t mAnchorTimeUs[kNumDelayBlocksMax];
+
+    CDrcPresModeWrapper mDrcWrap;
 
     enum {
         NONE,
@@ -69,9 +71,22 @@
     void initPorts();
     status_t initDecoder();
     bool isConfigured() const;
-    void maybeConfigureDownmix() const;
+    void configureDownmix() const;
     void drainDecoder();
 
+//      delay compensation
+    bool mEndOfInput;
+    bool mEndOfOutput;
+    int32_t mOutputDelayCompensated;
+    int32_t mOutputDelayRingBufferSize;
+    short *mOutputDelayRingBuffer;
+    int32_t mOutputDelayRingBufferWritePos;
+    int32_t mOutputDelayRingBufferReadPos;
+    bool outputDelayRingBufferPutSamples(INT_PCM *samples, int numSamples);
+    int32_t outputDelayRingBufferGetSamples(INT_PCM *samples, int numSamples);
+    int32_t outputDelayRingBufferSamplesAvailable();
+    int32_t outputDelayRingBufferSamplesLeft();
+
     DISALLOW_EVIL_CONSTRUCTORS(SoftAAC2);
 };
 
diff --git a/media/libstagefright/codecs/hevcdec/Android.mk b/media/libstagefright/codecs/hevcdec/Android.mk
index 2fe347b..960602f 100644
--- a/media/libstagefright/codecs/hevcdec/Android.mk
+++ b/media/libstagefright/codecs/hevcdec/Android.mk
@@ -1,3 +1,5 @@
+ifeq ($(if $(wildcard external/libhevc),1,0),1)
+
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
@@ -20,3 +22,5 @@
 
 
 include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_dct_9_arm.s b/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_dct_9_arm.s
deleted file mode 100644
index 3a6dd4f..0000000
--- a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_dct_9_arm.s
+++ /dev/null
@@ -1,210 +0,0 @@
-; ------------------------------------------------------------------
-; Copyright (C) 1998-2009 PacketVideo
-;
-; Licensed under the Apache License, Version 2.0 (the "License");
-; you may not use this file except in compliance with the License.
-; You may obtain a copy of the License at
-;
-;      http://www.apache.org/licenses/LICENSE-2.0
-;
-; Unless required by applicable law or agreed to in writing, software
-; distributed under the License is distributed on an "AS IS" BASIS,
-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
-; express or implied.
-; See the License for the specific language governing permissions
-; and limitations under the License.
-; -------------------------------------------------------------------
-
-;
-;
-;   Filename: pvmp3_dct_9.s
-;
-;------------------------------------------------------------------------------
-; REVISION HISTORY
-;
-;
-; Who:                                   Date: MM/DD/YYYY
-; Description: 
-;
-;------------------------------------------------------------------------------
-
-  AREA  |.drectve|, DRECTVE
-
-    DCB "-defaultlib:coredll.lib "
-    DCB "-defaultlib:corelibc.lib "
-
-  IMPORT pvmp3_mdct_18 ; pvmp3_mdct_18.cpp
-
-;------------------------------------------------------------------------------
-
-  AREA  |.rdata|, DATA, READONLY
-  % 4
-
-
-;------------------------------------------------------------------------------
-
-  AREA  |.text|, CODE, READONLY
-
-
-;------------------------------------------------------------------------------
-
- EXPORT |pvmp3_dct_9|
-
-|pvmp3_dct_9| PROC
-        stmfd    sp!,{r4-r10,lr}
-        ldr      r2, [r0, #0x20]
-        ldr      r3, [r0]
-        ldr      r12,[r0, #4]
-        add      r1,r2,r3
-        sub      lr,r2,r3
-        ldr      r3,[r0, #0x1c]
-        ldr      r4,[r0, #0x18]
-        add      r2,r3,r12
-        ldr      r5,[r0,#8]
-        sub      r3,r3,r12
-        add      r12,r4,r5
-        sub      r4,r4,r5
-        ldr      r5,[r0, #0x14]
-        ldr      r7,[r0, #0xc]
-        ldr      r9,[r0, #0x10]
-        add      r6,r5,r7
-        sub      r5,r5,r7
-        add      r7,r1,r12
-        add      r8,r9,r2
-        add      r7,r7,r6
-        add      r10,r7,r8
-        rsb      r7,r8,r7,asr #1
-        str      r7,[r0, #0x18]
-        rsb      r2,r9,r2,asr #1
-        str      r10,[r0]
-        ldr      r11,|cos_2pi_9|
-        rsb      r7,r2,#0
-
-        mov      r9,r1,lsl #1
-		mov      r1,r9			;;;;;;  !!!!!!
-        mov      r8,r7
-
-;    vec[4]  = fxp_mac32_Q32( vec[4], tmp0<<1, cos_2pi_9); 
-
-        smlal    r1,r8,r11,r9
-        ldr      r10,|cos_4pi_9|
-        ldr      r11,|cos_pi_9|
-
-;    vec[8]  = fxp_mac32_Q32( vec[8], tmp0<<1, cos_4pi_9);
-
-        smlal    r1,r7,r10,r9
-
-
-
-;    vec[2]  = fxp_mac32_Q32( vec[2], tmp0<<1, cos_pi_9);
-
-        smlal    r9,r2,r11,r9
-        mov      r1,r12,lsl #1
-        rsb      r9,r10,#0
-        ldr      r11,|cos_5pi_9|
-
-        smlal    r12,r2,r9,r1
-
-
-
-;    vec[2]  = fxp_mac32_Q32( vec[2], tmp2<<1, cos_5pi_9);
-
-        ldr      r9,|cos_2pi_9|
-        mov      r12,r1			;;;;;;  !!!!!!
-        smlal    r12,r8,r11,r1
-
-
-;    vec[8]  = fxp_mac32_Q32( vec[8], tmp2<<1, cos_2pi_9);
-
-        smlal    r1,r7,r9,r1
-        mov      r1,r6,lsl #1
-        smlal    r12,r7,r11,r1
-        and      r6,r10,r11,asr #14
-        smlal    r12,r8,r6,r1
-        ldr      r10,|cos_11pi_18|
-        add      r12,r11,r6
-        smlal    r1,r2,r12,r1
-        ldr      r9,|cos_8pi_9|
-        str      r2,[r0,#8]
-        mov      r1,r5,lsl #1
-
-;    vec[8]  = fxp_mac32_Q32( vec[8], tmp3<<1, cos_8pi_9);
-
-        smull    r2,r6,r9,r1
-        str      r7,[r0,#0x20]
-        mov      r2,r4,lsl #1
-        ldr      r7,|cos_13pi_18|
-        smlal    r12,r6,r10,r2
-
-        mov      r3,r3,lsl #1
-
-;    vec[5]  = fxp_mac32_Q32( vec[5], tmp8<<1, cos_13pi_18);
-
-        smlal    r12,r6,r7,r3
-        add      r4,r5,r4
-        mov      r12,lr,lsl #1
-        sub      lr,r4,lr
-        ldr      r7,|cos_17pi_18|
-        str      r8,[r0, #0x10]
-        ldr      r4,|cos_pi_6|
-
-        mov      lr,lr,lsl #1
-
-;    vec[1]  = fxp_mac32_Q32( vec[1], tmp8<<1, cos_17pi_18);
-
-        smlal    r8,r6,r7,r12
-
-;    vec[3]  = fxp_mul32_Q32((tmp5 + tmp6  - tmp8)<<1, cos_pi_6);
-
-        smull    r5,lr,r4,lr
-        str      r6,[r0, #4]
-        str      lr,[r0, #0xc]
-
-
-;    vec[5]  = fxp_mul32_Q32(tmp5<<1, cos_17pi_18);
-        smull    r5,lr,r7,r1
-        rsb      r6,r9,#0
-;    vec[5]  = fxp_mac32_Q32( vec[5], tmp6<<1,  cos_7pi_18);
-        smlal    r5,lr,r6,r2
-;    vec[5]  = fxp_mac32_Q32( vec[5], tmp7<<1,    cos_pi_6);
-        smlal    r5,lr,r4,r3
-;    vec[5]  = fxp_mac32_Q32( vec[5], tmp8<<1, cos_13pi_18);
-        smlal    r5,lr,r10,r12
-        str      lr,[r0, #0x14]
-        rsb      lr,r10,#0
-
-;    vec[7]  = fxp_mul32_Q32(tmp5<<1, cos_5pi_18);
-        smull    r5,r1,lr,r1
-;    vec[7]  = fxp_mac32_Q32( vec[7], tmp6<<1, cos_17pi_18);
-        smlal    r2,r1,r7,r2
-;    vec[7]  = fxp_mac32_Q32( vec[7], tmp7<<1,    cos_pi_6);
-        smlal    r3,r1,r4,r3
-;    vec[7]  = fxp_mac32_Q32( vec[7], tmp8<<1, cos_11pi_18);
-        smlal    r12,r1,r9,r12
-        str      r1,[r0, #0x1c]
-        ldmfd    sp!,{r4-r10,pc}
-|cos_2pi_9|
-        DCD      0x620dbe80
-|cos_4pi_9|
-        DCD      0x163a1a80
-|cos_pi_9|
-        DCD      0x7847d900
-|cos_5pi_9|
-        DCD      0x87b82700
-|cos_8pi_9|
-        DCD      0xd438af00
-|cos_11pi_18|
-        DCD      0xadb92280
-|cos_13pi_18|
-        DCD      0x91261480
-|cos_17pi_18|
-        DCD      0x81f1d200
-|cos_pi_6|
-        DCD      0x6ed9eb80
-        ENDP
-
-
-
-
-
-        END
diff --git a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_mdct_18_arm.s b/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_mdct_18_arm.s
deleted file mode 100644
index 9401d8c..0000000
--- a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_mdct_18_arm.s
+++ /dev/null
@@ -1,369 +0,0 @@
-; ------------------------------------------------------------------
-; Copyright (C) 1998-2009 PacketVideo
-;
-; Licensed under the Apache License, Version 2.0 (the "License");
-; you may not use this file except in compliance with the License.
-; You may obtain a copy of the License at
-;
-;      http://www.apache.org/licenses/LICENSE-2.0
-;
-; Unless required by applicable law or agreed to in writing, software
-; distributed under the License is distributed on an "AS IS" BASIS,
-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
-; express or implied.
-; See the License for the specific language governing permissions
-; and limitations under the License.
-; -------------------------------------------------------------------
-
-;
-;
-;   Filename: pvmp3_dct_18.s
-;
-;------------------------------------------------------------------------------
-; REVISION HISTORY
-;
-;
-; Who:                                   Date: MM/DD/YYYY
-; Description: 
-;
-;------------------------------------------------------------------------------
-
-        EXPORT pvmp3_mdct_18
-
-        IMPORT ||Lib$$Request$$armlib|| [WEAK]
-        IMPORT ||Lib$$Request$$cpplib|| [WEAK]
-        IMPORT pvmp3_dct_9
-
-
-;------------------------------------------------------------------------------
-
- AREA |.text|, CODE, READONLY, ALIGN=2
-
-
-;------------------------------------------------------------------------------
-
-|pvmp3_mdct_18| PROC
-        stmfd    sp!,{r4-r10,lr}
-        mov      r7,r2
-        ldr      r2,table
-        mov      r6,r1
-        add      r3,r2,#0x24
-        add      r12,r3,#0x44
-        add      r1,r0,#0x44
-        mov      r5,r0
-
-;    for ( i=9; i!=0; i--)
-;    {
-
-        mov      r4,#9
-Loop_1
-
-;       tmp  = *(pt_vec);
-;		tmp1 = *(pt_vec_o);
-
-        ldr      lr,[r0]		;; tmp  == lr
-        ldr      r8,[r3],#4		;; tmp1 == r8
-
-;        tmp  = fxp_mul32_Q32( tmp<<1,  *(pt_cos++  ));
-;        tmp1 = fxp_mul32_Q27( tmp1, *(pt_cos_x--));
-
-        mov      lr,lr,lsl #1
-        smull    r10,lr,r8,lr
-        ldr      r8,[r12],#-4
-        ldr      r9,[r1]
-        subs     r4,r4,#1
-        smull    r9,r10,r8,r9
-        mov      r8,r9,lsr #27
-        add      r8,r8,r10,lsl #5
-
-;        *(pt_vec++)   =   tmp + tmp1 ;
-;        *(pt_vec_o--) = fxp_mul32_Q28( (tmp - tmp1), *(pt_cos_split++));
-
-        add      r9,lr,r8
-        sub      r8,lr,r8
-        ldr      lr,[r2],#4
-        str      r9,[r0],#4
-        smull    r8,r9,lr,r8
-        mov      lr,r8,lsr #28
-        add      lr,lr,r9,lsl #4
-        str      lr,[r1],#-4
-        bne      Loop_1
-
-;		}
-
-        mov      r0,r5			;; r0 = vec
-        bl       pvmp3_dct_9
-        add      r0,r5,#0x24	;; r0 = &vec[9]
-        bl       pvmp3_dct_9
-
-        ldr      r0,[r5,#0x20]
-        ldr      r2,[r5,#0x40]
-        str      r0,[r5,#0x40]
-        ldr      r0,[r5,#0x1c]
-        ldr      r3,[r5,#0x38]
-        str      r0,[r5,#0x38]
-        ldr      r1,[r5,#0x18]
-        ldr      r0,[r5,#0x30]
-        str      r1,[r5,#0x30]
-        ldr      r12,[r5,#0x14]
-        ldr      r1,[r5,#0x28]
-        str      r12,[r5,#0x28]
-        ldr      r12,[r5,#0x10]
-        str      r12,[r5,#0x20]
-        ldr      r12,[r5,#0xc]
-        str      r12,[r5,#0x18]
-        ldr      r12,[r5,#8]
-        str      r12,[r5,#0x10]
-        ldr      r12,[r5,#4]
-        str      r12,[r5,#8]
-        ldr      r12,[r5,#0x24]
-        sub      r12,r12,r1
-        str      r12,[r5,#4]
-        ldr      r12,[r5,#0x2c]
-        sub      r1,r12,r1
-        str      r1,[r5,#0xc]
-        sub      r1,r12,r0
-        str      r1,[r5,#0x14]
-        ldr      r1,[r5,#0x34]
-        sub      r0,r1,r0
-        str      r0,[r5,#0x1c]
-        sub      r0,r1,r3
-        str      r0,[r5,#0x24]
-        ldr      r1,[r5,#0x3c]
-        sub      r3,r1,r3
-        sub      r1,r1,r2
-        str      r1,[r5,#0x34]
-        str      r3,[r5,#0x2c]
-        ldr      r1,[r5,#0x44]
-        sub      r1,r1,r2
-        str      r1,[r5,#0x3c]
-        ldr      r12,[r5,#0]
-
-Loop_2
-        add      r1,r5,r4,lsl #2
-        ldr      r2,[r1,#0x28]
-        ldr      r3,[r6,r4,lsl #2]
-        add      r0,r0,r2
-        str      r0,[r1,#0x28]
-        ldr      lr,[r7,r4,lsl #2]
-        ldr      r1,[r1,#4]
-        smlal    r0,r3,lr,r0
-        mov      r0,r2
-        add      r2,r12,r1
-        rsb      r2,r2,#0
-        str      r3,[r5,r4,lsl #2]
-        str      r2,[r6,r4,lsl #2]
-        add      r4,r4,#1
-        cmp      r4,#6
-        mov      r12,r1
-
-        blt      Loop_2
-
-        ldr      r1,[r5,#0x40]
-        ldr      r2,[r6,#0x18]
-        add      r3,r0,r1
-        str      r3,[r5,#0x40]
-        ldr      lr,[r7,r4,lsl #2]
-        mov      r3,r3,lsl #1
-        ldr      r0,[r5,#0x1c]
-        smlal    r3,r2,lr,r3
-        add      r3,r12,r0
-        str      r2,[r5,#0x18]
-        ldr      r2,[r6,#0x1c]
-        rsb      r3,r3,#0
-        str      r3,[r6,#0x18]
-        ldr      r3,[r5,#0x20]
-        add      r0,r3,r0
-        rsb      r0,r0,#0
-        str      r0,[r6,#0x1c]
-        ldr      r3,[r5,#0x44]
-        ldr      r0,[r6,#0x20]
-        add      r3,r3,r1
-        mov      r1,r2
-        ldr      r10,[r7,#0x1c]
-        mov      r2,r3,lsl #1
-        smlal    r12,r1,r10,r2
-        str      r1,[r5,#0x1c]
-        ldr      r1,[r5,#0x20]
-        ldr      r3,[r5,#0x24]
-        add      r1,r1,r3
-        rsb      r1,r1,#0
-        str      r1,[r6,#0x20]
-        ldr      r1,[r5,#0x44]
-        ldr      r3,[r7,#0x20]
-        mov      r1,r1,lsl #1
-        smlal    r12,r0,r3,r1
-        ldr      lr,[r7,#0x24]
-        ldr      r3,[r6,#0x24]
-        str      r0,[r5,#0x20]
-        smlal    r1,r3,lr,r1
-        ldr      r0,[r6,#0x40]
-        ldr      r12,[r6,#0x44]
-        str      r3,[r5,#0x24]
-        ldr      r1,[r5,#0x28]
-        ldr      r3,[r7,#0x44]
-        mov      r1,r1,lsl #1
-        smlal    r1,r12,r3,r1
-        ldr      r1,[r5,#0x40]
-        str      r12,[r5,#0x44]
-        rsb      r8,r1,#0
-        str      r8,[r5,#0x28]
-        ldr      r1,[r5,#0x2c]
-        ldr      r3,[r7,#0x40]
-        mov      r1,r1,lsl #1
-        smlal    r1,r0,r3,r1
-        str      r0,[r5,#0x40]
-        ldr      r0,[r5,#0x3c]
-        ldr      r1,[r6,#0x38]
-        ldr      r3,[r6,#0x3c]
-        rsb      r9,r0,#0
-        str      r9,[r5,#0x2c]
-        ldr      r0,[r5,#0x30]
-        ldr      r12,[r7,#0x3c]
-        mov      r0,r0,lsl #1
-        smlal    r0,r3,r12,r0
-        str      r3,[r5,#0x3c]
-        ldr      r0,[r5,#0x38]
-        rsb      r0,r0,#0
-        str      r0,[r5,#0x30]
-        ldr      r3,[r5,#0x34]
-        ldr      r12,[r7,#0x38]
-        mov      r3,r3,lsl #1
-        smlal    r3,r1,r12,r3
-        mov      r0,r0,lsl #1
-        str      r1,[r5,#0x38]
-        ldr      r4,[r7,#0x34]
-        ldr      r1,[r6,#0x34]
-        ldr      r3,[r6,#0x30]
-        smlal    r0,r1,r4,r0
-        ldr      r12,[r6,#0x2c]
-        ldr      lr,[r6,#0x28]
-        str      r1,[r5,#0x34]
-        ldr      r1,[r7,#0x30]
-        mov      r0,r9,lsl #1
-        smlal    r0,r3,r1,r0
-        mov      r0,r8,lsl #1
-        ldr      r1,[r7,#0x2c]
-        str      r3,[r5,#0x30]
-        smlal    r0,r12,r1,r0
-        ldr      r0,[r7,#0x28]
-        str      r12,[r5,#0x2c]
-        smlal    r2,lr,r0,r2
-        str      lr,[r5,#0x28]
-        ldr      r1,[r6,#4]
-        ldr      r12,[r7,#0x48]
-        mov      r2,r1,lsl #1
-        ldr      r1,[r6,#0x20]
-        ldr      r0,[r6]
-        mov      r1,r1,lsl #1
-        smull    r4,lr,r12,r1
-        ldr      r3,[r6,#0x1c]
-        str      lr,[r6]
-        ldr      r12,[r7,#0x4c]
-        mov      r3,r3,lsl #1
-        smull    r4,lr,r12,r3
-        mov      r0,r0,lsl #1
-        ldr      r12,[r7,#0x64]
-        str      lr,[r6,#4]
-        smull    r4,lr,r12,r2
-        ldr      r12,[r7,#0x68]
-        str      lr,[r6,#0x1c]
-        smull    r4,lr,r12,r0
-        ldr      r12,[r7,#0x6c]
-        str      lr,[r6,#0x20]
-        smull    lr,r0,r12,r0
-        ldr      r12,[r7,#0x70]
-        str      r0,[r6,#0x24]
-        smull    r0,r2,r12,r2
-        ldr      r0,[r7,#0x88]
-        str      r2,[r6,#0x28]
-        smull    r3,r2,r0,r3
-        ldr      r0,[r7,#0x8c]
-        str      r2,[r6,#0x40]
-        smull    r2,r1,r0,r1
-        str      r1,[r6,#0x44]
-        ldr      r0,[r6,#0x18]
-        ldr      lr,[r7,#0x50]
-        mov      r1,r0,lsl #1
-        ldr      r0,[r6,#0x14]
-        smull    r5,r4,lr,r1
-        ldr      r12,[r6,#0x10]
-        mov      r3,r0,lsl #1
-        ldr      r0,[r6,#0xc]
-        mov      r12,r12,lsl #1
-        mov      r2,r0,lsl #1
-        ldr      r0,[r6,#8]
-        str      r4,[r6,#8]
-        ldr      lr,[r7,#0x54]
-        mov      r0,r0,lsl #1
-        smull    r5,r4,lr,r3
-        ldr      lr,[r7,#0x58]
-        str      r4,[r6,#0xc]
-        smull    r5,r4,lr,r12
-        ldr      lr,[r7,#0x5c]
-        str      r4,[r6,#0x10]
-        smull    r5,r4,lr,r2
-        ldr      lr,[r7,#0x60]
-        str      r4,[r6,#0x14]
-        smull    r5,r4,lr,r0
-        ldr      lr,[r7,#0x74]
-        str      r4,[r6,#0x18]
-        smull    r4,r0,lr,r0
-        ldr      lr,[r7,#0x78]
-        str      r0,[r6,#0x2c]
-        smull    r0,r2,lr,r2
-        ldr      r0,[r7,#0x7c]
-        str      r2,[r6,#0x30]
-        smull    r12,r2,r0,r12
-        ldr      r0,[r7,#0x80]
-        str      r2,[r6,#0x34]
-        smull    r3,r2,r0,r3
-        ldr      r0,[r7,#0x84]
-        str      r2,[r6,#0x38]
-        smull    r2,r1,r0,r1
-        str      r1,[r6,#0x3c]
-        ldmfd    sp!,{r4-r10,pc}
-table
-        DCD      ||.constdata$1||
-        ENDP
-
-;------------------------------------------------------------------------------
-
- AREA |.constdata|, DATA, READONLY, ALIGN=2
-
-;------------------------------------------------------------------------------
-
-||.constdata$1||
-cosTerms_dct18
-        DCD      0x0807d2b0
-        DCD      0x08483ee0
-        DCD      0x08d3b7d0
-        DCD      0x09c42570
-        DCD      0x0b504f30
-        DCD      0x0df29440
-        DCD      0x12edfb20
-        DCD      0x1ee8dd40
-        DCD      0x5bca2a00
-cosTerms_1_ov_cos_phi
-        DCD      0x400f9c00
-        DCD      0x408d6080
-        DCD      0x418dcb80
-        DCD      0x431b1a00
-        DCD      0x4545ea00
-        DCD      0x48270680
-        DCD      0x4be25480
-        DCD      0x50ab9480
-        DCD      0x56ce4d80
-        DCD      0x05ebb630
-        DCD      0x06921a98
-        DCD      0x0771d3a8
-        DCD      0x08a9a830
-        DCD      0x0a73d750
-        DCD      0x0d4d5260
-        DCD      0x127b1ca0
-        DCD      0x1ea52b40
-        DCD      0x5bb3cc80
-
-
-
-        END
diff --git a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_mdct_18_wm.asm b/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_mdct_18_wm.asm
deleted file mode 100644
index 5be75d4..0000000
--- a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_mdct_18_wm.asm
+++ /dev/null
@@ -1,366 +0,0 @@
-; ------------------------------------------------------------------
-; Copyright (C) 1998-2009 PacketVideo
-;
-; Licensed under the Apache License, Version 2.0 (the "License");
-; you may not use this file except in compliance with the License.
-; You may obtain a copy of the License at
-;
-;      http://www.apache.org/licenses/LICENSE-2.0
-;
-; Unless required by applicable law or agreed to in writing, software
-; distributed under the License is distributed on an "AS IS" BASIS,
-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
-; express or implied.
-; See the License for the specific language governing permissions
-; and limitations under the License.
-; -------------------------------------------------------------------
-
-;
-;
-;   Filename: pvmp3_dct_18.s
-;
-;------------------------------------------------------------------------------
-; REVISION HISTORY
-;
-;
-; Who:                                   Date: MM/DD/YYYY
-; Description: 
-;
-;------------------------------------------------------------------------------
-
-        EXPORT |pvmp3_mdct_18|
-
-        IMPORT pvmp3_dct_9
-
-
-;------------------------------------------------------------------------------
-
- AREA |.text|, CODE, READONLY, ALIGN=2
-
-
-;------------------------------------------------------------------------------
-
-|pvmp3_mdct_18| PROC
-        stmfd    sp!,{r4-r10,lr}
-        mov      r7,r2
-        ldr      r2,table
-        mov      r6,r1
-        add      r3,r2,#0x24
-        add      r12,r3,#0x44
-        add      r1,r0,#0x44
-        mov      r5,r0
-
-;    for ( i=9; i!=0; i--)
-;    {
-
-        mov      r4,#9
-Loop_1
-
-;       tmp  = *(pt_vec);
-;		tmp1 = *(pt_vec_o);
-
-        ldr      lr,[r0]		;; tmp  == lr
-        ldr      r8,[r3],#4		;; tmp1 == r8
-
-;        tmp  = fxp_mul32_Q32( tmp<<1,  *(pt_cos++  ));
-;        tmp1 = fxp_mul32_Q27( tmp1, *(pt_cos_x--));
-
-        mov      lr,lr,lsl #1
-        smull    r10,lr,r8,lr
-        ldr      r8,[r12],#-4
-        ldr      r9,[r1]
-        subs     r4,r4,#1
-        smull    r9,r10,r8,r9
-        mov      r8,r9,lsr #27
-        add      r8,r8,r10,lsl #5
-
-;        *(pt_vec++)   =   tmp + tmp1 ;
-;        *(pt_vec_o--) = fxp_mul32_Q28( (tmp - tmp1), *(pt_cos_split++));
-
-        add      r9,lr,r8
-        sub      r8,lr,r8
-        ldr      lr,[r2],#4
-        str      r9,[r0],#4
-        smull    r8,r9,lr,r8
-        mov      lr,r8,lsr #28
-        add      lr,lr,r9,lsl #4
-        str      lr,[r1],#-4
-        bne      Loop_1
-
-;		}
-
-        mov      r0,r5			;; r0 = vec
-        bl       pvmp3_dct_9
-        add      r0,r5,#0x24	;; r0 = &vec[9]
-        bl       pvmp3_dct_9
-
-        ldr      r0,[r5,#0x20]
-        ldr      r2,[r5,#0x40]
-        str      r0,[r5,#0x40]
-        ldr      r0,[r5,#0x1c]
-        ldr      r3,[r5,#0x38]
-        str      r0,[r5,#0x38]
-        ldr      r1,[r5,#0x18]
-        ldr      r0,[r5,#0x30]
-        str      r1,[r5,#0x30]
-        ldr      r12,[r5,#0x14]
-        ldr      r1,[r5,#0x28]
-        str      r12,[r5,#0x28]
-        ldr      r12,[r5,#0x10]
-        str      r12,[r5,#0x20]
-        ldr      r12,[r5,#0xc]
-        str      r12,[r5,#0x18]
-        ldr      r12,[r5,#8]
-        str      r12,[r5,#0x10]
-        ldr      r12,[r5,#4]
-        str      r12,[r5,#8]
-        ldr      r12,[r5,#0x24]
-        sub      r12,r12,r1
-        str      r12,[r5,#4]
-        ldr      r12,[r5,#0x2c]
-        sub      r1,r12,r1
-        str      r1,[r5,#0xc]
-        sub      r1,r12,r0
-        str      r1,[r5,#0x14]
-        ldr      r1,[r5,#0x34]
-        sub      r0,r1,r0
-        str      r0,[r5,#0x1c]
-        sub      r0,r1,r3
-        str      r0,[r5,#0x24]
-        ldr      r1,[r5,#0x3c]
-        sub      r3,r1,r3
-        sub      r1,r1,r2
-        str      r1,[r5,#0x34]
-        str      r3,[r5,#0x2c]
-        ldr      r1,[r5,#0x44]
-        sub      r1,r1,r2
-        str      r1,[r5,#0x3c]
-        ldr      r12,[r5,#0]
-
-Loop_2
-        add      r1,r5,r4,lsl #2
-        ldr      r2,[r1,#0x28]
-        ldr      r3,[r6,r4,lsl #2]
-        add      r0,r0,r2
-        str      r0,[r1,#0x28]
-        ldr      lr,[r7,r4,lsl #2]
-        ldr      r1,[r1,#4]
-        smlal    r0,r3,lr,r0
-        mov      r0,r2
-        add      r2,r12,r1
-        rsb      r2,r2,#0
-        str      r3,[r5,r4,lsl #2]
-        str      r2,[r6,r4,lsl #2]
-        add      r4,r4,#1
-        cmp      r4,#6
-        mov      r12,r1
-
-        blt      Loop_2
-
-        ldr      r1,[r5,#0x40]
-        ldr      r2,[r6,#0x18]
-        add      r3,r0,r1
-        str      r3,[r5,#0x40]
-        ldr      lr,[r7,r4,lsl #2]
-        mov      r3,r3,lsl #1
-        ldr      r0,[r5,#0x1c]
-        smlal    r3,r2,lr,r3
-        add      r3,r12,r0
-        str      r2,[r5,#0x18]
-        ldr      r2,[r6,#0x1c]
-        rsb      r3,r3,#0
-        str      r3,[r6,#0x18]
-        ldr      r3,[r5,#0x20]
-        add      r0,r3,r0
-        rsb      r0,r0,#0
-        str      r0,[r6,#0x1c]
-        ldr      r3,[r5,#0x44]
-        ldr      r0,[r6,#0x20]
-        add      r3,r3,r1
-        mov      r1,r2
-        ldr      r10,[r7,#0x1c]
-        mov      r2,r3,lsl #1
-        smlal    r12,r1,r10,r2
-        str      r1,[r5,#0x1c]
-        ldr      r1,[r5,#0x20]
-        ldr      r3,[r5,#0x24]
-        add      r1,r1,r3
-        rsb      r1,r1,#0
-        str      r1,[r6,#0x20]
-        ldr      r1,[r5,#0x44]
-        ldr      r3,[r7,#0x20]
-        mov      r1,r1,lsl #1
-        smlal    r12,r0,r3,r1
-        ldr      lr,[r7,#0x24]
-        ldr      r3,[r6,#0x24]
-        str      r0,[r5,#0x20]
-        smlal    r1,r3,lr,r1
-        ldr      r0,[r6,#0x40]
-        ldr      r12,[r6,#0x44]
-        str      r3,[r5,#0x24]
-        ldr      r1,[r5,#0x28]
-        ldr      r3,[r7,#0x44]
-        mov      r1,r1,lsl #1
-        smlal    r1,r12,r3,r1
-        ldr      r1,[r5,#0x40]
-        str      r12,[r5,#0x44]
-        rsb      r8,r1,#0
-        str      r8,[r5,#0x28]
-        ldr      r1,[r5,#0x2c]
-        ldr      r3,[r7,#0x40]
-        mov      r1,r1,lsl #1
-        smlal    r1,r0,r3,r1
-        str      r0,[r5,#0x40]
-        ldr      r0,[r5,#0x3c]
-        ldr      r1,[r6,#0x38]
-        ldr      r3,[r6,#0x3c]
-        rsb      r9,r0,#0
-        str      r9,[r5,#0x2c]
-        ldr      r0,[r5,#0x30]
-        ldr      r12,[r7,#0x3c]
-        mov      r0,r0,lsl #1
-        smlal    r0,r3,r12,r0
-        str      r3,[r5,#0x3c]
-        ldr      r0,[r5,#0x38]
-        rsb      r0,r0,#0
-        str      r0,[r5,#0x30]
-        ldr      r3,[r5,#0x34]
-        ldr      r12,[r7,#0x38]
-        mov      r3,r3,lsl #1
-        smlal    r3,r1,r12,r3
-        mov      r0,r0,lsl #1
-        str      r1,[r5,#0x38]
-        ldr      r4,[r7,#0x34]
-        ldr      r1,[r6,#0x34]
-        ldr      r3,[r6,#0x30]
-        smlal    r0,r1,r4,r0
-        ldr      r12,[r6,#0x2c]
-        ldr      lr,[r6,#0x28]
-        str      r1,[r5,#0x34]
-        ldr      r1,[r7,#0x30]
-        mov      r0,r9,lsl #1
-        smlal    r0,r3,r1,r0
-        mov      r0,r8,lsl #1
-        ldr      r1,[r7,#0x2c]
-        str      r3,[r5,#0x30]
-        smlal    r0,r12,r1,r0
-        ldr      r0,[r7,#0x28]
-        str      r12,[r5,#0x2c]
-        smlal    r2,lr,r0,r2
-        str      lr,[r5,#0x28]
-        ldr      r1,[r6,#4]
-        ldr      r12,[r7,#0x48]
-        mov      r2,r1,lsl #1
-        ldr      r1,[r6,#0x20]
-        ldr      r0,[r6]
-        mov      r1,r1,lsl #1
-        smull    r4,lr,r12,r1
-        ldr      r3,[r6,#0x1c]
-        str      lr,[r6]
-        ldr      r12,[r7,#0x4c]
-        mov      r3,r3,lsl #1
-        smull    r4,lr,r12,r3
-        mov      r0,r0,lsl #1
-        ldr      r12,[r7,#0x64]
-        str      lr,[r6,#4]
-        smull    r4,lr,r12,r2
-        ldr      r12,[r7,#0x68]
-        str      lr,[r6,#0x1c]
-        smull    r4,lr,r12,r0
-        ldr      r12,[r7,#0x6c]
-        str      lr,[r6,#0x20]
-        smull    lr,r0,r12,r0
-        ldr      r12,[r7,#0x70]
-        str      r0,[r6,#0x24]
-        smull    r0,r2,r12,r2
-        ldr      r0,[r7,#0x88]
-        str      r2,[r6,#0x28]
-        smull    r3,r2,r0,r3
-        ldr      r0,[r7,#0x8c]
-        str      r2,[r6,#0x40]
-        smull    r2,r1,r0,r1
-        str      r1,[r6,#0x44]
-        ldr      r0,[r6,#0x18]
-        ldr      lr,[r7,#0x50]
-        mov      r1,r0,lsl #1
-        ldr      r0,[r6,#0x14]
-        smull    r5,r4,lr,r1
-        ldr      r12,[r6,#0x10]
-        mov      r3,r0,lsl #1
-        ldr      r0,[r6,#0xc]
-        mov      r12,r12,lsl #1
-        mov      r2,r0,lsl #1
-        ldr      r0,[r6,#8]
-        str      r4,[r6,#8]
-        ldr      lr,[r7,#0x54]
-        mov      r0,r0,lsl #1
-        smull    r5,r4,lr,r3
-        ldr      lr,[r7,#0x58]
-        str      r4,[r6,#0xc]
-        smull    r5,r4,lr,r12
-        ldr      lr,[r7,#0x5c]
-        str      r4,[r6,#0x10]
-        smull    r5,r4,lr,r2
-        ldr      lr,[r7,#0x60]
-        str      r4,[r6,#0x14]
-        smull    r5,r4,lr,r0
-        ldr      lr,[r7,#0x74]
-        str      r4,[r6,#0x18]
-        smull    r4,r0,lr,r0
-        ldr      lr,[r7,#0x78]
-        str      r0,[r6,#0x2c]
-        smull    r0,r2,lr,r2
-        ldr      r0,[r7,#0x7c]
-        str      r2,[r6,#0x30]
-        smull    r12,r2,r0,r12
-        ldr      r0,[r7,#0x80]
-        str      r2,[r6,#0x34]
-        smull    r3,r2,r0,r3
-        ldr      r0,[r7,#0x84]
-        str      r2,[r6,#0x38]
-        smull    r2,r1,r0,r1
-        str      r1,[r6,#0x3c]
-        ldmfd    sp!,{r4-r10,pc}
-table
-        DCD      cosTerms_dct18
-        ENDP
-
-;------------------------------------------------------------------------------
-
- AREA |.constdata|, DATA, READONLY, ALIGN=2
-
-;------------------------------------------------------------------------------
-
-cosTerms_dct18
-        DCD      0x0807d2b0
-        DCD      0x08483ee0
-        DCD      0x08d3b7d0
-        DCD      0x09c42570
-        DCD      0x0b504f30
-        DCD      0x0df29440
-        DCD      0x12edfb20
-        DCD      0x1ee8dd40
-        DCD      0x5bca2a00
-cosTerms_1_ov_cos_phi
-        DCD      0x400f9c00
-        DCD      0x408d6080
-        DCD      0x418dcb80
-        DCD      0x431b1a00
-        DCD      0x4545ea00
-        DCD      0x48270680
-        DCD      0x4be25480
-        DCD      0x50ab9480
-        DCD      0x56ce4d80
-        DCD      0x05ebb630
-        DCD      0x06921a98
-        DCD      0x0771d3a8
-        DCD      0x08a9a830
-        DCD      0x0a73d750
-        DCD      0x0d4d5260
-        DCD      0x127b1ca0
-        DCD      0x1ea52b40
-        DCD      0x5bb3cc80
-
-
-
-        END
diff --git a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_polyphase_filter_window_arm.s b/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_polyphase_filter_window_arm.s
deleted file mode 100644
index abec599..0000000
--- a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_polyphase_filter_window_arm.s
+++ /dev/null
@@ -1,237 +0,0 @@
-; ------------------------------------------------------------------
-; Copyright (C) 1998-2009 PacketVideo
-;
-; Licensed under the Apache License, Version 2.0 (the "License");
-; you may not use this file except in compliance with the License.
-; You may obtain a copy of the License at
-;
-;      http://www.apache.org/licenses/LICENSE-2.0
-;
-; Unless required by applicable law or agreed to in writing, software
-; distributed under the License is distributed on an "AS IS" BASIS,
-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
-; express or implied.
-; See the License for the specific language governing permissions
-; and limitations under the License.
-; -------------------------------------------------------------------
-
-;
-;
-;   Filename: pvmp3_polyphase_filter_window.s
-;
-;------------------------------------------------------------------------------
-; REVISION HISTORY
-;
-;
-; Who:                                   Date: MM/DD/YYYY
-; Description: 
-;
-;------------------------------------------------------------------------------
-
-        EXPORT pvmp3_polyphase_filter_window
-
-        IMPORT ||Lib$$Request$$armlib|| [WEAK]
-        IMPORT ||Lib$$Request$$cpplib|| [WEAK]
-        IMPORT pqmfSynthWin
-
-
-
-;------------------------------------------------------------------------------
-
- AREA |.text|, CODE, READONLY, ALIGN=2
-
-
-;------------------------------------------------------------------------------
-
-|pvmp3_polyphase_filter_window| PROC
-
-        stmfd    sp!,{r0-r2,r4-r11,lr}
-
-        sub      sp,sp,#4
-        ldr      r2,[sp,#0xc]
-        ldr      r1,PolyPh_filter_coeff
-		
-        sub      r2,r2,#1
-        mov      r10,#1
-        str      r2,[sp]
-
-; Accumulators r9, r11::> Initialization
-
-Loop_j
-        mov      r9,  #0x20
-        mov      r11, #0x20
-        mov      r4,  #0x10
-Loop_i
-        add      r2,r4,r10
-        add      r3,r0,r2,lsl #2
-        sub      r2,r4,r10
-        ldr      r5,[r3]
-        ldr      lr,[r1]
-        add      r12,r0,r2,lsl #2
-        ldr      r6,[r12,#0x780]
-        smlal    r2,r9,lr,r5
-        smlal    r2,r11,lr,r6
-        ldr      r2,[r1,#4]
-        ldr      r7,[r12,#0x80]
-        smlal    r5,r11,r2,r5
-        smull    r6,r5,r2,r6
-        sub      r9,r9,r5
-        ldr      r5,[r1,#8]
-        ldr      r8,[r3,#0x700]
-        add      r4,r4,#0x200
-        smlal    r6,r9,r5,r7
-        smull    r6,r2,r5,r8
-        ldr      r5,[r1,#0xc]
-        sub      r11,r11,r2
-        smlal    r8,r9,r5,r8
-        smlal    r7,r11,r5,r7
-        ldr      r5,[r3,#0x100]
-        ldr      r2,[r1,#0x10]
-        ldr      r6,[r12,#0x680]
-        smlal    lr,r9,r2,r5
-        smlal    lr,r11,r2,r6
-        ldr      r2,[r1,#0x14]
-        ldr      r7,[r12,#0x180]
-        smlal    r5,r11,r2,r5
-        smull    r6,r5,r2,r6
-        ldr      r6,[r1,#0x18]
-        ldr      r8,[r3,#0x600]
-        sub      r9,r9,r5
-        smlal    r5,r9,r6,r7
-        smull    r2,r5,r6,r8
-        ldr      r6,[r1,#0x1c]
-        sub      r11,r11,r5
-        smlal    r8,r9,r6,r8
-        ldr      r2,[r1,#0x20]
-        ldr      r5,[r3,#0x200]
-        smlal    r7,r11,r6,r7
-        ldr      r6,[r12,#0x580]
-        smlal    lr,r9,r2,r5
-        smlal    lr,r11,r2,r6
-        ldr      r2,[r1,#0x24]
-        ldr      r7,[r12,#0x280]
-        smlal    r5,r11,r2,r5
-        smull    r6,r5,r2,r6
-        ldr      r6,[r1,#0x28]
-        ldr      r8,[r3,#0x500]
-        sub      r9,r9,r5
-        smlal    r5,r9,r6,r7
-        smull    r2,r5,r6,r8
-        ldr      r6,[r1,#0x2c]
-        sub      r11,r11,r5
-
-        smlal    r8,r9,r6,r8
-        smlal    r7,r11,r6,r7
-        ldr      r5,[r3,#0x300]
-        ldr      r8,[r1,#0x30]
-        ldr      r6,[r12,#0x480]
-        smlal    r7,r9,r8,r5
-        smlal    r7,r11,r8,r6
-        ldr      r8,[r1,#0x34]
-        ldr      r12,[r12,#0x380]
-        smlal    r5,r11,r8,r5
-        smull    r6,r5,r8,r6
-        ldr      r6,[r1,#0x38]
-
-
-        ldr      r3,[r3,#0x400]
-        sub      r9,r9,r5
-        smlal    r7,r9,r6,r12
-        smull    r8,r7,r6,r3
-        cmp      r4,#0x210
-        sub      r11,r11,r7
-
-        ldr      r2,[r1,#0x3c]
-        add      r1,r1,#0x40
-        smlal    r3,r9,r2,r3
-        smlal    r12,r11,r2,r12
-
-        blt      Loop_i
-
-        mov      r3,r9, asr #6
-        mov      r4,r3, asr #15
-        teq      r4,r3, asr #31
-        ldr      r12,LOW_16BITS
-        ldr      r2,[sp]
-        eorne    r3,r12,r3,asr #31
-        ldr      r4,[sp,#8]
-        mov      r2,r10,lsl r2
-        add      r4,r4,r2,lsl #1
-        strh     r3,[r4]
-
-        mov      r3,r11,asr #6
-        mov      r4,r3,asr #15
-        teq      r4,r3,asr #31
-        eorne    r3,r12,r3,asr #31
-        ldr      r12,[sp,#0xc]
-        ldr      r11,[sp,#8]
-        rsb      r2,r2,r12,lsl #5
-        add      r2,r11,r2,lsl #1
-        strh     r3,[r2]
-
-        add      r10,r10,#1
-        cmp      r10,#0x10
-        blt      Loop_j
-
-; Accumulators r4, r5 Initialization
-
-        mov      r4,#0x20
-        mov      r5,#0x20
-        mov      r3,#0x10
-PolyPh_filter_loop2
-        add      r2,r0,r3,lsl #2
-        ldr      r12,[r2]
-        ldr      r8,[r1]
-        ldr      r6,[r2,#0x80]
-        smlal    r12,r4,r8,r12
-        ldr      r12,[r1,#4]
-        ldr      r7,[r2,#0x40]
-        smlal    r6,r4,r12,r6
-
-        ldr      r12,[r1,#8]
-        ldr      r6,[r2,#0x180]
-        smlal    r7,r5,r12,r7
-        ldr      r12,[r2,#0x100]
-        ldr      r7,[r1,#0xc]
-        ldr      r2,[r2,#0x140]
-        smlal    r12,r4,r7,r12
-        ldr      r12,[r1,#0x10]
-        add      r3,r3,#0x80
-        smlal    r6,r4,r12,r6
-        ldr      r6,[r1,#0x14]
-        cmp      r3,#0x210
-        smlal    r2,r5,r6,r2
-        add      r1,r1,#0x18
-
-        blt      PolyPh_filter_loop2
-        mov      r0,r4,asr #6
-        mov      r2,r0,asr #15
-        teq      r2,r0,asr #31
-        ldrne    r12,LOW_16BITS
-        ldr      r1,[sp,#8]
-        eorne    r0,r12,r0,asr #31
-        strh     r0,[r1,#0]
-        mov      r0,r5,asr #6
-        mov      r2,r0,asr #15
-        teq      r2,r0,asr #31
-        ldrne    r12,LOW_16BITS
-        ldr      r2,[sp]
-        mov      r1,#0x10
-        eorne    r0,r12,r0,asr #31
-        ldr      r12,[sp,#8]
-        mov      r1,r1,lsl r2
-        add      r1,r12,r1,lsl #1
-        strh     r0,[r1]
-        add      sp,sp,#0x10
-        ldmfd    sp!,{r4-r11,pc}
-
-
-PolyPh_filter_coeff
-        DCD      pqmfSynthWin
-LOW_16BITS
-        DCD      0x00007fff
-
-        ENDP
-
-
-        END
diff --git a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_polyphase_filter_window_wm.asm b/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_polyphase_filter_window_wm.asm
deleted file mode 100644
index f957267..0000000
--- a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_polyphase_filter_window_wm.asm
+++ /dev/null
@@ -1,231 +0,0 @@
-; ------------------------------------------------------------------
-; Copyright (C) 1998-2009 PacketVideo
-;
-; Licensed under the Apache License, Version 2.0 (the "License");
-; you may not use this file except in compliance with the License.
-; You may obtain a copy of the License at
-;
-;      http://www.apache.org/licenses/LICENSE-2.0
-;
-; Unless required by applicable law or agreed to in writing, software
-; distributed under the License is distributed on an "AS IS" BASIS,
-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
-; express or implied.
-; See the License for the specific language governing permissions
-; and limitations under the License.
-; -------------------------------------------------------------------
-
-;
-;
-;   Filename: pvmp3_polyphase_filter_window.s
-;
-;------------------------------------------------------------------------------
-; REVISION HISTORY
-;
-;
-; Who:                                   Date: MM/DD/YYYY
-; Description: 
-;
-;------------------------------------------------------------------------------
-
-	CODE32
-
-	AREA	|.drectve|, DRECTVE
-
-	EXPORT	|pvmp3_polyphase_filter_window|
-	IMPORT	|pqmfSynthWin|
-
-	AREA	|.pdata|, PDATA
-
-	AREA	|.text|, CODE, ARM
-
-|pvmp3_polyphase_filter_window| PROC
-        stmfd    sp!,{r0-r2,r4-r11,lr}
-
-        sub      sp,sp,#4
-        ldr      r2,[sp,#0xc]
-        ldr      r1,PolyPh_filter_coeff
-		
-        sub      r2,r2,#1
-        mov      r10,#1
-        str      r2,[sp]
-
-; Accumulators r9, r11::> Initialization
-
-Loop_j
-        mov      r9,  #0x20
-        mov      r11, #0x20
-        mov      r4,  #0x10
-Loop_i
-        add      r2,r4,r10
-        add      r3,r0,r2,lsl #2
-        sub      r2,r4,r10
-        ldr      r5,[r3]
-        ldr      lr,[r1]
-        add      r12,r0,r2,lsl #2
-        ldr      r6,[r12,#0x780]
-        smlal    r2,r9,lr,r5
-        smlal    r2,r11,lr,r6
-        ldr      r2,[r1,#4]
-        ldr      r7,[r12,#0x80]
-        smlal    r5,r11,r2,r5
-        smull    r6,r5,r2,r6
-        sub      r9,r9,r5
-        ldr      r5,[r1,#8]
-        ldr      r8,[r3,#0x700]
-        add      r4,r4,#0x200
-        smlal    r6,r9,r5,r7
-        smull    r6,r2,r5,r8
-        ldr      r5,[r1,#0xc]
-        sub      r11,r11,r2
-        smlal    r8,r9,r5,r8
-        smlal    r7,r11,r5,r7
-        ldr      r5,[r3,#0x100]
-        ldr      r2,[r1,#0x10]
-        ldr      r6,[r12,#0x680]
-        smlal    lr,r9,r2,r5
-        smlal    lr,r11,r2,r6
-        ldr      r2,[r1,#0x14]
-        ldr      r7,[r12,#0x180]
-        smlal    r5,r11,r2,r5
-        smull    r6,r5,r2,r6
-        ldr      r6,[r1,#0x18]
-        ldr      r8,[r3,#0x600]
-        sub      r9,r9,r5
-        smlal    r5,r9,r6,r7
-        smull    r2,r5,r6,r8
-        ldr      r6,[r1,#0x1c]
-        sub      r11,r11,r5
-        smlal    r8,r9,r6,r8
-        ldr      r2,[r1,#0x20]
-        ldr      r5,[r3,#0x200]
-        smlal    r7,r11,r6,r7
-        ldr      r6,[r12,#0x580]
-        smlal    lr,r9,r2,r5
-        smlal    lr,r11,r2,r6
-        ldr      r2,[r1,#0x24]
-        ldr      r7,[r12,#0x280]
-        smlal    r5,r11,r2,r5
-        smull    r6,r5,r2,r6
-        ldr      r6,[r1,#0x28]
-        ldr      r8,[r3,#0x500]
-        sub      r9,r9,r5
-        smlal    r5,r9,r6,r7
-        smull    r2,r5,r6,r8
-        ldr      r6,[r1,#0x2c]
-        sub      r11,r11,r5
-
-        smlal    r8,r9,r6,r8
-        smlal    r7,r11,r6,r7
-        ldr      r5,[r3,#0x300]
-        ldr      r8,[r1,#0x30]
-        ldr      r6,[r12,#0x480]
-        smlal    r7,r9,r8,r5
-        smlal    r7,r11,r8,r6
-        ldr      r8,[r1,#0x34]
-        ldr      r12,[r12,#0x380]
-        smlal    r5,r11,r8,r5
-        smull    r6,r5,r8,r6
-        ldr      r6,[r1,#0x38]
-
-
-        ldr      r3,[r3,#0x400]
-        sub      r9,r9,r5
-        smlal    r7,r9,r6,r12
-        smull    r8,r7,r6,r3
-        cmp      r4,#0x210
-        sub      r11,r11,r7
-
-        ldr      r2,[r1,#0x3c]
-        add      r1,r1,#0x40
-        smlal    r3,r9,r2,r3
-        smlal    r12,r11,r2,r12
-
-        blt      Loop_i
-
-        mov      r3,r9, asr #6
-        mov      r4,r3, asr #15
-        teq      r4,r3, asr #31
-        ldr      r12,LOW_16BITS
-        ldr      r2,[sp]
-        eorne    r3,r12,r3,asr #31
-        ldr      r4,[sp,#8]
-        mov      r2,r10,lsl r2
-        add      r4,r4,r2,lsl #1
-        strh     r3,[r4]
-
-        mov      r3,r11,asr #6
-        mov      r4,r3,asr #15
-        teq      r4,r3,asr #31
-        eorne    r3,r12,r3,asr #31
-        ldr      r12,[sp,#0xc]
-        ldr      r11,[sp,#8]
-        rsb      r2,r2,r12,lsl #5
-        add      r2,r11,r2,lsl #1
-        strh     r3,[r2]
-
-        add      r10,r10,#1
-        cmp      r10,#0x10
-        blt      Loop_j
-
-; Accumulators r4, r5 Initialization
-
-        mov      r4,#0x20
-        mov      r5,#0x20
-        mov      r3,#0x10
-PolyPh_filter_loop2
-        add      r2,r0,r3,lsl #2
-        ldr      r12,[r2]
-        ldr      r8,[r1]
-        ldr      r6,[r2,#0x80]
-        smlal    r12,r4,r8,r12
-        ldr      r12,[r1,#4]
-        ldr      r7,[r2,#0x40]
-        smlal    r6,r4,r12,r6
-
-        ldr      r12,[r1,#8]
-        ldr      r6,[r2,#0x180]
-        smlal    r7,r5,r12,r7
-        ldr      r12,[r2,#0x100]
-        ldr      r7,[r1,#0xc]
-        ldr      r2,[r2,#0x140]
-        smlal    r12,r4,r7,r12
-        ldr      r12,[r1,#0x10]
-        add      r3,r3,#0x80
-        smlal    r6,r4,r12,r6
-        ldr      r6,[r1,#0x14]
-        cmp      r3,#0x210
-        smlal    r2,r5,r6,r2
-        add      r1,r1,#0x18
-
-        blt      PolyPh_filter_loop2
-        mov      r0,r4,asr #6
-        mov      r2,r0,asr #15
-        teq      r2,r0,asr #31
-        ldrne    r12,LOW_16BITS
-        ldr      r1,[sp,#8]
-        eorne    r0,r12,r0,asr #31
-        strh     r0,[r1,#0]
-        mov      r0,r5,asr #6
-        mov      r2,r0,asr #15
-        teq      r2,r0,asr #31
-        ldrne    r12,LOW_16BITS
-        ldr      r2,[sp]
-        mov      r1,#0x10
-        eorne    r0,r12,r0,asr #31
-        ldr      r12,[sp,#8]
-        mov      r1,r1,lsl r2
-        add      r1,r12,r1,lsl #1
-        strh     r0,[r1]
-        add      sp,sp,#0x10
-        ldmfd    sp!,{r4-r11,pc}
-
-
-PolyPh_filter_coeff
-        DCD      pqmfSynthWin
-LOW_16BITS
-        DCD      0x00007fff
-	
-		ENDP  ; |pvmp3_polyphase_filter_window|
-		END
-
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index d1afd8b..338e899 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -555,7 +555,9 @@
         }
 #endif
 
-        return OK;
+        if (!payload_unit_start_indicator) {
+            return OK;
+        }
     }
 
     mExpectedContinuityCounter = (continuity_counter + 1) & 0x0f;
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index 786bf0d..3a280f0 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -25,7 +25,8 @@
 	libmediaplayerservice \
 	libutils \
 	liblog \
-	libbinder
+	libbinder \
+	libsoundtriggerservice
 
 LOCAL_STATIC_LIBRARIES := \
 	libregistermsext
@@ -36,7 +37,8 @@
     frameworks/av/services/audioflinger \
     frameworks/av/services/audiopolicy \
     frameworks/av/services/camera/libcameraservice \
-    $(call include-path-for, audio-utils)
+    $(call include-path-for, audio-utils) \
+    frameworks/av/services/soundtrigger
 
 LOCAL_MODULE:= mediaserver
 LOCAL_32_BIT_ONLY := true
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index a347951..af1c9e6 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -34,6 +34,7 @@
 #include "MediaLogService.h"
 #include "MediaPlayerService.h"
 #include "AudioPolicyService.h"
+#include "SoundTriggerHwService.h"
 
 using namespace android;
 
@@ -128,6 +129,7 @@
         MediaPlayerService::instantiate();
         CameraService::instantiate();
         AudioPolicyService::instantiate();
+        SoundTriggerHwService::instantiate();
         registerExtensions();
         ProcessState::self()->startThreadPool();
         IPCThreadState::self()->joinThreadPool();
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 500e2b8..527fd65 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -431,7 +431,7 @@
         if (mLogMemoryDealer != 0) {
             sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
             if (binder != 0) {
-                fdprintf(fd, "\nmedia.log:\n");
+                dprintf(fd, "\nmedia.log:\n");
                 Vector<String16> args;
                 binder->dump(fd, args);
             }
@@ -2609,7 +2609,7 @@
             }
         } else {
             if (fd >= 0) {
-                fdprintf(fd, "unable to rotate tees in %s: %s\n", teePath, strerror(errno));
+                dprintf(fd, "unable to rotate tees in %s: %s\n", teePath, strerror(errno));
             }
         }
         char teeTime[16];
@@ -2663,11 +2663,11 @@
             write(teeFd, &temp, sizeof(temp));
             close(teeFd);
             if (fd >= 0) {
-                fdprintf(fd, "tee copied to %s\n", teePath);
+                dprintf(fd, "tee copied to %s\n", teePath);
             }
         } else {
             if (fd >= 0) {
-                fdprintf(fd, "unable to create tee %s: %s\n", teePath, strerror(errno));
+                dprintf(fd, "unable to create tee %s: %s\n", teePath, strerror(errno));
             }
         }
     }
diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/services/audioflinger/AudioResamplerDyn.cpp
index a4446a4..318eb57 100644
--- a/services/audioflinger/AudioResamplerDyn.cpp
+++ b/services/audioflinger/AudioResamplerDyn.cpp
@@ -460,9 +460,15 @@
     const uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;   // stereo output
-    size_t inFrameCount = getInFrameCountRequired(outFrameCount) + (phaseFraction != 0);
-    ALOG_ASSERT(0 < inFrameCount && inFrameCount < (1U << 31));
     const uint32_t phaseWrapLimit = c.mL << c.mShift;
+    size_t inFrameCount = (phaseIncrement * (uint64_t)outFrameCount + phaseFraction)
+            / phaseWrapLimit;
+    // sanity check that inFrameCount is in signed 32 bit integer range.
+    ALOG_ASSERT(0 <= inFrameCount && inFrameCount < (1U << 31));
+
+    //ALOGV("inFrameCount:%d  outFrameCount:%d"
+    //        "  phaseIncrement:%u  phaseFraction:%u  phaseWrapLimit:%u",
+    //        inFrameCount, outFrameCount, phaseIncrement, phaseFraction, phaseWrapLimit);
 
     // NOTE: be very careful when modifying the code here. register
     // pressure is very high and a small change might cause the compiler
@@ -472,10 +478,17 @@
     // the following logic is a bit convoluted to keep the main processing loop
     // as tight as possible with register allocation.
     while (outputIndex < outputSampleCount) {
-        // buffer is empty, fetch a new one
-        while (mBuffer.frameCount == 0) {
+        //ALOGV("LOOP: inFrameCount:%d  outputIndex:%d  outFrameCount:%d"
+        //        "  phaseFraction:%u  phaseWrapLimit:%u",
+        //        inFrameCount, outputIndex, outFrameCount, phaseFraction, phaseWrapLimit);
+
+        // check inputIndex overflow
+        ALOG_ASSERT(inputIndex <= mBuffer.frameCount, "inputIndex%d > frameCount%d",
+                inputIndex, mBuffer.frameCount);
+        // Buffer is empty, fetch a new one if necessary (inFrameCount > 0).
+        // We may not fetch a new buffer if the existing data is sufficient.
+        while (mBuffer.frameCount == 0 && inFrameCount > 0) {
             mBuffer.frameCount = inFrameCount;
-            ALOG_ASSERT(inFrameCount > 0);
             provider->getNextBuffer(&mBuffer,
                     calculateOutputPTS(outputIndex / 2));
             if (mBuffer.raw == NULL) {
@@ -486,9 +499,9 @@
                 mInBuffer.template readAdvance<CHANNELS>(
                         impulse, c.mHalfNumCoefs,
                         reinterpret_cast<TI*>(mBuffer.raw), inputIndex);
+                inputIndex++;
                 phaseFraction -= phaseWrapLimit;
                 while (phaseFraction >= phaseWrapLimit) {
-                    inputIndex++;
                     if (inputIndex >= mBuffer.frameCount) {
                         inputIndex = 0;
                         provider->releaseBuffer(&mBuffer);
@@ -497,6 +510,7 @@
                     mInBuffer.template readAdvance<CHANNELS>(
                             impulse, c.mHalfNumCoefs,
                             reinterpret_cast<TI*>(mBuffer.raw), inputIndex);
+                    inputIndex++;
                     phaseFraction -= phaseWrapLimit;
                 }
             }
@@ -507,9 +521,6 @@
         const int halfNumCoefs = c.mHalfNumCoefs;
         const TO* const volumeSimd = mVolumeSimd;
 
-        // reread the last input in.
-        mInBuffer.template readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
-
         // main processing loop
         while (CC_LIKELY(outputIndex < outputSampleCount)) {
             // caution: fir() is inlined and may be large.
@@ -518,6 +529,10 @@
             // from the input samples in impulse[-halfNumCoefs+1]... impulse[halfNumCoefs]
             // from the polyphase filter of (phaseFraction / phaseWrapLimit) in coefs.
             //
+            //ALOGV("LOOP2: inFrameCount:%d  outputIndex:%d  outFrameCount:%d"
+            //        "  phaseFraction:%u  phaseWrapLimit:%u",
+            //        inFrameCount, outputIndex, outFrameCount, phaseFraction, phaseWrapLimit);
+            ALOG_ASSERT(phaseFraction < phaseWrapLimit);
             fir<CHANNELS, LOCKED, STRIDE>(
                     &out[outputIndex],
                     phaseFraction, phaseWrapLimit,
@@ -527,17 +542,20 @@
 
             phaseFraction += phaseIncrement;
             while (phaseFraction >= phaseWrapLimit) {
-                inputIndex++;
                 if (inputIndex >= frameCount) {
                     goto done;  // need a new buffer
                 }
                 mInBuffer.template readAdvance<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
+                inputIndex++;
                 phaseFraction -= phaseWrapLimit;
             }
         }
 done:
-        // often arrives here when input buffer runs out
-        if (inputIndex >= frameCount) {
+        // We arrive here when we're finished or when the input buffer runs out.
+        // Regardless we need to release the input buffer if we've acquired it.
+        if (inputIndex > 0) {  // we've acquired a buffer (alternatively could check frameCount)
+            ALOG_ASSERT(inputIndex == frameCount, "inputIndex(%d) != frameCount(%d)",
+                    inputIndex, frameCount);  // must have been fully read.
             inputIndex = 0;
             provider->releaseBuffer(&mBuffer);
             ALOG_ASSERT(mBuffer.frameCount == 0);
@@ -545,14 +563,12 @@
     }
 
 resample_exit:
-    // Release frames to avoid the count being inaccurate for pts timing.
-    // TODO: Avoid this extra check by making fetch count exact. This is tricky
-    // due to the overfetching mechanism which loads unnecessarily when
-    // mBuffer.frameCount == 0.
-    if (inputIndex) {
-        mBuffer.frameCount = inputIndex;
-        provider->releaseBuffer(&mBuffer);
-    }
+    // inputIndex must be zero in all three cases:
+    // (1) the buffer never was been acquired; (2) the buffer was
+    // released at "done:"; or (3) getNextBuffer() failed.
+    ALOG_ASSERT(inputIndex == 0, "Releasing: inputindex:%d frameCount:%d  phaseFraction:%u",
+            inputIndex, mBuffer.frameCount, phaseFraction);
+    ALOG_ASSERT(mBuffer.frameCount == 0); // there must be no frames in the buffer
     mInBuffer.setImpulse(impulse);
     mPhaseFraction = phaseFraction;
 }
diff --git a/services/audioflinger/AudioWatchdog.cpp b/services/audioflinger/AudioWatchdog.cpp
index 93d185e..877e776 100644
--- a/services/audioflinger/AudioWatchdog.cpp
+++ b/services/audioflinger/AudioWatchdog.cpp
@@ -34,7 +34,7 @@
     } else {
         strcpy(buf, "N/A\n");
     }
-    fdprintf(fd, "Watchdog: underruns=%u, logs=%u, most recent underrun log at %s",
+    dprintf(fd, "Watchdog: underruns=%u, logs=%u, most recent underrun log at %s",
             mUnderruns, mLogs, buf);
 }
 
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index c9a3f10..c486630 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -26,7 +26,6 @@
 #define ATRACE_TAG ATRACE_TAG_AUDIO
 
 #include "Configuration.h"
-#include <sys/atomics.h>
 #include <time.h>
 #include <utils/Log.h>
 #include <utils/Trace.h>
@@ -492,7 +491,7 @@
 void FastMixerDumpState::dump(int fd) const
 {
     if (mCommand == FastMixerState::INITIAL) {
-        fdprintf(fd, "  FastMixer not initialized\n");
+        dprintf(fd, "  FastMixer not initialized\n");
         return;
     }
 #define COMMAND_MAX 32
@@ -526,10 +525,10 @@
     double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) +
             (mMeasuredWarmupTs.tv_nsec / 1000000.0);
     double mixPeriodSec = (double) mFrameCount / (double) mSampleRate;
-    fdprintf(fd, "  FastMixer command=%s writeSequence=%u framesWritten=%u\n"
-                 "            numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
-                 "            sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n"
-                 "            mixPeriod=%.2f ms\n",
+    dprintf(fd, "  FastMixer command=%s writeSequence=%u framesWritten=%u\n"
+                "            numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
+                "            sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n"
+                "            mixPeriod=%.2f ms\n",
                  string, mWriteSequence, mFramesWritten,
                  mNumTracks, mWriteErrors, mUnderruns, mOverruns,
                  mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles,
@@ -581,26 +580,26 @@
 #endif
     }
     if (n) {
-        fdprintf(fd, "  Simple moving statistics over last %.1f seconds:\n",
-                     wall.n() * mixPeriodSec);
-        fdprintf(fd, "    wall clock time in ms per mix cycle:\n"
-                     "      mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
-                     wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6,
-                     wall.stddev()*1e-6);
-        fdprintf(fd, "    raw CPU load in us per mix cycle:\n"
-                     "      mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
-                     loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
-                     loadNs.stddev()*1e-3);
+        dprintf(fd, "  Simple moving statistics over last %.1f seconds:\n",
+                    wall.n() * mixPeriodSec);
+        dprintf(fd, "    wall clock time in ms per mix cycle:\n"
+                    "      mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
+                    wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6,
+                    wall.stddev()*1e-6);
+        dprintf(fd, "    raw CPU load in us per mix cycle:\n"
+                    "      mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
+                    loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
+                    loadNs.stddev()*1e-3);
     } else {
-        fdprintf(fd, "  No FastMixer statistics available currently\n");
+        dprintf(fd, "  No FastMixer statistics available currently\n");
     }
 #ifdef CPU_FREQUENCY_STATISTICS
-    fdprintf(fd, "  CPU clock frequency in MHz:\n"
-                 "    mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
-                 kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3);
-    fdprintf(fd, "  adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n"
-                 "    mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
-                 loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
+    dprintf(fd, "  CPU clock frequency in MHz:\n"
+                "    mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
+                kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3);
+    dprintf(fd, "  adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n"
+                "    mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
+                loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
 #endif
     if (tail != NULL) {
         qsort(tail, n, sizeof(uint32_t), compare_uint32_t);
@@ -611,12 +610,12 @@
             left.sample(tail[i]);
             right.sample(tail[n - (i + 1)]);
         }
-        fdprintf(fd, "  Distribution of mix cycle times in ms for the tails (> ~3 stddev outliers):\n"
-                     "    left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
-                     "    right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
-                     left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6,
-                     right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6,
-                     right.stddev()*1e-6);
+        dprintf(fd, "  Distribution of mix cycle times in ms for the tails (> ~3 stddev outliers):\n"
+                    "    left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
+                    "    right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
+                    left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6,
+                    right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6,
+                    right.stddev()*1e-6);
         delete[] tail;
     }
 #endif
@@ -626,9 +625,9 @@
     // Instead we always display all tracks, with an indication
     // of whether we think the track is active.
     uint32_t trackMask = mTrackMask;
-    fdprintf(fd, "  Fast tracks: kMaxFastTracks=%u activeMask=%#x\n",
+    dprintf(fd, "  Fast tracks: kMaxFastTracks=%u activeMask=%#x\n",
             FastMixerState::kMaxFastTracks, trackMask);
-    fdprintf(fd, "  Index Active Full Partial Empty  Recent Ready\n");
+    dprintf(fd, "  Index Active Full Partial Empty  Recent Ready\n");
     for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) {
         bool isActive = trackMask & 1;
         const FastTrackDump *ftDump = &mTracks[i];
@@ -648,7 +647,7 @@
             mostRecent = "?";
             break;
         }
-        fdprintf(fd, "  %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no",
+        dprintf(fd, "  %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no",
                 (underruns.mBitFields.mFull) & UNDERRUN_MASK,
                 (underruns.mBitFields.mPartial) & UNDERRUN_MASK,
                 (underruns.mBitFields.mEmpty) & UNDERRUN_MASK,
diff --git a/services/audioflinger/StateQueue.cpp b/services/audioflinger/StateQueue.cpp
index 48399c0..7e01c9f 100644
--- a/services/audioflinger/StateQueue.cpp
+++ b/services/audioflinger/StateQueue.cpp
@@ -28,12 +28,12 @@
 #ifdef STATE_QUEUE_DUMP
 void StateQueueObserverDump::dump(int fd)
 {
-    fdprintf(fd, "State queue observer: stateChanges=%u\n", mStateChanges);
+    dprintf(fd, "State queue observer: stateChanges=%u\n", mStateChanges);
 }
 
 void StateQueueMutatorDump::dump(int fd)
 {
-    fdprintf(fd, "State queue mutator: pushDirty=%u pushAck=%u blockedSequence=%u\n",
+    dprintf(fd, "State queue mutator: pushDirty=%u pushAck=%u blockedSequence=%u\n",
             mPushDirty, mPushAck, mBlockedSequence);
 }
 #endif
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index d6333be..d08c966 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -574,30 +574,30 @@
 
     bool locked = AudioFlinger::dumpTryLock(mLock);
     if (!locked) {
-        fdprintf(fd, "thread %p maybe dead locked\n", this);
+        dprintf(fd, "thread %p maybe dead locked\n", this);
     }
 
-    fdprintf(fd, "  I/O handle: %d\n", mId);
-    fdprintf(fd, "  TID: %d\n", getTid());
-    fdprintf(fd, "  Standby: %s\n", mStandby ? "yes" : "no");
-    fdprintf(fd, "  Sample rate: %u\n", mSampleRate);
-    fdprintf(fd, "  HAL frame count: %zu\n", mFrameCount);
-    fdprintf(fd, "  HAL buffer size: %u bytes\n", mBufferSize);
-    fdprintf(fd, "  Channel Count: %u\n", mChannelCount);
-    fdprintf(fd, "  Channel Mask: 0x%08x (%s)\n", mChannelMask,
+    dprintf(fd, "  I/O handle: %d\n", mId);
+    dprintf(fd, "  TID: %d\n", getTid());
+    dprintf(fd, "  Standby: %s\n", mStandby ? "yes" : "no");
+    dprintf(fd, "  Sample rate: %u\n", mSampleRate);
+    dprintf(fd, "  HAL frame count: %zu\n", mFrameCount);
+    dprintf(fd, "  HAL buffer size: %u bytes\n", mBufferSize);
+    dprintf(fd, "  Channel Count: %u\n", mChannelCount);
+    dprintf(fd, "  Channel Mask: 0x%08x (%s)\n", mChannelMask,
             channelMaskToString(mChannelMask, mType != RECORD).string());
-    fdprintf(fd, "  Format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
-    fdprintf(fd, "  Frame size: %zu\n", mFrameSize);
-    fdprintf(fd, "  Pending config events:");
+    dprintf(fd, "  Format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
+    dprintf(fd, "  Frame size: %zu\n", mFrameSize);
+    dprintf(fd, "  Pending config events:");
     size_t numConfig = mConfigEvents.size();
     if (numConfig) {
         for (size_t i = 0; i < numConfig; i++) {
             mConfigEvents[i]->dump(buffer, SIZE);
-            fdprintf(fd, "\n    %s", buffer);
+            dprintf(fd, "\n    %s", buffer);
         }
-        fdprintf(fd, "\n");
+        dprintf(fd, "\n");
     } else {
-        fdprintf(fd, " none\n");
+        dprintf(fd, " none\n");
     }
 
     if (locked) {
@@ -1260,15 +1260,15 @@
 
     // These values are "raw"; they will wrap around.  See prepareTracks_l() for a better way.
     FastTrackUnderruns underruns = getFastTrackUnderruns(0);
-    fdprintf(fd, "  Normal mixer raw underrun counters: partial=%u empty=%u\n",
+    dprintf(fd, "  Normal mixer raw underrun counters: partial=%u empty=%u\n",
             underruns.mBitFields.mPartial, underruns.mBitFields.mEmpty);
 
     size_t numtracks = mTracks.size();
     size_t numactive = mActiveTracks.size();
-    fdprintf(fd, "  %d Tracks", numtracks);
+    dprintf(fd, "  %d Tracks", numtracks);
     size_t numactiveseen = 0;
     if (numtracks) {
-        fdprintf(fd, " of which %d are active\n", numactive);
+        dprintf(fd, " of which %d are active\n", numactive);
         Track::appendDumpHeader(result);
         for (size_t i = 0; i < numtracks; ++i) {
             sp<Track> track = mTracks[i];
@@ -1300,22 +1300,21 @@
     }
 
     write(fd, result.string(), result.size());
-
 }
 
 void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
 {
-    fdprintf(fd, "\nOutput thread %p:\n", this);
-    fdprintf(fd, "  Normal frame count: %zu\n", mNormalFrameCount);
-    fdprintf(fd, "  Last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
-    fdprintf(fd, "  Total writes: %d\n", mNumWrites);
-    fdprintf(fd, "  Delayed writes: %d\n", mNumDelayedWrites);
-    fdprintf(fd, "  Blocked in write: %s\n", mInWrite ? "yes" : "no");
-    fdprintf(fd, "  Suspend count: %d\n", mSuspended);
-    fdprintf(fd, "  Sink buffer : %p\n", mSinkBuffer);
-    fdprintf(fd, "  Mixer buffer: %p\n", mMixerBuffer);
-    fdprintf(fd, "  Effect buffer: %p\n", mEffectBuffer);
-    fdprintf(fd, "  Fast track availMask=%#x\n", mFastTrackAvailMask);
+    dprintf(fd, "\nOutput thread %p:\n", this);
+    dprintf(fd, "  Normal frame count: %zu\n", mNormalFrameCount);
+    dprintf(fd, "  Last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
+    dprintf(fd, "  Total writes: %d\n", mNumWrites);
+    dprintf(fd, "  Delayed writes: %d\n", mNumDelayedWrites);
+    dprintf(fd, "  Blocked in write: %s\n", mInWrite ? "yes" : "no");
+    dprintf(fd, "  Suspend count: %d\n", mSuspended);
+    dprintf(fd, "  Sink buffer : %p\n", mSinkBuffer);
+    dprintf(fd, "  Mixer buffer: %p\n", mMixerBuffer);
+    dprintf(fd, "  Effect buffer: %p\n", mEffectBuffer);
+    dprintf(fd, "  Fast track availMask=%#x\n", mFastTrackAvailMask);
 
     dumpBase(fd, args);
 }
@@ -3799,7 +3798,7 @@
 
     PlaybackThread::dumpInternals(fd, args);
 
-    fdprintf(fd, "  AudioMixer tracks: 0x%08x\n", mAudioMixer->trackNames());
+    dprintf(fd, "  AudioMixer tracks: 0x%08x\n", mAudioMixer->trackNames());
 
     // Make a non-atomic copy of fast mixer dump state so it won't change underneath us
     const FastMixerDumpState copy(mFastMixerDumpState);
@@ -5717,12 +5716,12 @@
 
 void AudioFlinger::RecordThread::dumpInternals(int fd, const Vector<String16>& args)
 {
-    fdprintf(fd, "\nInput thread %p:\n", this);
+    dprintf(fd, "\nInput thread %p:\n", this);
 
     if (mActiveTracks.size() > 0) {
-        fdprintf(fd, "  Buffer size: %zu bytes\n", mBufferSize);
+        dprintf(fd, "  Buffer size: %zu bytes\n", mBufferSize);
     } else {
-        fdprintf(fd, "  No active record clients\n");
+        dprintf(fd, "  No active record clients\n");
     }
     dprintf(fd, "  Fast track available: %s\n", mFastTrackAvail ? "yes" : "no");
 
@@ -5738,9 +5737,9 @@
     size_t numtracks = mTracks.size();
     size_t numactive = mActiveTracks.size();
     size_t numactiveseen = 0;
-    fdprintf(fd, "  %d Tracks", numtracks);
+    dprintf(fd, "  %d Tracks", numtracks);
     if (numtracks) {
-        fdprintf(fd, " of which %d are active\n", numactive);
+        dprintf(fd, " of which %d are active\n", numactive);
         RecordTrack::appendDumpHeader(result);
         for (size_t i = 0; i < numtracks ; ++i) {
             sp<RecordTrack> track = mTracks[i];
@@ -5754,7 +5753,7 @@
             }
         }
     } else {
-        fdprintf(fd, "\n");
+        dprintf(fd, "\n");
     }
 
     if (numactiveseen != numactive) {
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index 61edac2..d4c9374 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -100,6 +100,7 @@
     STRING_TO_ENUM(AUDIO_DEVICE_IN_TV_TUNER),
     STRING_TO_ENUM(AUDIO_DEVICE_IN_LINE),
     STRING_TO_ENUM(AUDIO_DEVICE_IN_SPDIF),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
 };
 
 const StringToEnum sFlagNameToEnumTable[] = {
@@ -284,16 +285,8 @@
                             0);
         }
 
-        if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET) {
-            device = AUDIO_DEVICE_IN_WIRED_HEADSET;
-        } else if (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO ||
-                   device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
-                   device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
-            device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
-        } else {
-            mpClientInterface->onAudioPortListUpdate();
-            return NO_ERROR;
-        }
+        mpClientInterface->onAudioPortListUpdate();
+        return NO_ERROR;
     }  // end if is output device
 
     // handle input devices
@@ -3809,6 +3802,12 @@
 
     case AUDIO_SOURCE_DEFAULT:
     case AUDIO_SOURCE_MIC:
+    if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
+        device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+        break;
+    }
+    // FALL THROUGH
+
     case AUDIO_SOURCE_VOICE_RECOGNITION:
     case AUDIO_SOURCE_HOTWORD:
     case AUDIO_SOURCE_VOICE_COMMUNICATION:
@@ -3985,6 +3984,11 @@
 };
 
 const AudioPolicyManager::VolumeCurvePoint
+    AudioPolicyManager::sSpeakerMediaVolumeCurveDrc[AudioPolicyManager::VOLCNT] = {
+    {1, -56.0f}, {20, -34.0f}, {86, -10.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManager::VolumeCurvePoint
     AudioPolicyManager::sSpeakerSonificationVolumeCurve[AudioPolicyManager::VOLCNT] = {
     {1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f}
 };
@@ -4098,6 +4102,8 @@
                 sSpeakerSonificationVolumeCurveDrc;
         mStreams[AUDIO_STREAM_NOTIFICATION].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
                 sSpeakerSonificationVolumeCurveDrc;
+        mStreams[AUDIO_STREAM_MUSIC].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+                sSpeakerMediaVolumeCurveDrc;
     }
 }
 
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
index adf1b33..1abeb6a 100644
--- a/services/audiopolicy/AudioPolicyManager.h
+++ b/services/audiopolicy/AudioPolicyManager.h
@@ -374,6 +374,7 @@
         static const VolumeCurvePoint sDefaultMediaVolumeCurve[AudioPolicyManager::VOLCNT];
         // volume curve for media strategy on speakers
         static const VolumeCurvePoint sSpeakerMediaVolumeCurve[AudioPolicyManager::VOLCNT];
+        static const VolumeCurvePoint sSpeakerMediaVolumeCurveDrc[AudioPolicyManager::VOLCNT];
         // volume curve for sonification strategy on speakers
         static const VolumeCurvePoint sSpeakerSonificationVolumeCurve[AudioPolicyManager::VOLCNT];
         static const VolumeCurvePoint sSpeakerSonificationVolumeCurveDrc[AudioPolicyManager::VOLCNT];
diff --git a/services/camera/libcameraservice/utils/CameraTraces.cpp b/services/camera/libcameraservice/utils/CameraTraces.cpp
index 346e15f..374dc5e 100644
--- a/services/camera/libcameraservice/utils/CameraTraces.cpp
+++ b/services/camera/libcameraservice/utils/CameraTraces.cpp
@@ -74,10 +74,10 @@
         return BAD_VALUE;
     }
 
-    fdprintf(fd, "Camera traces (%zu):\n", pcsList.size());
+    dprintf(fd, "Camera traces (%zu):\n", pcsList.size());
 
     if (pcsList.empty()) {
-        fdprintf(fd, "  No camera traces collected.\n");
+        dprintf(fd, "  No camera traces collected.\n");
     }
 
     // Print newest items first
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index 0c7fbbd..41dab1f 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -60,7 +60,7 @@
     static const String16 sDump("android.permission.DUMP");
     if (!(IPCThreadState::self()->getCallingUid() == AID_MEDIA ||
             PermissionCache::checkCallingPermission(sDump))) {
-        fdprintf(fd, "Permission Denial: can't dump media.log from pid=%d, uid=%d\n",
+        dprintf(fd, "Permission Denial: can't dump media.log from pid=%d, uid=%d\n",
                 IPCThreadState::self()->getCallingPid(),
                 IPCThreadState::self()->getCallingUid());
         return NO_ERROR;
@@ -74,7 +74,7 @@
     for (size_t i = 0; i < namedReaders.size(); i++) {
         const NamedReader& namedReader = namedReaders[i];
         if (fd >= 0) {
-            fdprintf(fd, "\n%s:\n", namedReader.name());
+            dprintf(fd, "\n%s:\n", namedReader.name());
         } else {
             ALOGI("%s:", namedReader.name());
         }
diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk
new file mode 100644
index 0000000..b7ccaab
--- /dev/null
+++ b/services/soundtrigger/Android.mk
@@ -0,0 +1,41 @@
+# Copyright 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+
+ifeq ($(SOUND_TRIGGER_USE_STUB_MODULE), 1)
+    LOCAL_CFLAGS += -DSOUND_TRIGGER_USE_STUB_MODULE
+endif
+
+LOCAL_SRC_FILES:=               \
+    SoundTriggerHwService.cpp
+
+LOCAL_SHARED_LIBRARIES:= \
+    libui \
+    liblog \
+    libutils \
+    libbinder \
+    libcutils \
+    libhardware \
+    libsoundtrigger
+
+#LOCAL_C_INCLUDES += \
+
+
+LOCAL_MODULE:= libsoundtriggerservice
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
new file mode 100644
index 0000000..f09e79e
--- /dev/null
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SoundTriggerHwService"
+//#define LOG_NDEBUG 0
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
+#include <cutils/atomic.h>
+#include <cutils/properties.h>
+#include <hardware/hardware.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "SoundTriggerHwService.h"
+#include <system/sound_trigger.h>
+#include <hardware/sound_trigger.h>
+
+namespace android {
+
+#ifdef SOUND_TRIGGER_USE_STUB_MODULE
+#define HW_MODULE_PREFIX "stub"
+#else
+#define HW_MODULE_PREFIX "primary"
+#endif
+
+SoundTriggerHwService::SoundTriggerHwService()
+    : BnSoundTriggerHwService(),
+      mNextUniqueId(1)
+{
+}
+
+void SoundTriggerHwService::onFirstRef()
+{
+    const hw_module_t *mod;
+    int rc;
+    sound_trigger_hw_device *dev;
+
+    rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, &mod);
+    if (rc != 0) {
+        ALOGE("couldn't load sound trigger module %s.%s (%s)",
+              SOUND_TRIGGER_HARDWARE_MODULE_ID, "primary", strerror(-rc));
+        return;
+    }
+    rc = sound_trigger_hw_device_open(mod, &dev);
+    if (rc != 0) {
+        ALOGE("couldn't open sound trigger hw device in %s.%s (%s)",
+              SOUND_TRIGGER_HARDWARE_MODULE_ID, "primary", strerror(-rc));
+        return;
+    }
+    if (dev->common.version != SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
+        ALOGE("wrong sound trigger hw device version %04x", dev->common.version);
+        return;
+    }
+
+    sound_trigger_module_descriptor descriptor;
+    rc = dev->get_properties(dev, &descriptor.properties);
+    if (rc != 0) {
+        ALOGE("could not read implementation properties");
+        return;
+    }
+    descriptor.handle =
+            (sound_trigger_module_handle_t)android_atomic_inc(&mNextUniqueId);
+    ALOGI("loaded default module %s, handle %d", descriptor.properties.description,
+                                                 descriptor.handle);
+
+    sp<ISoundTriggerClient> client;
+    sp<Module> module = new Module(this, dev, descriptor, client);
+    mModules.add(descriptor.handle, module);
+    mCallbackThread = new CallbackThread(this);
+}
+
+SoundTriggerHwService::~SoundTriggerHwService()
+{
+    if (mCallbackThread != 0) {
+        mCallbackThread->exit();
+    }
+    for (size_t i = 0; i < mModules.size(); i++) {
+        sound_trigger_hw_device_close(mModules.valueAt(i)->hwDevice());
+    }
+}
+
+status_t SoundTriggerHwService::listModules(struct sound_trigger_module_descriptor *modules,
+                             uint32_t *numModules)
+{
+    ALOGV("listModules");
+    AutoMutex lock(mServiceLock);
+    if (numModules == NULL || (*numModules != 0 && modules == NULL)) {
+        return BAD_VALUE;
+    }
+    size_t maxModules = *numModules;
+    *numModules = mModules.size();
+    for (size_t i = 0; i < mModules.size() && i < maxModules; i++) {
+        modules[i] = mModules.valueAt(i)->descriptor();
+    }
+    return NO_ERROR;
+}
+
+status_t SoundTriggerHwService::attach(const sound_trigger_module_handle_t handle,
+                        const sp<ISoundTriggerClient>& client,
+                        sp<ISoundTrigger>& moduleInterface)
+{
+    ALOGV("attach module %d", handle);
+    AutoMutex lock(mServiceLock);
+    moduleInterface.clear();
+    if (client == 0) {
+        return BAD_VALUE;
+    }
+    ssize_t index = mModules.indexOfKey(handle);
+    if (index < 0) {
+        return BAD_VALUE;
+    }
+    sp<Module> module = mModules.valueAt(index);
+
+    module->setClient(client);
+    client->asBinder()->linkToDeath(module);
+    moduleInterface = module;
+
+    return NO_ERROR;
+}
+
+void SoundTriggerHwService::detachModule(sp<Module> module) {
+    AutoMutex lock(mServiceLock);
+    ALOGV("detachModule");
+    module->clearClient();
+}
+
+static const int kDumpLockRetries = 50;
+static const int kDumpLockSleep = 60000;
+
+static bool tryLock(Mutex& mutex)
+{
+    bool locked = false;
+    for (int i = 0; i < kDumpLockRetries; ++i) {
+        if (mutex.tryLock() == NO_ERROR) {
+            locked = true;
+            break;
+        }
+        usleep(kDumpLockSleep);
+    }
+    return locked;
+}
+
+status_t SoundTriggerHwService::dump(int fd, const Vector<String16>& args __unused) {
+    String8 result;
+    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+        result.appendFormat("Permission Denial: can't dump SoundTriggerHwService");
+        write(fd, result.string(), result.size());
+    } else {
+        bool locked = tryLock(mServiceLock);
+        // failed to lock - SoundTriggerHwService is probably deadlocked
+        if (!locked) {
+            result.append("SoundTriggerHwService may be deadlocked\n");
+            write(fd, result.string(), result.size());
+        }
+
+        if (locked) mServiceLock.unlock();
+    }
+    return NO_ERROR;
+}
+
+status_t SoundTriggerHwService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+    return BnSoundTriggerHwService::onTransact(code, data, reply, flags);
+}
+
+
+// static
+void SoundTriggerHwService::recognitionCallback(struct sound_trigger_recognition_event *event,
+                                                void *cookie)
+{
+    Module *module = (Module *)cookie;
+    if (module == NULL) {
+        return;
+    }
+    module->sendRecognitionEvent(event);
+}
+
+
+void SoundTriggerHwService::sendRecognitionEvent(const sp<RecognitionEvent>& event)
+{
+    mCallbackThread->sendRecognitionEvent(event);
+}
+
+void SoundTriggerHwService::onRecognitionEvent(const sp<RecognitionEvent>& event)
+{
+    ALOGV("onRecognitionEvent");
+    sp<Module> module;
+    {
+        AutoMutex lock(mServiceLock);
+        module = event->mModule.promote();
+        if (module == 0) {
+            return;
+        }
+    }
+    module->onRecognitionEvent(event->mEventMemory);
+}
+
+// static
+void SoundTriggerHwService::soundModelCallback(struct sound_trigger_model_event *event __unused,
+                                               void *cookie)
+{
+    Module *module = (Module *)cookie;
+
+}
+
+#undef LOG_TAG
+#define LOG_TAG "SoundTriggerHwService::CallbackThread"
+
+SoundTriggerHwService::CallbackThread::CallbackThread(const wp<SoundTriggerHwService>& service)
+    : mService(service)
+{
+}
+
+SoundTriggerHwService::CallbackThread::~CallbackThread()
+{
+    mEventQueue.clear();
+}
+
+void SoundTriggerHwService::CallbackThread::onFirstRef()
+{
+    run("soundTrigger cbk", ANDROID_PRIORITY_URGENT_AUDIO);
+}
+
+bool SoundTriggerHwService::CallbackThread::threadLoop()
+{
+    while (!exitPending()) {
+        sp<RecognitionEvent> event;
+        sp<SoundTriggerHwService> service;
+        {
+            Mutex::Autolock _l(mCallbackLock);
+            while (mEventQueue.isEmpty() && !exitPending()) {
+                ALOGV("CallbackThread::threadLoop() sleep");
+                mCallbackCond.wait(mCallbackLock);
+                ALOGV("CallbackThread::threadLoop() wake up");
+            }
+            if (exitPending()) {
+                break;
+            }
+            event = mEventQueue[0];
+            mEventQueue.removeAt(0);
+            service = mService.promote();
+        }
+        if (service != 0) {
+            service->onRecognitionEvent(event);
+        }
+    }
+    return false;
+}
+
+void SoundTriggerHwService::CallbackThread::exit()
+{
+    Mutex::Autolock _l(mCallbackLock);
+    requestExit();
+    mCallbackCond.broadcast();
+}
+
+void SoundTriggerHwService::CallbackThread::sendRecognitionEvent(
+                        const sp<SoundTriggerHwService::RecognitionEvent>& event)
+{
+    AutoMutex lock(mCallbackLock);
+    mEventQueue.add(event);
+    mCallbackCond.signal();
+}
+
+SoundTriggerHwService::RecognitionEvent::RecognitionEvent(
+                                            sp<IMemory> eventMemory,
+                                            wp<Module> module)
+    : mEventMemory(eventMemory), mModule(module)
+{
+}
+
+SoundTriggerHwService::RecognitionEvent::~RecognitionEvent()
+{
+}
+
+#undef LOG_TAG
+#define LOG_TAG "SoundTriggerHwService::Module"
+
+SoundTriggerHwService::Module::Module(const sp<SoundTriggerHwService>& service,
+                                      sound_trigger_hw_device* hwDevice,
+                                      sound_trigger_module_descriptor descriptor,
+                                      const sp<ISoundTriggerClient>& client)
+ : mService(service), mHwDevice(hwDevice), mDescriptor(descriptor),
+   mClient(client)
+{
+}
+
+SoundTriggerHwService::Module::~Module() {
+}
+
+void SoundTriggerHwService::Module::detach() {
+    ALOGV("detach()");
+    {
+        AutoMutex lock(mLock);
+        for (size_t i = 0; i < mModels.size(); i++) {
+            sp<Model> model = mModels.valueAt(i);
+            ALOGV("detach() unloading model %d", model->mHandle);
+            if (model->mState == Model::STATE_ACTIVE) {
+                mHwDevice->stop_recognition(mHwDevice, model->mHandle);
+                model->deallocateMemory();
+            }
+            mHwDevice->unload_sound_model(mHwDevice, model->mHandle);
+        }
+        mModels.clear();
+    }
+    if (mClient != 0) {
+        mClient->asBinder()->unlinkToDeath(this);
+    }
+    sp<SoundTriggerHwService> service = mService.promote();
+    if (service == 0) {
+        return;
+    }
+    service->detachModule(this);
+}
+
+status_t SoundTriggerHwService::Module::loadSoundModel(const sp<IMemory>& modelMemory,
+                                sound_model_handle_t *handle)
+{
+    ALOGV("loadSoundModel() handle");
+
+    if (modelMemory == 0 || modelMemory->pointer() == NULL) {
+        ALOGE("loadSoundModel() modelMemory is 0 or has NULL pointer()");
+        return BAD_VALUE;
+    }
+    struct sound_trigger_sound_model *sound_model =
+            (struct sound_trigger_sound_model *)modelMemory->pointer();
+
+    AutoMutex lock(mLock);
+    status_t status = mHwDevice->load_sound_model(mHwDevice,
+                                                  sound_model,
+                                                  SoundTriggerHwService::soundModelCallback,
+                                                  this,
+                                                  handle);
+    if (status == NO_ERROR) {
+        mModels.replaceValueFor(*handle, new Model(*handle));
+    }
+
+    return status;
+}
+
+status_t SoundTriggerHwService::Module::unloadSoundModel(sound_model_handle_t handle)
+{
+    ALOGV("unloadSoundModel() model handle %d", handle);
+
+    AutoMutex lock(mLock);
+    ssize_t index = mModels.indexOfKey(handle);
+    if (index < 0) {
+        return BAD_VALUE;
+    }
+    mModels.removeItem(handle);
+
+    return mHwDevice->unload_sound_model(mHwDevice, handle);
+}
+
+status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle,
+                                  const sp<IMemory>& dataMemory)
+{
+    ALOGV("startRecognition() model handle %d", handle);
+
+    if (dataMemory != 0 && dataMemory->pointer() == NULL) {
+        ALOGE("startRecognition() dataMemory is non-0 but has NULL pointer()");
+        return BAD_VALUE;
+
+    }
+    AutoMutex lock(mLock);
+    sp<Model> model = getModel(handle);
+    if (model == 0) {
+        return BAD_VALUE;
+    }
+
+    if (model->mState == Model::STATE_ACTIVE) {
+        return INVALID_OPERATION;
+    }
+    model->mState = Model::STATE_ACTIVE;
+
+    char *data = NULL;
+    unsigned int data_size = 0;
+    if (dataMemory != 0 && dataMemory->size() != 0) {
+        data_size = (unsigned int)dataMemory->size();
+        data = (char *)dataMemory->pointer();
+        ALOGV("startRecognition() data size %d data %d - %d",
+                      data_size, data[0], data[data_size - 1]);
+    }
+
+    //TODO: get capture handle and device from audio policy service
+    audio_io_handle_t capture_handle = 0;
+    return mHwDevice->start_recognition(mHwDevice, handle, capture_handle, AUDIO_DEVICE_NONE,
+                                        SoundTriggerHwService::recognitionCallback,
+                                        this,
+                                        data_size,
+                                        data);
+}
+
+status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t handle)
+{
+    ALOGV("stopRecognition() model handle %d", handle);
+
+    AutoMutex lock(mLock);
+    sp<Model> model = getModel(handle);
+    if (model == 0) {
+        return BAD_VALUE;
+    }
+
+    if (model->mState != Model::STATE_ACTIVE) {
+        return INVALID_OPERATION;
+    }
+    mHwDevice->stop_recognition(mHwDevice, handle);
+    model->deallocateMemory();
+    model->mState = Model::STATE_IDLE;
+    return NO_ERROR;
+}
+
+void SoundTriggerHwService::Module::sendRecognitionEvent(
+                                                    struct sound_trigger_recognition_event *event)
+{
+    sp<SoundTriggerHwService> service;
+    sp<IMemory> eventMemory;
+    ALOGV("sendRecognitionEvent for model %d", event->model);
+    {
+        AutoMutex lock(mLock);
+        sp<Model> model = getModel(event->model);
+        if (model == 0) {
+            return;
+        }
+        if (model->mState != Model::STATE_ACTIVE) {
+            ALOGV("sendRecognitionEvent model->mState %d != Model::STATE_ACTIVE", model->mState);
+            return;
+        }
+        if (mClient == 0) {
+            return;
+        }
+        service = mService.promote();
+        if (service == 0) {
+            return;
+        }
+
+        //sanitize event
+        switch (event->type) {
+        case SOUND_MODEL_TYPE_KEYPHRASE:
+            ALOGW_IF(event->data_offset !=
+                        sizeof(struct sound_trigger_phrase_recognition_event),
+                        "sendRecognitionEvent(): invalid data offset %u for keyphrase event type",
+                        event->data_offset);
+            event->data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
+            break;
+        case SOUND_MODEL_TYPE_UNKNOWN:
+            ALOGW_IF(event->data_offset !=
+                        sizeof(struct sound_trigger_recognition_event),
+                        "sendRecognitionEvent(): invalid data offset %u for unknown event type",
+                        event->data_offset);
+            event->data_offset = sizeof(struct sound_trigger_recognition_event);
+            break;
+        default:
+                return;
+        }
+
+        size_t size = event->data_offset + event->data_size;
+        eventMemory = model->allocateMemory(size);
+        if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+            return;
+        }
+        memcpy(eventMemory->pointer(), event, size);
+    }
+    service->sendRecognitionEvent(new RecognitionEvent(eventMemory, this));
+}
+
+void SoundTriggerHwService::Module::onRecognitionEvent(sp<IMemory> eventMemory)
+{
+    ALOGV("Module::onRecognitionEvent");
+
+    AutoMutex lock(mLock);
+
+    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+        return;
+    }
+    struct sound_trigger_recognition_event *event =
+            (struct sound_trigger_recognition_event *)eventMemory->pointer();
+
+    sp<Model> model = getModel(event->model);
+    if (model == 0) {
+        ALOGI("%s model == 0", __func__);
+        return;
+    }
+    if (model->mState != Model::STATE_ACTIVE) {
+        ALOGV("onRecognitionEvent model->mState %d != Model::STATE_ACTIVE", model->mState);
+        return;
+    }
+    if (mClient == 0) {
+        ALOGI("%s mClient == 0", __func__);
+        return;
+    }
+    mClient->onRecognitionEvent(eventMemory);
+    model->mState = Model::STATE_IDLE;
+    model->deallocateMemory();
+}
+
+sp<SoundTriggerHwService::Model> SoundTriggerHwService::Module::getModel(
+        sound_model_handle_t handle)
+{
+    sp<Model> model;
+    ssize_t index = mModels.indexOfKey(handle);
+    if (index >= 0) {
+        model = mModels.valueAt(index);
+    }
+    return model;
+}
+
+void SoundTriggerHwService::Module::binderDied(
+    const wp<IBinder> &who __unused) {
+    ALOGW("client binder died for module %d", mDescriptor.handle);
+    detach();
+}
+
+
+SoundTriggerHwService::Model::Model(sound_model_handle_t handle) :
+    mHandle(handle), mState(STATE_IDLE), mInputHandle(AUDIO_IO_HANDLE_NONE),
+    mCaptureSession(AUDIO_SESSION_ALLOCATE),
+    mMemoryDealer(new MemoryDealer(sizeof(struct sound_trigger_recognition_event),
+                                   "SoundTriggerHwService::Event"))
+{
+
+}
+
+
+sp<IMemory> SoundTriggerHwService::Model::allocateMemory(size_t size)
+{
+    sp<IMemory> memory;
+    if (mMemoryDealer->getMemoryHeap()->getSize() < size) {
+        mMemoryDealer = new MemoryDealer(size, "SoundTriggerHwService::Event");
+    }
+    memory = mMemoryDealer->allocate(size);
+    return memory;
+}
+
+void SoundTriggerHwService::Model::deallocateMemory()
+{
+    mMemoryDealer->deallocate(0);
+}
+
+status_t SoundTriggerHwService::Module::dump(int fd __unused,
+                                             const Vector<String16>& args __unused) {
+    String8 result;
+    return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
new file mode 100644
index 0000000..377f2a1
--- /dev/null
+++ b/services/soundtrigger/SoundTriggerHwService.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_HAL_SERVICE_H
+#define ANDROID_HARDWARE_SOUNDTRIGGER_HAL_SERVICE_H
+
+#include <utils/Vector.h>
+//#include <binder/AppOpsManager.h>
+#include <binder/MemoryDealer.h>
+#include <binder/BinderService.h>
+#include <binder/IAppOpsCallback.h>
+#include <soundtrigger/ISoundTriggerHwService.h>
+#include <soundtrigger/ISoundTrigger.h>
+#include <soundtrigger/ISoundTriggerClient.h>
+#include <system/sound_trigger.h>
+#include <hardware/sound_trigger.h>
+
+namespace android {
+
+class MemoryHeapBase;
+
+class SoundTriggerHwService :
+    public BinderService<SoundTriggerHwService>,
+    public BnSoundTriggerHwService
+{
+    friend class BinderService<SoundTriggerHwService>;
+public:
+    class Module;
+
+    static char const* getServiceName() { return "media.sound_trigger_hw"; }
+
+                        SoundTriggerHwService();
+    virtual             ~SoundTriggerHwService();
+
+    // ISoundTriggerHwService
+    virtual status_t listModules(struct sound_trigger_module_descriptor *modules,
+                                 uint32_t *numModules);
+
+    virtual status_t attach(const sound_trigger_module_handle_t handle,
+                            const sp<ISoundTriggerClient>& client,
+                            sp<ISoundTrigger>& module);
+
+    virtual status_t    onTransact(uint32_t code, const Parcel& data,
+                                   Parcel* reply, uint32_t flags);
+
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+
+    class Model : public RefBase {
+     public:
+
+        enum {
+            STATE_IDLE,
+            STATE_ACTIVE
+        };
+
+        Model(sound_model_handle_t handle);
+        ~Model() {}
+
+        sp<IMemory> allocateMemory(size_t size);
+        void deallocateMemory();
+
+        sound_model_handle_t    mHandle;
+        int                     mState;
+        audio_io_handle_t       mInputHandle;
+        audio_session_t         mCaptureSession;
+        sp<MemoryDealer>        mMemoryDealer;
+    };
+
+    class Module : public virtual RefBase,
+                   public BnSoundTrigger,
+                   public IBinder::DeathRecipient     {
+    public:
+
+       Module(const sp<SoundTriggerHwService>& service,
+              sound_trigger_hw_device* hwDevice,
+              sound_trigger_module_descriptor descriptor,
+              const sp<ISoundTriggerClient>& client);
+
+       virtual ~Module();
+
+       virtual void detach();
+
+       virtual status_t loadSoundModel(const sp<IMemory>& modelMemory,
+                                       sound_model_handle_t *handle);
+
+       virtual status_t unloadSoundModel(sound_model_handle_t handle);
+
+       virtual status_t startRecognition(sound_model_handle_t handle,
+                                         const sp<IMemory>& dataMemory);
+       virtual status_t stopRecognition(sound_model_handle_t handle);
+
+       virtual status_t dump(int fd, const Vector<String16>& args);
+
+
+       sound_trigger_hw_device *hwDevice() const { return mHwDevice; }
+       struct sound_trigger_module_descriptor descriptor() { return mDescriptor; }
+       void setClient(sp<ISoundTriggerClient> client) { mClient = client; }
+       void clearClient() { mClient.clear(); }
+       sp<ISoundTriggerClient> client() { return mClient; }
+
+       void sendRecognitionEvent(struct sound_trigger_recognition_event *event);
+       void onRecognitionEvent(sp<IMemory> eventMemory);
+
+       sp<Model> getModel(sound_model_handle_t handle);
+
+       // IBinder::DeathRecipient implementation
+       virtual void        binderDied(const wp<IBinder> &who);
+
+    private:
+        Mutex                                  mLock;
+        wp<SoundTriggerHwService>              mService;
+        struct sound_trigger_hw_device*        mHwDevice;
+        struct sound_trigger_module_descriptor mDescriptor;
+        sp<ISoundTriggerClient>                mClient;
+        DefaultKeyedVector< sound_model_handle_t, sp<Model> >     mModels;
+    }; // class Module
+
+    class RecognitionEvent : public RefBase {
+    public:
+
+        RecognitionEvent(sp<IMemory> eventMemory, wp<Module> module);
+
+        virtual             ~RecognitionEvent();
+
+        sp<IMemory> mEventMemory;
+        wp<Module> mModule;
+    };
+
+    class CallbackThread : public Thread {
+    public:
+
+        CallbackThread(const wp<SoundTriggerHwService>& service);
+
+        virtual             ~CallbackThread();
+
+        // Thread virtuals
+        virtual bool        threadLoop();
+
+        // RefBase
+        virtual void        onFirstRef();
+
+                void        exit();
+                void        sendRecognitionEvent(const sp<RecognitionEvent>& event);
+
+    private:
+        wp<SoundTriggerHwService>   mService;
+        Condition                   mCallbackCond;
+        Mutex                       mCallbackLock;
+        Vector< sp<RecognitionEvent> > mEventQueue;
+    };
+
+    void detachModule(sp<Module> module);
+
+    static void recognitionCallback(struct sound_trigger_recognition_event *event, void *cookie);
+    void sendRecognitionEvent(const sp<RecognitionEvent>& event);
+    void onRecognitionEvent(const sp<RecognitionEvent>& event);
+
+    static void soundModelCallback(struct sound_trigger_model_event *event, void *cookie);
+
+private:
+
+    virtual void onFirstRef();
+
+    Mutex               mServiceLock;
+    volatile int32_t    mNextUniqueId;
+    DefaultKeyedVector< sound_trigger_module_handle_t, sp<Module> >     mModules;
+    sp<CallbackThread>  mCallbackThread;
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_SOUNDTRIGGER_HAL_SERVICE_H
diff --git a/soundtrigger/Android.mk b/soundtrigger/Android.mk
new file mode 100644
index 0000000..d91c4c2
--- /dev/null
+++ b/soundtrigger/Android.mk
@@ -0,0 +1,38 @@
+# Copyright 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	SoundTrigger.cpp \
+	ISoundTrigger.cpp \
+	ISoundTriggerClient.cpp \
+	ISoundTriggerHwService.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	libutils \
+	liblog \
+	libbinder \
+	libhardware
+
+#LOCAL_C_INCLUDES += \
+	system/media/camera/include \
+	system/media/private/camera/include
+
+LOCAL_MODULE:= libsoundtrigger
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/soundtrigger/ISoundTrigger.cpp b/soundtrigger/ISoundTrigger.cpp
new file mode 100644
index 0000000..42280d1
--- /dev/null
+++ b/soundtrigger/ISoundTrigger.cpp
@@ -0,0 +1,177 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "ISoundTrigger"
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <binder/IMemory.h>
+#include <soundtrigger/ISoundTrigger.h>
+#include <soundtrigger/ISoundTriggerHwService.h>
+#include <soundtrigger/ISoundTriggerClient.h>
+#include <system/sound_trigger.h>
+
+namespace android {
+
+enum {
+    DETACH = IBinder::FIRST_CALL_TRANSACTION,
+    LOAD_SOUND_MODEL,
+    UNLOAD_SOUND_MODEL,
+    START_RECOGNITION,
+    STOP_RECOGNITION,
+};
+
+class BpSoundTrigger: public BpInterface<ISoundTrigger>
+{
+public:
+    BpSoundTrigger(const sp<IBinder>& impl)
+        : BpInterface<ISoundTrigger>(impl)
+    {
+    }
+
+    void detach()
+    {
+        ALOGV("detach");
+        Parcel data, reply;
+        data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor());
+        remote()->transact(DETACH, data, &reply);
+    }
+
+    status_t loadSoundModel(const sp<IMemory>&  modelMemory,
+                                    sound_model_handle_t *handle)
+    {
+        if (modelMemory == 0 || handle == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor());
+        data.writeStrongBinder(modelMemory->asBinder());
+        status_t status = remote()->transact(LOAD_SOUND_MODEL, data, &reply);
+        if (status != NO_ERROR ||
+                (status = (status_t)reply.readInt32()) != NO_ERROR) {
+            return status;
+        }
+        reply.read(handle, sizeof(sound_model_handle_t));
+        return status;
+    }
+
+    virtual status_t unloadSoundModel(sound_model_handle_t handle)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor());
+        data.write(&handle, sizeof(sound_model_handle_t));
+        status_t status = remote()->transact(UNLOAD_SOUND_MODEL, data, &reply);
+        if (status != NO_ERROR) {
+            status = (status_t)reply.readInt32();
+        }
+        return status;
+    }
+
+    virtual status_t startRecognition(sound_model_handle_t handle,
+                                      const sp<IMemory>& dataMemory)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor());
+        data.write(&handle, sizeof(sound_model_handle_t));
+        if (dataMemory == 0) {
+            data.writeInt32(0);
+        } else {
+            data.writeInt32(dataMemory->size());
+        }
+        data.writeStrongBinder(dataMemory->asBinder());
+        status_t status = remote()->transact(START_RECOGNITION, data, &reply);
+        if (status != NO_ERROR) {
+            status = (status_t)reply.readInt32();
+        }
+        return status;
+    }
+
+    virtual status_t stopRecognition(sound_model_handle_t handle)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor());
+        data.write(&handle, sizeof(sound_model_handle_t));
+        status_t status = remote()->transact(STOP_RECOGNITION, data, &reply);
+        if (status != NO_ERROR) {
+            status = (status_t)reply.readInt32();
+        }
+        return status;
+    }
+
+};
+
+IMPLEMENT_META_INTERFACE(SoundTrigger, "android.hardware.ISoundTrigger");
+
+// ----------------------------------------------------------------------
+
+status_t BnSoundTrigger::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case DETACH: {
+            ALOGV("DETACH");
+            CHECK_INTERFACE(ISoundTrigger, data, reply);
+            detach();
+            return NO_ERROR;
+        } break;
+        case LOAD_SOUND_MODEL: {
+            CHECK_INTERFACE(ISoundTrigger, data, reply);
+            sp<IMemory> modelMemory = interface_cast<IMemory>(
+                data.readStrongBinder());
+            sound_model_handle_t handle;
+            status_t status = loadSoundModel(modelMemory, &handle);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->write(&handle, sizeof(sound_model_handle_t));
+            }
+            return NO_ERROR;
+        }
+        case UNLOAD_SOUND_MODEL: {
+            CHECK_INTERFACE(ISoundTrigger, data, reply);
+            sound_model_handle_t handle;
+            data.read(&handle, sizeof(sound_model_handle_t));
+            status_t status = unloadSoundModel(handle);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        }
+        case START_RECOGNITION: {
+            CHECK_INTERFACE(ISoundTrigger, data, reply);
+            sound_model_handle_t handle;
+            data.read(&handle, sizeof(sound_model_handle_t));
+            sp<IMemory> dataMemory;
+            if (data.readInt32() != 0) {
+                dataMemory = interface_cast<IMemory>(data.readStrongBinder());
+            }
+            status_t status = startRecognition(handle, dataMemory);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        }
+        case STOP_RECOGNITION: {
+            CHECK_INTERFACE(ISoundTrigger, data, reply);
+            sound_model_handle_t handle;
+            data.read(&handle, sizeof(sound_model_handle_t));
+            status_t status = stopRecognition(handle);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/soundtrigger/ISoundTriggerClient.cpp b/soundtrigger/ISoundTriggerClient.cpp
new file mode 100644
index 0000000..1d0c0ec
--- /dev/null
+++ b/soundtrigger/ISoundTriggerClient.cpp
@@ -0,0 +1,75 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <soundtrigger/ISoundTriggerClient.h>
+
+namespace android {
+
+enum {
+    ON_RECOGNITION_EVENT = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BpSoundTriggerClient: public BpInterface<ISoundTriggerClient>
+{
+
+public:
+    BpSoundTriggerClient(const sp<IBinder>& impl)
+        : BpInterface<ISoundTriggerClient>(impl)
+    {
+    }
+
+    virtual void onRecognitionEvent(const sp<IMemory>& eventMemory)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISoundTriggerClient::getInterfaceDescriptor());
+        data.writeStrongBinder(eventMemory->asBinder());
+        remote()->transact(ON_RECOGNITION_EVENT,
+                           data,
+                           &reply);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(SoundTriggerClient,
+                         "android.hardware.ISoundTriggerClient");
+
+// ----------------------------------------------------------------------
+
+status_t BnSoundTriggerClient::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case ON_RECOGNITION_EVENT: {
+            CHECK_INTERFACE(ISoundTriggerClient, data, reply);
+            sp<IMemory> eventMemory = interface_cast<IMemory>(
+                data.readStrongBinder());
+            onRecognitionEvent(eventMemory);
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/soundtrigger/ISoundTriggerHwService.cpp b/soundtrigger/ISoundTriggerHwService.cpp
new file mode 100644
index 0000000..c9a0c24
--- /dev/null
+++ b/soundtrigger/ISoundTriggerHwService.cpp
@@ -0,0 +1,150 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "BpSoundTriggerHwService"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include <soundtrigger/ISoundTriggerHwService.h>
+#include <soundtrigger/ISoundTrigger.h>
+#include <soundtrigger/ISoundTriggerClient.h>
+
+namespace android {
+
+enum {
+    LIST_MODULES = IBinder::FIRST_CALL_TRANSACTION,
+    ATTACH,
+};
+
+class BpSoundTriggerHwService: public BpInterface<ISoundTriggerHwService>
+{
+public:
+    BpSoundTriggerHwService(const sp<IBinder>& impl)
+        : BpInterface<ISoundTriggerHwService>(impl)
+    {
+    }
+
+    virtual status_t listModules(struct sound_trigger_module_descriptor *modules,
+                                 uint32_t *numModules)
+    {
+        if (numModules == NULL || (*numModules != 0 && modules == NULL)) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(ISoundTriggerHwService::getInterfaceDescriptor());
+        unsigned int numModulesReq = (modules == NULL) ? 0 : *numModules;
+        data.writeInt32(numModulesReq);
+        status_t status = remote()->transact(LIST_MODULES, data, &reply);
+        if (status == NO_ERROR) {
+            status = (status_t)reply.readInt32();
+            *numModules = (unsigned int)reply.readInt32();
+        }
+        ALOGV("listModules() status %d got *numModules %d", status, *numModules);
+        if (status == NO_ERROR) {
+            if (numModulesReq > *numModules) {
+                numModulesReq = *numModules;
+            }
+            if (numModulesReq > 0) {
+                reply.read(modules, numModulesReq * sizeof(struct sound_trigger_module_descriptor));
+            }
+        }
+        return status;
+    }
+
+    virtual status_t attach(const sound_trigger_module_handle_t handle,
+                            const sp<ISoundTriggerClient>& client,
+                            sp<ISoundTrigger>& module)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISoundTriggerHwService::getInterfaceDescriptor());
+        data.write(&handle, sizeof(sound_trigger_module_handle_t));
+        data.writeStrongBinder(client->asBinder());
+        remote()->transact(ATTACH, data, &reply);
+        status_t status = reply.readInt32();
+        if (reply.readInt32() != 0) {
+            module = interface_cast<ISoundTrigger>(reply.readStrongBinder());
+        }
+        return status;
+    }
+
+};
+
+IMPLEMENT_META_INTERFACE(SoundTriggerHwService, "android.hardware.ISoundTriggerHwService");
+
+// ----------------------------------------------------------------------
+
+status_t BnSoundTriggerHwService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case LIST_MODULES: {
+            CHECK_INTERFACE(ISoundTriggerHwService, data, reply);
+            unsigned int numModulesReq = data.readInt32();
+            unsigned int numModules = numModulesReq;
+            struct sound_trigger_module_descriptor *modules =
+                    (struct sound_trigger_module_descriptor *)calloc(numModulesReq,
+                                                   sizeof(struct sound_trigger_module_descriptor));
+            status_t status = listModules(modules, &numModules);
+            reply->writeInt32(status);
+            reply->writeInt32(numModules);
+            ALOGV("LIST_MODULES status %d got numModules %d", status, numModules);
+
+            if (status == NO_ERROR) {
+                if (numModulesReq > numModules) {
+                    numModulesReq = numModules;
+                }
+                reply->write(modules,
+                             numModulesReq * sizeof(struct sound_trigger_module_descriptor));
+            }
+            free(modules);
+            return NO_ERROR;
+        }
+
+        case ATTACH: {
+            CHECK_INTERFACE(ISoundTriggerHwService, data, reply);
+            sound_trigger_module_handle_t handle;
+            data.read(&handle, sizeof(sound_trigger_module_handle_t));
+            sp<ISoundTriggerClient> client =
+                    interface_cast<ISoundTriggerClient>(data.readStrongBinder());
+            sp<ISoundTrigger> module;
+            status_t status = attach(handle, client, module);
+            reply->writeInt32(status);
+            if (module != 0) {
+                reply->writeInt32(1);
+                reply->writeStrongBinder(module->asBinder());
+            } else {
+                reply->writeInt32(0);
+            }
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/soundtrigger/SoundTrigger.cpp b/soundtrigger/SoundTrigger.cpp
new file mode 100644
index 0000000..e43acd0
--- /dev/null
+++ b/soundtrigger/SoundTrigger.cpp
@@ -0,0 +1,253 @@
+/*
+**
+** Copyright (C) 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "SoundTrigger"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IMemory.h>
+
+#include <soundtrigger/SoundTrigger.h>
+#include <soundtrigger/ISoundTrigger.h>
+#include <soundtrigger/ISoundTriggerHwService.h>
+#include <soundtrigger/ISoundTriggerClient.h>
+#include <soundtrigger/SoundTriggerCallback.h>
+
+namespace android {
+
+namespace {
+    sp<ISoundTriggerHwService> gSoundTriggerHwService;
+    const int                  kSoundTriggerHwServicePollDelay = 500000; // 0.5s
+    const char*                kSoundTriggerHwServiceName      = "media.sound_trigger_hw";
+    Mutex                      gLock;
+
+    class DeathNotifier : public IBinder::DeathRecipient
+    {
+    public:
+        DeathNotifier() {
+        }
+
+        virtual void binderDied(const wp<IBinder>& who __unused) {
+            ALOGV("binderDied");
+            Mutex::Autolock _l(gLock);
+            gSoundTriggerHwService.clear();
+            ALOGW("Sound trigger service died!");
+        }
+    };
+
+    sp<DeathNotifier>         gDeathNotifier;
+}; // namespace anonymous
+
+const sp<ISoundTriggerHwService>& SoundTrigger::getSoundTriggerHwService()
+{
+    Mutex::Autolock _l(gLock);
+    if (gSoundTriggerHwService.get() == 0) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder;
+        do {
+            binder = sm->getService(String16(kSoundTriggerHwServiceName));
+            if (binder != 0) {
+                break;
+            }
+            ALOGW("SoundTriggerHwService not published, waiting...");
+            usleep(kSoundTriggerHwServicePollDelay);
+        } while(true);
+        if (gDeathNotifier == NULL) {
+            gDeathNotifier = new DeathNotifier();
+        }
+        binder->linkToDeath(gDeathNotifier);
+        gSoundTriggerHwService = interface_cast<ISoundTriggerHwService>(binder);
+    }
+    ALOGE_IF(gSoundTriggerHwService == 0, "no SoundTriggerHwService!?");
+    return gSoundTriggerHwService;
+}
+
+// Static methods
+status_t SoundTrigger::listModules(struct sound_trigger_module_descriptor *modules,
+                                 uint32_t *numModules)
+{
+    ALOGV("listModules()");
+    const sp<ISoundTriggerHwService>& service = getSoundTriggerHwService();
+    if (service == 0) {
+        return NO_INIT;
+    }
+    return service->listModules(modules, numModules);
+}
+
+sp<SoundTrigger> SoundTrigger::attach(const sound_trigger_module_handle_t module,
+                                            const sp<SoundTriggerCallback>& callback)
+{
+    ALOGV("attach()");
+    sp<SoundTrigger> soundTrigger;
+    const sp<ISoundTriggerHwService>& service = getSoundTriggerHwService();
+    if (service == 0) {
+        return soundTrigger;
+    }
+    soundTrigger = new SoundTrigger(module, callback);
+    status_t status = service->attach(module, soundTrigger, soundTrigger->mISoundTrigger);
+
+    if (status == NO_ERROR && soundTrigger->mISoundTrigger != 0) {
+        soundTrigger->mISoundTrigger->asBinder()->linkToDeath(soundTrigger);
+    } else {
+        ALOGW("Error %d connecting to sound trigger service", status);
+        soundTrigger.clear();
+    }
+    return soundTrigger;
+}
+
+
+// SoundTrigger
+SoundTrigger::SoundTrigger(sound_trigger_module_handle_t module,
+                                 const sp<SoundTriggerCallback>& callback)
+    : mModule(module), mCallback(callback)
+{
+}
+
+SoundTrigger::~SoundTrigger()
+{
+    if (mISoundTrigger != 0) {
+        mISoundTrigger->detach();
+    }
+}
+
+
+void SoundTrigger::detach() {
+    ALOGV("detach()");
+    Mutex::Autolock _l(mLock);
+    mCallback.clear();
+    if (mISoundTrigger != 0) {
+        mISoundTrigger->detach();
+        mISoundTrigger->asBinder()->unlinkToDeath(this);
+        mISoundTrigger = 0;
+    }
+}
+
+status_t SoundTrigger::loadSoundModel(const sp<IMemory>& modelMemory,
+                                sound_model_handle_t *handle)
+{
+    Mutex::Autolock _l(mLock);
+    if (mISoundTrigger == 0) {
+        return NO_INIT;
+    }
+
+    return mISoundTrigger->loadSoundModel(modelMemory, handle);
+}
+
+status_t SoundTrigger::unloadSoundModel(sound_model_handle_t handle)
+{
+    Mutex::Autolock _l(mLock);
+    if (mISoundTrigger == 0) {
+        return NO_INIT;
+    }
+    return mISoundTrigger->unloadSoundModel(handle);
+}
+
+status_t SoundTrigger::startRecognition(sound_model_handle_t handle,
+                                        const sp<IMemory>& dataMemory)
+{
+    Mutex::Autolock _l(mLock);
+    if (mISoundTrigger == 0) {
+        return NO_INIT;
+    }
+    return mISoundTrigger->startRecognition(handle, dataMemory);
+}
+
+status_t SoundTrigger::stopRecognition(sound_model_handle_t handle)
+{
+    Mutex::Autolock _l(mLock);
+    if (mISoundTrigger == 0) {
+        return NO_INIT;
+    }
+    return mISoundTrigger->stopRecognition(handle);
+}
+
+// BpSoundTriggerClient
+void SoundTrigger::onRecognitionEvent(const sp<IMemory>& eventMemory)
+{
+    Mutex::Autolock _l(mLock);
+    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+        return;
+    }
+
+    if (mCallback != 0) {
+        mCallback->onRecognitionEvent(
+                (struct sound_trigger_recognition_event *)eventMemory->pointer());
+    }
+}
+
+
+//IBinder::DeathRecipient
+void SoundTrigger::binderDied(const wp<IBinder>& who __unused) {
+    Mutex::Autolock _l(mLock);
+    ALOGW("SoundTrigger server binder Died ");
+    mISoundTrigger = 0;
+    if (mCallback != 0) {
+        mCallback->onServiceDied();
+    }
+}
+
+status_t SoundTrigger::stringToGuid(const char *str, sound_trigger_uuid_t *guid)
+{
+    if (str == NULL || guid == NULL) {
+        return BAD_VALUE;
+    }
+
+    int tmp[10];
+
+    if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+            tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) {
+        return BAD_VALUE;
+    }
+    guid->timeLow = (uint32_t)tmp[0];
+    guid->timeMid = (uint16_t)tmp[1];
+    guid->timeHiAndVersion = (uint16_t)tmp[2];
+    guid->clockSeq = (uint16_t)tmp[3];
+    guid->node[0] = (uint8_t)tmp[4];
+    guid->node[1] = (uint8_t)tmp[5];
+    guid->node[2] = (uint8_t)tmp[6];
+    guid->node[3] = (uint8_t)tmp[7];
+    guid->node[4] = (uint8_t)tmp[8];
+    guid->node[5] = (uint8_t)tmp[9];
+
+    return NO_ERROR;
+}
+
+status_t SoundTrigger::guidToString(const sound_trigger_uuid_t *guid, char *str, size_t maxLen)
+{
+    if (guid == NULL || str == NULL) {
+        return BAD_VALUE;
+    }
+
+    snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+            guid->timeLow,
+            guid->timeMid,
+            guid->timeHiAndVersion,
+            guid->clockSeq,
+            guid->node[0],
+            guid->node[1],
+            guid->node[2],
+            guid->node[3],
+            guid->node[4],
+            guid->node[5]);
+
+    return NO_ERROR;
+}
+
+}; // namespace android