Merge "Camera1: Validate scene mode override AF mode" into lmp-dev
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 8b4dd6f..4569c1c 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_TAG "SoftAAC2"
 //#define LOG_NDEBUG 0
+#define LOG_TAG "SoftAAC2"
 #include <utils/Log.h>
 
 #include "SoftAAC2.h"
@@ -68,7 +68,6 @@
       mOutputBufferCount(0),
       mSignalledError(false),
       mLastInHeader(NULL),
-      mCurrentInputTime(0),
       mOutputPortSettingsChange(NONE) {
     initPorts();
     CHECK_EQ(initDecoder(), (status_t)OK);
@@ -610,9 +609,24 @@
                     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
@@ -621,136 +635,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();
 
-            AAC_DECODER_ERROR decoderErr =
-                aacDecoder_DecodeFrame(mAACDecoder,
-                                       tmpOutBuffer,
-                                       2048 * MAX_CHANNEL_COUNT,
-                                       0 /* flags */);
+            UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
+            inHeader->nFilledLen -= inBufferUsedLength;
+            inHeader->nOffset += inBufferUsedLength;
 
-            if (decoderErr != AAC_DEC_OK) {
-                ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
-            }
-
-            if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
-                ALOGE("AAC_DEC_NOT_ENOUGH_BITS should never happen");
-                mSignalledError = true;
-                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
-                return;
-            }
-
-            if (bytesValid[0] != 0) {
-                ALOGE("bytesValid[0] != 0 should never happen");
-                mSignalledError = true;
-                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
-                return;
-            }
-
-            size_t numOutBytes =
-                mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
-
-            if (decoderErr == AAC_DEC_OK) {
-                if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
-                        mStreamInfo->frameSize * mStreamInfo->numChannels)) {
-                    mSignalledError = true;
-                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
-                    return;
+            AAC_DECODER_ERROR decoderErr;
+            do {
+                if (outputDelayRingBufferSamplesLeft() <
+                        (mStreamInfo->frameSize * mStreamInfo->numChannels)) {
+                    ALOGV("skipping decode: not enough space left in ringbuffer");
+                    break;
                 }
-                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
+                int numconsumed = mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes;
+                decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
+                                           tmpOutBuffer,
+                                           2048 * MAX_CHANNEL_COUNT,
+                                           0 /* flags */);
 
-                if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
-                        mStreamInfo->frameSize * mStreamInfo->numChannels)) {
+                numconsumed = (mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes) - numconsumed;
+                if (numconsumed != 0) {
+                    mDecodedSizes.add(numconsumed);
+                }
+
+                if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
+                    break;
+                }
+
+                if (decoderErr != AAC_DEC_OK) {
+                    ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
+                }
+
+                if (bytesValid[0] != 0) {
+                    ALOGE("bytesValid[0] != 0 should never happen");
                     mSignalledError = true;
-                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                     return;
                 }
 
-                // Discard input buffer.
-                inHeader->nFilledLen = 0;
+                size_t numOutBytes =
+                    mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
 
-                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;
+                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");
+                    mSignalledError = true;
+                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, 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);
-            }
+                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);
+                }
+            } while (decoderErr == AAC_DEC_OK);
         }
 
         int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels;
@@ -809,8 +823,9 @@
 
             INT_PCM *outBuffer =
                     reinterpret_cast<INT_PCM *>(outHeader->pBuffer + outHeader->nOffset);
+            int samplesize = mStreamInfo->numChannels * sizeof(int16_t);
             if (outHeader->nOffset
-                    + mStreamInfo->frameSize * mStreamInfo->numChannels * sizeof(int16_t)
+                    + mStreamInfo->frameSize * samplesize
                     > outHeader->nAllocLen) {
                 ALOGE("buffer overflow");
                 mSignalledError = true;
@@ -818,17 +833,67 @@
                 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;
+
+            int available = outputDelayRingBufferSamplesAvailable();
+            int numSamples = outHeader->nAllocLen / sizeof(int16_t);
+            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;
+                }
             }
 
