Merge "NuPlayerDriver: do not set to paused state when receiving playback complete and reset is in progress." into lmp-dev
diff --git a/include/media/MediaProfiles.h b/include/media/MediaProfiles.h
index 253c557..f061d22 100644
--- a/include/media/MediaProfiles.h
+++ b/include/media/MediaProfiles.h
@@ -54,7 +54,8 @@
     CAMCORDER_QUALITY_HIGH_SPEED_480P = 2002,
     CAMCORDER_QUALITY_HIGH_SPEED_720P = 2003,
     CAMCORDER_QUALITY_HIGH_SPEED_1080P = 2004,
-    CAMCORDER_QUALITY_HIGH_SPEED_LIST_END = 2004,
+    CAMCORDER_QUALITY_HIGH_SPEED_2160P = 2005,
+    CAMCORDER_QUALITY_HIGH_SPEED_LIST_END = 2005,
 };
 
 /**
diff --git a/include/media/stagefright/MediaErrors.h b/include/media/stagefright/MediaErrors.h
index 7540e07..2e663ec 100644
--- a/include/media/stagefright/MediaErrors.h
+++ b/include/media/stagefright/MediaErrors.h
@@ -58,20 +58,22 @@
     // drm/drm_framework_common.h
     DRM_ERROR_BASE = -2000,
 
-    ERROR_DRM_UNKNOWN                       = DRM_ERROR_BASE,
-    ERROR_DRM_NO_LICENSE                    = DRM_ERROR_BASE - 1,
-    ERROR_DRM_LICENSE_EXPIRED               = DRM_ERROR_BASE - 2,
-    ERROR_DRM_SESSION_NOT_OPENED            = DRM_ERROR_BASE - 3,
-    ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED  = DRM_ERROR_BASE - 4,
-    ERROR_DRM_DECRYPT                       = DRM_ERROR_BASE - 5,
-    ERROR_DRM_CANNOT_HANDLE                 = DRM_ERROR_BASE - 6,
-    ERROR_DRM_TAMPER_DETECTED               = DRM_ERROR_BASE - 7,
-    ERROR_DRM_NOT_PROVISIONED               = DRM_ERROR_BASE - 8,
-    ERROR_DRM_DEVICE_REVOKED                = DRM_ERROR_BASE - 9,
-    ERROR_DRM_RESOURCE_BUSY                 = DRM_ERROR_BASE - 10,
+    ERROR_DRM_UNKNOWN                        = DRM_ERROR_BASE,
+    ERROR_DRM_NO_LICENSE                     = DRM_ERROR_BASE - 1,
+    ERROR_DRM_LICENSE_EXPIRED                = DRM_ERROR_BASE - 2,
+    ERROR_DRM_SESSION_NOT_OPENED             = DRM_ERROR_BASE - 3,
+    ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED   = DRM_ERROR_BASE - 4,
+    ERROR_DRM_DECRYPT                        = DRM_ERROR_BASE - 5,
+    ERROR_DRM_CANNOT_HANDLE                  = DRM_ERROR_BASE - 6,
+    ERROR_DRM_TAMPER_DETECTED                = DRM_ERROR_BASE - 7,
+    ERROR_DRM_NOT_PROVISIONED                = DRM_ERROR_BASE - 8,
+    ERROR_DRM_DEVICE_REVOKED                 = DRM_ERROR_BASE - 9,
+    ERROR_DRM_RESOURCE_BUSY                  = DRM_ERROR_BASE - 10,
+    ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION = DRM_ERROR_BASE - 11,
+    ERROR_DRM_LAST_USED_ERRORCODE            = DRM_ERROR_BASE - 11,
 
-    ERROR_DRM_VENDOR_MAX                    = DRM_ERROR_BASE - 500,
-    ERROR_DRM_VENDOR_MIN                    = DRM_ERROR_BASE - 999,
+    ERROR_DRM_VENDOR_MAX                     = DRM_ERROR_BASE - 500,
+    ERROR_DRM_VENDOR_MIN                     = DRM_ERROR_BASE - 999,
 
     // Heartbeat Error Codes
     HEARTBEAT_ERROR_BASE = -3000,
@@ -100,7 +102,7 @@
 
 // returns true if err is a recognized DRM error code
 static inline bool isCryptoError(status_t err) {
-    return (ERROR_DRM_RESOURCE_BUSY <= err && err <= ERROR_DRM_UNKNOWN)
+    return (ERROR_DRM_LAST_USED_ERRORCODE <= err && err <= ERROR_DRM_UNKNOWN)
             || (ERROR_DRM_VENDOR_MIN <= err && err <= ERROR_DRM_VENDOR_MAX);
 }
 
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index d2e181b..e2e6042 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -87,6 +87,7 @@
     {"highspeed480p", CAMCORDER_QUALITY_HIGH_SPEED_480P},
     {"highspeed720p", CAMCORDER_QUALITY_HIGH_SPEED_720P},
     {"highspeed1080p", CAMCORDER_QUALITY_HIGH_SPEED_1080P},
+    {"highspeed2160p", CAMCORDER_QUALITY_HIGH_SPEED_2160P},
 };
 
 #if LOG_NDEBUG
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index c9be0dd..ab7906a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -115,9 +115,12 @@
     notify->post();
     mPendingBuffers++;
 
-    sp<AMessage> message = new AMessage(kWhatRequestABuffer, id());
-    message->setInt32("generation", mBufferGeneration);
-    message->post();
+    // pending buffers will already result in requestABuffer
+    if (mPendingBuffers < kMaxPendingBuffers) {
+        sp<AMessage> message = new AMessage(kWhatRequestABuffer, id());
+        message->setInt32("generation", mBufferGeneration);
+        message->post();
+    }
     return;
 }
 
@@ -155,9 +158,7 @@
 void NuPlayer::DecoderPassThrough::onBufferConsumed(int32_t size) {
     mPendingBuffers--;
     mCachedBytes -= size;
-    sp<AMessage> message = new AMessage(kWhatRequestABuffer, id());
-    message->setInt32("generation", mBufferGeneration);
-    message->post();
+    requestABuffer();
 }
 
 void NuPlayer::DecoderPassThrough::onFlush() {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index fc2dd30..0bfc6e4 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -270,7 +270,20 @@
     }
 
     sp<AMessage> response;
-    return PostAndAwaitResponse(msg, &response);
+    status_t err = PostAndAwaitResponse(msg, &response);
+
+    if (err != OK && err != INVALID_OPERATION) {
+        // MediaCodec now set state to UNINITIALIZED upon any fatal error.
+        // To maintain backward-compatibility, do a reset() to put codec
+        // back into INITIALIZED state.
+        // But don't reset if the err is INVALID_OPERATION, which means
+        // the configure failure is due to wrong state.
+
+        ALOGE("configure failed with err 0x%08x, resetting...", err);
+        reset();
+    }
+
+    return err;
 }
 
 status_t MediaCodec::createInputSurface(
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 6dd9b92..8b4dd6f 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-//#define LOG_NDEBUG 0
 #define LOG_TAG "SoftAAC2"
+//#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
 #include "SoftAAC2.h"
@@ -68,6 +68,7 @@
       mOutputBufferCount(0),
       mSignalledError(false),
       mLastInHeader(NULL),
+      mCurrentInputTime(0),
       mOutputPortSettingsChange(NONE) {
     initPorts();
     CHECK_EQ(initDecoder(), (status_t)OK);
@@ -609,24 +610,9 @@
                     notify(OMX_EventError, OMX_ErrorStreamCorrupt, ERROR_MALFORMED, NULL);
                     return;
                 }
-
-                // insert buffer size and time stamp
-                mBufferSizes.add(inBufferLength[0]);
-                if (mLastInHeader != inHeader) {
-                    mBufferTimestamps.add(inHeader->nTimeStamp);
-                    mLastInHeader = inHeader;
-                } else {
-                    int64_t currentTime = mBufferTimestamps.top();
-                    currentTime += mStreamInfo->aacSamplesPerFrame *
-                            1000000ll / mStreamInfo->sampleRate;
-                    mBufferTimestamps.add(currentTime);
-                }
             } else {
                 inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
                 inBufferLength[0] = inHeader->nFilledLen;
-                mLastInHeader = inHeader;
-                mBufferTimestamps.add(inHeader->nTimeStamp);
-                mBufferSizes.add(inHeader->nFilledLen);
             }
 
             // Fill and decode
@@ -635,130 +621,136 @@
             INT prevSampleRate = mStreamInfo->sampleRate;
             INT prevNumChannels = mStreamInfo->numChannels;
 
+            if (inHeader != mLastInHeader) {
+                mLastInHeader = inHeader;
+                mCurrentInputTime = inHeader->nTimeStamp;
+            } else {
+                if (mStreamInfo->sampleRate) {
+                    mCurrentInputTime += mStreamInfo->aacSamplesPerFrame *
+                            1000000ll / mStreamInfo->sampleRate;
+                } else {
+                    ALOGW("no sample rate yet");
+                }
+            }
+            mAnchorTimes.add(mCurrentInputTime);
             aacDecoder_Fill(mAACDecoder,
                             inBuffer,
                             inBufferLength,
                             bytesValid);
 
-            // run DRC check
-            mDrcWrap.submitStreamData(mStreamInfo);
-            mDrcWrap.update();
+             // run DRC check
+             mDrcWrap.submitStreamData(mStreamInfo);
+             mDrcWrap.update();
 
-            UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
-            inHeader->nFilledLen -= inBufferUsedLength;
-            inHeader->nOffset += inBufferUsedLength;
+            AAC_DECODER_ERROR decoderErr =
+                aacDecoder_DecodeFrame(mAACDecoder,
+                                       tmpOutBuffer,
+                                       2048 * MAX_CHANNEL_COUNT,
+                                       0 /* flags */);
 
