Merge "ACodec: handle errors related to native window." into lmp-dev
diff --git a/camera/CameraUtils.cpp b/camera/CameraUtils.cpp
index 1ff63ab..04244ac 100644
--- a/camera/CameraUtils.cpp
+++ b/camera/CameraUtils.cpp
@@ -73,23 +73,23 @@
                 return INVALID_OPERATION;
         }
     } else {
-        // Front camera needs to be horizontally flipped for
-        // mirror-like behavior.
-        // Note: Flips are applied before rotates.
+        // Front camera needs to be horizontally flipped for mirror-like behavior.
+        // Note: Flips are applied before rotates; using XOR here as some of these flags are
+        // composed in terms of other flip/rotation flags, and are not bitwise-ORable.
         switch (orientation) {
             case 0:
                 flags = NATIVE_WINDOW_TRANSFORM_FLIP_H;
                 break;
             case 90:
-                flags = NATIVE_WINDOW_TRANSFORM_FLIP_H |
+                flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^
                         NATIVE_WINDOW_TRANSFORM_ROT_270;
                 break;
             case 180:
-                flags = NATIVE_WINDOW_TRANSFORM_FLIP_H |
+                flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^
                         NATIVE_WINDOW_TRANSFORM_ROT_180;
                 break;
             case 270:
-                flags = NATIVE_WINDOW_TRANSFORM_FLIP_H |
+                flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^
                         NATIVE_WINDOW_TRANSFORM_ROT_90;
 
                 break;
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index 3fb9e36..8000e84 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -48,7 +48,7 @@
             const sp<IMediaHTTPService> &httpService,
             const char *uri,
             const KeyedVector<String8, String8> *headers = NULL,
-            AString *sniffedMIME = NULL);
+            String8 *contentType = NULL);
 
     DataSource() {}
 
@@ -102,10 +102,6 @@
     virtual ~DataSource() {}
 
 private:
-    enum {
-        kDefaultMetaSize = 200000,
-    };
-
     static Mutex gSnifferMutex;
     static List<SnifferFunc> gSniffers;
     static bool gSniffersRegistered;
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index dacb144..3e0fc0d 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -60,7 +60,7 @@
     return OK;
 }
 