-            outHeader->nFilledLen = mStreamInfo->frameSize * mStreamInfo->numChannels
-                    * sizeof(int16_t);
+            outHeader->nFilledLen = numSamples * sizeof(int16_t);
+
             if (mEndOfInput && !outQueue.empty() && outputDelayRingBufferSamplesAvailable() == 0) {
                 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
                 mEndOfOutput = true;
@@ -836,13 +901,13 @@
                 outHeader->nFlags = 0;
             }
 
-            outHeader->nTimeStamp = mAnchorTimes.isEmpty() ? 0 : mAnchorTimes.itemAt(0);
-            mAnchorTimes.removeAt(0);
+            outHeader->nTimeStamp = currentTime;
 
             mOutputBufferCount++;
             outInfo->mOwnedByUs = false;
             outQueue.erase(outQueue.begin());
             outInfo = NULL;
+            ALOGV("out timestamp %lld / %d", outHeader->nTimeStamp, outHeader->nFilledLen);
             notifyFillBufferDone(outHeader);
             outHeader = NULL;
         }
@@ -877,8 +942,10 @@
                     outHeader->nFilledLen = 0;
                     outHeader->nFlags = OMX_BUFFERFLAG_EOS;
 
-                    outHeader->nTimeStamp = mAnchorTimes.itemAt(0);
-                    mAnchorTimes.removeAt(0);
+                    outHeader->nTimeStamp = mBufferTimestamps.itemAt(0);
+                    mBufferTimestamps.clear();
+                    mBufferSizes.clear();
+                    mDecodedSizes.clear();
 
                     mOutputBufferCount++;
                     outInfo->mOwnedByUs = false;
@@ -899,7 +966,9 @@
         // depend on fragments from the last one decoded.
         // drain all existing data
         drainDecoder();
-        mAnchorTimes.clear();
+        mBufferTimestamps.clear();
+        mBufferSizes.clear();
+        mDecodedSizes.clear();
         mLastInHeader = NULL;
     } else {
         while (outputDelayRingBufferSamplesAvailable() > 0) {
@@ -955,7 +1024,9 @@
     mOutputDelayRingBufferReadPos = 0;
     mEndOfInput = false;
     mEndOfOutput = false;
-    mAnchorTimes.clear();
+    mBufferTimestamps.clear();
+    mBufferSizes.clear();
+    mDecodedSizes.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 865bd15..9fcb598 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h
@@ -59,8 +59,9 @@
     size_t mOutputBufferCount;
     bool mSignalledError;
     OMX_BUFFERHEADERTYPE *mLastInHeader;
-    int64_t mCurrentInputTime;
-    Vector<int64_t> mAnchorTimes;
+    Vector<int32_t> mBufferSizes;
+    Vector<int32_t> mDecodedSizes;
+    Vector<int64_t> mBufferTimestamps;
 
     CDrcPresModeWrapper mDrcWrap;
 
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 83481bc..3720085 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -81,6 +81,7 @@
         mDiscontinuities.add(indexToType(i), new AnotherPacketSource(NULL /* meta */));
         mPacketSources.add(indexToType(i), new AnotherPacketSource(NULL /* meta */));
         mPacketSources2.add(indexToType(i), new AnotherPacketSource(NULL /* meta */));
+        mBuffering[i] = false;
     }
 }
 
@@ -133,8 +134,26 @@
 
     sp<AnotherPacketSource> packetSource = mPacketSources.valueFor(stream);
 
+    ssize_t idx = typeToIndex(stream);
     if (!packetSource->hasBufferAvailable(&finalResult)) {
-        return finalResult == OK ? -EAGAIN : finalResult;
+        if (finalResult == OK) {
+            mBuffering[idx] = true;
+            return -EAGAIN;
+        } else {
+            return finalResult;
+        }
+    }
+
+    if (mBuffering[idx]) {
+        if (mSwitchInProgress
+                || packetSource->isFinished(0)
+                || packetSource->getEstimatedDurationUs() > 10000000ll) {
+            mBuffering[idx] = false;
+        }
+    }
+
+    if (mBuffering[idx]) {
+        return -EAGAIN;
     }
 
     // wait for counterpart
@@ -567,6 +586,21 @@
     return (StreamType)(1 << idx);
 }
 
