resolved conflicts for merge of b52c152d to master

Change-Id: I34869bda071d511c9595ea0a5ff6571eb34da059
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/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h
index 2f000d7..c07f4c9 100644
--- a/include/ndk/NdkMediaCodec.h
+++ b/include/ndk/NdkMediaCodec.h
@@ -163,17 +163,6 @@
 media_status_t AMediaCodec_releaseOutputBufferAtTime(
         AMediaCodec *mData, size_t idx, int64_t timestampNs);
 
-typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
-
-/**
- * Set a callback to be called when a new buffer is available, or there was a format
- * or buffer change.
- * Note that you cannot perform any operations on the mediacodec from within the callback.
- * If you need to perform mediacodec operations, you must do so on a different thread.
- */
-media_status_t AMediaCodec_setNotificationCallback(
-        AMediaCodec*, OnCodecEvent callback, void *userdata);
-
 
 typedef enum {
     AMEDIACODECRYPTOINFO_MODE_CLEAR = 0,
diff --git a/include/ndk/NdkMediaExtractor.h b/include/ndk/NdkMediaExtractor.h
index 5a319d7..7a4e702 100644
--- a/include/ndk/NdkMediaExtractor.h
+++ b/include/ndk/NdkMediaExtractor.h
@@ -106,7 +106,7 @@
  * Returns the current sample's presentation time in microseconds.
  * or -1 if no more samples are available.
  */
-int64_t AMediaExtractor_getSampletime(AMediaExtractor*);
+int64_t AMediaExtractor_getSampleTime(AMediaExtractor*);
 
 /**
  * Advance to the next sample. Returns false if no more sample data
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/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 1c808d0..db61e85 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -203,23 +203,6 @@
         mFrameSize = sizeof(uint8_t);
     }
 
-    // validate framecount
-    size_t minFrameCount;
-    status_t status = AudioRecord::getMinFrameCount(&minFrameCount,
-            sampleRate, format, channelMask);
-    if (status != NO_ERROR) {
-        ALOGE("getMinFrameCount() failed for sampleRate %u, format %#x, channelMask %#x; status %d",
-                sampleRate, format, channelMask, status);
-        return status;
-    }
-    ALOGV("AudioRecord::set() minFrameCount = %d", minFrameCount);
-
-    if (frameCount == 0) {
-        frameCount = minFrameCount;
-    } else if (frameCount < minFrameCount) {
-        ALOGE("frameCount %u < minFrameCount %u", frameCount, minFrameCount);
-        return BAD_VALUE;
-    }
     // mFrameCount is initialized in openRecord_l
     mReqFrameCount = frameCount;
 
@@ -242,7 +225,7 @@
     }
 
     // create the IAudioRecord
-    status = openRecord_l(0 /*epoch*/);
+    status_t status = openRecord_l(0 /*epoch*/);
 
     if (status != NO_ERROR) {
         if (mAudioRecordThread != 0) {
@@ -464,6 +447,29 @@
     size_t frameCount = mReqFrameCount;
 
     if (!(mFlags & AUDIO_INPUT_FLAG_FAST)) {
+        // validate framecount
+        // If fast track was not requested, this preserves
+        // the old behavior of validating on client side.
+        // FIXME Eventually the validation should be done on server side
+        // regardless of whether it's a fast or normal track.  It's debatable
+        // whether to account for the input latency to provision buffers appropriately.
+        size_t minFrameCount;
+        status = AudioRecord::getMinFrameCount(&minFrameCount,
+                mSampleRate, mFormat, mChannelMask);
+        if (status != NO_ERROR) {
+            ALOGE("getMinFrameCount() failed for sampleRate %u, format %#x, channelMask %#x; "
+                    "status %d",
+                    mSampleRate, mFormat, mChannelMask, status);
+            return status;
+        }
+
+        if (frameCount == 0) {
+            frameCount = minFrameCount;
+        } else if (frameCount < minFrameCount) {
+            ALOGE("frameCount %u < minFrameCount %u", frameCount, minFrameCount);
+            return BAD_VALUE;
+        }
+
         // Make sure that application is notified with sufficient margin before overrun
         if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/2) {
             mNotificationFramesAct = frameCount/2;
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/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/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..a0e3265 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,67 @@
         // but only if initialization has already happened.
         if (mInputBufferCount != 0) {
             mInputBufferCount = 1;
-            mStreamInfo->sampleRate = 0;
         }
+    } 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/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index bd2541f..2ac16c7 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -61,6 +61,8 @@
     virtual void onMessageReceived(const sp<AMessage> &msg);
 };
 
+typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
+
 struct AMediaCodec {
     sp<android::MediaCodec> mCodec;
     sp<ALooper> mLooper;
@@ -347,7 +349,7 @@
     return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs));
 }
 
-EXPORT
+//EXPORT
 media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) {
     mData->mCallback = callback;
     mData->mCallbackUserData = userdata;
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index b0a9590..f9f9ac3 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -205,7 +205,7 @@
 }
 
 EXPORT
-int64_t AMediaExtractor_getSampletime(AMediaExtractor *mData) {
+int64_t AMediaExtractor_getSampleTime(AMediaExtractor *mData) {
     int64_t time;
     if (mData->mImpl->getSampleTime(&time) != OK) {
         return -1;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 457ac3d..5b09d54 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -430,7 +430,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);
             }
@@ -2606,7 +2606,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];
@@ -2660,11 +2660,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/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 805eaa4..ace3bf1 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -34,6 +34,7 @@
 #include <system/audio.h>
 
 #include <audio_utils/primitives.h>
+#include <audio_utils/format.h>
 #include <common_time/local_clock.h>
 #include <common_time/cc_helper.h>
 
@@ -88,6 +89,103 @@
     }
 }
 
