Merge "Fix non-monotonic AudioTrack::getTimestamp after pause" into lmp-preview-dev
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index e862ec3..d38d976 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -53,6 +53,7 @@
     kKeyESDS              = 'esds',  // raw data
     kKeyAACProfile        = 'aacp',  // int32_t
     kKeyAVCC              = 'avcc',  // raw data
+    kKeyHVCC              = 'hvcc',  // raw data
     kKeyD263              = 'd263',  // raw data
     kKeyVorbisInfo        = 'vinf',  // raw data
     kKeyVorbisBooks       = 'vboo',  // raw data
@@ -170,6 +171,7 @@
 enum {
     kTypeESDS        = 'esds',
     kTypeAVCC        = 'avcc',
+    kTypeHVCC        = 'hvcc',
     kTypeD263        = 'd263',
 };
 
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 5121c17..5590b60 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -352,6 +352,9 @@
 
     int64_t getDecodingTimeUs();
 
+    status_t parseHEVCCodecSpecificData(
+            const void *data, size_t size,
+            unsigned *profile, unsigned *level);
     status_t parseAVCCodecSpecificData(
             const void *data, size_t size,
             unsigned *profile, unsigned *level);
diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp
index 788dfc8..14b31ec 100644
--- a/media/img_utils/src/DngUtils.cpp
+++ b/media/img_utils/src/DngUtils.cpp
@@ -19,7 +19,7 @@
 namespace android {
 namespace img_utils {
 
-OpcodeListBuilder::OpcodeListBuilder() : mOpList(), mEndianOut(&mOpList, BIG) {
+OpcodeListBuilder::OpcodeListBuilder() : mCount(0), mOpList(), mEndianOut(&mOpList, BIG) {
     if(mEndianOut.open() != OK) {
         ALOGE("%s: Open failed.", __FUNCTION__);
     }
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/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 219dbfd..0dbfa62 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -134,10 +134,17 @@
         ssize_t filled = rear - front;
         // pipe should not be overfull
         if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
-            ALOGE("Shared memory control block is corrupt (filled=%d); shutting down", filled);
-            mIsShutdown = true;
-            status = NO_INIT;
-            goto end;
+            if (mIsOut) {
+                ALOGE("Shared memory control block is corrupt (filled=%d, mFrameCount=%u); "
+                        "shutting down", filled, mFrameCount);
+                mIsShutdown = true;
+                status = NO_INIT;
+                goto end;
+            }
+            // for input, sync up on overrun
+            filled = 0;
+            cblk->u.mStreaming.mFront = rear;
+            (void) android_atomic_or(CBLK_OVERRUN, &cblk->mFlags);
         }
         // don't allow filling pipe beyond the nominal size
         size_t avail = mIsOut ? mFrameCount - filled : filled;
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index eee72c5..77d131b 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -421,7 +421,6 @@
             status = (status_t)reply.readInt32();
             *num_ports = (unsigned int)reply.readInt32();
         }
-        ALOGI("listAudioPorts() status %d got *num_ports %d", status, *num_ports);
         if (status == NO_ERROR) {
             if (numPortsReq > *num_ports) {
                 numPortsReq = *num_ports;
@@ -840,7 +839,6 @@
             status_t status = listAudioPorts(role, type, &numPorts, ports, &generation);
             reply->writeInt32(status);
             reply->writeInt32(numPorts);
-            ALOGI("LIST_AUDIO_PORTS status %d got numPorts %d", status, numPorts);
 
             if (status == NO_ERROR) {
                 if (numPortsReq > numPorts) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 469c9ca..cfbf282 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -37,6 +37,7 @@
     : mNotify(notify),
       mNativeWindow(nativeWindow),
       mBufferGeneration(0),
+      mPaused(true),
       mComponentName("decoder") {
     // Every decoder has its own looper because MediaCodec operations
     // are blocking, but NuPlayer needs asynchronous operations.
@@ -112,6 +113,7 @@
             mOutputBuffers.size());
 
     requestCodecNotification();
+    mPaused = false;
 }
 
 void NuPlayer::Decoder::requestCodecNotification() {
@@ -352,6 +354,11 @@
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatFlushCompleted);
     notify->post();
+    mPaused = true;
+}
+
+void NuPlayer::Decoder::onResume() {
+    mPaused = false;
 }
 
 void NuPlayer::Decoder::onShutdown() {
@@ -380,6 +387,7 @@
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatShutdownCompleted);
     notify->post();
+    mPaused = true;
 }
 
 void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
@@ -397,7 +405,9 @@
         case kWhatCodecNotify:
         {
             if (!isStaleReply(msg)) {
-                while (handleAnInputBuffer()) {
+                if (!mPaused) {
+                    while (handleAnInputBuffer()) {
+                    }
                 }
 
                 while (handleAnOutputBuffer()) {
@@ -430,6 +440,12 @@
             break;
         }
 
+        case kWhatResume:
+        {
+            onResume();
+            break;
+        }
+
         case kWhatShutdown:
         {
             onShutdown();
@@ -447,7 +463,7 @@
 }
 
 void NuPlayer::Decoder::signalResume() {
-    // nothing to do
+    (new AMessage(kWhatResume, id()))->post();
 }
 
 void NuPlayer::Decoder::initiateShutdown() {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 94243fc..2892584 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -87,11 +87,13 @@
 
     void onConfigure(const sp<AMessage> &format);
     void onFlush();
+    void onResume();
     void onInputBufferFilled(const sp<AMessage> &msg);
     void onRenderBuffer(const sp<AMessage> &msg);
     void onShutdown();
 
     int32_t mBufferGeneration;
+    bool mPaused;
     AString mComponentName;
 
     bool supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index e07b6aa..aabe0ec 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -95,6 +95,7 @@
     uint64_t* mCurrentSampleInfoOffsets;
 
     bool mIsAVC;
+    bool mIsHEVC;
     size_t mNALLengthSize;
 
     bool mStarted;
@@ -317,6 +318,9 @@
         case FOURCC('a', 'v', 'c', '1'):
             return MEDIA_MIMETYPE_VIDEO_AVC;
 
+        case FOURCC('h', 'v', 'c', '1'):
+        case FOURCC('h', 'e', 'v', '1'):
+            return MEDIA_MIMETYPE_VIDEO_HEVC;
         default:
             CHECK(!"should not be here.");
             return NULL;
@@ -478,11 +482,20 @@
     off64_t offset = 0;
     status_t err;
     while (true) {
+        off64_t orig_offset = offset;
         err = parseChunk(&offset, 0);
-        if (err == OK) {
-            continue;
-        }
 
+        if (offset <= orig_offset) {
+            // only continue parsing if the offset was advanced,
+            // otherwise we might end up in an infinite loop
+            ALOGE("did not advance: 0x%lld->0x%lld", orig_offset, offset);
+            err = ERROR_MALFORMED;
+            break;
+        } else if (err == OK) {
+            continue;
+        } else if (err != UNKNOWN_ERROR) {
+            break;
+        }
         uint32_t hdr[2];
         if (mDataSource->readAt(offset, hdr, 8) < 8) {
             break;
@@ -505,8 +518,6 @@
         } else {
             mFileMetaData->setCString(kKeyMIMEType, "audio/mp4");
         }
-
-        mInitCheck = OK;
     } else {
         mInitCheck = err;
     }
@@ -758,8 +769,25 @@
             // The smallest valid chunk is 16 bytes long in this case.
             return ERROR_MALFORMED;
         }
+    } else if (chunk_size == 0) {
+        if (depth == 0) {
+            // atom extends to end of file
+            off64_t sourceSize;
+            if (mDataSource->getSize(&sourceSize) == OK) {
+                chunk_size = (sourceSize - *offset);
+            } else {
+                // XXX could we just pick a "sufficiently large" value here?
+                ALOGE("atom size is 0, and data source has no size");
+                return ERROR_MALFORMED;
+            }
+        } else {
+            // not allowed for non-toplevel atoms, skip it
+            *offset += 4;
+            return OK;
+        }
     } else if (chunk_size < 8) {
         // The smallest valid chunk is 8 bytes long.
+        ALOGE("invalid chunk size: %d", int(chunk_size));
         return ERROR_MALFORMED;
     }
 
@@ -1288,6 +1316,8 @@
         case FOURCC('H', '2', '6', '3'):
         case FOURCC('h', '2', '6', '3'):
         case FOURCC('a', 'v', 'c', '1'):
+        case FOURCC('h', 'v', 'c', '1'):
+        case FOURCC('h', 'e', 'v', '1'):
         {
             mHasVideo = true;
 
@@ -1580,6 +1610,21 @@
 
             break;
         }
+        case FOURCC('h', 'v', 'c', 'C'):
+        {
+            sp<ABuffer> buffer = new ABuffer(chunk_data_size);
+
+            if (mDataSource->readAt(
+                        data_offset, buffer->data(), chunk_data_size) < chunk_data_size) {
+                return ERROR_IO;
+            }
+
+            mLastTrack->meta->setData(
+                    kKeyHVCC, kTypeHVCC, buffer->data(), chunk_data_size);
+
+            *offset += chunk_size;
+            break;
+        }
 
         case FOURCC('d', '2', '6', '3'):
         {
@@ -2452,6 +2497,11 @@
                 || type != kTypeAVCC) {
             return ERROR_MALFORMED;
         }
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+        if (!track->meta->findData(kKeyHVCC, &type, &data, &size)
+                    || type != kTypeHVCC) {
+            return ERROR_MALFORMED;
+        }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
             || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
         if (!track->meta->findData(kKeyESDS, &type, &data, &size)
@@ -2776,6 +2826,7 @@
       mCurrentSampleInfoOffsetsAllocSize(0),
       mCurrentSampleInfoOffsets(NULL),
       mIsAVC(false),
+      mIsHEVC(false),
       mNALLengthSize(0),
       mStarted(false),
       mGroup(NULL),
@@ -2800,6 +2851,7 @@
     CHECK(success);
 
     mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
+    mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
 
     if (mIsAVC) {
         uint32_t type;
@@ -2814,6 +2866,18 @@
 
         // The number of bytes used to encode the length of a NAL unit.
         mNALLengthSize = 1 + (ptr[4] & 3);
+    } else if (mIsHEVC) {
+        uint32_t type;
+        const void *data;
+        size_t size;
+        CHECK(format->findData(kKeyHVCC, &type, &data, &size));
+
+        const uint8_t *ptr = (const uint8_t *)data;
+
+        CHECK(size >= 7);
+        CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
+
+        mNALLengthSize = 1 + (ptr[14 + 7] & 3);
     }
 
     CHECK(format->findInt32(kKeyTrackID, &mTrackId));
@@ -3562,7 +3626,7 @@
         }
     }
 
-    if (!mIsAVC || mWantsNALFragments) {
+    if ((!mIsAVC && !mIsHEVC) || mWantsNALFragments) {
         if (newBuffer) {
             ssize_t num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
@@ -3594,7 +3658,7 @@
             ++mCurrentSampleIndex;
         }
 
-        if (!mIsAVC) {
+        if (!mIsAVC && !mIsHEVC) {
             *out = mBuffer;
             mBuffer = NULL;
 
@@ -3837,7 +3901,7 @@
         bufmeta->setData(kKeyCryptoKey, 0, mCryptoKey, 16);
     }
 
-    if (!mIsAVC || mWantsNALFragments) {
+    if ((!mIsAVC && !mIsHEVC)|| mWantsNALFragments) {
         if (newBuffer) {
             ssize_t num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
@@ -3869,7 +3933,7 @@
             ++mCurrentSampleIndex;
         }
 
-        if (!mIsAVC) {
+        if (!mIsAVC && !mIsHEVC) {
             *out = mBuffer;
             mBuffer = NULL;
 
@@ -4043,6 +4107,8 @@
         FOURCC('i', 's', 'o', 'm'),
         FOURCC('i', 's', 'o', '2'),
         FOURCC('a', 'v', 'c', '1'),
+        FOURCC('h', 'v', 'c', '1'),
+        FOURCC('h', 'e', 'v', '1'),
         FOURCC('3', 'g', 'p', '4'),
         FOURCC('m', 'p', '4', '1'),
         FOURCC('m', 'p', '4', '2'),
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 8a451c8..cd51582 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -70,11 +70,6 @@
         return;
     }
 
-    // These are currently still used by the video editing suite.
-    addMediaCodec(true /* encoder */, "AACEncoder", "audio/mp4a-latm");
-    addMediaCodec(
-            false /* encoder */, "OMX.google.raw.decoder", "audio/raw");
-
     for (size_t i = mCodecInfos.size(); i-- > 0;) {
         CodecInfo *info = &mCodecInfos.editItemAt(i);
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index c028dbf..354712c 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -381,6 +381,57 @@
     return NULL;
 }
 
+status_t OMXCodec::parseHEVCCodecSpecificData(
+        const void *data, size_t size,
+        unsigned *profile, unsigned *level) {
+    const uint8_t *ptr = (const uint8_t *)data;
+
+    // verify minimum size and configurationVersion == 1.
+    if (size < 7 || ptr[0] != 1) {
+        return ERROR_MALFORMED;
+    }
+
+    *profile = (ptr[1] & 31);
+    *level = ptr[12];
+
+    ptr += 22;
+    size -= 22;
+
+    size_t numofArrays = (char)ptr[0];
+    ptr += 1;
+    size -= 1;
+    size_t j = 0, i = 0;
+    for (i = 0; i < numofArrays; i++) {
+        ptr += 1;
+        size -= 1;
+
+        // Num of nals
+        size_t numofNals = U16_AT(ptr);
+        ptr += 2;
+        size -= 2;
+
+        for (j = 0;j < numofNals;j++) {
+            if (size < 2) {
+                return ERROR_MALFORMED;
+            }
+
+            size_t length = U16_AT(ptr);
+
+            ptr += 2;
+            size -= 2;
+
+            if (size < length) {
+                return ERROR_MALFORMED;
+            }
+            addCodecSpecificData(ptr, length);
+
+            ptr += length;
+            size -= length;
+        }
+    }
+    return OK;
+}
+
 status_t OMXCodec::parseAVCCodecSpecificData(
         const void *data, size_t size,
         unsigned *profile, unsigned *level) {
@@ -493,6 +544,20 @@
             CODEC_LOGI(
                     "AVC profile = %u (%s), level = %u",
                     profile, AVCProfileToString(profile), level);
+        } else if (meta->findData(kKeyHVCC, &type, &data, &size)) {
+            // Parse the HEVCDecoderConfigurationRecord
+
+            unsigned profile, level;
+            status_t err;
+            if ((err = parseHEVCCodecSpecificData(
+                            data, size, &profile, &level)) != OK) {
+                ALOGE("Malformed HEVC codec specific data.");
+                return err;
+            }
+
+            CODEC_LOGI(
+                    "HEVC profile = %u , level = %u",
+                    profile, level);
         } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) {
             addCodecSpecificData(data, size);
 
@@ -822,6 +887,8 @@
     OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
     if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
         compressionFormat = OMX_VIDEO_CodingAVC;
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
+        compressionFormat = OMX_VIDEO_CodingHEVC;
     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
         compressionFormat = OMX_VIDEO_CodingMPEG4;
     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
@@ -1217,6 +1284,8 @@
         compressionFormat = OMX_VIDEO_CodingAVC;
     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
         compressionFormat = OMX_VIDEO_CodingMPEG4;
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
+        compressionFormat = OMX_VIDEO_CodingHEVC;
     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
         compressionFormat = OMX_VIDEO_CodingH263;
     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_VP8, mime)) {
@@ -1411,6 +1480,8 @@
             "audio_decoder.g711alaw", "audio_encoder.g711alaw" },
         { MEDIA_MIMETYPE_VIDEO_AVC,
             "video_decoder.avc", "video_encoder.avc" },
+        { MEDIA_MIMETYPE_VIDEO_HEVC,
+            "video_decoder.hevc", "video_encoder.hevc" },
         { MEDIA_MIMETYPE_VIDEO_MPEG4,
             "video_decoder.mpeg4", "video_encoder.mpeg4" },
         { MEDIA_MIMETYPE_VIDEO_H263,
@@ -3009,7 +3080,8 @@
 
         size_t size = specific->mSize;
 
-        if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mMIME)
+        if ((!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mMIME) ||
+             !strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mMIME))
                 && !(mQuirks & kWantsNALFragments)) {
             static const uint8_t kNALStartCode[4] =
                     { 0x00, 0x00, 0x00, 0x01 };
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 047fac7..7ff31a1 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -217,6 +217,56 @@
         buffer->meta()->setInt32("csd", true);
         buffer->meta()->setInt64("timeUs", 0);
         msg->setBuffer("csd-1", buffer);
+    } else if (meta->findData(kKeyHVCC, &type, &data, &size)) {
+        const uint8_t *ptr = (const uint8_t *)data;
+
+        CHECK(size >= 7);
+        CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
+        uint8_t profile = ptr[1] & 31;
+        uint8_t level = ptr[12];
+        ptr += 22;
+        size -= 22;
+
+
+        size_t numofArrays = (char)ptr[0];
+        ptr += 1;
+        size -= 1;
+        size_t j = 0, i = 0;
+
+        sp<ABuffer> buffer = new ABuffer(1024);
+        buffer->setRange(0, 0);
+
+        for (i = 0; i < numofArrays; i++) {
+            ptr += 1;
+            size -= 1;
+
+            //Num of nals
+            size_t numofNals = U16_AT(ptr);
+
+            ptr += 2;
+            size -= 2;
+
+            for (j = 0; j < numofNals; j++) {
+                CHECK(size >= 2);
+                size_t length = U16_AT(ptr);
+
+                ptr += 2;
+                size -= 2;
+
+                CHECK(size >= length);
+
+                memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4);
+                memcpy(buffer->data() + buffer->size() + 4, ptr, length);
+                buffer->setRange(0, buffer->size() + 4 + length);
+
+                ptr += length;
+                size -= length;
+            }
+        }
+        buffer->meta()->setInt32("csd", true);
+        buffer->meta()->setInt64("timeUs", 0);
+        msg->setBuffer("csd-0", buffer);
+
     } else if (meta->findData(kKeyESDS, &type, &data, &size)) {
         ESDS esds((const char *)data, size);
         CHECK_EQ(esds.InitCheck(), (status_t)OK);
diff --git a/media/libstagefright/codecs/hevcdec/Android.mk b/media/libstagefright/codecs/hevcdec/Android.mk
new file mode 100644
index 0000000..2fe347b
--- /dev/null
+++ b/media/libstagefright/codecs/hevcdec/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE            := libstagefright_soft_hevcdec
+LOCAL_MODULE_TAGS       := optional
+
+LOCAL_STATIC_LIBRARIES  := libhevcdec
+LOCAL_SRC_FILES         := SoftHEVC.cpp
+
+LOCAL_C_INCLUDES := $(TOP)/external/libhevc/decoder
+LOCAL_C_INCLUDES += $(TOP)/external/libhevc/common
+LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include
+LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax
+
+LOCAL_SHARED_LIBRARIES  := libstagefright
+LOCAL_SHARED_LIBRARIES  += libstagefright_omx
+LOCAL_SHARED_LIBRARIES  += libstagefright_foundation
+LOCAL_SHARED_LIBRARIES  += libutils
+LOCAL_SHARED_LIBRARIES  += liblog
+
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
new file mode 100644
index 0000000..0aae5ed
--- /dev/null
+++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
@@ -0,0 +1,710 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoftHEVC"
+#include <utils/Log.h>
+
+#include "ihevc_typedefs.h"
+#include "iv.h"
+#include "ivd.h"
+#include "ithread.h"
+#include "ihevcd_cxa.h"
+#include "SoftHEVC.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <OMX_VideoExt.h>
+
+namespace android {
+
+#define componentName                   "video_decoder.hevc"
+#define codingType                      OMX_VIDEO_CodingHEVC
+#define CODEC_MIME_TYPE                 MEDIA_MIMETYPE_VIDEO_HEVC
+
+/** Function and structure definitions to keep code similar for each codec */
+#define ivdec_api_function              ihevcd_cxa_api_function
+#define ivdext_init_ip_t                ihevcd_cxa_init_ip_t
+#define ivdext_init_op_t                ihevcd_cxa_init_op_t
+#define ivdext_fill_mem_rec_ip_t        ihevcd_cxa_fill_mem_rec_ip_t
+#define ivdext_fill_mem_rec_op_t        ihevcd_cxa_fill_mem_rec_op_t
+#define ivdext_ctl_set_num_cores_ip_t   ihevcd_cxa_ctl_set_num_cores_ip_t
+#define ivdext_ctl_set_num_cores_op_t   ihevcd_cxa_ctl_set_num_cores_op_t
+
+#define IVDEXT_CMD_CTL_SET_NUM_CORES    \
+        (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES
+
+static const CodecProfileLevel kProfileLevels[] = {
+    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel1  },
+    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel2  },
+    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel21 },
+    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel3  },
+    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel31 },
+    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel4  },
+    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel41 },
+    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel5  },
+    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel51 },
+};
+
+SoftHEVC::SoftHEVC(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : SoftVideoDecoderOMXComponent(name, componentName, codingType,
+            kProfileLevels, ARRAY_SIZE(kProfileLevels),
+            CODEC_MAX_WIDTH /* width */, CODEC_MAX_HEIGHT /* height */, callbacks,
+            appData, component) {
+    initPorts(kNumBuffers, INPUT_BUF_SIZE, kNumBuffers,
+            CODEC_MIME_TYPE);
+
+    mOmxColorFormat = OMX_COLOR_FormatYUV420Planar;
+    mStride = mWidth;
+
+    if (OMX_COLOR_FormatYUV420Planar == mOmxColorFormat) {
+        mIvColorFormat = IV_YUV_420P;
+    } else if (OMX_COLOR_FormatYUV420SemiPlanar == mOmxColorFormat) {
+        mIvColorFormat = IV_YUV_420SP_UV;
+    }
+
+    mInitWidth = mWidth;
+    mInitHeight = mHeight;
+
+    CHECK_EQ(initDecoder(), (status_t)OK);
+}
+
+SoftHEVC::~SoftHEVC() {
+    ALOGD("In SoftHEVC::~SoftHEVC");
+    CHECK_EQ(deInitDecoder(), (status_t)OK);
+}
+
+static size_t GetCPUCoreCount() {
+    long cpuCoreCount = 1;
+#if defined(_SC_NPROCESSORS_ONLN)
+    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+    // _SC_NPROC_ONLN must be defined...
+    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
+#endif
+    CHECK(cpuCoreCount >= 1);
+    ALOGD("Number of CPU cores: %ld", cpuCoreCount);
+    return (size_t)cpuCoreCount;
+}
+
+status_t SoftHEVC::getVersion() {
+    ivd_ctl_getversioninfo_ip_t s_ctl_ip;
+    ivd_ctl_getversioninfo_op_t s_ctl_op;
+    UWORD8 au1_buf[512];
+    IV_API_CALL_STATUS_T status;
+
+    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
+    s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
+    s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
+    s_ctl_ip.pv_version_buffer = au1_buf;
+    s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf);
+
+    status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
+            (void *)&s_ctl_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGE("Error in getting version number: 0x%x",
+                s_ctl_op.u4_error_code);
+    } else {
+        ALOGD("Ittiam decoder version number: %s",
+                (char *)s_ctl_ip.pv_version_buffer);
+    }
+    return OK;
+}
+
+status_t SoftHEVC::setParams(WORD32 stride, IVD_VIDEO_DECODE_MODE_T decMode) {
+    ivd_ctl_set_config_ip_t s_ctl_ip;
+    ivd_ctl_set_config_op_t s_ctl_op;
+    IV_API_CALL_STATUS_T status;
+    s_ctl_ip.u4_disp_wd = stride;
+    s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
+
+    s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
+    s_ctl_ip.e_vid_dec_mode = decMode;
+    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
+    s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
+    s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
+
+    ALOGD("Set the run-time (dynamic) parameters");
+    status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
+            (void *)&s_ctl_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGE("Error in setting the run-time parameters: 0x%x",
+                s_ctl_op.u4_error_code);
+
+        return UNKNOWN_ERROR;
+    }
+    return OK;
+}
+
+status_t SoftHEVC::resetPlugin() {
+    mIsInFlush = false;
+    mReceivedEOS = false;
+    memset(mTimeStamps, 0, sizeof(mTimeStamps));
+    memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
+
+    /* Initialize both start and end times */
+    gettimeofday(&mTimeStart, NULL);
+    gettimeofday(&mTimeEnd, NULL);
+
+    return OK;
+}
+
+status_t SoftHEVC::resetDecoder() {
+    ivd_ctl_reset_ip_t s_ctl_ip;
+    ivd_ctl_reset_op_t s_ctl_op;
+    IV_API_CALL_STATUS_T status;
+
+    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
+    s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
+    s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
+
+    status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
+            (void *)&s_ctl_op);
+    if (IV_SUCCESS != status) {
+        ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code);
+        return UNKNOWN_ERROR;
+    }
+
+    /* Set the run-time (dynamic) parameters */
+    setParams(0, IVD_DECODE_FRAME);
+
+    /* Set number of cores/threads to be used by the codec */
+    setNumCores();
+
+    return OK;
+}
+
+status_t SoftHEVC::setNumCores() {
+    ivdext_ctl_set_num_cores_ip_t s_set_cores_ip;
+    ivdext_ctl_set_num_cores_op_t s_set_cores_op;
+    IV_API_CALL_STATUS_T status;
+    s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
+    s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES);
+    s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
+    s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
+    ALOGD("Set number of cores to %u", s_set_cores_ip.u4_num_cores);
+    status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip,
+            (void *)&s_set_cores_op);
+    if (IV_SUCCESS != status) {
+        ALOGE("Error in setting number of cores: 0x%x",
+                s_set_cores_op.u4_error_code);
+        return UNKNOWN_ERROR;
+    }
+    return OK;
+}
+
+status_t SoftHEVC::setFlushMode() {
+    IV_API_CALL_STATUS_T status;
+    ivd_ctl_flush_ip_t s_video_flush_ip;
+    ivd_ctl_flush_op_t s_video_flush_op;
+
+    s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
+    s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
+    s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
+    ALOGD("Set the decoder in flush mode ");
+
+    /* Set the decoder in Flush mode, subsequent decode() calls will flush */
+    status = ivdec_api_function(mCodecCtx, (void *)&s_video_flush_ip,
+            (void *)&s_video_flush_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status,
+                s_video_flush_op.u4_error_code);
+        return UNKNOWN_ERROR;
+    }
+
+    mIsInFlush = true;
+    return OK;
+}
+
+status_t SoftHEVC::initDecoder() {
+    IV_API_CALL_STATUS_T status;
+
+    UWORD32 u4_num_reorder_frames;
+    UWORD32 u4_num_ref_frames;
+    UWORD32 u4_share_disp_buf;
+    WORD32 i4_level;
+
+    mNumCores = GetCPUCoreCount();
+
+    /* Initialize number of ref and reorder modes (for HEVC) */
+    u4_num_reorder_frames = 16;
+    u4_num_ref_frames = 16;
+    u4_share_disp_buf = 0;
+
+    if ((mWidth * mHeight) > (1920 * 1088)) {
+        i4_level = 50;
+    } else if ((mWidth * mHeight) > (1280 * 720)) {
+        i4_level = 41;
+    } else {
+        i4_level = 31;
+    }
+
+    {
+        iv_num_mem_rec_ip_t s_num_mem_rec_ip;
+        iv_num_mem_rec_op_t s_num_mem_rec_op;
+
+        s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip);
+        s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op);
+        s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
+
+        ALOGV("Get number of mem records");
+        status = ivdec_api_function(mCodecCtx, (void*)&s_num_mem_rec_ip,
+                (void*)&s_num_mem_rec_op);
+        if (IV_SUCCESS != status) {
+            ALOGE("Error in getting mem records: 0x%x",
+                    s_num_mem_rec_op.u4_error_code);
+            return UNKNOWN_ERROR;
+        }
+
+        mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec;
+    }
+
+    mMemRecords = (iv_mem_rec_t*)ivd_aligned_malloc(
+            128, mNumMemRecords * sizeof(iv_mem_rec_t));
+    if (mMemRecords == NULL) {
+        ALOGE("Allocation failure");
+        return NO_MEMORY;
+    }
+
+    {
+        size_t i;
+        ivdext_fill_mem_rec_ip_t s_fill_mem_ip;
+        ivdext_fill_mem_rec_op_t s_fill_mem_op;
+        iv_mem_rec_t *ps_mem_rec;
+
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size =
+            sizeof(ivdext_fill_mem_rec_ip_t);
+        s_fill_mem_ip.i4_level = i4_level;
+        s_fill_mem_ip.u4_num_reorder_frames = u4_num_reorder_frames;
+        s_fill_mem_ip.u4_num_ref_frames = u4_num_ref_frames;
+        s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf;
+        s_fill_mem_ip.u4_num_extra_disp_buf = 0;
+        s_fill_mem_ip.e_output_format = mIvColorFormat;
+
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords;
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = mWidth;
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = mHeight;
+        s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size =
+            sizeof(ivdext_fill_mem_rec_op_t);
+
+        ps_mem_rec = mMemRecords;
+        for (i = 0; i < mNumMemRecords; i++)
+            ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t);
+
+        status = ivdec_api_function(mCodecCtx, (void *)&s_fill_mem_ip,
+                (void *)&s_fill_mem_op);
+
+        if (IV_SUCCESS != status) {
+            ALOGE("Error in filling mem records: 0x%x",
+                    s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code);
+            return UNKNOWN_ERROR;
+        }
+        mNumMemRecords =
+            s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled;
+
+        ps_mem_rec = mMemRecords;
+
+        for (i = 0; i < mNumMemRecords; i++) {
+            ps_mem_rec->pv_base = ivd_aligned_malloc(
+                    ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
+            if (ps_mem_rec->pv_base == NULL) {
+                ALOGE("Allocation failure for memory record #%zu of size %u",
+                        i, ps_mem_rec->u4_mem_size);
+                status = IV_FAIL;
+                return NO_MEMORY;
+            }
+
+            ps_mem_rec++;
+        }
+    }
+
+    /* Initialize the decoder */
+    {
+        ivdext_init_ip_t s_init_ip;
+        ivdext_init_op_t s_init_op;
+
+        void *dec_fxns = (void *)ivdec_api_function;
+
+        s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t);
+        s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
+        s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
+        s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = mWidth;
+        s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight;
+
+        s_init_ip.i4_level = i4_level;
+        s_init_ip.u4_num_reorder_frames = u4_num_reorder_frames;
+        s_init_ip.u4_num_ref_frames = u4_num_ref_frames;
+        s_init_ip.u4_share_disp_buf = u4_share_disp_buf;
+        s_init_ip.u4_num_extra_disp_buf = 0;
+
+        s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op);
+
+        s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
+        s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat;
+
+        mCodecCtx = (iv_obj_t*)mMemRecords[0].pv_base;
+        mCodecCtx->pv_fxns = dec_fxns;
+        mCodecCtx->u4_size = sizeof(iv_obj_t);
+
+        ALOGD("Initializing decoder");
+        status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip,
+                (void *)&s_init_op);
+        if (status != IV_SUCCESS) {
+            ALOGE("Error in init: 0x%x",
+                    s_init_op.s_ivd_init_op_t.u4_error_code);
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    /* Reset the plugin state */
+    resetPlugin();
+
+    /* Set the run time (dynamic) parameters */
+    setParams(0, IVD_DECODE_FRAME);
+
+    /* Set number of cores/threads to be used by the codec */
+    setNumCores();
+
+    /* Get codec version */
+    getVersion();
+
+    /* Allocate internal picture buffer */
+    mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, mStride * mHeight * 3 / 2);
+    if (NULL == mFlushOutBuffer) {
+        ALOGE("Could not allocate flushOutputBuffer of size %zu", mStride * mHeight * 3 / 2);
+        return NO_MEMORY;
+    }
+
+    return OK;
+}
+
+status_t SoftHEVC::deInitDecoder() {
+    size_t i;
+    iv_mem_rec_t *ps_mem_rec;
+    ps_mem_rec = mMemRecords;
+    ALOGD("Freeing codec memory");
+    for (i = 0; i < mNumMemRecords; i++) {
+        ivd_aligned_free(ps_mem_rec->pv_base);
+        ps_mem_rec++;
+    }
+
+    ivd_aligned_free(mMemRecords);
+    ivd_aligned_free(mFlushOutBuffer);
+    return OK;
+}
+
+void SoftHEVC::onReset() {
+    ALOGD("onReset called");
+    SoftVideoDecoderOMXComponent::onReset();
+
+    resetDecoder();
+    resetPlugin();
+}
+
+void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) {
+    ALOGD("onPortFlushCompleted on port %d", portIndex);
+
+    /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
+    if (kOutputPortIndex == portIndex) {
+        setFlushMode();
+
+        /* Reset the time stamp arrays */
+        memset(mTimeStamps, 0, sizeof(mTimeStamps));
+        memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
+
+        while (true) {
+            ivd_video_decode_ip_t s_dec_ip;
+            ivd_video_decode_op_t s_dec_op;
+            IV_API_CALL_STATUS_T status;
+            size_t sizeY, sizeUV;
+
+            s_dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
+
+            s_dec_ip.u4_ts = 0;
+            s_dec_ip.pv_stream_buffer = NULL;
+            s_dec_ip.u4_num_Bytes = 0;
+
+            s_dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);
+            s_dec_op.u4_size = sizeof(ivd_video_decode_op_t);
+
+            sizeY = mStride * mHeight;
+            sizeUV = sizeY / 4;
+            s_dec_ip.s_out_buffer.u4_min_out_buf_size[0] = sizeY;
+            s_dec_ip.s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
+            s_dec_ip.s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
+
+            s_dec_ip.s_out_buffer.pu1_bufs[0] = mFlushOutBuffer;
+            s_dec_ip.s_out_buffer.pu1_bufs[1] =
+                s_dec_ip.s_out_buffer.pu1_bufs[0] + sizeY;
+            s_dec_ip.s_out_buffer.pu1_bufs[2] =
+                s_dec_ip.s_out_buffer.pu1_bufs[1] + sizeUV;
+            s_dec_ip.s_out_buffer.u4_num_bufs = 3;
+
+            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip,
+                    (void *)&s_dec_op);
+            if (0 == s_dec_op.u4_output_present) {
+                resetPlugin();
+                break;
+            }
+        }
+    }
+}
+
+void SoftHEVC::onQueueFilled(OMX_U32 portIndex) {
+    IV_API_CALL_STATUS_T status;
+
+    UNUSED(portIndex);
+
+    if (mOutputPortSettingsChange != NONE) {
+        return;
+    }
+
+    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
+    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+
+    /* If input EOS is seen and decoder is not in flush mode,
+     * set the decoder in flush mode.
+     * There can be a case where EOS is sent along with last picture data
+     * In that case, only after decoding that input data, decoder has to be
+     * put in flush. This case is handled here  */
+
+    if (mReceivedEOS && !mIsInFlush) {
+        setFlushMode();
+    }
+
+    while (outQueue.size() == kNumBuffers) {
+        BufferInfo *inInfo;
+        OMX_BUFFERHEADERTYPE *inHeader;
+
+        BufferInfo *outInfo;
+        OMX_BUFFERHEADERTYPE *outHeader;
+        size_t timeStampIx;
+
+        inInfo = NULL;
+        inHeader = NULL;
+
+        if (!mIsInFlush) {
+            if (!inQueue.empty()) {
+                inInfo = *inQueue.begin();
+                inHeader = inInfo->mHeader;
+            } else {
+                break;
+            }
+        }
+
+        outInfo = *outQueue.begin();
+        outHeader = outInfo->mHeader;
+        outHeader->nFlags = 0;
+        outHeader->nTimeStamp = 0;
+        outHeader->nOffset = 0;
+
+        if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
+            ALOGD("EOS seen on input");
+            mReceivedEOS = true;
+            if (inHeader->nFilledLen == 0) {
+                inQueue.erase(inQueue.begin());
+                inInfo->mOwnedByUs = false;
+                notifyEmptyBufferDone(inHeader);
+                inHeader = NULL;
+                setFlushMode();
+            }
+        }
+
+        /* Get a free slot in timestamp array to hold input timestamp */
+        {
+            size_t i;
+            timeStampIx = 0;
+            for (i = 0; i < MAX_TIME_STAMPS; i++) {
+                if (!mTimeStampsValid[i]) {
+                    timeStampIx = i;
+                    break;
+                }
+            }
+            if (inHeader != NULL) {
+                mTimeStampsValid[timeStampIx] = true;
+                mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
+            }
+        }
+
+        {
+            ivd_video_decode_ip_t s_dec_ip;
+            ivd_video_decode_op_t s_dec_op;
+            WORD32 timeDelay, timeTaken;
+            size_t sizeY, sizeUV;
+
+            s_dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
+
+            /* When in flush and after EOS with zero byte input,
+             * inHeader is set to zero. Hence check for non-null */
+            if (inHeader != NULL) {
+                s_dec_ip.u4_ts = timeStampIx;
+                s_dec_ip.pv_stream_buffer = inHeader->pBuffer
+                        + inHeader->nOffset;
+                s_dec_ip.u4_num_Bytes = inHeader->nFilledLen;
+            } else {
+                s_dec_ip.u4_ts = 0;
+                s_dec_ip.pv_stream_buffer = NULL;
+                s_dec_ip.u4_num_Bytes = 0;
+            }
+
+            s_dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);
+            s_dec_op.u4_size = sizeof(ivd_video_decode_op_t);
+
+            sizeY = mStride * mHeight;
+            sizeUV = sizeY / 4;
+            s_dec_ip.s_out_buffer.u4_min_out_buf_size[0] = sizeY;
+            s_dec_ip.s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
+            s_dec_ip.s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
+
+            s_dec_ip.s_out_buffer.pu1_bufs[0] = outHeader->pBuffer;
+            s_dec_ip.s_out_buffer.pu1_bufs[1] =
+                s_dec_ip.s_out_buffer.pu1_bufs[0] + sizeY;
+            s_dec_ip.s_out_buffer.pu1_bufs[2] =
+                s_dec_ip.s_out_buffer.pu1_bufs[1] + sizeUV;
+            s_dec_ip.s_out_buffer.u4_num_bufs = 3;
+
+            GETTIME(&mTimeStart, NULL);
+            /* Compute time elapsed between end of previous decode()
+             * to start of current decode() */
+            TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
+
+            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip,
+                    (void *)&s_dec_op);
+
+            GETTIME(&mTimeEnd, NULL);
+            /* Compute time taken for decode() */
+            TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
+
+            ALOGD("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
+                    s_dec_op.u4_num_bytes_consumed);
+
+            if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
+                /* If the input did not contain picture data, then ignore
+                 * the associated timestamp */
+                mTimeStampsValid[timeStampIx] = false;
+            }
+
+            /* If valid height and width are decoded,
+             * then look at change in resolution */
+            if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
+                uint32_t width = s_dec_op.u4_pic_wd;
+                uint32_t height = s_dec_op.u4_pic_ht;
+
+                if ((width != mWidth || height != mHeight)) {
+                    mWidth = width;
+                    mHeight = height;
+                    mStride = mWidth;
+
+                    /* If width and height are greater than the
+                     * the dimensions used during codec create, then
+                     * delete the current instance and recreate an instance with
+                     * new dimensions */
+                    /* TODO: The following does not work currently, since the decoder
+                     * currently returns 0 x 0 as width height when it is not supported
+                     * Once the decoder is updated to return actual width and height,
+                     * then this can be validated*/
+
+                    if ((mWidth * mHeight) > (mInitWidth * mInitHeight)) {
+                        status_t ret;
+                        ALOGD("Trying reInit");
+                        ret = deInitDecoder();
+                        if (OK != ret) {
+                            // TODO: Handle graceful exit
+                            ALOGE("Create failure");
+                            return;
+                        }
+
+                        mInitWidth = mWidth;
+                        mInitHeight = mHeight;
+
+                        ret = initDecoder();
+                        if (OK != ret) {
+                            // TODO: Handle graceful exit
+                            ALOGE("Create failure");
+                            return;
+                        }
+                    }
+                    updatePortDefinitions();
+
+                    notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+                    mOutputPortSettingsChange = AWAITING_DISABLED;
+                    return;
+                }
+            }
+
+            if (s_dec_op.u4_output_present) {
+                outHeader->nFilledLen = (mStride * mHeight * 3) / 2;
+
+                outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts];
+                mTimeStampsValid[s_dec_op.u4_ts] = false;
+
+                outInfo->mOwnedByUs = false;
+                outQueue.erase(outQueue.begin());
+                outInfo = NULL;
+                notifyFillBufferDone(outHeader);
+                outHeader = NULL;
+            } else {
+                /* If in flush mode and no output is returned by the codec,
+                 * then come out of flush mode */
+                mIsInFlush = false;
+
+                /* If EOS was recieved on input port and there is no output
+                 * from the codec, then signal EOS on output port */
+                if (mReceivedEOS) {
+                    outHeader->nFilledLen = 0;
+                    outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
+
+                    outInfo->mOwnedByUs = false;
+                    outQueue.erase(outQueue.begin());
+                    outInfo = NULL;
+                    notifyFillBufferDone(outHeader);
+                    outHeader = NULL;
+                    resetPlugin();
+                }
+            }
+        }
+
+        // TODO: Handle more than one picture data
+        if (inHeader != NULL) {
+            inInfo->mOwnedByUs = false;
+            inQueue.erase(inQueue.begin());
+            inInfo = NULL;
+            notifyEmptyBufferDone(inHeader);
+            inHeader = NULL;
+        }
+    }
+}
+
+} // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(const char *name,
+        const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
+        OMX_COMPONENTTYPE **component) {
+    return new android::SoftHEVC(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.h b/media/libstagefright/codecs/hevcdec/SoftHEVC.h
new file mode 100644
index 0000000..20db0e1
--- /dev/null
+++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOFT_HEVC_H_
+
+#define SOFT_HEVC_H_
+
+#include "SoftVideoDecoderOMXComponent.h"
+#include <sys/time.h>
+
+namespace android {
+
+#define ivd_aligned_malloc(alignment, size) memalign(alignment, size)
+#define ivd_aligned_free(buf) free(buf)
+
+/** Number of entries in the time-stamp array */
+#define MAX_TIME_STAMPS 64
+
+/** Maximum number of cores supported by the codec */
+#define CODEC_MAX_NUM_CORES 4
+
+#define CODEC_MAX_WIDTH     1920
+
+#define CODEC_MAX_HEIGHT    1088
+
+/** Input buffer size */
+#define INPUT_BUF_SIZE (1024 * 1024)
+
+#define MIN(a, b) ((a) < (b)) ? (a) : (b)
+
+/** Used to remove warnings about unused parameters */
+#define UNUSED(x) ((void)(x))
+
+/** Get time */
+#define GETTIME(a, b) gettimeofday(a, b);
+
+/** Compute difference between start and end */
+#define TIME_DIFF(start, end, diff) \
+    diff = ((end.tv_sec - start.tv_sec) * 1000000) + \
+            (end.tv_usec - start.tv_usec);
+
+struct SoftHEVC: public SoftVideoDecoderOMXComponent {
+    SoftHEVC(const char *name, const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData, OMX_COMPONENTTYPE **component);
+
+protected:
+    virtual ~SoftHEVC();
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+    virtual void onPortFlushCompleted(OMX_U32 portIndex);
+    virtual void onReset();
+private:
+    // Number of input and output buffers
+    enum {
+        kNumBuffers = 8
+    };
+
+    iv_obj_t *mCodecCtx;         // Codec context
+    iv_mem_rec_t *mMemRecords;   // Memory records requested by the codec
+    size_t mNumMemRecords;       // Number of memory records requested by the codec
+
+    uint32_t mNewWidth;          // New width after change in resolution
+    uint32_t mNewHeight;         // New height after change in resolution
+    uint32_t mInitWidth;         // Width used during codec creation
+    uint32_t mInitHeight;        // Height used during codec creation
+    size_t mStride;              // Stride to be used for display buffers
+
+    size_t mNumCores;            // Number of cores to be uesd by the codec
+
+    struct timeval mTimeStart;   // Time at the start of decode()
+    struct timeval mTimeEnd;     // Time at the end of decode()
+
+    // Internal buffer to be used to flush out the buffers from decoder
+    uint8_t *mFlushOutBuffer;
+
+    // Status of entries in the timestamp array
+    bool mTimeStampsValid[MAX_TIME_STAMPS];
+
+    // Timestamp array - Since codec does not take 64 bit timestamps,
+    // they are maintained in the plugin
+    OMX_S64 mTimeStamps[MAX_TIME_STAMPS];
+
+    OMX_COLOR_FORMATTYPE mOmxColorFormat;    // OMX Color format
+    IV_COLOR_FORMAT_T mIvColorFormat;        // Ittiam Color format
+
+    bool mIsInFlush;        // codec is flush mode
+    bool mReceivedEOS;      // EOS is receieved on input port
+    bool mIsAdapting;       // plugin in middle of change in resolution
+
+    status_t initDecoder();
+    status_t deInitDecoder();
+    status_t setFlushMode();
+    status_t setParams(WORD32 stride, IVD_VIDEO_DECODE_MODE_T decMode);
+    status_t getVersion();
+    status_t setNumCores();
+    status_t resetDecoder();
+    status_t resetPlugin();
+
+    DISALLOW_EVIL_CONSTRUCTORS (SoftHEVC);
+};
+
+} // namespace android
+
+#endif  // SOFT_HEVC_H_
diff --git a/media/libstagefright/data/media_codecs_google_audio.xml b/media/libstagefright/data/media_codecs_google_audio.xml
index b1f93de..f6db0cc 100644
--- a/media/libstagefright/data/media_codecs_google_audio.xml
+++ b/media/libstagefright/data/media_codecs_google_audio.xml
@@ -24,6 +24,7 @@
         <MediaCodec name="OMX.google.g711.mlaw.decoder" type="audio/g711-mlaw" />
         <MediaCodec name="OMX.google.vorbis.decoder" type="audio/vorbis" />
         <MediaCodec name="OMX.google.opus.decoder" type="audio/opus" />
+        <MediaCodec name="OMX.google.raw.decoder" type="audio/raw" />
     </Decoders>
 
     <Encoders>
diff --git a/media/libstagefright/data/media_codecs_google_video.xml b/media/libstagefright/data/media_codecs_google_video.xml
index 41e0efb..9b930bc 100644
--- a/media/libstagefright/data/media_codecs_google_video.xml
+++ b/media/libstagefright/data/media_codecs_google_video.xml
@@ -19,6 +19,7 @@
         <MediaCodec name="OMX.google.mpeg4.decoder" type="video/mp4v-es" />
         <MediaCodec name="OMX.google.h263.decoder" type="video/3gpp" />
         <MediaCodec name="OMX.google.h264.decoder" type="video/avc" />
+        <MediaCodec name="OMX.google.hevc.decoder" type="video/hevc" />
         <MediaCodec name="OMX.google.vp8.decoder" type="video/x-vnd.on2.vp8" />
         <MediaCodec name="OMX.google.vp9.decoder" type="video/x-vnd.on2.vp9" />
     </Decoders>
diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp
index 65f5404..9b6958a 100644
--- a/media/libstagefright/omx/SoftOMXPlugin.cpp
+++ b/media/libstagefright/omx/SoftOMXPlugin.cpp
@@ -42,6 +42,7 @@
     { "OMX.google.amrwb.encoder", "amrwbenc", "audio_encoder.amrwb" },
     { "OMX.google.h264.decoder", "h264dec", "video_decoder.avc" },
     { "OMX.google.h264.encoder", "h264enc", "video_encoder.avc" },
+    { "OMX.google.hevc.decoder", "hevcdec", "video_decoder.hevc" },
     { "OMX.google.g711.alaw.decoder", "g711dec", "audio_decoder.g711alaw" },
     { "OMX.google.g711.mlaw.decoder", "g711dec", "audio_decoder.g711mlaw" },
     { "OMX.google.h263.decoder", "mpeg4dec", "video_decoder.h263" },
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index eb9fcf7..1c383f7 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -183,12 +183,12 @@
                 return OMX_ErrorUnsupportedIndex;
             }
 
-            if (index >= mNumProfileLevels) {
+            if (profileLevel->nProfileIndex >= mNumProfileLevels) {
                 return OMX_ErrorNoMore;
             }
 
-            profileLevel->eProfile = mProfileLevels[index].mProfile;
-            profileLevel->eLevel   = mProfileLevels[index].mLevel;
+            profileLevel->eProfile = mProfileLevels[profileLevel->nProfileIndex].mProfile;
+            profileLevel->eLevel   = mProfileLevels[profileLevel->nProfileIndex].mLevel;
             return OMX_ErrorNone;
         }
 
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index f7b6f64..0bdf5a3 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -64,6 +64,7 @@
 
 LOCAL_SRC_FILES += FastMixer.cpp FastMixerState.cpp AudioWatchdog.cpp
 LOCAL_SRC_FILES += FastThread.cpp FastThreadState.cpp
+LOCAL_SRC_FILES += FastCapture.cpp FastCaptureState.cpp
 
 LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"'
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 457ac3d..a4cad4e 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -169,7 +169,8 @@
       mBtNrecIsOff(false),
       mIsLowRamDevice(true),
       mIsDeviceTypeKnown(false),
-      mGlobalEffectEnableTime(0)
+      mGlobalEffectEnableTime(0),
+      mPrimaryOutputSampleRate(0)
 {
     getpid_cached = getpid();
     char value[PROPERTY_VALUE_MAX];
@@ -1265,7 +1266,7 @@
     :   RefBase(),
         mAudioFlinger(audioFlinger),
         // FIXME should be a "k" constant not hard-coded, in .h or ro. property, see 4 lines below
-        mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client")),
+        mMemoryDealer(new MemoryDealer(4 * 1024*1024, "AudioFlinger::Client")),
         mPid(pid),
         mTimedTrackCount(0)
 {
@@ -1679,6 +1680,8 @@
             mHardwareStatus = AUDIO_HW_SET_MODE;
             hwDevHal->set_mode(hwDevHal, mMode);
             mHardwareStatus = AUDIO_HW_IDLE;
+
+            mPrimaryOutputSampleRate = config.sample_rate;
         }
         return id;
     }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 29dc6b2..6e73a14 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -50,6 +50,8 @@
 
 #include <media/AudioBufferProvider.h>
 #include <media/ExtendedAudioBufferProvider.h>
+
+#include "FastCapture.h"
 #include "FastMixer.h"
 #include <media/nbaio/NBAIO.h>
 #include "AudioWatchdog.h"
@@ -691,6 +693,9 @@
     nsecs_t mGlobalEffectEnableTime;  // when a global effect was last enabled
 
     sp<PatchPanel> mPatchPanel;
+
+    uint32_t    mPrimaryOutputSampleRate;   // sample rate of the primary output, or zero if none
+                                            // protected by mHardwareLock
 };
 
 #undef INCLUDING_FROM_AUDIOFLINGER_H
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 805eaa4..d73292e 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);
@@ -162,8 +265,8 @@
         // assume default parameters for the track, except where noted below
         track_t* t = &mState.tracks[n];
         t->needs = 0;
