Merge "Better workaround for slow decoders." into klp-dev
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index d027ba9..94c626a 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -37,11 +37,13 @@
 #include <media/ICrypto.h>
 
 #include <stdlib.h>
+#include <unistd.h>
 #include <string.h>
 #include <stdio.h>
 #include <fcntl.h>
 #include <signal.h>
 #include <getopt.h>
+#include <sys/wait.h>
 
 using namespace android;
 
@@ -498,23 +500,61 @@
 
 /*
  * Sends a broadcast to the media scanner to tell it about the new video.
+ *
+ * This is optional, but nice to have.
  */
 static status_t notifyMediaScanner(const char* fileName) {
-    String8 command("am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://");
-    command.append(fileName);
-    if (gVerbose) {
-        printf("Shell: %s\n", command.string());
-    }
+    pid_t pid = fork();
+    if (pid < 0) {
+        int err = errno;
+        ALOGW("fork() failed: %s", strerror(err));
+        return -err;
+    } else if (pid > 0) {
+        // parent; wait for the child, mostly to make the verbose-mode output
+        // look right, but also to check for and log failures
+        int status;
+        pid_t actualPid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
+        if (actualPid != pid) {
+            ALOGW("waitpid() returned %d (errno=%d)", actualPid, errno);
+        } else if (status != 0) {
+            ALOGW("'am broadcast' exited with status=%d", status);
+        } else {
+            ALOGV("'am broadcast' exited successfully");
+        }
+    } else {
+        const char* kCommand = "/system/bin/am";
 
-    // TODO: for non-verbose mode we should suppress stdout
-    int status = system(command.string());
-    if (status < 0) {
-        fprintf(stderr, "Unable to fork shell for media scanner broadcast\n");
-        return UNKNOWN_ERROR;
-    } else if (status != 0) {
-        fprintf(stderr, "am command failed (status=%d): '%s'\n",
-                status, command.string());
-        return UNKNOWN_ERROR;
+        // child; we're single-threaded, so okay to alloc
+        String8 fileUrl("file://");
+        fileUrl.append(fileName);
+        const char* const argv[] = {
+                kCommand,
+                "broadcast",
+                "-a",
+                "android.intent.action.MEDIA_SCANNER_SCAN_FILE",
+                "-d",
+                fileUrl.string(),
+                NULL
+        };
+        if (gVerbose) {
+            printf("Executing:");
+            for (int i = 0; argv[i] != NULL; i++) {
+                printf(" %s", argv[i]);
+            }
+            putchar('\n');
+        } else {
+            // non-verbose, suppress 'am' output
+            ALOGV("closing stdout/stderr in child");
+            int fd = open("/dev/null", O_WRONLY);
+            if (fd >= 0) {
+                dup2(fd, STDOUT_FILENO);
+                dup2(fd, STDERR_FILENO);
+                close(fd);
+            }
+        }
+        execv(kCommand, const_cast<char* const*>(argv));
+        ALOGE("execv(%s) failed: %s\n", kCommand, strerror(errno));
+        exit(1);
     }
     return NO_ERROR;
 }
diff --git a/drm/common/DrmInfoEvent.cpp b/drm/common/DrmInfoEvent.cpp
index 2315aa9..27a5a2d 100644
--- a/drm/common/DrmInfoEvent.cpp
+++ b/drm/common/DrmInfoEvent.cpp
@@ -16,29 +16,16 @@
 
 #include <utils/String8.h>
 #include <drm/DrmInfoEvent.h>
-#include <stdlib.h>
 
 using namespace android;
 
 DrmInfoEvent::DrmInfoEvent(int uniqueId, int infoType, const String8 message)
     : mUniqueId(uniqueId),
       mInfoType(infoType),
-      mMessage(message),
-      mDrmBuffer() {
+      mMessage(message) {
 
 }
 
-DrmInfoEvent::DrmInfoEvent(int uniqueId, int infoType, const String8 message,
-        const DrmBuffer& drmBuffer)
-        : mUniqueId(uniqueId), mInfoType(infoType), mMessage(message), mDrmBuffer() {
-    setData(drmBuffer);
-}
-
-DrmInfoEvent::~DrmInfoEvent() {
-    delete [] mDrmBuffer.data;
-}
-
-
 int DrmInfoEvent::getUniqueId() const {
     return mUniqueId;
 }
@@ -51,80 +38,3 @@
     return mMessage;
 }
 
-int DrmInfoEvent::getCount() const {
-    return mAttributes.size();
-}
-
-status_t DrmInfoEvent::put(const String8& key, String8& value) {
-        mAttributes.add(key, value);
-    return DRM_NO_ERROR;
-}
-
-const String8 DrmInfoEvent::get(const String8& key) const {
-    if (mAttributes.indexOfKey(key) != NAME_NOT_FOUND) {
-        return mAttributes.valueFor(key);
-    }
-    return String8("");
-}
-
-const DrmBuffer& DrmInfoEvent::getData() const {
-    return mDrmBuffer;
-}
-
-void DrmInfoEvent::setData(const DrmBuffer& drmBuffer) {
-    delete [] mDrmBuffer.data;
-    mDrmBuffer.data = new char[drmBuffer.length];;
-    mDrmBuffer.length = drmBuffer.length;
-    memcpy(mDrmBuffer.data, drmBuffer.data, drmBuffer.length);
-}
-
-DrmInfoEvent::KeyIterator DrmInfoEvent::keyIterator() const {
-    return KeyIterator(this);
-}
-
-DrmInfoEvent::Iterator DrmInfoEvent::iterator() const {
-    return Iterator(this);
-}
-
-// KeyIterator implementation
-DrmInfoEvent::KeyIterator::KeyIterator(const DrmInfoEvent::KeyIterator& keyIterator)
-        : mDrmInfoEvent(keyIterator.mDrmInfoEvent), mIndex(keyIterator.mIndex) {
-}
-
-bool DrmInfoEvent::KeyIterator::hasNext() {
-    return (mIndex < mDrmInfoEvent->mAttributes.size());
-}
-
-const String8& DrmInfoEvent::KeyIterator::next() {
-    const String8& key = mDrmInfoEvent->mAttributes.keyAt(mIndex);
-    mIndex++;
-    return key;
-}
-
-DrmInfoEvent::KeyIterator& DrmInfoEvent::KeyIterator::operator=(
-        const DrmInfoEvent::KeyIterator& keyIterator) {
-    mDrmInfoEvent = keyIterator.mDrmInfoEvent;
-    mIndex = keyIterator.mIndex;
-    return *this;
-}
-
-// Iterator implementation
-DrmInfoEvent::Iterator::Iterator(const DrmInfoEvent::Iterator& iterator)
-        : mDrmInfoEvent(iterator.mDrmInfoEvent), mIndex(iterator.mIndex) {
-}
-
-DrmInfoEvent::Iterator& DrmInfoEvent::Iterator::operator=(const DrmInfoEvent::Iterator& iterator) {
-    mDrmInfoEvent = iterator.mDrmInfoEvent;
-    mIndex = iterator.mIndex;
-    return *this;
-}
-
-bool DrmInfoEvent::Iterator::hasNext() {
-    return mIndex < mDrmInfoEvent->mAttributes.size();
-}
-
-const String8& DrmInfoEvent::Iterator::next() {
-    const String8& value = mDrmInfoEvent->mAttributes.editValueAt(mIndex);
-    mIndex++;
-    return value;
-}
diff --git a/drm/common/IDrmServiceListener.cpp b/drm/common/IDrmServiceListener.cpp
index d825afb..6eeea40 100644
--- a/drm/common/IDrmServiceListener.cpp
+++ b/drm/common/IDrmServiceListener.cpp
@@ -32,19 +32,6 @@
     data.writeInt32(event.getType());
     data.writeString8(event.getMessage());
 
-    data.writeInt32(event.getCount());
-    DrmInfoEvent::KeyIterator keyIt = event.keyIterator();
-    while (keyIt.hasNext()) {
-        String8 key = keyIt.next();
-        data.writeString8(key);
-        data.writeString8(event.get(key));
-    }
-    const DrmBuffer& value = event.getData();
-    data.writeInt32(value.length);
-    if (value.length > 0) {
-        data.write(value.data, value.length);
-    }
-
     remote()->transact(NOTIFY, data, &reply);
     return reply.readInt32();
 }
