Merge "Fix warning while building mediaserver"
diff --git a/camera/camera2/ICameraDeviceUser.cpp b/camera/camera2/ICameraDeviceUser.cpp
index 277b5db..d1d63d5 100644
--- a/camera/camera2/ICameraDeviceUser.cpp
+++ b/camera/camera2/ICameraDeviceUser.cpp
@@ -208,14 +208,11 @@
         return reply.readInt32();
     }
 
-    virtual status_t createStream(int width, int height, int format,
+    virtual status_t createStream(
                           const sp<IGraphicBufferProducer>& bufferProducer)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
-        data.writeInt32(width);
-        data.writeInt32(height);
-        data.writeInt32(format);
 
         data.writeInt32(1); // marker that bufferProducer is not null
         data.writeString16(String16("unknown_name")); // name of surface
@@ -396,14 +393,6 @@
         } break;
         case CREATE_STREAM: {
             CHECK_INTERFACE(ICameraDeviceUser, data, reply);
-            int width, height, format;
-
-            width = data.readInt32();
-            ALOGV("%s: CREATE_STREAM: width = %d", __FUNCTION__, width);
-            height = data.readInt32();
-            ALOGV("%s: CREATE_STREAM: height = %d", __FUNCTION__, height);
-            format = data.readInt32();
-            ALOGV("%s: CREATE_STREAM: format = %d", __FUNCTION__, format);
 
             sp<IGraphicBufferProducer> bp;
             if (data.readInt32() != 0) {
@@ -419,7 +408,7 @@
             }
 
             status_t ret;
-            ret = createStream(width, height, format, bp);
+            ret = createStream(bp);
 
             reply->writeNoException();
             ALOGV("%s: CREATE_STREAM: write noException", __FUNCTION__);
diff --git a/cmds/stagefright/SimplePlayer.cpp b/cmds/stagefright/SimplePlayer.cpp
index 40762e5..ac1a547 100644
--- a/cmds/stagefright/SimplePlayer.cpp
+++ b/cmds/stagefright/SimplePlayer.cpp
@@ -116,7 +116,7 @@
                 mState = UNPREPARED;
             }
 
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             sp<AMessage> response = new AMessage;
@@ -139,7 +139,7 @@
                 err = OK;
             }
 
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             sp<AMessage> response = new AMessage;
@@ -161,7 +161,7 @@
                 }
             }
 
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             sp<AMessage> response = new AMessage;
@@ -194,7 +194,7 @@
                 }
             }
 
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             sp<AMessage> response = new AMessage;
@@ -217,7 +217,7 @@
                 }
             }
 
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             sp<AMessage> response = new AMessage;
@@ -240,7 +240,7 @@
                 mState = UNINITIALIZED;
             }
 
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             sp<AMessage> response = new AMessage;
diff --git a/include/camera/camera2/ICameraDeviceUser.h b/include/camera/camera2/ICameraDeviceUser.h
index 35488bb..bfc2aa0 100644
--- a/include/camera/camera2/ICameraDeviceUser.h
+++ b/include/camera/camera2/ICameraDeviceUser.h
@@ -101,7 +101,6 @@
 
     virtual status_t        deleteStream(int streamId) = 0;
     virtual status_t        createStream(
-            int width, int height, int format,
             const sp<IGraphicBufferProducer>& bufferProducer) = 0;
 
     // Create a request object from a template.
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 2e1ed6c..3de0774 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -63,7 +63,7 @@
                                     // See AudioTimestamp for the information included with event.
     };
 
-    /* Client should declare Buffer on the stack and pass address to obtainBuffer()
+    /* Client should declare a Buffer and pass the address to obtainBuffer()
      * and releaseBuffer().  See also callback_t for EVENT_MORE_DATA.
      */
 
@@ -72,14 +72,20 @@
     public:
         // FIXME use m prefix
         size_t      frameCount;   // number of sample frames corresponding to size;
-                                  // on input it is the number of frames desired,
-                                  // on output is the number of frames actually filled
-                                  // (currently ignored, but will make the primary field in future)
+                                  // on input to obtainBuffer() it is the number of frames desired,
+                                  // on output from obtainBuffer() it is the number of available
+                                  //    [empty slots for] frames to be filled
+                                  // on input to releaseBuffer() it is currently ignored
 
         size_t      size;         // input/output in bytes == frameCount * frameSize
-                                  // on input it is unused
-                                  // on output is the number of bytes actually filled
-                                  // FIXME this is redundant with respect to frameCount.
+                                  // on input to obtainBuffer() it is ignored
+                                  // on output from obtainBuffer() it is the number of available
+                                  //    [empty slots for] bytes to be filled,
+                                  //    which is frameCount * frameSize
+                                  // on input to releaseBuffer() it is the number of bytes to
+                                  //    release
+                                  // FIXME This is redundant with respect to frameCount.  Consider
+                                  //    removing size and making frameCount the primary field.
 
         union {
             void*       raw;
@@ -484,10 +490,18 @@
      */
             status_t    attachAuxEffect(int effectId);
 
-    /* Obtains a buffer of up to "audioBuffer->frameCount" empty slots for frames.
+    /* Public API for TRANSFER_OBTAIN mode.
+     * Obtains a buffer of up to "audioBuffer->frameCount" empty slots for frames.
      * After filling these slots with data, the caller should release them with releaseBuffer().
      * If the track buffer is not full, obtainBuffer() returns as many contiguous
      * [empty slots for] frames as are available immediately.
+     *
+     * If nonContig is non-NULL, it is an output parameter that will be set to the number of
+     * additional non-contiguous frames that are predicted to be available immediately,
+     * if the client were to release the first frames and then call obtainBuffer() again.
+     * This value is only a prediction, and needs to be confirmed.
+     * It will be set to zero for an error return.
+     *
      * If the track buffer is full and track is stopped, obtainBuffer() returns WOULD_BLOCK
      * regardless of the value of waitCount.
      * If the track buffer is full and track is not stopped, obtainBuffer() blocks with a
@@ -496,7 +510,6 @@
      * is exhausted, at which point obtainBuffer() will either block
      * or return WOULD_BLOCK depending on the value of the "waitCount"
      * parameter.
-     * Each sample is 16-bit signed PCM.
      *
      * obtainBuffer() and releaseBuffer() are deprecated for direct use by applications,
      * which should use write() or callback EVENT_MORE_DATA instead.
@@ -508,24 +521,29 @@
      *
      * Buffer fields
      * On entry:
-     *  frameCount  number of frames requested
+     *  frameCount  number of [empty slots for] frames requested
+     *  size        ignored
+     *  raw         ignored
      * After error return:
      *  frameCount  0
      *  size        0
      *  raw         undefined
      * After successful return:
-     *  frameCount  actual number of frames available, <= number requested
+     *  frameCount  actual number of [empty slots for] frames available, <= number requested
      *  size        actual number of bytes available
      *  raw         pointer to the buffer
      */
-
     /* FIXME Deprecated public API for TRANSFER_OBTAIN mode */
-            status_t    obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
+            status_t    obtainBuffer(Buffer* audioBuffer, int32_t waitCount,
+                                size_t *nonContig = NULL)
                                 __attribute__((__deprecated__));
 
 private:
     /* If nonContig is non-NULL, it is an output parameter that will be set to the number of
-     * additional non-contiguous frames that are available immediately.
+     * additional non-contiguous frames that are predicted to be available immediately,
+     * if the client were to release the first frames and then call obtainBuffer() again.
+     * This value is only a prediction, and needs to be confirmed.
+     * It will be set to zero for an error return.
      * FIXME We could pass an array of Buffers instead of only one Buffer to obtainBuffer(),
      * in case the requested amount of frames is in two or more non-contiguous regions.
      * FIXME requested and elapsed are both relative times.  Consider changing to absolute time.
@@ -534,9 +552,17 @@
                                      struct timespec *elapsed = NULL, size_t *nonContig = NULL);
 public:
 
-    /* Release a filled buffer of "audioBuffer->frameCount" frames for AudioFlinger to process. */
+    /* Public API for TRANSFER_OBTAIN mode.
+     * Release a filled buffer of frames for AudioFlinger to process.
+     *
+     * Buffer fields:
+     *  frameCount  currently ignored but recommend to set to actual number of frames filled
+     *  size        actual number of bytes filled, must be multiple of frameSize
+     *  raw         ignored
+     *
+     */
     // FIXME make private when obtainBuffer() for TRANSFER_OBTAIN is removed
-            void        releaseBuffer(Buffer* audioBuffer);
+            void        releaseBuffer(const Buffer* audioBuffer);
 
     /* As a convenience we provide a write() interface to the audio buffer.
      * Input parameter 'size' is in byte units.
diff --git a/media/libmediaplayerservice/nuplayer/MediaClock.h b/include/media/stagefright/MediaClock.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/MediaClock.h
rename to include/media/stagefright/MediaClock.h
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index d448097..8241e19 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -27,6 +27,7 @@
 
 struct ABuffer;
 struct AMessage;
+struct AReplyToken;
 struct AString;
 struct CodecBase;
 struct ICrypto;
@@ -222,7 +223,7 @@
     sp<ALooper> mCodecLooper;
     sp<CodecBase> mCodec;
     AString mComponentName;
-    uint32_t mReplyID;
+    sp<AReplyToken> mReplyID;
     uint32_t mFlags;
     status_t mStickyError;
     sp<Surface> mNativeWindow;
@@ -249,10 +250,10 @@
     Vector<BufferInfo> mPortBuffers[2];
 
     int32_t mDequeueInputTimeoutGeneration;
-    uint32_t mDequeueInputReplyID;
+    sp<AReplyToken> mDequeueInputReplyID;
 
     int32_t mDequeueOutputTimeoutGeneration;
-    uint32_t mDequeueOutputReplyID;
+    sp<AReplyToken> mDequeueOutputReplyID;
 
     sp<ICrypto> mCrypto;
 
@@ -267,7 +268,7 @@
     static status_t PostAndAwaitResponse(
             const sp<AMessage> &msg, sp<AMessage> *response);
 
-    static void PostReplyWithError(int32_t replyID, int32_t err);
+    static void PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err);
 
     status_t init(const AString &name, bool nameIsType, bool encoder);
 
@@ -283,8 +284,8 @@
             size_t portIndex, size_t index,
             sp<ABuffer> *buffer, sp<AMessage> *format);
 
-    bool handleDequeueInputBuffer(uint32_t replyID, bool newRequest = false);
-    bool handleDequeueOutputBuffer(uint32_t replyID, bool newRequest = false);
+    bool handleDequeueInputBuffer(const sp<AReplyToken> &replyID, bool newRequest = false);
+    bool handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool newRequest = false);
     void cancelPendingDequeueOperations();
 
     void extractCSD(const sp<AMessage> &format);
diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h
index 0970b2b..7b8f59d 100644
--- a/include/media/stagefright/MediaCodecSource.h
+++ b/include/media/stagefright/MediaCodecSource.h
@@ -25,6 +25,7 @@
 
 class ALooper;
 class AMessage;
+struct AReplyToken;
 class IGraphicBufferProducer;
 class MediaCodec;
 class MetaData;
@@ -99,7 +100,7 @@
     sp<Puller> mPuller;
     sp<MediaCodec> mEncoder;
     uint32_t mFlags;
-    List<uint32_t> mStopReplyIDQueue;
+    List<sp<AReplyToken>> mStopReplyIDQueue;
     bool mIsVideo;
     bool mStarted;
     bool mStopping;
diff --git a/include/media/stagefright/foundation/ALooper.h b/include/media/stagefright/foundation/ALooper.h
index 150cdba..09c469b 100644
--- a/include/media/stagefright/foundation/ALooper.h
+++ b/include/media/stagefright/foundation/ALooper.h
@@ -30,6 +30,7 @@
 
 struct AHandler;
 struct AMessage;
+struct AReplyToken;
 
 struct ALooper : public RefBase {
     typedef int32_t event_id;
@@ -79,7 +80,27 @@
     sp<LooperThread> mThread;
     bool mRunningLocally;
 
+    // use a separate lock for reply handling, as it is always on another thread
+    // use a central lock, however, to avoid creating a mutex for each reply
+    Mutex mRepliesLock;
+    Condition mRepliesCondition;
+
+    // START --- methods used only by AMessage
+
+    // posts a message on this looper with the given timeout
     void post(const sp<AMessage> &msg, int64_t delayUs);
+
+    // creates a reply token to be used with this looper
+    sp<AReplyToken> createReplyToken();
+    // waits for a response for the reply token.  If status is OK, the response
+    // is stored into the supplied variable.  Otherwise, it is unchanged.
+    status_t awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response);
+    // posts a reply for a reply token.  If the reply could be successfully posted,
+    // it returns OK. Otherwise, it returns an error value.
+    status_t postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &msg);
+
+    // END --- methods used only by AMessage
+
     bool loop();
 
     DISALLOW_EVIL_CONSTRUCTORS(ALooper);
diff --git a/include/media/stagefright/foundation/ALooperRoster.h b/include/media/stagefright/foundation/ALooperRoster.h
index 96bce6b..9912455 100644
--- a/include/media/stagefright/foundation/ALooperRoster.h
+++ b/include/media/stagefright/foundation/ALooperRoster.h
@@ -33,11 +33,6 @@
     void unregisterHandler(ALooper::handler_id handlerID);
     void unregisterStaleHandlers();
 
-    status_t postAndAwaitResponse(
-            const sp<AMessage> &msg, sp<AMessage> *response);
-
-    void postReply(uint32_t replyID, const sp<AMessage> &reply);
-
     void dump(int fd, const Vector<String16>& args);
 
 private:
@@ -49,10 +44,6 @@
     Mutex mLock;
     KeyedVector<ALooper::handler_id, HandlerInfo> mHandlers;
     ALooper::handler_id mNextHandlerID;
-    uint32_t mNextReplyID;
-    Condition mRepliesCondition;
-
-    KeyedVector<uint32_t, sp<AMessage> > mReplies;
 
     DISALLOW_EVIL_CONSTRUCTORS(ALooperRoster);
 };
diff --git a/include/media/stagefright/foundation/AMessage.h b/include/media/stagefright/foundation/AMessage.h
index ab3279d..4c6bd21 100644
--- a/include/media/stagefright/foundation/AMessage.h
+++ b/include/media/stagefright/foundation/AMessage.h
@@ -30,6 +30,34 @@
 struct AString;
 struct Parcel;
 
+struct AReplyToken : public RefBase {
+    AReplyToken(const sp<ALooper> &looper)
+        : mLooper(looper),
+          mReplied(false) {
+    }
+
+private:
+    friend struct AMessage;
+    friend struct ALooper;
+    wp<ALooper> mLooper;
+    sp<AMessage> mReply;
+    bool mReplied;
+
+    sp<ALooper> getLooper() const {
+        return mLooper.promote();
+    }
+    // if reply is not set, returns false; otherwise, it retrieves the reply and returns true
+    bool retrieveReply(sp<AMessage> *reply) {
+        if (mReplied) {
+            *reply = mReply;
+            mReply.clear();
+        }
+        return mReplied;
+    }
+    // sets the reply for this token. returns OK or error
+    status_t setReply(const sp<AMessage> &reply);
+};
+
 struct AMessage : public RefBase {
     AMessage();
     AMessage(uint32_t what, const sp<const AHandler> &handler);
@@ -84,11 +112,15 @@
     status_t postAndAwaitResponse(sp<AMessage> *response);
 
     // If this returns true, the sender of this message is synchronously
-    // awaiting a response, the "replyID" can be used to send the response
-    // via "postReply" below.
-    bool senderAwaitsResponse(uint32_t *replyID) const;
+    // awaiting a response and the reply token is consumed from the message
+    // and stored into replyID. The reply token must be used to send the response
+    // using "postReply" below.
+    bool senderAwaitsResponse(sp<AReplyToken> *replyID);
 
-    void postReply(uint32_t replyID);
+    // Posts the message as a response to a reply token.  A reply token can
+    // only be used once. Returns OK if the response could be posted; otherwise,
+    // an error.
+    status_t postReply(const sp<AReplyToken> &replyID);
 
     // Performs a deep-copy of "this", contained messages are in turn "dup'ed".
     // Warning: RefBase items, i.e. "objects" are _not_ copied but only have
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 1d5fc95..c775e7b 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -299,6 +299,9 @@
         ALOGV("Building AudioTrack with attributes: usage=%d content=%d flags=0x%x tags=[%s]",
                 mAttributes.usage, mAttributes.content_type, mAttributes.flags, mAttributes.tags);
         mStreamType = AUDIO_STREAM_DEFAULT;
+        if ((mAttributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
+            flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
+        }
     }
 
     // these below should probably come from the audioFlinger too...
@@ -1002,7 +1005,9 @@
             // use case 1: shared buffer
             (mSharedBuffer != 0) ||
             // use case 2: callback transfer mode
-            (mTransfer == TRANSFER_CALLBACK)) &&
+            (mTransfer == TRANSFER_CALLBACK) ||
+            // use case 3: obtain/release mode
+            (mTransfer == TRANSFER_OBTAIN)) &&
             // matching sample rate
             (mSampleRate == afSampleRate))) {
         ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client");
@@ -1236,7 +1241,7 @@
     return status;
 }
 
-status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
+status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount, size_t *nonContig)
 {
     if (audioBuffer == NULL) {
         return BAD_VALUE;
@@ -1263,7 +1268,7 @@
         ALOGE("%s invalid waitCount %d", __func__, waitCount);
         requested = NULL;
     }
-    return obtainBuffer(audioBuffer, requested);
+    return obtainBuffer(audioBuffer, requested, NULL /*elapsed*/, nonContig);
 }
 
 status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, const struct timespec *requested,