-        t->volume[0] = UNITY_GAIN;
-        t->volume[1] = UNITY_GAIN;
+        t->volume[0] = UNITY_GAIN_INT;
+        t->volume[1] = UNITY_GAIN_INT;
         // no initialization needed
         // t->prevVolume[0]
         // t->prevVolume[1]
@@ -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);
 }
@@ -394,6 +536,44 @@
     }
 }
 
+/* Sets the volume ramp variables for the AudioMixer.
+ *
+ * The volume ramp variables are used to transition between the previous
+ * volume to the target volume.  The duration of the transition is
+ * set by ramp, which is either 0 for immediate, or typically one state
+ * framecount period.
+ *
+ * @param newFloatValue new volume target in float [0.0, 1.0].
+ * @param ramp number of frames to increment over. ramp is 0 if the volume
+ * should be set immediately.
+ * @param volume reference to the U4.12 target volume, set on return.
+ * @param prevVolume reference to the U4.27 previous volume, set on return.
+ * @param volumeInc reference to the increment per output audio frame, set on return.
+ * @return true if the volume has changed, false if volume is same.
+ */
+static inline bool setVolumeRampVariables(float newFloatValue, int32_t ramp,
+        int16_t &volume, int32_t &prevVolume, int32_t &volumeInc) {
+    int32_t newValue = newFloatValue * AudioMixer::UNITY_GAIN_INT;
+    if (newValue > AudioMixer::UNITY_GAIN_INT) {
+        newValue = AudioMixer::UNITY_GAIN_INT;
+    } else if (newValue < 0) {
+        ALOGE("negative volume %.7g", newFloatValue);
+        newValue = 0; // should never happen, but for safety check.
+    }
+    if (newValue == volume) {
+        return false;
+    }
+    if (ramp != 0) {
+        volumeInc = ((newValue - volume) << 16) / ramp;
+        prevVolume = (volumeInc == 0 ? newValue : volume) << 16;
+    } else {
+        volumeInc = 0;
+        prevVolume = newValue << 16;
+    }
+    volume = newValue;
+    return true;
+}
+
 void AudioMixer::setParameter(int name, int target, int param, void *value)
 {
     name -= TRACK0;
@@ -435,9 +615,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:
@@ -484,41 +675,23 @@
         switch (param) {
         case VOLUME0:
         case VOLUME1:
-            if (track.volume[param-VOLUME0] != valueInt) {
-                ALOGV("setParameter(VOLUME, VOLUME0/1: %04x)", valueInt);
-                track.prevVolume[param-VOLUME0] = track.volume[param-VOLUME0] << 16;
-                track.volume[param-VOLUME0] = valueInt;
-                if (target == VOLUME) {
-                    track.prevVolume[param-VOLUME0] = valueInt << 16;
-                    track.volumeInc[param-VOLUME0] = 0;
-                } else {
-                    int32_t d = (valueInt<<16) - track.prevVolume[param-VOLUME0];
-                    int32_t volInc = d / int32_t(mState.frameCount);
-                    track.volumeInc[param-VOLUME0] = volInc;
-                    if (volInc == 0) {
-                        track.prevVolume[param-VOLUME0] = valueInt << 16;
-                    }
-                }
+            if (setVolumeRampVariables(*reinterpret_cast<float*>(value),
+                    target == RAMP_VOLUME ? mState.frameCount : 0,
+                    track.volume[param - VOLUME0], track.prevVolume[param - VOLUME0],
+                    track.volumeInc[param - VOLUME0])) {
+                ALOGV("setParameter(%s, VOLUME%d: %04x)",
+                        target == VOLUME ? "VOLUME" : "RAMP_VOLUME", param - VOLUME0,
+                                track.volume[param - VOLUME0]);
                 invalidateState(1 << name);
             }
             break;
         case AUXLEVEL:
             //ALOG_ASSERT(0 <= valueInt && valueInt <= MAX_GAIN_INT, "bad aux level %d", valueInt);
-            if (track.auxLevel != valueInt) {
-                ALOGV("setParameter(VOLUME, AUXLEVEL: %04x)", valueInt);
-                track.prevAuxLevel = track.auxLevel << 16;
-                track.auxLevel = valueInt;
-                if (target == VOLUME) {
-                    track.prevAuxLevel = valueInt << 16;
-                    track.auxInc = 0;
-                } else {
-                    int32_t d = (valueInt<<16) - track.prevAuxLevel;
-                    int32_t volInc = d / int32_t(mState.frameCount);
-                    track.auxInc = volInc;
-                    if (volInc == 0) {
-                        track.prevAuxLevel = valueInt << 16;
-                    }
-                }
+            if (setVolumeRampVariables(*reinterpret_cast<float*>(value),
+                    target == RAMP_VOLUME ? mState.frameCount : 0,
+                    track.auxLevel, track.prevAuxLevel, track.auxInc)) {
+                ALOGV("setParameter(%s, AUXLEVEL: %04x)",
+                        target == VOLUME ? "VOLUME" : "RAMP_VOLUME", track.auxLevel);
                 invalidateState(1 << name);
             }
             break;
@@ -550,8 +723,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 +770,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]);
 }
 
 
@@ -769,7 +938,7 @@
         // always resample with unity gain when sending to auxiliary buffer to be able
         // to apply send level after resampling
         // TODO: modify each resampler to support aux channel?
-        t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
+        t->resampler->setVolume(UNITY_GAIN_INT, UNITY_GAIN_INT);
         memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
         t->resampler->resample(temp, outFrameCount, t->bufferProvider);
         if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc)) {
@@ -779,7 +948,7 @@
         }
     } else {
         if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1])) {
-            t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
+            t->resampler->setVolume(UNITY_GAIN_INT, UNITY_GAIN_INT);
             memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
             t->resampler->resample(temp, outFrameCount, t->bufferProvider);
             volumeRampStereo(t, out, outFrameCount, temp, aux);
@@ -1301,6 +1470,7 @@
     AudioBufferProvider::Buffer& b(t.buffer);
 
     int32_t* out = t.mainBuffer;
+    float *fout = reinterpret_cast<float*>(out);
     size_t numFrames = state->frameCount;
 
     const int16_t vl = t.volume[0];
@@ -1314,9 +1484,10 @@
 
         // in == NULL can happen if the track was flushed just after having
         // been enabled for mixing.
-        if (in == NULL || ((unsigned long)in & 3)) {
-            memset(out, 0, numFrames*MAX_NUM_CHANNELS*sizeof(int16_t));
-            ALOGE_IF(((unsigned long)in & 3), "process stereo track: input buffer alignment pb: "
+        if (in == NULL || (((uintptr_t)in) & 3)) {
+            memset(out, 0, numFrames
+                    * MAX_NUM_CHANNELS * audio_bytes_per_sample(t.mMixerFormat));
+            ALOGE_IF((((uintptr_t)in) & 3), "process stereo track: input buffer alignment pb: "
                                               "buffer %p track %d, channels %d, needs %08x",
                     in, i, t.channelCount, t.needs);
             return;
@@ -1324,8 +1495,7 @@
         size_t outFrames = b.frameCount;
 
         switch (t.mMixerFormat) {
-        case AUDIO_FORMAT_PCM_FLOAT: {
-            float *fout = reinterpret_cast<float*>(out);
+        case AUDIO_FORMAT_PCM_FLOAT:
             do {
                 uint32_t rl = *reinterpret_cast<const uint32_t *>(in);
                 in += 2;
@@ -1336,9 +1506,9 @@
                 // Note: In case of later int16_t sink output,
                 // conversion and clamping is done by memcpy_to_i16_from_float().
             } while (--outFrames);
-            } break;
+            break;
         case AUDIO_FORMAT_PCM_16_BIT:
-            if (CC_UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
+            if (CC_UNLIKELY(uint32_t(vl) > UNITY_GAIN_INT || uint32_t(vr) > UNITY_GAIN_INT)) {
                 // volume is boosted, so we might need to clamp even though
                 // we process only one track.
                 do {
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 09e63a6..766ff60 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -31,7 +31,7 @@
 #include <media/nbaio/NBLog.h>
 
 // FIXME This is actually unity gain, which might not be max in future, expressed in U.12
-#define MAX_GAIN_INT AudioMixer::UNITY_GAIN
+#define MAX_GAIN_INT AudioMixer::UNITY_GAIN_INT
 
 namespace android {
 
@@ -58,7 +58,8 @@
     // maximum number of channels supported for the content
     static const uint32_t MAX_NUM_CHANNELS_TO_DOWNMIX = 8;
 
-    static const uint16_t UNITY_GAIN = 0x1000;
+    static const uint16_t UNITY_GAIN_INT = 0x1000;
+    static const float    UNITY_GAIN_FLOAT = 1.0f;
 
     enum { // names
 
@@ -104,7 +105,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 +126,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 +154,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 +182,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 +205,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 +256,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 +312,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..318eb57 100644
--- a/services/audioflinger/AudioResamplerDyn.cpp
+++ b/services/audioflinger/AudioResamplerDyn.cpp
@@ -455,13 +455,20 @@
     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);
     const uint32_t phaseWrapLimit = c.mL << c.mShift;
+    size_t inFrameCount = (phaseIncrement * (uint64_t)outFrameCount + phaseFraction)
+            / phaseWrapLimit;
+    // sanity check that inFrameCount is in signed 32 bit integer range.
+    ALOG_ASSERT(0 <= inFrameCount && inFrameCount < (1U << 31));
+
+    //ALOGV("inFrameCount:%d  outFrameCount:%d"
+    //        "  phaseIncrement:%u  phaseFraction:%u  phaseWrapLimit:%u",
+    //        inFrameCount, outFrameCount, phaseIncrement, phaseFraction, phaseWrapLimit);
 
     // NOTE: be very careful when modifying the code here. register
     // pressure is very high and a small change might cause the compiler
@@ -471,29 +478,39 @@
     // the following logic is a bit convoluted to keep the main processing loop
     // as tight as possible with register allocation.
     while (outputIndex < outputSampleCount) {
-        // buffer is empty, fetch a new one
-        while (mBuffer.frameCount == 0) {
+        //ALOGV("LOOP: inFrameCount:%d  outputIndex:%d  outFrameCount:%d"
+        //        "  phaseFraction:%u  phaseWrapLimit:%u",
+        //        inFrameCount, outputIndex, outFrameCount, phaseFraction, phaseWrapLimit);
+
+        // check inputIndex overflow
+        ALOG_ASSERT(inputIndex <= mBuffer.frameCount, "inputIndex%d > frameCount%d",
+                inputIndex, mBuffer.frameCount);
+        // Buffer is empty, fetch a new one if necessary (inFrameCount > 0).
+        // We may not fetch a new buffer if the existing data is sufficient.
+        while (mBuffer.frameCount == 0 && inFrameCount > 0) {
             mBuffer.frameCount = inFrameCount;
             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,
                         reinterpret_cast<TI*>(mBuffer.raw), inputIndex);
+                inputIndex++;
                 phaseFraction -= phaseWrapLimit;
                 while (phaseFraction >= phaseWrapLimit) {
-                    inputIndex++;
                     if (inputIndex >= mBuffer.frameCount) {
-                        inputIndex -= mBuffer.frameCount;
+                        inputIndex = 0;
                         provider->releaseBuffer(&mBuffer);
                         break;
                     }
                     mInBuffer.template readAdvance<CHANNELS>(
                             impulse, c.mHalfNumCoefs,
                             reinterpret_cast<TI*>(mBuffer.raw), inputIndex);
+                    inputIndex++;
                     phaseFraction -= phaseWrapLimit;
                 }
             }
@@ -504,9 +521,6 @@
         const int halfNumCoefs = c.mHalfNumCoefs;
         const TO* const volumeSimd = mVolumeSimd;
 
-        // reread the last input in.
-        mInBuffer.template readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
-
         // main processing loop
         while (CC_LIKELY(outputIndex < outputSampleCount)) {
             // caution: fir() is inlined and may be large.
@@ -515,6 +529,10 @@
             // from the input samples in impulse[-halfNumCoefs+1]... impulse[halfNumCoefs]
             // from the polyphase filter of (phaseFraction / phaseWrapLimit) in coefs.
             //
+            //ALOGV("LOOP2: inFrameCount:%d  outputIndex:%d  outFrameCount:%d"
+            //        "  phaseFraction:%u  phaseWrapLimit:%u",
+            //        inFrameCount, outputIndex, outFrameCount, phaseFraction, phaseWrapLimit);
+            ALOG_ASSERT(phaseFraction < phaseWrapLimit);
             fir<CHANNELS, LOCKED, STRIDE>(
                     &out[outputIndex],
                     phaseFraction, phaseWrapLimit,
@@ -524,26 +542,34 @@
 
             phaseFraction += phaseIncrement;
             while (phaseFraction >= phaseWrapLimit) {
-                inputIndex++;
                 if (inputIndex >= frameCount) {
                     goto done;  // need a new buffer
                 }
                 mInBuffer.template readAdvance<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
+                inputIndex++;
                 phaseFraction -= phaseWrapLimit;
             }
         }
 done:
-        // often arrives here when input buffer runs out
-        if (inputIndex >= frameCount) {
-            inputIndex -= frameCount;
+        // We arrive here when we're finished or when the input buffer runs out.
+        // Regardless we need to release the input buffer if we've acquired it.
+        if (inputIndex > 0) {  // we've acquired a buffer (alternatively could check frameCount)
+            ALOG_ASSERT(inputIndex == frameCount, "inputIndex(%d) != frameCount(%d)",
+                    inputIndex, frameCount);  // must have been fully read.
+            inputIndex = 0;
             provider->releaseBuffer(&mBuffer);
-            // mBuffer.frameCount MUST be zero here.
+            ALOG_ASSERT(mBuffer.frameCount == 0);
         }
     }
 
 resample_exit:
+    // inputIndex must be zero in all three cases:
+    // (1) the buffer never was been acquired; (2) the buffer was
+    // released at "done:"; or (3) getNextBuffer() failed.
+    ALOG_ASSERT(inputIndex == 0, "Releasing: inputindex:%d frameCount:%d  phaseFraction:%u",
+            inputIndex, mBuffer.frameCount, phaseFraction);
+    ALOG_ASSERT(mBuffer.frameCount == 0); // there must be no frames in the buffer
     mInBuffer.setImpulse(impulse);
-    mInputIndex = inputIndex;
     mPhaseFraction = phaseFraction;
 }
 
diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp
new file mode 100644
index 0000000..0c9b976
--- /dev/null
+++ b/services/audioflinger/FastCapture.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "FastCapture"
+//#define LOG_NDEBUG 0
+
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+
+#include "Configuration.h"
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#include <media/AudioBufferProvider.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include "FastCapture.h"
+
+namespace android {
+
+/*static*/ const FastCaptureState FastCapture::initial;
+
+FastCapture::FastCapture() : FastThread(),
+    inputSource(NULL), inputSourceGen(0), pipeSink(NULL), pipeSinkGen(0),
+    readBuffer(NULL), readBufferState(-1), format(Format_Invalid), sampleRate(0),
+    // dummyDumpState
+    totalNativeFramesRead(0)
+{
+    previous = &initial;
+    current = &initial;
+
+    mDummyDumpState = &dummyDumpState;
+}
+
+FastCapture::~FastCapture()
+{
+}
+
+FastCaptureStateQueue* FastCapture::sq()
+{
+    return &mSQ;
+}
+
+const FastThreadState *FastCapture::poll()
+{
+    return mSQ.poll();
+}
+
+void FastCapture::setLog(NBLog::Writer *logWriter __unused)
+{
+}
+
+void FastCapture::onIdle()
+{
+    preIdle = *(const FastCaptureState *)current;
+    current = &preIdle;
+}
+
+void FastCapture::onExit()
+{
+    delete[] readBuffer;
+}
+
+bool FastCapture::isSubClassCommand(FastThreadState::Command command)
+{
+    switch ((FastCaptureState::Command) command) {
+    case FastCaptureState::READ:
+    case FastCaptureState::WRITE:
+    case FastCaptureState::READ_WRITE:
+        return true;
+    default:
+        return false;
+    }
+}
+
+void FastCapture::onStateChange()
+{
+    const FastCaptureState * const current = (const FastCaptureState *) this->current;
+    const FastCaptureState * const previous = (const FastCaptureState *) this->previous;
+    FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) this->dumpState;
+    const size_t frameCount = current->mFrameCount;
+
+    bool eitherChanged = false;
+
+    // check for change in input HAL configuration
+    NBAIO_Format previousFormat = format;
+    if (current->mInputSourceGen != inputSourceGen) {
+        inputSource = current->mInputSource;
+        inputSourceGen = current->mInputSourceGen;
+        if (inputSource == NULL) {
+            format = Format_Invalid;
+            sampleRate = 0;
+        } else {
+            format = inputSource->format();
+            sampleRate = Format_sampleRate(format);
+            unsigned channelCount = Format_channelCount(format);
+            ALOG_ASSERT(channelCount == 1 || channelCount == 2);
+        }
+        dumpState->mSampleRate = sampleRate;
+        eitherChanged = true;
+    }
+
+    // check for change in pipe
+    if (current->mPipeSinkGen != pipeSinkGen) {
+        pipeSink = current->mPipeSink;
+        pipeSinkGen = current->mPipeSinkGen;
+        eitherChanged = true;
+    }
+
+    // input source and pipe sink must be compatible
+    if (eitherChanged && inputSource != NULL && pipeSink != NULL) {
+        ALOG_ASSERT(Format_isEqual(format, pipeSink->format()));
+    }
+
+    if ((!Format_isEqual(format, previousFormat)) || (frameCount != previous->mFrameCount)) {
+        // FIXME to avoid priority inversion, don't delete here
+        delete[] readBuffer;
+        readBuffer = 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 capture thread allocate for
+            //       us to avoid blocking here and to prevent possible priority inversion
+            unsigned channelCount = Format_channelCount(format);
+            // FIXME frameSize
+            readBuffer = new short[frameCount * channelCount];
+            periodNs = (frameCount * 1000000000LL) / sampleRate;    // 1.00
+            underrunNs = (frameCount * 1750000000LL) / sampleRate;  // 1.75
+            overrunNs = (frameCount * 500000000LL) / sampleRate;    // 0.50
+            forceNs = (frameCount * 950000000LL) / sampleRate;      // 0.95
+            warmupNs = (frameCount * 500000000LL) / sampleRate;     // 0.50
+        } else {
+            periodNs = 0;
+            underrunNs = 0;
+            overrunNs = 0;
+            forceNs = 0;
+            warmupNs = 0;
+        }
+        readBufferState = -1;
+        dumpState->mFrameCount = frameCount;
+    }
+
+}
+
+void FastCapture::onWork()
+{
+    const FastCaptureState * const current = (const FastCaptureState *) this->current;
+    FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) this->dumpState;
+    const FastCaptureState::Command command = this->command;
+    const size_t frameCount = current->mFrameCount;
+
+    if ((command & FastCaptureState::READ) /*&& isWarm*/) {
+        ALOG_ASSERT(inputSource != NULL);
+        ALOG_ASSERT(readBuffer != NULL);
+        dumpState->mReadSequence++;
+        ATRACE_BEGIN("read");
+        ssize_t framesRead = inputSource->read(readBuffer, frameCount,
+                AudioBufferProvider::kInvalidPTS);
+        ATRACE_END();
+        dumpState->mReadSequence++;
+        if (framesRead >= 0) {
+            LOG_ALWAYS_FATAL_IF((size_t) framesRead > frameCount);
+            totalNativeFramesRead += framesRead;
+            dumpState->mFramesRead = totalNativeFramesRead;
+            readBufferState = framesRead;
+        } else {
+            dumpState->mReadErrors++;
+            readBufferState = 0;
+        }
+        // FIXME rename to attemptedIO
+        attemptedWrite = true;
+    }
+
+    if (command & FastCaptureState::WRITE) {
+        ALOG_ASSERT(pipeSink != NULL);
+        ALOG_ASSERT(readBuffer != NULL);
+        if (readBufferState < 0) {
+            unsigned channelCount = Format_channelCount(format);
+            // FIXME frameSize
+            memset(readBuffer, 0, frameCount * channelCount * sizeof(short));
+            readBufferState = frameCount;
+        }
+        if (readBufferState > 0) {
+            ssize_t framesWritten = pipeSink->write(readBuffer, readBufferState);
+            // FIXME This supports at most one fast capture client.
+            //       To handle multiple clients this could be converted to an array,
+            //       or with a lot more work the control block could be shared by all clients.
+            audio_track_cblk_t* cblk = current->mCblk;
+            if (cblk != NULL && framesWritten > 0) {
+                int32_t rear = cblk->u.mStreaming.mRear;
+                android_atomic_release_store(framesWritten + rear, &cblk->u.mStreaming.mRear);
+                cblk->mServer += framesWritten;
+                int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
+                if (!(old & CBLK_FUTEX_WAKE)) {
+                    // client is never in server process, so don't use FUTEX_WAKE_PRIVATE
+                    (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, 1);
+                }
+            }
+        }
+    }
+}
+
+FastCaptureDumpState::FastCaptureDumpState() : FastThreadDumpState(),
+    mReadSequence(0), mFramesRead(0), mReadErrors(0), mSampleRate(0), mFrameCount(0)
+{
+}
+
+FastCaptureDumpState::~FastCaptureDumpState()
+{
+}
+
+}   // namespace android
diff --git a/services/audioflinger/FastCapture.h b/services/audioflinger/FastCapture.h
new file mode 100644
index 0000000..e535b9d
--- /dev/null
+++ b/services/audioflinger/FastCapture.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_FAST_CAPTURE_H
+#define ANDROID_AUDIO_FAST_CAPTURE_H
+
+#include "FastThread.h"
+#include "StateQueue.h"
+#include "FastCaptureState.h"
+
+namespace android {
+
+typedef StateQueue<FastCaptureState> FastCaptureStateQueue;
+
+struct FastCaptureDumpState : FastThreadDumpState {
+    FastCaptureDumpState();
+    /*virtual*/ ~FastCaptureDumpState();
+
+    // FIXME by renaming, could pull up many of these to FastThreadDumpState
+    uint32_t mReadSequence;     // incremented before and after each read()
+    uint32_t mFramesRead;       // total number of frames read successfully
+    uint32_t mReadErrors;       // total number of read() errors
+    uint32_t mSampleRate;
+    size_t   mFrameCount;
+};
+
+class FastCapture : public FastThread {
+
+public:
+            FastCapture();
+    virtual ~FastCapture();
+
+            FastCaptureStateQueue*  sq();
+
+private:
+            FastCaptureStateQueue   mSQ;
+
+    // callouts
+    virtual const FastThreadState *poll();
+    virtual void setLog(NBLog::Writer *logWriter);
+    virtual void onIdle();
+    virtual void onExit();
+    virtual bool isSubClassCommand(FastThreadState::Command command);
+    virtual void onStateChange();
+    virtual void onWork();
+
+    static const FastCaptureState initial;
+    FastCaptureState preIdle; // copy of state before we went into idle
+    // FIXME by renaming, could pull up many of these to FastThread
+    NBAIO_Source *inputSource;
+    int inputSourceGen;
+    NBAIO_Sink *pipeSink;
+    int pipeSinkGen;
+    short *readBuffer;
+    ssize_t readBufferState;    // number of initialized frames in readBuffer, or -1 to clear
+    NBAIO_Format format;
+    unsigned sampleRate;
+    FastCaptureDumpState dummyDumpState;
+    uint32_t totalNativeFramesRead; // copied to dumpState->mFramesRead
+
+};  // class FastCapture
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_FAST_CAPTURE_H
diff --git a/services/audioflinger/FastCaptureState.cpp b/services/audioflinger/FastCaptureState.cpp
new file mode 100644
index 0000000..1d029b7
--- /dev/null
+++ b/services/audioflinger/FastCaptureState.cpp
@@ -0,0 +1,30 @@
+/*
+ * 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 "FastCaptureState.h"
+
+namespace android {
+
+FastCaptureState::FastCaptureState() : FastThreadState(),
+    mInputSource(NULL), mInputSourceGen(0), mPipeSink(NULL), mPipeSinkGen(0), mFrameCount(0)
+{
+}
+
+FastCaptureState::~FastCaptureState()
+{
+}
+
+}   // android
diff --git a/services/audioflinger/FastCaptureState.h b/services/audioflinger/FastCaptureState.h
new file mode 100644
index 0000000..29c865a
--- /dev/null
+++ b/services/audioflinger/FastCaptureState.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_FAST_CAPTURE_STATE_H
+#define ANDROID_AUDIO_FAST_CAPTURE_STATE_H
+
+#include <media/nbaio/NBAIO.h>
+#include "FastThreadState.h"
+#include <private/media/AudioTrackShared.h>
+
+namespace android {
+
+// Represent a single state of the fast capture
+struct FastCaptureState : FastThreadState {
+                FastCaptureState();
+    /*virtual*/ ~FastCaptureState();
+
+    // all pointer fields use raw pointers; objects are owned and ref-counted by RecordThread
+    NBAIO_Source    *mInputSource;      // HAL input device, must already be negotiated
+    // FIXME by renaming, could pull up these fields to FastThreadState
+    int             mInputSourceGen;    // increment when mInputSource is assigned
+    NBAIO_Sink      *mPipeSink;         // after reading from input source, write to this pipe sink
+    int             mPipeSinkGen;       // increment when mPipeSink is assigned
+    size_t          mFrameCount;        // number of frames per fast capture buffer
+    audio_track_cblk_t  *mCblk;         // control block for the single fast client, or NULL
+
+    // Extends FastThreadState::Command
+    static const Command
+        // The following commands also process configuration changes, and can be "or"ed:
+        READ = 0x8,             // read from input source
+        WRITE = 0x10,           // write to pipe sink
+        READ_WRITE = 0x18;      // read from input source and write to pipe sink
+
+};  // struct FastCaptureState
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_FAST_CAPTURE_STATE_H
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 1caed11..c9a3f10 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -37,6 +37,7 @@
 #include <cpustats/ThreadCpuUsage.h>
 #endif
 #endif
+#include <audio_utils/format.h>
 #include "AudioMixer.h"
 #include "FastMixer.h"
 
@@ -53,8 +54,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 +114,8 @@
 void FastMixer::onExit()
 {
     delete mixer;
-    delete[] mixBuffer;
+    free(mMixerBuffer);
+    free(mSinkBuffer);
 }
 
 bool FastMixer::isSubClassCommand(FastThreadState::Command command)
@@ -155,14 +161,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 +190,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 +208,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 +239,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;
@@ -252,13 +274,18 @@
                     ALOG_ASSERT(name >= 0);
                     mixer->setBufferProvider(name, bufferProvider);
                     if (fastTrack->mVolumeProvider == NULL) {
-                        mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0,
-                                (void *) MAX_GAIN_INT);
-                        mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1,
-                                (void *) MAX_GAIN_INT);
+                        float f = AudioMixer::UNITY_GAIN_FLOAT;
+                        mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &f);
+                        mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &f);
                     }
                     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) {
@@ -309,12 +336,11 @@
             ALOG_ASSERT(name >= 0);
             if (fastTrack->mVolumeProvider != NULL) {
                 gain_minifloat_packed_t vlr = fastTrack->mVolumeProvider->getVolumeLR();
-                mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0,
-                        (void *) (uintptr_t)
-                            (float_from_gain(gain_minifloat_unpack_left(vlr)) * MAX_GAIN_INT));
-                mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1,
-                        (void *) (uintptr_t)
-                            (float_from_gain(gain_minifloat_unpack_right(vlr)) * MAX_GAIN_INT));
+                float vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
+                float vrf = float_from_gain(gain_minifloat_unpack_right(vlr));
+
+                mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &vlf);
+                mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &vrf);
             }
             // FIXME The current implementation of framesReady() for fast tracks
             // takes a tryLock, which can block