@@ -62,24 +49,7 @@
         int type = data.readInt32();
         const String8& message = data.readString8();
 
-        DrmInfoEvent event(uniqueId, type, message);
-        int size = data.readInt32();
-        for (int index = 0; index < size; index++) {
-            String8 key(data.readString8());
-            String8 value(data.readString8());
-            event.put(key, value);
-        }
-        int valueSize = data.readInt32();
-        if (valueSize > 0) {
-            char* valueData = new char[valueSize];
-            data.read(valueData, valueSize);
-            DrmBuffer drmBuffer(valueData, valueSize);
-            event.setData(drmBuffer);
-            delete[] valueData;
-        }
-
-        status_t status = notify(event);
-
+        status_t status = notify(DrmInfoEvent(uniqueId, type, message));
         reply->writeInt32(status);
 
         return DRM_NO_ERROR;
diff --git a/include/drm/DrmInfoEvent.h b/include/drm/DrmInfoEvent.h
index 23b2950..dfca228 100644
--- a/include/drm/DrmInfoEvent.h
+++ b/include/drm/DrmInfoEvent.h
@@ -17,8 +17,6 @@
 #ifndef __DRM_INFO_EVENT_H__
 #define __DRM_INFO_EVENT_H__
 
-#include "drm_framework_common.h"
-
 namespace android {
 
 class String8;
@@ -73,70 +71,18 @@
 
 public:
     /**
-     * Constructor for DrmInfoEvent.
-     * Data in drmBuffer are copied to newly allocated buffer.
+     * Constructor for DrmInfoEvent
      *
      * @param[in] uniqueId Unique session identifier
      * @param[in] infoType Type of information
      * @param[in] message Message description
-     * @param[in] drmBuffer Binary information
      */
     DrmInfoEvent(int uniqueId, int infoType, const String8 message);
-    DrmInfoEvent(int uniqueId, int infoType, const String8 message, const DrmBuffer& drmBuffer);
 
     /**
      * Destructor for DrmInfoEvent
      */
-    ~DrmInfoEvent();
-
-public:
-    /**
-     * Iterator for key
-     */
-    class KeyIterator {
-        friend class DrmInfoEvent;
-
-    private:
-        KeyIterator(const DrmInfoEvent* drmInfoEvent)
-                : mDrmInfoEvent(const_cast <DrmInfoEvent*> (drmInfoEvent)), mIndex(0) {}
-
-    public:
-        KeyIterator(const KeyIterator& keyIterator);
-        KeyIterator& operator=(const KeyIterator& keyIterator);
-        virtual ~KeyIterator() {}
-
-    public:
-        bool hasNext();
-        const String8& next();
-
-    private:
-        DrmInfoEvent* mDrmInfoEvent;
-        unsigned int mIndex;
-    };
-
-    /**
-     * Iterator
-     */
-    class Iterator {
-        friend class DrmInfoEvent;
-
-    private:
-        Iterator(const DrmInfoEvent* drmInfoEvent)
-                : mDrmInfoEvent(const_cast <DrmInfoEvent*> (drmInfoEvent)), mIndex(0) {}
-
-    public:
-        Iterator(const Iterator& iterator);
-        Iterator& operator=(const Iterator& iterator);
-        virtual ~Iterator() {}
-
-    public:
-        bool hasNext();
-        const String8& next();
-
-    private:
-        DrmInfoEvent* mDrmInfoEvent;
-        unsigned int mIndex;
-    };
+    virtual ~DrmInfoEvent() {}
 
 public:
     /**
@@ -160,69 +106,10 @@
      */
     const String8 getMessage() const;
 
-    /**
-     * Returns the number of attributes contained in this instance
-     *
-     * @return Number of attributes
-     */
-    int getCount() const;
-
-    /**
-     * Adds optional information as <key, value> pair to this instance
-     *
-     * @param[in] key Key to add
-     * @param[in] value Value to add
-     * @return Returns the error code
-     */
-    status_t put(const String8& key, String8& value);
-
-    /**
-     * Retrieves the value of given key
-     *
-     * @param key Key whose value to be retrieved
-     * @return The value
-     */
-    const String8 get(const String8& key) const;
-
-    /**
-     * Returns KeyIterator object to walk through the keys associated with this instance
-     *
-     * @return KeyIterator object
-     */
-    KeyIterator keyIterator() const;
-
-    /**
-     * Returns Iterator object to walk through the values associated with this instance
-     *
-     * @return Iterator object
-     */
-    Iterator iterator() const;
-
-    /**
-     * Returns the Binary information associated with this instance
-     *
-     * @return Binary information
-     */
-    const DrmBuffer& getData() const;
-
-    /**
-     * Sets the Binary information associated with this instance.
-     * Data in drmBuffer are copied to newly allocated buffer.
-     *
-     * @param[in] drmBuffer Binary information associated with this instance
-     */
-    void setData(const DrmBuffer& drmBuffer);
-
-private:
-    DrmInfoEvent(const DrmInfoEvent& ref);
-    const DrmInfoEvent& operator=(const DrmInfoEvent& ref);
-
 private:
     int mUniqueId;
     int mInfoType;
     const String8 mMessage;
-    KeyedVector<String8, String8> mAttributes;
-    DrmBuffer mDrmBuffer;
 };
 
 };
diff --git a/include/media/ExtendedAudioBufferProvider.h b/include/media/ExtendedAudioBufferProvider.h
index 00c4444..2539ed3 100644
--- a/include/media/ExtendedAudioBufferProvider.h
+++ b/include/media/ExtendedAudioBufferProvider.h
@@ -18,12 +18,20 @@
 #define ANDROID_EXTENDED_AUDIO_BUFFER_PROVIDER_H
 
 #include <media/AudioBufferProvider.h>
+#include <media/AudioTimestamp.h>
 
 namespace android {
 
 class ExtendedAudioBufferProvider : public AudioBufferProvider {
 public:
     virtual size_t  framesReady() const = 0;  // see description at AudioFlinger.h
+
+    // Return the total number of frames that have been obtained and released
+    virtual size_t  framesReleased() const { return 0; }
+
+    // Invoked by buffer consumer when a new timestamp is available.
+    // Default implementation ignores the timestamp.
+    virtual void    onTimestamp(const AudioTimestamp& timestamp) { }
 };
 
 }   // namespace android
diff --git a/include/media/IHDCP.h b/include/media/IHDCP.h
index 54fefa3..352561e 100644
--- a/include/media/IHDCP.h
+++ b/include/media/IHDCP.h
@@ -46,6 +46,17 @@
     // Request to shutdown the active HDCP session.
     virtual status_t shutdownAsync() = 0;
 
+    // Returns the capability bitmask of this HDCP session.
+    // Possible return values (please refer to HDCAPAPI.h):
+    //   HDCP_CAPS_ENCRYPT: mandatory, meaning the HDCP module can encrypt
+    //   from an input byte-array buffer to an output byte-array buffer
+    //   HDCP_CAPS_ENCRYPT_NATIVE: the HDCP module supports encryption from
+    //   a native buffer to an output byte-array buffer. The format of the
+    //   input native buffer is specific to vendor's encoder implementation.
+    //   It is the same format as that used by the encoder when
+    //   "storeMetaDataInBuffers" extension is enabled on its output port.
+    virtual uint32_t getCaps() = 0;
+
     // ENCRYPTION only:
     // Encrypt data according to the HDCP spec. "size" bytes of data are
     // available at "inData" (virtual address), "size" may not be a multiple