@@ -1338,8 +1343,9 @@
     return status;
 }
 
-void AudioTrack::releaseBuffer(Buffer* audioBuffer)
+void AudioTrack::releaseBuffer(const Buffer* audioBuffer)
 {
+    // FIXME add error checking on mode, by adding an internal version
     if (mTransfer == TRANSFER_SHARED) {
         return;
     }
diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp
index 73f1a2a..d4f6fab 100644
--- a/media/libmediaplayerservice/Drm.cpp
+++ b/media/libmediaplayerservice/Drm.cpp
@@ -23,6 +23,8 @@
 
 #include "Drm.h"
 
+#include "DrmSessionClientInterface.h"
+#include "DrmSessionManager.h"
 #include <media/drm/DrmAPI.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AString.h>
@@ -33,6 +35,10 @@
 
 namespace android {
 
+static inline int getCallingPid() {
+    return IPCThreadState::self()->getCallingPid();
+}
+
 static bool checkPermission(const char* permissionString) {
 #ifndef HAVE_ANDROID_OS
     return true;
@@ -57,14 +63,41 @@
     return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
 }
 
+struct DrmSessionClient : public DrmSessionClientInterface {
+    DrmSessionClient(Drm* drm) : mDrm(drm) {}
+
+    virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
+        sp<Drm> drm = mDrm.promote();
+        if (drm == NULL) {
+            return true;
+        }
+        status_t err = drm->closeSession(sessionId);
+        if (err != OK) {
+            return false;
+        }
+        drm->sendEvent(DrmPlugin::kDrmPluginEventSessionReclaimed, 0, &sessionId, NULL);
+        return true;
+    }
+
+protected:
+    virtual ~DrmSessionClient() {}
+
+private:
+    wp<Drm> mDrm;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
+};
+
 Drm::Drm()
     : mInitCheck(NO_INIT),
+      mDrmSessionClient(new DrmSessionClient(this)),
       mListener(NULL),
       mFactory(NULL),
       mPlugin(NULL) {
 }
 
 Drm::~Drm() {
+    DrmSessionManager::Instance()->removeDrm(mDrmSessionClient);
     delete mPlugin;
     mPlugin = NULL;
     closeFactory();
@@ -289,7 +322,18 @@
         return -EINVAL;
     }
 
-    return mPlugin->openSession(sessionId);
+    status_t err = mPlugin->openSession(sessionId);
+    if (err == ERROR_DRM_RESOURCE_BUSY) {
+        bool retry = false;
+        retry = DrmSessionManager::Instance()->reclaimSession(getCallingPid());
+        if (retry) {
+            err = mPlugin->openSession(sessionId);
+        }
+    }
+    if (err == OK) {
+        DrmSessionManager::Instance()->addSession(getCallingPid(), mDrmSessionClient, sessionId);
+    }
+    return err;
 }
 
 status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
@@ -303,7 +347,11 @@
         return -EINVAL;
     }
 
-    return mPlugin->closeSession(sessionId);
+    status_t err = mPlugin->closeSession(sessionId);
+    if (err == OK) {
+        DrmSessionManager::Instance()->removeSession(sessionId);
+    }
+    return err;
 }
 
 status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId,
@@ -321,6 +369,8 @@
         return -EINVAL;
     }
 
+    DrmSessionManager::Instance()->useSession(sessionId);
+
     return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
                                   optionalParameters, request, defaultUrl);
 }
@@ -338,6 +388,8 @@
         return -EINVAL;
     }
 
+    DrmSessionManager::Instance()->useSession(sessionId);
+
     return mPlugin->provideKeyResponse(sessionId, response, keySetId);
 }
 
@@ -367,6 +419,8 @@
         return -EINVAL;
     }
 
+    DrmSessionManager::Instance()->useSession(sessionId);
+
     return mPlugin->restoreKeys(sessionId, keySetId);
 }
 
@@ -382,6 +436,8 @@
         return -EINVAL;
     }
 
+    DrmSessionManager::Instance()->useSession(sessionId);
+
     return mPlugin->queryKeyStatus(sessionId, infoMap);
 }
 
@@ -561,6 +617,8 @@
         return -EINVAL;
     }
 
+    DrmSessionManager::Instance()->useSession(sessionId);
+
     return mPlugin->setCipherAlgorithm(sessionId, algorithm);
 }
 
@@ -576,6 +634,8 @@
         return -EINVAL;
     }
 
+    DrmSessionManager::Instance()->useSession(sessionId);
+
     return mPlugin->setMacAlgorithm(sessionId, algorithm);
 }
 
@@ -594,6 +654,8 @@
         return -EINVAL;
     }
 
+    DrmSessionManager::Instance()->useSession(sessionId);
+
     return mPlugin->encrypt(sessionId, keyId, input, iv, output);
 }
 
@@ -612,6 +674,8 @@
         return -EINVAL;
     }
 
+    DrmSessionManager::Instance()->useSession(sessionId);
+
     return mPlugin->decrypt(sessionId, keyId, input, iv, output);
 }
 
@@ -629,6 +693,8 @@
         return -EINVAL;
     }
 
+    DrmSessionManager::Instance()->useSession(sessionId);
+
     return mPlugin->sign(sessionId, keyId, message, signature);
 }
 
@@ -647,6 +713,8 @@
         return -EINVAL;
     }
 
+    DrmSessionManager::Instance()->useSession(sessionId);
+
     return mPlugin->verify(sessionId, keyId, message, signature, match);
 }
 
@@ -669,6 +737,8 @@
         return -EPERM;
     }
 
+    DrmSessionManager::Instance()->useSession(sessionId);
+
     return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature);
 }
 
diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h
index 0e1eb2c..0cea639 100644
--- a/media/libmediaplayerservice/Drm.h
+++ b/media/libmediaplayerservice/Drm.h
@@ -28,6 +28,7 @@
 
 struct DrmFactory;
 struct DrmPlugin;
+struct DrmSessionClientInterface;
 
 struct Drm : public BnDrm,
              public IBinder::DeathRecipient,
@@ -138,6 +139,8 @@
 
     status_t mInitCheck;
 
+    sp<DrmSessionClientInterface> mDrmSessionClient;
+
     sp<IDrmClient> mListener;
     mutable Mutex mEventLock;
     mutable Mutex mNotifyLock;
diff --git a/media/libmediaplayerservice/DrmSessionManager.cpp b/media/libmediaplayerservice/DrmSessionManager.cpp
index 43346e0..6e17eb1 100644
--- a/media/libmediaplayerservice/DrmSessionManager.cpp
+++ b/media/libmediaplayerservice/DrmSessionManager.cpp
@@ -23,6 +23,8 @@
 #include "DrmSessionClientInterface.h"
 #include "ProcessInfoInterface.h"
 #include <binder/IPCThreadState.h>
+#include <binder/IProcessInfoService.h>
+#include <binder/IServiceManager.h>
 #include <unistd.h>
 #include <utils/String8.h>
 
@@ -39,12 +41,25 @@
 struct ProcessInfo : public ProcessInfoInterface {
     ProcessInfo() {}
 
-    virtual int getPriority(int pid) {
-        // TODO: implement
-        // Get process state to determine priority.
-        // According to the define of PROCESS_STATE_***, higher the value lower
-        // the priority. So we will do a converting from state to priority here.
-        return -1;
+    virtual bool getPriority(int pid, int* priority) {
+        sp<IBinder> binder = defaultServiceManager()->getService(String16("processinfo"));
+        sp<IProcessInfoService> service = interface_cast<IProcessInfoService>(binder);
+
+        size_t length = 1;
+        int32_t states;
+        status_t err = service->getProcessStatesFromPids(length, &pid, &states);
+        if (err != OK) {
+            ALOGE("getProcessStatesFromPids failed");
+            return false;
+        }
+        ALOGV("pid %d states %d", pid, states);
+        if (states < 0) {
+            return false;
+        }
+
+        // Use process state as the priority. Lower the value, higher the priority.
+        *priority = states;
+        return true;
     }
 
 protected:
@@ -66,6 +81,11 @@
     return true;
 }
 
+sp<DrmSessionManager> DrmSessionManager::Instance() {
+    static sp<DrmSessionManager> drmSessionManager = new DrmSessionManager();
+    return drmSessionManager;
+}
+
 DrmSessionManager::DrmSessionManager()
     : mProcessInfo(new ProcessInfo()),
       mTime(0) {}
@@ -155,15 +175,18 @@
 
     sp<DrmSessionClientInterface> drm;
     Vector<uint8_t> sessionId;
+    int lowestPriorityPid;
+    int lowestPriority;
     {
         Mutex::Autolock lock(mLock);
-        int callingPriority = mProcessInfo->getPriority(callingPid);
-        int lowestPriorityPid;
-        int lowestPriority;
+        int callingPriority;
+        if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
+            return false;
+        }
         if (!getLowestPriority_l(&lowestPriorityPid, &lowestPriority)) {
             return false;
         }
-        if (lowestPriority >= callingPriority) {
+        if (lowestPriority <= callingPriority) {
             return false;
         }
 
@@ -176,6 +199,9 @@
         return false;
     }
 
+    ALOGV("reclaim session(%s) opened by pid %d",
+            GetSessionIdString(sessionId).string(), lowestPriorityPid);
+
     return drm->reclaimSession(sessionId);
 }
 