+template <typename T>
+T min(const T& a, const T& b)
+{
+    return a < b ? a : b;
+}
+
+AudioMixer::ReformatBufferProvider::ReformatBufferProvider(int32_t channels,
+        audio_format_t inputFormat, audio_format_t outputFormat) :
+        mTrackBufferProvider(NULL),
+        mChannels(channels),
+        mInputFormat(inputFormat),
+        mOutputFormat(outputFormat),
+        mInputFrameSize(channels * audio_bytes_per_sample(inputFormat)),
+        mOutputFrameSize(channels * audio_bytes_per_sample(outputFormat)),
+        mOutputData(NULL),
+        mOutputCount(0),
+        mConsumed(0)
+{
+    ALOGV("ReformatBufferProvider(%p)(%d, %#x, %#x)", this, channels, inputFormat, outputFormat);
+    if (requiresInternalBuffers()) {
+        mOutputCount = 256;
+        (void)posix_memalign(&mOutputData, 32, mOutputCount * mOutputFrameSize);
+    }
+    mBuffer.frameCount = 0;
+}
+
+AudioMixer::ReformatBufferProvider::~ReformatBufferProvider()
+{
+    ALOGV("~ReformatBufferProvider(%p)", this);
+    if (mBuffer.frameCount != 0) {
+        mTrackBufferProvider->releaseBuffer(&mBuffer);
+    }
+    free(mOutputData);
+}
+
+status_t AudioMixer::ReformatBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer,
+        int64_t pts) {
+    //ALOGV("ReformatBufferProvider(%p)::getNextBuffer(%p (%zu), %lld)",
+    //        this, pBuffer, pBuffer->frameCount, pts);
+    if (!requiresInternalBuffers()) {
+        status_t res = mTrackBufferProvider->getNextBuffer(pBuffer, pts);
+        if (res == OK) {
+            memcpy_by_audio_format(pBuffer->raw, mOutputFormat, pBuffer->raw, mInputFormat,
+                    pBuffer->frameCount * mChannels);
+        }
+        return res;
+    }
+    if (mBuffer.frameCount == 0) {
+        mBuffer.frameCount = pBuffer->frameCount;
+        status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts);
+        // TODO: Track down a bug in the upstream provider
+        // LOG_ALWAYS_FATAL_IF(res == OK && mBuffer.frameCount == 0,
+        //        "ReformatBufferProvider::getNextBuffer():"
+        //        " Invalid zero framecount returned from getNextBuffer()");
+        if (res != OK || mBuffer.frameCount == 0) {
+            pBuffer->raw = NULL;
+            pBuffer->frameCount = 0;
+            return res;
+        }
+    }
+    ALOG_ASSERT(mConsumed < mBuffer.frameCount);
+    size_t count = min(mOutputCount, mBuffer.frameCount - mConsumed);
+    count = min(count, pBuffer->frameCount);
+    pBuffer->raw = mOutputData;
+    pBuffer->frameCount = count;
+    //ALOGV("reformatting %d frames from %#x to %#x, %d chan",
+    //        pBuffer->frameCount, mInputFormat, mOutputFormat, mChannels);
+    memcpy_by_audio_format(pBuffer->raw, mOutputFormat,
+            (uint8_t*)mBuffer.raw + mConsumed * mInputFrameSize, mInputFormat,
+            pBuffer->frameCount * mChannels);
+    return OK;
+}
+
+void AudioMixer::ReformatBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) {
+    //ALOGV("ReformatBufferProvider(%p)::releaseBuffer(%p(%zu))",
+    //        this, pBuffer, pBuffer->frameCount);
+    if (!requiresInternalBuffers()) {
+        mTrackBufferProvider->releaseBuffer(pBuffer);
+        return;
+    }
+    // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
+    mConsumed += pBuffer->frameCount; // TODO: update for efficiency to reuse existing content
+    if (mConsumed != 0 && mConsumed >= mBuffer.frameCount) {
+        mConsumed = 0;
+        mTrackBufferProvider->releaseBuffer(&mBuffer);
+        // ALOG_ASSERT(mBuffer.frameCount == 0);
+    }
+    pBuffer->raw = NULL;
+    pBuffer->frameCount = 0;
+}
+
+void AudioMixer::ReformatBufferProvider::reset() {
+    if (mBuffer.frameCount != 0) {
+        mTrackBufferProvider->releaseBuffer(&mBuffer);
+    }
+    mConsumed = 0;
+}
 
 // ----------------------------------------------------------------------------
 bool AudioMixer::sIsMultichannelCapable = false;
@@ -153,8 +251,13 @@
     mState.mLog = log;
 }
 