-            AAC_DECODER_ERROR decoderErr;
-            do {
-                int numconsumed = mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes;
-                decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
-                                           tmpOutBuffer,
-                                           2048 * MAX_CHANNEL_COUNT,
-                                           0 /* flags */);
+            if (decoderErr != AAC_DEC_OK) {
+                ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
+            }
 
-                numconsumed = (mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes) - numconsumed;
-                if (numconsumed != 0) {
-                    mDecodedSizes.add(numconsumed);
-                }
+            if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
+                ALOGE("AAC_DEC_NOT_ENOUGH_BITS should never happen");
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                return;
+            }
 
-                if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
-                    break;
-                }
+            if (bytesValid[0] != 0) {
+                ALOGE("bytesValid[0] != 0 should never happen");
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                return;
+            }
 
-                if (decoderErr != AAC_DEC_OK) {
-                    ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
-                }
+            size_t numOutBytes =
+                mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
 
-                if (bytesValid[0] != 0) {
-                    ALOGE("bytesValid[0] != 0 should never happen");
-                    mSignalledError = true;
-                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
-                    return;
-                }
-
-                size_t numOutBytes =
-                    mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
-
-                if (decoderErr == AAC_DEC_OK) {
-                    if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
-                            mStreamInfo->frameSize * mStreamInfo->numChannels)) {
-                        mSignalledError = true;
-                        notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
-                        return;
-                    }
-                } else {
-                    ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr);
-
-                    memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow
-
-                    if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
-                            mStreamInfo->frameSize * mStreamInfo->numChannels)) {
-                        mSignalledError = true;
-                        notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
-                        return;
-                    }
-
-                    // Discard input buffer.
-                    inHeader->nFilledLen = 0;
-
-                    aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
-
-                    // fall through
-                }
-
-                /*
-                 * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
-                 * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
-                 * rate system and the sampling rate in the final output is actually
-                 * doubled compared with the core AAC decoder sampling rate.
-                 *
-                 * Explicit signalling is done by explicitly defining SBR audio object
-                 * type in the bitstream. Implicit signalling is done by embedding
-                 * SBR content in AAC extension payload specific to SBR, and hence
-                 * requires an AAC decoder to perform pre-checks on actual audio frames.
-                 *
-                 * Thus, we could not say for sure whether a stream is
-                 * AAC+/eAAC+ until the first data frame is decoded.
-                 */
-                if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1
-                    if (mStreamInfo->sampleRate != prevSampleRate ||
-                        mStreamInfo->numChannels != prevNumChannels) {
-                        ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels",
-                              prevSampleRate, mStreamInfo->sampleRate,
-                              prevNumChannels, mStreamInfo->numChannels);
-
-                        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
-                        mOutputPortSettingsChange = AWAITING_DISABLED;
-
-                        if (inHeader->nFilledLen == 0) {
-                            inInfo->mOwnedByUs = false;
-                            mInputBufferCount++;
-                            inQueue.erase(inQueue.begin());
-                            mLastInHeader = NULL;
-                            inInfo = NULL;
-                            notifyEmptyBufferDone(inHeader);
-                            inHeader = NULL;
-                        }
-                        return;
-                    }
-                } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) {
-                    ALOGW("Invalid AAC stream");
+            if (decoderErr == AAC_DEC_OK) {
+                if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
+                        mStreamInfo->frameSize * mStreamInfo->numChannels)) {
                     mSignalledError = true;
                     notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
                     return;
                 }