@@ -358,26 +384,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) {
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/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 02b5094..6d84296 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -235,7 +235,7 @@
                 param.addInt(String8(AudioParameter::keyInputSource),
                                                      (int)patch->sinks[0].ext.mix.usecase.source);
 
-                ALOGW("createAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s",
+                ALOGV("createAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s",
                                                                       param.toString().string());
                 status = thread->setParameters(param.toString());
             }
@@ -354,7 +354,7 @@
                 }
                 AudioParameter param;
                 param.addInt(String8(AudioParameter::keyRouting), 0);
-                ALOGW("releaseAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s",
+                ALOGV("releaseAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s",
                                                                       param.toString().string());
                 status = thread->setParameters(param.toString());
             }
diff --git a/services/audioflinger/ServiceUtilities.cpp b/services/audioflinger/ServiceUtilities.cpp
index 152455d..8246fef 100644
--- a/services/audioflinger/ServiceUtilities.cpp
+++ b/services/audioflinger/ServiceUtilities.cpp
@@ -59,6 +59,13 @@
     return ok;
 }
 
+bool modifyAudioRoutingAllowed() {
+    static const String16 sModifyAudioRoutingAllowed("android.permission.MODIFY_AUDIO_ROUTING");
+    bool ok = checkCallingPermission(sModifyAudioRoutingAllowed);
+    if (!ok) ALOGE("android.permission.MODIFY_AUDIO_ROUTING");
+    return ok;
+}
+
 bool dumpAllowed() {
     // don't optimize for same pid, since mediaserver never dumps itself
     static const String16 sDump("android.permission.DUMP");
diff --git a/services/audioflinger/ServiceUtilities.h b/services/audioflinger/ServiceUtilities.h
index 531bc56..df6f6f4 100644
--- a/services/audioflinger/ServiceUtilities.h
+++ b/services/audioflinger/ServiceUtilities.h
@@ -24,6 +24,7 @@
 bool captureAudioOutputAllowed();
 bool captureHotwordAllowed();
 bool settingsAllowed();
+bool modifyAudioRoutingAllowed();
 bool dumpAllowed();
 
 }