-player_type MediaPlayerFactory::getDefaultPlayerType() {
+static player_type getDefaultPlayerType() {
     char value[PROPERTY_VALUE_MAX];
     if (property_get("media.stagefright.use-awesome", value, NULL)
             && (!strcmp("1", value) || !strcasecmp("true", value))) {
@@ -181,16 +181,19 @@
                                int64_t offset,
                                int64_t /*length*/,
                                float /*curScore*/) {
-        char buf[20];
-        lseek(fd, offset, SEEK_SET);
-        read(fd, buf, sizeof(buf));
-        lseek(fd, offset, SEEK_SET);
+        if (getDefaultPlayerType()
+                == STAGEFRIGHT_PLAYER) {
+            char buf[20];
+            lseek(fd, offset, SEEK_SET);
+            read(fd, buf, sizeof(buf));
+            lseek(fd, offset, SEEK_SET);
 
-        uint32_t ident = *((uint32_t*)buf);
+            uint32_t ident = *((uint32_t*)buf);
 
-        // Ogg vorbis?
-        if (ident == 0x5367674f) // 'OggS'
-            return 1.0;
+            // Ogg vorbis?
+            if (ident == 0x5367674f) // 'OggS'
+                return 1.0;
+        }
 
         return 0.0;
     }
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.h b/media/libmediaplayerservice/MediaPlayerFactory.h
index 5ddde19..55ff918 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.h
+++ b/media/libmediaplayerservice/MediaPlayerFactory.h
@@ -71,7 +71,6 @@
 
     static status_t registerFactory_l(IFactory* factory,
                                       player_type type);
-    static player_type getDefaultPlayerType();
 
     static Mutex       sLock;
     static tFactoryMap sFactoryMap;
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 2c48306..b5bd988 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1798,7 +1798,9 @@
     //ALOGV("write(%p, %u)", buffer, size);
     if (mTrack != 0) {
         ssize_t ret = mTrack->write(buffer, size);
-        mBytesWritten += ret;
+        if (ret >= 0) {
+            mBytesWritten += ret;
+        }
         return ret;
     }
     return NO_INIT;
@@ -1945,7 +1947,7 @@
 #define LOG_TAG "AudioCache"
 MediaPlayerService::AudioCache::AudioCache(const sp<IMemoryHeap>& heap) :
     mHeap(heap), mChannelCount(0), mFrameCount(1024), mSampleRate(0), mSize(0),
-    mError(NO_ERROR),  mCommandComplete(false)
+    mFrameSize(1), mError(NO_ERROR),  mCommandComplete(false)
 {
 }
 
@@ -1962,14 +1964,14 @@
 status_t MediaPlayerService::AudioCache::getPosition(uint32_t *position) const
 {
     if (position == 0) return BAD_VALUE;
-    *position = mSize;
+    *position = mSize / mFrameSize;
     return NO_ERROR;
 }
 
 status_t MediaPlayerService::AudioCache::getFramesWritten(uint32_t *written) const
 {
     if (written == 0) return BAD_VALUE;
-    *written = mSize;
+    *written = mSize / mFrameSize;
     return NO_ERROR;
 }
 
@@ -2031,6 +2033,8 @@
 
     if (actualSize > 0) {
         sink->write(mBuffer, actualSize);
+        // Could return false on sink->write() error or short count.
+        // Not necessarily appropriate but would work for AudioCache behavior.
     }
 
     return true;
@@ -2053,6 +2057,9 @@
     mChannelCount = (uint16_t)channelCount;
     mFormat = format;
     mMsecsPerFrame = 1.e3 / (float) sampleRate;
+    mFrameSize =  audio_is_linear_pcm(mFormat)
+            ? mChannelCount * audio_bytes_per_sample(mFormat) : 1;
+    mFrameCount = mHeap->getSize() / mFrameSize;
 
     if (cb != NULL) {
         mCallbackThread = new CallbackThread(this, cb, cookie);
@@ -2082,12 +2089,26 @@
     if (p == NULL) return NO_INIT;
     p += mSize;
     ALOGV("memcpy(%p, %p, %u)", p, buffer, size);
-    if (mSize + size > mHeap->getSize()) {
+
+    bool overflow = mSize + size > mHeap->getSize();
+    if (overflow) {
         ALOGE("Heap size overflow! req size: %d, max size: %d", (mSize + size), mHeap->getSize());
         size = mHeap->getSize() - mSize;
     }
+    size -= size % mFrameSize; // consume only integral amounts of frame size
     memcpy(p, buffer, size);
     mSize += size;
+
+    if (overflow) {
+        // Signal heap filled here (last frame may be truncated).
+        // After this point, no more data should be written as the
+        // heap is filled and the AudioCache should be effectively
+        // immutable with respect to future writes.
+        //
+        // It is thus safe for another thread to read the AudioCache.
+        mCommandComplete = true;
+        mSignal.signal();
+    }
     return size;
 }
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 406e3f6..4fe7075 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -194,7 +194,7 @@
         virtual ssize_t         bufferSize() const { return frameSize() * mFrameCount; }
         virtual ssize_t         frameCount() const { return mFrameCount; }
         virtual ssize_t         channelCount() const { return (ssize_t)mChannelCount; }
-        virtual ssize_t         frameSize() const { return ssize_t(mChannelCount * ((mFormat == AUDIO_FORMAT_PCM_16_BIT)?sizeof(int16_t):sizeof(u_int8_t))); }
+        virtual ssize_t         frameSize() const { return (ssize_t)mFrameSize; }
         virtual uint32_t        latency() const;
         virtual float           msecsPerFrame() const;
         virtual status_t        getPosition(uint32_t *position) const;
@@ -244,6 +244,7 @@
         ssize_t             mFrameCount;
         uint32_t            mSampleRate;
         uint32_t            mSize;
+        size_t              mFrameSize;
         int                 mError;
         bool                mCommandComplete;
 
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 8774117..e2bcb1e 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1433,6 +1433,10 @@
             format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
             break;
 
+        case VIDEO_ENCODER_VP8:
+            format->setString("mime", MEDIA_MIMETYPE_VIDEO_VP8);
+            break;
+
         default:
             CHECK(!"Should not be here, unsupported video encoding.");
             break;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 76e1d54..3706117 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -32,6 +32,7 @@
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
+#include "../../libstagefright/include/NuCachedSource2.h"
 #include "../../libstagefright/include/WVMExtractor.h"
 
 namespace android {
@@ -47,7 +48,8 @@
       mAudioIsVorbis(false),
       mIsWidevine(false),
       mUIDValid(uidValid),
-      mUID(uid) {
+      mUID(uid),
+      mMetaDataSize(-1ll) {
     resetDataSource();
     DataSource::RegisterDefaultSniffers();
 }
@@ -92,18 +94,18 @@
     return OK;
 }
 
-status_t NuPlayer::GenericSource::initFromDataSource(
-        const sp<DataSource> &dataSource,
-        const char* mime) {
+status_t NuPlayer::GenericSource::initFromDataSource() {
     sp<MediaExtractor> extractor;
 
+    CHECK(mDataSource != NULL);
+
     if (mIsWidevine) {
         String8 mimeType;
         float confidence;
         sp<AMessage> dummy;
         bool success;
 
-        success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
+        success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy);
         if (!success
                 || strcasecmp(
                     mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
@@ -111,14 +113,15 @@
             return UNKNOWN_ERROR;
         }
 
-        sp<WVMExtractor> wvmExtractor = new WVMExtractor(dataSource);
+        sp<WVMExtractor> wvmExtractor = new WVMExtractor(mDataSource);
         wvmExtractor->setAdaptiveStreamingMode(true);
         if (mUIDValid) {
             wvmExtractor->setUID(mUID);
         }
         extractor = wvmExtractor;
     } else {
-        extractor = MediaExtractor::Create(dataSource, mime);
+        extractor = MediaExtractor::Create(mDataSource,
+                mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str());
     }
 
     if (extractor == NULL) {
@@ -213,34 +216,49 @@
 
 void NuPlayer::GenericSource::onPrepareAsync() {
     // delayed data source creation
-    AString sniffedMIME;
-    sp<DataSource> dataSource;
+    if (mDataSource == NULL) {
+        if (!mUri.empty()) {
+            mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11);
 
-    if (!mUri.empty()) {
-        mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11);
+            mDataSource = DataSource::CreateFromURI(
+                   mHTTPService, mUri.c_str(), &mUriHeaders, &mContentType);
+        } else {
+            // set to false first, if the extractor
+            // comes back as secure, set it to true then.
+            mIsWidevine = false;
 
-        dataSource = DataSource::CreateFromURI(
-               mHTTPService, mUri.c_str(), &mUriHeaders, &sniffedMIME);
-    } else {
-        // set to false first, if the extractor
-        // comes back as secure, set it to true then.
-        mIsWidevine = false;
+            mDataSource = new FileSource(mFd, mOffset, mLength);
+        }
 
-        dataSource = new FileSource(mFd, mOffset, mLength);
+        if (mDataSource == NULL) {
+            ALOGE("Failed to create data source!");
+            notifyPreparedAndCleanup(UNKNOWN_ERROR);
+            return;
+        }
+
+        if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
+            mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
+        }
     }
 
-    if (dataSource == NULL) {
-        ALOGE("Failed to create data source!");
-        notifyPrepared(UNKNOWN_ERROR);
+    // check initial caching status
+    status_t err = prefillCacheIfNecessary();
+    if (err != OK) {
+        if (err == -EAGAIN) {
+            (new AMessage(kWhatPrepareAsync, id()))->post(200000);
+        } else {
+            ALOGE("Failed to prefill data cache!");
+            notifyPreparedAndCleanup(UNKNOWN_ERROR);
+        }
         return;
     }
 
-    status_t err = initFromDataSource(
-            dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str());
+    // init extrator from data source
+    err = initFromDataSource();
 
     if (err != OK) {
         ALOGE("Failed to init from data source!");
-        notifyPrepared(err);
+        notifyPreparedAndCleanup(err);
         return;
     }
 
@@ -258,6 +276,87 @@
     notifyPrepared();
 }
 
+void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
+    if (err != OK) {
+        mMetaDataSize = -1ll;
+        mContentType = "";
+        mSniffedMIME = "";
+        mDataSource.clear();
+        mCachedSource.clear();
+    }
+    notifyPrepared(err);
+}
+
+status_t NuPlayer::GenericSource::prefillCacheIfNecessary() {
+    CHECK(mDataSource != NULL);
+
+    if (mCachedSource == NULL) {
+        // no prefill if the data source is not cached
+        return OK;
+    }
+
+    // We're not doing this for streams that appear to be audio-only
+    // streams to ensure that even low bandwidth streams start
+    // playing back fairly instantly.
+    if (!strncasecmp(mContentType.string(), "audio/", 6)) {
+        return OK;
+    }
+
+    // We're going to prefill the cache before trying to instantiate
+    // the extractor below, as the latter is an operation that otherwise
+    // could block on the datasource for a significant amount of time.
+    // During that time we'd be unable to abort the preparation phase
+    // without this prefill.
+
+    // Initially make sure we have at least 192 KB for the sniff
+    // to complete without blocking.
+    static const size_t kMinBytesForSniffing = 192 * 1024;
+    static const size_t kDefaultMetaSize = 200000;
+
+    status_t finalStatus;
+
+    size_t cachedDataRemaining =
+            mCachedSource->approxDataRemaining(&finalStatus);
+
+    if (finalStatus != OK || (mMetaDataSize >= 0
+            && (off64_t)cachedDataRemaining >= mMetaDataSize)) {
+        ALOGV("stop caching, status %d, "
+                "metaDataSize %lld, cachedDataRemaining %zu",
+                finalStatus, mMetaDataSize, cachedDataRemaining);
+        return OK;
+    }
+
+    ALOGV("now cached %zu bytes of data", cachedDataRemaining);
+
+    if (mMetaDataSize < 0
+            && cachedDataRemaining >= kMinBytesForSniffing) {
+        String8 tmp;
+        float confidence;
+        sp<AMessage> meta;
+        if (!mCachedSource->sniff(&tmp, &confidence, &meta)) {
+            return UNKNOWN_ERROR;
+        }
+
+        // We successfully identified the file's extractor to
+        // be, remember this mime type so we don't have to
+        // sniff it again when we call MediaExtractor::Create()
+        mSniffedMIME = tmp.string();
+
+        if (meta == NULL
+                || !meta->findInt64("meta-data-size",
+                        reinterpret_cast<int64_t*>(&mMetaDataSize))) {
+            mMetaDataSize = kDefaultMetaSize;
+        }
+
+        if (mMetaDataSize < 0ll) {
+            ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize);
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    return -EAGAIN;
+}
+
 void NuPlayer::GenericSource::start() {
     ALOGI("start");
 
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index d3081de..946307c 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -33,6 +33,7 @@
 struct IMediaHTTPService;
 struct MediaSource;
 class MediaBuffer;
+struct NuCachedSource2;
 
 struct NuPlayer::GenericSource : public NuPlayer::Source {
     GenericSource(const sp<AMessage> &notify, bool uidValid, uid_t uid);
@@ -105,14 +106,21 @@
     int64_t mOffset;
     int64_t mLength;
 
-    sp<ALooper> mLooper;
+    sp<DataSource> mDataSource;
+    sp<NuCachedSource2> mCachedSource;
+    String8 mContentType;
+    AString mSniffedMIME;
+    off64_t mMetaDataSize;
 
+    sp<ALooper> mLooper;
 
     void resetDataSource();
 
-    status_t initFromDataSource(
-            const sp<DataSource> &dataSource,
-            const char *mime);
+    status_t initFromDataSource();
+
+    status_t prefillCacheIfNecessary();
+
+    void notifyPreparedAndCleanup(status_t err);
 
     void onPrepareAsync();
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 75e1371..0a9b65c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -803,6 +803,14 @@
                     err = UNKNOWN_ERROR;
                 }
                 mRenderer->queueEOS(audio, err);
+                if (audio && mFlushingAudio != NONE) {
+                    mAudioDecoder.clear();
+                    mFlushingAudio = SHUT_DOWN;
+                } else if (!audio && mFlushingVideo != NONE){
+                    mVideoDecoder.clear();
+                    mFlushingVideo = SHUT_DOWN;
+                }
+                finishFlushIfPossible();
             } else if (what == Decoder::kWhatDrainThisBuffer) {
                 renderBuffer(audio, msg);
             } else {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 37ecbf1..47c46d6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -44,11 +44,11 @@
     // Every decoder has its own looper because MediaCodec operations
     // are blocking, but NuPlayer needs asynchronous operations.
     mDecoderLooper = new ALooper;
-    mDecoderLooper->setName("NuPlayerDecoder");
+    mDecoderLooper->setName("NPDecoder");
     mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
 
     mCodecLooper = new ALooper;
-    mCodecLooper->setName("NuPlayerDecoder-MC");
+    mCodecLooper->setName("NPDecoder-CL");
     mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 140e1ae..60beb9d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -36,6 +36,8 @@
       mAsyncResult(UNKNOWN_ERROR),
       mDurationUs(-1),
       mPositionUs(-1),
+      mNotifyTimeRealUs(-1),
+      mPauseStartedTimeUs(-1),
       mNumFramesTotal(0),
       mNumFramesDropped(0),
       mLooper(new ALooper),
@@ -227,7 +229,7 @@
 
             if (mStartupSeekTimeUs >= 0) {
                 if (mStartupSeekTimeUs == 0) {
-                    notifySeekComplete();
+                    notifySeekComplete_l();
                 } else {
                     mPlayer->seekToAsync(mStartupSeekTimeUs);
                 }
@@ -238,12 +240,20 @@
         }
 
         case STATE_RUNNING:
+        {
+            if (mAtEOS) {
+                mPlayer->seekToAsync(0);
+                mAtEOS = false;
+                mPositionUs = -1;
+            }
             break;
+        }
 
         case STATE_PAUSED:
         case STATE_STOPPED_AND_PREPARED:
         {
             mPlayer->resume();
+            mPositionUs -= ALooper::GetNowUs() - mPauseStartedTimeUs;
             break;
         }
 
@@ -252,6 +262,7 @@
     }
 
     mState = STATE_RUNNING;
+    mPauseStartedTimeUs = -1;
 
     return OK;
 }
@@ -265,7 +276,7 @@
             // fall through
 
         case STATE_PAUSED:
-            notifyListener(MEDIA_STOPPED);
+            notifyListener_l(MEDIA_STOPPED);
             // fall through
 
         case STATE_PREPARED:
@@ -278,6 +289,7 @@
         default:
             return INVALID_OPERATION;
     }
+    setPauseStartedTimeIfNeeded();
 
     return OK;
 }
@@ -291,7 +303,7 @@
             return OK;
 
         case STATE_RUNNING:
-            notifyListener(MEDIA_PAUSED);
+            notifyListener_l(MEDIA_PAUSED);
             mPlayer->pause();
             break;
 
@@ -299,6 +311,7 @@
             return INVALID_OPERATION;
     }
 
+    setPauseStartedTimeIfNeeded();
     mState = STATE_PAUSED;
 
     return OK;
@@ -320,7 +333,7 @@
             // pretend that the seek completed. It will actually happen when starting playback.
             // TODO: actually perform the seek here, so the player is ready to go at the new
             // location
-            notifySeekComplete();
+            notifySeekComplete_l();
             break;
         }
 
@@ -329,7 +342,7 @@
         {
             mAtEOS = false;
             // seeks can take a while, so we essentially paused
-            notifyListener(MEDIA_PAUSED);
+            notifyListener_l(MEDIA_PAUSED);
             mPlayer->seekToAsync(seekTimeUs);
             break;
         }
@@ -338,6 +351,8 @@
             return INVALID_OPERATION;
     }
 