+// static
+ssize_t LiveSession::typeToIndex(int32_t type) {
+    switch (type) {
+        case STREAMTYPE_AUDIO:
+            return 0;
+        case STREAMTYPE_VIDEO:
+            return 1;
+        case STREAMTYPE_SUBTITLES:
+            return 2;
+        default:
+            return -1;
+    };
+    return -1;
+}
+
 void LiveSession::onConnect(const sp<AMessage> &msg) {
     AString url;
     CHECK(msg->findString("url", &url));
@@ -1252,12 +1286,6 @@
     CHECK(msg->findInt32("streamMask", (int32_t *)&streamMask));
     CHECK(msg->findInt32("resumeMask", (int32_t *)&resumeMask));
 
-    for (size_t i = 0; i < kMaxStreams; ++i) {
-        if (streamMask & indexToType(i)) {
-            CHECK(msg->findString(mStreams[i].uriKey().c_str(), &mStreams[i].mUri));
-        }
-    }
-
     int64_t timeUs;
     int32_t pickTrack;
     bool switching = false;
@@ -1273,7 +1301,20 @@
         mRealTimeBaseUs = ALooper::GetNowUs() - timeUs;
     }
 
+    for (size_t i = 0; i < kMaxStreams; ++i) {
+        if (streamMask & indexToType(i)) {
+            if (switching) {
+                CHECK(msg->findString(mStreams[i].uriKey().c_str(), &mStreams[i].mNewUri));
+            } else {
+                CHECK(msg->findString(mStreams[i].uriKey().c_str(), &mStreams[i].mUri));
+            }
+        }
+    }
+
     mNewStreamMask = streamMask | resumeMask;
+    if (switching) {
+        mSwapMask = mStreamMask & ~resumeMask;
+    }
 
     // Of all existing fetchers:
     // * Resume fetchers that are still needed and assign them original packet sources.
@@ -1323,7 +1364,7 @@
         }
 
         AString uri;
-        uri = mStreams[i].mUri;
+        uri = switching ? mStreams[i].mNewUri : mStreams[i].mUri;
 
         sp<PlaylistFetcher> fetcher = addFetcher(uri.c_str());
         CHECK(fetcher != NULL);