diff --git a/services/audioflinger/StateQueueInstantiations.cpp b/services/audioflinger/StateQueueInstantiations.cpp
index 0d5cd0c..6f4505e 100644
--- a/services/audioflinger/StateQueueInstantiations.cpp
+++ b/services/audioflinger/StateQueueInstantiations.cpp
@@ -16,12 +16,14 @@
 
 #include "Configuration.h"
 #include "FastMixerState.h"
+#include "FastCaptureState.h"
 #include "StateQueue.h"
 
 // FIXME hack for gcc
 
 namespace android {
 
-template class StateQueue<FastMixerState>;  // typedef FastMixerStateQueue
+template class StateQueue<FastMixerState>;      // typedef FastMixerStateQueue
+template class StateQueue<FastCaptureState>;    // typedef FastCaptureStateQueue
 
 }
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 4972c7a..d6333be 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -38,6 +38,7 @@
 #include <audio_utils/minifloat.h>
 
 // NBAIO implementations
+#include <media/nbaio/AudioStreamInSource.h>
 #include <media/nbaio/AudioStreamOutSink.h>
 #include <media/nbaio/MonoPipe.h>
 #include <media/nbaio/MonoPipeReader.h>
@@ -53,6 +54,7 @@
 #include "AudioFlinger.h"
 #include "AudioMixer.h"
 #include "FastMixer.h"
+#include "FastCapture.h"
 #include "ServiceUtilities.h"
 #include "SchedulingPolicyService.h"
 
@@ -131,9 +133,17 @@
     //  up large writes into smaller ones, and the wrapper would need to deal with scheduler.
 } kUseFastMixer = FastMixer_Static;
 
+// Whether to use fast capture
+static const enum {
+    FastCapture_Never,  // never initialize or use: for debugging only
+    FastCapture_Always, // always initialize and use, even if not needed: for debugging only
+    FastCapture_Static, // initialize if needed, then use all the time if initialized
+} kUseFastCapture = FastCapture_Static;
+
 // Priorities for requestPriority
 static const int kPriorityAudioApp = 2;
 static const int kPriorityFastMixer = 3;
+static const int kPriorityFastCapture = 3;
 
 // IAudioFlinger::createTrack() reports back to client the total size of shared memory area
 // for the track.  The client then sub-divides this into smaller buffers for its use.
@@ -142,8 +152,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 +171,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) {
@@ -1356,7 +1391,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 +2755,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 +2816,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 +3270,7 @@
                     fastTrack->mBufferProvider = eabp;
                     fastTrack->mVolumeProvider = vp;
                     fastTrack->mChannelMask = track->mChannelMask;
+                    fastTrack->mFormat = track->mFormat;
                     fastTrack->mGeneration++;
                     state->mTrackMask |= 1 << j;
                     didModify = true;
@@ -3319,9 +3380,11 @@
             }
 
             // compute volume for this track
-            uint32_t vl, vr, va;
+            uint32_t vl, vr;       // in U8.24 integer format
+            float vlf, vrf, vaf;   // in [0.0, 1.0] float format
             if (track->isPausing() || mStreamTypes[track->streamType()].mute) {
-                vl = vr = va = 0;
+                vl = vr = 0;
+                vlf = vrf = vaf = 0.;
                 if (track->isPausing()) {
                     track->setPaused();
                 }
@@ -3332,8 +3395,8 @@
                 float v = masterVolume * typeVolume;
                 AudioTrackServerProxy *proxy = track->mAudioTrackServerProxy;
                 gain_minifloat_packed_t vlr = proxy->getVolumeLR();
-                float vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
-                float vrf = float_from_gain(gain_minifloat_unpack_right(vlr));
+                vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
+                vrf = float_from_gain(gain_minifloat_unpack_right(vlr));
                 // track volumes come from shared memory, so can't be trusted and must be clamped
                 if (vlf > GAIN_FLOAT_UNITY) {
                     ALOGV("Track left volume out of range: %.3g", vlf);
@@ -3344,20 +3407,22 @@
                     vrf = GAIN_FLOAT_UNITY;
                 }
                 // now apply the master volume and stream type volume
-                // FIXME we're losing the wonderful dynamic range in the minifloat representation
-                float v8_24 = v * (MAX_GAIN_INT * MAX_GAIN_INT);
-                vl = (uint32_t) (v8_24 * vlf);
-                vr = (uint32_t) (v8_24 * vrf);
+                vlf *= v;
+                vrf *= v;
                 // assuming master volume and stream type volume each go up to 1.0,
-                // vl and vr are now in 8.24 format
-
+                // then derive vl and vr as U8.24 versions for the effect chain
+                const float scaleto8_24 = MAX_GAIN_INT * MAX_GAIN_INT;
+                vl = (uint32_t) (scaleto8_24 * vlf);
+                vr = (uint32_t) (scaleto8_24 * vrf);
+                // vl and vr are now in U8.24 format
                 uint16_t sendLevel = proxy->getSendLevel_U4_12();
                 // send level comes from shared memory and so may be corrupt
                 if (sendLevel > MAX_GAIN_INT) {
                     ALOGV("Track send level out of range: %04X", sendLevel);
                     sendLevel = MAX_GAIN_INT;
                 }
-                va = (uint32_t)(v * sendLevel);
+                // vaf is represented as [0.0, 1.0] float by rescaling sendLevel
+                vaf = v * sendLevel * (1. / MAX_GAIN_INT);
             }
 
             // Delegate volume control to effect in track effect chain if needed
@@ -3374,29 +3439,13 @@
                 track->mHasVolumeController = false;
             }
 
-            // FIXME Use float
-            // Convert volumes from 8.24 to 4.12 format
-            // This additional clamping is needed in case chain->setVolume_l() overshot
-            vl = (vl + (1 << 11)) >> 12;
-            if (vl > MAX_GAIN_INT) {
-                vl = MAX_GAIN_INT;
-            }
-            vr = (vr + (1 << 11)) >> 12;
-            if (vr > MAX_GAIN_INT) {
-                vr = MAX_GAIN_INT;
-            }
-
-            if (va > MAX_GAIN_INT) {
-                va = MAX_GAIN_INT;   // va is uint32_t, so no need to check for -
-            }
-
             // XXX: these things DON'T need to be done each time
             mAudioMixer->setBufferProvider(name, track);
             mAudioMixer->enable(name);
 
-            mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, (void *)(uintptr_t)vl);
-            mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, (void *)(uintptr_t)vr);
-            mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, (void *)(uintptr_t)va);
+            mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, &vlf);
+            mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, &vrf);
+            mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, &vaf);
             mAudioMixer->setParameter(
                 name,
                 AudioMixer::TRACK,
@@ -3601,9 +3650,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 +3766,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;
                 }
@@ -4007,7 +4058,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;
 }
@@ -4708,16 +4759,151 @@
 #endif
     , mReadOnlyHeap(new MemoryDealer(kRecordThreadReadOnlyHeapSize,
             "RecordThreadRO", MemoryHeapBase::READ_ONLY))
+    // mFastCapture below
+    , mFastCaptureFutex(0)
+    // mInputSource
+    // mPipeSink
+    // mPipeSource
+    , mPipeFramesP2(0)
+    // mPipeMemory
+    // mFastCaptureNBLogWriter
+    , mFastTrackAvail(true)
 {
     snprintf(mName, kNameLength, "AudioIn_%X", id);
     mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mName);
 
     readInputParameters_l();
+
+    // create an NBAIO source for the HAL input stream, and negotiate
+    mInputSource = new AudioStreamInSource(input->stream);
+    size_t numCounterOffers = 0;
+    const NBAIO_Format offers[1] = {Format_from_SR_C(mSampleRate, mChannelCount, mFormat)};
+    ssize_t index = mInputSource->negotiate(offers, 1, NULL, numCounterOffers);
+    ALOG_ASSERT(index == 0);
+
+    // initialize fast capture depending on configuration
+    bool initFastCapture;
+    switch (kUseFastCapture) {
+    case FastCapture_Never:
+        initFastCapture = false;
+        break;
+    case FastCapture_Always:
+        initFastCapture = true;
+        break;
+    case FastCapture_Static:
+        uint32_t primaryOutputSampleRate;
+        {
+            AutoMutex _l(audioFlinger->mHardwareLock);
+            primaryOutputSampleRate = audioFlinger->mPrimaryOutputSampleRate;
+        }
+        initFastCapture =
+                // either capture sample rate is same as (a reasonable) primary output sample rate
+                (((primaryOutputSampleRate == 44100 || primaryOutputSampleRate == 48000) &&
+                    (mSampleRate == primaryOutputSampleRate)) ||
+                // or primary output sample rate is unknown, and capture sample rate is reasonable
+                ((primaryOutputSampleRate == 0) &&
+                    ((mSampleRate == 44100 || mSampleRate == 48000)))) &&
+                // and the buffer size is < 10 ms
+                (mFrameCount * 1000) / mSampleRate < 10;
+        break;
+    // case FastCapture_Dynamic:
+    }
+
+    if (initFastCapture) {
+        // create a Pipe for FastMixer to write to, and for us and fast tracks to read from
+        NBAIO_Format format = mInputSource->format();
+        size_t pipeFramesP2 = roundup(mFrameCount * 8);
+        size_t pipeSize = pipeFramesP2 * Format_frameSize(format);
+        void *pipeBuffer;
+        const sp<MemoryDealer> roHeap(readOnlyHeap());
+        sp<IMemory> pipeMemory;
+        if ((roHeap == 0) ||
+                (pipeMemory = roHeap->allocate(pipeSize)) == 0 ||
+                (pipeBuffer = pipeMemory->pointer()) == NULL) {
+            ALOGE("not enough memory for pipe buffer size=%zu", pipeSize);
+            goto failed;
+        }
+        // pipe will be shared directly with fast clients, so clear to avoid leaking old information
+        memset(pipeBuffer, 0, pipeSize);
+        Pipe *pipe = new Pipe(pipeFramesP2, format, pipeBuffer);
+        const NBAIO_Format offers[1] = {format};
+        size_t numCounterOffers = 0;
+        ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers);
+        ALOG_ASSERT(index == 0);
+        mPipeSink = pipe;
+        PipeReader *pipeReader = new PipeReader(*pipe);
+        numCounterOffers = 0;
+        index = pipeReader->negotiate(offers, 1, NULL, numCounterOffers);
+        ALOG_ASSERT(index == 0);
+        mPipeSource = pipeReader;
+        mPipeFramesP2 = pipeFramesP2;
+        mPipeMemory = pipeMemory;
+
+        // create fast capture
+        mFastCapture = new FastCapture();
+        FastCaptureStateQueue *sq = mFastCapture->sq();
+#ifdef STATE_QUEUE_DUMP
+        // FIXME
+#endif
+        FastCaptureState *state = sq->begin();
+        state->mCblk = NULL;
+        state->mInputSource = mInputSource.get();
+        state->mInputSourceGen++;
+        state->mPipeSink = pipe;
+        state->mPipeSinkGen++;
+        state->mFrameCount = mFrameCount;
+        state->mCommand = FastCaptureState::COLD_IDLE;
+        // already done in constructor initialization list
+        //mFastCaptureFutex = 0;
+        state->mColdFutexAddr = &mFastCaptureFutex;
+        state->mColdGen++;
+        state->mDumpState = &mFastCaptureDumpState;
+#ifdef TEE_SINK
+        // FIXME
+#endif
+        mFastCaptureNBLogWriter = audioFlinger->newWriter_l(kFastCaptureLogSize, "FastCapture");
+        state->mNBLogWriter = mFastCaptureNBLogWriter.get();
+        sq->end();
+        sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);
+
+        // start the fast capture
+        mFastCapture->run("FastCapture", ANDROID_PRIORITY_URGENT_AUDIO);
+        pid_t tid = mFastCapture->getTid();
+        int err = requestPriority(getpid_cached, tid, kPriorityFastMixer);
+        if (err != 0) {
+            ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
+                    kPriorityFastCapture, getpid_cached, tid, err);
+        }
+
+#ifdef AUDIO_WATCHDOG
+        // FIXME
+#endif
+
+    }
+failed: ;
+
+    // FIXME mNormalSource
 }
 
 
 AudioFlinger::RecordThread::~RecordThread()
 {
+    if (mFastCapture != 0) {
+        FastCaptureStateQueue *sq = mFastCapture->sq();
+        FastCaptureState *state = sq->begin();
+        if (state->mCommand == FastCaptureState::COLD_IDLE) {
+            int32_t old = android_atomic_inc(&mFastCaptureFutex);
+            if (old == -1) {
+                (void) syscall(__NR_futex, &mFastCaptureFutex, FUTEX_WAKE_PRIVATE, 1);
+            }
+        }
+        state->mCommand = FastCaptureState::EXIT;
+        sq->end();
+        sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);
+        mFastCapture->join();
+        mFastCapture.clear();
+    }
+    mAudioFlinger->unregisterWriter(mFastCaptureNBLogWriter);
     mAudioFlinger->unregisterWriter(mNBLogWriter);
     delete[] mRsmpInBuffer;
 }
@@ -4772,6 +4958,8 @@
         // activeTracks accumulates a copy of a subset of mActiveTracks
         Vector< sp<RecordTrack> > activeTracks;
 