-int AudioMixer::getTrackName(audio_channel_mask_t channelMask, int sessionId)
+int AudioMixer::getTrackName(audio_channel_mask_t channelMask,
+        audio_format_t format, int sessionId)
 {
+    if (!isValidPcmTrackFormat(format)) {
+        ALOGE("AudioMixer::getTrackName invalid format (%#x)", format);
+        return -1;
+    }
     uint32_t names = (~mTrackNames) & mConfiguredNames;
     if (names != 0) {
         int n = __builtin_ctz(names);
@@ -176,7 +279,8 @@
         // t->frameCount
         t->channelCount = audio_channel_count_from_out_mask(channelMask);
         t->enabled = false;
-        t->format = 16;
+        ALOGV_IF(channelMask != AUDIO_CHANNEL_OUT_STEREO,
+                "Non-stereo channel mask: %d\n", channelMask);
         t->channelMask = channelMask;
         t->sessionId = sessionId;
         // setBufferProvider(name, AudioBufferProvider *) is required before enable(name)
@@ -191,9 +295,15 @@
         // setParameter(name, TRACK, MAIN_BUFFER, mixBuffer) is required before enable(name)
         t->mainBuffer = NULL;
         t->auxBuffer = NULL;
+        t->mInputBufferProvider = NULL;
+        t->mReformatBufferProvider = NULL;
         t->downmixerBufferProvider = NULL;
         t->mMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
-
+        t->mFormat = format;
+        t->mMixerInFormat = AUDIO_FORMAT_PCM_16_BIT;
+        if (t->mFormat != t->mMixerInFormat) {
+            prepareTrackForReformat(t, n);
+        }
         status_t status = initTrackDownmix(&mState.tracks[n], n, channelMask);
         if (status != OK) {
             ALOGE("AudioMixer::getTrackName invalid channelMask (%#x)", channelMask);
@@ -237,9 +347,9 @@
     if (pTrack->downmixerBufferProvider != NULL) {
         // this track had previously been configured with a downmixer, delete it
         ALOGV(" deleting old downmixer");
-        pTrack->bufferProvider = pTrack->downmixerBufferProvider->mTrackBufferProvider;
         delete pTrack->downmixerBufferProvider;
         pTrack->downmixerBufferProvider = NULL;
+        reconfigureBufferProviders(pTrack);
     } else {
         ALOGV(" nothing to do, no downmixer to delete");
     }
@@ -333,21 +443,51 @@
     }// end of scope for local variables that are not used in goto label "noDownmixForActiveTrack"
 
     // initialization successful:
-    // - keep track of the real buffer provider in case it was set before
-    pDbp->mTrackBufferProvider = pTrack->bufferProvider;
-    // - we'll use the downmix effect integrated inside this
-    //    track's buffer provider, and we'll use it as the track's buffer provider
     pTrack->downmixerBufferProvider = pDbp;
-    pTrack->bufferProvider = pDbp;
-
+    reconfigureBufferProviders(pTrack);
     return NO_ERROR;
 
 noDownmixForActiveTrack:
     delete pDbp;
     pTrack->downmixerBufferProvider = NULL;
+    reconfigureBufferProviders(pTrack);
     return NO_INIT;
 }
 
+void AudioMixer::unprepareTrackForReformat(track_t* pTrack, int trackName __unused) {
+    ALOGV("AudioMixer::unprepareTrackForReformat(%d)", trackName);
+    if (pTrack->mReformatBufferProvider != NULL) {
+        delete pTrack->mReformatBufferProvider;
+        pTrack->mReformatBufferProvider = NULL;
+        reconfigureBufferProviders(pTrack);
+    }
+}
+
+status_t AudioMixer::prepareTrackForReformat(track_t* pTrack, int trackName)
+{
+    ALOGV("AudioMixer::prepareTrackForReformat(%d) with format %#x", trackName, pTrack->mFormat);
+    // discard the previous reformatter if there was one
+     unprepareTrackForReformat(pTrack, trackName);
+     pTrack->mReformatBufferProvider = new ReformatBufferProvider(
+             audio_channel_count_from_out_mask(pTrack->channelMask),
+             pTrack->mFormat, pTrack->mMixerInFormat);
+     reconfigureBufferProviders(pTrack);
+     return NO_ERROR;
+}
+
+void AudioMixer::reconfigureBufferProviders(track_t* pTrack)
+{
+    pTrack->bufferProvider = pTrack->mInputBufferProvider;
+    if (pTrack->mReformatBufferProvider) {
+        pTrack->mReformatBufferProvider->mTrackBufferProvider = pTrack->bufferProvider;
+        pTrack->bufferProvider = pTrack->mReformatBufferProvider;
+    }
+    if (pTrack->downmixerBufferProvider) {
+        pTrack->downmixerBufferProvider->mTrackBufferProvider = pTrack->bufferProvider;
+        pTrack->bufferProvider = pTrack->downmixerBufferProvider;
+    }
+}
+
 void AudioMixer::deleteTrackName(int name)
 {
     ALOGV("AudioMixer::deleteTrackName(%d)", name);
@@ -364,6 +504,8 @@
     track.resampler = NULL;
     // delete the downmixer
     unprepareTrackForDownmix(&mState.tracks[name], name);
+    // delete the reformatter
+    unprepareTrackForReformat(&mState.tracks[name], name);
 
     mTrackNames &= ~(1<<name);
 }
@@ -435,9 +577,20 @@
                 invalidateState(1 << name);
             }
             break;
-        case FORMAT:
-            ALOG_ASSERT(valueInt == AUDIO_FORMAT_PCM_16_BIT);
-            break;
+        case FORMAT: {
+            audio_format_t format = static_cast<audio_format_t>(valueInt);
+            if (track.mFormat != format) {
+                ALOG_ASSERT(audio_is_linear_pcm(format), "Invalid format %#x", format);
+                track.mFormat = format;
+                ALOGV("setParameter(TRACK, FORMAT, %#x)", format);
+                //if (track.mFormat != track.mMixerInFormat)
+                {
+                    ALOGD("Reformatting!");
+                    prepareTrackForReformat(&track, name);
+                }
+                invalidateState(1 << name);
+            }
+            } break;
         // FIXME do we want to support setting the downmix type from AudioFlinger?
         //         for a specific track? or per mixer?
         /* case DOWNMIX_TYPE:
@@ -550,8 +703,9 @@
                 } else {
                     quality = AudioResampler::DEFAULT_QUALITY;
                 }
+                const int bits = mMixerInFormat == AUDIO_FORMAT_PCM_16_BIT ? 16 : /* FLOAT */ 32;
                 resampler = AudioResampler::create(
-                        format,
+                        bits,
                         // the resampler sees the number of channels after the downmixer, if any
                         (int) (downmixerBufferProvider != NULL ? MAX_NUM_CHANNELS : channelCount),
                         devSampleRate, quality);
@@ -596,21 +750,16 @@
     name -= TRACK0;
     ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name);
 
-    if (mState.tracks[name].downmixerBufferProvider != NULL) {
-        // update required?
-        if (mState.tracks[name].downmixerBufferProvider->mTrackBufferProvider != bufferProvider) {
-            ALOGV("AudioMixer::setBufferProvider(%p) for downmix", bufferProvider);
-            // setting the buffer provider for a track that gets downmixed consists in:
-            //  1/ setting the buffer provider to the "downmix / buffer provider" wrapper
-            //     so it's the one that gets called when the buffer provider is needed,
-            mState.tracks[name].bufferProvider = mState.tracks[name].downmixerBufferProvider;
-            //  2/ saving the buffer provider for the track so the wrapper can use it
-            //     when it downmixes.
-            mState.tracks[name].downmixerBufferProvider->mTrackBufferProvider = bufferProvider;
-        }
-    } else {
-        mState.tracks[name].bufferProvider = bufferProvider;
+    if (mState.tracks[name].mInputBufferProvider == bufferProvider) {
+        return; // don't reset any buffer providers if identical.
     }
+    if (mState.tracks[name].mReformatBufferProvider != NULL) {
+        mState.tracks[name].mReformatBufferProvider->reset();
+    } else if (mState.tracks[name].downmixerBufferProvider != NULL) {
+    }
+
+    mState.tracks[name].mInputBufferProvider = bufferProvider;
+    reconfigureBufferProviders(&mState.tracks[name]);
 }
 
 
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 09e63a6..573ba96 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -104,7 +104,10 @@
     // For all APIs with "name": TRACK0 <= name < TRACK0 + MAX_NUM_TRACKS
 
     // Allocate a track name.  Returns new track name if successful, -1 on failure.