+    mPositionUs = seekTimeUs;
+    mNotifyTimeRealUs = -1;
     return OK;
 }
 
@@ -346,8 +361,12 @@
 
     if (mPositionUs < 0) {
         *msec = 0;
+    } else if (mNotifyTimeRealUs == -1) {
+        *msec = mPositionUs / 1000;
     } else {
-        *msec = (mPositionUs + 500ll) / 1000;
+        int64_t nowUs =
+                (isPlaying() ?  ALooper::GetNowUs() : mPauseStartedTimeUs);
+        *msec = (mPositionUs + nowUs - mNotifyTimeRealUs + 500ll) / 1000;
     }
 
     return OK;
@@ -380,7 +399,7 @@
         {
             CHECK(mIsAsyncPrepare);
 
-            notifyListener(MEDIA_PREPARED);
+            notifyListener_l(MEDIA_PREPARED);
             break;
         }
 
@@ -389,7 +408,7 @@
     }
 
     if (mState != STATE_STOPPED) {
-        notifyListener(MEDIA_STOPPED);
+        notifyListener_l(MEDIA_STOPPED);
     }
 
     mState = STATE_RESET_IN_PROGRESS;
@@ -522,26 +541,29 @@
 void NuPlayerDriver::notifyPosition(int64_t positionUs) {
     Mutex::Autolock autoLock(mLock);
     mPositionUs = positionUs;
+    mNotifyTimeRealUs = ALooper::GetNowUs();
 }
 
 void NuPlayerDriver::notifySeekComplete() {
+    Mutex::Autolock autoLock(mLock);
+    notifySeekComplete_l();
+}
+
+void NuPlayerDriver::notifySeekComplete_l() {
     bool wasSeeking = true;
-    {
-        Mutex::Autolock autoLock(mLock);
-        if (mState == STATE_STOPPED_AND_PREPARING) {
-            wasSeeking = false;
-            mState = STATE_STOPPED_AND_PREPARED;
-            mCondition.broadcast();
-            if (!mIsAsyncPrepare) {
-                // if we are preparing synchronously, no need to notify listener
-                return;
-            }
-        } else if (mState == STATE_STOPPED) {
-            // no need to notify listener
+    if (mState == STATE_STOPPED_AND_PREPARING) {
+        wasSeeking = false;
+        mState = STATE_STOPPED_AND_PREPARED;
+        mCondition.broadcast();
+        if (!mIsAsyncPrepare) {
+            // if we are preparing synchronously, no need to notify listener
             return;
         }
+    } else if (mState == STATE_STOPPED) {
+        // no need to notify listener
+        return;
     }
-    notifyListener(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED);
+    notifyListener_l(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED);
 }
 
 void NuPlayerDriver::notifyFrameStats(
@@ -573,11 +595,19 @@
 
 void NuPlayerDriver::notifyListener(
         int msg, int ext1, int ext2, const Parcel *in) {
+    Mutex::Autolock autoLock(mLock);
+    notifyListener_l(msg, ext1, ext2, in);
+}
+
+void NuPlayerDriver::notifyListener_l(
+        int msg, int ext1, int ext2, const Parcel *in) {
     switch (msg) {
         case MEDIA_PLAYBACK_COMPLETE:
         {
             if (mLooping) {
+                mLock.unlock();
                 mPlayer->seekToAsync(0);
+                mLock.lock();
                 break;
             }
             // fall through
@@ -586,6 +616,7 @@
         case MEDIA_ERROR:
         {
             mAtEOS = true;
+            setPauseStartedTimeIfNeeded();
             break;
         }
 
@@ -593,7 +624,9 @@
             break;
     }
 
+    mLock.unlock();
     sendEvent(msg, ext1, ext2, in);
+    mLock.lock();
 }
 
 void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
@@ -623,12 +656,12 @@
 
     if (err == OK) {
         if (mIsAsyncPrepare) {
-            notifyListener(MEDIA_PREPARED);
+            notifyListener_l(MEDIA_PREPARED);
         }
         mState = STATE_PREPARED;
     } else {
         if (mIsAsyncPrepare) {
-            notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
+            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
         }
         mState = STATE_UNPREPARED;
     }
@@ -642,4 +675,10 @@
     mPlayerFlags = flags;
 }
 
+void NuPlayerDriver::setPauseStartedTimeIfNeeded() {
+    if (mPauseStartedTimeUs == -1) {
+        mPauseStartedTimeUs = ALooper::GetNowUs();
+    }
+}
+
 }  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index f520395..b0a52ad 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -69,6 +69,7 @@
     void notifyDuration(int64_t durationUs);
     void notifyPosition(int64_t positionUs);
     void notifySeekComplete();
+    void notifySeekComplete_l();
     void notifyFrameStats(int64_t numFramesTotal, int64_t numFramesDropped);
     void notifyListener(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL);
     void notifyFlagsChanged(uint32_t flags);
@@ -103,6 +104,8 @@
     // >>>
     int64_t mDurationUs;
     int64_t mPositionUs;
+    int64_t mNotifyTimeRealUs;
+    int64_t mPauseStartedTimeUs;
     int64_t mNumFramesTotal;
     int64_t mNumFramesDropped;
     // <<<
@@ -117,6 +120,8 @@
     int64_t mStartupSeekTimeUs;
 
     status_t prepare_l();
+    void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL);
+    void setPauseStartedTimeIfNeeded();
 
     DISALLOW_EVIL_CONSTRUCTORS(NuPlayerDriver);
 };
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 1213a18..a3c976d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -448,11 +448,13 @@
             copy = numBytesAvailableToWrite;
         }
 