-                if (inHeader && inHeader->nFilledLen == 0) {
-                    inInfo->mOwnedByUs = false;
-                    mInputBufferCount++;
-                    inQueue.erase(inQueue.begin());
-                    mLastInHeader = NULL;
-                    inInfo = NULL;
-                    notifyEmptyBufferDone(inHeader);
-                    inHeader = NULL;
-                } else {
-                    ALOGV("inHeader->nFilledLen = %d", inHeader ? inHeader->nFilledLen : 0);
+                UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
+                inHeader->nFilledLen -= inBufferUsedLength;
+                inHeader->nOffset += inBufferUsedLength;
+            } else {
+                ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr);
+
+                memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow
+
+                if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
+                        mStreamInfo->frameSize * mStreamInfo->numChannels)) {
+                    mSignalledError = true;
+                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+                    return;
                 }
-            } while (decoderErr == AAC_DEC_OK);
+
+                // Discard input buffer.
+                inHeader->nFilledLen = 0;
+
+                aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
+
+                // fall through
+            }
+
+            /*
+             * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
+             * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
+             * rate system and the sampling rate in the final output is actually
+             * doubled compared with the core AAC decoder sampling rate.
+             *
+             * Explicit signalling is done by explicitly defining SBR audio object
+             * type in the bitstream. Implicit signalling is done by embedding
+             * SBR content in AAC extension payload specific to SBR, and hence
+             * requires an AAC decoder to perform pre-checks on actual audio frames.
+             *
+             * Thus, we could not say for sure whether a stream is
+             * AAC+/eAAC+ until the first data frame is decoded.
+             */
+            if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1
+                if (mStreamInfo->sampleRate != prevSampleRate ||
+                    mStreamInfo->numChannels != prevNumChannels) {
+                    ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels",
+                          prevSampleRate, mStreamInfo->sampleRate,
+                          prevNumChannels, mStreamInfo->numChannels);
+
+                    notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+                    mOutputPortSettingsChange = AWAITING_DISABLED;
+
+                    if (inHeader->nFilledLen == 0) {
+                        inInfo->mOwnedByUs = false;
+                        mInputBufferCount++;
+                        inQueue.erase(inQueue.begin());
+                        mLastInHeader = NULL;
+                        inInfo = NULL;
+                        notifyEmptyBufferDone(inHeader);
+                        inHeader = NULL;
+                    }
+                    return;
+                }
+            } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) {
+                ALOGW("Invalid AAC stream");
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+                return;
+            }
+            if (inHeader->nFilledLen == 0) {
+                inInfo->mOwnedByUs = false;
+                mInputBufferCount++;
+                inQueue.erase(inQueue.begin());
+                mLastInHeader = NULL;
+                inInfo = NULL;
+                notifyEmptyBufferDone(inHeader);
+                inHeader = NULL;
+            } else {
+                ALOGV("inHeader->nFilledLen = %d", inHeader->nFilledLen);
+            }
         }
 
         int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels;