@@ -1336,7 +1377,8 @@
 
         // TRICKY: looping from i as earlier streams are already removed from streamMask
         for (size_t j = i; j < kMaxStreams; ++j) {
-            if ((streamMask & indexToType(j)) && uri == mStreams[j].mUri) {
+            const AString &streamUri = switching ? mStreams[j].mNewUri : mStreams[j].mUri;
+            if ((streamMask & indexToType(j)) && uri == streamUri) {
                 sources[j] = mPacketSources.valueFor(indexToType(j));
 
                 if (timeUs >= 0) {
@@ -1425,7 +1467,6 @@
     mReconfigurationInProgress = false;
     if (switching) {
         mSwitchInProgress = true;
-        mSwapMask = streamMask;
     } else {
         mStreamMask = mNewStreamMask;
     }
@@ -1444,6 +1485,15 @@
 
     int32_t stream;
     CHECK(msg->findInt32("stream", &stream));
+
+    ssize_t idx = typeToIndex(stream);
+    CHECK(idx >= 0);
+    if ((mNewStreamMask & stream) && mStreams[idx].mNewUri.empty()) {
+        ALOGW("swapping stream type %d %s to empty stream", stream, mStreams[idx].mUri.c_str());
+    }
+    mStreams[idx].mUri = mStreams[idx].mNewUri;
+    mStreams[idx].mNewUri.clear();
+
     mSwapMask &= ~stream;
     if (mSwapMask != 0) {
         return;
@@ -1455,6 +1505,15 @@
         StreamType extraStream = (StreamType) (extraStreams & ~(extraStreams - 1));
         swapPacketSource(extraStream);
         extraStreams &= ~extraStream;
+
+        idx = typeToIndex(extraStream);
+        CHECK(idx >= 0);
+        if (mStreams[idx].mNewUri.empty()) {
+            ALOGW("swapping extra stream type %d %s to empty stream",
+                    extraStream, mStreams[idx].mUri.c_str());
+        }
+        mStreams[idx].mUri = mStreams[idx].mNewUri;
+        mStreams[idx].mNewUri.clear();
     }
 
     tryToFinishBandwidthSwitch();
@@ -1535,6 +1594,28 @@
     mSwitchGeneration++;
     mSwitchInProgress = false;
     mSwapMask = 0;
+
+    for (size_t i = 0; i < mFetcherInfos.size(); ++i) {
+        FetcherInfo& info = mFetcherInfos.editValueAt(i);
+        if (info.mToBeRemoved) {
+            info.mToBeRemoved = false;
+        }
+    }
+
+    for (size_t i = 0; i < kMaxStreams; ++i) {
+        if (!mStreams[i].mNewUri.empty()) {
+            ssize_t j = mFetcherInfos.indexOfKey(mStreams[i].mNewUri);
+            if (j < 0) {
+                mStreams[i].mNewUri.clear();
+                continue;
+            }
+
+            const FetcherInfo &info = mFetcherInfos.valueAt(j);
+            info.mFetcher->stopAsync();
+            mFetcherInfos.removeItemsAt(j);
+            mStreams[i].mNewUri.clear();
+        }
+    }
 }
 
 bool LiveSession::canSwitchBandwidthTo(size_t bandwidthIndex) {
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index 8a800da..6be86cf 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -126,7 +126,7 @@
 
     struct StreamItem {
         const char *mType;
-        AString mUri;
+        AString mUri, mNewUri;
         size_t mCurDiscontinuitySeq;
         int64_t mLastDequeuedTimeUs;
         int64_t mLastSampleDurationUs;
@@ -153,6 +153,7 @@
     sp<IMediaHTTPService> mHTTPService;
 
     bool mInPreparationPhase;
+    bool mBuffering[kMaxStreams];
 
     sp<HTTPBase> mHTTPDataSource;
     KeyedVector<String8, String8> mExtraHeaders;
@@ -242,6 +243,7 @@
 
     static int SortByBandwidth(const BandwidthItem *, const BandwidthItem *);
     static StreamType indexToType(int idx);
+    static ssize_t typeToIndex(int32_t type);
 
     void changeConfiguration(
             int64_t timeUs, size_t bandwidthIndex, bool pickTrack = false);
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index 22c4e04..d5f6c1e 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -2294,14 +2294,14 @@
             }
             sp<DeviceDescriptor> srcDeviceDesc =
                     mAvailableInputDevices.getDeviceFromId(patch->sources[0].id);
+            if (srcDeviceDesc == 0) {
+                return BAD_VALUE;
+            }
 
             //update source and sink with our own data as the data passed in the patch may
             // be incomplete.
             struct audio_patch newPatch = *patch;
             srcDeviceDesc->toAudioPortConfig(&newPatch.sources[0], &patch->sources[0]);
-            if (srcDeviceDesc == 0) {
-                return BAD_VALUE;
-            }
 
             for (size_t i = 0; i < patch->num_sinks; i++) {
                 if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
@@ -3670,8 +3670,11 @@
 
 void AudioPolicyManager::checkOutputForAllStrategies()
 {
-    checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
+    if (mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
+        checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
     checkOutputForStrategy(STRATEGY_PHONE);
+    if (mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] != AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
+        checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
     checkOutputForStrategy(STRATEGY_SONIFICATION);
     checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
     checkOutputForStrategy(STRATEGY_MEDIA);
@@ -3752,23 +3755,28 @@
     }
 
     // check the following by order of priority to request a routing change if necessary:
-    // 1: the strategy enforced audible is active on the output:
+    // 1: the strategy enforced audible is active and enforced on the output:
     //      use device for strategy enforced audible
     // 2: we are in call or the strategy phone is active on the output:
     //      use device for strategy phone
-    // 3: the strategy sonification is active on the output:
+    // 3: the strategy for enforced audible is active but not enforced on the output:
+    //      use the device for strategy enforced audible
+    // 4: the strategy sonification is active on the output:
     //      use device for strategy sonification
-    // 4: the strategy "respectful" sonification is active on the output:
+    // 5: the strategy "respectful" sonification is active on the output:
     //      use device for strategy "respectful" sonification
-    // 5: the strategy media is active on the output:
+    // 6: the strategy media is active on the output:
     //      use device for strategy media
-    // 6: the strategy DTMF is active on the output:
+    // 7: the strategy DTMF is active on the output:
     //      use device for strategy DTMF
-    if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE)) {
+    if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE) &&
+        mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
         device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
     } else if (isInCall() ||
                     outputDesc->isStrategyActive(STRATEGY_PHONE)) {
         device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
+    } else if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE)) {
+        device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
     } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION)) {
         device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
     } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION_RESPECTFUL)) {
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 6f4a507..10038c5 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -921,6 +921,13 @@
                         "stop preview: %s (%d)",
                         __FUNCTION__, mCameraId, strerror(-res), res);
             }