-        CHECK_EQ(mAudioSink->write(
-                    entry->mBuffer->data() + entry->mOffset, copy),
-                 (ssize_t)copy);
+        ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset, copy);
+        if (written < 0) {
+            // An error in AudioSink write is fatal here.
+            LOG_ALWAYS_FATAL("AudioSink write error(%zd) when writing %zu bytes", written, copy);
+        }
 
-        entry->mOffset += copy;
+        entry->mOffset += written;
         if (entry->mOffset == entry->mBuffer->size()) {
             entry->mNotifyConsumed->post();
             mAudioQueue.erase(mAudioQueue.begin());
@@ -460,13 +462,33 @@
             entry = NULL;
         }
 
-        numBytesAvailableToWrite -= copy;
-        size_t copiedFrames = copy / mAudioSink->frameSize();
+        numBytesAvailableToWrite -= written;
+        size_t copiedFrames = written / mAudioSink->frameSize();
         mNumFramesWritten += copiedFrames;
 
         notifyIfMediaRenderingStarted();
-    }
 
+        if (written != (ssize_t)copy) {
+            // A short count was received from AudioSink::write()
+            //
+            // AudioSink write should block until exactly the number of bytes are delivered.
+            // But it may return with a short count (without an error) when:
+            //
+            // 1) Size to be copied is not a multiple of the frame size. We consider this fatal.
+            // 2) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded.
+
+            // (Case 1)
+            // Must be a multiple of the frame size.  If it is not a multiple of a frame size, it
+            // needs to fail, as we should not carry over fractional frames between calls.
+            CHECK_EQ(copy % mAudioSink->frameSize(), 0);
+
+            // (Case 2)
+            // Return early to the caller.
+            // Beware of calling immediately again as this may busy-loop if you are not careful.
+            ALOGW("AudioSink write short frame count %zd < %zu", written, copy);
+            break;
+        }
+    }
     notifyPosition();
 
     return !mAudioQueue.empty();
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 008da5a..9d6fd78 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -186,9 +186,9 @@
         const sp<IMediaHTTPService> &httpService,
         const char *uri,
         const KeyedVector<String8, String8> *headers,