@@ -185,19 +211,23 @@
 
 bool DrmSessionManager::getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority) {
     int pid = -1;
-    int priority = INT_MAX;
+    int priority = -1;
     for (size_t i = 0; i < mSessionMap.size(); ++i) {
         if (mSessionMap.valueAt(i).size() == 0) {
             // no opened session by this process.
             continue;
         }
         int tempPid = mSessionMap.keyAt(i);
-        int tempPriority = mProcessInfo->getPriority(tempPid);
+        int tempPriority;
+        if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
+            // shouldn't happen.
+            return false;
+        }
         if (pid == -1) {
             pid = tempPid;
             priority = tempPriority;
         } else {
-            if (tempPriority < priority) {
+            if (tempPriority > priority) {
                 pid = tempPid;
                 priority = tempPriority;
             }
diff --git a/media/libmediaplayerservice/DrmSessionManager.h b/media/libmediaplayerservice/DrmSessionManager.h
index 1d0ed43..ba5c268 100644
--- a/media/libmediaplayerservice/DrmSessionManager.h
+++ b/media/libmediaplayerservice/DrmSessionManager.h
@@ -42,6 +42,8 @@
 typedef KeyedVector<int, SessionInfos > PidSessionInfosMap;
 
 struct DrmSessionManager : public RefBase {
+    static sp<DrmSessionManager> Instance();
+
     DrmSessionManager();
     DrmSessionManager(sp<ProcessInfoInterface> processInfo);
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 5e5d099..f113e21 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -290,8 +290,9 @@
     const sp<IServiceManager> sm(defaultServiceManager());
     if (sm != NULL) {
         const String16 name("batterystats");
+        // use checkService() to avoid blocking if service is not up yet
         sp<IBatteryStats> batteryStats =
-                interface_cast<IBatteryStats>(sm->getService(name));
+                interface_cast<IBatteryStats>(sm->checkService(name));
         if (batteryStats != NULL) {
             batteryStats->noteResetVideo();
             batteryStats->noteResetAudio();
@@ -441,6 +442,9 @@
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
+    SortedVector< sp<Client> > clients; //to serialise the mutex unlock & client destruction.
+    SortedVector< sp<MediaRecorderClient> > mediaRecorderClients;
+
     if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
         snprintf(buffer, SIZE, "Permission Denial: "
                 "can't dump MediaPlayerService from pid=%d, uid=%d\n",
@@ -452,6 +456,7 @@
         for (int i = 0, n = mClients.size(); i < n; ++i) {
             sp<Client> c = mClients[i].promote();
             if (c != 0) c->dump(fd, args);
+            clients.add(c);
         }
         if (mMediaRecorderClients.size() == 0) {
                 result.append(" No media recorder client\n\n");
@@ -464,6 +469,7 @@
                     write(fd, result.string(), result.size());
                     result = "\n";
                     c->dump(fd, args);
+                    mediaRecorderClients.add(c);
                 }
             }
         }
diff --git a/media/libmediaplayerservice/ProcessInfoInterface.h b/media/libmediaplayerservice/ProcessInfoInterface.h
index bdcc1da..222f92d 100644
--- a/media/libmediaplayerservice/ProcessInfoInterface.h
+++ b/media/libmediaplayerservice/ProcessInfoInterface.h
@@ -22,7 +22,7 @@
 namespace android {
 
 struct ProcessInfoInterface : public RefBase {
-    virtual int getPriority(int pid) = 0;
+    virtual bool getPriority(int pid, int* priority) = 0;
 
 protected:
     virtual ~ProcessInfoInterface() {}
diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk
index e2c72ed..6609874 100644
--- a/media/libmediaplayerservice/nuplayer/Android.mk
+++ b/media/libmediaplayerservice/nuplayer/Android.mk
@@ -4,7 +4,6 @@
 LOCAL_SRC_FILES:=                       \
         GenericSource.cpp               \
         HTTPLiveSource.cpp              \
-        MediaClock.cpp                  \
         NuPlayer.cpp                    \
         NuPlayerCCDecoder.cpp           \
         NuPlayerDecoder.cpp             \
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 24163e8..a040343 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -65,12 +65,12 @@
       mUID(uid),
       mFd(-1),
       mDrmManagerClient(NULL),
-      mMetaDataSize(-1ll),
       mBitrate(-1ll),
       mPollBufferingGeneration(0),
       mPendingReadBufferTypes(0),
       mBuffering(false),
-      mPrepareBuffering(false) {
+      mPrepareBuffering(false),
+      mPrevBufferPercentage(-1) {
     resetDataSource();
     DataSource::RegisterDefaultSniffers();
 }
@@ -147,14 +147,11 @@
             return UNKNOWN_ERROR;
         }
     } else if (mIsStreaming) {
-        if (mSniffedMIME.empty()) {
-            if (!mDataSource->sniff(&mimeType, &confidence, &dummy)) {
-                return UNKNOWN_ERROR;
-            }
-            mSniffedMIME = mimeType.string();
+        if (!mDataSource->sniff(&mimeType, &confidence, &dummy)) {
+            return UNKNOWN_ERROR;
         }
         isWidevineStreaming = !strcasecmp(
-                mSniffedMIME.c_str(), MEDIA_MIMETYPE_CONTAINER_WVM);
+                mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM);
     }
 
     if (isWidevineStreaming) {
@@ -169,7 +166,7 @@
         extractor = mWVMExtractor;
     } else {
         extractor = MediaExtractor::Create(mDataSource,
-                mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str());
+                mimeType.isEmpty() ? NULL : mimeType.string());
     }
 
     if (extractor == NULL) {
@@ -347,6 +344,7 @@
 
         if (!mUri.empty()) {
             const char* uri = mUri.c_str();
+            String8 contentType;
             mIsWidevine = !strncasecmp(uri, "widevine://", 11);
 
             if (!strncasecmp("http://", uri, 7)
@@ -361,7 +359,7 @@
             }
 
             mDataSource = DataSource::CreateFromURI(
-                   mHTTPService, uri, &mUriHeaders, &mContentType,
+                   mHTTPService, uri, &mUriHeaders, &contentType,
                    static_cast<HTTPBase *>(mHttpSource.get()));
         } else {
             mIsWidevine = false;
@@ -389,20 +387,8 @@
         mIsStreaming = (mIsWidevine || mCachedSource != NULL);
     }
 
-    // check initial caching status
-    status_t err = prefillCacheIfNecessary();
-    if (err != OK) {
-        if (err == -EAGAIN) {
-            (new AMessage(kWhatPrepareAsync, this))->post(200000);
-        } else {
-            ALOGE("Failed to prefill data cache!");
-            notifyPreparedAndCleanup(UNKNOWN_ERROR);
-        }
-        return;
-    }
-
-    // init extrator from data source
-    err = initFromDataSource();
+    // init extractor from data source
+    status_t err = initFromDataSource();
 
     if (err != OK) {
         ALOGE("Failed to init from data source!");
@@ -441,9 +427,6 @@
 
 void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
     if (err != OK) {
-        mMetaDataSize = -1ll;
-        mContentType = "";
-        mSniffedMIME = "";
         mDataSource.clear();
         mCachedSource.clear();
         mHttpSource.clear();
@@ -453,76 +436,6 @@
     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");
 
@@ -599,6 +512,7 @@
 void NuPlayer::GenericSource::cancelPollBuffering() {
     mBuffering = false;
     ++mPollBufferingGeneration;
+    mPrevBufferPercentage = -1;
 }
 
 void NuPlayer::GenericSource::restartPollBuffering() {
@@ -608,7 +522,19 @@
     }
 }
 
-void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) {
+void NuPlayer::GenericSource::notifyBufferingUpdate(int32_t percentage) {
+    // Buffering percent could go backward as it's estimated from remaining
+    // data and last access time. This could cause the buffering position
+    // drawn on media control to jitter slightly. Remember previously reported
+    // percentage and don't allow it to go backward.
+    if (percentage < mPrevBufferPercentage) {
+        percentage = mPrevBufferPercentage;
+    } else if (percentage > 100) {
+        percentage = 100;
+    }
+
+    mPrevBufferPercentage = percentage;
+
     ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
 
     sp<AMessage> msg = dupNotify();
@@ -888,7 +814,7 @@
               mVideoTrack.mPackets->clear();
           }
           sp<AMessage> response = new AMessage;
-          uint32_t replyID;
+          sp<AReplyToken> replyID;
           CHECK(msg->senderAwaitsResponse(&replyID));
           response->postReply(replyID);
           break;
@@ -990,7 +916,7 @@
     sp<MetaData> format = doGetFormatMeta(audio);
     response->setPointer("format", format.get());
 
-    uint32_t replyID;
+    sp<AReplyToken> replyID;
     CHECK(msg->senderAwaitsResponse(&replyID));
     response->postReply(replyID);
 }
@@ -1153,7 +1079,7 @@
     ssize_t index = doGetSelectedTrack(type);
     response->setInt32("index", index);
 
-    uint32_t replyID;
+    sp<AReplyToken> replyID;
     CHECK(msg->senderAwaitsResponse(&replyID));
     response->postReply(replyID);
 }
@@ -1211,7 +1137,7 @@
     status_t err = doSelectTrack(trackIndex, select, timeUs);
     response->setInt32("err", err);
 
-    uint32_t replyID;
+    sp<AReplyToken> replyID;
     CHECK(msg->senderAwaitsResponse(&replyID));
     response->postReply(replyID);
 }
@@ -1324,7 +1250,7 @@
     status_t err = doSeek(seekTimeUs);
     response->setInt32("err", err);
 
-    uint32_t replyID;
+    sp<AReplyToken> replyID;
     CHECK(msg->senderAwaitsResponse(&replyID));
     response->postReply(replyID);
 }
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 385d73a..5fc41ec 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -139,14 +139,13 @@
     sp<DecryptHandle> mDecryptHandle;
     bool mStarted;
     bool mStopRead;
-    String8 mContentType;
-    AString mSniffedMIME;
-    off64_t mMetaDataSize;
     int64_t mBitrate;
     int32_t mPollBufferingGeneration;
     uint32_t mPendingReadBufferTypes;
     bool mBuffering;
     bool mPrepareBuffering;
+    int32_t mPrevBufferPercentage;
+
     mutable Mutex mReadBufferLock;
 
     sp<ALooper> mLooper;
@@ -158,8 +157,6 @@
     int64_t getLastReadPosition();
     void setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position);
 
-    status_t prefillCacheIfNecessary();
-
     void notifyPreparedAndCleanup(status_t err);
 
     void onGetFormatMeta(sp<AMessage> msg) const;
@@ -200,7 +197,7 @@
     void cancelPollBuffering();
     void restartPollBuffering();
     void onPollBuffering();
-    void notifyBufferingUpdate(int percentage);
+    void notifyBufferingUpdate(int32_t percentage);
     void startBufferingIfNecessary();
     void stopBufferingIfNecessary();
     void sendCacheStats();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 007fbb9..f4d3794 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -408,7 +408,7 @@
 
         case kWhatGetTrackInfo:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             Parcel* reply;
@@ -461,7 +461,7 @@
             sp<AMessage> response = new AMessage;
             response->setInt32("err", err);
 
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
             response->postReply(replyID);
             break;
@@ -469,7 +469,7 @@
 
         case kWhatSelectTrack:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             size_t trackIndex;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 8e59b75..04ac699 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -56,6 +56,7 @@
       mIsVideoAVC(false),
       mIsSecure(false),
       mFormatChangePending(false),
+      mTimeChangePending(false),
       mPaused(true),
       mResumePending(false),
       mComponentName("decoder") {
@@ -121,6 +122,7 @@
     CHECK(mCodec == NULL);
 
     mFormatChangePending = false;
+    mTimeChangePending = false;
 
     ++mBufferGeneration;
 
@@ -235,7 +237,7 @@
     }
 }
 
-void NuPlayer::Decoder::onFlush(bool notifyComplete) {
+void NuPlayer::Decoder::doFlush(bool notifyComplete) {
     if (mCCDecoder != NULL) {
         mCCDecoder->flush();
     }
@@ -259,13 +261,22 @@
         // we attempt to release the buffers even if flush fails.
     }
     releaseAndResetMediaBuffers();
+}
 
-    if (notifyComplete) {
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatFlushCompleted);
-        notify->post();
-        mPaused = true;
+void NuPlayer::Decoder::onFlush() {
+    doFlush(true);
+
+    if (isDiscontinuityPending()) {
+        // This could happen if the client starts seeking/shutdown
+        // after we queued an EOS for discontinuities.
+        // We can consider discontinuity handled.
+        finishHandleDiscontinuity(false /* flushOnTimeChange */);
     }
+
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatFlushCompleted);
+    notify->post();
+    mPaused = true;
 }
 
 void NuPlayer::Decoder::onShutdown(bool notifyComplete) {
@@ -309,16 +320,17 @@
 }
 
 void NuPlayer::Decoder::doRequestBuffers() {
-    if (mFormatChangePending) {
+    if (isDiscontinuityPending()) {
         return;
     }
     status_t err = OK;
-    while (!mDequeuedInputBuffers.empty()) {
+    while (err == OK && !mDequeuedInputBuffers.empty()) {
         size_t bufferIx = *mDequeuedInputBuffers.begin();
         sp<AMessage> msg = new AMessage();
         msg->setSize("buffer-ix", bufferIx);
         err = fetchInputData(msg);
-        if (err != OK) {
+        if (err != OK && err != ERROR_END_OF_STREAM) {
+            // if EOS, need to queue EOS buffer
             break;
         }
         mDequeuedInputBuffers.erase(mDequeuedInputBuffers.begin());
@@ -336,7 +348,7 @@
 }
 
 bool NuPlayer::Decoder::handleAnInputBuffer() {
-    if (mFormatChangePending) {
+    if (isDiscontinuityPending()) {
         return false;
     }
     size_t bufferIx = -1;
@@ -391,9 +403,6 @@
 }
 
 bool NuPlayer::Decoder::handleAnOutputBuffer() {
-    if (mFormatChangePending) {
-        return false;
-    }
     size_t bufferIx = -1;
     size_t offset;
     size_t size;
@@ -474,17 +483,20 @@
     buffer->setRange(offset, size);
     buffer->meta()->clear();
     buffer->meta()->setInt64("timeUs", timeUs);
-    if (flags & MediaCodec::BUFFER_FLAG_EOS) {
-        buffer->meta()->setInt32("eos", true);
-        notifyResumeCompleteIfNecessary();
-    }
+
+    bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
     // we do not expect CODECCONFIG or SYNCFRAME for decoder
 
     sp<AMessage> reply = new AMessage(kWhatRenderBuffer, this);
     reply->setSize("buffer-ix", bufferIx);
     reply->setInt32("generation", mBufferGeneration);
 
-    if (mSkipRenderingUntilMediaTimeUs >= 0) {
+    if (eos) {
+        ALOGI("[%s] saw output EOS", mIsAudio ? "audio" : "video");
+
+        buffer->meta()->setInt32("eos", true);
+        reply->setInt32("eos", true);
+    } else if (mSkipRenderingUntilMediaTimeUs >= 0) {
         if (timeUs < mSkipRenderingUntilMediaTimeUs) {
             ALOGV("[%s] dropping buffer at time %lld as requested.",
                      mComponentName.c_str(), (long long)timeUs);
@@ -502,7 +514,7 @@
     if (mRenderer != NULL) {
         // send the buffer to renderer.
         mRenderer->queueBuffer(mIsAudio, buffer, reply);
-        if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+        if (eos && !isDiscontinuityPending()) {
             mRenderer->queueEOS(mIsAudio, ERROR_END_OF_STREAM);
         }
     }
@@ -533,9 +545,6 @@
 }
 
 void NuPlayer::Decoder::requestCodecNotification() {
-    if (mFormatChangePending) {
-        return;
-    }
     if (mCodec != NULL) {
         sp<AMessage> reply = new AMessage(kWhatCodecNotify, this);
         reply->setInt32("generation", mBufferGeneration);
@@ -582,39 +591,31 @@
                     formatChange = !seamlessFormatChange;
                 }
 
-                if (formatChange || timeChange) {
-                    sp<AMessage> msg = mNotify->dup();
-                    msg->setInt32("what", kWhatInputDiscontinuity);
-                    msg->setInt32("formatChange", formatChange);
-                    msg->post();
-                }
-
+                // For format or time change, return EOS to queue EOS input,
+                // then wait for EOS on output.
                 if (formatChange /* not seamless */) {
-                    // must change decoder
-                    // return EOS and wait to be killed
                     mFormatChangePending = true;
-                    return ERROR_END_OF_STREAM;
+                    err = ERROR_END_OF_STREAM;
                 } else if (timeChange) {
-                    // need to flush
-                    // TODO: Ideally we shouldn't need a flush upon time
-                    // discontinuity, flushing will cause loss of frames.
-                    // We probably should queue a time change marker to the
-                    // output queue, and handles it in renderer instead.
                     rememberCodecSpecificData(newFormat);
-                    onFlush(false /* notifyComplete */);
-                    err = OK;
+                    mTimeChangePending = true;
+                    err = ERROR_END_OF_STREAM;
                 } else if (seamlessFormatChange) {
                     // reuse existing decoder and don't flush
                     rememberCodecSpecificData(newFormat);
-                    err = OK;
+                    continue;
                 } else {
                     // This stream is unaffected by the discontinuity
                     return -EWOULDBLOCK;
                 }
             }
 
+            // reply should only be returned without a buffer set
+            // when there is an error (including EOS)
+            CHECK(err != OK);
+
             reply->setInt32("err", err);
-            return OK;
+            return ERROR_END_OF_STREAM;
         }
 
         if (!mIsAudio) {
@@ -636,7 +637,7 @@
 #if 0
     int64_t mediaTimeUs;
     CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
-    ALOGV("feeding %s input buffer at media time %.2f secs",
+    ALOGV("[%s] feeding input buffer at media time %" PRId64,
          mIsAudio ? "audio" : "video",
          mediaTimeUs / 1E6);
 #endif
@@ -696,10 +697,7 @@
         int32_t streamErr = ERROR_END_OF_STREAM;
         CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
 
-        if (streamErr == OK) {
-            /* buffers are returned to hold on to */
-            return true;
-        }
+        CHECK(streamErr != OK);
 
         // attempt to queue EOS
         status_t err = mCodec->queueInputBuffer(
@@ -781,6 +779,7 @@
     status_t err;
     int32_t render;
     size_t bufferIx;
+    int32_t eos;
     CHECK(msg->findSize("buffer-ix", &bufferIx));
 
     if (!mIsAudio) {
@@ -805,6 +804,42 @@
                 mComponentName.c_str(), err);
         handleError(err);
     }
+    if (msg->findInt32("eos", &eos) && eos
+            && isDiscontinuityPending()) {
+        finishHandleDiscontinuity(true /* flushOnTimeChange */);
+    }
+}
+
+bool NuPlayer::Decoder::isDiscontinuityPending() const {
+    return mFormatChangePending || mTimeChangePending;
+}
+
+void NuPlayer::Decoder::finishHandleDiscontinuity(bool flushOnTimeChange) {
+    ALOGV("finishHandleDiscontinuity: format %d, time %d, flush %d",
+            mFormatChangePending, mTimeChangePending, flushOnTimeChange);
+
+    // If we have format change, pause and wait to be killed;
+    // If we have time change only, flush and restart fetching.
+
+    if (mFormatChangePending) {
+        mPaused = true;
+    } else if (mTimeChangePending) {
+        if (flushOnTimeChange) {
+            doFlush(false /*notifyComplete*/);
+        }
+
+        // restart fetching input
+        scheduleRequestBuffers();
+    }
+
+    // Notify NuPlayer to either shutdown decoder, or rescan sources
+    sp<AMessage> msg = mNotify->dup();
+    msg->setInt32("what", kWhatInputDiscontinuity);
+    msg->setInt32("formatChange", mFormatChangePending);
+    msg->post();
+
+    mFormatChangePending = false;
+    mTimeChangePending = false;
 }
 
 bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 1bfa94f..4aab2c6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -43,7 +43,7 @@
     virtual void onSetRenderer(const sp<Renderer> &renderer);
     virtual void onGetInputBuffers(Vector<sp<ABuffer> > *dstBuffers);
     virtual void onResume(bool notifyComplete);
-    virtual void onFlush(bool notifyComplete);
+    virtual void onFlush();
     virtual void onShutdown(bool notifyComplete);
     virtual void doRequestBuffers();
 
@@ -81,6 +81,7 @@
     bool mIsVideoAVC;
     bool mIsSecure;
     bool mFormatChangePending;
+    bool mTimeChangePending;
 
     bool mPaused;
     bool mResumePending;
@@ -93,6 +94,7 @@
     void requestCodecNotification();
     bool isStaleReply(const sp<AMessage> &msg);
 
+    void doFlush(bool notifyComplete);
     status_t fetchInputData(sp<AMessage> &reply);
     bool onInputBufferFetched(const sp<AMessage> &msg);
     void onRenderBuffer(const sp<AMessage> &msg);
@@ -100,6 +102,8 @@
     bool supportsSeamlessFormatChange(const sp<AMessage> &to) const;
     bool supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const;
     void rememberCodecSpecificData(const sp<AMessage> &format);
+    bool isDiscontinuityPending() const;
+    void finishHandleDiscontinuity(bool flushOnTimeChange);
 
     void notifyResumeCompleteIfNecessary();
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
index 72e7b0d..4636f0a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
@@ -136,7 +136,7 @@
 
         case kWhatGetInputBuffers:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             Vector<sp<ABuffer> > *dstBuffers;
@@ -157,7 +157,7 @@
 
         case kWhatFlush:
         {
-            onFlush(true);
+            onFlush();
             break;
         }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
index 6732ff4..97e9269 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
@@ -65,7 +65,7 @@
     virtual void onSetRenderer(const sp<Renderer> &renderer) = 0;
     virtual void onGetInputBuffers(Vector<sp<ABuffer> > *dstBuffers) = 0;
     virtual void onResume(bool notifyComplete) = 0;
-    virtual void onFlush(bool notifyComplete) = 0;
+    virtual void onFlush() = 0;
     virtual void onShutdown(bool notifyComplete) = 0;
 
     void onRequestInputBuffers();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index 479eba1..29b4c26 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -247,7 +247,7 @@
                 }
 
                 if (timeChange) {
-                    onFlush(false /* notifyComplete */);
+                    doFlush(false /* notifyComplete */);
                     err = OK;
                 } else if (formatChange) {
                     // do seamless format change
@@ -364,7 +364,7 @@
     }
 }
 
-void NuPlayer::DecoderPassThrough::onFlush(bool notifyComplete) {
+void NuPlayer::DecoderPassThrough::doFlush(bool notifyComplete) {
     ++mBufferGeneration;
     mSkipRenderingUntilMediaTimeUs = -1;
     mPendingAudioAccessUnit.clear();
@@ -376,18 +376,21 @@
         mRenderer->signalTimeDiscontinuity();
     }
 
-    if (notifyComplete) {
-        mPaused = true;
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatFlushCompleted);
-        notify->post();
-    }
-
     mPendingBuffersToDrain = 0;
     mCachedBytes = 0;
     mReachedEOS = false;
 }
 
+void NuPlayer::DecoderPassThrough::onFlush() {
+    doFlush(true /* notifyComplete */);
+
+    mPaused = true;
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatFlushCompleted);
+    notify->post();
+
+}
+
 void NuPlayer::DecoderPassThrough::onShutdown(bool notifyComplete) {
     ++mBufferGeneration;
     mSkipRenderingUntilMediaTimeUs = -1;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
index a6e1faf..173cfbd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
@@ -43,7 +43,7 @@
     virtual void onSetRenderer(const sp<Renderer> &renderer);
     virtual void onGetInputBuffers(Vector<sp<ABuffer> > *dstBuffers);
     virtual void onResume(bool notifyComplete);
-    virtual void onFlush(bool notifyComplete);
+    virtual void onFlush();
     virtual void onShutdown(bool notifyComplete);
     virtual void doRequestBuffers();
 
@@ -77,6 +77,7 @@
     status_t dequeueAccessUnit(sp<ABuffer> *accessUnit);
     sp<ABuffer> aggregateBuffer(const sp<ABuffer> &accessUnit);
     status_t fetchInputData(sp<AMessage> &reply);
+    void doFlush(bool notifyComplete);
 
     void onInputBufferFetched(const sp<AMessage> &msg);
     void onBufferConsumed(int32_t size);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 337f7b1..4bccfa8 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -20,13 +20,12 @@
 
 #include "NuPlayerRenderer.h"
 
-#include "MediaClock.h"
-
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/foundation/AWakeLock.h>
+#include <media/stagefright/MediaClock.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
@@ -265,7 +264,7 @@
             response->setInt32("err", err);
             response->setInt32("offload", offloadingAudio());
 
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
             response->postReply(replyID);
 
@@ -274,7 +273,7 @@
 
         case kWhatCloseAudioSink:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             onCloseAudioSink();
@@ -716,6 +715,7 @@
     int64_t nowUs = ALooper::GetNowUs();
     int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs);
     mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs);
+    mAnchorNumFramesWritten = mNumFramesWritten;
     mAnchorTimeMediaUs = mediaTimeUs;
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 57d9ab2..5210fc8 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -311,7 +311,7 @@
 
 void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
     if (msg->what() == kWhatDisconnect) {
-        uint32_t replyID;
+        sp<AReplyToken> replyID;
         CHECK(msg->senderAwaitsResponse(&replyID));
 
         mDisconnectReplyID = replyID;
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index ac3299a..5f2cf33 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -25,6 +25,7 @@
 namespace android {
 
 struct ALooper;
+struct AReplyToken;
 struct AnotherPacketSource;
 struct MyHandler;
 struct SDPLoader;
@@ -96,7 +97,7 @@
     bool mIsSDP;
     State mState;
     status_t mFinalResult;
-    uint32_t mDisconnectReplyID;
+    sp<AReplyToken> mDisconnectReplyID;
     Mutex mBufferingLock;
     bool mBuffering;
 
diff --git a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
index a199ee1..27b482b 100644
--- a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
+++ b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
@@ -32,7 +32,12 @@
     FakeProcessInfo() {}
     virtual ~FakeProcessInfo() {}
 
-    virtual int getPriority(int pid) { return pid; }
+    virtual bool getPriority(int pid, int* priority) {
+        // For testing, use pid as priority.
+        // Lower the value higher the priority.
+        *priority = pid;
+        return true;
+    }
 
 private:
     DISALLOW_EVIL_CONSTRUCTORS(FakeProcessInfo);
@@ -57,7 +62,7 @@
     DISALLOW_EVIL_CONSTRUCTORS(FakeDrm);
 };
 
-static const int kTestPid1 = 10;
+static const int kTestPid1 = 30;
 static const int kTestPid2 = 20;
 static const uint8_t kTestSessionId1[] = {1, 2, 3};
 static const uint8_t kTestSessionId2[] = {4, 5, 6, 7, 8};
@@ -122,7 +127,9 @@
 
         EXPECT_EQ(kTestPid1, pid);
         FakeProcessInfo processInfo;
-        EXPECT_EQ(processInfo.getPriority(kTestPid1), priority);
+        int priority1;
+        processInfo.getPriority(kTestPid1, &priority1);
+        EXPECT_EQ(priority1, priority);
     }
 
     void testGetLeastUsedSession() {
@@ -210,9 +217,9 @@
     addSession();
 
     // calling pid priority is too low
-    EXPECT_FALSE(mDrmSessionManager->reclaimSession(5));
+    EXPECT_FALSE(mDrmSessionManager->reclaimSession(50));
 
-    EXPECT_TRUE(mDrmSessionManager->reclaimSession(30));
+    EXPECT_TRUE(mDrmSessionManager->reclaimSession(10));
     EXPECT_EQ(1, mTestDrm1->reclaimedSessions().size());
     EXPECT_TRUE(isEqualSessionId(mSessionId1, mTestDrm1->reclaimedSessions()[0]));
 
@@ -220,12 +227,12 @@
 
     // add a session from a higher priority process.
     sp<FakeDrm> drm = new FakeDrm;
-    const uint8_t ids[] = {456, 7890, 123};
+    const uint8_t ids[] = {1, 3, 5};
     Vector<uint8_t> sessionId;
     GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
-    mDrmSessionManager->addSession(30, drm, sessionId);
+    mDrmSessionManager->addSession(15, drm, sessionId);
 
-    EXPECT_TRUE(mDrmSessionManager->reclaimSession(40));
+    EXPECT_TRUE(mDrmSessionManager->reclaimSession(18));
     EXPECT_EQ(1, mTestDrm2->reclaimedSessions().size());
     // mSessionId2 is reclaimed.
     EXPECT_TRUE(isEqualSessionId(mSessionId2, mTestDrm2->reclaimedSessions()[0]));
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 6d9bbae..38f2e34 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -31,6 +31,7 @@
         MediaAdapter.cpp                  \
         MediaBuffer.cpp                   \
         MediaBufferGroup.cpp              \
+        MediaClock.cpp                    \
         MediaCodec.cpp                    \
         MediaCodecList.cpp                \
         MediaCodecSource.cpp              \
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
index 0c2ff15..77a652a 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libstagefright/HTTPBase.cpp
@@ -75,7 +75,11 @@
 bool HTTPBase::estimateBandwidth(int32_t *bandwidth_bps) {
     Mutex::Autolock autoLock(mLock);
 
-    if (mNumBandwidthHistoryItems < 2) {
+    // Do not do bandwidth estimation if we don't have enough samples, or
+    // total bytes download are too small (<64K).
+    // Bandwidth estimation from these samples can often shoot up and cause
+    // unwanted bw adaption behaviors.
+    if (mNumBandwidthHistoryItems < 2 || mTotalTransferBytes < 65536) {
         return false;
     }
 
diff --git a/media/libmediaplayerservice/nuplayer/MediaClock.cpp b/media/libstagefright/MediaClock.cpp
similarity index 98%
rename from media/libmediaplayerservice/nuplayer/MediaClock.cpp
rename to media/libstagefright/MediaClock.cpp
index 9152da1..38db5e4 100644
--- a/media/libmediaplayerservice/nuplayer/MediaClock.cpp
+++ b/media/libstagefright/MediaClock.cpp
@@ -18,7 +18,7 @@
 #define LOG_TAG "MediaClock"
 #include <utils/Log.h>
 
-#include "MediaClock.h"
+#include <media/stagefright/MediaClock.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 6282813..0597f1d 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -174,7 +174,7 @@
 }
 
 // static
-void MediaCodec::PostReplyWithError(int32_t replyID, int32_t err) {
+void MediaCodec::PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err) {
     sp<AMessage> response = new AMessage;
     response->setInt32("err", err);
     response->postReply(replyID);
@@ -650,7 +650,7 @@
     }
 }
 
-bool MediaCodec::handleDequeueInputBuffer(uint32_t replyID, bool newRequest) {
+bool MediaCodec::handleDequeueInputBuffer(const sp<AReplyToken> &replyID, bool newRequest) {
     if (!isExecuting() || (mFlags & kFlagIsAsync)
             || (newRequest && (mFlags & kFlagDequeueInputPending))) {
         PostReplyWithError(replyID, INVALID_OPERATION);
@@ -674,7 +674,7 @@
     return true;
 }
 
-bool MediaCodec::handleDequeueOutputBuffer(uint32_t replyID, bool newRequest) {
+bool MediaCodec::handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool newRequest) {
     sp<AMessage> response = new AMessage;
 
     if (!isExecuting() || (mFlags & kFlagIsAsync)
@@ -1198,7 +1198,7 @@
 
         case kWhatInit:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             if (mState != UNINITIALIZED) {
@@ -1234,7 +1234,7 @@
 
         case kWhatSetCallback:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             if (mState == UNINITIALIZED
@@ -1266,7 +1266,7 @@
 
         case kWhatConfigure:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             if (mState != INITIALIZED) {
@@ -1323,7 +1323,7 @@
 
         case kWhatCreateInputSurface:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             // Must be configured, but can't have been started yet.
@@ -1339,7 +1339,7 @@
 
         case kWhatStart:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             if (mState == FLUSHED) {
@@ -1365,7 +1365,7 @@
             State targetState =
                 (msg->what() == kWhatStop) ? INITIALIZED : UNINITIALIZED;
 
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             if (!((mFlags & kFlagIsComponentAllocated) && targetState == UNINITIALIZED) // See 1
@@ -1413,7 +1413,7 @@
 
         case kWhatDequeueInputBuffer:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             if (mFlags & kFlagIsAsync) {
@@ -1474,7 +1474,7 @@
 
         case kWhatQueueInputBuffer:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             if (!isExecuting()) {
@@ -1493,7 +1493,7 @@
 
         case kWhatDequeueOutputBuffer:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             if (mFlags & kFlagIsAsync) {
@@ -1548,7 +1548,7 @@
 
         case kWhatReleaseOutputBuffer:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             if (!isExecuting()) {
@@ -1567,7 +1567,7 @@
 
         case kWhatSignalEndOfInputStream:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             if (!isExecuting()) {
@@ -1585,7 +1585,7 @@
 
         case kWhatGetBuffers:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             if (!isExecuting() || (mFlags & kFlagIsAsync)) {
@@ -1619,7 +1619,7 @@
 
         case kWhatFlush:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             if (!isExecuting()) {
@@ -1645,7 +1645,7 @@
             sp<AMessage> format =
                 (msg->what() == kWhatGetOutputFormat ? mOutputFormat : mInputFormat);
 
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             if ((mState != CONFIGURED && mState != STARTING &&
@@ -1682,7 +1682,7 @@
 
         case kWhatGetName:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             if (mComponentName.empty()) {
@@ -1698,7 +1698,7 @@
 
         case kWhatSetParameters:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             sp<AMessage> params;
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 1ef4170..b6fa810 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -182,7 +182,7 @@
             sp<AMessage> response = new AMessage;
             response->setInt32("err", err);
 
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
             response->postReply(replyID);
             break;
@@ -491,7 +491,7 @@
     if (mStopping && mEncoderReachedEOS) {
         ALOGI("encoder (%s) stopped", mIsVideo ? "video" : "audio");
         // posting reply to everyone that's waiting
-        List<uint32_t>::iterator it;
+        List<sp<AReplyToken>>::iterator it;
         for (it = mStopReplyIDQueue.begin();
                 it != mStopReplyIDQueue.end(); it++) {
             (new AMessage)->postReply(*it);
@@ -766,7 +766,7 @@
     }
     case kWhatStart:
     {
-        uint32_t replyID;
+        sp<AReplyToken> replyID;
         CHECK(msg->senderAwaitsResponse(&replyID));
 
         sp<RefBase> obj;
@@ -782,7 +782,7 @@
     {
         ALOGI("encoder (%s) stopping", mIsVideo ? "video" : "audio");
 
-        uint32_t replyID;
+        sp<AReplyToken> replyID;
         CHECK(msg->senderAwaitsResponse(&replyID));
 
         if (mEncoderReachedEOS) {
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 1505f08..10937ec 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -975,6 +975,7 @@
         mBufferSizes.clear();
         mDecodedSizes.clear();
         mLastInHeader = NULL;
+        mEndOfInput = false;
     } else {
         int avail;
         while ((avail = outputDelayRingBufferSamplesAvailable()) > 0) {
@@ -989,6 +990,7 @@
             mOutputBufferCount++;
         }
         mOutputDelayRingBufferReadPos = mOutputDelayRingBufferWritePos;
+        mEndOfOutput = false;
     }
 }
 
diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp
index 617d32b..90b5f68 100644
--- a/media/libstagefright/foundation/ALooper.cpp
+++ b/media/libstagefright/foundation/ALooper.cpp
@@ -16,6 +16,9 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "ALooper"
+
+#include <media/stagefright/foundation/ADebug.h>
+
 #include <utils/Log.h>
 
 #include <sys/time.h>
@@ -220,4 +223,29 @@
     return true;
 }
 
+// to be called by AMessage::postAndAwaitResponse only
+sp<AReplyToken> ALooper::createReplyToken() {
+    return new AReplyToken(this);
+}
+
+// to be called by AMessage::postAndAwaitResponse only
+status_t ALooper::awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response) {
+    // return status in case we want to handle an interrupted wait
+    Mutex::Autolock autoLock(mRepliesLock);
+    CHECK(replyToken != NULL);
+    while (!replyToken->retrieveReply(response)) {
+        mRepliesCondition.wait(mRepliesLock);
+    }
+    return OK;
+}
+
+status_t ALooper::postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &reply) {
+    Mutex::Autolock autoLock(mRepliesLock);
+    status_t err = replyToken->setReply(reply);
+    if (err == OK) {
+        mRepliesCondition.broadcast();
+    }
+    return err;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp
index c4e6788..473ce1b 100644
--- a/media/libstagefright/foundation/ALooperRoster.cpp
+++ b/media/libstagefright/foundation/ALooperRoster.cpp
@@ -30,8 +30,7 @@
 static bool verboseStats = false;
 
 ALooperRoster::ALooperRoster()
-    : mNextHandlerID(1),
-      mNextReplyID(1) {
+    : mNextHandlerID(1) {
 }
 
 ALooper::handler_id ALooperRoster::registerHandler(
@@ -100,39 +99,6 @@
     }
 }
 
-status_t ALooperRoster::postAndAwaitResponse(
-        const sp<AMessage> &msg, sp<AMessage> *response) {
-    Mutex::Autolock autoLock(mLock);
-
-    uint32_t replyID = mNextReplyID++;
-
-    msg->setInt32("replyID", replyID);
-
-    status_t err = msg->post(0 /* delayUs */);
-    if (err != OK) {
-        response->clear();
-        return err;
-    }
-
-    ssize_t index;
-    while ((index = mReplies.indexOfKey(replyID)) < 0) {
-        mRepliesCondition.wait(mLock);
-    }
-
-    *response = mReplies.valueAt(index);
-    mReplies.removeItemsAt(index);
-
-    return OK;
-}
-
-void ALooperRoster::postReply(uint32_t replyID, const sp<AMessage> &reply) {
-    Mutex::Autolock autoLock(mLock);
-
-    CHECK(mReplies.indexOfKey(replyID) < 0);
-    mReplies.add(replyID, reply);
-    mRepliesCondition.broadcast();
-}
-
 static void makeFourCC(uint32_t fourcc, char *s) {
     s[0] = (fourcc >> 24) & 0xff;
     if (s[0]) {
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index d4add15..e549ff6 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -37,6 +37,17 @@
 
 extern ALooperRoster gLooperRoster;
 
+status_t AReplyToken::setReply(const sp<AMessage> &reply) {
+    if (mReplied) {
+        ALOGE("trying to post a duplicate reply");
+        return -EBUSY;
+    }
+    CHECK(mReply == NULL);
+    mReply = reply;
+    mReplied = true;
+    return OK;
+}
+
 AMessage::AMessage(void)
     : mWhat(0),
       mTarget(0),
@@ -355,24 +366,50 @@
 }
 
 status_t AMessage::postAndAwaitResponse(sp<AMessage> *response) {
-    return gLooperRoster.postAndAwaitResponse(this, response);
+    sp<ALooper> looper = mLooper.promote();
+    if (looper == NULL) {
+        ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
+        return -ENOENT;
+    }
+
+    sp<AReplyToken> token = looper->createReplyToken();
+    if (token == NULL) {
+        ALOGE("failed to create reply token");
+        return -ENOMEM;
+    }
+    setObject("replyID", token);
+
+    looper->post(this, 0 /* delayUs */);
+    return looper->awaitResponse(token, response);
 }
 
-void AMessage::postReply(uint32_t replyID) {
-    gLooperRoster.postReply(replyID, this);
+status_t AMessage::postReply(const sp<AReplyToken> &replyToken) {
+    if (replyToken == NULL) {
+        ALOGW("failed to post reply to a NULL token");
+        return -ENOENT;
+    }
+    sp<ALooper> looper = replyToken->getLooper();
+    if (looper == NULL) {
+        ALOGW("failed to post reply as target looper is gone.");
+        return -ENOENT;
+    }
+    return looper->postReply(replyToken, this);
 }
 
-bool AMessage::senderAwaitsResponse(uint32_t *replyID) const {
-    int32_t tmp;
-    bool found = findInt32("replyID", &tmp);
+bool AMessage::senderAwaitsResponse(sp<AReplyToken> *replyToken) {
+    sp<RefBase> tmp;
+    bool found = findObject("replyID", &tmp);
 
     if (!found) {
         return false;
     }
 
-    *replyID = static_cast<uint32_t>(tmp);
+    *replyToken = static_cast<AReplyToken *>(tmp.get());
+    tmp.clear();
+    setObject("replyID", tmp);
+    // TODO: delete Object instead of setting it to NULL
 
-    return true;
+    return *replyToken != NULL;
 }
 
 sp<AMessage> AMessage::dup() const {
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index dcac765..a8f60a8 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -49,8 +49,13 @@
 
 namespace android {
 
+// static
 // Number of recently-read bytes to use for bandwidth estimation
 const size_t LiveSession::kBandwidthHistoryBytes = 200 * 1024;
+// High water mark to start up switch or report prepared)
+const int64_t LiveSession::kHighWaterMark = 8000000ll;
+const int64_t LiveSession::kMidWaterMark = 5000000ll;
+const int64_t LiveSession::kLowWaterMark = 3000000ll;
 
 LiveSession::LiveSession(
         const sp<AMessage> &notify, uint32_t flags,
@@ -75,14 +80,14 @@
       mSeekReplyID(0),
       mFirstTimeUsValid(false),
       mFirstTimeUs(0),
-      mLastSeekTimeUs(0) {
+      mLastSeekTimeUs(0),
+      mPollBufferingGeneration(0) {
 
     mStreams[kAudioIndex] = StreamItem("audio");
     mStreams[kVideoIndex] = StreamItem("video");
     mStreams[kSubtitleIndex] = StreamItem("subtitles");
 
     for (size_t i = 0; i < kMaxStreams; ++i) {
-        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;
@@ -97,6 +102,9 @@
 }
 
 LiveSession::~LiveSession() {
+    if (mFetcherLooper != NULL) {
+        mFetcherLooper->stop();
+    }
 }
 
 sp<ABuffer> LiveSession::createFormatChangeBuffer(bool swap) {
@@ -125,24 +133,7 @@
         return -EWOULDBLOCK;
     }
 
-    status_t finalResult;
-    sp<AnotherPacketSource> discontinuityQueue  = mDiscontinuities.valueFor(stream);
-    if (discontinuityQueue->hasBufferAvailable(&finalResult)) {
-        discontinuityQueue->dequeueAccessUnit(accessUnit);
-        // seeking, track switching
-        sp<AMessage> extra;
-        int64_t timeUs;
-        if ((*accessUnit)->meta()->findMessage("extra", &extra)
-                && extra != NULL
-                && extra->findInt64("timeUs", &timeUs)) {
-            // seeking only
-            mLastSeekTimeUs = timeUs;
-            mDiscontinuityOffsetTimesUs.clear();
-            mDiscontinuityAbsStartTimesUs.clear();
-        }
-        return INFO_DISCONTINUITY;
-    }
-
+    status_t finalResult = OK;
     sp<AnotherPacketSource> packetSource = mPacketSources.valueFor(stream);
 
     ssize_t idx = typeToIndex(stream);
@@ -172,7 +163,7 @@
     if (mBuffering[idx]) {
         if (mSwitchInProgress
                 || packetSource->isFinished(0)
-                || packetSource->getEstimatedDurationUs() > targetDurationUs) {
+                || packetSource->hasBufferAvailable(&finalResult)) {
             mBuffering[idx] = false;
         }
     }
@@ -402,7 +393,7 @@
 
         case kWhatSeek:
         {
-            uint32_t seekReplyID;
+            sp<AReplyToken> seekReplyID;
             CHECK(msg->senderAwaitsResponse(&seekReplyID));
             mSeekReplyID = seekReplyID;
             mSeekReply = new AMessage;
@@ -429,11 +420,16 @@
                     if (what == PlaylistFetcher::kWhatStopped) {
                         AString uri;
                         CHECK(msg->findString("uri", &uri));
-                        if (mFetcherInfos.removeItem(uri) < 0) {
+                        ssize_t index = mFetcherInfos.indexOfKey(uri);
+                        if (index < 0) {
                             // ignore duplicated kWhatStopped messages.
                             break;
                         }
 
+                        mFetcherLooper->unregisterHandler(
+                                mFetcherInfos[index].mFetcher->id());
+                        mFetcherInfos.removeItemsAt(index);
+
                         if (mSwitchInProgress) {
                             tryToFinishBandwidthSwitch();
                         }
@@ -443,14 +439,6 @@
                         CHECK_GT(mContinuationCounter, 0);
                         if (--mContinuationCounter == 0) {
                             mContinuation->post();
-
-                            if (mSeekReplyID != 0) {
-                                CHECK(mSeekReply != NULL);
-                                mSeekReply->setInt32("err", OK);
-                                mSeekReply->postReply(mSeekReplyID);
-                                mSeekReplyID = 0;
-                                mSeekReply.clear();
-                            }
                         }
                     }
                     break;
@@ -464,8 +452,11 @@
                     int64_t durationUs;
                     CHECK(msg->findInt64("durationUs", &durationUs));
 
-                    FetcherInfo *info = &mFetcherInfos.editValueFor(uri);
-                    info->mDurationUs = durationUs;
+                    ssize_t index = mFetcherInfos.indexOfKey(uri);
+                    if (index >= 0) {
+                        FetcherInfo *info = &mFetcherInfos.editValueFor(uri);
+                        info->mDurationUs = durationUs;
+                    }
                     break;
                 }
 
@@ -513,34 +504,6 @@
                     break;
                 }
 
-                case PlaylistFetcher::kWhatTemporarilyDoneFetching:
-                {
-                    AString uri;
-                    CHECK(msg->findString("uri", &uri));
-
-                    if (mFetcherInfos.indexOfKey(uri) < 0) {
-                        ALOGE("couldn't find uri");
-                        break;
-                    }
-                    FetcherInfo *info = &mFetcherInfos.editValueFor(uri);
-                    info->mIsPrepared = true;
-
-                    if (mInPreparationPhase) {
-                        bool allFetchersPrepared = true;
-                        for (size_t i = 0; i < mFetcherInfos.size(); ++i) {
-                            if (!mFetcherInfos.valueAt(i).mIsPrepared) {
-                                allFetchersPrepared = false;
-                                break;
-                            }
-                        }
-
-                        if (allFetchersPrepared) {
-                            postPrepared(OK);
-                        }
-                    }
-                    break;
-                }
-
                 case PlaylistFetcher::kWhatStartedAt:
                 {
                     int32_t switchGeneration;
@@ -569,19 +532,6 @@
             break;
         }
 
-        case kWhatCheckBandwidth:
-        {
-            int32_t generation;
-            CHECK(msg->findInt32("generation", &generation));
-
-            if (generation != mCheckBandwidthGeneration) {
-                break;
-            }
-
-            onCheckBandwidth(msg);
-            break;
-        }
-
         case kWhatChangeConfiguration:
         {
             onChangeConfiguration(msg);
@@ -612,15 +562,13 @@
             break;
         }
 
-        case kWhatCheckSwitchDown:
+        case kWhatPollBuffering:
         {
-            onCheckSwitchDown();
-            break;
-        }
-
-        case kWhatSwitchDown:
-        {
-            onSwitchDown();
+            int32_t generation;
+            CHECK(msg->findInt32("generation", &generation));
+            if (generation == mPollBufferingGeneration) {
+                onPollBuffering();
+            }
             break;
         }
 
@@ -691,6 +639,14 @@
         return;
     }
 
+    // create looper for fetchers
+    if (mFetcherLooper == NULL) {
+        mFetcherLooper = new ALooper();
+
+        mFetcherLooper->setName("Fetcher");
+        mFetcherLooper->start(false, false);
+    }
+
     // We trust the content provider to make a reasonable choice of preferred
     // initial bandwidth by listing it first in the variant playlist.
     // At startup we really don't have a good estimate on the available
@@ -739,19 +695,20 @@
     mPlaylist->pickRandomMediaItems();
     changeConfiguration(
             0ll /* timeUs */, initialBandwidthIndex, false /* pickTrack */);
+
+    schedulePollBuffering();
 }
 
 void LiveSession::finishDisconnect() {
     // No reconfiguration is currently pending, make sure none will trigger
     // during disconnection either.
-    cancelCheckBandwidthEvent();
 
     // Protect mPacketSources from a swapPacketSource race condition through disconnect.
     // (finishDisconnect, onFinishDisconnect2)
     cancelBandwidthSwitch();
 
-    // cancel switch down monitor
-    mSwitchDownMonitor.clear();
+    // cancel buffer polling
+    cancelPollBuffering();
 
     for (size_t i = 0; i < mFetcherInfos.size(); ++i) {
         mFetcherInfos.valueAt(i).mFetcher->stopAsync();
@@ -799,7 +756,7 @@
     info.mDurationUs = -1ll;
     info.mIsPrepared = false;
     info.mToBeRemoved = false;
-    looper()->registerHandler(info.mFetcher);
+    mFetcherLooper->registerHandler(info.mFetcher);
 
     mFetcherInfos.add(uri, info);
 
@@ -1201,19 +1158,6 @@
     }
 }
 
-bool LiveSession::canSwitchUp() {
-    // Allow upwards bandwidth switch when a stream has buffered at least 10 seconds.
-    status_t err = OK;
-    for (size_t i = 0; i < mPacketSources.size(); ++i) {
-        sp<AnotherPacketSource> source = mPacketSources.valueAt(i);
-        int64_t dur = source->getBufferedDurationUs(&err);
-        if (err == OK && dur > 10000000) {
-            return true;
-        }
-    }
-    return false;
-}
-
 void LiveSession::changeConfiguration(
         int64_t timeUs, size_t bandwidthIndex, bool pickTrack) {
     // Protect mPacketSources from a swapPacketSource race condition through reconfiguration.
@@ -1296,14 +1240,6 @@
 
     if (mContinuationCounter == 0) {
         msg->post();
-
-        if (mSeekReplyID != 0) {
-            CHECK(mSeekReply != NULL);
-            mSeekReply->setInt32("err", OK);
-            mSeekReply->postReply(mSeekReplyID);
-            mSeekReplyID = 0;
-            mSeekReply.clear();
-        }
     }
 }
 
@@ -1323,6 +1259,30 @@
 
     // All fetchers are either suspended or have been removed now.
 
+    // If we're seeking, clear all packet sources before we report
+    // seek complete, to prevent decoder from pulling stale data.
+    int64_t timeUs;
+    CHECK(msg->findInt64("timeUs", &timeUs));
+
+    if (timeUs >= 0) {
+        mLastSeekTimeUs = timeUs;
+
+        for (size_t i = 0; i < mPacketSources.size(); i++) {
+            mPacketSources.editValueAt(i)->clear();
+        }
+
+        mDiscontinuityOffsetTimesUs.clear();
+        mDiscontinuityAbsStartTimesUs.clear();
+
+        if (mSeekReplyID != 0) {
+            CHECK(mSeekReply != NULL);
+            mSeekReply->setInt32("err", OK);
+            mSeekReply->postReply(mSeekReplyID);
+            mSeekReplyID = 0;
+            mSeekReply.clear();
+        }
+    }
+
     uint32_t streamMask, resumeMask;
     CHECK(msg->findInt32("streamMask", (int32_t *)&streamMask));
     CHECK(msg->findInt32("resumeMask", (int32_t *)&resumeMask));
@@ -1428,19 +1388,8 @@
         for (size_t j = 0; j < kMaxStreams; ++j) {
             if ((resumeMask & indexToType(j)) && uri == mStreams[j].mUri) {
                 sources[j] = mPacketSources.valueFor(indexToType(j));
-
-                if (j != kSubtitleIndex) {
-                    ALOGV("queueing dummy discontinuity for stream type %d", indexToType(j));
-                    sp<AnotherPacketSource> discontinuityQueue;
-                    discontinuityQueue = mDiscontinuities.valueFor(indexToType(j));
-                    discontinuityQueue->queueDiscontinuity(
-                            ATSParser::DISCONTINUITY_NONE,
-                            NULL,
-                            true);
-                }
             }
         }
-
         FetcherInfo &info = mFetcherInfos.editValueAt(i);
         if (sources[kAudioIndex] != NULL || sources[kVideoIndex] != NULL
                 || sources[kSubtitleIndex] != NULL) {
@@ -1486,15 +1435,7 @@
                 sources[j] = mPacketSources.valueFor(indexToType(j));
 
                 if (timeUs >= 0) {
-                    sources[j]->clear();
                     startTimeUs = timeUs;
-
-                    sp<AnotherPacketSource> discontinuityQueue;
-                    sp<AMessage> extra = new AMessage;
-                    extra->setInt64("timeUs", timeUs);
-                    discontinuityQueue = mDiscontinuities.valueFor(indexToType(j));
-                    discontinuityQueue->queueDiscontinuity(
-                            ATSParser::DISCONTINUITY_TIME, extra, true);
                 } else {
                     int32_t type;
                     sp<AMessage> meta;
@@ -1532,9 +1473,10 @@
                         if (j == kSubtitleIndex) {
                             break;
                         }
-                        sp<AnotherPacketSource> discontinuityQueue;
-                        discontinuityQueue = mDiscontinuities.valueFor(indexToType(j));
-                        discontinuityQueue->queueDiscontinuity(
+
+                        ALOGV("stream[%d]: queue format change", j);
+
+                        sources[j]->queueDiscontinuity(
                                 ATSParser::DISCONTINUITY_FORMATCHANGE, NULL, true);
                     } else {
                         // adapting, queue discontinuities after resume
@@ -1564,9 +1506,6 @@
     // All fetchers have now been started, the configuration change
     // has completed.
 
-    cancelCheckBandwidthEvent();
-    scheduleCheckBandwidthEvent();
-
     ALOGV("XXX configuration change completed.");
     mReconfigurationInProgress = false;
     if (switching) {
@@ -1623,47 +1562,35 @@
     tryToFinishBandwidthSwitch();
 }
 
-void LiveSession::onCheckSwitchDown() {
-    if (mSwitchDownMonitor == NULL) {
-        return;
-    }
+void LiveSession::schedulePollBuffering() {
+    sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
+    msg->setInt32("generation", mPollBufferingGeneration);
+    msg->post(1000000ll);
+}
 
-    if (mSwitchInProgress || mReconfigurationInProgress) {
-        ALOGV("Switch/Reconfig in progress, defer switch down");
-        mSwitchDownMonitor->post(1000000ll);
-        return;
-    }
+void LiveSession::cancelPollBuffering() {
+    ++mPollBufferingGeneration;
+}
 
-    for (size_t i = 0; i < kMaxStreams; ++i) {
-        int32_t targetDuration;
-        sp<AnotherPacketSource> packetSource = mPacketSources.valueFor(indexToType(i));
-        sp<AMessage> meta = packetSource->getLatestDequeuedMeta();
+void LiveSession::onPollBuffering() {
+    ALOGV("onPollBuffering: mSwitchInProgress %d, mReconfigurationInProgress %d, "
+            "mInPreparationPhase %d, mStreamMask 0x%x",
+        mSwitchInProgress, mReconfigurationInProgress,
+        mInPreparationPhase, mStreamMask);
 
-        if (meta != NULL && meta->findInt32("targetDuration", &targetDuration) ) {
-            int64_t bufferedDurationUs = packetSource->getEstimatedDurationUs();
-            int64_t targetDurationUs = targetDuration * 1000000ll;
+    bool low, mid, high;
+    if (checkBuffering(low, mid, high)) {
+        if (mInPreparationPhase && mid) {
+            postPrepared(OK);
+        }
 
-            if (bufferedDurationUs < targetDurationUs / 3) {
-                (new AMessage(kWhatSwitchDown, this))->post();
-                break;
-            }
+        // don't switch before we report prepared
+        if (!mInPreparationPhase && (low || high)) {
+            switchBandwidthIfNeeded(high);
         }
     }
 
-    mSwitchDownMonitor->post(1000000ll);
-}
-
-void LiveSession::onSwitchDown() {
-    if (mReconfigurationInProgress || mSwitchInProgress || mCurBandwidthIndex == 0) {
-        return;
-    }
-
-    ssize_t bandwidthIndex = getBandwidthIndex();
-    if (bandwidthIndex < mCurBandwidthIndex) {
-        changeConfiguration(-1, bandwidthIndex, false);
-        return;
-    }
-
+    schedulePollBuffering();
 }
 
 // Mark switch done when:
@@ -1688,16 +1615,6 @@
     }
 }
 
-void LiveSession::scheduleCheckBandwidthEvent() {
-    sp<AMessage> msg = new AMessage(kWhatCheckBandwidth, this);
-    msg->setInt32("generation", mCheckBandwidthGeneration);
-    msg->post(10000000ll);
-}
-
-void LiveSession::cancelCheckBandwidthEvent() {
-    ++mCheckBandwidthGeneration;
-}
-
 void LiveSession::cancelBandwidthSwitch() {
     Mutex::Autolock lock(mSwapMutex);
     mSwitchGeneration++;
@@ -1727,33 +1644,69 @@
     }
 }
 
-bool LiveSession::canSwitchBandwidthTo(size_t bandwidthIndex) {
-    if (mReconfigurationInProgress || mSwitchInProgress) {
+bool LiveSession::checkBuffering(bool &low, bool &mid, bool &high) {
+    low = mid = high = false;
+
+    if (mSwitchInProgress || mReconfigurationInProgress) {
+        ALOGV("Switch/Reconfig in progress, defer buffer polling");
         return false;
     }
 
-    if (mCurBandwidthIndex < 0) {
+    // TODO: Fine tune low/high mark.
+    //       We also need to pause playback if buffering is too low.
+    //       Currently during underflow, we depend on decoder to starve
+    //       to pause, but A/V could have different buffering left,
+    //       they're not paused together.
+    // TODO: Report buffering level to NuPlayer for BUFFERING_UPDATE
+
+    // Switch down if any of the fetchers are below low mark;
+    // Switch up   if all of the fetchers are over high mark.
+    size_t activeCount, lowCount, midCount, highCount;
+    activeCount = lowCount = midCount = highCount = 0;
+    for (size_t i = 0; i < mPacketSources.size(); ++i) {
+        // we don't check subtitles for buffering level
+        if (!(mStreamMask & mPacketSources.keyAt(i)
+                & (STREAMTYPE_AUDIO | STREAMTYPE_VIDEO))) {
+            continue;
+        }
+        // ignore streams that never had any packet queued.
+        // (it's possible that the variant only has audio or video)
+        sp<AMessage> meta = mPacketSources[i]->getLatestEnqueuedMeta();
+        if (meta == NULL) {
+            continue;
+        }
+
+        ++activeCount;
+        int64_t bufferedDurationUs =
+                mPacketSources[i]->getEstimatedDurationUs();
+        ALOGV("source[%d]: buffered %lld us", i, bufferedDurationUs);
+        if (bufferedDurationUs < kLowWaterMark) {
+            ++lowCount;
+            break;
+        } else if (bufferedDurationUs > kHighWaterMark) {
+            ++midCount;
+            ++highCount;
+        } else if (bufferedDurationUs > kMidWaterMark) {
+            ++midCount;
+        }
+    }
+
+    if (activeCount > 0) {
+        high = (highCount == activeCount);
+        mid = (midCount == activeCount);
+        low = (lowCount > 0);
         return true;
     }
 
-    if (bandwidthIndex == (size_t)mCurBandwidthIndex) {
-        return false;
-    } else if (bandwidthIndex > (size_t)mCurBandwidthIndex) {
-        return canSwitchUp();
-    } else {
-        return true;
-    }
+    return false;
 }
 
-void LiveSession::onCheckBandwidth(const sp<AMessage> &msg) {
-    size_t bandwidthIndex = getBandwidthIndex();
-    if (canSwitchBandwidthTo(bandwidthIndex)) {
-        changeConfiguration(-1ll /* timeUs */, bandwidthIndex);
-    } else {
-        // Come back and check again 10 seconds later in case there is nothing to do now.
-        // If we DO change configuration, once that completes it'll schedule a new
-        // check bandwidth event with an incremented mCheckBandwidthGeneration.
-        msg->post(10000000ll);
+void LiveSession::switchBandwidthIfNeeded(bool canSwitchUp) {
+    ssize_t bandwidthIndex = getBandwidthIndex();
+
+    if ((canSwitchUp && bandwidthIndex > mCurBandwidthIndex)
+            || (!canSwitchUp && bandwidthIndex < mCurBandwidthIndex)) {
+        changeConfiguration(-1, bandwidthIndex, false);
     }
 }
 
@@ -1771,10 +1724,8 @@
     notify->post();
 
     mInPreparationPhase = false;
-
-    mSwitchDownMonitor = new AMessage(kWhatCheckSwitchDown, this);
-    mSwitchDownMonitor->post();
 }
 
+
 }  // namespace android
 
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index 2d3a25a..3b0a9a4 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -26,6 +26,7 @@
 namespace android {
 
 struct ABuffer;
+struct AReplyToken;
 struct AnotherPacketSource;
 struct DataSource;
 struct HTTPBase;
@@ -39,10 +40,6 @@
         // Don't log any URLs.
         kFlagIncognito = 1,
     };
-    LiveSession(
-            const sp<AMessage> &notify,
-            uint32_t flags,
-            const sp<IMediaHTTPService> &httpService);
 
     enum StreamIndex {
         kAudioIndex    = 0,
@@ -56,6 +53,12 @@
         STREAMTYPE_VIDEO        = 1 << kVideoIndex,
         STREAMTYPE_SUBTITLES    = 1 << kSubtitleIndex,
     };
+
+    LiveSession(
+            const sp<AMessage> &notify,
+            uint32_t flags,
+            const sp<IMediaHTTPService> &httpService);
+
     status_t dequeueAccessUnit(StreamType stream, sp<ABuffer> *accessUnit);
 
     status_t getStreamFormat(StreamType stream, sp<AMessage> *format);
@@ -109,11 +112,13 @@
         kWhatChangeConfiguration3       = 'chC3',
         kWhatFinishDisconnect2          = 'fin2',
         kWhatSwapped                    = 'swap',
-        kWhatCheckSwitchDown            = 'ckSD',
-        kWhatSwitchDown                 = 'sDwn',
+        kWhatPollBuffering              = 'poll',
     };
 
     static const size_t kBandwidthHistoryBytes;
+    static const int64_t kHighWaterMark;
+    static const int64_t kMidWaterMark;
+    static const int64_t kLowWaterMark;
 
     struct BandwidthItem {
         size_t mPlaylistIndex;
@@ -168,6 +173,7 @@
 
     sp<M3UParser> mPlaylist;
 
+    sp<ALooper> mFetcherLooper;
     KeyedVector<AString, FetcherInfo> mFetcherInfos;
     uint32_t mStreamMask;
 
@@ -180,7 +186,6 @@
     // we use this to track reconfiguration progress.
     uint32_t mSwapMask;
 
-    KeyedVector<StreamType, sp<AnotherPacketSource> > mDiscontinuities;
     KeyedVector<StreamType, sp<AnotherPacketSource> > mPacketSources;
     // A second set of packet sources that buffer content for the variant we're switching to.
     KeyedVector<StreamType, sp<AnotherPacketSource> > mPacketSources2;
@@ -203,16 +208,17 @@
 
     bool mReconfigurationInProgress;
     bool mSwitchInProgress;
-    uint32_t mDisconnectReplyID;
-    uint32_t mSeekReplyID;
+    sp<AReplyToken> mDisconnectReplyID;
+    sp<AReplyToken> mSeekReplyID;
 
     bool mFirstTimeUsValid;
     int64_t mFirstTimeUs;
     int64_t mLastSeekTimeUs;
-    sp<AMessage> mSwitchDownMonitor;
     KeyedVector<size_t, int64_t> mDiscontinuityAbsStartTimesUs;
     KeyedVector<size_t, int64_t> mDiscontinuityOffsetTimesUs;
 
+    int32_t mPollBufferingGeneration;
+
     sp<PlaylistFetcher> addFetcher(const char *uri);
 
     void onConnect(const sp<AMessage> &msg);
@@ -256,27 +262,24 @@
     void onChangeConfiguration2(const sp<AMessage> &msg);
     void onChangeConfiguration3(const sp<AMessage> &msg);
     void onSwapped(const sp<AMessage> &msg);
-    void onCheckSwitchDown();
-    void onSwitchDown();
     void tryToFinishBandwidthSwitch();
 
-    void scheduleCheckBandwidthEvent();
-    void cancelCheckBandwidthEvent();
-
     // cancelBandwidthSwitch is atomic wrt swapPacketSource; call it to prevent packet sources
     // from being swapped out on stale discontinuities while manipulating
     // mPacketSources/mPacketSources2.
     void cancelBandwidthSwitch();
 
-    bool canSwitchBandwidthTo(size_t bandwidthIndex);
-    void onCheckBandwidth(const sp<AMessage> &msg);
+    void schedulePollBuffering();
+    void cancelPollBuffering();
+    void onPollBuffering();
+    bool checkBuffering(bool &low, bool &mid, bool &high);
+    void switchBandwidthIfNeeded(bool canSwitchUp);
 
     void finishDisconnect();
 
     void postPrepared(status_t err);
 
     void swapPacketSource(StreamType stream);
-    bool canSwitchUp();
 
     DISALLOW_EVIL_CONSTRUCTORS(LiveSession);
 };
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 4ccbf76..3710686 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -49,6 +49,7 @@
 // static
 const int64_t PlaylistFetcher::kMinBufferedDurationUs = 10000000ll;
 const int64_t PlaylistFetcher::kMaxMonitorDelayUs = 3000000ll;
+const int64_t PlaylistFetcher::kFetcherResumeThreshold = 100000ll;
 // LCM of 188 (size of a TS packet) & 1k works well
 const int32_t PlaylistFetcher::kDownloadBlockSize = 47 * 1024;
 const int32_t PlaylistFetcher::kNumSkipFrames = 5;
@@ -535,12 +536,19 @@
     sp<AMessage> params;
     CHECK(msg->findMessage("params", &params));
 
-    bool stop = false;
+    size_t stopCount = 0;
     for (size_t i = 0; i < mPacketSources.size(); i++) {
         sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
 
         const char *stopKey;
         int streamType = mPacketSources.keyAt(i);
+
+        if (streamType == LiveSession::STREAMTYPE_SUBTITLES) {
+            // the subtitle track can always be stopped
+            ++stopCount;
+            continue;
+        }
+
         switch (streamType) {
         case LiveSession::STREAMTYPE_VIDEO:
             stopKey = "timeUsVideo";
@@ -550,15 +558,11 @@
             stopKey = "timeUsAudio";
             break;
 
-        case LiveSession::STREAMTYPE_SUBTITLES:
-            stopKey = "timeUsSubtitle";
-            break;
-
         default:
             TRESPASS();
         }
 
-        // Don't resume if we would stop within a resume threshold.
+        // check if this stream has too little data left to be resumed
         int32_t discontinuitySeq;
         int64_t latestTimeUs = 0, stopTimeUs = 0;
         sp<AMessage> latestMeta = packetSource->getLatestEnqueuedMeta();
@@ -567,12 +571,13 @@
                 && discontinuitySeq == mDiscontinuitySeq
                 && latestMeta->findInt64("timeUs", &latestTimeUs)
                 && params->findInt64(stopKey, &stopTimeUs)
-                && stopTimeUs - latestTimeUs < resumeThreshold(latestMeta)) {
-            stop = true;
+                && stopTimeUs - latestTimeUs < kFetcherResumeThreshold) {
+            ++stopCount;
         }
     }
 
-    if (stop) {
+    // Don't resume if all streams are within a resume threshold
+    if (stopCount == mPacketSources.size()) {
         for (size_t i = 0; i < mPacketSources.size(); i++) {
             mPacketSources.valueAt(i)->queueAccessUnit(mSession->createFormatChangeBuffer());
         }
@@ -581,7 +586,7 @@
     }
 
     mStopParams = params;
-    postMonitorQueue();
+    onDownloadNext();
 
     return OK;
 }
@@ -660,9 +665,6 @@
 
         ALOGV("prepared, buffered=%" PRId64 " > %" PRId64 "",
                 bufferedDurationUs, targetDurationUs);
-        sp<AMessage> msg = mNotify->dup();
-        msg->setInt32("what", kWhatTemporarilyDoneFetching);
-        msg->post();
     }
 
     if (finalResult == OK && downloadMore) {
@@ -676,11 +678,6 @@
         msg->post(1000l);
     } else {
         // Nothing to do yet, try again in a second.
-
-        sp<AMessage> msg = mNotify->dup();
-        msg->setInt32("what", kWhatTemporarilyDoneFetching);
-        msg->post();
-
         int64_t delayUs = mPrepared ? kMaxMonitorDelayUs : targetDurationUs / 2;
         ALOGV("pausing for %" PRId64 ", buffered=%" PRId64 " > %" PRId64 "",
                 delayUs, bufferedDurationUs, durationToBufferUs);
@@ -1687,33 +1684,4 @@
     msg->post();
 }
 
-int64_t PlaylistFetcher::resumeThreshold(const sp<AMessage> &msg) {
-    int64_t durationUs;
-    if (msg->findInt64("durationUs", &durationUs) && durationUs > 0) {
-        return kNumSkipFrames * durationUs;
-    }
-
-    sp<RefBase> obj;
-    msg->findObject("format", &obj);
-    MetaData *format = static_cast<MetaData *>(obj.get());
-
-    const char *mime;
-    CHECK(format->findCString(kKeyMIMEType, &mime));
-    bool audio = !strncasecmp(mime, "audio/", 6);
-    if (audio) {
-        // Assumes 1000 samples per frame.
-        int32_t sampleRate;
-        CHECK(format->findInt32(kKeySampleRate, &sampleRate));
-        return kNumSkipFrames  /* frames */ * 1000 /* samples */
-                * (1000000 / sampleRate) /* sample duration (us) */;
-    } else {
-        int32_t frameRate;
-        if (format->findInt32(kKeyFrameRate, &frameRate) && frameRate > 0) {
-            return kNumSkipFrames * (1000000 / frameRate);
-        }
-    }
-
-    return 500000ll;
-}
-
 }  // namespace android
diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h
index 4e15f85..2f11949 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.h
+++ b/media/libstagefright/httplive/PlaylistFetcher.h
@@ -36,6 +36,7 @@
 struct PlaylistFetcher : public AHandler {
     static const int64_t kMinBufferedDurationUs;
     static const int32_t kDownloadBlockSize;
+    static const int64_t kFetcherResumeThreshold;
 
     enum {
         kWhatStarted,
@@ -43,7 +44,6 @@
         kWhatStopped,
         kWhatError,
         kWhatDurationUpdate,
-        kWhatTemporarilyDoneFetching,
         kWhatPrepared,
         kWhatPreparationFailed,
         kWhatStartedAt,
@@ -212,10 +212,6 @@
 
     void updateDuration();
 
-    // Before resuming a fetcher in onResume, check the remaining duration is longer than that
-    // returned by resumeThreshold.
-    int64_t resumeThreshold(const sp<AMessage> &msg);
-
     DISALLOW_EVIL_CONSTRUCTORS(PlaylistFetcher);
 };
 
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 934e2e5..6786506 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -35,6 +35,7 @@
 #include <media/stagefright/Utils.h>
 #include <media/IStreamSource.h>
 #include <utils/KeyedVector.h>
+#include <utils/Vector.h>
 
 #include <inttypes.h>
 
@@ -86,6 +87,11 @@
     }
 
 private:
+    struct StreamInfo {
+        unsigned mType;
+        unsigned mPID;
+    };
+
     ATSParser *mParser;
     unsigned mProgramNumber;
     unsigned mProgramMapPID;
@@ -96,6 +102,7 @@
 
     status_t parseProgramMap(ABitReader *br);
     int64_t recoverPTS(uint64_t PTS_33bit);
+    bool switchPIDs(const Vector<StreamInfo> &infos);
 
     DISALLOW_EVIL_CONSTRUCTORS(Program);
 };
@@ -185,7 +192,7 @@
       mProgramMapPID(programMapPID),
       mFirstPTSValid(false),
       mFirstPTS(0),
-      mLastRecoveredPTS(0) {
+      mLastRecoveredPTS(-1ll) {
     ALOGV("new program number %u", programNumber);
 }
 
@@ -240,10 +247,71 @@
     }
 }
 
-struct StreamInfo {
-    unsigned mType;
-    unsigned mPID;
-};
+bool ATSParser::Program::switchPIDs(const Vector<StreamInfo> &infos) {
+    bool success = false;
+
+    if (mStreams.size() == infos.size()) {
+        // build type->PIDs map for old and new mapping
+        size_t i;
+        KeyedVector<int32_t, Vector<int32_t> > oldType2PIDs, newType2PIDs;
+        for (i = 0; i < mStreams.size(); ++i) {
+            ssize_t index = oldType2PIDs.indexOfKey(mStreams[i]->type());
+            if (index < 0) {
+                oldType2PIDs.add(mStreams[i]->type(), Vector<int32_t>());
+            }
+            oldType2PIDs.editValueFor(mStreams[i]->type()).push_back(mStreams[i]->pid());
+        }
+        for (i = 0; i < infos.size(); ++i) {
+            ssize_t index = newType2PIDs.indexOfKey(infos[i].mType);
+            if (index < 0) {
+                newType2PIDs.add(infos[i].mType, Vector<int32_t>());
+            }
+            newType2PIDs.editValueFor(infos[i].mType).push_back(infos[i].mPID);
+        }
+
+        // we can recover if the number of streams for each type hasn't changed
+        if (oldType2PIDs.size() == newType2PIDs.size()) {
+            success = true;
+            for (i = 0; i < oldType2PIDs.size(); ++i) {
+                // KeyedVector is sorted, we just compare key and size of each index
+                if (oldType2PIDs.keyAt(i) != newType2PIDs.keyAt(i)
+                        || oldType2PIDs[i].size() != newType2PIDs[i].size()) {
+                     success = false;
+                     break;
+                }
+            }
+        }
+
+        if (success) {
+            // save current streams to temp
+            KeyedVector<int32_t, sp<Stream> > temp;
+            for (i = 0; i < mStreams.size(); ++i) {
+                 temp.add(mStreams.keyAt(i), mStreams.editValueAt(i));
+            }
+
+            mStreams.clear();
+            for (i = 0; i < temp.size(); ++i) {
+                // The two checks below shouldn't happen,
+                // we already checked above the stream count matches
+                ssize_t index = newType2PIDs.indexOfKey(temp[i]->type());
+                CHECK(index >= 0);
+                Vector<int32_t> &newPIDs = newType2PIDs.editValueAt(index);
+                CHECK(newPIDs.size() > 0);
+
+                // get the next PID for temp[i]->type() in the new PID map
+                Vector<int32_t>::iterator it = newPIDs.begin();
+
+                // change the PID of the stream, and add it back
+                temp.editValueAt(i)->setPID(*it);
+                mStreams.add(temp[i]->pid(), temp.editValueAt(i));
+
+                // removed the used PID
+                newPIDs.erase(it);
+            }
+        }
+    }
+    return success;
+}
 
 status_t ATSParser::Program::parseProgramMap(ABitReader *br) {
     unsigned table_id = br->getBits(8);
@@ -372,39 +440,8 @@
         }
 #endif
 
-        // The only case we can recover from is if we have two streams
-        // and they switched PIDs.
-
-        bool success = false;
-
-        if (mStreams.size() == 2 && infos.size() == 2) {
-            const StreamInfo &info1 = infos.itemAt(0);
-            const StreamInfo &info2 = infos.itemAt(1);
-
-            sp<Stream> s1 = mStreams.editValueAt(0);
-            sp<Stream> s2 = mStreams.editValueAt(1);
-
-            bool caseA =
-                info1.mPID == s1->pid() && info1.mType == s2->type()
-                    && info2.mPID == s2->pid() && info2.mType == s1->type();
-
-            bool caseB =
-                info1.mPID == s2->pid() && info1.mType == s1->type()
-                    && info2.mPID == s1->pid() && info2.mType == s2->type();
-
-            if (caseA || caseB) {
-                unsigned pid1 = s1->pid();
-                unsigned pid2 = s2->pid();
-                s1->setPID(pid2);
-                s2->setPID(pid1);
-
-                mStreams.clear();
-                mStreams.add(s1->pid(), s1);
-                mStreams.add(s2->pid(), s2);
-
-                success = true;
-            }
-        }
+        // we can recover if number of streams for each type remain the same
+        bool success = switchPIDs(infos);
 
         if (!success) {
             ALOGI("Stream PIDs changed and we cannot recover.");
@@ -433,14 +470,25 @@
     // reasonable amount of time. To handle the wrap-around, use fancy math
     // to get an extended PTS that is within [-0xffffffff, 0xffffffff]
     // of the latest recovered PTS.
-    mLastRecoveredPTS = static_cast<int64_t>(
-            ((mLastRecoveredPTS - PTS_33bit + 0x100000000ll)
-            & 0xfffffffe00000000ull) | PTS_33bit);
+    if (mLastRecoveredPTS < 0ll) {
+        // Use the original 33bit number for 1st frame, the reason is that
+        // if 1st frame wraps to negative that's far away from 0, we could
+        // never start. Only start wrapping around from 2nd frame.
+        mLastRecoveredPTS = static_cast<int64_t>(PTS_33bit);
+    } else {
+        mLastRecoveredPTS = static_cast<int64_t>(
+                ((mLastRecoveredPTS - PTS_33bit + 0x100000000ll)
+                & 0xfffffffe00000000ull) | PTS_33bit);
+        // We start from 0, but recovered PTS could be slightly below 0.
+        // Clamp it to 0 as rest of the pipeline doesn't take negative pts.
+        // (eg. video is read first and starts at 0, but audio starts at 0xfffffff0)
+        if (mLastRecoveredPTS < 0ll) {
+            ALOGI("Clamping negative recovered PTS (%" PRId64 ") to 0", mLastRecoveredPTS);
+            mLastRecoveredPTS = 0ll;
+        }
+    }
 
-    // We start from 0, but recovered PTS could be slightly below 0.
-    // Clamp it to 0 as rest of the pipeline doesn't take negative pts.
-    // (eg. video is read first and starts at 0, but audio starts at 0xfffffff0)
-    return mLastRecoveredPTS < 0ll ? 0ll : mLastRecoveredPTS;
+    return mLastRecoveredPTS;
 }
 
 sp<MediaSource> ATSParser::Program::getSource(SourceType type) {
@@ -1118,7 +1166,8 @@
 
         if (payload_unit_start_indicator) {
             if (!section->isEmpty()) {
-                return ERROR_UNSUPPORTED;
+                ALOGW("parsePID encounters payload_unit_start_indicator when section is not empty");
+                section->clear();
             }
 
             unsigned skip = br->getBits(8);
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index f266fe7..bb05417 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -91,13 +91,11 @@
     while (it != mBuffers.end()) {
         sp<ABuffer> buffer = *it;
         int32_t discontinuity;
-        if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
-            break;
-        }
-
-        sp<RefBase> object;
-        if (buffer->meta()->findObject("format", &object)) {
-            return mFormat = static_cast<MetaData*>(object.get());
+        if (!buffer->meta()->findInt32("discontinuity", &discontinuity)) {
+            sp<RefBase> object;
+            if (buffer->meta()->findObject("format", &object)) {
+                return mFormat = static_cast<MetaData*>(object.get());
+            }
         }
 
         ++it;
diff --git a/media/libstagefright/wifi-display/source/MediaPuller.cpp b/media/libstagefright/wifi-display/source/MediaPuller.cpp
index 927a53c..ce07a4e 100644
--- a/media/libstagefright/wifi-display/source/MediaPuller.cpp
+++ b/media/libstagefright/wifi-display/source/MediaPuller.cpp
@@ -105,7 +105,7 @@
             sp<AMessage> response = new AMessage;
             response->setInt32("err", err);
 
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
             response->postReply(replyID);
             break;
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index 210914e..14d0951 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -57,7 +57,7 @@
       mNetSession(netSession),
       mClient(client),
       mSessionID(0),
-      mStopReplyID(0),
+      mStopReplyID(NULL),
       mChosenRTPPort(-1),
       mUsingPCMAudio(false),
       mClientSessionID(0),
@@ -138,7 +138,7 @@
     switch (msg->what()) {
         case kWhatStart:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             AString iface;
@@ -325,7 +325,7 @@
 
         case kWhatPause:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             status_t err = OK;
@@ -345,7 +345,7 @@
 
         case kWhatResume:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             status_t err = OK;
@@ -492,7 +492,7 @@
             if (mState == AWAITING_CLIENT_TEARDOWN) {
                 ALOGI("TEARDOWN trigger timed out, forcing disconnection.");
 
-                CHECK_NE(mStopReplyID, 0);
+                CHECK(mStopReplyID != NULL);
                 finishStop();
                 break;
             }
@@ -1470,7 +1470,7 @@
     mNetSession->sendRequest(sessionID, response.c_str());
 
     if (mState == AWAITING_CLIENT_TEARDOWN) {
-        CHECK_NE(mStopReplyID, 0);
+        CHECK(mStopReplyID != NULL);
         finishStop();
     } else {
         mClient->onDisplayError(IRemoteDisplayClient::kDisplayErrorUnknown);
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.h b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
index 750265f..0f779e4 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.h
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
@@ -27,6 +27,7 @@
 
 namespace android {
 
+struct AReplyToken;
 struct IHDCP;
 struct IRemoteDisplayClient;
 struct ParsedMessage;
@@ -121,7 +122,7 @@
     struct in_addr mInterfaceAddr;
     int32_t mSessionID;
 
-    uint32_t mStopReplyID;
+    sp<AReplyToken> mStopReplyID;
 
     AString mWfdClientRtpPorts;
     int32_t mChosenRTPPort;  // extracted from "wfd_client_rtp_ports"
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 46757bc..80c1c2f 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -116,7 +116,7 @@
 
         case kWhatStopActivityNotifications:
         {
-            uint32_t replyID;
+            sp<AReplyToken> replyID;
             msg->senderAwaitsResponse(&replyID);
 
             mCodec->mGeneration++;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 3474f24..c1da6bc 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -741,6 +741,7 @@
         dprintf(fd, "thread %p may be deadlocked\n", this);
     }
 
+    dprintf(fd, "  Thread name: %s\n", mThreadName);
     dprintf(fd, "  I/O handle: %d\n", mId);
     dprintf(fd, "  TID: %d\n", getTid());
     dprintf(fd, "  Standby: %s\n", mStandby ? "yes" : "no");
@@ -764,6 +765,9 @@
     } else {
         dprintf(fd, " none\n");
     }
+    dprintf(fd, "  Output device: %#x (%s)\n", mOutDevice, devicesToString(mOutDevice).string());
+    dprintf(fd, "  Input device: %#x (%s)\n", mInDevice, devicesToString(mInDevice).string());
+    dprintf(fd, "  Audio source: %d (%s)\n", mAudioSource, sourceToString(mAudioSource));
 
     if (locked) {
         mLock.unlock();
@@ -1479,6 +1483,9 @@
 void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
 {
     dprintf(fd, "\nOutput thread %p type %d (%s):\n", this, type(), threadTypeToString(type()));
+
+    dumpBase(fd, args);
+
     dprintf(fd, "  Normal frame count: %zu\n", mNormalFrameCount);
     dprintf(fd, "  Last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
     dprintf(fd, "  Total writes: %d\n", mNumWrites);
@@ -1493,8 +1500,6 @@
     audio_output_flags_t flags = output != NULL ? output->flags : AUDIO_OUTPUT_FLAG_NONE;
     String8 flagsAsString = outputFlagsToString(flags);
     dprintf(fd, "  AudioStreamOut: %p flags %#x (%s)\n", output, flags, flagsAsString.string());
-
-    dumpBase(fd, args);
 }
 
 // Thread virtuals
@@ -1545,9 +1550,10 @@
               (
                 (sharedBuffer != 0)
               ) ||
-              // use case 2: callback handler and frame count is default or at least as large as HAL
+              // use case 2: frame count is default or at least as large as HAL
               (
-                (tid != -1) &&
+                // we formerly checked for a callback handler (non-0 tid),
+                // but that is no longer required for TRANSFER_OBTAIN mode
                 ((frameCount == 0) ||
                 (frameCount >= mFrameCount))
               )
@@ -6151,15 +6157,13 @@
 {
     dprintf(fd, "\nInput thread %p:\n", this);
 
-    if (mActiveTracks.size() > 0) {
-        dprintf(fd, "  Buffer size: %zu bytes\n", mBufferSize);
-    } else {
+    dumpBase(fd, args);
+
+    if (mActiveTracks.size() == 0) {
         dprintf(fd, "  No active record clients\n");
     }
     dprintf(fd, "  Fast capture thread: %s\n", hasFastCapture() ? "yes" : "no");
     dprintf(fd, "  Fast track available: %s\n", mFastTrackAvail ? "yes" : "no");
-
-    dumpBase(fd, args);
 }
 
 void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args __unused)
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
index 8e894cd..7a79750 100644
--- a/services/camera/libcameraservice/CameraFlashlight.cpp
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -388,7 +388,8 @@
     if (mAnw == NULL) {
         return NO_MEMORY;
     }
-    res = device->createStream(mAnw, width, height, format, &mStreamId);
+    res = device->createStream(mAnw, width, height, format,
+            HAL_DATASPACE_UNKNOWN, &mStreamId);
     if (res) {
         return res;
     }
diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
index eadaa00..fd4e714 100644
--- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
@@ -155,7 +155,7 @@
                 callbackFormat, params.previewFormat);
         res = device->createStream(mCallbackWindow,
                 params.previewWidth, params.previewHeight,
-                callbackFormat, &mCallbackStreamId);
+                callbackFormat, HAL_DATASPACE_JFIF, &mCallbackStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Can't create output stream for callbacks: "
                     "%s (%d)", __FUNCTION__, mId,
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index 2772267..5b387f9 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -145,7 +145,8 @@
         // Create stream for HAL production
         res = device->createStream(mCaptureWindow,
                 params.pictureWidth, params.pictureHeight,
-                HAL_PIXEL_FORMAT_BLOB, &mCaptureStreamId);
+                HAL_PIXEL_FORMAT_BLOB, HAL_DATASPACE_JFIF,
+                &mCaptureStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Can't create output stream for capture: "
                     "%s (%d)", __FUNCTION__, mId,
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index 470624b..ea5dcdd 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -181,7 +181,8 @@
     if (mPreviewStreamId == NO_STREAM) {
         res = device->createStream(mPreviewWindow,
                 params.previewWidth, params.previewHeight,
-                CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, &mPreviewStreamId);
+                CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, HAL_DATASPACE_UNKNOWN,
+                &mPreviewStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Unable to create preview stream: %s (%d)",
                     __FUNCTION__, mId, strerror(-res), res);
@@ -420,9 +421,12 @@
 
     if (mRecordingStreamId == NO_STREAM) {
         mRecordingFrameCount = 0;
+        // Selecting BT.709 colorspace by default
+        // TODO: Wire this in from encoder side
         res = device->createStream(mRecordingWindow,
                 params.videoWidth, params.videoHeight,
-                CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, &mRecordingStreamId);
+                CAMERA2_HAL_PIXEL_FORMAT_OPAQUE,
+                HAL_DATASPACE_BT709, &mRecordingStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Can't create output stream for recording: "
                     "%s (%d)", __FUNCTION__, mId,
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 8b7e4b4..db7e10d 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -186,7 +186,7 @@
                 (int)HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
         res = device->createStream(mZslWindow,
                 params.fastInfo.arrayWidth, params.fastInfo.arrayHeight,
-                streamType, &mZslStreamId);
+                streamType, HAL_DATASPACE_UNKNOWN, &mZslStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Can't create output stream for ZSL: "
                     "%s (%d)", __FUNCTION__, mId,
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index acc092c..dde1779 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -314,11 +314,10 @@
     return res;
 }
 
-status_t CameraDeviceClient::createStream(int width, int height, int format,
+status_t CameraDeviceClient::createStream(
                       const sp<IGraphicBufferProducer>& bufferProducer)
 {
     ATRACE_CALL();
-    ALOGV("%s (w = %d, h = %d, f = 0x%x)", __FUNCTION__, width, height, format);
 
     status_t res;
     if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
@@ -370,7 +369,8 @@
     sp<IBinder> binder = IInterface::asBinder(bufferProducer);
     sp<ANativeWindow> anw = new Surface(bufferProducer, useAsync);
 
-    // TODO: remove w,h,f since we are ignoring them
+    int width, height, format;
+    android_dataspace dataSpace;
 
     if ((res = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, &width)) != OK) {
         ALOGE("%s: Camera %d: Failed to query Surface width", __FUNCTION__,
@@ -387,6 +387,12 @@
               mCameraId);
         return res;
     }
+    if ((res = anw->query(anw.get(), NATIVE_WINDOW_DEFAULT_DATASPACE,
+                            reinterpret_cast<int*>(&dataSpace))) != OK) {
+        ALOGE("%s: Camera %d: Failed to query Surface dataSpace", __FUNCTION__,
+              mCameraId);
+        return res;
+    }
 
     // FIXME: remove this override since the default format should be
     //       IMPLEMENTATION_DEFINED. b/9487482
@@ -399,14 +405,15 @@
 
     // Round dimensions to the nearest dimensions available for this format
     if (flexibleConsumer && !CameraDeviceClient::roundBufferDimensionNearest(width, height,
-            format, mDevice->info(), /*out*/&width, /*out*/&height)) {
+            format, dataSpace, mDevice->info(), /*out*/&width, /*out*/&height)) {
         ALOGE("%s: No stream configurations with the format %#x defined, failed to create stream.",
                 __FUNCTION__, format);
         return BAD_VALUE;
     }
 
     int streamId = -1;
-    res = mDevice->createStream(anw, width, height, format, &streamId);
+    res = mDevice->createStream(anw, width, height, format, dataSpace,
+            &streamId);
 
     if (res == OK) {
         mStreamMap.add(binder, streamId);
@@ -441,10 +448,12 @@
 
 
 bool CameraDeviceClient::roundBufferDimensionNearest(int32_t width, int32_t height,
-        int32_t format, const CameraMetadata& info,
+        int32_t format, android_dataspace dataSpace, const CameraMetadata& info,
         /*out*/int32_t* outWidth, /*out*/int32_t* outHeight) {
 
     camera_metadata_ro_entry streamConfigs =
+            (dataSpace == HAL_DATASPACE_DEPTH) ?
+            info.find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS) :
             info.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
 
     int32_t bestWidth = -1;
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index e687175..c89c269 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -84,9 +84,6 @@
     virtual status_t      deleteStream(int streamId);
 
     virtual status_t      createStream(
-            int width,
-            int height,
-            int format,
             const sp<IGraphicBufferProducer>& bufferProducer);
 
     // Create a request object from a template.
@@ -161,7 +158,8 @@
     // a width <= ROUNDING_WIDTH_CAP
     static const int32_t ROUNDING_WIDTH_CAP = 1080;
     static bool roundBufferDimensionNearest(int32_t width, int32_t height, int32_t format,
-            const CameraMetadata& info, /*out*/int32_t* outWidth, /*out*/int32_t* outHeight);
+            android_dataspace dataSpace, const CameraMetadata& info,
+            /*out*/int32_t* outWidth, /*out*/int32_t* outHeight);
 
     // IGraphicsBufferProducer binder -> Stream ID
     KeyedVector<sp<IBinder>, int> mStreamMap;
diff --git a/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp b/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp
index 30a89c2..ba93554 100644
--- a/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp
+++ b/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp
@@ -281,7 +281,7 @@
     }
 
     return mDevice->createStream(window, width, height, format,
-                                 streamId);
+                                 HAL_DATASPACE_UNKNOWN, streamId);
 }
 
 // Create a request object from a template.
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 06615f6..8764504 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -100,17 +100,14 @@
             nsecs_t timeout) = 0;
 
     /**
-     * Create an output stream of the requested size and format.
+     * Create an output stream of the requested size, format, and dataspace
      *
-     * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device selects
-     * an appropriate format; it can be queried with getStreamInfo.
-     *
-     * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must be
-     * equal to the size in bytes of the buffers to allocate for the stream. For
-     * other formats, the size parameter is ignored.
+     * For HAL_PIXEL_FORMAT_BLOB formats, the width and height should be the
+     * logical dimensions of the buffer, not the number of bytes.
      */
     virtual status_t createStream(sp<ANativeWindow> consumer,
-            uint32_t width, uint32_t height, int format, int *id) = 0;
+            uint32_t width, uint32_t height, int format,
+            android_dataspace dataSpace, int *id) = 0;
 
     /**
      * Create an input reprocess stream that uses buffers from an existing
diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp
index 43c8307..ee862a2 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.cpp
+++ b/services/camera/libcameraservice/device2/Camera2Device.cpp
@@ -241,7 +241,8 @@
 }
 
 status_t Camera2Device::createStream(sp<ANativeWindow> consumer,
-        uint32_t width, uint32_t height, int format, int *id) {
+        uint32_t width, uint32_t height, int format,
+        android_dataspace /*dataSpace*/, int *id) {
     ATRACE_CALL();
     status_t res;
     ALOGV("%s: E", __FUNCTION__);
diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h
index 1cc5482..e4c2856 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.h
+++ b/services/camera/libcameraservice/device2/Camera2Device.h
@@ -57,7 +57,8 @@
     virtual status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL);
     virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout);
     virtual status_t createStream(sp<ANativeWindow> consumer,
-            uint32_t width, uint32_t height, int format, int *id);
+            uint32_t width, uint32_t height, int format,
+            android_dataspace dataSpace, int *id);
     virtual status_t createReprocessStreamFromStream(int outputId, int *id);
     virtual status_t getStreamInfo(int id,
             uint32_t *width, uint32_t *height, uint32_t *format);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index bca9bfd..529d249 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -801,12 +801,13 @@
 }
 
 status_t Camera3Device::createStream(sp<ANativeWindow> consumer,
-        uint32_t width, uint32_t height, int format, int *id) {
+        uint32_t width, uint32_t height, int format, android_dataspace dataSpace,
+        int *id) {
     ATRACE_CALL();
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
-    ALOGV("Camera %d: Creating new stream %d: %d x %d, format %d",
-            mId, mNextStreamId, width, height, format);
+    ALOGV("Camera %d: Creating new stream %d: %d x %d, format %d, dataspace %d",
+            mId, mNextStreamId, width, height, format, dataSpace);
 
     status_t res;
     bool wasActive = false;
@@ -846,10 +847,10 @@
         }
 
         newStream = new Camera3OutputStream(mNextStreamId, consumer,
-                width, height, jpegBufferSize, format);
+                width, height, jpegBufferSize, format, dataSpace);
     } else {
         newStream = new Camera3OutputStream(mNextStreamId, consumer,
-                width, height, format);
+                width, height, format, dataSpace);
     }
     newStream->setStatusTracker(mStatusTracker);
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index de10cfe..e2ad1fa 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -95,7 +95,8 @@
     // If adding streams while actively capturing, will pause device before adding
     // stream, reconfiguring device, and unpausing.
     virtual status_t createStream(sp<ANativeWindow> consumer,
-            uint32_t width, uint32_t height, int format, int *id);
+            uint32_t width, uint32_t height, int format,
+            android_dataspace dataSpace, int *id);
     virtual status_t createInputStream(
             uint32_t width, uint32_t height, int format,
             int *id);
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
index 6656b09..6201484 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -28,7 +28,7 @@
 
 Camera3DummyStream::Camera3DummyStream(int id) :
         Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, DUMMY_WIDTH, DUMMY_HEIGHT,
-                /*maxSize*/0, DUMMY_FORMAT) {
+                /*maxSize*/0, DUMMY_FORMAT, DUMMY_DATASPACE) {
 
 }
 
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h
index 3e42623..7f52d84 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.h
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h
@@ -75,6 +75,7 @@
     static const int DUMMY_WIDTH = 320;
     static const int DUMMY_HEIGHT = 240;
     static const int DUMMY_FORMAT = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+    static const android_dataspace DUMMY_DATASPACE = HAL_DATASPACE_UNKNOWN;
     static const uint32_t DUMMY_USAGE = GRALLOC_USAGE_HW_COMPOSER;
 
     /**
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index cc66459..ff0acbb 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -30,9 +30,10 @@
 namespace camera3 {
 
 Camera3IOStreamBase::Camera3IOStreamBase(int id, camera3_stream_type_t type,
-        uint32_t width, uint32_t height, size_t maxSize, int format) :
+        uint32_t width, uint32_t height, size_t maxSize, int format,
+        android_dataspace dataSpace) :
         Camera3Stream(id, type,
-                width, height, maxSize, format),
+                width, height, maxSize, format, dataSpace),
         mTotalBufferCount(0),
         mHandoutTotalBufferCount(0),
         mHandoutOutputBufferCount(0),
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index a35c290..83d4350 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -33,7 +33,8 @@
         public Camera3Stream {
   protected:
     Camera3IOStreamBase(int id, camera3_stream_type_t type,
-            uint32_t width, uint32_t height, size_t maxSize, int format);
+            uint32_t width, uint32_t height, size_t maxSize, int format,
+            android_dataspace dataSpace);
 
   public:
 
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index 319be1d..85ed88d 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -29,7 +29,7 @@
 Camera3InputStream::Camera3InputStream(int id,
         uint32_t width, uint32_t height, int format) :
         Camera3IOStreamBase(id, CAMERA3_STREAM_INPUT, width, height,
-                            /*maxSize*/0, format) {
+                            /*maxSize*/0, format, HAL_DATASPACE_UNKNOWN) {
 
     if (format == HAL_PIXEL_FORMAT_BLOB) {
         ALOGE("%s: Bad format, BLOB not supported", __FUNCTION__);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 77ad503..103d90b 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -33,9 +33,10 @@
 
 Camera3OutputStream::Camera3OutputStream(int id,
         sp<ANativeWindow> consumer,
-        uint32_t width, uint32_t height, int format) :
+        uint32_t width, uint32_t height, int format,
+        android_dataspace dataSpace) :
         Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height,
-                            /*maxSize*/0, format),
+                            /*maxSize*/0, format, dataSpace),
         mConsumer(consumer),
         mTransform(0),
         mTraceFirstBuffer(true) {
@@ -48,9 +49,10 @@
 
 Camera3OutputStream::Camera3OutputStream(int id,
         sp<ANativeWindow> consumer,
-        uint32_t width, uint32_t height, size_t maxSize, int format) :
+        uint32_t width, uint32_t height, size_t maxSize, int format,
+        android_dataspace dataSpace) :
         Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height, maxSize,
-                            format),
+                            format, dataSpace),
         mConsumer(consumer),
         mTransform(0),
         mTraceFirstBuffer(true) {
@@ -69,10 +71,11 @@
 
 Camera3OutputStream::Camera3OutputStream(int id, camera3_stream_type_t type,
                                          uint32_t width, uint32_t height,
-                                         int format) :
+                                         int format,
+                                         android_dataspace dataSpace) :
         Camera3IOStreamBase(id, type, width, height,
                             /*maxSize*/0,
-                            format),
+                            format, dataSpace),
         mTransform(0) {
 
     // Subclasses expected to initialize mConsumer themselves
@@ -323,6 +326,14 @@
         return res;
     }
 
+    res = native_window_set_buffers_data_space(mConsumer.get(),
+            camera3_stream::data_space);
+    if (res != OK) {
+        ALOGE("%s: Unable to configure stream dataspace %#x for stream %d",
+                __FUNCTION__, camera3_stream::data_space, mId);
+        return res;
+    }
+
     int maxConsumerBuffers;
     res = mConsumer->query(mConsumer.get(),
             NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index be278c5..f016d60 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -39,14 +39,16 @@
      * Set up a stream for formats that have 2 dimensions, such as RAW and YUV.
      */
     Camera3OutputStream(int id, sp<ANativeWindow> consumer,
-            uint32_t width, uint32_t height, int format);
+            uint32_t width, uint32_t height, int format,
+            android_dataspace dataSpace);
 
     /**
      * Set up a stream for formats that have a variable buffer size for the same
      * dimensions, such as compressed JPEG.
      */
     Camera3OutputStream(int id, sp<ANativeWindow> consumer,
-            uint32_t width, uint32_t height, size_t maxSize, int format);
+            uint32_t width, uint32_t height, size_t maxSize, int format,
+            android_dataspace dataSpace);
 
     virtual ~Camera3OutputStream();
 
@@ -64,7 +66,8 @@
 
   protected:
     Camera3OutputStream(int id, camera3_stream_type_t type,
-            uint32_t width, uint32_t height, int format);
+            uint32_t width, uint32_t height, int format,
+            android_dataspace dataSpace);
 
     /**
      * Note that we release the lock briefly in this function
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 3c0e908..f829741 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -46,7 +46,8 @@
 
 Camera3Stream::Camera3Stream(int id,
         camera3_stream_type type,
-        uint32_t width, uint32_t height, size_t maxSize, int format) :
+        uint32_t width, uint32_t height, size_t maxSize, int format,
+        android_dataspace dataSpace) :
     camera3_stream(),
     mId(id),
     mName(String8::format("Camera3Stream[%d]", id)),
@@ -58,6 +59,7 @@
     camera3_stream::width = width;
     camera3_stream::height = height;
     camera3_stream::format = format;
+    camera3_stream::data_space = dataSpace;
     camera3_stream::usage = 0;
     camera3_stream::max_buffers = 0;
     camera3_stream::priv = NULL;
@@ -84,6 +86,10 @@
     return camera3_stream::format;
 }
 
+android_dataspace Camera3Stream::getDataSpace() const {
+    return camera3_stream::data_space;
+}
+
 camera3_stream* Camera3Stream::startConfiguration() {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index d0e1337..72f3ee9 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -119,9 +119,10 @@
     /**
      * Get the stream's dimensions and format
      */
-    uint32_t         getWidth() const;
-    uint32_t         getHeight() const;
-    int              getFormat() const;
+    uint32_t          getWidth() const;
+    uint32_t          getHeight() const;
+    int               getFormat() const;
+    android_dataspace getDataSpace() const;
 
     /**
      * Start the stream configuration process. Returns a handle to the stream's
@@ -264,7 +265,8 @@
     mutable Mutex mLock;
 
     Camera3Stream(int id, camera3_stream_type type,
-            uint32_t width, uint32_t height, size_t maxSize, int format);
+            uint32_t width, uint32_t height, size_t maxSize, int format,
+            android_dataspace dataSpace);
 
     /**
      * Interface to be implemented by derived classes
diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
index 81330ea..5bf7a4c 100644
--- a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
@@ -114,7 +114,8 @@
         int bufferCount) :
         Camera3OutputStream(id, CAMERA3_STREAM_BIDIRECTIONAL,
                             width, height,
-                            HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+                            HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+                            HAL_DATASPACE_UNKNOWN),
         mDepth(bufferCount) {
 
     sp<IGraphicBufferProducer> producer;