+            {
+                // Ideally we should recover the override after recording stopped, but
+                // right now recording stream will live until here, so we are forced to
+                // recover here. TODO: find a better way to handle that (b/17495165)
+                SharedParameters::Lock l(mParameters);
+                l.mParameters.recoverOverriddenJpegSize();
+            }
             // no break
         case Parameters::WAITING_FOR_PREVIEW_WINDOW: {
             SharedParameters::Lock l(mParameters);
@@ -1075,34 +1082,65 @@
     // and we can't fail record start without stagefright asserting.
     params.previewCallbackFlags = 0;
 
-    res = updateProcessorStream<
-            StreamingProcessor,
-            &StreamingProcessor::updateRecordingStream>(mStreamingProcessor,
-                                                        params);
+    bool recordingStreamNeedsUpdate;
+    res = mStreamingProcessor->recordingStreamNeedsUpdate(params, &recordingStreamNeedsUpdate);
     if (res != OK) {
-        ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)",
-                __FUNCTION__, mCameraId, strerror(-res), res);
+        ALOGE("%s: Camera %d: Can't query recording stream",
+                __FUNCTION__, mCameraId);
         return res;
     }
 
+    if (recordingStreamNeedsUpdate) {
+        // Need to stop stream here in case updateRecordingStream fails
+        // Right now camera device cannot handle configureStream failure gracefully
+        // when device is streaming
+        res = mStreamingProcessor->stopStream();
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Can't stop streaming to update record stream",
+                    __FUNCTION__, mCameraId);
+            return res;
+        }
+        res = mDevice->waitUntilDrained();
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
+                    __FUNCTION__, mCameraId, strerror(-res), res);
+        }
+        res = updateProcessorStream<
+                StreamingProcessor,
+                &StreamingProcessor::updateRecordingStream>(mStreamingProcessor,
+                                                            params);
+
+        // updateRecordingStream might trigger a configureStream call and device might fail
+        // configureStream due to jpeg size > video size. Try again with jpeg size overridden
+        // to video size.
+        // TODO: This may not be needed after we add stop streaming above. Remove that if
+        // it's the case.
+        if (res == BAD_VALUE) {
+            overrideVideoSnapshotSize(params);
+            res = updateProcessorStream<
+                    StreamingProcessor,
+                    &StreamingProcessor::updateRecordingStream>(mStreamingProcessor,
+                                                                params);
+        }
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)",
+                    __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+    }
+
     Vector<int32_t> outputStreams;
     outputStreams.push(getPreviewStreamId());
     outputStreams.push(getRecordingStreamId());
 
     res = mStreamingProcessor->startStream(StreamingProcessor::RECORD,
             outputStreams);