-        AString *sniffedMIME) {
-    if (sniffedMIME != NULL) {
-        *sniffedMIME = "";
+        String8 *contentType) {
+    if (contentType != NULL) {
+        *contentType = "";
     }
 
     bool isWidevine = !strncasecmp("widevine://", uri, 11);
@@ -226,77 +226,14 @@
         }
 
         if (!isWidevine) {
-            String8 contentType = httpSource->getMIMEType();
+            if (contentType != NULL) {
+                *contentType = httpSource->getMIMEType();
+            }
 
-            sp<NuCachedSource2> cachedSource = new NuCachedSource2(
+            source = new NuCachedSource2(
                     httpSource,
                     cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
                     disconnectAtHighwatermark);
-
-            if (strncasecmp(contentType.string(), "audio/", 6)) {
-                // We're not doing this for streams that appear to be audio-only
-                // streams to ensure that even low bandwidth streams start
-                // playing back fairly instantly.
-
-                // We're going to prefill the cache before trying to instantiate
-                // the extractor below, as the latter is an operation that otherwise
-                // could block on the datasource for a significant amount of time.
-                // During that time we'd be unable to abort the preparation phase
-                // without this prefill.
-
-                // Initially make sure we have at least 192 KB for the sniff
-                // to complete without blocking.
-                static const size_t kMinBytesForSniffing = 192 * 1024;
-
-                off64_t metaDataSize = -1ll;
-                for (;;) {
-                    status_t finalStatus;
-                    size_t cachedDataRemaining =
-                            cachedSource->approxDataRemaining(&finalStatus);
-
-                    if (finalStatus != OK || (metaDataSize >= 0
-                            && (off64_t)cachedDataRemaining >= metaDataSize)) {
-                        ALOGV("stop caching, status %d, "
-                                "metaDataSize %lld, cachedDataRemaining %zu",
-                                finalStatus, metaDataSize, cachedDataRemaining);
-                        break;
-                    }
-
-                    ALOGV("now cached %zu bytes of data", cachedDataRemaining);
-
-                    if (metaDataSize < 0
-                            && cachedDataRemaining >= kMinBytesForSniffing) {
-                        String8 tmp;
-                        float confidence;
-                        sp<AMessage> meta;
-                        if (!cachedSource->sniff(&tmp, &confidence, &meta)) {
-                            return NULL;
-                        }
-
-                        // We successfully identified the file's extractor to
-                        // be, remember this mime type so we don't have to
-                        // sniff it again when we call MediaExtractor::Create()
-                        if (sniffedMIME != NULL) {
-                            *sniffedMIME = tmp.string();
-                        }
-
-                        if (meta == NULL
-                                || !meta->findInt64("meta-data-size",
-                                     reinterpret_cast<int64_t*>(&metaDataSize))) {
-                            metaDataSize = kDefaultMetaSize;
-                        }
-
-                        if (metaDataSize < 0ll) {
-                            ALOGE("invalid metaDataSize = %lld bytes", metaDataSize);
-                            return NULL;
-                        }
-                    }
-
-                    usleep(200000);
-                }
-            }
-
-            source = cachedSource;
         } else {
             // We do not want that prefetching, caching, datasource wrapper
             // in the widevine:// case.
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 7bb7ed9..814adab 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -716,7 +716,8 @@
                     CHECK(msg->findInt32("err", &err));
                     CHECK(msg->findInt32("actionCode", &actionCode));
 
-                    ALOGE("Codec reported err %#x, actionCode %d", err, actionCode);
+                    ALOGE("Codec reported err %#x, actionCode %d, while in state %d",
+                            err, actionCode, mState);
                     if (err == DEAD_OBJECT) {
                         mFlags |= kFlagSawMediaServerDie;
                     }
@@ -767,8 +768,12 @@
 
                         case FLUSHING:
                         {
-                            setState(
-                                    (mFlags & kFlagIsAsync) ? FLUSHED : STARTED);
+                            if (actionCode == ACTION_CODE_FATAL) {
+                                setState(UNINITIALIZED);
+                            } else {
+                                setState(
+                                        (mFlags & kFlagIsAsync) ? FLUSHED : STARTED);
+                            }
                             break;
                         }
 
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 09c6e69..90df607 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -493,6 +493,7 @@
     return mOutputDelayRingBufferSize - outputDelayRingBufferSamplesAvailable();
 }
 
+
 void SoftAAC2::onQueueFilled(OMX_U32 portIndex) {
     if (mSignalledError || mOutputPortSettingsChange != NONE) {
         return;
@@ -505,59 +506,55 @@
     List<BufferInfo *> &inQueue = getPortQueue(0);
     List<BufferInfo *> &outQueue = getPortQueue(1);
 
-    if (portIndex == 0 && mInputBufferCount == 0) {
-        BufferInfo *inInfo = *inQueue.begin();
-        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
-
-        inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
-        inBufferLength[0] = inHeader->nFilledLen;
-
-        AAC_DECODER_ERROR decoderErr =
-            aacDecoder_ConfigRaw(mAACDecoder,
-                                 inBuffer,
-                                 inBufferLength);
-
-        if (decoderErr != AAC_DEC_OK) {
-            ALOGW("aacDecoder_ConfigRaw decoderErr = 0x%4.4x", decoderErr);
-            mSignalledError = true;
-            notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
-            return;
-        }
-
-        mInputBufferCount++;
-        mOutputBufferCount++; // fake increase of outputBufferCount to keep the counters aligned
-
-        inInfo->mOwnedByUs = false;
-        inQueue.erase(inQueue.begin());
-        inInfo = NULL;
-        notifyEmptyBufferDone(inHeader);
-        inHeader = NULL;
-
-        configureDownmix();
-        // Only send out port settings changed event if both sample rate
-        // and numChannels are valid.
-        if (mStreamInfo->sampleRate && mStreamInfo->numChannels) {
-            ALOGI("Initially configuring decoder: %d Hz, %d channels",
-                mStreamInfo->sampleRate,
-                mStreamInfo->numChannels);
-
-            notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
-            mOutputPortSettingsChange = AWAITING_DISABLED;
-        }
-
-        return;
-    }
-
     while ((!inQueue.empty() || mEndOfInput) && !outQueue.empty()) {
         if (!inQueue.empty()) {
             INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT];
             BufferInfo *inInfo = *inQueue.begin();
             OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
 
-            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
-                mEndOfInput = true;
-            } else {
-                mEndOfInput = false;
+            mEndOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0;
+            if (portIndex == 0 &&
+                    (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) != 0) {
+                BufferInfo *inInfo = *inQueue.begin();
+                OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+                inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
+                inBufferLength[0] = inHeader->nFilledLen;
+
+                AAC_DECODER_ERROR decoderErr =
+                    aacDecoder_ConfigRaw(mAACDecoder,
+                                         inBuffer,
+                                         inBufferLength);
+
+                if (decoderErr != AAC_DEC_OK) {
+                    ALOGW("aacDecoder_ConfigRaw decoderErr = 0x%4.4x", decoderErr);
+                    mSignalledError = true;
+                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+                    return;
+                }
+
+                mInputBufferCount++;
+                mOutputBufferCount++; // fake increase of outputBufferCount to keep the counters aligned
+
+                inInfo->mOwnedByUs = false;
+                inQueue.erase(inQueue.begin());
+                mLastInHeader = NULL;
+                inInfo = NULL;
+                notifyEmptyBufferDone(inHeader);
+                inHeader = NULL;
+
+                configureDownmix();
+                // Only send out port settings changed event if both sample rate
+                // and numChannels are valid.
+                if (mStreamInfo->sampleRate && mStreamInfo->numChannels) {
+                    ALOGI("Initially configuring decoder: %d Hz, %d channels",
+                        mStreamInfo->sampleRate,
+                        mStreamInfo->numChannels);
+
+                    notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+                    mOutputPortSettingsChange = AWAITING_DISABLED;
+                }
+                return;
             }
 
             if (inHeader->nFilledLen == 0) {
@@ -567,206 +564,193 @@
                 inInfo = NULL;
                 notifyEmptyBufferDone(inHeader);
                 inHeader = NULL;
-            } else {
-                if (mIsADTS) {
-                    size_t adtsHeaderSize = 0;
-                    // skip 30 bits, aac_frame_length follows.
-                    // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
+                continue;
+            }
 
-                    const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;
+            if (mIsADTS) {
+                size_t adtsHeaderSize = 0;
+                // skip 30 bits, aac_frame_length follows.
+                // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
 
-                    bool signalError = false;
-                    if (inHeader->nFilledLen < 7) {
-                        ALOGE("Audio data too short to contain even the ADTS header. "
-                                "Got %d bytes.", inHeader->nFilledLen);
+                const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;
+
+                bool signalError = false;
+                if (inHeader->nFilledLen < 7) {
+                    ALOGE("Audio data too short to contain even the ADTS header. "
+                            "Got %d bytes.", inHeader->nFilledLen);
+                    hexdump(adtsHeader, inHeader->nFilledLen);
+                    signalError = true;
+                } else {
+                    bool protectionAbsent = (adtsHeader[1] & 1);
+
+                    unsigned aac_frame_length =
+                        ((adtsHeader[3] & 3) << 11)
+                        | (adtsHeader[4] << 3)
+                        | (adtsHeader[5] >> 5);
+
+                    if (inHeader->nFilledLen < aac_frame_length) {
+                        ALOGE("Not enough audio data for the complete frame. "
+                                "Got %d bytes, frame size according to the ADTS "
+                                "header is %u bytes.",
+                                inHeader->nFilledLen, aac_frame_length);
                         hexdump(adtsHeader, inHeader->nFilledLen);
                         signalError = true;
                     } else {
-                        bool protectionAbsent = (adtsHeader[1] & 1);
+                        adtsHeaderSize = (protectionAbsent ? 7 : 9);
 
-                        unsigned aac_frame_length =
-                            ((adtsHeader[3] & 3) << 11)
-                            | (adtsHeader[4] << 3)
-                            | (adtsHeader[5] >> 5);
+                        inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize;
+                        inBufferLength[0] = aac_frame_length - adtsHeaderSize;
 
-                        if (inHeader->nFilledLen < aac_frame_length) {
-                            ALOGE("Not enough audio data for the complete frame. "
-                                    "Got %d bytes, frame size according to the ADTS "
-                                    "header is %u bytes.",
-                                    inHeader->nFilledLen, aac_frame_length);
-                            hexdump(adtsHeader, inHeader->nFilledLen);
-                            signalError = true;
-                        } else {
-                            adtsHeaderSize = (protectionAbsent ? 7 : 9);
-
-                            inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize;
-                            inBufferLength[0] = aac_frame_length - adtsHeaderSize;
-
-                            inHeader->nOffset += adtsHeaderSize;
-                            inHeader->nFilledLen -= adtsHeaderSize;
-                        }
-                    }
-
-                    if (signalError) {
-                        mSignalledError = true;
-
-                        notify(OMX_EventError,
-                               OMX_ErrorStreamCorrupt,
-                               ERROR_MALFORMED,
-                               NULL);
-
-                        return;
-                    }
-                } else {
-                    inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
-                    inBufferLength[0] = inHeader->nFilledLen;
-                }
-
-                // Fill and decode
-                bytesValid[0] = inBufferLength[0];
-
-                INT prevSampleRate = mStreamInfo->sampleRate;
-                INT prevNumChannels = mStreamInfo->numChannels;
-
-                if (inHeader != mLastInHeader) {
-                    mLastInHeader = inHeader;
-                    mCurrentInputTime = inHeader->nTimeStamp;
-                } else {
-                    if (mStreamInfo->sampleRate) {
-                        mCurrentInputTime += mStreamInfo->aacSamplesPerFrame *
-                                1000000ll / mStreamInfo->sampleRate;
-                    } else {
-                        ALOGW("no sample rate yet");
+                        inHeader->nOffset += adtsHeaderSize;
+                        inHeader->nFilledLen -= adtsHeaderSize;
                     }
                 }
-                mAnchorTimes.add(mCurrentInputTime);
-                aacDecoder_Fill(mAACDecoder,
-                                inBuffer,
-                                inBufferLength,
-                                bytesValid);
 
-                 // run DRC check
-                 mDrcWrap.submitStreamData(mStreamInfo);
-                 mDrcWrap.update();
-
-                AAC_DECODER_ERROR decoderErr =
-                    aacDecoder_DecodeFrame(mAACDecoder,
-                                           tmpOutBuffer,
-                                           2048 * MAX_CHANNEL_COUNT,
-                                           0 /* flags */);
-
-                if (decoderErr != AAC_DEC_OK) {
-                    ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
-                }
-
-                if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
-                    ALOGE("AAC_DEC_NOT_ENOUGH_BITS should never happen");
+                if (signalError) {
                     mSignalledError = true;
-                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                    notify(OMX_EventError, OMX_ErrorStreamCorrupt, ERROR_MALFORMED, NULL);
                     return;
                 }
+            } else {
+                inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
+                inBufferLength[0] = inHeader->nFilledLen;
+            }
 
-                if (bytesValid[0] != 0) {
-                    ALOGE("bytesValid[0] != 0 should never happen");
-                    mSignalledError = true;
-                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
-                    return;
-                }
+            // Fill and decode
+            bytesValid[0] = inBufferLength[0];
 
-                size_t numOutBytes =
-                    mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
+            INT prevSampleRate = mStreamInfo->sampleRate;
+            INT prevNumChannels = mStreamInfo->numChannels;
 
-                if (decoderErr == AAC_DEC_OK) {
-                    if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
-                            mStreamInfo->frameSize * mStreamInfo->numChannels)) {
-                        mSignalledError = true;
-                        notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
-                        return;
-                    }
-                    UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
-                    inHeader->nFilledLen -= inBufferUsedLength;
-                    inHeader->nOffset += inBufferUsedLength;
+            if (inHeader != mLastInHeader) {
+                mLastInHeader = inHeader;
+                mCurrentInputTime = inHeader->nTimeStamp;
+            } else {
+                if (mStreamInfo->sampleRate) {
+                    mCurrentInputTime += mStreamInfo->aacSamplesPerFrame *
+                            1000000ll / mStreamInfo->sampleRate;
                 } 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
+                    ALOGW("no sample rate yet");
                 }
+            }
+            mAnchorTimes.add(mCurrentInputTime);
+            aacDecoder_Fill(mAACDecoder,
+                            inBuffer,
+                            inBufferLength,
+                            bytesValid);
 
-                /*
-                 * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
-                 * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
-                 * rate system and the sampling rate in the final output is actually
-                 * doubled compared with the core AAC decoder sampling rate.
-                 *
-                 * Explicit signalling is done by explicitly defining SBR audio object
-                 * type in the bitstream. Implicit signalling is done by embedding
-                 * SBR content in AAC extension payload specific to SBR, and hence
-                 * requires an AAC decoder to perform pre-checks on actual audio frames.
-                 *
-                 * Thus, we could not say for sure whether a stream is
-                 * AAC+/eAAC+ until the first data frame is decoded.
-                 */
-                if (mOutputBufferCount > 1) {
-                    if (mStreamInfo->sampleRate != prevSampleRate ||
-                        mStreamInfo->numChannels != prevNumChannels) {
-                        ALOGE("can not reconfigure AAC output");
-                        mSignalledError = true;
-                        notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
-                        return;
-                    }
-                }
-                if (mInputBufferCount <= 2) { // TODO: <= 1
-                    if (mStreamInfo->sampleRate != prevSampleRate ||
-                        mStreamInfo->numChannels != prevNumChannels) {
-                        ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels",
-                              prevSampleRate, mStreamInfo->sampleRate,
-                              prevNumChannels, mStreamInfo->numChannels);
+             // run DRC check
+             mDrcWrap.submitStreamData(mStreamInfo);
+             mDrcWrap.update();
 
-                        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
-                        mOutputPortSettingsChange = AWAITING_DISABLED;
+            AAC_DECODER_ERROR decoderErr =
+                aacDecoder_DecodeFrame(mAACDecoder,
+                                       tmpOutBuffer,
+                                       2048 * MAX_CHANNEL_COUNT,
+                                       0 /* flags */);
 
-                        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) {
+                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;
                 }
-                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);
+                UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
+                inHeader->nFilledLen -= inBufferUsedLength;
+                inHeader->nOffset += inBufferUsedLength;
+            } else {
+                ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr);
+
+                memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow
+
+                if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
+                        mStreamInfo->frameSize * mStreamInfo->numChannels)) {
+                    mSignalledError = true;
+                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+                    return;
                 }
+
+                // Discard input buffer.
+                inHeader->nFilledLen = 0;
+
+                aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
+
+                // fall through
+            }
+
+            /*
+             * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
+             * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
+             * rate system and the sampling rate in the final output is actually
+             * doubled compared with the core AAC decoder sampling rate.
+             *
+             * Explicit signalling is done by explicitly defining SBR audio object
+             * type in the bitstream. Implicit signalling is done by embedding
+             * SBR content in AAC extension payload specific to SBR, and hence
+             * requires an AAC decoder to perform pre-checks on actual audio frames.
+             *
+             * Thus, we could not say for sure whether a stream is
+             * AAC+/eAAC+ until the first data frame is decoded.
+             */
+            if (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);
             }
         }
 
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
index 76f8f54..7eb6542 100644
--- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
@@ -358,6 +358,11 @@
             CopyTimes(accessUnit, buffer);
             mPackets.push_back(accessUnit);
         }