+        // reference to the (first and only) fast track
+        sp<RecordTrack> fastTrack;
 
         { // scope for mLock
             Mutex::Autolock _l(mLock);
@@ -4853,6 +5041,11 @@
                 activeTracks.add(activeTrack);
                 i++;
 
+                if (activeTrack->isFastTrack()) {
+                    ALOG_ASSERT(!mFastTrackAvail);
+                    ALOG_ASSERT(fastTrack == 0);
+                    fastTrack = activeTrack;
+                }
             }
             if (doBroadcast) {
                 mStartStopCond.broadcast();
@@ -4878,6 +5071,36 @@
             effectChains[i]->process_l();
         }
 
+        // Start the fast capture if it's not already running
+        if (mFastCapture != 0) {
+            FastCaptureStateQueue *sq = mFastCapture->sq();
+            FastCaptureState *state = sq->begin();
+            if (state->mCommand != FastCaptureState::READ_WRITE /* FIXME &&
+                    (kUseFastMixer != FastMixer_Dynamic || state->mTrackMask > 1)*/) {
+                if (state->mCommand == FastCaptureState::COLD_IDLE) {
+                    int32_t old = android_atomic_inc(&mFastCaptureFutex);
+                    if (old == -1) {
+                        (void) syscall(__NR_futex, &mFastCaptureFutex, FUTEX_WAKE_PRIVATE, 1);
+                    }
+                }
+                state->mCommand = FastCaptureState::READ_WRITE;
+#if 0   // FIXME
+                mFastCaptureDumpState.increaseSamplingN(mAudioFlinger->isLowRamDevice() ?
+                        FastCaptureDumpState::kSamplingNforLowRamDevice : FastMixerDumpState::kSamplingN);
+#endif
+                state->mCblk = fastTrack != 0 ? fastTrack->cblk() : NULL;
+                sq->end();
+                sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);
+#if 0
+                if (kUseFastCapture == FastCapture_Dynamic) {
+                    mNormalSource = mPipeSource;
+                }
+#endif
+            } else {
+                sq->end(false /*didModify*/);
+            }
+        }
+
         // Read from HAL to keep up with fastest client if multiple active tracks, not slowest one.
         // Only the client(s) that are too slow will overrun. But if even the fastest client is too
         // slow, then this RecordThread will overrun by not calling HAL read often enough.
@@ -4885,24 +5108,45 @@
         // copy to the right place.  Permitted because mRsmpInBuffer was over-allocated.
 
         int32_t rear = mRsmpInRear & (mRsmpInFramesP2 - 1);
-        ssize_t bytesRead = mInput->stream->read(mInput->stream,
-                &mRsmpInBuffer[rear * mChannelCount], mBufferSize);
-        if (bytesRead <= 0) {
-            ALOGE("read failed: bytesRead=%d < %u", bytesRead, mBufferSize);
+        ssize_t framesRead;
+
+        // If an NBAIO source is present, use it to read the normal capture's data
+        if (mPipeSource != 0) {
+            size_t framesToRead = mBufferSize / mFrameSize;
+            framesRead = mPipeSource->read(&mRsmpInBuffer[rear * mChannelCount],
+                    framesToRead, AudioBufferProvider::kInvalidPTS);
+            if (framesRead == 0) {
+                // since pipe is non-blocking, simulate blocking input
+                sleepUs = (framesToRead * 1000000LL) / mSampleRate;
+            }
+        // otherwise use the HAL / AudioStreamIn directly
+        } else {
+            ssize_t bytesRead = mInput->stream->read(mInput->stream,
+                    &mRsmpInBuffer[rear * mChannelCount], mBufferSize);
+            if (bytesRead < 0) {
+                framesRead = bytesRead;
+            } else {
+                framesRead = bytesRead / mFrameSize;
+            }
+        }
+
+        if (framesRead < 0 || (framesRead == 0 && mPipeSource == 0)) {
+            ALOGE("read failed: framesRead=%d", framesRead);
             // Force input into standby so that it tries to recover at next read attempt
             inputStandBy();
             sleepUs = kRecordThreadSleepUs;
+        }
+        if (framesRead <= 0) {
             continue;
         }
-        ALOG_ASSERT((size_t) bytesRead <= mBufferSize);
-        size_t framesRead = bytesRead / mFrameSize;
         ALOG_ASSERT(framesRead > 0);
+
         if (mTeeSink != 0) {
             (void) mTeeSink->write(&mRsmpInBuffer[rear * mChannelCount], framesRead);
         }
         // If destination is non-contiguous, we now correct for reading past end of buffer.
         size_t part1 = mRsmpInFramesP2 - rear;
-        if (framesRead > part1) {
+        if ((size_t) framesRead > part1) {
             memcpy(mRsmpInBuffer, &mRsmpInBuffer[mRsmpInFramesP2 * mChannelCount],
                     (framesRead - part1) * mFrameSize);
         }
@@ -4913,6 +5157,11 @@
         for (size_t i = 0; i < size; i++) {
             activeTrack = activeTracks[i];
 
+            // skip fast tracks, as those are handled directly by FastCapture
+            if (activeTrack->isFastTrack()) {
+                continue;
+            }
+
             enum {
                 OVERRUN_UNKNOWN,
                 OVERRUN_TRUE,
@@ -5141,6 +5390,30 @@
 
 void AudioFlinger::RecordThread::inputStandBy()
 {
+    // Idle the fast capture if it's currently running
+    if (mFastCapture != 0) {
+        FastCaptureStateQueue *sq = mFastCapture->sq();
+        FastCaptureState *state = sq->begin();
+        if (!(state->mCommand & FastCaptureState::IDLE)) {
+            state->mCommand = FastCaptureState::COLD_IDLE;
+            state->mColdFutexAddr = &mFastCaptureFutex;
+            state->mColdGen++;
+            mFastCaptureFutex = 0;
+            sq->end();
+            // BLOCK_UNTIL_PUSHED would be insufficient, as we need it to stop doing I/O now
+            sq->push(FastCaptureStateQueue::BLOCK_UNTIL_ACKED);
+#if 0
+            if (kUseFastCapture == FastCapture_Dynamic) {
+                // FIXME
+            }
+#endif
+#ifdef AUDIO_WATCHDOG
+            // FIXME
+#endif
+        } else {
+            sq->end(false /*didModify*/);
+        }
+    }
     mInput->stream->common.standby(&mInput->stream->common);
 }
 
@@ -5167,42 +5440,47 @@
             // use case: callback handler and frame count is default or at least as large as HAL
             (
                 (tid != -1) &&
-                ((frameCount == 0) ||
+                ((frameCount == 0) /*||
+                // FIXME must be equal to pipe depth, so don't allow it to be specified by client
                 // FIXME not necessarily true, should be native frame count for native SR!
-                (frameCount >= mFrameCount))
+                (frameCount >= mFrameCount)*/)
             ) &&
             // PCM data
             audio_is_linear_pcm(format) &&
+            // native format
+            (format == mFormat) &&
             // mono or stereo
             ( (channelMask == AUDIO_CHANNEL_IN_MONO) ||
               (channelMask == AUDIO_CHANNEL_IN_STEREO) ) &&
-            // hardware sample rate
-            // FIXME actually the native hardware sample rate
+            // native channel mask
+            (channelMask == mChannelMask) &&
+            // native hardware sample rate
             (sampleRate == mSampleRate) &&
             // record thread has an associated fast capture
-            hasFastCapture()
-            // fast capture does not require slots
+            hasFastCapture() &&
+            // there are sufficient fast track slots available
+            mFastTrackAvail
         ) {
-        // if frameCount not specified, then it defaults to fast capture (HAL) frame count
+        // if frameCount not specified, then it defaults to pipe frame count
         if (frameCount == 0) {
-            // FIXME wrong mFrameCount
-            frameCount = mFrameCount * kFastTrackMultiplier;
+            frameCount = mPipeFramesP2;
         }
         ALOGV("AUDIO_INPUT_FLAG_FAST accepted: frameCount=%d mFrameCount=%d",
                 frameCount, mFrameCount);
       } else {
         ALOGV("AUDIO_INPUT_FLAG_FAST denied: frameCount=%d "
                 "mFrameCount=%d format=%d isLinear=%d channelMask=%#x sampleRate=%u mSampleRate=%u "
-                "hasFastCapture=%d tid=%d",
+                "hasFastCapture=%d tid=%d mFastTrackAvail=%d",
                 frameCount, mFrameCount, format,
                 audio_is_linear_pcm(format),
-                channelMask, sampleRate, mSampleRate, hasFastCapture(), tid);
+                channelMask, sampleRate, mSampleRate, hasFastCapture(), tid, mFastTrackAvail);
         *flags &= ~IAudioFlinger::TRACK_FAST;
         // FIXME It's not clear that we need to enforce this any more, since we have a pipe.
         // For compatibility with AudioRecord calculation, buffer depth is forced
         // 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);
@@ -5424,6 +5702,10 @@
 {
     mTracks.remove(track);
     // need anything related to effects here?
+    if (track->isFastTrack()) {
+        ALOG_ASSERT(!mFastTrackAvail);
+        mFastTrackAvail = true;
+    }
 }
 
 void AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)
@@ -5442,6 +5724,7 @@
     } else {
         fdprintf(fd, "  No active record clients\n");
     }
+    dprintf(fd, "  Fast track available: %s\n", mFastTrackAvail ? "yes" : "no");
 
     dumpBase(fd, args);
 }
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index f8037c6..07887fb 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;
@@ -1059,6 +1064,8 @@
 
     virtual sp<MemoryDealer>    readOnlyHeap() const { return mReadOnlyHeap; }
 
+    virtual sp<IMemory> pipeMemory() const { return mPipeMemory; }
+
             sp<AudioFlinger::RecordThread::RecordTrack>  createRecordTrack_l(
                     const sp<AudioFlinger::Client>& client,
                     uint32_t sampleRate,
@@ -1110,7 +1117,7 @@
     static void syncStartEventCallback(const wp<SyncEvent>& event);
 
     virtual size_t      frameCount() const { return mFrameCount; }
-            bool        hasFastCapture() const { return false; }
+            bool        hasFastCapture() const { return mFastCapture != 0; }
 
 private:
             // Enter standby if not already in standby, and set mStandby flag
@@ -1140,4 +1147,40 @@
             const sp<NBAIO_Sink>                mTeeSink;
 
             const sp<MemoryDealer>              mReadOnlyHeap;
+
+            // one-time initialization, no locks required
+            sp<FastCapture>                     mFastCapture;   // non-0 if there is also a fast capture
+            // FIXME audio watchdog thread
+
+            // contents are not guaranteed to be consistent, no locks required
+            FastCaptureDumpState                mFastCaptureDumpState;
+#ifdef STATE_QUEUE_DUMP
+            // FIXME StateQueue observer and mutator dump fields
+#endif
+            // FIXME audio watchdog dump
+
+            // accessible only within the threadLoop(), no locks required
+            //          mFastCapture->sq()      // for mutating and pushing state
+            int32_t     mFastCaptureFutex;      // for cold idle
+
+            // The HAL input source is treated as non-blocking,
+            // but current implementation is blocking
+            sp<NBAIO_Source>                    mInputSource;
+            // The source for the normal capture thread to read from: mInputSource or mPipeSource
+            sp<NBAIO_Source>                    mNormalSource;
+            // If a fast capture is present, the non-blocking pipe sink written to by fast capture,
+            // otherwise clear
+            sp<NBAIO_Sink>                      mPipeSink;
+            // If a fast capture is present, the non-blocking pipe source read by normal thread,
+            // otherwise clear
+            sp<NBAIO_Source>                    mPipeSource;
+            // Depth of pipe from fast capture to normal thread and fast clients, always power of 2
+            size_t                              mPipeFramesP2;
+            // If a fast capture is present, the Pipe as IMemory, otherwise clear
+            sp<IMemory>                         mPipeMemory;
+
+            static const size_t                 kFastCaptureLogSize = 4 * 1024;
+            sp<NBLog::Writer>                   mFastCaptureNBLogWriter;
+
+            bool                                mFastTrackAvail;    // true if fast track available
 };
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 cf71d65..4e8a058 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
@@ -388,7 +400,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;
@@ -1869,7 +1881,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 ? ALLOC_PIPE : 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)
@@ -1888,9 +1900,14 @@
         mResampler = AudioResampler::create(16, thread->mChannelCount, sampleRate);
         // source SR
         mResampler->setSampleRate(thread->mSampleRate);
-        mResampler->setVolume(AudioMixer::UNITY_GAIN, AudioMixer::UNITY_GAIN);
+        mResampler->setVolume(AudioMixer::UNITY_GAIN_INT, AudioMixer::UNITY_GAIN_INT);
         mResamplerBufferProvider = new ResamplerBufferProvider(this);
     }
+
+    if (flags & IAudioFlinger::TRACK_FAST) {
+        ALOG_ASSERT(thread->mFastTrackAvail);
+        thread->mFastTrackAvail = false;
+    }
 }
 
 AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