-    // try to reconfigure jpeg to video size if configureStreams failed
-    if (res == BAD_VALUE) {
 
-        ALOGV("%s: Camera %d: configure still size to video size before recording"
-                , __FUNCTION__, mCameraId);
-        params.overrideJpegSizeByVideoSize();
-        res = updateProcessorStream(mJpegProcessor, params);
-        if (res != OK) {
-            ALOGE("%s: Camera %d: Can't configure still image size to video size: %s (%d)",
-                    __FUNCTION__, mCameraId, strerror(-res), res);
-            return res;
-        }
+    // startStream might trigger a configureStream call and device might fail
+    // configureStream due to jpeg size > video size. Try again with jpeg size overridden
+    // to video size.
+    if (res == BAD_VALUE) {
+        overrideVideoSnapshotSize(params);
         res = mStreamingProcessor->startStream(StreamingProcessor::RECORD,
                 outputStreams);
     }
@@ -1146,7 +1184,6 @@
 
     mCameraService->playSound(CameraService::SOUND_RECORDING);
 
-    l.mParameters.recoverOverriddenJpegSize();
     res = startPreviewL(l.mParameters, true);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to return to preview",
@@ -1923,6 +1960,18 @@
     return res;
 }
 
+status_t Camera2Client::overrideVideoSnapshotSize(Parameters &params) {
+    ALOGV("%s: Camera %d: configure still size to video size before recording"
+            , __FUNCTION__, mCameraId);
+    params.overrideJpegSizeByVideoSize();
+    status_t res = updateProcessorStream(mJpegProcessor, params);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Can't override video snapshot size to video size: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+    }
+    return res;
+}
+
 const char* Camera2Client::kAutofocusLabel = "autofocus";
 const char* Camera2Client::kTakepictureLabel = "take_picture";
 
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index f5c3a30..d68bb29 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -208,6 +208,9 @@
 
     // Wait until the camera device has received the latest control settings
     status_t syncWithDevice();
+
+    // Video snapshot jpeg size overriding helper function
+    status_t overrideVideoSnapshotSize(Parameters &params);
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index 33bdaa3..1a4d9a6 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -122,6 +122,16 @@
             mClientPid);
     len = (len > SIZE - 1) ? SIZE - 1 : len;
     write(fd, buffer, len);
+
+    len = snprintf(buffer, SIZE, "Latest set parameters:\n");
+    len = (len > SIZE - 1) ? SIZE - 1 : len;
+    write(fd, buffer, len);
+
+    mLatestSetParameters.dump(fd, args);
+
+    const char *enddump = "\n\n";
+    write(fd, enddump, strlen(enddump));
+
     return mHardware->dump(fd, args);
 }
 
@@ -550,6 +560,7 @@
     status_t result = checkPidAndHardware();
     if (result != NO_ERROR) return result;
 
+    mLatestSetParameters = CameraParameters(params);
     CameraParameters p(params);
     return mHardware->setParameters(p);
 }
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 6779f5e..63a9d0f 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -142,6 +142,9 @@
     // of the original one), we allocate mPreviewBuffer and reuse it if possible.
     sp<MemoryHeapBase>              mPreviewBuffer;
 
+    // Debugging information
+    CameraParameters                mLatestSetParameters;
+
     // We need to avoid the deadlock when the incoming command thread and
     // the CameraHardwareInterface callback thread both want to grab mLock.
     // An extra flag is used to tell the callback thread that it should stop
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index ab0af0d..9e7fff8 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -318,6 +318,44 @@
     return OK;
 }
 