+
+        if (offset != buffer->size()) {
+            ALOGW("potentially malformed packet (offset %d, size %d)",
+                    offset, buffer->size());
+        }
     }
 
     queue->erase(queue->begin());
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
index 37de610..b388079 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
@@ -51,7 +51,8 @@
         mZslStreamId(NO_STREAM),
         mFrameListHead(0),
         mZslQueueHead(0),
-        mZslQueueTail(0) {
+        mZslQueueTail(0),
+        mHasFocuser(false) {
     // Initialize buffer queue and frame list based on pipeline max depth.
     size_t pipelineMaxDepth = kDefaultMaxPipelineDepth;
     if (client != 0) {
@@ -67,6 +68,11 @@
                         " use default pipeline max depth %zu", __FUNCTION__,
                         kDefaultMaxPipelineDepth);
             }
+
+            entry = device->info().find(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE);
+            if (entry.count > 0 && entry.data.f[0] != 0.) {
+                mHasFocuser = true;
+            }
         }
     }
 
@@ -489,20 +495,23 @@
                     continue;
                 }
 
-                // Make sure the candidate frame has good focus.
-                entry = frame.find(ANDROID_CONTROL_AF_STATE);
-                if (entry.count == 0) {
-                    ALOGW("%s: ZSL queue frame has no AF state field!",
-                            __FUNCTION__);
-                    continue;
-                }
-                uint8_t afState = entry.data.u8[0];
-                if (afState != ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED &&
-                        afState != ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED &&
-                        afState != ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
-                    ALOGW("%s: ZSL queue frame AF state is %d is not good for capture, skip it",
-                            __FUNCTION__, afState);
-                    continue;
+                // Check AF state if device has focuser
+                if (mHasFocuser) {
+                    // Make sure the candidate frame has good focus.
+                    entry = frame.find(ANDROID_CONTROL_AF_STATE);
+                    if (entry.count == 0) {
+                        ALOGW("%s: ZSL queue frame has no AF state field!",
+                                __FUNCTION__);
+                        continue;
+                    }
+                    uint8_t afState = entry.data.u8[0];
+                    if (afState != ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED &&
+                            afState != ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED &&
+                            afState != ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
+                        ALOGW("%s: ZSL queue frame AF state is %d is not good for capture, skip it",
+                                __FUNCTION__, afState);
+                        continue;
+                    }
                 }
 
                 minTimestamp = frameTimestamp;
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
index dfb1457..daa352b 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
@@ -121,6 +121,8 @@
 
     CameraMetadata mLatestCapturedRequest;
 
+    bool mHasFocuser;
+
     virtual bool threadLoop();
 
     status_t clearZslQueueLocked();
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 86f82a3..80c797a 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -254,9 +254,17 @@
 }
 
 status_t CameraDeviceClient::endConfigure() {
-    // TODO: Implement this.
-    ALOGE("%s: Not implemented yet.", __FUNCTION__);
-    return OK;
+    ALOGV("%s: ending configure (%zu streams)",
+            __FUNCTION__, mStreamMap.size());
+
+    status_t res;
+    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
+    return mDevice->configureStreams();
 }
 
 status_t CameraDeviceClient::deleteStream(int streamId) {
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 9e124b0..d26e20c 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -141,6 +141,18 @@
     virtual status_t deleteReprocessStream(int id) = 0;
 
     /**
+     * Take the currently-defined set of streams and configure the HAL to use
+     * them. This is a long-running operation (may be several hundered ms).
+     *
+     * The device must be idle (see waitUntilDrained) before calling this.
+     *
+     * Returns OK on success; otherwise on error:
+     * - BAD_VALUE if the set of streams was invalid (e.g. fmts or sizes)
+     * - INVALID_OPERATION if the device was in the wrong state
+     */
+    virtual status_t configureStreams() = 0;
+
+    /**
      * Create a metadata buffer with fields that the HAL device believes are
      * best for the given use case
      */
diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp
index d473a76..8caadd6 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.cpp
+++ b/services/camera/libcameraservice/device2/Camera2Device.cpp
@@ -415,6 +415,19 @@
     return OK;
 }
 