-    int         getTrackName(audio_channel_mask_t channelMask, int sessionId);
+    // The failure could be because of an invalid channelMask or format, or that
+    // the track capacity of the mixer is exceeded.
+    int         getTrackName(audio_channel_mask_t channelMask,
+                             audio_format_t format, int sessionId);
 
     // Free an allocated track by name
     void        deleteTrackName(int name);
@@ -122,6 +125,13 @@
 
     size_t      getUnreleasedFrames(int name) const;
 
+    static inline bool isValidPcmTrackFormat(audio_format_t format) {
+        return format == AUDIO_FORMAT_PCM_16_BIT ||
+                format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
+                format == AUDIO_FORMAT_PCM_32_BIT ||
+                format == AUDIO_FORMAT_PCM_FLOAT;
+    }
+
 private:
 
     enum {
@@ -143,6 +153,7 @@
     struct state_t;
     struct track_t;
     class DownmixerBufferProvider;
+    class ReformatBufferProvider;
 
     typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp,
                            int32_t* aux);
@@ -170,7 +181,7 @@
         uint16_t    frameCount;
 
         uint8_t     channelCount;   // 1 or 2, redundant with (needs & NEEDS_CHANNEL_COUNT__MASK)
-        uint8_t     format;         // always 16
+        uint8_t     unused_padding; // formerly format, was always 16
         uint16_t    enabled;        // actually bool
         audio_channel_mask_t channelMask;
 
@@ -193,14 +204,19 @@
         int32_t*           auxBuffer;
 
         // 16-byte boundary
-
+        AudioBufferProvider*     mInputBufferProvider;    // 4 bytes
+        ReformatBufferProvider*  mReformatBufferProvider; // 4 bytes
         DownmixerBufferProvider* downmixerBufferProvider; // 4 bytes
 
         int32_t     sessionId;
 
-        audio_format_t mMixerFormat; // at this time: AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
+        // 16-byte boundary
+        audio_format_t mMixerFormat;     // output mix format: AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
+        audio_format_t mFormat;          // input track format
+        audio_format_t mMixerInFormat;   // mix internal format AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
+                                         // each track must be converted to this format.
 
-        int32_t     padding[1];
+        int32_t        mUnused[1];       // alignment padding
 
         // 16-byte boundary
 
@@ -239,6 +255,35 @@
         effect_config_t    mDownmixConfig;
     };
 
+    // AudioBufferProvider wrapper that reformats track to acceptable mixer input type
+    class ReformatBufferProvider : public AudioBufferProvider {
+    public:
+        ReformatBufferProvider(int32_t channels,
+                audio_format_t inputFormat, audio_format_t outputFormat);
+        virtual ~ReformatBufferProvider();
+
+        // overrides AudioBufferProvider methods
+        virtual status_t getNextBuffer(Buffer* buffer, int64_t pts);
+        virtual void releaseBuffer(Buffer* buffer);
+
+        void reset();
+        inline bool requiresInternalBuffers() {
+            return true; //mInputFrameSize < mOutputFrameSize;
+        }
+
+        AudioBufferProvider* mTrackBufferProvider;
+        int32_t              mChannels;
+        audio_format_t       mInputFormat;
+        audio_format_t       mOutputFormat;
+        size_t               mInputFrameSize;
+        size_t               mOutputFrameSize;
+        // (only) required for reformatting to a larger size.
+        AudioBufferProvider::Buffer mBuffer;
+        void*                mOutputData;
+        size_t               mOutputCount;
+        size_t               mConsumed;
+    };
+
     // bitmask of allocated track names, where bit 0 corresponds to TRACK0 etc.
     uint32_t        mTrackNames;
 
@@ -266,6 +311,9 @@
     static status_t initTrackDownmix(track_t* pTrack, int trackNum, audio_channel_mask_t mask);
     static status_t prepareTrackForDownmix(track_t* pTrack, int trackNum);
     static void unprepareTrackForDownmix(track_t* pTrack, int trackName);
+    static status_t prepareTrackForReformat(track_t* pTrack, int trackNum);
+    static void unprepareTrackForReformat(track_t* pTrack, int trackName);
+    static void reconfigureBufferProviders(track_t* pTrack);
 
     static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp,
             int32_t* aux);
diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/services/audioflinger/AudioResamplerDyn.cpp
index 3abe8fd..a4446a4 100644
--- a/services/audioflinger/AudioResamplerDyn.cpp
+++ b/services/audioflinger/AudioResamplerDyn.cpp
@@ -455,12 +455,13 @@
     const Constants& c(mConstants);
     const TC* const coefs = mConstants.mFirCoefs;
     TI* impulse = mInBuffer.getImpulse();
-    size_t inputIndex = mInputIndex;
+    size_t inputIndex = 0;
     uint32_t phaseFraction = mPhaseFraction;
     const uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;   // stereo output
-    size_t inFrameCount = getInFrameCountRequired(outFrameCount);
+    size_t inFrameCount = getInFrameCountRequired(outFrameCount) + (phaseFraction != 0);
+    ALOG_ASSERT(0 < inFrameCount && inFrameCount < (1U << 31));
     const uint32_t phaseWrapLimit = c.mL << c.mShift;
 
     // NOTE: be very careful when modifying the code here. register