diff --git a/include/media/nbaio/AudioStreamOutSink.h b/include/media/nbaio/AudioStreamOutSink.h
index 5976b18..7948d40 100644
--- a/include/media/nbaio/AudioStreamOutSink.h
+++ b/include/media/nbaio/AudioStreamOutSink.h
@@ -52,6 +52,8 @@
     // implementation of GNWT (if any)
     virtual status_t getNextWriteTimestamp(int64_t *timestamp);
 
+    virtual status_t getTimestamp(AudioTimestamp& timestamp);
+
     // NBAIO_Sink end
 
 #if 0   // until necessary
diff --git a/include/media/nbaio/MonoPipe.h b/include/media/nbaio/MonoPipe.h
index 5fcfe9e..d3802fe 100644
--- a/include/media/nbaio/MonoPipe.h
+++ b/include/media/nbaio/MonoPipe.h
@@ -20,9 +20,12 @@
 #include <time.h>
 #include <utils/LinearTransform.h>
 #include "NBAIO.h"
+#include <media/SingleStateQueue.h>
 
 namespace android {
 
+typedef SingleStateQueue<AudioTimestamp> AudioTimestampSingleStateQueue;
+
 // MonoPipe is similar to Pipe except:
 //  - supports only a single reader, called MonoPipeReader
 //  - write() cannot overrun; instead it will return a short actual count if insufficient space
@@ -88,6 +91,9 @@
             // Return true if the write side of a pipe is currently shutdown.
             bool    isShutdown();
 
+            // Return NO_ERROR if there is a timestamp available
+            status_t getTimestamp(AudioTimestamp& timestamp);
+
 private:
     // A pair of methods and a helper variable which allows the reader and the
     // writer to update and observe the values of mFront and mNextRdPTS in an
@@ -127,6 +133,10 @@
     LinearTransform mSamplesToLocalTime;
 
     bool            mIsShutdown;    // whether shutdown(true) was called, no barriers are needed
+
+    AudioTimestampSingleStateQueue::Shared      mTimestampShared;
+    AudioTimestampSingleStateQueue::Mutator     mTimestampMutator;
+    AudioTimestampSingleStateQueue::Observer    mTimestampObserver;
 };
 
 }   // namespace android
diff --git a/include/media/nbaio/MonoPipeReader.h b/include/media/nbaio/MonoPipeReader.h
index 0e1c992..78fe867 100644
--- a/include/media/nbaio/MonoPipeReader.h
+++ b/include/media/nbaio/MonoPipeReader.h
@@ -49,6 +49,8 @@
 
     virtual ssize_t read(void *buffer, size_t count, int64_t readPTS);
 
+    virtual void    onTimestamp(const AudioTimestamp& timestamp);
+
     // NBAIO_Source end
 
 #if 0   // until necessary
diff --git a/include/media/nbaio/NBAIO.h b/include/media/nbaio/NBAIO.h
index f5d6eb5..1da0c73 100644
--- a/include/media/nbaio/NBAIO.h
+++ b/include/media/nbaio/NBAIO.h
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
+#include <media/AudioTimestamp.h>
 
 namespace android {
 
@@ -213,6 +214,11 @@
     //  <other> Something unexpected happened internally.  Check the logs and start debugging.
     virtual status_t getNextWriteTimestamp(int64_t *ts) { return INVALID_OPERATION; }
 
+    // Returns NO_ERROR if a timestamp is available.  The timestamp includes the total number
+    // of frames presented to an external observer, together with the value of CLOCK_MONOTONIC
+    // as of this presentation count.
+    virtual status_t getTimestamp(AudioTimestamp& timestamp) { return INVALID_OPERATION; }
+
 protected:
     NBAIO_Sink(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0) { }
     virtual ~NBAIO_Sink() { }
@@ -300,6 +306,10 @@
     virtual ssize_t readVia(readVia_t via, size_t total, void *user,
                             int64_t readPTS, size_t block = 0);
 
+    // Invoked asynchronously by corresponding sink when a new timestamp is available.
+    // Default implementation ignores the timestamp.
+    virtual void    onTimestamp(const AudioTimestamp& timestamp) { }
+
 protected:
     NBAIO_Source(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0) { }
     virtual ~NBAIO_Source() { }
diff --git a/include/media/nbaio/SourceAudioBufferProvider.h b/include/media/nbaio/SourceAudioBufferProvider.h
index c08331b..cdfb6fe 100644
--- a/include/media/nbaio/SourceAudioBufferProvider.h
+++ b/include/media/nbaio/SourceAudioBufferProvider.h
@@ -36,6 +36,8 @@
 
     // ExtendedAudioBufferProvider interface
     virtual size_t   framesReady() const;
+    virtual size_t   framesReleased() const;
+    virtual void     onTimestamp(const AudioTimestamp& timestamp);
 
 private:
     const sp<NBAIO_Source> mSource;     // the wrapped source
@@ -45,6 +47,7 @@
     size_t              mOffset;    // frame offset within mAllocated of valid data
     size_t              mRemaining; // frame count within mAllocated of valid data
     size_t              mGetCount;  // buffer.frameCount of the most recent getNextBuffer
+    uint32_t            mFramesReleased;    // counter of the total number of frames released
 };
 
 }   // namespace android
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 96755bb..56e7787 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -62,6 +62,7 @@
 LOCAL_CFLAGS += -DANDROID_SMP=$(if $(findstring true,$(TARGET_CPU_SMP)),1,0)
 LOCAL_SRC_FILES += SingleStateQueue.cpp
 LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiations.cpp"'
+# Consider a separate a library for SingleStateQueueInstantiations.
 
 LOCAL_SHARED_LIBRARIES := \
 	libui liblog libcutils libutils libbinder libsonivox libicuuc libexpat \
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 176197c..744faee 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1714,7 +1714,18 @@
 status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp)
 {
     AutoMutex lock(mLock);
-    return mAudioTrack->getTimestamp(timestamp);
+    // FIXME not implemented for fast tracks; should use proxy and SSQ
+    if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
+        return INVALID_OPERATION;
+    }
+    if (mState != STATE_ACTIVE && mState != STATE_PAUSED) {
+        return INVALID_OPERATION;
+    }
+    status_t status = mAudioTrack->getTimestamp(timestamp);
+    if (status == NO_ERROR) {
+        timestamp.mPosition += mProxy->getEpoch();
+    }
+    return status;
 }
 
 String8 AudioTrack::getParameters(const String8& keys)
diff --git a/media/libmedia/IHDCP.cpp b/media/libmedia/IHDCP.cpp
index a46ff91..1cf987a 100644
--- a/media/libmedia/IHDCP.cpp
+++ b/media/libmedia/IHDCP.cpp
@@ -30,6 +30,7 @@
     HDCP_SET_OBSERVER,
     HDCP_INIT_ASYNC,
     HDCP_SHUTDOWN_ASYNC,
+    HDCP_GET_CAPS,
     HDCP_ENCRYPT,
     HDCP_ENCRYPT_NATIVE,
     HDCP_DECRYPT,
@@ -85,6 +86,13 @@
         return reply.readInt32();
     }
 
+    virtual uint32_t getCaps() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IHDCP::getInterfaceDescriptor());
+        remote()->transact(HDCP_GET_CAPS, data, &reply);
+        return reply.readInt32();
+    }
+
     virtual status_t encrypt(
             const void *inData, size_t size, uint32_t streamCTR,
             uint64_t *outInputCTR, void *outData) {
@@ -222,6 +230,14 @@
             return OK;
         }
 