+status_t Camera2Device::configureStreams() {
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+
+    /**
+     * HAL2 devices do not need to configure streams;
+     * streams are created on the fly.
+     */
+    ALOGW("%s: No-op for HAL2 devices", __FUNCTION__);
+
+    return OK;
+}
+
 
 status_t Camera2Device::createDefaultRequest(int templateId,
         CameraMetadata *request) {
diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h
index d0ca46e..2a3f1d9 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.h
+++ b/services/camera/libcameraservice/device2/Camera2Device.h
@@ -64,6 +64,8 @@
     virtual status_t setStreamTransform(int id, int transform);
     virtual status_t deleteStream(int id);
     virtual status_t deleteReprocessStream(int id);
+    // No-op on HAL2 devices
+    virtual status_t configureStreams();
     virtual status_t createDefaultRequest(int templateId, CameraMetadata *request);
     virtual status_t waitUntilDrained();
     virtual status_t setNotifyCallback(NotificationListener *listener);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index ed350c1..0d33406 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1000,6 +1000,15 @@
     return INVALID_OPERATION;
 }
 
+status_t Camera3Device::configureStreams() {
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+
+    Mutex::Autolock il(mInterfaceLock);
+    Mutex::Autolock l(mLock);
+
+    return configureStreamsLocked();
+}
 
 status_t Camera3Device::createDefaultRequest(int templateId,
         CameraMetadata *request) {
@@ -2129,6 +2138,8 @@
         mPaused(true),
         mFrameNumber(0),
         mLatestRequestId(NAME_NOT_FOUND),
+        mCurrentAfTriggerId(0),
+        mCurrentPreCaptureTriggerId(0),
         mRepeatingLastFrameNumber(NO_IN_FLIGHT_REPEATING_FRAMES) {
     mStatusId = statusTracker->addComponent();
 }
@@ -2611,6 +2622,8 @@
 
     if (nextRequest != NULL) {
         nextRequest->mResultExtras.frameNumber = mFrameNumber++;
+        nextRequest->mResultExtras.afTriggerId = mCurrentAfTriggerId;
+        nextRequest->mResultExtras.precaptureTriggerId = mCurrentPreCaptureTriggerId;
     }
     return nextRequest;
 }