@@ -817,9 +809,8 @@
 
             INT_PCM *outBuffer =
                     reinterpret_cast<INT_PCM *>(outHeader->pBuffer + outHeader->nOffset);
-            int samplesize = mStreamInfo->numChannels * sizeof(int16_t);
             if (outHeader->nOffset
-                    + mStreamInfo->frameSize * samplesize
+                    + mStreamInfo->frameSize * mStreamInfo->numChannels * sizeof(int16_t)
                     > outHeader->nAllocLen) {
                 ALOGE("buffer overflow");
                 mSignalledError = true;
@@ -827,67 +818,17 @@
                 return;
 
             }
-
-            int available = outputDelayRingBufferSamplesAvailable();
-            int numSamples = outHeader->nAllocLen / samplesize;
-            if (numSamples > available) {
-                numSamples = available;
-            }
-            int64_t currentTime = 0;
-            if (available) {
-
-                int numFrames = numSamples / (mStreamInfo->frameSize * mStreamInfo->numChannels);
-                numSamples = numFrames * (mStreamInfo->frameSize * mStreamInfo->numChannels);
-
-                ALOGV("%d samples available (%d), or %d frames",
-                        numSamples, available, numFrames);
-                int64_t *nextTimeStamp = &mBufferTimestamps.editItemAt(0);
-                currentTime = *nextTimeStamp;
-                int32_t *currentBufLeft = &mBufferSizes.editItemAt(0);
-                for (int i = 0; i < numFrames; i++) {
-                    int32_t decodedSize = mDecodedSizes.itemAt(0);
-                    mDecodedSizes.removeAt(0);
-                    ALOGV("decoded %d of %d", decodedSize, *currentBufLeft);
-                    if (*currentBufLeft > decodedSize) {
-                        // adjust/interpolate next time stamp
-                        *currentBufLeft -= decodedSize;
-                        *nextTimeStamp += mStreamInfo->aacSamplesPerFrame *
-                                1000000ll / mStreamInfo->sampleRate;
-                        ALOGV("adjusted nextTimeStamp/size to %lld/%d",
-                                *nextTimeStamp, *currentBufLeft);
-                    } else {
-                        // move to next timestamp in list
-                        if (mBufferTimestamps.size() > 0) {
-                            mBufferTimestamps.removeAt(0);
-                            nextTimeStamp = &mBufferTimestamps.editItemAt(0);
-                            mBufferSizes.removeAt(0);
-                            currentBufLeft = &mBufferSizes.editItemAt(0);
-                            ALOGV("moved to next time/size: %lld/%d",
-                                    *nextTimeStamp, *currentBufLeft);
-                        }
-                        // try to limit output buffer size to match input buffers
-                        // (e.g when an input buffer contained 4 "sub" frames, output
-                        // at most 4 decoded units in the corresponding output buffer)
-                        // This is optional. Remove the next three lines to fill the output
-                        // buffer with as many units as available.
-                        numFrames = i + 1;
-                        numSamples = numFrames * mStreamInfo->frameSize * mStreamInfo->numChannels;
-                        break;
-                    }
-                }
-
-                ALOGV("getting %d from ringbuffer", numSamples);
-                int32_t ns = outputDelayRingBufferGetSamples(outBuffer, numSamples);
-                if (ns != numSamples) {
-                    ALOGE("not a complete frame of samples available");
-                    mSignalledError = true;
-                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
-                    return;
-                }
+            int32_t ns = outputDelayRingBufferGetSamples(outBuffer,
+                    mStreamInfo->frameSize * mStreamInfo->numChannels); // TODO: check for overflow
+            if (ns != mStreamInfo->frameSize * mStreamInfo->numChannels) {
+                ALOGE("not a complete frame of samples available");
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                return;
             }
 
-            outHeader->nFilledLen = numSamples * sizeof(int16_t);
-
+            outHeader->nFilledLen = mStreamInfo->frameSize * mStreamInfo->numChannels
+                    * sizeof(int16_t);
             if (mEndOfInput && !outQueue.empty() && outputDelayRingBufferSamplesAvailable() == 0) {
                 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
                 mEndOfOutput = true;
@@ -895,13 +836,13 @@
                 outHeader->nFlags = 0;
             }
 
-            outHeader->nTimeStamp = currentTime;
+            outHeader->nTimeStamp = mAnchorTimes.isEmpty() ? 0 : mAnchorTimes.itemAt(0);
+            mAnchorTimes.removeAt(0);
 
             mOutputBufferCount++;
             outInfo->mOwnedByUs = false;
             outQueue.erase(outQueue.begin());
             outInfo = NULL;
-            ALOGV("out timestamp %lld / %d", outHeader->nTimeStamp, outHeader->nFilledLen);
             notifyFillBufferDone(outHeader);
             outHeader = NULL;
         }