+        case HDCP_GET_CAPS:
+        {
+            CHECK_INTERFACE(IHDCP, data, reply);
+
+            reply->writeInt32(getCaps());
+            return OK;
+        }
+
         case HDCP_ENCRYPT:
         {
             size_t size = data.readInt32();
diff --git a/media/libmedia/SingleStateQueueInstantiations.cpp b/media/libmedia/SingleStateQueueInstantiations.cpp
index 2afebe9..0265c8c 100644
--- a/media/libmedia/SingleStateQueueInstantiations.cpp
+++ b/media/libmedia/SingleStateQueueInstantiations.cpp
@@ -16,11 +16,13 @@
 
 #include <media/SingleStateQueue.h>
 #include <private/media/StaticAudioTrackState.h>
+#include <media/AudioTimestamp.h>
 
 // FIXME hack for gcc
 
 namespace android {
 
 template class SingleStateQueue<StaticAudioTrackState>; // typedef StaticAudioTrackSingleStateQueue
+template class SingleStateQueue<AudioTimestamp>;        // typedef AudioTimestampSingleStateQueue
 
 }
diff --git a/media/libmediaplayerservice/HDCP.cpp b/media/libmediaplayerservice/HDCP.cpp
index 8a3188c..c2ac1a3 100644
--- a/media/libmediaplayerservice/HDCP.cpp
+++ b/media/libmediaplayerservice/HDCP.cpp
@@ -100,6 +100,20 @@
     return mHDCPModule->shutdownAsync();
 }
 
+uint32_t HDCP::getCaps() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mHDCPModule == NULL) {
+        return NO_INIT;
+    }
+
+    // TO-DO:
+    // Only support HDCP_CAPS_ENCRYPT (byte-array to byte-array) for now.
+    // use mHDCPModule->getCaps() when the HDCP libraries get updated.
+    //return mHDCPModule->getCaps();
+    return HDCPModule::HDCP_CAPS_ENCRYPT;
+}
+
 status_t HDCP::encrypt(
         const void *inData, size_t size, uint32_t streamCTR,
         uint64_t *outInputCTR, void *outData) {
diff --git a/media/libmediaplayerservice/HDCP.h b/media/libmediaplayerservice/HDCP.h
index c60c2e0..26ddc86 100644
--- a/media/libmediaplayerservice/HDCP.h
+++ b/media/libmediaplayerservice/HDCP.h
@@ -30,6 +30,7 @@
     virtual status_t setObserver(const sp<IHDCPObserver> &observer);
     virtual status_t initAsync(const char *host, unsigned port);
     virtual status_t shutdownAsync();
+    virtual uint32_t getCaps();
 
     virtual status_t encrypt(
             const void *inData, size_t size, uint32_t streamCTR,
diff --git a/media/libnbaio/Android.mk b/media/libnbaio/Android.mk
index 5d00d15..69c75b8 100644
--- a/media/libnbaio/Android.mk
+++ b/media/libnbaio/Android.mk
@@ -31,6 +31,9 @@
     libcommon_time_client \
     libcutils \
     libutils \
-    liblog
+    liblog \
+    libmedia
+# This dependency on libmedia is for SingleStateQueueInstantiations.
+# Consider a separate a library for SingleStateQueueInstantiations.
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp
index 6f525e5..e4341d7 100644
--- a/media/libnbaio/AudioStreamOutSink.cpp
+++ b/media/libnbaio/AudioStreamOutSink.cpp
@@ -79,4 +79,19 @@
     return mStream->get_next_write_timestamp(mStream, timestamp);
 }
 
+status_t AudioStreamOutSink::getTimestamp(AudioTimestamp& timestamp)
+{
+    if (mStream->get_presentation_position == NULL) {
+        return INVALID_OPERATION;
+    }
+    // FIXME position64 won't be needed after AudioTimestamp.mPosition is changed to uint64_t
+    uint64_t position64;
+    int ok = mStream->get_presentation_position(mStream, &position64, &timestamp.mTime);
+    if (ok != 0) {
+        return INVALID_OPERATION;
+    }
+    timestamp.mPosition = position64;
+    return OK;
+}
+
 }   // namespace android
diff --git a/media/libnbaio/MonoPipe.cpp b/media/libnbaio/MonoPipe.cpp
index e8d3d9b..de0ad28 100644
--- a/media/libnbaio/MonoPipe.cpp
+++ b/media/libnbaio/MonoPipe.cpp
@@ -42,7 +42,10 @@
         // mWriteTs
         mSetpoint((reqFrames * 11) / 16),
         mWriteCanBlock(writeCanBlock),
-        mIsShutdown(false)
+        mIsShutdown(false),
+        // mTimestampShared
+        mTimestampMutator(&mTimestampShared),
+        mTimestampObserver(&mTimestampShared)
 {
     CCHelper tmpHelper;
     status_t res;
@@ -310,4 +313,12 @@
     return mIsShutdown;
 }
 
+status_t MonoPipe::getTimestamp(AudioTimestamp& timestamp)
+{
+    if (mTimestampObserver.poll(timestamp)) {
+        return OK;
+    }
+    return INVALID_OPERATION;
+}
+
 }   // namespace android
diff --git a/media/libnbaio/MonoPipeReader.cpp b/media/libnbaio/MonoPipeReader.cpp
index 394f6ac..851341a 100644
--- a/media/libnbaio/MonoPipeReader.cpp
+++ b/media/libnbaio/MonoPipeReader.cpp
@@ -86,4 +86,9 @@
     return red;
 }
 
+void MonoPipeReader::onTimestamp(const AudioTimestamp& timestamp)
+{
+    mPipe->mTimestampMutator.push(timestamp);
+}
+
 }   // namespace android
diff --git a/media/libnbaio/SourceAudioBufferProvider.cpp b/media/libnbaio/SourceAudioBufferProvider.cpp
index d11a86c..062fa0f 100644
--- a/media/libnbaio/SourceAudioBufferProvider.cpp
+++ b/media/libnbaio/SourceAudioBufferProvider.cpp
@@ -25,7 +25,7 @@
 SourceAudioBufferProvider::SourceAudioBufferProvider(const sp<NBAIO_Source>& source) :
     mSource(source),
     // mFrameBitShiftFormat below
-    mAllocated(NULL), mSize(0), mOffset(0), mRemaining(0), mGetCount(0)
+    mAllocated(NULL), mSize(0), mOffset(0), mRemaining(0), mGetCount(0), mFramesReleased(0)
 {
     ALOG_ASSERT(source != 0);
 
@@ -90,6 +90,7 @@
             (mOffset + mRemaining <= mSize));
     mOffset += buffer->frameCount;
     mRemaining -= buffer->frameCount;
+    mFramesReleased += buffer->frameCount;
     buffer->raw = NULL;
     buffer->frameCount = 0;
     mGetCount = 0;
@@ -101,4 +102,14 @@
     return avail < 0 ? 0 : (size_t) avail;
 }
 
+size_t SourceAudioBufferProvider::framesReleased() const
+{
+    return mFramesReleased;
+}
+
+void SourceAudioBufferProvider::onTimestamp(const AudioTimestamp& timestamp)
+{
+    mSource->onTimestamp(timestamp);
+}
+
 }   // namespace android
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index c9b5d26..1b20cbb 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -58,8 +58,6 @@
       mIsADTS(false),
       mInputBufferCount(0),
       mSignalledError(false),
-      mSawInputEos(false),
-      mSignalledOutputEos(false),
       mAnchorTimeUs(0),
       mNumSamplesOutput(0),
       mOutputPortSettingsChange(NONE) {
@@ -352,83 +350,115 @@
         return;
     }
 