@@ -474,11 +475,13 @@
         // buffer is empty, fetch a new one
         while (mBuffer.frameCount == 0) {
             mBuffer.frameCount = inFrameCount;
+            ALOG_ASSERT(inFrameCount > 0);
             provider->getNextBuffer(&mBuffer,
                     calculateOutputPTS(outputIndex / 2));
             if (mBuffer.raw == NULL) {
                 goto resample_exit;
             }
+            inFrameCount -= mBuffer.frameCount;
             if (phaseFraction >= phaseWrapLimit) { // read in data
                 mInBuffer.template readAdvance<CHANNELS>(
                         impulse, c.mHalfNumCoefs,
@@ -487,7 +490,7 @@
                 while (phaseFraction >= phaseWrapLimit) {
                     inputIndex++;
                     if (inputIndex >= mBuffer.frameCount) {
-                        inputIndex -= mBuffer.frameCount;
+                        inputIndex = 0;
                         provider->releaseBuffer(&mBuffer);
                         break;
                     }
@@ -535,15 +538,22 @@
 done:
         // often arrives here when input buffer runs out
         if (inputIndex >= frameCount) {
-            inputIndex -= frameCount;
+            inputIndex = 0;
             provider->releaseBuffer(&mBuffer);
-            // mBuffer.frameCount MUST be zero here.
+            ALOG_ASSERT(mBuffer.frameCount == 0);
         }
     }
 
 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);
+    }
     mInBuffer.setImpulse(impulse);
-    mInputIndex = inputIndex;
     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 1caed11..13b21ec 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>
@@ -37,6 +36,7 @@
 #include <cpustats/ThreadCpuUsage.h>
 #endif
 #endif
+#include <audio_utils/format.h>
 #include "AudioMixer.h"
 #include "FastMixer.h"
 
@@ -53,8 +53,12 @@
     outputSink(NULL),
     outputSinkGen(0),
     mixer(NULL),
-    mixBuffer(NULL),
-    mixBufferState(UNDEFINED),
+    mSinkBuffer(NULL),
+    mSinkBufferSize(0),
+    mMixerBuffer(NULL),
+    mMixerBufferSize(0),
+    mMixerBufferFormat(AUDIO_FORMAT_PCM_16_BIT),
+    mMixerBufferState(UNDEFINED),
     format(Format_Invalid),
     sampleRate(0),
     fastTracksGen(0),
@@ -109,7 +113,8 @@
 void FastMixer::onExit()
 {
     delete mixer;
-    delete[] mixBuffer;
+    free(mMixerBuffer);
+    free(mSinkBuffer);
 }
 
 bool FastMixer::isSubClassCommand(FastThreadState::Command command)
@@ -155,14 +160,23 @@
         // FIXME to avoid priority inversion, don't delete here
         delete mixer;
         mixer = NULL;
-        delete[] mixBuffer;
-        mixBuffer = NULL;
+        free(mMixerBuffer);
+        mMixerBuffer = NULL;
+        free(mSinkBuffer);
+        mSinkBuffer = NULL;
         if (frameCount > 0 && sampleRate > 0) {
             // FIXME new may block for unbounded time at internal mutex of the heap
             //       implementation; it would be better to have normal mixer allocate for us
             //       to avoid blocking here and to prevent possible priority inversion
             mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks);
-            mixBuffer = new short[frameCount * FCC_2];
+            const size_t mixerFrameSize = FCC_2 * audio_bytes_per_sample(mMixerBufferFormat);
+            mMixerBufferSize = mixerFrameSize * frameCount;
+            (void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize);
+            const size_t sinkFrameSize = FCC_2 * audio_bytes_per_sample(format.mFormat);
+            if (sinkFrameSize > mixerFrameSize) { // need a sink buffer
+                mSinkBufferSize = sinkFrameSize * frameCount;
+                (void)posix_memalign(&mSinkBuffer, 32, mSinkBufferSize);
+            }
             periodNs = (frameCount * 1000000000LL) / sampleRate;    // 1.00
             underrunNs = (frameCount * 1750000000LL) / sampleRate;  // 1.75
             overrunNs = (frameCount * 500000000LL) / sampleRate;    // 0.50
@@ -175,7 +189,7 @@
             forceNs = 0;
             warmupNs = 0;
         }
-        mixBufferState = UNDEFINED;
+        mMixerBufferState = UNDEFINED;
 #if !LOG_NDEBUG
         for (unsigned i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
             fastTrackNames[i] = -1;
@@ -193,7 +207,7 @@
     const unsigned currentTrackMask = current->mTrackMask;
     dumpState->mTrackMask = currentTrackMask;
     if (current->mFastTracksGen != fastTracksGen) {
-        ALOG_ASSERT(mixBuffer != NULL);
+        ALOG_ASSERT(mMixerBuffer != NULL);
         int name;
 
         // process removed tracks first to avoid running out of track names
@@ -224,13 +238,20 @@
             AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
             ALOG_ASSERT(bufferProvider != NULL && fastTrackNames[i] == -1);
             if (mixer != NULL) {
-                name = mixer->getTrackName(fastTrack->mChannelMask, AUDIO_SESSION_OUTPUT_MIX);
+                name = mixer->getTrackName(fastTrack->mChannelMask,
+                        fastTrack->mFormat, AUDIO_SESSION_OUTPUT_MIX);
                 ALOG_ASSERT(name >= 0);
                 fastTrackNames[i] = name;
                 mixer->setBufferProvider(name, bufferProvider);
                 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
-                        (void *) mixBuffer);
+                        (void *) mMixerBuffer);
                 // newly allocated track names default to full scale volume
+                mixer->setParameter(
+                        name,
+                        AudioMixer::TRACK,
+                        AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat);
+                mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
+                        (void *)(uintptr_t)fastTrack->mFormat);
                 mixer->enable(name);
             }
             generations[i] = fastTrack->mGeneration;
@@ -259,6 +280,12 @@
                     }
                     mixer->setParameter(name, AudioMixer::RESAMPLE,
                             AudioMixer::REMOVE, NULL);