@@ -936,10 +877,8 @@
                     outHeader->nFilledLen = 0;
                     outHeader->nFlags = OMX_BUFFERFLAG_EOS;
 
-                    outHeader->nTimeStamp = mBufferTimestamps.itemAt(0);
-                    mBufferTimestamps.clear();
-                    mBufferSizes.clear();
-                    mDecodedSizes.clear();
+                    outHeader->nTimeStamp = mAnchorTimes.itemAt(0);
+                    mAnchorTimes.removeAt(0);
 
                     mOutputBufferCount++;
                     outInfo->mOwnedByUs = false;
@@ -960,9 +899,7 @@
         // depend on fragments from the last one decoded.
         // drain all existing data
         drainDecoder();
-        mBufferTimestamps.clear();
-        mBufferSizes.clear();
-        mDecodedSizes.clear();
+        mAnchorTimes.clear();
         mLastInHeader = NULL;
     } else {
         while (outputDelayRingBufferSamplesAvailable() > 0) {
@@ -1018,9 +955,7 @@
     mOutputDelayRingBufferReadPos = 0;
     mEndOfInput = false;
     mEndOfOutput = false;
-    mBufferTimestamps.clear();
-    mBufferSizes.clear();
-    mDecodedSizes.clear();
+    mAnchorTimes.clear();
     mLastInHeader = NULL;
 
     // To make the codec behave the same before and after a reset, we need to invalidate the
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h
index 9fcb598..865bd15 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h
@@ -59,9 +59,8 @@
     size_t mOutputBufferCount;
     bool mSignalledError;
     OMX_BUFFERHEADERTYPE *mLastInHeader;
-    Vector<int32_t> mBufferSizes;
-    Vector<int32_t> mDecodedSizes;
-    Vector<int64_t> mBufferTimestamps;
+    int64_t mCurrentInputTime;
+    Vector<int64_t> mAnchorTimes;
 
     CDrcPresModeWrapper mDrcWrap;
 
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 2d0a25f..7544052 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -593,10 +593,10 @@
                         status = BAD_VALUE;
                         break;
                     }
-                    status = thread->sendReleaseAudioPatchConfigEvent(mPatches[index]->mHalHandle);
+                    status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle);
                 } else {
                     audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
-                    status = hwDevice->release_audio_patch(hwDevice, mPatches[index]->mHalHandle);
+                    status = hwDevice->release_audio_patch(hwDevice, removedPatch->mHalHandle);
                 }
             } else {
                 sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
@@ -632,7 +632,7 @@
             }
             AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
             if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