@@ -2690,8 +2703,13 @@
         if (tag == ANDROID_CONTROL_AF_TRIGGER_ID || tag == ANDROID_CONTROL_AE_PRECAPTURE_ID) {
             bool isAeTrigger = (trigger.metadataTag == ANDROID_CONTROL_AE_PRECAPTURE_ID);
             uint32_t triggerId = static_cast<uint32_t>(trigger.entryValue);
-            isAeTrigger ? request->mResultExtras.precaptureTriggerId = triggerId :
-                          request->mResultExtras.afTriggerId = triggerId;
+            if (isAeTrigger) {
+                request->mResultExtras.precaptureTriggerId = triggerId;
+                mCurrentPreCaptureTriggerId = triggerId;
+            } else {
+                request->mResultExtras.afTriggerId = triggerId;
+                mCurrentAfTriggerId = triggerId;
+            }
             if (parent->mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
                 continue; // Trigger ID tag is deprecated since device HAL 3.2
             }
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 7656237..915c024 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -114,6 +114,8 @@
     virtual status_t deleteStream(int id);
     virtual status_t deleteReprocessStream(int id);
 
+    virtual status_t configureStreams();
+
     virtual status_t createDefaultRequest(int templateId, CameraMetadata *request);
 
     // Transitions to the idle state on success
@@ -484,6 +486,8 @@
         TriggerMap         mTriggerMap;
         TriggerMap         mTriggerRemovedMap;
         TriggerMap         mTriggerReplacedMap;
+        uint32_t           mCurrentAfTriggerId;
+        uint32_t           mCurrentPreCaptureTriggerId;
 
         int64_t            mRepeatingLastFrameNumber;
     };
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index 50a2c10..cc66459 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -184,15 +184,6 @@
         return INVALID_OPERATION;
     }
 
-    // Only limit dequeue amount when fully configured
-    if (mState == STATE_CONFIGURED &&
-            mHandoutTotalBufferCount == camera3_stream::max_buffers) {
-        ALOGE("%s: Stream %d: Already dequeued maximum number of simultaneous"
-                " buffers (%d)", __FUNCTION__, mId,
-                camera3_stream::max_buffers);
-        return INVALID_OPERATION;
-    }
-
     return OK;
 }