-    while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
-        BufferInfo *inInfo = NULL;
-        OMX_BUFFERHEADERTYPE *inHeader = NULL;
-        if (!inQueue.empty()) {
-            inInfo = *inQueue.begin();
-            inHeader = inInfo->mHeader;
-        }
+    while (!inQueue.empty() && !outQueue.empty()) {
+        BufferInfo *inInfo = *inQueue.begin();
+        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
 
         BufferInfo *outInfo = *outQueue.begin();
         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
-        outHeader->nFlags = 0;
 
-        if (inHeader) {
-            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
-                mSawInputEos = true;
-            }
+        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+            inQueue.erase(inQueue.begin());
+            inInfo->mOwnedByUs = false;
+            notifyEmptyBufferDone(inHeader);
 
-            if (inHeader->nOffset == 0 && inHeader->nFilledLen) {
-                mAnchorTimeUs = inHeader->nTimeStamp;
-                mNumSamplesOutput = 0;
-            }
+            if (mDecoderHasData) {
+                // flush out the decoder's delayed data by calling DecodeFrame
+                // one more time, with the AACDEC_FLUSH flag set
+                INT_PCM *outBuffer =
+                        reinterpret_cast<INT_PCM *>(
+                                outHeader->pBuffer + outHeader->nOffset);
 
-            if (mIsADTS) {
-                size_t adtsHeaderSize = 0;
-                // skip 30 bits, aac_frame_length follows.
-                // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
+                AAC_DECODER_ERROR decoderErr =
+                    aacDecoder_DecodeFrame(mAACDecoder,
+                                           outBuffer,
+                                           outHeader->nAllocLen,
+                                           AACDEC_FLUSH);
+                mDecoderHasData = false;
 
-                const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;
-
-                bool signalError = false;
-                if (inHeader->nFilledLen < 7) {
-                    ALOGE("Audio data too short to contain even the ADTS header. "
-                          "Got %ld bytes.", inHeader->nFilledLen);
-                    hexdump(adtsHeader, inHeader->nFilledLen);
-                    signalError = true;
-                } else {
-                    bool protectionAbsent = (adtsHeader[1] & 1);
-
-                    unsigned aac_frame_length =
-                        ((adtsHeader[3] & 3) << 11)
-                        | (adtsHeader[4] << 3)
-                        | (adtsHeader[5] >> 5);
-
-                    if (inHeader->nFilledLen < aac_frame_length) {
-                        ALOGE("Not enough audio data for the complete frame. "
-                              "Got %ld bytes, frame size according to the ADTS "
-                              "header is %u bytes.",
-                              inHeader->nFilledLen, aac_frame_length);
-                        hexdump(adtsHeader, inHeader->nFilledLen);
-                        signalError = true;
-                    } else {
-                        adtsHeaderSize = (protectionAbsent ? 7 : 9);
-
-                        inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize;
-                        inBufferLength[0] = aac_frame_length - adtsHeaderSize;
-
-                        inHeader->nOffset += adtsHeaderSize;
-                        inHeader->nFilledLen -= adtsHeaderSize;
-                    }
-                }
-
-                if (signalError) {
+                if (decoderErr != AAC_DEC_OK) {
                     mSignalledError = true;
 
-                    notify(OMX_EventError,
-                           OMX_ErrorStreamCorrupt,
-                           ERROR_MALFORMED,
+                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr,
                            NULL);
 
                     return;
                 }
+
+                outHeader->nFilledLen =
+                        mStreamInfo->frameSize
+                            * sizeof(int16_t)
+                            * mStreamInfo->numChannels;
             } else {
-                inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
-                inBufferLength[0] = inHeader->nFilledLen;
+                // we never submitted any data to the decoder, so there's nothing to flush out
+                outHeader->nFilledLen = 0;
+            }
+
+            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+            outQueue.erase(outQueue.begin());
+            outInfo->mOwnedByUs = false;
+            notifyFillBufferDone(outHeader);
+            return;
+        }
+
+        if (inHeader->nOffset == 0) {
+            mAnchorTimeUs = inHeader->nTimeStamp;
+            mNumSamplesOutput = 0;
+        }
+
+        size_t adtsHeaderSize = 0;
+        if (mIsADTS) {
+            // skip 30 bits, aac_frame_length follows.
+            // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
+
+            const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;
+
+            bool signalError = false;
+            if (inHeader->nFilledLen < 7) {
+                ALOGE("Audio data too short to contain even the ADTS header. "
+                      "Got %ld bytes.", inHeader->nFilledLen);
+                hexdump(adtsHeader, inHeader->nFilledLen);
+                signalError = true;
+            } else {
+                bool protectionAbsent = (adtsHeader[1] & 1);
+
+                unsigned aac_frame_length =
+                    ((adtsHeader[3] & 3) << 11)
+                    | (adtsHeader[4] << 3)
+                    | (adtsHeader[5] >> 5);
+
+                if (inHeader->nFilledLen < aac_frame_length) {
+                    ALOGE("Not enough audio data for the complete frame. "
+                          "Got %ld bytes, frame size according to the ADTS "
+                          "header is %u bytes.",
+                          inHeader->nFilledLen, aac_frame_length);
+                    hexdump(adtsHeader, inHeader->nFilledLen);
+                    signalError = true;
+                } else {
+                    adtsHeaderSize = (protectionAbsent ? 7 : 9);
+
+                    inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize;
+                    inBufferLength[0] = aac_frame_length - adtsHeaderSize;
+
+                    inHeader->nOffset += adtsHeaderSize;
+                    inHeader->nFilledLen -= adtsHeaderSize;
+                }
+            }
+
+            if (signalError) {
+                mSignalledError = true;
+
+                notify(OMX_EventError,
+                       OMX_ErrorStreamCorrupt,
+                       ERROR_MALFORMED,
+                       NULL);
+
+                return;
             }
         } else {
-            inBufferLength[0] = 0;
+            inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
+            inBufferLength[0] = inHeader->nFilledLen;
         }
 
         // Fill and decode
@@ -441,66 +471,50 @@
         int prevNumChannels = mStreamInfo->numChannels;
 
         AAC_DECODER_ERROR decoderErr = AAC_DEC_NOT_ENOUGH_BITS;
-        while ((bytesValid[0] > 0 || mSawInputEos) && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
-            mDecoderHasData |= (bytesValid[0] > 0);
+        while (bytesValid[0] > 0 && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
             aacDecoder_Fill(mAACDecoder,
                             inBuffer,
                             inBufferLength,
                             bytesValid);
+            mDecoderHasData = true;
 
             decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
                                                 outBuffer,
                                                 outHeader->nAllocLen,
                                                 0 /* flags */);
+
             if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
-                if (mSawInputEos && bytesValid[0] <= 0) {
-                    if (mDecoderHasData) {
-                        // flush out the decoder's delayed data by calling DecodeFrame
-                        // one more time, with the AACDEC_FLUSH flag set
-                        decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
-                                                            outBuffer,
-                                                            outHeader->nAllocLen,
-                                                            AACDEC_FLUSH);
-                        mDecoderHasData = false;
-                    }
-                    outHeader->nFlags = OMX_BUFFERFLAG_EOS;
-                    mSignalledOutputEos = true;
-                    break;
-                } else {
-                    ALOGW("Not enough bits, bytesValid %d", bytesValid[0]);
-                }
+                ALOGW("Not enough bits, bytesValid %d", bytesValid[0]);
             }
         }
 
         size_t numOutBytes =
             mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
 