-                status = thread->sendReleaseAudioPatchConfigEvent(mPatches[index]->mHalHandle);
+                status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle);
             } else {
                 AudioParameter param;
                 param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), 0);
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 9d6ab23..e184d97 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -34,6 +34,7 @@
     api1/client2/JpegProcessor.cpp \
     api1/client2/CallbackProcessor.cpp \
     api1/client2/ZslProcessor.cpp \
+    api1/client2/ZslProcessorInterface.cpp \
     api1/client2/BurstCapture.cpp \
     api1/client2/JpegCompressor.cpp \
     api1/client2/CaptureSequencer.cpp \
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index d59ee51..36a93b2 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -434,6 +434,9 @@
     mCallbackProcessor->deleteStream();
     mZslProcessor->deleteStream();
 
+    // Remove all ZSL stream state before disconnect; needed to work around b/15408128.
+    mZslProcessor->disconnect();
+
     ALOGV("Camera %d: Disconnecting device", mCameraId);
 
     mDevice->disconnect();
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 8fb876e..bb72206 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -48,6 +48,7 @@
         mDevice(client->getCameraDevice()),
         mSequencer(sequencer),
         mId(client->getCameraId()),
+        mDeleted(false),
         mZslBufferAvailable(false),
         mZslStreamId(NO_STREAM),
         mZslReprocessStreamId(NO_STREAM),