+status_t StreamingProcessor::recordingStreamNeedsUpdate(
+        const Parameters &params, bool *needsUpdate) {
+    status_t res;
+
+    if (needsUpdate == 0) {
+        ALOGE("%s: Camera %d: invalid argument", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
+
+    if (mRecordingStreamId == NO_STREAM) {
+        *needsUpdate = true;
+        return OK;
+    }
+
+    sp<CameraDeviceBase> device = mDevice.promote();
+    if (device == 0) {
+        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
+
+    uint32_t currentWidth, currentHeight;
+    res = device->getStreamInfo(mRecordingStreamId,
+            &currentWidth, &currentHeight, 0);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Error querying recording output stream info: "
+                "%s (%d)", __FUNCTION__, mId,
+                strerror(-res), res);
+        return res;
+    }
+
+    if (mRecordingConsumer == 0 || currentWidth != (uint32_t)params.videoWidth ||
+            currentHeight != (uint32_t)params.videoHeight) {
+        *needsUpdate = true;
+    }
+    *needsUpdate = false;
+    return res;
+}
+
 status_t StreamingProcessor::updateRecordingStream(const Parameters &params) {
     ATRACE_CALL();
     status_t res;
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
index 833bb8f..8466af4 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
@@ -54,6 +54,9 @@
 
     status_t setRecordingBufferCount(size_t count);
     status_t updateRecordingRequest(const Parameters &params);
+    // If needsUpdate is set to true, a updateRecordingStream call with params will recreate
+    // recording stream
+    status_t recordingStreamNeedsUpdate(const Parameters &params, bool *needsUpdate);
     status_t updateRecordingStream(const Parameters &params);
     status_t deleteRecordingStream();
     int getRecordingStreamId() const;
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
index fa65b74..de31e23 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
@@ -244,6 +244,46 @@
     return mZslStreamId;
 }
 
+status_t ZslProcessor3::updateRequestWithDefaultStillRequest(CameraMetadata &request) const {
+    sp<Camera2Client> client = mClient.promote();
+    if (client == 0) {
+        ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
+    sp<Camera3Device> device =
+        static_cast<Camera3Device*>(client->getCameraDevice().get());
+    if (device == 0) {
+        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
+
+    CameraMetadata stillTemplate;
+    device->createDefaultRequest(CAMERA3_TEMPLATE_STILL_CAPTURE, &stillTemplate);
+
+    // Find some of the post-processing tags, and assign the value from template to the request.
+    // Only check the aberration mode and noise reduction mode for now, as they are very important
+    // for image quality.
+    uint32_t postProcessingTags[] = {
+            ANDROID_NOISE_REDUCTION_MODE,
+            ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+            ANDROID_COLOR_CORRECTION_MODE,
+            ANDROID_TONEMAP_MODE,
+            ANDROID_SHADING_MODE,
+            ANDROID_HOT_PIXEL_MODE,
+            ANDROID_EDGE_MODE
+    };
+
+    camera_metadata_entry_t entry;
+    for (size_t i = 0; i < sizeof(postProcessingTags) / sizeof(uint32_t); i++) {
+        entry = stillTemplate.find(postProcessingTags[i]);
+        if (entry.count > 0) {
+            request.update(postProcessingTags[i], entry.data.u8, 1);
+        }
+    }
+
+    return OK;
+}
+
 status_t ZslProcessor3::pushToReprocess(int32_t requestId) {
     ALOGV("%s: Send in reprocess request with id %d",
             __FUNCTION__, requestId);
@@ -369,6 +409,13 @@
             }
         }
 
+        // Update post-processing settings
+        res = updateRequestWithDefaultStillRequest(request);
+        if (res != OK) {
+            ALOGW("%s: Unable to update post-processing tags, the reprocessed image quality "
+                    "may be compromised", __FUNCTION__);
+        }
+
         mLatestCapturedRequest = request;
         res = client->getCameraDevice()->capture(request);
         if (res != OK ) {
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
index 2975f7c..fc9f70c 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
@@ -135,6 +135,9 @@
     nsecs_t getCandidateTimestampLocked(size_t* metadataIdx) const;
 
     bool isFixedFocusMode(uint8_t afMode) const;
+
+    // Update the post-processing metadata with the default still capture request template
+    status_t updateRequestWithDefaultStillRequest(CameraMetadata &request) const;
 };
 
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index fafe349..690f675 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1044,6 +1044,11 @@
             return INVALID_OPERATION;
     }
 
+    if (!mRequestTemplateCache[templateId].isEmpty()) {
+        *request = mRequestTemplateCache[templateId];
+        return OK;
+    }
+
     const camera_metadata_t *rawRequest;
     ATRACE_BEGIN("camera3->construct_default_request_settings");
     rawRequest = mHal3Device->ops->construct_default_request_settings(
@@ -1055,6 +1060,7 @@
         return DEAD_OBJECT;
     }
     *request = rawRequest;
+    mRequestTemplateCache[templateId] = rawRequest;
 
     return OK;
 }
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index b99ed7e..ec6bba1 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -174,6 +174,8 @@
 
     CameraMetadata             mDeviceInfo;
 
+    CameraMetadata             mRequestTemplateCache[CAMERA3_TEMPLATE_COUNT];
+
     uint32_t                   mDeviceVersion;
 
     enum Status {