-        if (inHeader) {
-            if (decoderErr == AAC_DEC_OK) {
-                UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
-                inHeader->nFilledLen -= inBufferUsedLength;
-                inHeader->nOffset += inBufferUsedLength;
-            } else {
-                ALOGW("AAC decoder returned error %d, substituting silence",
-                      decoderErr);
+        if (decoderErr == AAC_DEC_OK) {
+            UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
+            inHeader->nFilledLen -= inBufferUsedLength;
+            inHeader->nOffset += inBufferUsedLength;
+        } else {
+            ALOGW("AAC decoder returned error %d, substituting silence",
+                  decoderErr);
 
-                memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes);
+            memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes);
 
-                // Discard input buffer.
-                inHeader->nFilledLen = 0;
+            // Discard input buffer.
+            inHeader->nFilledLen = 0;
 
-                aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
+            aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
 
-                // fall through
-            }
+            // fall through
+        }
 
-            if (inHeader->nFilledLen == 0) {
-                inInfo->mOwnedByUs = false;
-                inQueue.erase(inQueue.begin());
-                inInfo = NULL;
-                notifyEmptyBufferDone(inHeader);
-                inHeader = NULL;
-            }
+        if (inHeader->nFilledLen == 0) {
+            inInfo->mOwnedByUs = false;
+            inQueue.erase(inQueue.begin());
+            inInfo = NULL;
+            notifyEmptyBufferDone(inHeader);
+            inHeader = NULL;
         }
 
         /*
@@ -541,6 +555,7 @@
             // we've previously decoded valid data, in the latter case
             // (decode failed) we'll output a silent frame.
             outHeader->nFilledLen = numOutBytes;
+            outHeader->nFlags = 0;
 
             outHeader->nTimeStamp =
                 mAnchorTimeUs
@@ -591,8 +606,6 @@
     mStreamInfo->sampleRate = 0;
 
     mSignalledError = false;
-    mSawInputEos = false;
-    mSignalledOutputEos = false;
     mOutputPortSettingsChange = NONE;
 }
 
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h
index a7ea1e2..2d960ab 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h
@@ -55,8 +55,6 @@
     bool mDecoderHasData;
     size_t mInputBufferCount;
     bool mSignalledError;
-    bool mSawInputEos;
-    bool mSignalledOutputEos;
     int64_t mAnchorTimeUs;
     int64_t mNumSamplesOutput;
 
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
index 5749733..ff2b503 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
@@ -292,6 +292,10 @@
         return AOT_AAC_LC;
     } else if (profile == OMX_AUDIO_AACObjectHE) {
         return AOT_SBR;
+    } else if (profile == OMX_AUDIO_AACObjectHE_PS) {
+        return AOT_PS;
+    } else if (profile == OMX_AUDIO_AACObjectLD) {
+        return AOT_ER_AAC_LD;
     } else if (profile == OMX_AUDIO_AACObjectELD) {
         return AOT_ER_AAC_ELD;
     } else {
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index 877e3cb..7c382fb 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -49,8 +49,6 @@
       mNumChannels(2),
       mSamplingRate(44100),
       mSignalledError(false),
-      mSawInputEos(false),
-      mSignalledOutputEos(false),
       mOutputPortSettingsChange(NONE) {
     initPorts();
     initDecoder();
@@ -196,36 +194,48 @@
     List<BufferInfo *> &inQueue = getPortQueue(0);
     List<BufferInfo *> &outQueue = getPortQueue(1);
 
-    while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
-        BufferInfo *inInfo = NULL;
-        OMX_BUFFERHEADERTYPE *inHeader = NULL;
-        if (!inQueue.empty()) {
-            inInfo = *inQueue.begin();
-            inHeader = inInfo->mHeader;
-        }
+    while (!inQueue.empty() && !outQueue.empty()) {
+        BufferInfo *inInfo = *inQueue.begin();
+        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
 
         BufferInfo *outInfo = *outQueue.begin();
         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
-        outHeader->nFlags = 0;
 
-        if (inHeader) {
-            if (inHeader->nOffset == 0 && inHeader->nFilledLen) {
-                mAnchorTimeUs = inHeader->nTimeStamp;
-                mNumFramesOutput = 0;
+        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+            inQueue.erase(inQueue.begin());
+            inInfo->mOwnedByUs = false;
+            notifyEmptyBufferDone(inHeader);
+
+            if (!mIsFirst) {
+                // pad the end of the stream with 529 samples, since that many samples
+                // were trimmed off the beginning when decoding started
+                outHeader->nFilledLen =
+                    kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);
+
+                memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
+            } else {
+                // Since we never discarded frames from the start, we won't have
+                // to add any padding at the end either.
+                outHeader->nFilledLen = 0;
             }
 
-            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
-                mSawInputEos = true;
-            }
+            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
 
-            mConfig->pInputBuffer =
-                inHeader->pBuffer + inHeader->nOffset;
-
-            mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
-        } else {
-            mConfig->pInputBuffer = NULL;
-            mConfig->inputBufferCurrentLength = 0;
+            outQueue.erase(outQueue.begin());
+            outInfo->mOwnedByUs = false;
+            notifyFillBufferDone(outHeader);
+            return;
         }
+
+        if (inHeader->nOffset == 0) {
+            mAnchorTimeUs = inHeader->nTimeStamp;
+            mNumFramesOutput = 0;
+        }
+
+        mConfig->pInputBuffer =
+            inHeader->pBuffer + inHeader->nOffset;
+
+        mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
         mConfig->inputBufferMaxLength = 0;
         mConfig->inputBufferUsedLength = 0;
 
@@ -252,28 +262,13 @@
                 mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
             }
 
-            if (decoderErr == NO_ENOUGH_MAIN_DATA_ERROR && mSawInputEos) {
-                if (!mIsFirst) {
-                    // pad the end of the stream with 529 samples, since that many samples
-                    // were trimmed off the beginning when decoding started
-                    outHeader->nOffset = 0;
-                    outHeader->nFilledLen = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);
+            // This is recoverable, just ignore the current frame and
+            // play silence instead.
+            memset(outHeader->pBuffer,
+                   0,
+                   mConfig->outputFrameSize * sizeof(int16_t));
 
-                    memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
-                }
-                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
-                mSignalledOutputEos = true;
-            } else {
-                // This is recoverable, just ignore the current frame and
-                // play silence instead.
-                memset(outHeader->pBuffer,
-                       0,
-                       mConfig->outputFrameSize * sizeof(int16_t));
-
-                if (inHeader) {
-                    mConfig->inputBufferUsedLength = inHeader->nFilledLen;
-                }
-            }
+            mConfig->inputBufferUsedLength = inHeader->nFilledLen;
         } else if (mConfig->samplingRate != mSamplingRate
                 || mConfig->num_channels != mNumChannels) {
             mSamplingRate = mConfig->samplingRate;
@@ -294,7 +289,7 @@
 
             outHeader->nFilledLen =
                 mConfig->outputFrameSize * sizeof(int16_t) - outHeader->nOffset;
-        } else if (!mSignalledOutputEos) {
+        } else {
             outHeader->nOffset = 0;
             outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t);
         }
@@ -303,24 +298,23 @@
             mAnchorTimeUs
                 + (mNumFramesOutput * 1000000ll) / mConfig->samplingRate;
 
-        if (inHeader) {
-            CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);
+        outHeader->nFlags = 0;
 
-            inHeader->nOffset += mConfig->inputBufferUsedLength;
-            inHeader->nFilledLen -= mConfig->inputBufferUsedLength;
+        CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);
 
-
-            if (inHeader->nFilledLen == 0) {
-                inInfo->mOwnedByUs = false;
-                inQueue.erase(inQueue.begin());
-                inInfo = NULL;
-                notifyEmptyBufferDone(inHeader);
-                inHeader = NULL;
-            }
-        }
+        inHeader->nOffset += mConfig->inputBufferUsedLength;
+        inHeader->nFilledLen -= mConfig->inputBufferUsedLength;
 
         mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;
 
+        if (inHeader->nFilledLen == 0) {
+            inInfo->mOwnedByUs = false;
+            inQueue.erase(inQueue.begin());
+            inInfo = NULL;
+            notifyEmptyBufferDone(inHeader);
+            inHeader = NULL;
+        }
+
         outInfo->mOwnedByUs = false;
         outQueue.erase(outQueue.begin());
         outInfo = NULL;
@@ -368,8 +362,6 @@
     pvmp3_InitDecoder(mConfig, mDecoderBuf);
     mIsFirst = true;
     mSignalledError = false;
-    mSawInputEos = false;
-    mSignalledOutputEos = false;
     mOutputPortSettingsChange = NONE;
 }
 
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.h b/media/libstagefright/codecs/mp3dec/SoftMP3.h
index f9e7b53..4af91ea 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.h
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.h
@@ -61,8 +61,6 @@
 
     bool mIsFirst;
     bool mSignalledError;
-    bool mSawInputEos;
-    bool mSignalledOutputEos;
 
     enum {
         NONE,
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index a377b23..51bb958 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -54,8 +54,6 @@
       mAnchorTimeUs(0),
       mNumFramesOutput(0),
       mNumFramesLeftOnPage(-1),
-      mSawInputEos(false),
-      mSignalledOutputEos(false),
       mOutputPortSettingsChange(NONE) {
     initPorts();
     CHECK_EQ(initDecoder(), (status_t)OK);
@@ -292,47 +290,48 @@
         return;
     }
 
-    while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
-        BufferInfo *inInfo = NULL;
-        OMX_BUFFERHEADERTYPE *inHeader = NULL;
-        if (!inQueue.empty()) {
-            inInfo = *inQueue.begin();
-            inHeader = inInfo->mHeader;
-        }
+    while (!inQueue.empty() && !outQueue.empty()) {
+        BufferInfo *inInfo = *inQueue.begin();
+        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
 
         BufferInfo *outInfo = *outQueue.begin();
         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
 
-        int32_t numPageSamples = 0;
+        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+            inQueue.erase(inQueue.begin());
+            inInfo->mOwnedByUs = false;
+            notifyEmptyBufferDone(inHeader);
 
-        if (inHeader) {
-            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
-                mSawInputEos = true;
-            }
+            outHeader->nFilledLen = 0;
+            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
 
-            if (inHeader->nFilledLen || !mSawInputEos) {
-                CHECK_GE(inHeader->nFilledLen, sizeof(numPageSamples));
-                memcpy(&numPageSamples,
-                       inHeader->pBuffer
-                        + inHeader->nOffset + inHeader->nFilledLen - 4,
-                       sizeof(numPageSamples));
-
-                if (inHeader->nOffset == 0) {
-                    mAnchorTimeUs = inHeader->nTimeStamp;
-                    mNumFramesOutput = 0;
-                }
-
-                inHeader->nFilledLen -= sizeof(numPageSamples);;
-            }
+            outQueue.erase(outQueue.begin());
+            outInfo->mOwnedByUs = false;
+            notifyFillBufferDone(outHeader);
+            return;
         }
 
+        int32_t numPageSamples;
+        CHECK_GE(inHeader->nFilledLen, sizeof(numPageSamples));
+        memcpy(&numPageSamples,
+               inHeader->pBuffer
+                + inHeader->nOffset + inHeader->nFilledLen - 4,
+               sizeof(numPageSamples));
+
         if (numPageSamples >= 0) {
             mNumFramesLeftOnPage = numPageSamples;
         }
 
+        if (inHeader->nOffset == 0) {
+            mAnchorTimeUs = inHeader->nTimeStamp;
+            mNumFramesOutput = 0;
+        }
+
+        inHeader->nFilledLen -= sizeof(numPageSamples);;
+
         ogg_buffer buf;
-        buf.data = inHeader ? inHeader->pBuffer + inHeader->nOffset : NULL;
-        buf.size = inHeader ? inHeader->nFilledLen : 0;
+        buf.data = inHeader->pBuffer + inHeader->nOffset;
+        buf.size = inHeader->nFilledLen;
         buf.refcount = 1;
         buf.ptr.owner = NULL;
 
@@ -385,13 +384,11 @@
 
         mNumFramesOutput += numFrames;
 
-        if (inHeader) {
-            inInfo->mOwnedByUs = false;
-            inQueue.erase(inQueue.begin());
-            inInfo = NULL;
-            notifyEmptyBufferDone(inHeader);
-            inHeader = NULL;
-        }
+        inInfo->mOwnedByUs = false;
+        inQueue.erase(inQueue.begin());
+        inInfo = NULL;
+        notifyEmptyBufferDone(inHeader);
+        inHeader = NULL;
 
         outInfo->mOwnedByUs = false;
         outQueue.erase(outQueue.begin());
@@ -428,8 +425,6 @@
         mVi = NULL;
     }
 
-    mSawInputEos = false;
-    mSignalledOutputEos = false;
     mOutputPortSettingsChange = NONE;
 }
 
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
index 1d00816..cb628a0 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
@@ -59,8 +59,6 @@
     int64_t mAnchorTimeUs;
     int64_t mNumFramesOutput;
     int32_t mNumFramesLeftOnPage;
-    bool mSawInputEos;
-    bool mSignalledOutputEos;
 
     enum {
         NONE,
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 9f3b19c..8f9c9c8 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -504,15 +504,11 @@
 
         if (first) {
             timeUs = info->mTimestampUs;
+            first = false;
         }
 
         if (info->mLength > size) {
             info->mLength -= size;
-
-            if (first) {
-                info->mTimestampUs = -1;
-            }
-
             size = 0;
         } else {
             size -= info->mLength;
@@ -521,7 +517,6 @@
             info = NULL;
         }
 
-        first = false;
     }
 
     if (timeUs == 0ll) {
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index 0aa4ee5..286ea13 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -939,7 +939,8 @@
     if (isVideo) {
         format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
         format->setInt32("store-metadata-in-buffers", true);
-        format->setInt32("store-metadata-in-buffers-output", (mHDCP != NULL));
+        format->setInt32("store-metadata-in-buffers-output", (mHDCP != NULL)
+                && (mHDCP->getCaps() & HDCPModule::HDCP_CAPS_ENCRYPT_NATIVE));
         format->setInt32(
                 "color-format", OMX_COLOR_FormatAndroidOpaque);
         format->setInt32("profile-idc", profileIdc);
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index ad9f4f2..f27ea17 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -96,6 +96,12 @@
     uint32_t warmupCycles = 0;  // counter of number of loop cycles required to warmup
     NBAIO_Sink* teeSink = NULL; // if non-NULL, then duplicate write() to this non-blocking sink
     NBLog::Writer dummyLogWriter, *logWriter = &dummyLogWriter;
+    uint32_t totalNativeFramesWritten = 0;  // copied to dumpState->mFramesWritten
+
+    // next 2 fields are valid only when timestampStatus == NO_ERROR
+    AudioTimestamp timestamp;
+    uint32_t nativeFramesWrittenButNotPresented = 0;    // the = 0 is to silence the compiler
+    status_t timestampStatus = INVALID_OPERATION;
 
     for (;;) {
 
@@ -192,6 +198,7 @@
                 full = false;
 #endif
                 oldTsValid = !clock_gettime(CLOCK_MONOTONIC, &oldTs);
+                timestampStatus = INVALID_OPERATION;
             } else {
                 sleepNs = FAST_HOT_IDLE_NS;
             }
@@ -382,6 +389,31 @@
                 i = __builtin_ctz(currentTrackMask);
                 currentTrackMask &= ~(1 << i);
                 const FastTrack* fastTrack = &current->mFastTracks[i];
+
+                // Refresh the per-track timestamp
+                if (timestampStatus == NO_ERROR) {
+                    uint32_t trackFramesWrittenButNotPresented;
+                    uint32_t trackSampleRate = fastTrack->mSampleRate;
+                    // There is currently no sample rate conversion for fast tracks currently
+                    if (trackSampleRate != 0 && trackSampleRate != sampleRate) {
+                        trackFramesWrittenButNotPresented =
+                                ((int64_t) nativeFramesWrittenButNotPresented * trackSampleRate) /
+                                sampleRate;
+                    } else {
+                        trackFramesWrittenButNotPresented = nativeFramesWrittenButNotPresented;
+                    }
+                    uint32_t trackFramesWritten = fastTrack->mBufferProvider->framesReleased();
+                    // Can't provide an AudioTimestamp before first frame presented,
+                    // or during the brief 32-bit wraparound window
+                    if (trackFramesWritten >= trackFramesWrittenButNotPresented) {
+                        AudioTimestamp perTrackTimestamp;
+                        perTrackTimestamp.mPosition =
+                                trackFramesWritten - trackFramesWrittenButNotPresented;
+                        perTrackTimestamp.mTime = timestamp.mTime;
+                        fastTrack->mBufferProvider->onTimestamp(perTrackTimestamp);
+                    }
+                }
+
                 int name = fastTrackNames[i];
                 ALOG_ASSERT(name >= 0);
                 if (fastTrack->mVolumeProvider != NULL) {
@@ -455,7 +487,8 @@
             dumpState->mWriteSequence++;
             if (framesWritten >= 0) {
                 ALOG_ASSERT((size_t) framesWritten <= frameCount);
-                dumpState->mFramesWritten += framesWritten;
+                totalNativeFramesWritten += framesWritten;
+                dumpState->mFramesWritten = totalNativeFramesWritten;
                 //if ((size_t) framesWritten == frameCount) {
                 //    didFullWrite = true;
                 //}
@@ -464,6 +497,18 @@
             }
             attemptedWrite = true;
             // FIXME count # of writes blocked excessively, CPU usage, etc. for dump
+
+            timestampStatus = outputSink->getTimestamp(timestamp);
+            if (timestampStatus == NO_ERROR) {
+                uint32_t totalNativeFramesPresented = timestamp.mPosition;
+                if (totalNativeFramesPresented <= totalNativeFramesWritten) {
+                    nativeFramesWrittenButNotPresented =
+                        totalNativeFramesWritten - totalNativeFramesPresented;
+                } else {
+                    // HAL reported that more frames were presented than were written
+                    timestampStatus = INVALID_OPERATION;
+                }
+            }
         }
 
         // To be exactly periodic, compute the next sleep time based on current time.
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index d34833f..0308b99 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -81,7 +81,9 @@
                                    int64_t pts = kInvalidPTS);
     // releaseBuffer() not overridden
 
+    // ExtendedAudioBufferProvider interface
     virtual size_t framesReady() const;
+    virtual size_t framesReleased() const;
 
     bool isPausing() const { return mState == PAUSING; }
     bool isPaused() const { return mState == PAUSED; }
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index bc01ede..fda4211 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1820,7 +1820,7 @@
         } else {
             bytesWritten = framesWritten;
         }
-        status_t status = INVALID_OPERATION;    // mLatchD.mTimestamp is invalid
+        status_t status = mNormalSink->getTimestamp(mLatchD.mTimestamp);
         if (status == NO_ERROR) {
             size_t totalFramesWritten = mNormalSink->framesWritten();
             if (totalFramesWritten >= mLatchD.mTimestamp.mPosition) {
@@ -1837,6 +1837,8 @@
             ALOG_ASSERT(mCallbackThread != 0);
             mCallbackThread->setWriteBlocked(true);
         }
+        // FIXME We should have an implementation of timestamps for direct output threads.
+        // They are used e.g for multichannel PCM playback over HDMI.
         bytesWritten = mOutput->stream->write(mOutput->stream,
                                                    mMixBuffer + offset, mBytesRemaining);
         if (mUseAsyncWrite &&
@@ -3810,10 +3812,6 @@
     size_t count = mActiveTracks.size();
 
     mixer_state mixerStatus = MIXER_IDLE;
-    if (mFlushPending) {
-        flushHw_l();
-        mFlushPending = false;
-    }
     // find out which tracks need to be processed
     for (size_t i = 0; i < count; i++) {
         sp<Track> t = mActiveTracks[i].promote();
@@ -3938,6 +3936,12 @@
         // compute volume for this track
         processVolume_l(track, last);
     }
+
+    if (mFlushPending) {
+        flushHw_l();
+        mFlushPending = false;
+    }
+
     // remove all the tracks that need to be...
     removeTracks_l(*tracksToRemove);
 
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 9622709..2042050 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -498,6 +498,10 @@
     return status;
 }
 
+// releaseBuffer() is not overridden
+
+// ExtendedAudioBufferProvider interface
+
 // Note that framesReady() takes a mutex on the control block using tryLock().
 // This could result in priority inversion if framesReady() is called by the normal mixer,
 // as the normal mixer thread runs at lower
@@ -510,6 +514,11 @@
     return mAudioTrackServerProxy->framesReady();
 }
 
+size_t AudioFlinger::PlaybackThread::Track::framesReleased() const
+{
+    return mAudioTrackServerProxy->framesReleased();
+}
+
 // Don't call for fast tracks; the framesReady() could result in priority inversion
 bool AudioFlinger::PlaybackThread::Track::isReady() const {
     if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing()) {
@@ -718,9 +727,13 @@
 
 status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& timestamp)
 {
+    // Client should implement this using SSQ; the unpresented frame count in latch is irrelevant
+    if (isFastTrack()) {
+        return INVALID_OPERATION;
+    }
     sp<ThreadBase> thread = mThread.promote();
     if (thread == 0) {
-        return false;
+        return INVALID_OPERATION;
     }
     Mutex::Autolock _l(thread->mLock);
     PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index bf9bc71..fe16314 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -492,7 +492,7 @@
           case CAMERA_DEVICE_API_VERSION_1_0:
             ALOGE("Camera id %d uses HALv1, doesn't support ProCamera",
                   cameraId);
-            return -ENOTSUP;
+            return -EOPNOTSUPP;
             break;
           case CAMERA_DEVICE_API_VERSION_2_0:
           case CAMERA_DEVICE_API_VERSION_2_1:
@@ -570,7 +570,7 @@
         switch(deviceVersion) {
           case CAMERA_DEVICE_API_VERSION_1_0:
             ALOGW("Camera using old HAL version: %d", deviceVersion);
-            return -ENOTSUP;
+            return -EOPNOTSUPP;
            // TODO: don't allow 2.0  Only allow 2.1 and higher
           case CAMERA_DEVICE_API_VERSION_2_0:
           case CAMERA_DEVICE_API_VERSION_2_1:
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 3d9fe01..0a18501 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -854,6 +854,7 @@
             // no break
         case Parameters::RECORD:
         case Parameters::PREVIEW:
+            syncWithDevice();
             res = stopStream();
             if (res != OK) {
                 ALOGE("%s: Camera %d: Can't stop streaming: %s (%d)",
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index 76750aa..7ad461a 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -100,7 +100,7 @@
      * Internal to CaptureSequencer
      */
     static const nsecs_t kWaitDuration = 100000000; // 100 ms
-    static const int kMaxTimeoutsForPrecaptureStart = 2; // 200 ms
+    static const int kMaxTimeoutsForPrecaptureStart = 10; // 1 sec
     static const int kMaxTimeoutsForPrecaptureEnd = 20;  // 2 sec
     static const int kMaxTimeoutsForCaptureEnd    = 40;  // 4 sec