@@ -62,7 +63,7 @@
 
 ZslProcessor::~ZslProcessor() {
     ALOGV("%s: Exit", __FUNCTION__);
-    deleteStream();
+    disconnect();
 }
 
 void ZslProcessor::onFrameAvailable() {
@@ -153,7 +154,7 @@
                     mId, strerror(-res), res);
             return res;
         }
-        if (currentWidth != (uint32_t)params.fastInfo.arrayWidth ||
+        if (mDeleted || currentWidth != (uint32_t)params.fastInfo.arrayWidth ||
                 currentHeight != (uint32_t)params.fastInfo.arrayHeight) {
             res = device->deleteReprocessStream(mZslReprocessStreamId);
             if (res != OK) {
@@ -175,6 +176,8 @@
         }
     }
 
+    mDeleted = false;
+
     if (mZslStreamId == NO_STREAM) {
         // Create stream for HAL production
         // TODO: Sort out better way to select resolution for ZSL
@@ -209,6 +212,14 @@
 
 status_t ZslProcessor::deleteStream() {
     ATRACE_CALL();
+    Mutex::Autolock l(mInputMutex);
+    // WAR(b/15408128): do not delete stream unless client is being disconnected.
+    mDeleted = true;
+    return OK;
+}
+
+status_t ZslProcessor::disconnect() {
+    ATRACE_CALL();
     status_t res;
 
     Mutex::Autolock l(mInputMutex);
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.h b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
index f4cf0c8..b6533cf 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
@@ -67,6 +67,7 @@
 
     status_t updateStream(const Parameters &params);
     status_t deleteStream();
+    status_t disconnect();
     int getStreamId() const;
 
     status_t pushToReprocess(int32_t requestId);
@@ -86,6 +87,8 @@
     wp<CaptureSequencer> mSequencer;
     int mId;
 
+    bool mDeleted;
+
     mutable Mutex mInputMutex;
     bool mZslBufferAvailable;
     Condition mZslBufferAvailableSignal;
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.cpp
new file mode 100644
index 0000000..9efeaba
--- /dev/null
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.cpp
@@ -0,0 +1,28 @@
+/*
+ * 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 "ZslProcessorInterface.h"
+
+namespace android {
+namespace camera2 {
+
+status_t ZslProcessorInterface::disconnect() {
+    return OK;
+}
+
+}; //namespace camera2
+}; //namespace android
+
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h b/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h
index 183c0c2..9e266e7 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h
@@ -19,6 +19,8 @@
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
 
 namespace android {
 namespace camera2 {
@@ -37,6 +39,9 @@
     // Delete the underlying CameraDevice streams
     virtual status_t deleteStream() = 0;
 
+    // Clear any additional state necessary before the CameraDevice is disconnected
+    virtual status_t disconnect();
+
     /**
      * Submits a ZSL capture request (id = requestId)
      *