+                    mixer->setParameter(
+                            name,
+                            AudioMixer::TRACK,
+                            AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat);
+                    mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
+                            (void *)(uintptr_t)fastTrack->mFormat);
                     mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
                             (void *)(uintptr_t) fastTrack->mChannelMask);
                     // already enabled
@@ -281,7 +308,7 @@
     const size_t frameCount = current->mFrameCount;
 
     if ((command & FastMixerState::MIX) && (mixer != NULL) && isWarm) {
-        ALOG_ASSERT(mixBuffer != NULL);
+        ALOG_ASSERT(mMixerBuffer != NULL);
         // for each track, update volume and check for underrun
         unsigned currentTrackMask = current->mTrackMask;
         while (currentTrackMask != 0) {
@@ -358,26 +385,31 @@
 
         // process() is CPU-bound
         mixer->process(pts);
-        mixBufferState = MIXED;
-    } else if (mixBufferState == MIXED) {
-        mixBufferState = UNDEFINED;
+        mMixerBufferState = MIXED;
+    } else if (mMixerBufferState == MIXED) {
+        mMixerBufferState = UNDEFINED;
     }
     //bool didFullWrite = false;    // dumpsys could display a count of partial writes
-    if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mixBuffer != NULL)) {
-        if (mixBufferState == UNDEFINED) {
-            memset(mixBuffer, 0, frameCount * FCC_2 * sizeof(short));
-            mixBufferState = ZEROED;
+    if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mMixerBuffer != NULL)) {
+        if (mMixerBufferState == UNDEFINED) {
+            memset(mMixerBuffer, 0, mMixerBufferSize);
+            mMixerBufferState = ZEROED;
+        }
+        void *buffer = mSinkBuffer != NULL ? mSinkBuffer : mMixerBuffer;
+        if (format.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format
+            memcpy_by_audio_format(buffer, format.mFormat, mMixerBuffer, mMixerBufferFormat,
+                    frameCount * Format_channelCount(format));
         }
         // if non-NULL, then duplicate write() to this non-blocking sink
         NBAIO_Sink* teeSink;
         if ((teeSink = current->mTeeSink) != NULL) {
-            (void) teeSink->write(mixBuffer, frameCount);
+            (void) teeSink->write(mMixerBuffer, frameCount);
         }
         // FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink,
         //       but this code should be modified to handle both non-blocking and blocking sinks
         dumpState->mWriteSequence++;
         ATRACE_BEGIN("write");
-        ssize_t framesWritten = outputSink->write(mixBuffer, frameCount);
+        ssize_t framesWritten = outputSink->write(buffer, frameCount);
         ATRACE_END();
         dumpState->mWriteSequence++;
         if (framesWritten >= 0) {
@@ -461,7 +493,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
@@ -495,10 +527,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,
@@ -550,26 +582,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);
@@ -580,12 +612,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
@@ -595,9 +627,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];
@@ -617,7 +649,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/FastMixer.h b/services/audioflinger/FastMixer.h
index db89ef4..4671670 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -61,8 +61,16 @@
     NBAIO_Sink *outputSink;
     int outputSinkGen;
     AudioMixer* mixer;
-    short *mixBuffer;
-    enum {UNDEFINED, MIXED, ZEROED} mixBufferState;
+
+    // mSinkBuffer audio format is stored in format.mFormat.
+    void* mSinkBuffer;                  // used for mixer output format translation
+                                        // if sink format is different than mixer output.
+    size_t mSinkBufferSize;
+    void* mMixerBuffer;                 // mixer output buffer.
+    size_t mMixerBufferSize;
+    audio_format_t mMixerBufferFormat;  // mixer output format: AUDIO_FORMAT_PCM_(16_BIT|FLOAT).
+
+    enum {UNDEFINED, MIXED, ZEROED} mMixerBufferState;
     NBAIO_Format format;
     unsigned sampleRate;
     int fastTracksGen;
diff --git a/services/audioflinger/FastMixerState.cpp b/services/audioflinger/FastMixerState.cpp
index 8e6d0d4..3aa8dad 100644
--- a/services/audioflinger/FastMixerState.cpp
+++ b/services/audioflinger/FastMixerState.cpp
@@ -20,7 +20,7 @@
 
 FastTrack::FastTrack() :
     mBufferProvider(NULL), mVolumeProvider(NULL),
-    mChannelMask(AUDIO_CHANNEL_OUT_STEREO), mGeneration(0)
+    mChannelMask(AUDIO_CHANNEL_OUT_STEREO), mFormat(AUDIO_FORMAT_INVALID), mGeneration(0)
 {
 }
 
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index e388fb3..661c9ca 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -45,6 +45,7 @@
     ExtendedAudioBufferProvider* mBufferProvider; // must be NULL if inactive, or non-NULL if active
     VolumeProvider*         mVolumeProvider; // optional; if NULL then full-scale
     audio_channel_mask_t    mChannelMask;    // AUDIO_CHANNEL_OUT_MONO or AUDIO_CHANNEL_OUT_STEREO
+    audio_format_t          mFormat;         // track format
     int                     mGeneration;     // increment when any field is assigned
 };
 
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 4972c7a..742163b 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -142,8 +142,17 @@
 // FIXME It would be better for client to tell AudioFlinger the value of N,
 // so AudioFlinger could allocate the right amount of memory.
 // See the client's minBufCount and mNotificationFramesAct calculations for details.
+
+// This is the default value, if not specified by property.
 static const int kFastTrackMultiplier = 2;
 
+// The minimum and maximum allowed values
+static const int kFastTrackMultiplierMin = 1;
+static const int kFastTrackMultiplierMax = 2;
+
+// The actual value to use, which can be specified per-device via property af.fast_track_multiplier.
+static int sFastTrackMultiplier = kFastTrackMultiplier;
+
 // See Thread::readOnlyHeap().
 // Initially this heap is used to allocate client buffers for "fast" AudioRecord.
 // Eventually it will be the single buffer that FastCapture writes into via HAL read(),
@@ -152,6 +161,22 @@
 
 // ----------------------------------------------------------------------------
 