diff --git a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
index 2b33703..8cc386a 100644
--- a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
@@ -470,6 +470,9 @@
                                             unsigned int *generation)
 {
     Mutex::Autolock _l(mLock);
+    if(!modifyAudioRoutingAllowed()) {
+        return PERMISSION_DENIED;
+    }
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
@@ -480,6 +483,9 @@
 status_t AudioPolicyService::getAudioPort(struct audio_port *port)
 {
     Mutex::Autolock _l(mLock);
+    if(!modifyAudioRoutingAllowed()) {
+        return PERMISSION_DENIED;
+    }
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
@@ -491,6 +497,9 @@
         audio_patch_handle_t *handle)
 {
     Mutex::Autolock _l(mLock);
+    if(!modifyAudioRoutingAllowed()) {
+        return PERMISSION_DENIED;
+    }
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
@@ -501,6 +510,9 @@
 status_t AudioPolicyService::releaseAudioPatch(audio_patch_handle_t handle)
 {
     Mutex::Autolock _l(mLock);
+    if(!modifyAudioRoutingAllowed()) {
+        return PERMISSION_DENIED;
+    }
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
@@ -514,6 +526,9 @@
         unsigned int *generation)
 {
     Mutex::Autolock _l(mLock);
+    if(!modifyAudioRoutingAllowed()) {
+        return PERMISSION_DENIED;
+    }
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
@@ -524,6 +539,9 @@
 status_t AudioPolicyService::setAudioPortConfig(const struct audio_port_config *config)
 {
     Mutex::Autolock _l(mLock);
+    if(!modifyAudioRoutingAllowed()) {
+        return PERMISSION_DENIED;
+    }
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index 8c3af5b..61edac2 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -223,7 +223,7 @@
             index = mAvailableOutputDevices.add(devDesc);
             if (index >= 0) {
                 mAvailableOutputDevices[index]->mId = nextUniqueId();
-                HwModule *module = getModuleForDevice(device);
+                sp<HwModule> module = getModuleForDevice(device);
                 ALOG_ASSERT(module != NULL, "setDeviceConnectionState():"
                         "could not find HW module for device %08x", device);
                 mAvailableOutputDevices[index]->mModule = module;
@@ -260,7 +260,7 @@
         // outputs must be closed after checkOutputForAllStrategies() is executed
         if (!outputs.isEmpty()) {
             for (size_t i = 0; i < outputs.size(); i++) {
-                AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]);
+                sp<AudioOutputDescriptor> desc = mOutputs.valueFor(outputs[i]);
                 // close unused outputs after device disconnection or direct outputs that have been
                 // opened by checkOutputsForDevice() to query dynamic parameters
                 if ((state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) ||
@@ -311,7 +311,7 @@
                 ALOGW("setDeviceConnectionState() device already connected: %d", device);
                 return INVALID_OPERATION;
             }
-            HwModule *module = getModuleForDevice(device);
+            sp<HwModule> module = getModuleForDevice(device);
             if (module == NULL) {
                 ALOGW("setDeviceConnectionState(): could not find HW module for device %08x",
                       device);
@@ -442,7 +442,7 @@
     checkOutputForAllStrategies();
     updateDevicesAndOutputs();
 
-    AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mPrimaryOutput);
+    sp<AudioOutputDescriptor> hwOutputDesc = mOutputs.valueFor(mPrimaryOutput);
 
     // force routing command to audio hardware when ending call
     // even if no device change is needed
@@ -454,7 +454,7 @@
     if (isStateInCall(state)) {
         nsecs_t sysTime = systemTime();
         for (size_t i = 0; i < mOutputs.size(); i++) {
-            AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+            sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
             // mute media and sonification strategies and delay device switch by the largest
             // latency of any output where either strategy is active.
             // This avoid sending the ring tone or music tail into the earpiece or headset.
@@ -644,7 +644,7 @@
 
         if (mTestOutputs[mCurOutput] == 0) {
             ALOGV("getOutput() opening test output");
-            AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(NULL);
+            sp<AudioOutputDescriptor> outputDesc = new AudioOutputDescriptor(NULL);
             outputDesc->mDevice = mTestDevice;
             outputDesc->mSamplingRate = mTestSamplingRate;
             outputDesc->mFormat = mTestFormat;
@@ -696,10 +696,10 @@
     }
 
     if (profile != 0) {
-        AudioOutputDescriptor *outputDesc = NULL;
+        sp<AudioOutputDescriptor> outputDesc = NULL;
 
         for (size_t i = 0; i < mOutputs.size(); i++) {
-            AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+            sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
             if (!desc->isDuplicated() && (profile == desc->mProfile)) {
                 outputDesc = desc;
                 // reuse direct output if currently open and configured with same parameters
@@ -747,7 +747,6 @@
             if (output != 0) {
                 mpClientInterface->closeOutput(output);
             }
-            delete outputDesc;
             return 0;
         }
         audio_io_handle_t srcOutput = getOutputForEffect();
@@ -804,7 +803,7 @@
     audio_io_handle_t outputPrimary = 0;
 
     for (size_t i = 0; i < outputs.size(); i++) {
-        AudioOutputDescriptor *outputDesc = mOutputs.valueFor(outputs[i]);
+        sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(outputs[i]);
         if (!outputDesc->isDuplicated()) {
             int commonFlags = popcount(outputDesc->mProfile->mFlags & flags);
             if (commonFlags > maxCommonFlags) {
@@ -839,7 +838,7 @@
         return BAD_VALUE;
     }
 
-    AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+    sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
 
     // increment usage count for this stream on the requested output:
     // NOTE that the usage count is the same for duplicated output and hardware output which is
@@ -854,7 +853,7 @@
         uint32_t waitMs = 0;
         bool force = false;
         for (size_t i = 0; i < mOutputs.size(); i++) {
-            AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+            sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
             if (desc != outputDesc) {
                 // force a device change if any other output is managed by the same hw
                 // module and has a current device selection that differs from selected device.
@@ -907,7 +906,7 @@
         return BAD_VALUE;
     }
 
-    AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+    sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
 
     // handle special case for sonification while in call
     if (isInCall()) {
@@ -932,7 +931,7 @@
             // one being selected for this output
             for (size_t i = 0; i < mOutputs.size(); i++) {
                 audio_io_handle_t curOutput = mOutputs.keyAt(i);
-                AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+                sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
                 if (curOutput != output &&
                         desc->isActive() &&
                         outputDesc->sharesHwModuleWith(desc) &&
@@ -965,10 +964,9 @@
 #ifdef AUDIO_POLICY_TEST
     int testIndex = testOutputIndex(output);
     if (testIndex != 0) {
-        AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+        sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
         if (outputDesc->isActive()) {
             mpClientInterface->closeOutput(output);
-            delete mOutputs.valueAt(index);
             mOutputs.removeItem(output);
             mTestOutputs[testIndex] = 0;
         }
@@ -976,7 +974,7 @@
     }
 #endif //AUDIO_POLICY_TEST
 
-    AudioOutputDescriptor *desc = mOutputs.valueAt(index);
+    sp<AudioOutputDescriptor> desc = mOutputs.valueAt(index);
     if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
         if (desc->mDirectOpenCount <= 0) {
             ALOGW("releaseOutput() invalid open count %d for output %d",
@@ -1045,7 +1043,7 @@
         return 0;
     }
 
-    AudioInputDescriptor *inputDesc = new AudioInputDescriptor(profile);
+    sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(profile);
 
     inputDesc->mInputSource = inputSource;
     inputDesc->mDevice = device;
@@ -1069,7 +1067,6 @@
         if (input != 0) {
             mpClientInterface->closeInput(input);
         }
-        delete inputDesc;
         return 0;
     }
     addInput(input, inputDesc);
@@ -1085,7 +1082,7 @@
         ALOGW("startInput() unknown input %d", input);
         return BAD_VALUE;
     }
-    AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+    sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
 
 #ifdef AUDIO_POLICY_TEST
     if (mTestInput == 0)
@@ -1095,7 +1092,7 @@
         // uses AUDIO_SOURCE_HOTWORD in which case it is closed.
         audio_io_handle_t activeInput = getActiveInput();
         if (!isVirtualInputDevice(inputDesc->mDevice) && activeInput != 0) {
-            AudioInputDescriptor *activeDesc = mInputs.valueFor(activeInput);
+            sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
             if (activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) {
                 ALOGW("startInput() preempting already started low-priority input %d", activeInput);
                 stopInput(activeInput);
@@ -1129,7 +1126,7 @@
         ALOGW("stopInput() unknown input %d", input);
         return BAD_VALUE;
     }
-    AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+    sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
 
     if (inputDesc->mRefCount == 0) {
         ALOGW("stopInput() input %d already stopped", input);
@@ -1156,7 +1153,6 @@
         return;
     }
     mpClientInterface->closeInput(input);
-    delete mInputs.valueAt(index);
     mInputs.removeItem(input);
     nextAudioPortGeneration();
     mpClientInterface->onAudioPortListUpdate();
@@ -1265,7 +1261,7 @@
     audio_io_handle_t outputDeepBuffer = 0;
 
     for (size_t i = 0; i < outputs.size(); i++) {
-        AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]);
+        sp<AudioOutputDescriptor> desc = mOutputs.valueFor(outputs[i]);
         ALOGV("selectOutputForEffects outputs[%zu] flags %x", i, desc->mFlags);
         if ((desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
             outputOffloaded = outputs[i];
@@ -1327,14 +1323,14 @@
             desc->name, io, strategy, session, id);
     ALOGV("registerEffect() memory %d, total memory %d", desc->memoryUsage, mTotalEffectsMemory);
 
-    EffectDescriptor *pDesc = new EffectDescriptor();
-    memcpy (&pDesc->mDesc, desc, sizeof(effect_descriptor_t));
-    pDesc->mIo = io;
-    pDesc->mStrategy = (routing_strategy)strategy;
-    pDesc->mSession = session;
-    pDesc->mEnabled = false;
+    sp<EffectDescriptor> effectDesc = new EffectDescriptor();
+    memcpy (&effectDesc->mDesc, desc, sizeof(effect_descriptor_t));
+    effectDesc->mIo = io;
+    effectDesc->mStrategy = (routing_strategy)strategy;
+    effectDesc->mSession = session;
+    effectDesc->mEnabled = false;
 
-    mEffects.add(id, pDesc);
+    mEffects.add(id, effectDesc);
 
     return NO_ERROR;
 }
@@ -1347,21 +1343,20 @@
         return INVALID_OPERATION;
     }
 
-    EffectDescriptor *pDesc = mEffects.valueAt(index);
+    sp<EffectDescriptor> effectDesc = mEffects.valueAt(index);
 
-    setEffectEnabled(pDesc, false);
+    setEffectEnabled(effectDesc, false);
 
-    if (mTotalEffectsMemory < pDesc->mDesc.memoryUsage) {
+    if (mTotalEffectsMemory < effectDesc->mDesc.memoryUsage) {
         ALOGW("unregisterEffect() memory %d too big for total %d",
-                pDesc->mDesc.memoryUsage, mTotalEffectsMemory);
-        pDesc->mDesc.memoryUsage = mTotalEffectsMemory;
+                effectDesc->mDesc.memoryUsage, mTotalEffectsMemory);
+        effectDesc->mDesc.memoryUsage = mTotalEffectsMemory;
     }
-    mTotalEffectsMemory -= pDesc->mDesc.memoryUsage;
+    mTotalEffectsMemory -= effectDesc->mDesc.memoryUsage;
     ALOGV("unregisterEffect() effect %s, ID %d, memory %d total memory %d",
-            pDesc->mDesc.name, id, pDesc->mDesc.memoryUsage, mTotalEffectsMemory);
+            effectDesc->mDesc.name, id, effectDesc->mDesc.memoryUsage, mTotalEffectsMemory);
 
     mEffects.removeItem(id);
-    delete pDesc;
 
     return NO_ERROR;
 }
@@ -1377,43 +1372,43 @@
     return setEffectEnabled(mEffects.valueAt(index), enabled);
 }
 
-status_t AudioPolicyManager::setEffectEnabled(EffectDescriptor *pDesc, bool enabled)
+status_t AudioPolicyManager::setEffectEnabled(const sp<EffectDescriptor>& effectDesc, bool enabled)
 {
-    if (enabled == pDesc->mEnabled) {
+    if (enabled == effectDesc->mEnabled) {
         ALOGV("setEffectEnabled(%s) effect already %s",
              enabled?"true":"false", enabled?"enabled":"disabled");
         return INVALID_OPERATION;
     }
 
     if (enabled) {
-        if (mTotalEffectsCpuLoad + pDesc->mDesc.cpuLoad > getMaxEffectsCpuLoad()) {
+        if (mTotalEffectsCpuLoad + effectDesc->mDesc.cpuLoad > getMaxEffectsCpuLoad()) {
             ALOGW("setEffectEnabled(true) CPU Load limit exceeded for Fx %s, CPU %f MIPS",
-                 pDesc->mDesc.name, (float)pDesc->mDesc.cpuLoad/10);
+                 effectDesc->mDesc.name, (float)effectDesc->mDesc.cpuLoad/10);
             return INVALID_OPERATION;
         }
-        mTotalEffectsCpuLoad += pDesc->mDesc.cpuLoad;
+        mTotalEffectsCpuLoad += effectDesc->mDesc.cpuLoad;
         ALOGV("setEffectEnabled(true) total CPU %d", mTotalEffectsCpuLoad);
     } else {
-        if (mTotalEffectsCpuLoad < pDesc->mDesc.cpuLoad) {
+        if (mTotalEffectsCpuLoad < effectDesc->mDesc.cpuLoad) {
             ALOGW("setEffectEnabled(false) CPU load %d too high for total %d",
-                    pDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad);
-            pDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad;
+                    effectDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad);
+            effectDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad;
         }
-        mTotalEffectsCpuLoad -= pDesc->mDesc.cpuLoad;
+        mTotalEffectsCpuLoad -= effectDesc->mDesc.cpuLoad;
         ALOGV("setEffectEnabled(false) total CPU %d", mTotalEffectsCpuLoad);
     }
-    pDesc->mEnabled = enabled;
+    effectDesc->mEnabled = enabled;
     return NO_ERROR;
 }
 
 bool AudioPolicyManager::isNonOffloadableEffectEnabled()
 {
     for (size_t i = 0; i < mEffects.size(); i++) {
-        const EffectDescriptor * const pDesc = mEffects.valueAt(i);
-        if (pDesc->mEnabled && (pDesc->mStrategy == STRATEGY_MEDIA) &&
-                ((pDesc->mDesc.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) == 0)) {
+        sp<EffectDescriptor> effectDesc = mEffects.valueAt(i);
+        if (effectDesc->mEnabled && (effectDesc->mStrategy == STRATEGY_MEDIA) &&
+                ((effectDesc->mDesc.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) == 0)) {
             ALOGV("isNonOffloadableEffectEnabled() non offloadable effect %s enabled on session %d",
-                  pDesc->mDesc.name, pDesc->mSession);
+                  effectDesc->mDesc.name, effectDesc->mSession);
             return true;
         }
     }
@@ -1424,7 +1419,7 @@
 {
     nsecs_t sysTime = systemTime();
     for (size_t i = 0; i < mOutputs.size(); i++) {
-        const AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+        const sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
         if (outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
             return true;
         }
@@ -1437,7 +1432,7 @@
 {
     nsecs_t sysTime = systemTime();
     for (size_t i = 0; i < mOutputs.size(); i++) {
-        const AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+        const sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
         if (((outputDesc->device() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) &&
                 outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
             return true;
@@ -1449,7 +1444,7 @@
 bool AudioPolicyManager::isSourceActive(audio_source_t source) const
 {
     for (size_t i = 0; i < mInputs.size(); i++) {
-        const AudioInputDescriptor * inputDescriptor = mInputs.valueAt(i);
+        const sp<AudioInputDescriptor>  inputDescriptor = mInputs.valueAt(i);
         if ((inputDescriptor->mInputSource == (int)source ||
                 (source == AUDIO_SOURCE_VOICE_RECOGNITION &&
                  inputDescriptor->mInputSource == AUDIO_SOURCE_HOTWORD))
@@ -1674,10 +1669,10 @@
     return NO_ERROR;
 }
 
-AudioPolicyManager::AudioOutputDescriptor *AudioPolicyManager::getOutputFromId(
+sp<AudioPolicyManager::AudioOutputDescriptor> AudioPolicyManager::getOutputFromId(
                                                                     audio_port_handle_t id) const
 {
-    AudioOutputDescriptor *outputDesc = NULL;
+    sp<AudioOutputDescriptor> outputDesc = NULL;
     for (size_t i = 0; i < mOutputs.size(); i++) {
         outputDesc = mOutputs.valueAt(i);
         if (outputDesc->mId == id) {
@@ -1687,10 +1682,10 @@
     return outputDesc;
 }
 
-AudioPolicyManager::AudioInputDescriptor *AudioPolicyManager::getInputFromId(
+sp<AudioPolicyManager::AudioInputDescriptor> AudioPolicyManager::getInputFromId(
                                                                     audio_port_handle_t id) const
 {
-    AudioInputDescriptor *inputDesc = NULL;
+    sp<AudioInputDescriptor> inputDesc = NULL;
     for (size_t i = 0; i < mInputs.size(); i++) {
         inputDesc = mInputs.valueAt(i);
         if (inputDesc->mId == id) {
@@ -1700,8 +1695,11 @@
     return inputDesc;
 }
 
-AudioPolicyManager::HwModule *AudioPolicyManager::getModuleForDevice(audio_devices_t device) const
+sp <AudioPolicyManager::HwModule> AudioPolicyManager::getModuleForDevice(
+                                                                    audio_devices_t device) const
 {
+    sp <HwModule> module;
+
     for (size_t i = 0; i < mHwModules.size(); i++) {
         if (mHwModules[i]->mHandle == 0) {
             continue;
@@ -1722,18 +1720,20 @@
             }
         }
     }
-    return NULL;
+    return module;
 }
 
-AudioPolicyManager::HwModule *AudioPolicyManager::getModuleFromName(const char *name) const
+sp <AudioPolicyManager::HwModule> AudioPolicyManager::getModuleFromName(const char *name) const
 {
+    sp <HwModule> module;
+
     for (size_t i = 0; i < mHwModules.size(); i++)
     {
         if (strcmp(mHwModules[i]->mName, name) == 0) {
             return mHwModules[i];
         }
     }
-    return NULL;
+    return module;
 }
 
 
@@ -1783,7 +1783,7 @@
             return BAD_VALUE;
         }
         // output mix to output device connection
-        AudioOutputDescriptor *outputDesc = getOutputFromId(patch->sources[0].id);
+        sp<AudioOutputDescriptor> outputDesc = getOutputFromId(patch->sources[0].id);
         if (outputDesc == NULL) {
             ALOGV("createAudioPatch() output not found for id %d", patch->sources[0].id);
             return BAD_VALUE;
@@ -1832,7 +1832,7 @@
     } else if (patch->sources[0].type == AUDIO_PORT_TYPE_DEVICE) {
         if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
             // input device to input mix connection
-            AudioInputDescriptor *inputDesc = getInputFromId(patch->sinks[0].id);
+            sp<AudioInputDescriptor> inputDesc = getInputFromId(patch->sinks[0].id);
             if (inputDesc == NULL) {
                 return BAD_VALUE;
             }
@@ -1957,7 +1957,7 @@
     struct audio_patch *patch = &patchDesc->mPatch;
     patchDesc->mUid = mUidCached;
     if (patch->sources[0].type == AUDIO_PORT_TYPE_MIX) {
-        AudioOutputDescriptor *outputDesc = getOutputFromId(patch->sources[0].id);
+        sp<AudioOutputDescriptor> outputDesc = getOutputFromId(patch->sources[0].id);
         if (outputDesc == NULL) {
             ALOGV("releaseAudioPatch() output not found for id %d", patch->sources[0].id);
             return BAD_VALUE;
@@ -1970,7 +1970,7 @@
                        NULL);
     } else if (patch->sources[0].type == AUDIO_PORT_TYPE_DEVICE) {
         if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
-            AudioInputDescriptor *inputDesc = getInputFromId(patch->sinks[0].id);
+            sp<AudioInputDescriptor> inputDesc = getInputFromId(patch->sinks[0].id);
             if (inputDesc == NULL) {
                 ALOGV("releaseAudioPatch() input not found for id %d", patch->sinks[0].id);
                 return BAD_VALUE;
@@ -2035,27 +2035,24 @@
     }
     ALOGV("setAudioPortConfig() on port handle %d", config->id);
     // Only support gain configuration for now
-    if (config->config_mask != AUDIO_PORT_CONFIG_GAIN || config->gain.index < 0) {
-        return BAD_VALUE;
+    if (config->config_mask != AUDIO_PORT_CONFIG_GAIN) {
+        return INVALID_OPERATION;
     }
 
-    sp<AudioPort> portDesc;
-    struct audio_port_config portConfig;
+    sp<AudioPortConfig> audioPortConfig;
     if (config->type == AUDIO_PORT_TYPE_MIX) {
         if (config->role == AUDIO_PORT_ROLE_SOURCE) {
-            AudioOutputDescriptor *outputDesc = getOutputFromId(config->id);
+            sp<AudioOutputDescriptor> outputDesc = getOutputFromId(config->id);
             if (outputDesc == NULL) {
                 return BAD_VALUE;
             }
-            portDesc = outputDesc->mProfile;
-            outputDesc->toAudioPortConfig(&portConfig);
+            audioPortConfig = outputDesc;
         } else if (config->role == AUDIO_PORT_ROLE_SINK) {
-            AudioInputDescriptor *inputDesc = getInputFromId(config->id);
+            sp<AudioInputDescriptor> inputDesc = getInputFromId(config->id);
             if (inputDesc == NULL) {
                 return BAD_VALUE;
             }
-            portDesc = inputDesc->mProfile;
-            inputDesc->toAudioPortConfig(&portConfig);
+            audioPortConfig = inputDesc;
         } else {
             return BAD_VALUE;
         }
@@ -2071,46 +2068,21 @@
         if (deviceDesc == NULL) {
             return BAD_VALUE;
         }
-        portDesc = deviceDesc;
-        deviceDesc->toAudioPortConfig(&portConfig);
+        audioPortConfig = deviceDesc;
     } else {
         return BAD_VALUE;
     }
 
-    if ((size_t)config->gain.index >= portDesc->mGains.size()) {
-        return INVALID_OPERATION;
+    struct audio_port_config backupConfig;
+    status_t status = audioPortConfig->applyAudioPortConfig(config, &backupConfig);
+    if (status == NO_ERROR) {
+        struct audio_port_config newConfig;
+        audioPortConfig->toAudioPortConfig(&newConfig, config);
+        status = mpClientInterface->setAudioPortConfig(&newConfig, 0);
     }
-    const struct audio_gain *gain = &portDesc->mGains[config->gain.index]->mGain;
-    if ((config->gain.mode & ~gain->mode) != 0) {
-        return BAD_VALUE;
+    if (status != NO_ERROR) {
+        audioPortConfig->applyAudioPortConfig(&backupConfig);
     }
-    if ((config->gain.mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
-        if ((config->gain.values[0] < gain->min_value) ||
-                    (config->gain.values[0] > gain->max_value)) {
-            return BAD_VALUE;
-        }
-    } else {
-        if ((config->gain.channel_mask & ~gain->channel_mask) != 0) {
-            return BAD_VALUE;
-        }
-        size_t numValues = popcount(config->gain.channel_mask);
-        for (size_t i = 0; i < numValues; i++) {
-            if ((config->gain.values[i] < gain->min_value) ||
-                    (config->gain.values[i] > gain->max_value)) {
-                return BAD_VALUE;
-            }
-        }
-    }
-    if ((config->gain.mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
-        if ((config->gain.ramp_duration_ms < gain->min_ramp_ms) ||
-                    (config->gain.ramp_duration_ms > gain->max_ramp_ms)) {
-            return BAD_VALUE;
-        }
-    }
-
-    portConfig.gain = config->gain;
-
-    status_t status = mpClientInterface->setAudioPortConfig(&portConfig, 0);
 
     return status;
 }
@@ -2230,7 +2202,7 @@
             audio_devices_t profileTypes = outProfile->mSupportedDevices.types();
             if ((profileTypes & outputDeviceTypes) &&
                     ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) {
-                AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(outProfile);
+                sp<AudioOutputDescriptor> outputDesc = new AudioOutputDescriptor(outProfile);
 
                 outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice->mDeviceType & profileTypes);
                 audio_io_handle_t output = mpClientInterface->openOutput(
@@ -2245,7 +2217,6 @@
                     ALOGW("Cannot open output stream for device %08x on hw module %s",
                           outputDesc->mDevice,
                           mHwModules[i]->mName);
-                    delete outputDesc;
                 } else {
                     for (size_t k = 0; k  < outProfile->mSupportedDevices.size(); k++) {
                         audio_devices_t type = outProfile->mSupportedDevices[k]->mDeviceType;
@@ -2282,7 +2253,7 @@
 
             audio_devices_t profileTypes = inProfile->mSupportedDevices.types();
             if (profileTypes & inputDeviceTypes) {
-                AudioInputDescriptor *inputDesc = new AudioInputDescriptor(inProfile);
+                sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(inProfile);
 
                 inputDesc->mInputSource = AUDIO_SOURCE_MIC;
                 inputDesc->mDevice = inProfile->mSupportedDevices[0]->mDeviceType;
@@ -2310,7 +2281,6 @@
                           inputDesc->mDevice,
                           mHwModules[i]->mName);
                 }
-                delete inputDesc;
             }
         }
     }
@@ -2372,17 +2342,15 @@
 #endif //AUDIO_POLICY_TEST
    for (size_t i = 0; i < mOutputs.size(); i++) {
         mpClientInterface->closeOutput(mOutputs.keyAt(i));
-        delete mOutputs.valueAt(i);
    }
    for (size_t i = 0; i < mInputs.size(); i++) {
         mpClientInterface->closeInput(mInputs.keyAt(i));
-        delete mInputs.valueAt(i);
-   }
-   for (size_t i = 0; i < mHwModules.size(); i++) {
-        delete mHwModules[i];
    }
    mAvailableOutputDevices.clear();
    mAvailableInputDevices.clear();
+   mOutputs.clear();
+   mInputs.clear();
+   mHwModules.clear();
 }
 
 status_t AudioPolicyManager::initCheck()
@@ -2486,15 +2454,14 @@
             if (param.get(String8("test_cmd_policy_reopen"), value) == NO_ERROR) {
                 param.remove(String8("test_cmd_policy_reopen"));
 
-                AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mPrimaryOutput);
+                sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(mPrimaryOutput);
                 mpClientInterface->closeOutput(mPrimaryOutput);
 
                 audio_module_handle_t moduleHandle = outputDesc->mModule->mHandle;
 
-                delete mOutputs.valueFor(mPrimaryOutput);
                 mOutputs.removeItem(mPrimaryOutput);
 
-                AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(NULL);
+                sp<AudioOutputDescriptor> outputDesc = new AudioOutputDescriptor(NULL);
                 outputDesc->mDevice = AUDIO_DEVICE_OUT_SPEAKER;
                 mPrimaryOutput = mpClientInterface->openOutput(moduleHandle,
                                                 &outputDesc->mDevice,
@@ -2542,7 +2509,7 @@
 
 // ---
 
-void AudioPolicyManager::addOutput(audio_io_handle_t output, AudioOutputDescriptor *outputDesc)
+void AudioPolicyManager::addOutput(audio_io_handle_t output, sp<AudioOutputDescriptor> outputDesc)
 {
     outputDesc->mIoHandle = output;
     outputDesc->mId = nextUniqueId();
@@ -2550,7 +2517,7 @@
     nextAudioPortGeneration();
 }
 
-void AudioPolicyManager::addInput(audio_io_handle_t input, AudioInputDescriptor *inputDesc)
+void AudioPolicyManager::addInput(audio_io_handle_t input, sp<AudioInputDescriptor> inputDesc)
 {
     inputDesc->mIoHandle = input;
     inputDesc->mId = nextUniqueId();
@@ -2571,7 +2538,7 @@
                                                        SortedVector<audio_io_handle_t>& outputs,
                                                        const String8 address)
 {
-    AudioOutputDescriptor *desc;
+    sp<AudioOutputDescriptor> desc;
 
     if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
         // first list already open outputs that can be routed to this device
@@ -2714,7 +2681,7 @@
                                                                                   mPrimaryOutput);
                         if (duplicatedOutput != 0) {
                             // add duplicated output descriptor
-                            AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(NULL);
+                            sp<AudioOutputDescriptor> dupOutputDesc = new AudioOutputDescriptor(NULL);
                             dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput);
                             dupOutputDesc->mOutput2 = mOutputs.valueFor(output);
                             dupOutputDesc->mSamplingRate = desc->mSamplingRate;
@@ -2736,7 +2703,6 @@
             }
             if (output == 0) {
                 ALOGW("checkOutputsForDevice() could not open output for device %x", device);
-                delete desc;
                 profiles.removeAt(profile_index);
                 profile_index--;
             } else {
@@ -2796,7 +2762,7 @@
                                                       SortedVector<audio_io_handle_t>& inputs,
                                                       const String8 address)
 {
-    AudioInputDescriptor *desc;
+    sp<AudioInputDescriptor> desc;
     if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
         // first list already open inputs that can be routed to this device
         for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
@@ -2911,7 +2877,6 @@
 
             if (input == 0) {
                 ALOGW("checkInputsForDevice() could not open input for device 0x%X", device);
-                delete desc;
                 profiles.removeAt(profile_index);
                 profile_index--;
             } else {
@@ -2972,7 +2937,7 @@
 {
     ALOGV("closeOutput(%d)", output);
 
-    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
     if (outputDesc == NULL) {
         ALOGW("closeOutput() unknown output %d", output);
         return;
@@ -2980,11 +2945,11 @@
 
     // look for duplicated outputs connected to the output being removed.
     for (size_t i = 0; i < mOutputs.size(); i++) {
-        AudioOutputDescriptor *dupOutputDesc = mOutputs.valueAt(i);
+        sp<AudioOutputDescriptor> dupOutputDesc = mOutputs.valueAt(i);
         if (dupOutputDesc->isDuplicated() &&
                 (dupOutputDesc->mOutput1 == outputDesc ||
                 dupOutputDesc->mOutput2 == outputDesc)) {
-            AudioOutputDescriptor *outputDesc2;
+            sp<AudioOutputDescriptor> outputDesc2;
             if (dupOutputDesc->mOutput1 == outputDesc) {
                 outputDesc2 = dupOutputDesc->mOutput2;
             } else {
@@ -3002,7 +2967,6 @@
             ALOGV("closeOutput() closing also duplicated output %d", duplicatedOutput);
 
             mpClientInterface->closeOutput(duplicatedOutput);
-            delete mOutputs.valueFor(duplicatedOutput);
             mOutputs.removeItem(duplicatedOutput);
         }
     }
@@ -3012,14 +2976,13 @@
     mpClientInterface->setParameters(output, param.toString());
 
     mpClientInterface->closeOutput(output);
-    delete outputDesc;
     mOutputs.removeItem(output);
     mPreviousOutputs = mOutputs;
     nextAudioPortGeneration();
 }
 
 SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice(audio_devices_t device,
-                        DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> openOutputs)
+                        DefaultKeyedVector<audio_io_handle_t, sp<AudioOutputDescriptor> > openOutputs)
 {
     SortedVector<audio_io_handle_t> outputs;
 
@@ -3061,7 +3024,7 @@
               strategy, srcOutputs[0], dstOutputs[0]);
         // mute strategy while moving tracks from one output to another
         for (size_t i = 0; i < srcOutputs.size(); i++) {
-            AudioOutputDescriptor *desc = mOutputs.valueFor(srcOutputs[i]);
+            sp<AudioOutputDescriptor> desc = mOutputs.valueFor(srcOutputs[i]);
             if (desc->isStrategyActive(strategy)) {
                 setStrategyMute(strategy, true, srcOutputs[i]);
                 setStrategyMute(strategy, false, srcOutputs[i], MUTE_TIME_MS, newDevice);
@@ -3073,17 +3036,17 @@
             audio_io_handle_t fxOutput = selectOutputForEffects(dstOutputs);
             SortedVector<audio_io_handle_t> moved;
             for (size_t i = 0; i < mEffects.size(); i++) {
-                EffectDescriptor *desc = mEffects.valueAt(i);
-                if (desc->mSession == AUDIO_SESSION_OUTPUT_MIX &&
-                        desc->mIo != fxOutput) {
-                    if (moved.indexOf(desc->mIo) < 0) {
+                sp<EffectDescriptor> effectDesc = mEffects.valueAt(i);
+                if (effectDesc->mSession == AUDIO_SESSION_OUTPUT_MIX &&
+                        effectDesc->mIo != fxOutput) {
+                    if (moved.indexOf(effectDesc->mIo) < 0) {
                         ALOGV("checkOutputForStrategy() moving effect %d to output %d",
                               mEffects.keyAt(i), fxOutput);
-                        mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, desc->mIo,
+                        mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, effectDesc->mIo,
                                                        fxOutput);
-                        moved.add(desc->mIo);
+                        moved.add(effectDesc->mIo);
                     }
-                    desc->mIo = fxOutput;
+                    effectDesc->mIo = fxOutput;
                 }
             }
         }
@@ -3109,7 +3072,7 @@
 audio_io_handle_t AudioPolicyManager::getA2dpOutput()
 {
     for (size_t i = 0; i < mOutputs.size(); i++) {
-        AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+        sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
         if (!outputDesc->isDuplicated() && outputDesc->device() & AUDIO_DEVICE_OUT_ALL_A2DP) {
             return mOutputs.keyAt(i);
         }
@@ -3167,7 +3130,7 @@
 {
     audio_devices_t device = AUDIO_DEVICE_NONE;
 
-    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
 
     ssize_t index = mAudioPatches.indexOfKey(outputDesc->mPatchHandle);
     if (index >= 0) {
@@ -3213,7 +3176,7 @@
 
 audio_devices_t AudioPolicyManager::getNewInputDevice(audio_io_handle_t input)
 {
-    AudioInputDescriptor *inputDesc = mInputs.valueFor(input);
+    sp<AudioInputDescriptor> inputDesc = mInputs.valueFor(input);
 
     ssize_t index = mAudioPatches.indexOfKey(inputDesc->mPatchHandle);
     if (index >= 0) {
@@ -3247,7 +3210,7 @@
     devices = getDeviceForStrategy(strategy, true /*fromCache*/);
     SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(devices, mOutputs);
     for (size_t i = 0; i < outputs.size(); i++) {
-        AudioOutputDescriptor *outputDesc = mOutputs.valueFor(outputs[i]);
+        sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(outputs[i]);
         if (outputDesc->isStrategyActive(strategy)) {
             devices = outputDesc->device();
             break;
@@ -3514,7 +3477,7 @@
     mPreviousOutputs = mOutputs;
 }
 
-uint32_t AudioPolicyManager::checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
+uint32_t AudioPolicyManager::checkDeviceMuteStrategies(sp<AudioOutputDescriptor> outputDesc,
                                                        audio_devices_t prevDevice,
                                                        uint32_t delayMs)
 {
@@ -3543,7 +3506,7 @@
         }
         if (doMute) {
             for (size_t j = 0; j < mOutputs.size(); j++) {
-                AudioOutputDescriptor *desc = mOutputs.valueAt(j);
+                sp<AudioOutputDescriptor> desc = mOutputs.valueAt(j);
                 // skip output if it does not share any device with current output
                 if ((desc->supportedDevices() & outputDesc->supportedDevices())
                         == AUDIO_DEVICE_NONE) {
@@ -3601,7 +3564,7 @@
                                              audio_patch_handle_t *patchHandle)
 {
     ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs);
-    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
     AudioParameter param;
     uint32_t muteWaitMs;
 
@@ -3703,7 +3666,7 @@
                                                int delayMs,
                                                audio_patch_handle_t *patchHandle)
 {
-    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
     ssize_t index;
     if (patchHandle) {
         index = mAudioPatches.indexOfKey(*patchHandle);
@@ -3730,7 +3693,7 @@
 {
     status_t status = NO_ERROR;
 
-    AudioInputDescriptor *inputDesc = mInputs.valueFor(input);
+    sp<AudioInputDescriptor> inputDesc = mInputs.valueFor(input);
     if ((device != AUDIO_DEVICE_NONE) && ((device != inputDesc->mDevice) || force)) {
         inputDesc->mDevice = device;
 
@@ -3785,7 +3748,7 @@
 status_t AudioPolicyManager::resetInputDevice(audio_io_handle_t input,
                                               audio_patch_handle_t *patchHandle)
 {
-    AudioInputDescriptor *inputDesc = mInputs.valueFor(input);
+    sp<AudioInputDescriptor> inputDesc = mInputs.valueFor(input);
     ssize_t index;
     if (patchHandle) {
         index = mAudioPatches.indexOfKey(*patchHandle);
@@ -3899,7 +3862,7 @@
 audio_io_handle_t AudioPolicyManager::getActiveInput(bool ignoreVirtualInputs)
 {
     for (size_t i = 0; i < mInputs.size(); i++) {
-        const AudioInputDescriptor * input_descriptor = mInputs.valueAt(i);
+        const sp<AudioInputDescriptor>  input_descriptor = mInputs.valueAt(i);
         if ((input_descriptor->mRefCount > 0)
                 && (!ignoreVirtualInputs || !isVirtualInputDevice(input_descriptor->mDevice))) {
             return mInputs.keyAt(i);
@@ -4144,7 +4107,7 @@
                                             audio_devices_t device)
 {
     float volume = 1.0;
-    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
     StreamDescriptor &streamDesc = mStreams[stream];
 
     if (device == AUDIO_DEVICE_NONE) {
@@ -4300,7 +4263,7 @@
                                            audio_devices_t device)
 {
     StreamDescriptor &streamDesc = mStreams[stream];
-    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
     if (device == AUDIO_DEVICE_NONE) {
         device = outputDesc->device();
     }
@@ -4345,7 +4308,7 @@
     const routing_strategy stream_strategy = getStrategy(stream);
     if ((stream_strategy == STRATEGY_SONIFICATION) ||
             ((stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL))) {
-        AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mPrimaryOutput);
+        sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(mPrimaryOutput);
         ALOGV("handleIncallSonification() stream %d starting %d device %x stateChange %d",
                 stream, starting, outputDesc->mDevice, stateChange);
         if (outputDesc->mRefCount[stream]) {
@@ -4403,8 +4366,7 @@
 
 AudioPolicyManager::AudioOutputDescriptor::AudioOutputDescriptor(
         const sp<IOProfile>& profile)
-    : mId(0), mIoHandle(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT),
-      mChannelMask(0), mLatency(0),
+    : mId(0), mIoHandle(0), mLatency(0),
     mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0),
     mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0)
 {
@@ -4419,9 +4381,13 @@
         mStrategyMutedByDevice[i] = false;
     }
     if (profile != NULL) {
+        mAudioPort = profile;
         mSamplingRate = profile->mSamplingRates[0];
         mFormat = profile->mFormats[0];
         mChannelMask = profile->mChannelMasks[0];
+        if (profile->mGains.size() > 0) {
+            profile->mGains[0]->getDefaultConfig(&mGain);
+        }
         mFlags = profile->mFlags;
     }
 }
@@ -4445,7 +4411,7 @@
 }
 
 bool AudioPolicyManager::AudioOutputDescriptor::sharesHwModuleWith(
-        const AudioOutputDescriptor *outputDesc)
+        const sp<AudioOutputDescriptor> outputDesc)
 {
     if (isDuplicated()) {
         return mOutput1->sharesHwModuleWith(outputDesc) || mOutput2->sharesHwModuleWith(outputDesc);
@@ -4528,31 +4494,16 @@
                                                  struct audio_port_config *dstConfig,
                                                  const struct audio_port_config *srcConfig) const
 {
+    dstConfig->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
+                            AUDIO_PORT_CONFIG_FORMAT|AUDIO_PORT_CONFIG_GAIN;
+    if (srcConfig != NULL) {
+        dstConfig->config_mask &= srcConfig->config_mask;
+    }
+    AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
+
     dstConfig->id = mId;
     dstConfig->role = AUDIO_PORT_ROLE_SOURCE;
     dstConfig->type = AUDIO_PORT_TYPE_MIX;
-    dstConfig->sample_rate = mSamplingRate;
-    dstConfig->channel_mask = mChannelMask;
-    dstConfig->format = mFormat;
-    dstConfig->gain.index = -1;
-    dstConfig->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
-                            AUDIO_PORT_CONFIG_FORMAT;
-    // use supplied variable configuration parameters if any
-    if (srcConfig != NULL) {
-        if (srcConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
-            dstConfig->sample_rate = srcConfig->sample_rate;
-        }
-        if (srcConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
-            dstConfig->channel_mask = srcConfig->channel_mask;
-        }
-        if (srcConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
-            dstConfig->format = srcConfig->format;
-        }
-        if (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) {
-            dstConfig->gain = srcConfig->gain;
-            dstConfig->config_mask |= AUDIO_PORT_CONFIG_GAIN;
-        }
-    }
     dstConfig->ext.mix.hw_module = mProfile->mModule->mHandle;
     dstConfig->ext.mix.handle = mIoHandle;
     dstConfig->ext.mix.usecase.stream = AUDIO_STREAM_DEFAULT;
@@ -4603,15 +4554,22 @@
 // --- AudioInputDescriptor class implementation
 
 AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile)
-    : mId(0), mIoHandle(0), mSamplingRate(0),
-      mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0),
+    : mId(0), mIoHandle(0),
       mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0), mRefCount(0),
       mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile)
 {
     if (profile != NULL) {
+        mAudioPort = profile;
         mSamplingRate = profile->mSamplingRates[0];
         mFormat = profile->mFormats[0];
         mChannelMask = profile->mChannelMasks[0];
+        if (profile->mGains.size() > 0) {
+            profile->mGains[0]->getDefaultConfig(&mGain);
+        }
+    } else {
+        mSamplingRate = 0;
+        mFormat = AUDIO_FORMAT_DEFAULT;
+        mChannelMask = 0;
     }
 }
 
@@ -4619,31 +4577,17 @@
                                                    struct audio_port_config *dstConfig,
                                                    const struct audio_port_config *srcConfig) const
 {
+    dstConfig->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
+                            AUDIO_PORT_CONFIG_FORMAT|AUDIO_PORT_CONFIG_GAIN;
+    if (srcConfig != NULL) {
+        dstConfig->config_mask &= srcConfig->config_mask;
+    }
+
+    AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
+
     dstConfig->id = mId;
     dstConfig->role = AUDIO_PORT_ROLE_SINK;
     dstConfig->type = AUDIO_PORT_TYPE_MIX;
-    dstConfig->sample_rate = mSamplingRate;
-    dstConfig->channel_mask = mChannelMask;
-    dstConfig->format = mFormat;
-    dstConfig->gain.index = -1;
-    dstConfig->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
-                            AUDIO_PORT_CONFIG_FORMAT;
-    // use supplied variable configuration parameters if any
-    if (srcConfig != NULL) {
-        if (srcConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
-            dstConfig->sample_rate = srcConfig->sample_rate;
-        }
-        if (srcConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
-            dstConfig->channel_mask = srcConfig->channel_mask;
-        }
-        if (srcConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
-            dstConfig->format = srcConfig->format;
-        }
-        if (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) {
-            dstConfig->gain = srcConfig->gain;
-            dstConfig->config_mask |= AUDIO_PORT_CONFIG_GAIN;
-        }
-    }
     dstConfig->ext.mix.hw_module = mProfile->mModule->mHandle;
     dstConfig->ext.mix.handle = mIoHandle;
     dstConfig->ext.mix.usecase.source = mInputSource;
@@ -4745,7 +4689,8 @@
 // --- HwModule class implementation
 
 AudioPolicyManager::HwModule::HwModule(const char *name)
-    : mName(strndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN)), mHandle(0)
+    : mName(strndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN)),
+      mHalVersion(AUDIO_DEVICE_API_VERSION_MIN), mHandle(0)
 {
 }
 
@@ -4904,6 +4849,8 @@
     result.append(buffer);
     snprintf(buffer, SIZE, "  - handle: %d\n", mHandle);
     result.append(buffer);
+    snprintf(buffer, SIZE, "  - version: %u.%u\n", mHalVersion >> 8, mHalVersion & 0xFF);
+    result.append(buffer);
     write(fd, result.string(), result.size());
     if (mOutputProfiles.size()) {
         write(fd, "  - outputs:\n", strlen("  - outputs:\n"));
@@ -4931,6 +4878,15 @@
 
 // --- AudioPort class implementation
 
+
+AudioPolicyManager::AudioPort::AudioPort(const String8& name, audio_port_type_t type,
+          audio_port_role_t role, const sp<HwModule>& module) :
+    mName(name), mType(type), mRole(role), mModule(module)
+{
+    mUseInChannelMask = ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
+                    ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
+}
+
 void AudioPolicyManager::AudioPort::toAudioPort(struct audio_port *port) const
 {
     port->role = mRole;
@@ -5066,18 +5022,17 @@
     return mode;
 }
 
-void AudioPolicyManager::AudioPort::loadGain(cnode *root)
+void AudioPolicyManager::AudioPort::loadGain(cnode *root, int index)
 {
     cnode *node = root->first_child;
 
-    sp<AudioGain> gain = new AudioGain();
+    sp<AudioGain> gain = new AudioGain(index, mUseInChannelMask);
 
     while (node) {
         if (strcmp(node->name, GAIN_MODE) == 0) {
             gain->mGain.mode = loadGainMode((char *)node->value);
         } else if (strcmp(node->name, GAIN_CHANNELS) == 0) {
-            if ((mType == AUDIO_PORT_TYPE_DEVICE && mRole == AUDIO_PORT_ROLE_SOURCE) ||
-                    (mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK)) {
+            if (mUseInChannelMask) {
                 gain->mGain.channel_mask =
                         (audio_channel_mask_t)stringToEnum(sInChannelsNameToEnumTable,
                                                            ARRAY_SIZE(sInChannelsNameToEnumTable),
@@ -5116,13 +5071,53 @@
 void AudioPolicyManager::AudioPort::loadGains(cnode *root)
 {
     cnode *node = root->first_child;
+    int index = 0;
     while (node) {
         ALOGV("loadGains() loading gain %s", node->name);
-        loadGain(node);
+        loadGain(node, index++);
         node = node->next;
     }
 }
 
+status_t AudioPolicyManager::AudioPort::checkSamplingRate(uint32_t samplingRate) const
+{
+    for (size_t i = 0; i < mSamplingRates.size(); i ++) {
+        if (mSamplingRates[i] == samplingRate) {
+            return NO_ERROR;
+        }
+    }
+    return BAD_VALUE;
+}
+
+status_t AudioPolicyManager::AudioPort::checkChannelMask(audio_channel_mask_t channelMask) const
+{
+    for (size_t i = 0; i < mChannelMasks.size(); i ++) {
+        if (mChannelMasks[i] == channelMask) {
+            return NO_ERROR;
+        }
+    }
+    return BAD_VALUE;
+}
+
+status_t AudioPolicyManager::AudioPort::checkFormat(audio_format_t format) const
+{
+    for (size_t i = 0; i < mFormats.size(); i ++) {
+        if (mFormats[i] == format) {
+            return NO_ERROR;
+        }
+    }
+    return BAD_VALUE;
+}
+
+status_t AudioPolicyManager::AudioPort::checkGain(const struct audio_gain_config *gainConfig,
+                                                  int index) const
+{
+    if (index < 0 || (size_t)index >= mGains.size()) {
+        return BAD_VALUE;
+    }
+    return mGains[index]->checkConfig(gainConfig);
+}
+
 void AudioPolicyManager::AudioPort::dump(int fd, int spaces) const
 {
     const size_t SIZE = 256;
@@ -5181,11 +5176,72 @@
 
 // --- AudioGain class implementation
 
-AudioPolicyManager::AudioGain::AudioGain()
+AudioPolicyManager::AudioGain::AudioGain(int index, bool useInChannelMask)
 {
+    mIndex = index;
+    mUseInChannelMask = useInChannelMask;
     memset(&mGain, 0, sizeof(struct audio_gain));
 }
 
+void AudioPolicyManager::AudioGain::getDefaultConfig(struct audio_gain_config *config)
+{
+    config->index = mIndex;
+    config->mode = mGain.mode;
+    config->channel_mask = mGain.channel_mask;
+    if ((mGain.mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
+        config->values[0] = mGain.default_value;
+    } else {
+        uint32_t numValues;
+        if (mUseInChannelMask) {
+            numValues = audio_channel_count_from_in_mask(mGain.channel_mask);
+        } else {
+            numValues = audio_channel_count_from_out_mask(mGain.channel_mask);
+        }
+        for (size_t i = 0; i < numValues; i++) {
+            config->values[i] = mGain.default_value;
+        }
+    }
+    if ((mGain.mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
+        config->ramp_duration_ms = mGain.min_ramp_ms;
+    }
+}
+
+status_t AudioPolicyManager::AudioGain::checkConfig(const struct audio_gain_config *config)
+{
+    if ((config->mode & ~mGain.mode) != 0) {
+        return BAD_VALUE;
+    }
+    if ((config->mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
+        if ((config->values[0] < mGain.min_value) ||
+                    (config->values[0] > mGain.max_value)) {
+            return BAD_VALUE;
+        }
+    } else {
+        if ((config->channel_mask & ~mGain.channel_mask) != 0) {
+            return BAD_VALUE;
+        }
+        uint32_t numValues;
+        if (mUseInChannelMask) {
+            numValues = audio_channel_count_from_in_mask(config->channel_mask);
+        } else {
+            numValues = audio_channel_count_from_out_mask(config->channel_mask);
+        }
+        for (size_t i = 0; i < numValues; i++) {
+            if ((config->values[i] < mGain.min_value) ||
+                    (config->values[i] > mGain.max_value)) {
+                return BAD_VALUE;
+            }
+        }
+    }
+    if ((config->mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
+        if ((config->ramp_duration_ms < mGain.min_ramp_ms) ||
+                    (config->ramp_duration_ms > mGain.max_ramp_ms)) {
+            return BAD_VALUE;
+        }
+    }
+    return NO_ERROR;
+}
+
 void AudioPolicyManager::AudioGain::dump(int fd, int spaces, int index) const
 {
     const size_t SIZE = 256;
@@ -5214,10 +5270,116 @@
     write(fd, result.string(), result.size());
 }
 
+// --- AudioPortConfig class implementation
+
+AudioPolicyManager::AudioPortConfig::AudioPortConfig()
+{
+    mSamplingRate = 0;
+    mChannelMask = AUDIO_CHANNEL_NONE;
+    mFormat = AUDIO_FORMAT_INVALID;
+    mGain.index = -1;
+}
+
+status_t AudioPolicyManager::AudioPortConfig::applyAudioPortConfig(
+                                                        const struct audio_port_config *config,
+                                                        struct audio_port_config *backupConfig)
+{
+    struct audio_port_config localBackupConfig;
+    status_t status = NO_ERROR;
+
+    localBackupConfig.config_mask = config->config_mask;
+    toAudioPortConfig(&localBackupConfig);
+
+    if (mAudioPort == 0) {
+        status = NO_INIT;
+        goto exit;
+    }
+    if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
+        status = mAudioPort->checkSamplingRate(config->sample_rate);
+        if (status != NO_ERROR) {
+            goto exit;
+        }
+        mSamplingRate = config->sample_rate;
+    }
+    if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
+        status = mAudioPort->checkChannelMask(config->channel_mask);
+        if (status != NO_ERROR) {
+            goto exit;
+        }
+        mChannelMask = config->channel_mask;
+    }
+    if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
+        status = mAudioPort->checkFormat(config->format);
+        if (status != NO_ERROR) {
+            goto exit;
+        }
+        mFormat = config->format;
+    }
+    if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
+        status = mAudioPort->checkGain(&config->gain, config->gain.index);
+        if (status != NO_ERROR) {
+            goto exit;
+        }
+        mGain = config->gain;
+    }
+
+exit:
+    if (status != NO_ERROR) {
+        applyAudioPortConfig(&localBackupConfig);
+    }
+    if (backupConfig != NULL) {
+        *backupConfig = localBackupConfig;
+    }
+    return status;
+}
+
+void AudioPolicyManager::AudioPortConfig::toAudioPortConfig(
+                                                    struct audio_port_config *dstConfig,
+                                                    const struct audio_port_config *srcConfig) const
+{
+    if (dstConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
+        dstConfig->sample_rate = mSamplingRate;
+        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE)) {
+            dstConfig->sample_rate = srcConfig->sample_rate;
+        }
+    } else {
+        dstConfig->sample_rate = 0;
+    }
+    if (dstConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
+        dstConfig->channel_mask = mChannelMask;
+        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK)) {
+            dstConfig->channel_mask = srcConfig->channel_mask;
+        }
+    } else {
+        dstConfig->channel_mask = AUDIO_CHANNEL_NONE;
+    }
+    if (dstConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
+        dstConfig->format = mFormat;
+        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT)) {
+            dstConfig->format = srcConfig->format;
+        }
+    } else {
+        dstConfig->format = AUDIO_FORMAT_INVALID;
+    }
+    if (dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) {
+        dstConfig->gain = mGain;
+        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)) {
+            dstConfig->gain = srcConfig->gain;
+        }
+    } else {
+        dstConfig->gain.index = -1;
+    }
+    if (dstConfig->gain.index != -1) {
+        dstConfig->config_mask |= AUDIO_PORT_CONFIG_GAIN;
+    } else {
+        dstConfig->config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
+    }
+}
+
 // --- IOProfile class implementation
 
 AudioPolicyManager::IOProfile::IOProfile(const String8& name, audio_port_role_t role,
-                                         HwModule *module)
+                                         const sp<HwModule>& module)
     : AudioPort(name, AUDIO_PORT_TYPE_MIX, role, module), mFlags((audio_output_flags_t)0)
 {
 }
@@ -5245,32 +5407,13 @@
      if ((mFlags & flags) != flags) {
          return false;
      }
-     size_t i;
-     for (i = 0; i < mSamplingRates.size(); i++)
-     {
-         if (mSamplingRates[i] == samplingRate) {
-             break;
-         }
-     }
-     if (i == mSamplingRates.size()) {
+     if (checkSamplingRate(samplingRate) != NO_ERROR) {
          return false;
      }
-     for (i = 0; i < mFormats.size(); i++)
-     {
-         if (mFormats[i] == format) {
-             break;
-         }
-     }
-     if (i == mFormats.size()) {
+     if (checkChannelMask(channelMask) != NO_ERROR) {
          return false;
      }
-     for (i = 0; i < mChannelMasks.size(); i++)
-     {
-         if (mChannelMasks[i] == channelMask) {
-             break;
-         }
-     }
-     if (i == mChannelMasks.size()) {
+     if (checkFormat(format) != NO_ERROR) {
          return false;
      }
      return true;
@@ -5322,6 +5465,21 @@
 
 // --- DeviceDescriptor implementation
 
+
+AudioPolicyManager::DeviceDescriptor::DeviceDescriptor(const String8& name, audio_devices_t type) :
+                     AudioPort(name, AUDIO_PORT_TYPE_DEVICE,
+                               audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
+                                                              AUDIO_PORT_ROLE_SOURCE,
+                             NULL),
+                     mDeviceType(type), mAddress(""),
+                     mChannelMask(AUDIO_CHANNEL_NONE), mId(0)
+{
+    mAudioPort = this;
+    if (mGains.size() > 0) {
+        mGains[0]->getDefaultConfig(&mGain);
+    }
+}
+
 bool AudioPolicyManager::DeviceDescriptor::equals(const sp<DeviceDescriptor>& other) const
 {
     // Devices are considered equal if they:
@@ -5486,23 +5644,17 @@
                                                     struct audio_port_config *dstConfig,
                                                     const struct audio_port_config *srcConfig) const
 {
+    dstConfig->config_mask = AUDIO_PORT_CONFIG_CHANNEL_MASK|AUDIO_PORT_CONFIG_GAIN;
+    if (srcConfig != NULL) {
+        dstConfig->config_mask &= srcConfig->config_mask;
+    }
+
+    AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
+
     dstConfig->id = mId;
     dstConfig->role = audio_is_output_device(mDeviceType) ?
                         AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
     dstConfig->type = AUDIO_PORT_TYPE_DEVICE;
-    dstConfig->channel_mask = mChannelMask;
-    dstConfig->gain.index = -1;
-    dstConfig->config_mask = AUDIO_PORT_CONFIG_CHANNEL_MASK;
-    // use supplied variable configuration parameters if any
-    if (srcConfig != NULL) {
-        if (srcConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
-            dstConfig->channel_mask = srcConfig->channel_mask;
-        }
-        if (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) {
-            dstConfig->gain = srcConfig->gain;
-            dstConfig->config_mask |= AUDIO_PORT_CONFIG_GAIN;
-        }
-    }
     dstConfig->ext.device.type = mDeviceType;
     dstConfig->ext.device.hw_module = mModule->mHandle;
     strncpy(dstConfig->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN);
@@ -5598,7 +5750,7 @@
 {
     status_t status = NAME_NOT_FOUND;
     cnode *node;
-    HwModule *module = new HwModule(root->name);
+    sp<HwModule> module = new HwModule(root->name);
 
     node = config_find(root, DEVICES_TAG);
     if (node != NULL) {
@@ -5640,8 +5792,6 @@
 
     if (status == NO_ERROR) {
         mHwModules.add(module);
-    } else {
-        delete module;
     }
 }
 
@@ -5660,9 +5810,10 @@
     }
 }
 
-void AudioPolicyManager::loadGlobalConfig(cnode *root, HwModule *module)
+void AudioPolicyManager::loadGlobalConfig(cnode *root, const sp<HwModule>& module)
 {
     cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
+
     if (node == NULL) {
         return;
     }
@@ -5695,6 +5846,12 @@
         } else if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
             mSpeakerDrcEnabled = stringToBool((char *)node->value);
             ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", mSpeakerDrcEnabled);
+        } else if (strcmp(AUDIO_HAL_VERSION_TAG, node->name) == 0) {
+            uint32_t major, minor;
+            sscanf((char *)node->value, "%u.%u", &major, &minor);
+            module->mHalVersion = HARDWARE_DEVICE_API_VERSION(major, minor);
+            ALOGV("loadGlobalConfig() mHalVersion = %04x major %u minor %u",
+                  module->mHalVersion, major, minor);
         }
         node = node->next;
     }
@@ -5726,9 +5883,10 @@
 
 void AudioPolicyManager::defaultAudioPolicyConfig(void)
 {
-    HwModule *module;
+    sp<HwModule> module;
     sp<IOProfile> profile;
-    sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(String8(""), AUDIO_DEVICE_IN_BUILTIN_MIC);
+    sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(String8(""),
+                                                                   AUDIO_DEVICE_IN_BUILTIN_MIC);
     mAvailableOutputDevices.add(mDefaultOutputDevice);
     mAvailableInputDevices.add(defaultInputDevice);
 
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
index e012d63..adf1b33 100644
--- a/services/audiopolicy/AudioPolicyManager.h
+++ b/services/audiopolicy/AudioPolicyManager.h
@@ -195,20 +195,23 @@
         class AudioGain: public RefBase
         {
         public:
-            AudioGain();
+            AudioGain(int index, bool useInChannelMask);
             virtual ~AudioGain() {}
 
             void dump(int fd, int spaces, int index) const;
 
+            void getDefaultConfig(struct audio_gain_config *config);
+            status_t checkConfig(const struct audio_gain_config *config);
+            int               mIndex;
             struct audio_gain mGain;
+            bool              mUseInChannelMask;
         };
 
-        class AudioPort: public RefBase
+        class AudioPort: public virtual RefBase
         {
         public:
             AudioPort(const String8& name, audio_port_type_t type,
-                      audio_port_role_t role, HwModule *module) :
-                mName(name), mType(type), mRole(role), mModule(module) {}
+                      audio_port_role_t role, const sp<HwModule>& module);
             virtual ~AudioPort() {}
 
             virtual void toAudioPort(struct audio_port *port) const;
@@ -219,14 +222,20 @@
             void loadInChannels(char *name);
 
             audio_gain_mode_t loadGainMode(char *name);
-            void loadGain(cnode *root);
+            void loadGain(cnode *root, int index);
             void loadGains(cnode *root);
 
+            status_t checkSamplingRate(uint32_t samplingRate) const;
+            status_t checkChannelMask(audio_channel_mask_t channelMask) const;
+            status_t checkFormat(audio_format_t format) const;
+            status_t checkGain(const struct audio_gain_config *gainConfig, int index) const;
+
             void dump(int fd, int spaces) const;
 
             String8           mName;
             audio_port_type_t mType;
             audio_port_role_t mRole;
+            bool              mUseInChannelMask;
             // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
             // indicates the supported parameters should be read from the output stream
             // after it is opened for the first time
@@ -234,9 +243,27 @@
             Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks
             Vector <audio_format_t> mFormats; // supported audio formats
             Vector < sp<AudioGain> > mGains; // gain controllers
-            HwModule *mModule;                 // audio HW module exposing this I/O stream
+            sp<HwModule> mModule;                 // audio HW module exposing this I/O stream
         };
 
+        class AudioPortConfig: public virtual RefBase
+        {
+        public:
+            AudioPortConfig();
+            virtual ~AudioPortConfig() {}
+
+            status_t applyAudioPortConfig(const struct audio_port_config *config,
+                                          struct audio_port_config *backupConfig = NULL);
+            virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
+                                   const struct audio_port_config *srcConfig = NULL) const = 0;
+            sp<AudioPort> mAudioPort;
+            uint32_t mSamplingRate;
+            audio_format_t mFormat;
+            audio_channel_mask_t mChannelMask;
+            struct audio_gain_config mGain;
+        };
+
+
         class AudioPatch: public RefBase
         {
         public:
@@ -250,29 +277,15 @@
             audio_patch_handle_t mAfPatchHandle;
         };
 
-        class DeviceDescriptor: public AudioPort
+        class DeviceDescriptor: public AudioPort, public AudioPortConfig
         {
         public:
-            DeviceDescriptor(const String8& name, audio_devices_t type, String8 address,
-                             audio_channel_mask_t channelMask) :
-                                 AudioPort(name, AUDIO_PORT_TYPE_DEVICE,
-                                           audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
-                                                                          AUDIO_PORT_ROLE_SOURCE,
-                                         NULL),
-                                 mDeviceType(type), mAddress(address),
-                                 mChannelMask(channelMask), mId(0) {}
+            DeviceDescriptor(const String8& name, audio_devices_t type);
 
-            DeviceDescriptor(String8 name, audio_devices_t type) :
-                                AudioPort(name, AUDIO_PORT_TYPE_DEVICE,
-                                          audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
-                                                                         AUDIO_PORT_ROLE_SOURCE,
-                                        NULL),
-                                mDeviceType(type), mAddress(""),
-                                mChannelMask(0), mId(0) {}
             virtual ~DeviceDescriptor() {}
 
             bool equals(const sp<DeviceDescriptor>& other) const;
-            void toAudioPortConfig(struct audio_port_config *dstConfig,
+            virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
                                    const struct audio_port_config *srcConfig = NULL) const;
 
             virtual void toAudioPort(struct audio_port *port) const;
@@ -317,7 +330,7 @@
         class IOProfile : public AudioPort
         {
         public:
-            IOProfile(const String8& name, audio_port_role_t role, HwModule *module);
+            IOProfile(const String8& name, audio_port_role_t role, const sp<HwModule>& module);
             virtual ~IOProfile();
 
             bool isCompatibleProfile(audio_devices_t device,
@@ -335,7 +348,7 @@
                                                 // direct output...). For outputs only.
         };
 
-        class HwModule {
+        class HwModule : public RefBase{
         public:
                     HwModule(const char *name);
                     ~HwModule();
@@ -346,8 +359,9 @@
 
             void dump(int fd);
 
-            const char *const mName; // base name of the audio HW module (primary, a2dp ...)
-            audio_module_handle_t mHandle;
+            const char *const        mName; // base name of the audio HW module (primary, a2dp ...)
+            uint32_t                 mHalVersion; // audio HAL API version
+            audio_module_handle_t    mHandle;
             Vector < sp<IOProfile> > mOutputProfiles; // output profiles exposed by this module
             Vector < sp<IOProfile> > mInputProfiles;  // input profiles exposed by this module
             DeviceVector             mDeclaredDevices; // devices declared in audio_policy.conf
@@ -373,7 +387,7 @@
 
         // descriptor for audio outputs. Used to maintain current configuration of each opened audio output
         // and keep track of the usage of this output by each audio stream type.
-        class AudioOutputDescriptor
+        class AudioOutputDescriptor: public AudioPortConfig
         {
         public:
             AudioOutputDescriptor(const sp<IOProfile>& profile);
@@ -386,7 +400,7 @@
             bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); }
             audio_devices_t supportedDevices();
             uint32_t latency();
-            bool sharesHwModuleWith(const AudioOutputDescriptor *outputDesc);
+            bool sharesHwModuleWith(const sp<AudioOutputDescriptor> outputDesc);
             bool isActive(uint32_t inPastMs = 0) const;
             bool isStreamActive(audio_stream_type_t stream,
                                 uint32_t inPastMs = 0,
@@ -395,23 +409,20 @@
                              uint32_t inPastMs = 0,
                              nsecs_t sysTime = 0) const;
 
-            void toAudioPortConfig(struct audio_port_config *dstConfig,
+            virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
                                    const struct audio_port_config *srcConfig = NULL) const;
             void toAudioPort(struct audio_port *port) const;
 
             audio_port_handle_t mId;
             audio_io_handle_t mIoHandle;              // output handle
-            uint32_t mSamplingRate;             //
-            audio_format_t mFormat;             //
-            audio_channel_mask_t mChannelMask;     // output configuration
             uint32_t mLatency;                  //
             audio_output_flags_t mFlags;   //
             audio_devices_t mDevice;                   // current device this output is routed to
             audio_patch_handle_t mPatchHandle;
             uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output
             nsecs_t mStopTime[AUDIO_STREAM_CNT];
-            AudioOutputDescriptor *mOutput1;    // used by duplicated outputs: first output
-            AudioOutputDescriptor *mOutput2;    // used by duplicated outputs: second output
+            sp<AudioOutputDescriptor> mOutput1;    // used by duplicated outputs: first output
+            sp<AudioOutputDescriptor> mOutput2;    // used by duplicated outputs: second output
             float mCurVolume[AUDIO_STREAM_CNT];   // current stream volume
             int mMuteCount[AUDIO_STREAM_CNT];     // mute request counter
             const sp<IOProfile> mProfile;          // I/O profile this output derives from
@@ -422,7 +433,7 @@
 
         // descriptor for audio inputs. Used to maintain current configuration of each opened audio input
         // and keep track of the usage of this input.
-        class AudioInputDescriptor
+        class AudioInputDescriptor: public AudioPortConfig
         {
         public:
             AudioInputDescriptor(const sp<IOProfile>& profile);
@@ -431,16 +442,13 @@
 
             audio_port_handle_t mId;
             audio_io_handle_t mIoHandle;              // input handle
-            uint32_t mSamplingRate;                     //
-            audio_format_t mFormat;                     // input configuration
-            audio_channel_mask_t mChannelMask;             //
             audio_devices_t mDevice;                    // current device this input is routed to
             audio_patch_handle_t mPatchHandle;
             uint32_t mRefCount;                         // number of AudioRecord clients using this output
             audio_source_t mInputSource;                // input source selected by application (mediarecorder.h)
             const sp<IOProfile> mProfile;                  // I/O profile this output derives from
 
-            void toAudioPortConfig(struct audio_port_config *dstConfig,
+            virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
                                    const struct audio_port_config *srcConfig = NULL) const;
             void toAudioPort(struct audio_port *port) const;
         };
@@ -463,7 +471,7 @@
         };
 
         // stream descriptor used for volume control
-        class EffectDescriptor
+        class EffectDescriptor : public RefBase
         {
         public:
 
@@ -476,8 +484,8 @@
             bool mEnabled;              // enabled state: CPU load being used or not
         };
 
-        void addOutput(audio_io_handle_t output, AudioOutputDescriptor *outputDesc);
-        void addInput(audio_io_handle_t input, AudioInputDescriptor *inputDesc);
+        void addOutput(audio_io_handle_t output, sp<AudioOutputDescriptor> outputDesc);
+        void addInput(audio_io_handle_t input, sp<AudioInputDescriptor> inputDesc);
 
         // return the strategy corresponding to a given stream type
         static routing_strategy getStrategy(audio_stream_type_t stream);
@@ -618,7 +626,7 @@
         int testOutputIndex(audio_io_handle_t output);
 #endif //AUDIO_POLICY_TEST
 
-        status_t setEffectEnabled(EffectDescriptor *pDesc, bool enabled);
+        status_t setEffectEnabled(const sp<EffectDescriptor>& effectDesc, bool enabled);
 
         // returns the category the device belongs to with regard to volume curve management
         static device_category getDeviceCategory(audio_devices_t device);
@@ -627,7 +635,7 @@
         static audio_devices_t getDeviceForVolume(audio_devices_t device);
 
         SortedVector<audio_io_handle_t> getOutputsForDevice(audio_devices_t device,
-                        DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> openOutputs);
+                        DefaultKeyedVector<audio_io_handle_t, sp<AudioOutputDescriptor> > openOutputs);
         bool vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
                                            SortedVector<audio_io_handle_t>& outputs2);
 
@@ -635,7 +643,7 @@
         // if muting, wait for the audio in pcm buffer to be drained before proceeding
         // if unmuting, unmute only after the specified delay
         // Returns the number of ms waited
-        uint32_t  checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
+        uint32_t  checkDeviceMuteStrategies(sp<AudioOutputDescriptor> outputDesc,
                                             audio_devices_t prevDevice,
                                             uint32_t delayMs);
 
@@ -659,10 +667,10 @@
                                const sp<AudioPatch>& patch);
         status_t removeAudioPatch(audio_patch_handle_t handle);
 
-        AudioOutputDescriptor *getOutputFromId(audio_port_handle_t id) const;
-        AudioInputDescriptor *getInputFromId(audio_port_handle_t id) const;
-        HwModule *getModuleForDevice(audio_devices_t device) const;
-        HwModule *getModuleFromName(const char *name) const;
+        sp<AudioOutputDescriptor> getOutputFromId(audio_port_handle_t id) const;
+        sp<AudioInputDescriptor> getInputFromId(audio_port_handle_t id) const;
+        sp<HwModule> getModuleForDevice(audio_devices_t device) const;
+        sp<HwModule> getModuleFromName(const char *name) const;
         //
         // Audio policy configuration file parsing (audio_policy.conf)
         //
@@ -677,7 +685,7 @@
         static audio_devices_t parseDeviceNames(char *name);
         void loadHwModule(cnode *root);
         void loadHwModules(cnode *root);
-        void loadGlobalConfig(cnode *root, HwModule *module);
+        void loadGlobalConfig(cnode *root, const sp<HwModule>& module);
         status_t loadAudioPolicyConfig(const char *path);
         void defaultAudioPolicyConfig(void);
 
@@ -686,11 +694,11 @@
         AudioPolicyClientInterface *mpClientInterface;  // audio policy client interface
         audio_io_handle_t mPrimaryOutput;              // primary output handle
         // list of descriptors for outputs currently opened
-        DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mOutputs;
+        DefaultKeyedVector<audio_io_handle_t, sp<AudioOutputDescriptor> > mOutputs;
         // copy of mOutputs before setDeviceConnectionState() opens new outputs
         // reset to mOutputs when updateDevicesAndOutputs() is called.
-        DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mPreviousOutputs;
-        DefaultKeyedVector<audio_io_handle_t, AudioInputDescriptor *> mInputs;     // list of input descriptors
+        DefaultKeyedVector<audio_io_handle_t, sp<AudioOutputDescriptor> > mPreviousOutputs;
+        DefaultKeyedVector<audio_io_handle_t, sp<AudioInputDescriptor> > mInputs;     // list of input descriptors
         DeviceVector  mAvailableOutputDevices; // all available output devices
         DeviceVector  mAvailableInputDevices;  // all available input devices
         int mPhoneState;                                                    // current phone state
@@ -707,13 +715,13 @@
         static const uint32_t MAX_EFFECTS_MEMORY = 512;
         uint32_t mTotalEffectsCpuLoad; // current CPU load used by effects
         uint32_t mTotalEffectsMemory;  // current memory used by effects
-        KeyedVector<int, EffectDescriptor *> mEffects;  // list of registered audio effects
+        KeyedVector<int, sp<EffectDescriptor> > mEffects;  // list of registered audio effects
         bool    mA2dpSuspended;  // true if A2DP output is suspended
         sp<DeviceDescriptor> mDefaultOutputDevice; // output device selected by default at boot time
         bool mSpeakerDrcEnabled;// true on devices that use DRC on the DEVICE_CATEGORY_SPEAKER path
                                 // to boost soft sounds, used to adjust volume curves accordingly
 
-        Vector <HwModule *> mHwModules;
+        Vector < sp<HwModule> > mHwModules;
         volatile int32_t mNextUniqueId;
         volatile int32_t mAudioPortGeneration;
 
diff --git a/services/audiopolicy/audio_policy.conf b/services/audiopolicy/audio_policy.conf
new file mode 100644
index 0000000..9b83fef
--- /dev/null
+++ b/services/audiopolicy/audio_policy.conf
@@ -0,0 +1,145 @@
+#
+# Template audio policy configuration file
+#
+
+# Global configuration section:
+# - before audio HAL version 3.0:
+#   lists input and output devices always present on the device
+#   as well as the output device selected by default.
+#   Devices are designated by a string that corresponds to the enum in audio.h
+#
+#  global_configuration {
+#    attached_output_devices AUDIO_DEVICE_OUT_SPEAKER
+#    default_output_device AUDIO_DEVICE_OUT_SPEAKER
+#    attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_REMOTE_SUBMIX
+#  }
+#
+# - after and including audio HAL 3.0 the global_configuration section is included in each
+#   hardware module section.
+#   it also includes the audio HAL version of this hw module:
+#  global_configuration {
+#    ...
+#     audio_hal_version <major.minor>  # audio HAL version in e.g. 3.0
+#  }
+#   other attributes (attached devices, default device) have to be included in the
+#   global_configuration section of each hardware module
+
+
+# audio hardware module section: contains descriptors for all audio hw modules present on the
+# device. Each hw module node is named after the corresponding hw module library base name.
+# For instance, "primary" corresponds to audio.primary.<device>.so.
+# The "primary" module is mandatory and must include at least one output with
+# AUDIO_OUTPUT_FLAG_PRIMARY flag.
+# Each module descriptor contains one or more output profile descriptors and zero or more
+# input profile descriptors. Each profile lists all the parameters supported by a given output
+# or input stream category.
+# The "channel_masks", "formats", "devices" and "flags" are specified using strings corresponding
+# to enums in audio.h and audio_policy.h. They are concatenated by use of "|" without space or "\n".
+#
+# For audio HAL version posterior to 3.0 the following sections or sub sections can be present in
+# a hw module section:
+# - A "global_configuration" section: see above
+# - Optionally a "devices" section:
+#   This section contains descriptors for audio devices with attributes like an address or a
+#   gain controller. The syntax for the devices section and device descriptor is as follows:
+#    devices {
+#      <device name> {              # <device name>: any string without space
+#        type <device type>         # <device type> e.g. AUDIO_DEVICE_OUT_SPEAKER
+#        address <address>          # optional: device address, char string less than 64 in length
+#      }
+#    }
+# - one or more "gains" sections can be present in a device descriptor section.
+#   If present, they describe the capabilities of gain controllers attached to this input or
+#   output device. e.g. :
+#   <device name> {                  # <device name>: any string without space
+#     type <device type>             # <device type> e.g. AUDIO_DEVICE_OUT_SPEAKER
+#     address <address>              # optional: device address, char string less than 64 in length
+#     gains {
+#       <gain name> {
+#         mode <gain modes supported>              # e.g. AUDIO_GAIN_MODE_CHANNELS
+#         channel_mask <controlled channels>       # needed if mode AUDIO_GAIN_MODE_CHANNELS
+#         min_value_mB <min value in millibel>
+#         max_value_mB <max value in millibel>
+#         default_value_mB <default value in millibel>
+#         step_value_mB <step value in millibel>
+#         min_ramp_ms <min duration in ms>         # needed if mode AUDIO_GAIN_MODE_RAMP
+#         max_ramp_ms <max duration ms>            # needed if mode AUDIO_GAIN_MODE_RAMP
+#       }
+#     }
+#   }
+# - when a device descriptor is present, output and input profiles can refer to this device by
+# its name in their "devices" section instead of specifying a device type. e.g. :
+#   outputs {
+#     primary {
+#       sampling_rates 44100
+#       channel_masks AUDIO_CHANNEL_OUT_STEREO
+#       formats AUDIO_FORMAT_PCM_16_BIT
+#       devices <device name>
+#       flags AUDIO_OUTPUT_FLAG_PRIMARY
+#     }
+#   }
+# sample audio_policy.conf file below
+
+audio_hw_modules {
+  primary {
+    global_configuration {
+      attached_output_devices AUDIO_DEVICE_OUT_SPEAKER
+      default_output_device AUDIO_DEVICE_OUT_SPEAKER
+      attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC
+      audio_hal_version 3.0
+    }
+    devices {
+      speaker {
+        type AUDIO_DEVICE_OUT_SPEAKER
+        gains {
+          gain_1 {
+            mode AUDIO_GAIN_MODE_JOINT
+            min_value_mB -8400
+            max_value_mB 4000
+            default_value_mB 0
+            step_value_mB 100
+          }
+        }
+      }
+    }
+    outputs {
+      primary {
+        sampling_rates 48000
+        channel_masks AUDIO_CHANNEL_OUT_STEREO
+        formats AUDIO_FORMAT_PCM_16_BIT
+        devices speaker
+        flags AUDIO_OUTPUT_FLAG_PRIMARY
+      }
+    }
+    inputs {
+      primary {
+        sampling_rates 8000|16000
+        channel_masks AUDIO_CHANNEL_IN_MONO
+        formats AUDIO_FORMAT_PCM_16_BIT
+        devices AUDIO_DEVICE_IN_BUILTIN_MIC
+      }
+    }
+  }
+  r_submix {
+    global_configuration {
+      attached_input_devices AUDIO_DEVICE_IN_REMOTE_SUBMIX
+      audio_hal_version 2.0
+    }
+    outputs {
+      submix {
+        sampling_rates 48000
+        channel_masks AUDIO_CHANNEL_OUT_STEREO
+        formats AUDIO_FORMAT_PCM_16_BIT
+        devices AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+      }
+    }
+    inputs {
+      submix {
+        sampling_rates 48000
+        channel_masks AUDIO_CHANNEL_IN_STEREO
+        formats AUDIO_FORMAT_PCM_16_BIT
+        devices AUDIO_DEVICE_IN_REMOTE_SUBMIX
+      }
+    }
+  }
+}
diff --git a/services/audiopolicy/audio_policy_conf.h b/services/audiopolicy/audio_policy_conf.h
index 79f20f1..2535a67 100644
--- a/services/audiopolicy/audio_policy_conf.h
+++ b/services/audiopolicy/audio_policy_conf.h
@@ -35,6 +35,7 @@
 #define DEFAULT_OUTPUT_DEVICE_TAG "default_output_device"
 #define ATTACHED_INPUT_DEVICES_TAG "attached_input_devices"
 #define SPEAKER_DRC_ENABLED_TAG "speaker_drc_enabled"
+#define AUDIO_HAL_VERSION_TAG "audio_hal_version"
 
 // hw modules descriptions
 #define AUDIO_HW_MODULE_TAG "audio_hw_modules"
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 9fd35e1..638b871 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -852,13 +852,12 @@
 
         switch(deviceVersion) {
           case CAMERA_DEVICE_API_VERSION_1_0:
-            ALOGW("Camera using old HAL version: %d", deviceVersion);
-            return -EOPNOTSUPP;
-           // TODO: don't allow 2.0  Only allow 2.1 and higher
           case CAMERA_DEVICE_API_VERSION_2_0:
           case CAMERA_DEVICE_API_VERSION_2_1:
           case CAMERA_DEVICE_API_VERSION_3_0:
           case CAMERA_DEVICE_API_VERSION_3_1:
+            ALOGW("Camera using old HAL version: %d", deviceVersion);
+            return -EOPNOTSUPP;
           case CAMERA_DEVICE_API_VERSION_3_2:
             client = new CameraDeviceClient(this, cameraCb, String16(),
                     cameraId, facing, callingPid, USE_CALLING_UID, getpid());
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 4fce1b3..8154e59 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -310,6 +310,10 @@
 
     Mutex::Autolock icl(mBinderSerializationLock);
 
+    if (bufferProducer == NULL) {
+        ALOGE("%s: bufferProducer must not be null", __FUNCTION__);
+        return BAD_VALUE;
+    }
     if (!mDevice.get()) return DEAD_OBJECT;
 
     // Don't create multiple streams for the same target surface