+static pthread_once_t sFastTrackMultiplierOnce = PTHREAD_ONCE_INIT;
+
+static void sFastTrackMultiplierInit()
+{
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("af.fast_track_multiplier", value, NULL) > 0) {
+        char *endptr;
+        unsigned long ul = strtoul(value, &endptr, 0);
+        if (*endptr == '\0' && kFastTrackMultiplierMin <= ul && ul <= kFastTrackMultiplierMax) {
+            sFastTrackMultiplier = (int) ul;
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+
 #ifdef ADD_BATTERY_DATA
 // To collect the amplifier usage
 static void addBatteryData(uint32_t params) {
@@ -539,30 +564,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) {
@@ -1225,15 +1250,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];
@@ -1265,22 +1290,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);
 }
@@ -1356,7 +1380,12 @@
         ) {
         // if frameCount not specified, then it defaults to fast mixer (HAL) frame count
         if (frameCount == 0) {
-            frameCount = mFrameCount * kFastTrackMultiplier;
+            // read the fast track multiplier property the first time it is needed
+            int ok = pthread_once(&sFastTrackMultiplierOnce, sFastTrackMultiplierInit);
+            if (ok != 0) {
+                ALOGE("%s pthread_once failed: %d", __func__, ok);
+            }
+            frameCount = mFrameCount * sFastTrackMultiplier;
         }
         ALOGV("AUDIO_OUTPUT_FLAG_FAST accepted: frameCount=%d mFrameCount=%d",
                 frameCount, mFrameCount);
@@ -2715,9 +2744,27 @@
         break;
     }
     if (initFastMixer) {
+        audio_format_t fastMixerFormat;
+        if (mMixerBufferEnabled && mEffectBufferEnabled) {
+            fastMixerFormat = AUDIO_FORMAT_PCM_FLOAT;
+        } else {
+            fastMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
+        }
+        if (mFormat != fastMixerFormat) {
+            // change our Sink format to accept our intermediate precision
+            mFormat = fastMixerFormat;
+            free(mSinkBuffer);
+            mFrameSize = mChannelCount * audio_bytes_per_sample(mFormat);
+            const size_t sinkBufferSize = mNormalFrameCount * mFrameSize;
+            (void)posix_memalign(&mSinkBuffer, 32, sinkBufferSize);
+        }
 
         // create a MonoPipe to connect our submix to FastMixer
         NBAIO_Format format = mOutputSink->format();
+        // adjust format to match that of the Fast Mixer
+        format.mFormat = fastMixerFormat;
+        format.mFrameSize = audio_bytes_per_sample(format.mFormat) * format.mChannelCount;
+
         // This pipe depth compensates for scheduling latency of the normal mixer thread.
         // When it wakes up after a maximum latency, it runs a few cycles quickly before
         // finally blocking.  Note the pipe implementation rounds up the request to a power of 2.
@@ -2758,6 +2805,8 @@
         // wrap the source side of the MonoPipe to make it an AudioBufferProvider
         fastTrack->mBufferProvider = new SourceAudioBufferProvider(new MonoPipeReader(monoPipe));
         fastTrack->mVolumeProvider = NULL;
+        fastTrack->mChannelMask = mChannelMask; // mPipeSink channel mask for audio to FastMixer
+        fastTrack->mFormat = mFormat; // mPipeSink format for audio to FastMixer
         fastTrack->mGeneration++;
         state->mFastTracksGen++;
         state->mTrackMask = 1;
@@ -3210,6 +3259,7 @@
                     fastTrack->mBufferProvider = eabp;
                     fastTrack->mVolumeProvider = vp;
                     fastTrack->mChannelMask = track->mChannelMask;
+                    fastTrack->mFormat = track->mFormat;
                     fastTrack->mGeneration++;
                     state->mTrackMask |= 1 << j;
                     didModify = true;
@@ -3601,9 +3651,10 @@
 }
 
 // getTrackName_l() must be called with ThreadBase::mLock held
-int AudioFlinger::MixerThread::getTrackName_l(audio_channel_mask_t channelMask, int sessionId)
+int AudioFlinger::MixerThread::getTrackName_l(audio_channel_mask_t channelMask,
+        audio_format_t format, int sessionId)
 {
-    return mAudioMixer->getTrackName(channelMask, sessionId);
+    return mAudioMixer->getTrackName(channelMask, format, sessionId);
 }
 
 // deleteTrackName_l() must be called with ThreadBase::mLock held
@@ -3716,7 +3767,8 @@
             delete mAudioMixer;
             mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
             for (size_t i = 0; i < mTracks.size() ; i++) {
-                int name = getTrackName_l(mTracks[i]->mChannelMask, mTracks[i]->mSessionId);
+                int name = getTrackName_l(mTracks[i]->mChannelMask,
+                        mTracks[i]->mFormat, mTracks[i]->mSessionId);
                 if (name < 0) {
                     break;
                 }
@@ -3748,7 +3800,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);
@@ -4007,7 +4059,7 @@
 
 // getTrackName_l() must be called with ThreadBase::mLock held
 int AudioFlinger::DirectOutputThread::getTrackName_l(audio_channel_mask_t channelMask __unused,
-        int sessionId __unused)
+        audio_format_t format __unused, int sessionId __unused)
 {
     return 0;
 }
@@ -5203,6 +5255,7 @@
         // to be at least 2 x the record thread frame count and cover audio hardware latency.
         // This is probably too conservative, but legacy application code may depend on it.
         // If you change this calculation, also review the start threshold which is related.
+        // FIXME It's not clear how input latency actually matters.  Perhaps this should be 0.
         uint32_t latencyMs = 50; // FIXME mInput->stream->get_latency(mInput->stream);
         size_t mNormalFrameCount = 2048; // FIXME
         uint32_t minBufCount = latencyMs / ((1000 * mNormalFrameCount) / mSampleRate);
@@ -5435,12 +5488,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");
     }
 
     dumpBase(fd, args);
@@ -5455,9 +5508,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];
@@ -5471,7 +5524,7 @@
             }
         }
     } else {
-        fdprintf(fd, "\n");
+        dprintf(fd, "\n");
     }
 
     if (numactiveseen != numactive) {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index f8037c6..8c9943c 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -356,6 +356,8 @@
                 // If a thread does not have such a heap, this method returns 0.
                 virtual sp<MemoryDealer>    readOnlyHeap() const { return 0; }
 
+                virtual sp<IMemory> pipeMemory() const { return 0; }
+
     mutable     Mutex                   mLock;
 
 protected:
@@ -674,7 +676,8 @@
 
     // Allocate a track name for a given channel mask.
     //   Returns name >= 0 if successful, -1 on failure.
-    virtual int             getTrackName_l(audio_channel_mask_t channelMask, int sessionId) = 0;
+    virtual int             getTrackName_l(audio_channel_mask_t channelMask,
+                                           audio_format_t format, int sessionId) = 0;
     virtual void            deleteTrackName_l(int name) = 0;
 
     // Time to sleep between cycles when:
@@ -831,7 +834,8 @@
 
 protected:
     virtual     mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
-    virtual     int         getTrackName_l(audio_channel_mask_t channelMask, int sessionId);
+    virtual     int         getTrackName_l(audio_channel_mask_t channelMask,
+                                           audio_format_t format, int sessionId);
     virtual     void        deleteTrackName_l(int name);
     virtual     uint32_t    idleSleepTimeUs() const;
     virtual     uint32_t    suspendSleepTimeUs() const;
@@ -884,7 +888,8 @@
                                                    status_t& status);
 
 protected:
-    virtual     int         getTrackName_l(audio_channel_mask_t channelMask, int sessionId);
+    virtual     int         getTrackName_l(audio_channel_mask_t channelMask,
+                                           audio_format_t format, int sessionId);
     virtual     void        deleteTrackName_l(int name);
     virtual     uint32_t    activeSleepTimeUs() const;
     virtual     uint32_t    idleSleepTimeUs() const;
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 5f13be3..4cba3fd 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -39,6 +39,13 @@
         STARTING_2,     // for RecordTrack only
     };
 
+    // where to allocate the data buffer
+    enum alloc_type {
+        ALLOC_CBLK,     // allocate immediately after control block
+        ALLOC_READONLY, // allocate from a separate read-only heap per thread
+        ALLOC_PIPE,     // do not allocate; use the pipe buffer
+    };
+
                         TrackBase(ThreadBase *thread,
                                 const sp<Client>& client,
                                 uint32_t sampleRate,
@@ -50,7 +57,7 @@
                                 int uid,
                                 IAudioFlinger::track_flags_t flags,
                                 bool isOut,
-                                bool useReadOnlyHeap = false);
+                                alloc_type alloc = ALLOC_CBLK);
     virtual             ~TrackBase();
     virtual status_t    initCheck() const { return getCblk() != 0 ? NO_ERROR : NO_MEMORY; }
 
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index f698fa2..7ddc71c 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -73,7 +73,7 @@
             int clientUid,
             IAudioFlinger::track_flags_t flags,
             bool isOut,
-            bool useReadOnlyHeap)
+            alloc_type alloc)
     :   RefBase(),
         mThread(thread),
         mClient(client),
@@ -117,7 +117,7 @@
     // ALOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
     size_t size = sizeof(audio_track_cblk_t);
     size_t bufferSize = (sharedBuffer == 0 ? roundup(frameCount) : frameCount) * mFrameSize;
-    if (sharedBuffer == 0 && !useReadOnlyHeap) {
+    if (sharedBuffer == 0 && alloc == ALLOC_CBLK) {
         size += bufferSize;
     }
 
@@ -139,7 +139,8 @@
     // construct the shared structure in-place.
     if (mCblk != NULL) {
         new(mCblk) audio_track_cblk_t();
-        if (useReadOnlyHeap) {
+        switch (alloc) {
+        case ALLOC_READONLY: {
             const sp<MemoryDealer> roHeap(thread->readOnlyHeap());
             if (roHeap == 0 ||
                     (mBufferMemory = roHeap->allocate(bufferSize)) == 0 ||
@@ -153,7 +154,17 @@
                 return;
             }
             memset(mBuffer, 0, bufferSize);
-        } else {
+            } break;
+        case ALLOC_PIPE:
+            mBufferMemory = thread->pipeMemory();
+            // mBuffer is the virtual address as seen from current process (mediaserver),
+            // and should normally be coming from mBufferMemory->pointer().
+            // However in this case the TrackBase does not reference the buffer directly.
+            // It should references the buffer via the pipe.
+            // Therefore, to detect incorrect usage of the buffer, we set mBuffer to NULL.
+            mBuffer = NULL;
+            break;
+        case ALLOC_CBLK:
             // clear all buffers
             if (sharedBuffer == 0) {
                 mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
@@ -164,6 +175,7 @@
                 mCblk->mFlags = CBLK_FORCEREADY;    // FIXME hack, need to fix the track ready logic
 #endif
             }
+            break;
         }
 
 #ifdef TEE_SINK
@@ -385,7 +397,7 @@
     }
     mServerProxy = mAudioTrackServerProxy;
 
-    mName = thread->getTrackName_l(channelMask, sessionId);
+    mName = thread->getTrackName_l(channelMask, format, sessionId);
     if (mName < 0) {
         ALOGE("no more track names available");
         return;
@@ -1842,7 +1854,7 @@
     :   TrackBase(thread, client, sampleRate, format,
                   channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, uid,
                   flags, false /*isOut*/,
-                  (flags & IAudioFlinger::TRACK_FAST) != 0 /*useReadOnlyHeap*/),
+                  (flags & IAudioFlinger::TRACK_FAST) != 0 ? ALLOC_READONLY : ALLOC_CBLK),
         mOverflow(false), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpOutFrameCount(0),
         // See real initialization of mRsmpInFront at RecordThread::start()
         mRsmpInUnrel(0), mRsmpInFront(0), mFramesToDrop(0), mResamplerBufferProvider(NULL)
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index b5b26d3..ee0c987 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[] = {
@@ -279,16 +280,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
@@ -3750,6 +3743,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:
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());
         }