Merge "SoftAVCEnc: Modified the code for runtime change in params to be generic" into nyc-dev
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index eacb32e..ca68722 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -33,6 +33,7 @@
 #include <binder/ProcessState.h>
 #include <media/ICrypto.h>
 #include <media/IMediaHTTPService.h>
+#include <media/IMediaCodecService.h>
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -904,8 +905,8 @@
 
     if (listComponents) {
         sp<IServiceManager> sm = defaultServiceManager();
-        sp<IBinder> binder = sm->getService(String16("media.player"));
-        sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+        sp<IBinder> binder = sm->getService(String16("media.codec"));
+        sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
 
         CHECK(service.get() != NULL);
 
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index c47a4e7..521557d 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -19,6 +19,7 @@
 
 #include <cutils/sched_policy.h>
 #include <media/AudioSystem.h>
+#include <media/AudioTimestamp.h>
 #include <media/IAudioRecord.h>
 #include <media/Modulo.h>
 #include <utils/threads.h>
@@ -314,6 +315,17 @@
      */
             status_t    getPosition(uint32_t *position) const;
 
+    /* Return the record timestamp.
+     *
+     * Parameters:
+     *  timestamp: A pointer to the timestamp to be filled.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - BAD_VALUE: timestamp is NULL
+     */
+            status_t getTimestamp(ExtendedTimestamp *timestamp);
+
     /* Returns a handle on the audio input used by this AudioRecord.
      *
      * Parameters:
@@ -571,6 +583,11 @@
     size_t                  mReqFrameCount;         // frame count to request the first or next time
                                                     // a new IAudioRecord is needed, non-decreasing
 
+    int64_t                 mFramesRead;            // total frames read. reset to zero after
+                                                    // the start() following stop(). It is not
+                                                    // changed after restoring the track.
+    int64_t                 mFramesReadServerOffset; // An offset to server frames read due to
+                                                    // restoring AudioRecord, or stop/start.
     // constant after constructor or set()
     uint32_t                mSampleRate;
     audio_format_t          mFormat;
diff --git a/include/media/AudioTimestamp.h b/include/media/AudioTimestamp.h
index 99e9c3e..e6ca225 100644
--- a/include/media/AudioTimestamp.h
+++ b/include/media/AudioTimestamp.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_AUDIO_TIMESTAMP_H
 #define ANDROID_AUDIO_TIMESTAMP_H
 
+#include <string>
+#include <sstream>
 #include <time.h>
 
 namespace android {
@@ -32,6 +34,85 @@
     struct timespec mTime;     // corresponding CLOCK_MONOTONIC when frame is expected to present
 };
 
+struct ExtendedTimestamp {
+    enum Location {
+        LOCATION_CLIENT,   // timestamp of last read frame from client-server track buffer
+        LOCATION_SERVER,   // timestamp of newest frame from client-server track buffer
+        LOCATION_KERNEL,   // timestamp of newest frame in the kernel (alsa) buffer.
+        LOCATION_MAX       // for sizing arrays only
+    };
+
+    // This needs to be kept in sync with android.media.AudioTimestamp
+    enum Timebase {
+        TIMEBASE_MONOTONIC,  // Clock monotonic offset (generally 0)
+        TIMEBASE_BOOTTIME,
+        TIMEBASE_MAX,
+    };
+
+    ExtendedTimestamp() {
+        clear();
+    }
+
+    // mPosition is expressed in frame units.
+    // It is generally nonnegative, though we keep this signed for
+    // to potentially express algorithmic latency at the start of the stream
+    // and to prevent unintentional unsigned integer underflow.
+    int64_t mPosition[LOCATION_MAX];
+
+    // mTimeNs is in nanoseconds for the default timebase, monotonic.
+    // If this value is -1, then both time and position are invalid.
+    // If this value is 0, then the time is not valid but the position is valid.
+    int64_t mTimeNs[LOCATION_MAX];
+
+    // mTimebaseOffset is the offset in ns from monotonic when the
+    // timestamp was taken.  This may vary due to suspend time
+    // or NTP adjustment.
+    int64_t mTimebaseOffset[TIMEBASE_MAX];
+
+    void clear() {
+        memset(mPosition, 0, sizeof(mPosition)); // actually not necessary if time is -1
+        for (int i = 0; i < LOCATION_MAX; ++i) {
+            mTimeNs[i] = -1;
+        }
+        memset(mTimebaseOffset, 0, sizeof(mTimebaseOffset));
+    }
+
+    // Returns the best timestamp as judged from the closest-to-hw stage in the
+    // pipeline with a valid timestamp.
+    int getBestTimestamp(int64_t *position, int64_t *time, int timebase) {
+        if (position == nullptr || time == nullptr
+                || timebase < 0 || timebase >= TIMEBASE_MAX) {
+            return BAD_VALUE;
+        }
+        // look for the closest-to-hw stage in the pipeline with a valid timestamp.
+        // We omit LOCATION_CLIENT as we prefer at least LOCATION_SERVER based accuracy
+        // when getting the best timestamp.
+        for (int i = LOCATION_MAX - 1; i >= LOCATION_SERVER; --i) {
+            if (mTimeNs[i] > 0) {
+                *position = mPosition[i];
+                *time = mTimeNs[i] + mTimebaseOffset[timebase];
+                return OK;
+            }
+        }
+        return INVALID_OPERATION;
+    }
+
+    // convert fields to a printable string
+    std::string toString() {
+        std::stringstream ss;
+
+        ss << "BOOTTIME offset " << mTimebaseOffset[TIMEBASE_BOOTTIME] << "\n";
+        for (int i = 0; i < LOCATION_MAX; ++i) {
+            ss << "ExtendedTimestamp[" << i << "]  position: "
+                    << mPosition[i] << "  time: "  << mTimeNs[i] << "\n";
+        }
+        return ss.str();
+    }
+    // TODO:
+    // Consider adding buffer status:
+    // size, available, algorithmic latency
+};
+
 }   // namespace
 
 #endif  // ANDROID_AUDIO_TIMESTAMP_H
diff --git a/include/media/IMediaCodecService.h b/include/media/IMediaCodecService.h
new file mode 100644
index 0000000..984a0fd
--- /dev/null
+++ b/include/media/IMediaCodecService.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IMEDIACODECSERVICE_H
+#define ANDROID_IMEDIACODECSERVICE_H
+
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <media/IDataSource.h>
+#include <include/OMX.h>
+
+namespace android {
+
+class IMediaCodecService: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(MediaCodecService);
+
+    virtual sp<IOMX> getOMX() = 0;
+};
+
+class BnMediaCodecService: public BnInterface<IMediaCodecService>
+{
+public:
+    virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                uint32_t flags = 0);
+};
+
+}   // namespace android
+
+#endif  // ANDROID_IMEDIACODECSERVICE_H
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index a316ce2..99ca6f0 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -51,7 +51,6 @@
     virtual sp<IMediaMetadataRetriever> createMetadataRetriever() = 0;
     virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client, int audioSessionId = 0)
             = 0;
-
     virtual sp<IOMX>            getOMX() = 0;
     virtual sp<ICrypto>         makeCrypto() = 0;
     virtual sp<IDrm>            makeDrm() = 0;
diff --git a/include/media/MediaCodecInfo.h b/include/media/MediaCodecInfo.h
index 4067b47..26dc1ce 100644
--- a/include/media/MediaCodecInfo.h
+++ b/include/media/MediaCodecInfo.h
@@ -33,7 +33,6 @@
 
 struct AMessage;
 class Parcel;
-struct CodecCapabilities;
 
 typedef KeyedVector<AString, AString> CodecSettings;
 
@@ -44,12 +43,23 @@
     };
 
     struct Capabilities : public RefBase {
+        enum {
+            // decoder flags
+            kFlagSupportsAdaptivePlayback = 1 << 0,
+            kFlagSupportsSecurePlayback = 1 << 1,
+            kFlagSupportsTunneledPlayback = 1 << 2,
+
+            // encoder flags
+            kFlagSupportsIntraRefresh = 1 << 0,
+
+        };
+
         void getSupportedProfileLevels(Vector<ProfileLevel> *profileLevels) const;
         void getSupportedColorFormats(Vector<uint32_t> *colorFormats) const;
         uint32_t getFlags() const;
         const sp<AMessage> getDetails() const;
 
-    private:
+    protected:
         Vector<ProfileLevel> mProfileLevels;
         Vector<uint32_t> mColorFormats;
         uint32_t mFlags;
@@ -57,6 +67,7 @@
 
         Capabilities();
 
+    private:
         // read object from parcel even if object creation fails
         static sp<Capabilities> FromParcel(const Parcel &parcel);
         status_t writeToParcel(Parcel *parcel) const;
@@ -66,6 +77,14 @@
         friend class MediaCodecInfo;
     };
 
+    // Use a subclass to allow setting fields on construction without allowing
+    // to do the same throughout the framework.
+    struct CapabilitiesBuilder : public Capabilities {
+        void addProfileLevel(uint32_t profile, uint32_t level);
+        void addColorFormat(uint32_t format);
+        void addFlags(uint32_t flags);
+    };
+
     bool isEncoder() const;
     bool hasQuirk(const char *name) const;
     void getSupportedMimes(Vector<AString> *mimes) const;
@@ -107,7 +126,9 @@
     void addQuirk(const char *name);
     status_t addMime(const char *mime);
     status_t updateMime(const char *mime);
-    status_t initializeCapabilities(const CodecCapabilities &caps);
+  
+    // after this call |caps| will be owned by MediaCodecInfo, which may modify it
+    status_t setCapabilitiesFromCodec(const sp<Capabilities> &caps);
     void addDetail(const AString &key, const AString &value);
     void addFeature(const AString &key, int32_t value);
     void addFeature(const AString &key, const char *value);
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 5db70a6..349db64 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -50,6 +50,10 @@
     virtual void initiateStart();
     virtual void initiateShutdown(bool keepComponentAllocated = false);
 
+    virtual status_t queryCapabilities(
+            const AString &name, const AString &mime, bool isEncoder,
+            sp<MediaCodecInfo::Capabilities> *caps);
+
     virtual status_t setSurface(const sp<Surface> &surface);
 
     virtual void signalFlush();
@@ -312,6 +316,10 @@
             ssize_t *index = NULL);
 
     status_t setComponentRole(bool isEncoder, const char *mime);
+    static const char *getComponentRole(bool isEncoder, const char *mime);
+    static status_t setComponentRole(
+            const sp<IOMX> &omx, IOMX::node_id node, const char *role);
+
     status_t configureCodec(const char *mime, const sp<AMessage> &msg);
 
     status_t configureTunneledVideoPlayback(int32_t audioHwSync,
diff --git a/include/media/stagefright/ClockEstimator.h b/include/media/stagefright/ClockEstimator.h
deleted file mode 100644
index 1455b7f..0000000
--- a/include/media/stagefright/ClockEstimator.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
-**
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef CLOCK_ESTIMATOR_H_
-
-#define CLOCK_ESTIMATOR_H_
-
-#include "foundation/ABase.h"
-#include <utils/RefBase.h>
-#include <utils/Vector.h>
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-struct ClockEstimator : RefBase {
-    virtual double estimate(double x, double y) = 0;
-    virtual void reset() = 0;
-};
-
-struct WindowedLinearFitEstimator : ClockEstimator {
-    struct LinearFit {
-        /**
-         * Fit y = a * x + b, where each input has a weight
-         */
-        double mX;  // sum(w_i * x_i)
-        double mXX; // sum(w_i * x_i^2)
-        double mY;  // sum(w_i * y_i)
-        double mYY; // sum(w_i * y_i^2)
-        double mXY; // sum(w_i * x_i * y_i)
-        double mW;  // sum(w_i)
-
-        LinearFit();
-        void reset();
-        void combine(const LinearFit &lf);
-        void add(double x, double y, double w);
-        void scale(double w);
-        double interpolate(double x);
-        double size() const;
-
-        DISALLOW_EVIL_CONSTRUCTORS(LinearFit);
-    };
-
-    /**
-     * Estimator for f(x) = y' where input y' is noisy, but
-     * theoretically linear:
-     *
-     *      y' =~ y = a * x + b
-     *
-     * It uses linear fit regression over a tapering rolling window
-     * to get an estimate for y (from the current and past inputs
-     * (x, y')).
-     *
-     *     ____________
-     *    /|          |\
-     *   / |          | \
-     *  /  |          |  \   <--- new data (x, y')
-     * /   |   main   |   \
-     * <--><----------><-->
-     * tail            head
-     *
-     * weight is 1 under the main window, tapers exponentially by
-     * the factors given in the head and the tail.
-     *
-     * Assuming that x and y' are monotonic, that x is somewhat
-     * evenly sampled, and that a =~ 1, the estimated y is also
-     * going to be monotonic.
-     */
-    WindowedLinearFitEstimator(
-            size_t headLength = 5, double headFactor = 0.5,
-            size_t mainLength = 0, double tailFactor = 0.99);
-
-    virtual void reset();
-
-    // add a new sample (x -> y') and return an estimated value for the true y
-    virtual double estimate(double x, double y);
-
-private:
-    Vector<double> mXHistory; // circular buffer
-    Vector<double> mYHistory; // circular buffer
-    LinearFit mHead;
-    LinearFit mMain;
-    LinearFit mTail;
-    double mHeadFactorInv;
-    double mTailFactor;
-    double mFirstWeight;
-    size_t mHistoryLength;
-    size_t mHeadLength;
-    size_t mNumSamples;
-    size_t mSampleIx;
-
-    DISALLOW_EVIL_CONSTRUCTORS(WindowedLinearFitEstimator);
-};
-
-}; // namespace android
-
-#endif
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
index 542db71..01b744b 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include <media/IOMX.h>
 
+#include <media/MediaCodecInfo.h>
 #include <media/stagefright/foundation/AHandler.h>
 
 namespace android {
@@ -59,6 +60,10 @@
     // require an explicit message handler
     virtual void onMessageReceived(const sp<AMessage> &msg) = 0;
 
+    virtual status_t queryCapabilities(
+            const AString &name, const AString &mime, bool isEncoder,
+            sp<MediaCodecInfo::Capabilities> *caps /* nonnull */) { return INVALID_OPERATION; }
+
     virtual status_t setSurface(const sp<Surface> &surface) { return INVALID_OPERATION; }
 
     virtual void signalFlush() = 0;
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index d4b8e4a..ea708e3 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -20,6 +20,7 @@
 
 #include <gui/IGraphicBufferProducer.h>
 #include <media/hardware/CryptoAPI.h>
+#include <media/MediaCodecInfo.h>
 #include <media/MediaResource.h>
 #include <media/stagefright/foundation/AHandler.h>
 #include <media/stagefright/FrameRenderTracker.h>
@@ -73,6 +74,11 @@
 
     static sp<PersistentSurface> CreatePersistentInputSurface();
 
+    // utility method to query capabilities
+    static status_t QueryCapabilities(
+            const AString &name, const AString &mime, bool isEncoder,
+            sp<MediaCodecInfo::Capabilities> *caps /* nonnull */);
+
     status_t configure(
             const sp<AMessage> &format,
             const sp<Surface> &nativeWindow,
@@ -341,6 +347,8 @@
 
     MediaCodec(const sp<ALooper> &looper, pid_t pid);
 
+    static sp<CodecBase> GetCodecBase(const AString &name, bool nameIsType = false);
+
     static status_t PostAndAwaitResponse(
             const sp<AMessage> &msg, sp<AMessage> *response);
 
diff --git a/include/media/stagefright/TimeSource.h b/include/media/stagefright/TimeSource.h
deleted file mode 100644
index 8f11e14..0000000
--- a/include/media/stagefright/TimeSource.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TIME_SOURCE_H_
-
-#define TIME_SOURCE_H_
-
-#include <stdint.h>
-
-namespace android {
-
-class TimeSource {
-public:
-    TimeSource() {}
-    virtual ~TimeSource() {}
-
-    virtual int64_t getRealTimeUs() = 0;
-
-private:
-    TimeSource(const TimeSource &);
-    TimeSource &operator=(const TimeSource &);
-};
-
-class SystemTimeSource : public TimeSource {
-public:
-    SystemTimeSource();
-
-    virtual int64_t getRealTimeUs();
-
-private:
-    int64_t mStartTimeUs;
-};
-
-}  // namespace android
-
-#endif  // TIME_SOURCE_H_
diff --git a/include/media/stagefright/timedtext/TimedTextDriver.h b/include/media/stagefright/timedtext/TimedTextDriver.h
deleted file mode 100644
index 6e699a6..0000000
--- a/include/media/stagefright/timedtext/TimedTextDriver.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TIMED_TEXT_DRIVER_H_
-#define TIMED_TEXT_DRIVER_H_
-
-#include <media/IMediaSource.h>
-#include <media/stagefright/foundation/ABase.h> // for DISALLOW_* macro
-#include <utils/Errors.h> // for status_t
-#include <utils/RefBase.h>
-#include <utils/threads.h>
-
-namespace android {
-
-struct ALooper;
-struct IMediaHTTPService;
-class MediaPlayerBase;
-class Parcel;
-class TimedTextPlayer;
-class TimedTextSource;
-class DataSource;
-
-class TimedTextDriver {
-public:
-    TimedTextDriver(
-            const wp<MediaPlayerBase> &listener,
-            const sp<IMediaHTTPService> &httpService);
-
-    ~TimedTextDriver();
-
-    status_t start();
-    status_t pause();
-    status_t selectTrack(size_t index);
-    status_t unselectTrack(size_t index);
-
-    status_t seekToAsync(int64_t timeUs);
-
-    status_t addInBandTextSource(
-            size_t trackIndex, const sp<IMediaSource>& source);
-
-    status_t addOutOfBandTextSource(
-            size_t trackIndex, const char *uri, const char *mimeType);
-
-    // Caller owns the file desriptor and caller is responsible for closing it.
-    status_t addOutOfBandTextSource(
-            size_t trackIndex, int fd, off64_t offset,
-            off64_t length, const char *mimeType);
-
-    void getExternalTrackInfo(Parcel *parcel);
-    size_t countExternalTracks() const;
-
-private:
-    Mutex mLock;
-
-    enum State {
-        UNINITIALIZED,
-        PREPARED,
-        PLAYING,
-        PAUSED,
-    };
-
-    enum TextSourceType {
-        TEXT_SOURCE_TYPE_IN_BAND = 0,
-        TEXT_SOURCE_TYPE_OUT_OF_BAND,
-    };
-
-    sp<ALooper> mLooper;
-    sp<TimedTextPlayer> mPlayer;
-    wp<MediaPlayerBase> mListener;
-    sp<IMediaHTTPService> mHTTPService;
-
-    // Variables to be guarded by mLock.
-    State mState;
-    size_t mCurrentTrackIndex;
-    KeyedVector<size_t, sp<TimedTextSource> > mTextSourceVector;
-    Vector<TextSourceType> mTextSourceTypeVector;
-
-    // -- End of variables to be guarded by mLock
-
-    status_t selectTrack_l(size_t index);
-
-    status_t createOutOfBandTextSource(
-            size_t trackIndex, const char* mimeType,
-            const sp<DataSource>& dataSource);
-
-    DISALLOW_EVIL_CONSTRUCTORS(TimedTextDriver);
-};
-
-}  // namespace android
-
-#endif  // TIMED_TEXT_DRIVER_H_
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 770f007..2270c85 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -26,6 +26,7 @@
 #include <utils/RefBase.h>
 #include <audio_utils/roundup.h>
 #include <media/AudioResamplerPublic.h>
+#include <media/AudioTimestamp.h>
 #include <media/Modulo.h>
 #include <media/SingleStateQueue.h>
 
@@ -118,6 +119,8 @@
 
 typedef SingleStateQueue<AudioPlaybackRate> PlaybackRateQueue;
 
+typedef SingleStateQueue<ExtendedTimestamp> ExtendedTimestampQueue;
+
 // ----------------------------------------------------------------------------
 
 // Important: do not add any virtual methods, including ~
@@ -171,6 +174,8 @@
 
                 uint16_t    mPad2;           // unused
 
+                // server write-only, client read
+                ExtendedTimestampQueue::Shared mExtendedTimestampQueue;
 public:
 
     volatile    int32_t     mFlags;         // combinations of CBLK_*
@@ -426,8 +431,39 @@
     AudioRecordClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
             size_t frameSize)
         : ClientProxy(cblk, buffers, frameCount, frameSize,
-            false /*isOut*/, false /*clientInServer*/) { }
+            false /*isOut*/, false /*clientInServer*/)
+        , mTimestampObserver(&cblk->mExtendedTimestampQueue) { }
     ~AudioRecordClientProxy() { }
+
+    status_t    getTimestamp(ExtendedTimestamp *timestamp) {
+        if (timestamp == nullptr) {
+            return BAD_VALUE;
+        }
+        (void) mTimestampObserver.poll(mTimestamp);
+        *timestamp = mTimestamp;
+        return OK;
+    }
+
+    void        clearTimestamp() {
+        mTimestamp.clear();
+    }
+
+    // Advances the client read pointer to the server write head pointer
+    // effectively flushing the client read buffer. The effect is
+    // instantaneous. Returns the number of frames flushed.
+    uint32_t    flush() {
+        int32_t rear = android_atomic_acquire_load(&mCblk->u.mStreaming.mRear);
+        int32_t front = mCblk->u.mStreaming.mFront;
+        android_atomic_release_store(rear, &mCblk->u.mStreaming.mFront);
+        return (Modulo<int32_t>(rear) - front).unsignedValue();
+    }
+
+private:
+    // The shared buffer contents referred to by the timestamp observer
+    // is initialized when the server proxy created.  A local zero timestamp
+    // is initialized by the client constructor.
+    ExtendedTimestampQueue::Observer mTimestampObserver;
+    ExtendedTimestamp mTimestamp; // initialized by constructor
 };
 
 // ----------------------------------------------------------------------------
@@ -476,6 +512,7 @@
 protected:
     size_t      mAvailToClient; // estimated frames available to client prior to releaseBuffer()
     int32_t     mFlush;         // our copy of cblk->u.mStreaming.mFlush, for streaming output only
+    int64_t     mReleased;      // our copy of cblk->mServer, at 64 bit resolution
 };
 
 // Proxy used by AudioFlinger for servicing AudioTrack
@@ -520,7 +557,7 @@
     virtual uint32_t    getUnderrunFrames() const { return mCblk->u.mStreaming.mUnderrunFrames; }
 
     // Return the total number of frames that AudioFlinger has obtained and released
-    virtual size_t      framesReleased() const { return mCblk->mServer; }
+    virtual size_t      framesReleased() const { return mReleased; }
 
     // Return the playback speed and pitch read atomically. Not multi-thread safe on server side.
     AudioPlaybackRate getPlaybackRate();
@@ -574,9 +611,20 @@
 public:
     AudioRecordServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
             size_t frameSize, bool clientInServer)
-        : ServerProxy(cblk, buffers, frameCount, frameSize, false /*isOut*/, clientInServer) { }
+        : ServerProxy(cblk, buffers, frameCount, frameSize, false /*isOut*/, clientInServer)
+        , mTimestampMutator(&cblk->mExtendedTimestampQueue) { }
+
+    // Return the total number of frames that AudioFlinger has obtained and released
+    virtual int64_t     framesReleased() const { return mReleased; }
+
+    // Expose timestamp to client proxy. Should only be called by a single thread.
+    virtual void        setExtendedTimestamp(const ExtendedTimestamp &timestamp) {
+                            mTimestampMutator.push(timestamp);
+                        }
 protected:
     virtual ~AudioRecordServerProxy() { }
+
+    ExtendedTimestampQueue::Mutator       mTimestampMutator;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 285c33e..c095724 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -30,6 +30,7 @@
     AudioSystem.cpp \
     mediaplayer.cpp \
     IMediaCodecList.cpp \
+    IMediaCodecService.cpp \
     IMediaHTTPConnection.cpp \
     IMediaHTTPService.cpp \
     IMediaLogService.cpp \
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 1c0d904..ec57d96 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -284,6 +284,8 @@
     mSequence = 1;
     mObservedSequence = mSequence;
     mInOverrun = false;
+    mFramesRead = 0;
+    mFramesReadServerOffset = 0;
 
     return NO_ERROR;
 }
@@ -299,6 +301,12 @@
         return NO_ERROR;
     }
 
+    // discard data in buffer
+    const uint32_t framesFlushed = mProxy->flush();
+    mFramesReadServerOffset -= mFramesRead + framesFlushed;
+    mFramesRead = 0;
+    mProxy->clearTimestamp();  // timestamp is invalid until next server push
+
     // reset current position as seen by client to 0
     mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());
     // force refresh of remaining frames by processAudioBuffer() as last
@@ -449,6 +457,27 @@
     return AudioSystem::getInputFramesLost(getInputPrivate());
 }
 
+status_t AudioRecord::getTimestamp(ExtendedTimestamp *timestamp)
+{
+    if (timestamp == nullptr) {
+        return BAD_VALUE;
+    }
+    AutoMutex lock(mLock);
+    status_t status = mProxy->getTimestamp(timestamp);
+    if (status == OK) {
+        timestamp->mPosition[ExtendedTimestamp::LOCATION_CLIENT] = mFramesRead;
+        timestamp->mTimeNs[ExtendedTimestamp::LOCATION_CLIENT] = 0;
+        // server side frame offset in case AudioRecord has been restored.
+        for (int i = ExtendedTimestamp::LOCATION_SERVER;
+                i < ExtendedTimestamp::LOCATION_MAX; ++i) {
+            if (timestamp->mTimeNs[i] >= 0) {
+                timestamp->mPosition[i] += mFramesReadServerOffset;
+            }
+        }
+    }
+    return status;
+}
+
 // ---- Explicit Routing ---------------------------------------------------
 status_t AudioRecord::setInputDevice(audio_port_handle_t deviceId) {
     AutoMutex lock(mLock);
@@ -837,7 +866,10 @@
 
         releaseBuffer(&audioBuffer);
     }
-
+    if (read > 0) {
+        mFramesRead += read / mFrameSize;
+        // mFramesReadTime = systemTime(SYSTEM_TIME_MONOTONIC); // not provided at this time.
+    }
     return read;
 }
 
@@ -988,6 +1020,7 @@
         requested = &timeout;
     }
 
+    size_t readFrames = 0;
     while (mRemainingFrames > 0) {
 
         Buffer audioBuffer;
@@ -1049,6 +1082,7 @@
         }
 
         releaseBuffer(&audioBuffer);
+        readFrames += releasedFrames;
 
         // FIXME here is where we would repeat EVENT_MORE_DATA again on same advanced buffer
         // if callback doesn't like to accept the full chunk
@@ -1072,6 +1106,11 @@
 #endif
 
     }
+    if (readFrames > 0) {
+        AutoMutex lock(mLock);
+        mFramesRead += readFrames;
+        // mFramesReadTime = systemTime(SYSTEM_TIME_MONOTONIC); // not provided at this time.
+    }
     mRemainingFrames = notificationFrames;
     mRetryOnPartialBuffer = true;
 
@@ -1096,6 +1135,7 @@
             // FIXME this fails if we have a new AudioFlinger instance
             result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0);
         }
+        mFramesReadServerOffset = mFramesRead; // server resets to zero so we need an offset.
     }
     if (result != NO_ERROR) {
         ALOGW("restoreRecord_l() failed status %d", result);
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index d75ad87..988386e 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -597,7 +597,7 @@
 ServerProxy::ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
         size_t frameSize, bool isOut, bool clientInServer)
     : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer),
-      mAvailToClient(0), mFlush(0)
+      mAvailToClient(0), mFlush(0), mReleased(0)
 {
 }
 
@@ -733,6 +733,7 @@
     }
 
     cblk->mServer += stepCount;
+    mReleased += stepCount;
 
     size_t half = mFrameCount / 2;
     if (half == 0) {
@@ -1033,6 +1034,8 @@
     mFramesReadySafe = clampToSize(mFramesReady);
 
     cblk->mServer += stepCount;
+    mReleased += stepCount;
+
     // This may overflow, but client is not supposed to rely on it
     StaticAudioTrackPosLoop posLoop;
     posLoop.mBufferPosition = mState.mPosition;
diff --git a/media/libmedia/IMediaCodecService.cpp b/media/libmedia/IMediaCodecService.cpp
new file mode 100644
index 0000000..dcf2b27
--- /dev/null
+++ b/media/libmedia/IMediaCodecService.cpp
@@ -0,0 +1,72 @@
+/*
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "IMediaCodecService"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/Parcel.h>
+#include <media/IMediaCodecService.h>
+
+namespace android {
+
+enum {
+    GET_OMX = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpMediaCodecService : public BpInterface<IMediaCodecService>
+{
+public:
+    BpMediaCodecService(const sp<IBinder>& impl)
+        : BpInterface<IMediaCodecService>(impl)
+    {
+    }
+
+    virtual sp<IOMX> getOMX() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaCodecService::getInterfaceDescriptor());
+        remote()->transact(GET_OMX, data, &reply);
+        return interface_cast<IOMX>(reply.readStrongBinder());
+    }
+
+};
+
+IMPLEMENT_META_INTERFACE(MediaCodecService, "android.media.IMediaCodecService");
+
+// ----------------------------------------------------------------------
+
+status_t BnMediaCodecService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+
+        case GET_OMX: {
+            CHECK_INTERFACE(IMediaCodecService, data, reply);
+            sp<IOMX> omx = getOMX();
+            reply->writeStrongBinder(IInterface::asBinder(omx));
+            return NO_ERROR;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+} // namespace android
diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp
index 8d3fa7b..8351af6 100644
--- a/media/libmedia/MediaCodecInfo.cpp
+++ b/media/libmedia/MediaCodecInfo.cpp
@@ -26,8 +26,6 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <binder/Parcel.h>
 
-#include <media/stagefright/OMXCodec.h>
-
 namespace android {
 
 void MediaCodecInfo::Capabilities::getSupportedProfileLevels(
@@ -101,6 +99,21 @@
     return OK;
 }
 
+void MediaCodecInfo::CapabilitiesBuilder::addProfileLevel(uint32_t profile, uint32_t level) {
+    ProfileLevel profileLevel;
+    profileLevel.mProfile = profile;
+    profileLevel.mLevel = level;
+    mProfileLevels.push_back(profileLevel);
+}
+
+void MediaCodecInfo::CapabilitiesBuilder::addColorFormat(uint32_t format) {
+    mColorFormats.push(format);
+}
+
+void MediaCodecInfo::CapabilitiesBuilder::addFlags(uint32_t flags) {
+    mFlags |= flags;
+}
+
 bool MediaCodecInfo::isEncoder() const {
     return mIsEncoder;
 }
@@ -225,26 +238,12 @@
     }
 }
 
-status_t MediaCodecInfo::initializeCapabilities(const CodecCapabilities &caps) {
-    mCurrentCaps->mProfileLevels.clear();
-    mCurrentCaps->mColorFormats.clear();
-
-    for (size_t i = 0; i < caps.mProfileLevels.size(); ++i) {
-        const CodecProfileLevel &src = caps.mProfileLevels.itemAt(i);
-
-        ProfileLevel profileLevel;
-        profileLevel.mProfile = src.mProfile;
-        profileLevel.mLevel = src.mLevel;
-        mCurrentCaps->mProfileLevels.push_back(profileLevel);
+status_t MediaCodecInfo::setCapabilitiesFromCodec(const sp<Capabilities> &caps) {
+    if (mCurrentCaps != NULL) {
+        // keep current capabilities map
+        caps->mDetails = mCurrentCaps->mDetails;
     }
-
-    for (size_t i = 0; i < caps.mColorFormats.size(); ++i) {
-        mCurrentCaps->mColorFormats.push_back(caps.mColorFormats.itemAt(i));
-    }
-
-    mCurrentCaps->mFlags = caps.mFlags;
-    mCurrentCaps->mDetails = new AMessage;
-
+    mCurrentCaps = caps;
     return OK;
 }
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index c5f53cb..bb24403 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -346,6 +346,7 @@
 }
 
 sp<IOMX> MediaPlayerService::getOMX() {
+    ALOGI("MediaPlayerService::getOMX");
     Mutex::Autolock autoLock(mLock);
 
     if (mOMX.get() == NULL) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 765ceff..2528777 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -736,6 +736,7 @@
             if (err == OK) {
                 if (rate.mSpeed == 0.f) {
                     onPause();
+                    mPausedByClient = true;
                     // save all other settings (using non-paused speed)
                     // so we can restore them on start
                     AudioPlaybackRate newRate = rate;
@@ -743,6 +744,7 @@
                     mPlaybackSettings = newRate;
                 } else { /* rate.mSpeed != 0.f */
                     onResume();
+                    mPausedByClient = false;
                     mPlaybackSettings = rate;
                 }
             }
@@ -1208,6 +1210,8 @@
                 break;
             }
 
+            mPendingBufferingFlag = PENDING_BUFFERING_FLAG_NONE;
+
             mDeferredActions.push_back(
                     new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
                                            FLUSH_CMD_FLUSH /* video */));
@@ -1908,6 +1912,7 @@
     }
     mPreviousSeekTimeUs = seekTimeUs;
     mSource->seekTo(seekTimeUs);
+    mPendingBufferingFlag = PENDING_BUFFERING_FLAG_NONE;
     ++mTimedTextGeneration;
 
     // everything's flushed, continue playback.
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 7535934..cd3ba53 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -69,6 +69,9 @@
 // is closed to allow the audio DSP to power down.
 static const int64_t kOffloadPauseMaxUs = 10000000ll;
 
+// Maximum allowed delay from AudioSink, 1.5 seconds.
+static const int64_t kMaxAllowedAudioSinkDelayUs = 1500000ll;
+
 // static
 const NuPlayer::Renderer::PcmInfo NuPlayer::Renderer::AUDIO_PCMINFO_INITIALIZER = {
         AUDIO_CHANNEL_NONE,
@@ -1038,10 +1041,25 @@
 
     AudioTimestamp ts;
     status_t res = mAudioSink->getTimestamp(ts);
+    int64_t nowUs = ALooper::GetNowUs();
     if (res == OK) {
-        int64_t nowUs = ALooper::GetNowUs();
         int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs);
         mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs);
+    } else {
+        int64_t unused;
+        if ((mMediaClock->getMediaTime(nowUs, &unused) != OK)
+                && (getDurationUsIfPlayedAtSampleRate(mNumFramesWritten)
+                        > kMaxAllowedAudioSinkDelayUs)) {
+            // Enough data has been sent to AudioSink, but AudioSink has not rendered
+            // any data yet. Something is wrong with AudioSink, e.g., the device is not
+            // connected to audio out.
+            // Switch to system clock. This essentially creates a virtual AudioSink with
+            // initial latenty of getDurationUsIfPlayedAtSampleRate(mNumFramesWritten).
+            // This virtual AudioSink renders audio data starting from the very first sample
+            // and it's paced by system clock.
+            ALOGW("AudioSink stuck. ARE YOU CONNECTED TO AUDIO OUT? Switching to system clock.");
+            mMediaClock->updateAnchor(mAudioFirstAnchorTimeMediaUs, nowUs, mediaTimeUs);
+        }
     }
     mAnchorNumFramesWritten = mNumFramesWritten;
     mAnchorTimeMediaUs = mediaTimeUs;
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index c861fd1..ec33478 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -385,10 +385,8 @@
         case MyHandler::kWhatSeekDone:
         {
             mState = CONNECTED;
-            if (mSeekReplyID != NULL) {
-                // Unblock seekTo here in case we attempted to seek in a live stream
-                finishSeek(OK);
-            }
+            // Unblock seekTo here in case we attempted to seek in a live stream
+            finishSeek(OK);
             break;
         }
 
@@ -409,12 +407,13 @@
 
             status_t err = OK;
             msg->findInt32("err", &err);
-            finishSeek(err);
 
             if (err == OK) {
                 int64_t timeUs;
                 CHECK(msg->findInt64("time", &timeUs));
                 mHandler->continueSeekAfterPause(timeUs);
+            } else {
+                finishSeek(err);
             }
             break;
         }
@@ -749,7 +748,9 @@
 }
 
 void NuPlayer::RTSPSource::finishSeek(status_t err) {
-    CHECK(mSeekReplyID != NULL);
+    if (mSeekReplyID == NULL) {
+        return;
+    }
     sp<AMessage> seekReply = new AMessage;
     seekReply->setInt32("err", err);
     seekReply->postReply(mSeekReplyID);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index fa6703e..d39fffa 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -55,6 +55,10 @@
 
 namespace android {
 
+enum {
+    kMaxIndicesToCheck = 32, // used when enumerating supported formats and profiles
+};
+
 // OMX errors are directly mapped into status_t range if
 // there is no corresponding MediaError status code.
 // Use the statusFromOMXError(int32_t omxError) function.
@@ -1528,6 +1532,21 @@
 
 status_t ACodec::setComponentRole(
         bool isEncoder, const char *mime) {
+    const char *role = getComponentRole(isEncoder, mime);
+    if (role == NULL) {
+        return BAD_VALUE;
+    }
+    status_t err = setComponentRole(mOMX, mNode, role);
+    if (err != OK) {
+        ALOGW("[%s] Failed to set standard component role '%s'.",
+             mComponentName.c_str(), role);
+    }
+    return err;
+}
+
+//static
+const char *ACodec::getComponentRole(
+        bool isEncoder, const char *mime) {
     struct MimeToRole {
         const char *mime;
         const char *decoderRole;
@@ -1594,35 +1613,27 @@
     }
 
     if (i == kNumMimeToRole) {
-        return ERROR_UNSUPPORTED;
+        return NULL;
     }
 
-    const char *role =
-        isEncoder ? kMimeToRole[i].encoderRole
+    return isEncoder ? kMimeToRole[i].encoderRole
                   : kMimeToRole[i].decoderRole;
+}
 
-    if (role != NULL) {
-        OMX_PARAM_COMPONENTROLETYPE roleParams;
-        InitOMXParams(&roleParams);
+//static
+status_t ACodec::setComponentRole(
+        const sp<IOMX> &omx, IOMX::node_id node, const char *role) {
+    OMX_PARAM_COMPONENTROLETYPE roleParams;
+    InitOMXParams(&roleParams);
 
-        strncpy((char *)roleParams.cRole,
-                role, OMX_MAX_STRINGNAME_SIZE - 1);
+    strncpy((char *)roleParams.cRole,
+            role, OMX_MAX_STRINGNAME_SIZE - 1);
 
-        roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
+    roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
 
-        status_t err = mOMX->setParameter(
-                mNode, OMX_IndexParamStandardComponentRole,
-                &roleParams, sizeof(roleParams));
-
-        if (err != OK) {
-            ALOGW("[%s] Failed to set standard component role '%s'.",
-                 mComponentName.c_str(), role);
-
-            return err;
-        }
-    }
-
-    return OK;
+    return omx->setParameter(
+            node, OMX_IndexParamStandardComponentRole,
+            &roleParams, sizeof(roleParams));
 }
 
 status_t ACodec::configureCodec(
@@ -2373,9 +2384,8 @@
     InitOMXParams(&format);
 
     format.nPortIndex = portIndex;
-    for (OMX_U32 index = 0;; ++index) {
+    for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
         format.nIndex = index;
-
         status_t err = mOMX->getParameter(
                 mNode, OMX_IndexParamAudioPortFormat,
                 &format, sizeof(format));
@@ -2387,6 +2397,13 @@
         if (format.eEncoding == desiredFormat) {
             break;
         }
+
+        if (index == kMaxIndicesToCheck) {
+            ALOGW("[%s] stopping checking formats after %u: %s(%x)",
+                    mComponentName.c_str(), index,
+                    asString(format.eEncoding), format.eEncoding);
+            return ERROR_UNSUPPORTED;
+        }
     }
 
     return mOMX->setParameter(
@@ -2806,8 +2823,7 @@
     format.nIndex = 0;
     bool found = false;
 
-    OMX_U32 index = 0;
-    for (;;) {
+    for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
         format.nIndex = index;
         status_t err = mOMX->getParameter(
                 mNode, OMX_IndexParamVideoPortFormat,
@@ -2852,7 +2868,12 @@
             break;
         }
 
-        ++index;
+        if (index == kMaxIndicesToCheck) {
+            ALOGW("[%s] stopping checking formats after %u: %s(%x)/%s(%x)",
+                    mComponentName.c_str(), index,
+                    asString(format.eCompressionFormat), format.eCompressionFormat,
+                    asString(format.eColorFormat), format.eColorFormat);
+        }
     }
 
     if (!found) {
@@ -3737,7 +3758,8 @@
     InitOMXParams(&params);
     params.nPortIndex = kPortIndexOutput;
 
-    for (params.nProfileIndex = 0;; ++params.nProfileIndex) {
+    for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
+        params.nProfileIndex = index;
         status_t err = mOMX->getParameter(
                 mNode,
                 OMX_IndexParamVideoProfileLevelQuerySupported,
@@ -3754,7 +3776,14 @@
         if (profile == supportedProfile && level <= supportedLevel) {
             return OK;
         }
+
+        if (index == kMaxIndicesToCheck) {
+            ALOGW("[%s] stopping checking profiles after %u: %x/%x",
+                    mComponentName.c_str(), index,
+                    params.eProfile, params.eLevel);
+        }
     }
+    return ERROR_UNSUPPORTED;
 }
 
 status_t ACodec::configureBitrate(
@@ -7004,6 +7033,168 @@
     }
 }
 
+status_t ACodec::queryCapabilities(
+        const AString &name, const AString &mime, bool isEncoder,
+        sp<MediaCodecInfo::Capabilities> *caps) {
+    (*caps).clear();
+    const char *role = getComponentRole(isEncoder, mime.c_str());
+    if (role == NULL) {
+        return BAD_VALUE;
+    }
+
+    OMXClient client;
+    status_t err = client.connect();
+    if (err != OK) {
+        return err;
+    }
+
+    sp<IOMX> omx = client.interface();
+    sp<CodecObserver> observer = new CodecObserver;
+    IOMX::node_id node = 0;
+
+    err = omx->allocateNode(name.c_str(), observer, &node);
+    if (err != OK) {
+        client.disconnect();
+        return err;
+    }
+
+    err = setComponentRole(omx, node, role);
+    if (err != OK) {
+        omx->freeNode(node);
+        client.disconnect();
+        return err;
+    }
+
+    sp<MediaCodecInfo::CapabilitiesBuilder> builder = new MediaCodecInfo::CapabilitiesBuilder();
+    bool isVideo = mime.startsWithIgnoreCase("video/");
+
+    if (isVideo) {
+        OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
+        InitOMXParams(&param);
+        param.nPortIndex = isEncoder ? kPortIndexOutput : kPortIndexInput;
+
+        for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
+            param.nProfileIndex = index;
+            status_t err = omx->getParameter(
+                    node, OMX_IndexParamVideoProfileLevelQuerySupported,
+                    &param, sizeof(param));
+            if (err != OK) {
+                break;
+            }
+            builder->addProfileLevel(param.eProfile, param.eLevel);
+
+            if (index == kMaxIndicesToCheck) {
+                ALOGW("[%s] stopping checking profiles after %u: %x/%x",
+                        name.c_str(), index,
+                        param.eProfile, param.eLevel);
+            }
+        }
+
+        // Color format query
+        // return colors in the order reported by the OMX component
+        // prefix "flexible" standard ones with the flexible equivalent
+        OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
+        InitOMXParams(&portFormat);
+        param.nPortIndex = isEncoder ? kPortIndexInput : kPortIndexOutput;
+        Vector<uint32_t> supportedColors; // shadow copy to check for duplicates
+        for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
+            portFormat.nIndex = index;
+            status_t err = omx->getParameter(
+                    node, OMX_IndexParamVideoPortFormat,
+                    &portFormat, sizeof(portFormat));
+            if (err != OK) {
+                break;
+            }
+
+            OMX_U32 flexibleEquivalent;
+            if (isFlexibleColorFormat(
+                    omx, node, portFormat.eColorFormat, false /* usingNativeWindow */,
+                    &flexibleEquivalent)) {
+                bool marked = false;
+                for (size_t i = 0; i < supportedColors.size(); ++i) {
+                    if (supportedColors[i] == flexibleEquivalent) {
+                        marked = true;
+                        break;
+                    }
+                }
+                if (!marked) {
+                    supportedColors.push(flexibleEquivalent);
+                    builder->addColorFormat(flexibleEquivalent);
+                }
+            }
+            supportedColors.push(portFormat.eColorFormat);
+            builder->addColorFormat(portFormat.eColorFormat);
+
+            if (index == kMaxIndicesToCheck) {
+                ALOGW("[%s] stopping checking formats after %u: %s(%x)",
+                        name.c_str(), index,
+                        asString(portFormat.eColorFormat), portFormat.eColorFormat);
+            }
+        }
+    } else if (mime.equalsIgnoreCase(MEDIA_MIMETYPE_AUDIO_AAC)) {
+        // More audio codecs if they have profiles.
+        OMX_AUDIO_PARAM_ANDROID_PROFILETYPE param;
+        InitOMXParams(&param);
+        param.nPortIndex = isEncoder ? kPortIndexOutput : kPortIndexInput;
+        for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
+            param.nProfileIndex = index;
+            status_t err = omx->getParameter(
+                    node, (OMX_INDEXTYPE)OMX_IndexParamAudioProfileQuerySupported,
+                    &param, sizeof(param));
+            if (err != OK) {
+                break;
+            }
+            // For audio, level is ignored.
+            builder->addProfileLevel(param.eProfile, 0 /* level */);
+
+            if (index == kMaxIndicesToCheck) {
+                ALOGW("[%s] stopping checking profiles after %u: %x",
+                        name.c_str(), index,
+                        param.eProfile);
+            }
+        }
+
+        // NOTE: Without Android extensions, OMX does not provide a way to query
+        // AAC profile support
+        if (param.nProfileIndex == 0) {
+            ALOGW("component %s doesn't support profile query.", name.c_str());
+        }
+    }
+
+    if (isVideo && !isEncoder) {
+        native_handle_t *sidebandHandle = NULL;
+        if (omx->configureVideoTunnelMode(
+                node, kPortIndexOutput, OMX_TRUE, 0, &sidebandHandle) == OK) {
+            // tunneled playback includes adaptive playback
+            builder->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback
+                    | MediaCodecInfo::Capabilities::kFlagSupportsTunneledPlayback);
+        } else if (omx->storeMetaDataInBuffers(
+                node, kPortIndexOutput, OMX_TRUE) == OK ||
+            omx->prepareForAdaptivePlayback(
+                node, kPortIndexOutput, OMX_TRUE,
+                1280 /* width */, 720 /* height */) == OK) {
+            builder->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback);
+        }
+    }
+
+    if (isVideo && isEncoder) {
+        OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE params;
+        InitOMXParams(&params);
+        params.nPortIndex = kPortIndexOutput;
+        // TODO: should we verify if fallback is supported?
+        if (omx->getConfig(
+                node, (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh,
+                &params, sizeof(params)) == OK) {
+            builder->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsIntraRefresh);
+        }
+    }
+
+    *caps = builder;
+    omx->freeNode(node);
+    client.disconnect();
+    return OK;
+}
+
 // These are supposed be equivalent to the logic in
 // "audio_channel_out_mask_from_count".
 //static
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index f297256..2df69b4 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -13,7 +13,6 @@
         CallbackDataSource.cpp            \
         CameraSource.cpp                  \
         CameraSourceTimeLapse.cpp         \
-        ClockEstimator.cpp                \
         CodecBase.cpp                     \
         DataSource.cpp                    \
         DataURISource.cpp                 \
@@ -58,7 +57,6 @@
         SurfaceMediaSource.cpp            \
         SurfaceUtils.cpp                  \
         ThrottledSource.cpp               \
-        TimeSource.cpp                    \
         Utils.cpp                         \
         VBRISeeker.cpp                    \
         VideoFrameScheduler.cpp           \
diff --git a/media/libstagefright/ClockEstimator.cpp b/media/libstagefright/ClockEstimator.cpp
deleted file mode 100644
index 34d1e42..0000000
--- a/media/libstagefright/ClockEstimator.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
-**
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "ClockEstimator"
-#include <utils/Log.h>
-
-#include <math.h>
-#include <media/stagefright/ClockEstimator.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-
-namespace android {
-
-WindowedLinearFitEstimator::WindowedLinearFitEstimator(
-        size_t headLength, double headFactor, size_t mainLength, double tailFactor)
-    : mHeadFactorInv(1. / headFactor),
-      mTailFactor(tailFactor),
-      mHistoryLength(mainLength + headLength),
-      mHeadLength(headLength) {
-    reset();
-    mXHistory.resize(mHistoryLength);
-    mYHistory.resize(mHistoryLength);
-    mFirstWeight = pow(headFactor, mHeadLength);
-}
-
-WindowedLinearFitEstimator::LinearFit::LinearFit() {
-    reset();
-}
-
-void WindowedLinearFitEstimator::LinearFit::reset() {
-    mX = mXX = mY = mYY = mXY = mW = 0.;
-}
-
-double WindowedLinearFitEstimator::LinearFit::size() const {
-    double s = mW * mW + mX * mX + mY * mY + mXX * mXX + mXY * mXY + mYY * mYY;
-    if (s > 1e72) {
-        // 1e72 corresponds to clock monotonic time of about 8 years
-        ALOGW("estimator is overflowing: w=%g x=%g y=%g xx=%g xy=%g yy=%g",
-              mW, mX, mY, mXX, mXY, mYY);
-    }
-    return s;
-}
-
-void WindowedLinearFitEstimator::LinearFit::add(double x, double y, double w) {
-    mW += w;
-    mX += w * x;
-    mY += w * y;
-    mXX += w * x * x;
-    mXY += w * x * y;
-    mYY += w * y * y;
-}
-
-void WindowedLinearFitEstimator::LinearFit::combine(const LinearFit &lf) {
-    mW += lf.mW;
-    mX += lf.mX;
-    mY += lf.mY;
-    mXX += lf.mXX;
-    mXY += lf.mXY;
-    mYY += lf.mYY;
-}
-
-void WindowedLinearFitEstimator::LinearFit::scale(double w) {
-    mW *= w;
-    mX *= w;
-    mY *= w;
-    mXX *= w;
-    mXY *= w;
-    mYY *= w;
-}
-
-double WindowedLinearFitEstimator::LinearFit::interpolate(double x) {
-    double div = mW * mXX - mX * mX;
-    if (fabs(div) < 1e-5 * mW * mW) {
-        // this only should happen on the first value
-        return x;
-        // assuming a = 1, we could also return x + (mY - mX) / mW;
-    }
-    double a_div = (mW * mXY - mX * mY);
-    double b_div = (mXX * mY - mX * mXY);
-    ALOGV("a=%.4g b=%.4g in=%g out=%g",
-            a_div / div, b_div / div, x, (a_div * x + b_div) / div);
-    return (a_div * x + b_div) / div;
-}
-
-double WindowedLinearFitEstimator::estimate(double x, double y) {
-    /*
-     * TODO: We could update the head by adding the new sample to it
-     * and amplifying it, but this approach can lead to unbounded
-     * error. Instead, we recalculate the head at each step, which
-     * is computationally more expensive. We could balance the two
-     * methods by recalculating just before the error becomes
-     * significant.
-     */
-    const bool update_head = false;
-    if (update_head) {
-        // add new sample to the head
-        mHead.scale(mHeadFactorInv); // amplify head
-        mHead.add(x, y, mFirstWeight);
-    }
-
-    /*
-     * TRICKY: place elements into the circular buffer at decreasing
-     * indices, so that we can access past elements by addition
-     * (thereby avoiding potentially negative indices.)
-     */
-    if (mNumSamples >= mHeadLength) {
-        // move last head sample from head to the main window
-        size_t lastHeadIx = (mSampleIx + mHeadLength) % mHistoryLength;
-        if (update_head) {
-            mHead.add(mXHistory[lastHeadIx], mYHistory[lastHeadIx], -1.); // remove
-        }
-        mMain.add(mXHistory[lastHeadIx], mYHistory[lastHeadIx], 1.);
-        if (mNumSamples >= mHistoryLength) {
-            // move last main sample from main window to tail
-            mMain.add(mXHistory[mSampleIx], mYHistory[mSampleIx], -1.); // remove
-            mTail.add(mXHistory[mSampleIx], mYHistory[mSampleIx], 1.);
-            mTail.scale(mTailFactor); // attenuate tail
-        }
-    }
-
-    mXHistory.editItemAt(mSampleIx) = x;
-    mYHistory.editItemAt(mSampleIx) = y;
-    if (mNumSamples < mHistoryLength) {
-        ++mNumSamples;
-    }
-
-    // recalculate head unless we were using the update method
-    if (!update_head) {
-        mHead.reset();
-        double w = mFirstWeight;
-        for (size_t headIx = 0; headIx < mHeadLength && headIx < mNumSamples; ++headIx) {
-            size_t ix = (mSampleIx + headIx) % mHistoryLength;
-            mHead.add(mXHistory[ix], mYHistory[ix], w);
-            w *= mHeadFactorInv;
-        }
-    }
-
-    if (mSampleIx > 0) {
-        --mSampleIx;
-    } else {
-        mSampleIx = mHistoryLength - 1;
-    }
-
-    // return estimation result
-    LinearFit total;
-    total.combine(mHead);
-    total.combine(mMain);
-    total.combine(mTail);
-    return total.interpolate(x);
-}
-
-void WindowedLinearFitEstimator::reset() {
-    mHead.reset();
-    mMain.reset();
-    mTail.reset();
-    mNumSamples = 0;
-    mSampleIx = mHistoryLength - 1;
-}
-
-}; // namespace android
-
-
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 8893e9c..ce67d78 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -193,6 +193,22 @@
 }
 
 // static
+status_t MediaCodec::QueryCapabilities(
+        const AString &name, const AString &mime, bool isEncoder,
+        sp<MediaCodecInfo::Capabilities> *caps /* nonnull */) {
+    // TRICKY: this method is used by MediaCodecList/Info during its
+    // initialization. As such, we cannot create a MediaCodec instance
+    // because that requires an initialized MediaCodecList.
+
+    sp<CodecBase> codec = GetCodecBase(name);
+    if (codec == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return codec->queryCapabilities(name, mime, isEncoder, caps);
+}
+
+// static
 sp<PersistentSurface> MediaCodec::CreatePersistentInputSurface() {
     OMXClient client;
     CHECK_EQ(client.connect(), (status_t)OK);
@@ -298,6 +314,18 @@
     response->postReply(replyID);
 }
 
+//static
+sp<CodecBase> MediaCodec::GetCodecBase(const AString &name, bool nameIsType) {
+    // at this time only ACodec specifies a mime type.
+    if (nameIsType || name.startsWithIgnoreCase("omx.")) {
+        return new ACodec;
+    } else if (name.startsWithIgnoreCase("android.filter.")) {
+        return new MediaFilter;
+    } else {
+        return NULL;
+    }
+}
+
 status_t MediaCodec::init(const AString &name, bool nameIsType, bool encoder) {
     mResourceManagerService->init();
 
@@ -311,12 +339,8 @@
     // we need to invest in an extra looper to free the main event
     // queue.
 
-    if (nameIsType || !strncasecmp(name.c_str(), "omx.", 4)) {
-        mCodec = new ACodec;
-    } else if (!nameIsType
-            && !strncasecmp(name.c_str(), "android.filter.", 15)) {
-        mCodec = new MediaFilter;
-    } else {
+    mCodec = GetCodecBase(name, nameIsType);
+    if (mCodec == NULL) {
         return NAME_NOT_FOUND;
     }
 
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index c049097..200796c 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -31,10 +31,10 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/ACodec.h>
+#include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
 
 #include <sys/stat.h>
 #include <utils/threads.h>
@@ -752,18 +752,22 @@
     ALOGV("initializeCapabilities %s:%s",
             mCurrentInfo->mName.c_str(), type);
 
-    CodecCapabilities caps;
-    status_t err = QueryCodec(
-            mOMX,
-            mCurrentInfo->mName.c_str(),
+    sp<MediaCodecInfo::Capabilities> caps;
+    status_t err = MediaCodec::QueryCapabilities(
+            mCurrentInfo->mName,
             type,
             mCurrentInfo->mIsEncoder,
             &caps);
     if (err != OK) {
         return err;
+    } else if (caps == NULL) {
+        ALOGE("MediaCodec::QueryCapabilities returned OK but no capabilities for '%s':'%s':'%s'",
+                mCurrentInfo->mName.c_str(), type,
+                mCurrentInfo->mIsEncoder ? "encoder" : "decoder");
+        return UNKNOWN_ERROR;
     }
 
-    return mCurrentInfo->initializeCapabilities(caps);
+    return mCurrentInfo->setCapabilitiesFromCodec(caps);
 }
 
 status_t MediaCodecList::addQuirk(const char **attrs) {
diff --git a/media/libstagefright/TimeSource.cpp b/media/libstagefright/TimeSource.cpp
deleted file mode 100644
index 041980f..0000000
--- a/media/libstagefright/TimeSource.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stddef.h>
-#include <sys/time.h>
-
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/TimeSource.h>
-
-namespace android {
-
-SystemTimeSource::SystemTimeSource()
-    : mStartTimeUs(ALooper::GetNowUs()) {
-}
-
-int64_t SystemTimeSource::getRealTimeUs() {
-    return ALooper::GetNowUs() - mStartTimeUs;
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index ae3cb33..6132a2c 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -23,6 +23,7 @@
 #include "SoftOMXPlugin.h"
 
 #include <dlfcn.h>
+#include <fcntl.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 
@@ -30,6 +31,29 @@
 
 OMXMaster::OMXMaster()
     : mVendorLibHandle(NULL) {
+
+    mProcessName[0] = 0;
+    if (mProcessName[0] == 0) {
+        pid_t pid = getpid();
+        char filename[20];
+        snprintf(filename, sizeof(filename), "/proc/%d/comm", pid);
+        int fd = open(filename, O_RDONLY);
+        if (fd < 0) {
+            ALOGW("couldn't determine process name");
+            sprintf(mProcessName, "<unknown>");
+        } else {
+            ssize_t len = read(fd, mProcessName, sizeof(mProcessName));
+            if (len < 2) {
+                ALOGW("couldn't determine process name");
+                sprintf(mProcessName, "<unknown>");
+            } else {
+                // the name is newline terminated, so erase the newline
+                mProcessName[len - 1] = 0;
+            }
+            close(fd);
+        }
+    }
+
     addVendorPlugin();
     addPlugin(new SoftOMXPlugin);
 }
@@ -123,6 +147,7 @@
         const OMX_CALLBACKTYPE *callbacks,
         OMX_PTR appData,
         OMX_COMPONENTTYPE **component) {
+    ALOGI("makeComponentInstance(%s) in %s process", name, mProcessName);
     Mutex::Autolock autoLock(mLock);
 
     *component = NULL;
diff --git a/media/libstagefright/omx/OMXMaster.h b/media/libstagefright/omx/OMXMaster.h
index 6069741..3f9c0ca 100644
--- a/media/libstagefright/omx/OMXMaster.h
+++ b/media/libstagefright/omx/OMXMaster.h
@@ -50,6 +50,7 @@
             Vector<String8> *roles);
 
 private:
+    char mProcessName[16];
     Mutex mLock;
     List<OMXPluginBase *> mPlugins;
     KeyedVector<String8, OMXPluginBase *> mPluginByComponentName;
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 5159de3..6e21c14 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -27,7 +27,7 @@
 #include <binder/IServiceManager.h>
 #include <binder/MemoryDealer.h>
 #include <media/IMediaHTTPService.h>
-#include <media/IMediaPlayerService.h>
+#include <media/IMediaCodecService.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/DataSource.h>
@@ -57,8 +57,8 @@
 
 status_t Harness::initOMX() {
     sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> binder = sm->getService(String16("media.player"));
-    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+    sp<IBinder> binder = sm->getService(String16("media.codec"));
+    sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
     mOMX = service->getOMX();
 
     return mOMX != 0 ? OK : NO_INIT;
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 3932339..eedbb42 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -1135,6 +1135,7 @@
                      result, strerror(-result));
 
                 mCheckPending = false;
+                ++mCheckGeneration;
                 postAccessUnitTimeoutCheck();
 
                 if (result == OK) {
@@ -1286,6 +1287,7 @@
                      result, strerror(-result));
 
                 mCheckPending = false;
+                ++mCheckGeneration;
                 postAccessUnitTimeoutCheck();
 
                 if (result == OK) {
diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk
index 4d4ffba..f2c6365 100644
--- a/media/libstagefright/timedtext/Android.mk
+++ b/media/libstagefright/timedtext/Android.mk
@@ -3,11 +3,6 @@
 
 LOCAL_SRC_FILES:=                 \
         TextDescriptions.cpp      \
-        TimedTextDriver.cpp       \
-        TimedText3GPPSource.cpp \
-        TimedTextSource.cpp       \
-        TimedTextSRTSource.cpp    \
-        TimedTextPlayer.cpp
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 LOCAL_CLANG := true
diff --git a/media/libstagefright/timedtext/TimedText3GPPSource.cpp b/media/libstagefright/timedtext/TimedText3GPPSource.cpp
deleted file mode 100644
index 0c8fb79..0000000
--- a/media/libstagefright/timedtext/TimedText3GPPSource.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
- /*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "TimedText3GPPSource"
-#include <utils/Log.h>
-
-#include <binder/Parcel.h>
-#include <media/stagefright/foundation/ADebug.h>  // CHECK_XX macro
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDefs.h>  // for MEDIA_MIMETYPE_xxx
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-
-#include "TimedText3GPPSource.h"
-#include "TextDescriptions.h"
-
-namespace android {
-
-TimedText3GPPSource::TimedText3GPPSource(const sp<IMediaSource>& mediaSource)
-    : mSource(mediaSource) {
-}
-
-TimedText3GPPSource::~TimedText3GPPSource() {
-}
-
-status_t TimedText3GPPSource::read(
-        int64_t *startTimeUs, int64_t *endTimeUs, Parcel *parcel,
-        const MediaSource::ReadOptions *options) {
-    MediaBuffer *textBuffer = NULL;
-    status_t err = mSource->read(&textBuffer, options);
-    if (err != OK) {
-        return err;
-    }
-    CHECK(textBuffer != NULL);
-    textBuffer->meta_data()->findInt64(kKeyTime, startTimeUs);
-    CHECK_GE(*startTimeUs, 0);
-    extractAndAppendLocalDescriptions(*startTimeUs, textBuffer, parcel);
-    textBuffer->release();
-    // endTimeUs is a dummy parameter for 3gpp timed text format.
-    // Set a negative value to it to mark it is unavailable.
-    *endTimeUs = -1;
-    return OK;
-}
-
-// Each text sample consists of a string of text, optionally with sample
-// modifier description. The modifier description could specify a new
-// text style for the string of text. These descriptions are present only
-// if they are needed. This method is used to extract the modifier
-// description and append it at the end of the text.
-status_t TimedText3GPPSource::extractAndAppendLocalDescriptions(
-        int64_t timeUs, const MediaBuffer *textBuffer, Parcel *parcel) {
-    const void *data;
-    size_t size = 0;
-    int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS;
-
-    const char *mime;
-    CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
-    CHECK(strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) == 0);
-
-    data = textBuffer->data();
-    size = textBuffer->size();
-
-    if (size > 0) {
-      parcel->freeData();
-      flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
-      return TextDescriptions::getParcelOfDescriptions(
-          (const uint8_t *)data, size, flag, timeUs / 1000, parcel);
-    }
-    return OK;
-}
-
-// To extract and send the global text descriptions for all the text samples
-// in the text track or text file.
-// TODO: send error message to application via notifyListener()...?
-status_t TimedText3GPPSource::extractGlobalDescriptions(Parcel *parcel) {
-    const void *data;
-    size_t size = 0;
-    int32_t flag = TextDescriptions::GLOBAL_DESCRIPTIONS;
-
-    const char *mime;
-    CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
-    CHECK(strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) == 0);
-
-    uint32_t type;
-    // get the 'tx3g' box content. This box contains the text descriptions
-    // used to render the text track
-    if (!mSource->getFormat()->findData(
-            kKeyTextFormatData, &type, &data, &size)) {
-        return ERROR_MALFORMED;
-    }
-
-    if (size > 0) {
-        flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
-        return TextDescriptions::getParcelOfDescriptions(
-                (const uint8_t *)data, size, flag, 0, parcel);
-    }
-    return OK;
-}
-
-sp<MetaData> TimedText3GPPSource::getFormat() {
-    return mSource->getFormat();
-}
-
-}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedText3GPPSource.h b/media/libstagefright/timedtext/TimedText3GPPSource.h
deleted file mode 100644
index fdc79ca..0000000
--- a/media/libstagefright/timedtext/TimedText3GPPSource.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TIMED_TEXT_3GPP_SOURCE_H_
-#define TIMED_TEXT_3GPP_SOURCE_H_
-
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-
-#include "TimedTextSource.h"
-
-namespace android {
-
-class MediaBuffer;
-class Parcel;
-
-class TimedText3GPPSource : public TimedTextSource {
-public:
-    TimedText3GPPSource(const sp<IMediaSource>& mediaSource);
-    virtual status_t start() { return mSource->start(); }
-    virtual status_t stop() { return mSource->stop(); }
-    virtual status_t read(
-            int64_t *startTimeUs,
-            int64_t *endTimeUs,
-            Parcel *parcel,
-            const MediaSource::ReadOptions *options = NULL);
-    virtual status_t extractGlobalDescriptions(Parcel *parcel);
-    virtual sp<MetaData> getFormat();
-
-protected:
-    virtual ~TimedText3GPPSource();
-
-private:
-    sp<IMediaSource> mSource;
-
-    status_t extractAndAppendLocalDescriptions(
-            int64_t timeUs, const MediaBuffer *textBuffer, Parcel *parcel);
-
-    DISALLOW_EVIL_CONSTRUCTORS(TimedText3GPPSource);
-};
-
-}  // namespace android
-
-#endif  // TIMED_TEXT_3GPP_SOURCE_H_
diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp
deleted file mode 100644
index fd0eebb..0000000
--- a/media/libstagefright/timedtext/TimedTextDriver.cpp
+++ /dev/null
@@ -1,287 +0,0 @@
- /*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "TimedTextDriver"
-#include <utils/Log.h>
-
-#include <binder/IPCThreadState.h>
-
-#include <media/IMediaHTTPService.h>
-#include <media/mediaplayer.h>
-#include <media/MediaPlayerInterface.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/timedtext/TimedTextDriver.h>
-
-#include "TextDescriptions.h"
-#include "TimedTextPlayer.h"
-#include "TimedTextSource.h"
-
-namespace android {
-
-TimedTextDriver::TimedTextDriver(
-        const wp<MediaPlayerBase> &listener,
-        const sp<IMediaHTTPService> &httpService)
-    : mLooper(new ALooper),
-      mListener(listener),
-      mHTTPService(httpService),
-      mState(UNINITIALIZED),
-      mCurrentTrackIndex(UINT_MAX) {
-    mLooper->setName("TimedTextDriver");
-    mLooper->start();
-    mPlayer = new TimedTextPlayer(listener);
-    mLooper->registerHandler(mPlayer);
-}
-
-TimedTextDriver::~TimedTextDriver() {
-    mTextSourceVector.clear();
-    mTextSourceTypeVector.clear();
-    mLooper->stop();
-}
-
-status_t TimedTextDriver::selectTrack_l(size_t index) {
-    if (mCurrentTrackIndex == index) {
-        return OK;
-    }
-    sp<TimedTextSource> source;
-    source = mTextSourceVector.valueFor(index);
-    mPlayer->setDataSource(source);
-    if (mState == UNINITIALIZED) {
-        mState = PREPARED;
-    }
-    mCurrentTrackIndex = index;
-    return OK;
-}
-
-status_t TimedTextDriver::start() {
-    Mutex::Autolock autoLock(mLock);
-    switch (mState) {
-        case UNINITIALIZED:
-            return INVALID_OPERATION;
-        case PLAYING:
-            return OK;
-        case PREPARED:
-            mPlayer->start();
-            mState = PLAYING;
-            return OK;
-        case PAUSED:
-            mPlayer->resume();
-            mState = PLAYING;
-            return OK;
-        default:
-            TRESPASS();
-    }
-    return UNKNOWN_ERROR;
-}
-
-status_t TimedTextDriver::pause() {
-    Mutex::Autolock autoLock(mLock);
-    ALOGV("%s() is called", __FUNCTION__);
-    switch (mState) {
-        case UNINITIALIZED:
-            return INVALID_OPERATION;
-        case PLAYING:
-            mPlayer->pause();
-            mState = PAUSED;
-            return OK;
-        case PREPARED:
-            return INVALID_OPERATION;
-        case PAUSED:
-            return OK;
-        default:
-            TRESPASS();
-    }
-    return UNKNOWN_ERROR;
-}
-
-status_t TimedTextDriver::selectTrack(size_t index) {
-    status_t ret = OK;
-    Mutex::Autolock autoLock(mLock);
-    ALOGV("%s() is called", __FUNCTION__);
-    switch (mState) {
-        case UNINITIALIZED:
-        case PREPARED:
-        case PAUSED:
-            ret = selectTrack_l(index);
-            break;
-        case PLAYING:
-            mPlayer->pause();
-            ret = selectTrack_l(index);
-            if (ret != OK) {
-                break;
-            }
-            mPlayer->start();
-            break;
-        default:
-            TRESPASS();
-    }
-    return ret;
-}
-
-status_t TimedTextDriver::unselectTrack(size_t index) {
-    Mutex::Autolock autoLock(mLock);
-    ALOGV("%s() is called", __FUNCTION__);
-    if (mCurrentTrackIndex != index) {
-        return INVALID_OPERATION;
-    }
-    mCurrentTrackIndex = UINT_MAX;
-    switch (mState) {
-        case UNINITIALIZED:
-            return INVALID_OPERATION;
-        case PLAYING:
-            mPlayer->setDataSource(NULL);
-            mState = UNINITIALIZED;
-            return OK;
-        case PREPARED:
-        case PAUSED:
-            mState = UNINITIALIZED;
-            return OK;
-        default:
-            TRESPASS();
-    }
-    return UNKNOWN_ERROR;
-}
-
-status_t TimedTextDriver::seekToAsync(int64_t timeUs) {
-    Mutex::Autolock autoLock(mLock);
-    ALOGV("%s() is called", __FUNCTION__);
-    switch (mState) {
-        case UNINITIALIZED:
-            return INVALID_OPERATION;
-        case PREPARED:
-            mPlayer->seekToAsync(timeUs);
-            mPlayer->pause();
-            mState = PAUSED;
-            return OK;
-        case PAUSED:
-            mPlayer->seekToAsync(timeUs);
-            mPlayer->pause();
-            return OK;
-        case PLAYING:
-            mPlayer->seekToAsync(timeUs);
-            return OK;
-        default:
-            TRESPASS();
-    }
-    return UNKNOWN_ERROR;
-}
-
-status_t TimedTextDriver::addInBandTextSource(
-        size_t trackIndex, const sp<IMediaSource>& mediaSource) {
-    sp<TimedTextSource> source =
-            TimedTextSource::CreateTimedTextSource(mediaSource);
-    if (source == NULL) {
-        return ERROR_UNSUPPORTED;
-    }
-    Mutex::Autolock autoLock(mLock);
-    mTextSourceVector.add(trackIndex, source);
-    mTextSourceTypeVector.add(TEXT_SOURCE_TYPE_IN_BAND);
-    return OK;
-}
-
-status_t TimedTextDriver::addOutOfBandTextSource(
-        size_t trackIndex, const char *uri, const char *mimeType) {
-
-    // To support local subtitle file only for now
-    if (strncasecmp("file://", uri, 7)) {
-        ALOGE("uri('%s') is not a file", uri);
-        return ERROR_UNSUPPORTED;
-    }
-
-    sp<DataSource> dataSource =
-            DataSource::CreateFromURI(mHTTPService, uri);
-    return createOutOfBandTextSource(trackIndex, mimeType, dataSource);
-}
-
-status_t TimedTextDriver::addOutOfBandTextSource(
-        size_t trackIndex, int fd, off64_t offset, off64_t length, const char *mimeType) {
-
-    if (fd < 0) {
-        ALOGE("Invalid file descriptor: %d", fd);
-        return ERROR_UNSUPPORTED;
-    }
-
-    sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
-    return createOutOfBandTextSource(trackIndex, mimeType, dataSource);
-}
-
-status_t TimedTextDriver::createOutOfBandTextSource(
-        size_t trackIndex,
-        const char *mimeType,
-        const sp<DataSource>& dataSource) {
-
-    if (dataSource == NULL) {
-        return ERROR_UNSUPPORTED;
-    }
-
-    sp<TimedTextSource> source;
-    if (strcasecmp(mimeType, MEDIA_MIMETYPE_TEXT_SUBRIP) == 0) {
-        source = TimedTextSource::CreateTimedTextSource(
-                dataSource, TimedTextSource::OUT_OF_BAND_FILE_SRT);
-    }
-
-    if (source == NULL) {
-        ALOGE("Failed to create timed text source");
-        return ERROR_UNSUPPORTED;
-    }
-
-    Mutex::Autolock autoLock(mLock);
-    mTextSourceVector.add(trackIndex, source);
-    mTextSourceTypeVector.add(TEXT_SOURCE_TYPE_OUT_OF_BAND);
-    return OK;
-}
-
-size_t TimedTextDriver::countExternalTracks() const {
-    size_t nTracks = 0;
-    for (size_t i = 0, n = mTextSourceTypeVector.size(); i < n; ++i) {
-        if (mTextSourceTypeVector[i] == TEXT_SOURCE_TYPE_OUT_OF_BAND) {
-            ++nTracks;
-        }
-    }
-    return nTracks;
-}
-
-void TimedTextDriver::getExternalTrackInfo(Parcel *parcel) {
-    Mutex::Autolock autoLock(mLock);
-    for (size_t i = 0, n = mTextSourceTypeVector.size(); i < n; ++i) {
-        if (mTextSourceTypeVector[i] == TEXT_SOURCE_TYPE_IN_BAND) {
-            continue;
-        }
-
-        sp<MetaData> meta = mTextSourceVector.valueAt(i)->getFormat();
-
-        // There are two fields.
-        parcel->writeInt32(2);
-
-        // track type.
-        parcel->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
-        const char *lang = "und";
-        if (meta != NULL) {
-            meta->findCString(kKeyMediaLanguage, &lang);
-        }
-        parcel->writeString16(String16(lang));
-    }
-}
-
-}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
deleted file mode 100644
index aecf666..0000000
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ /dev/null
@@ -1,316 +0,0 @@
- /*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "TimedTextPlayer"
-#include <utils/Log.h>
-
-#include <inttypes.h>
-#include <limits.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/timedtext/TimedTextDriver.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/MediaPlayerInterface.h>
-
-#include "TimedTextPlayer.h"
-
-#include "TimedTextSource.h"
-
-namespace android {
-
-// Event should be fired a bit earlier considering the processing time till
-// application actually gets the notification message.
-static const int64_t kAdjustmentProcessingTimeUs = 100000ll;
-static const int64_t kMaxDelayUs = 5000000ll;
-static const int64_t kWaitTimeUsToRetryRead = 100000ll;
-static const int64_t kInvalidTimeUs = INT_MIN;
-
-TimedTextPlayer::TimedTextPlayer(const wp<MediaPlayerBase> &listener)
-    : mListener(listener),
-      mSource(NULL),
-      mPendingSeekTimeUs(kInvalidTimeUs),
-      mPaused(false),
-      mSendSubtitleGeneration(0) {
-}
-
-TimedTextPlayer::~TimedTextPlayer() {
-    if (mSource != NULL) {
-        mSource->stop();
-        mSource.clear();
-        mSource = NULL;
-    }
-}
-
-void TimedTextPlayer::start() {
-    (new AMessage(kWhatStart, this))->post();
-}
-
-void TimedTextPlayer::pause() {
-    (new AMessage(kWhatPause, this))->post();
-}
-
-void TimedTextPlayer::resume() {
-    (new AMessage(kWhatResume, this))->post();
-}
-
-void TimedTextPlayer::seekToAsync(int64_t timeUs) {
-    sp<AMessage> msg = new AMessage(kWhatSeek, this);
-    msg->setInt64("seekTimeUs", timeUs);
-    msg->post();
-}
-
-void TimedTextPlayer::setDataSource(sp<TimedTextSource> source) {
-    sp<AMessage> msg = new AMessage(kWhatSetSource, this);
-    msg->setObject("source", source);
-    msg->post();
-}
-
-void TimedTextPlayer::onMessageReceived(const sp<AMessage> &msg) {
-    switch (msg->what()) {
-        case kWhatPause: {
-            mPaused = true;
-            break;
-        }
-        case kWhatResume: {
-            mPaused = false;
-            if (mPendingSeekTimeUs != kInvalidTimeUs) {
-                seekToAsync(mPendingSeekTimeUs);
-                mPendingSeekTimeUs = kInvalidTimeUs;
-            } else {
-                doRead();
-            }
-            break;
-        }
-        case kWhatStart: {
-            sp<MediaPlayerBase> listener = mListener.promote();
-            if (listener == NULL) {
-                ALOGE("Listener is NULL when kWhatStart is received.");
-                break;
-            }
-            mPaused = false;
-            mPendingSeekTimeUs = kInvalidTimeUs;
-            int32_t positionMs = 0;
-            listener->getCurrentPosition(&positionMs);
-            int64_t seekTimeUs = positionMs * 1000ll;
-
-            notifyListener();
-            mSendSubtitleGeneration++;
-            doSeekAndRead(seekTimeUs);
-            break;
-        }
-        case kWhatRetryRead: {
-            int32_t generation = -1;
-            CHECK(msg->findInt32("generation", &generation));
-            if (generation != mSendSubtitleGeneration) {
-                // Drop obsolete msg.
-                break;
-            }
-            int64_t seekTimeUs;
-            int seekMode;
-            if (msg->findInt64("seekTimeUs", &seekTimeUs) &&
-                msg->findInt32("seekMode", &seekMode)) {
-                MediaSource::ReadOptions options;
-                options.setSeekTo(
-                    seekTimeUs,
-                    static_cast<MediaSource::ReadOptions::SeekMode>(seekMode));
-                doRead(&options);
-            } else {
-                doRead();
-            }
-            break;
-        }
-        case kWhatSeek: {
-            int64_t seekTimeUs = kInvalidTimeUs;
-            // Clear a displayed timed text before seeking.
-            notifyListener();
-            msg->findInt64("seekTimeUs", &seekTimeUs);
-            if (seekTimeUs == kInvalidTimeUs) {
-                sp<MediaPlayerBase> listener = mListener.promote();
-                if (listener != NULL) {
-                    int32_t positionMs = 0;
-                    listener->getCurrentPosition(&positionMs);
-                    seekTimeUs = positionMs * 1000ll;
-                }
-            }
-            if (mPaused) {
-                mPendingSeekTimeUs = seekTimeUs;
-                break;
-            }
-            mSendSubtitleGeneration++;
-            doSeekAndRead(seekTimeUs);
-            break;
-        }
-        case kWhatSendSubtitle: {
-            int32_t generation;
-            CHECK(msg->findInt32("generation", &generation));
-            if (generation != mSendSubtitleGeneration) {
-                // Drop obsolete msg.
-                break;
-            }
-            // If current time doesn't reach to the fire time,
-            // re-post the message with the adjusted delay time.
-            int64_t fireTimeUs = kInvalidTimeUs;
-            if (msg->findInt64("fireTimeUs", &fireTimeUs)) {
-                // TODO: check if fireTimeUs is not kInvalidTimeUs.
-                int64_t delayUs = delayUsFromCurrentTime(fireTimeUs);
-                if (delayUs > 0) {
-                    msg->post(delayUs);
-                    break;
-                }
-            }
-            sp<RefBase> obj;
-            if (msg->findObject("subtitle", &obj)) {
-                sp<ParcelEvent> parcelEvent;
-                parcelEvent = static_cast<ParcelEvent*>(obj.get());
-                notifyListener(&(parcelEvent->parcel));
-                doRead();
-            } else {
-                notifyListener();
-            }
-            break;
-        }
-        case kWhatSetSource: {
-            mSendSubtitleGeneration++;
-            sp<RefBase> obj;
-            msg->findObject("source", &obj);
-            if (mSource != NULL) {
-                mSource->stop();
-                mSource.clear();
-                mSource = NULL;
-            }
-            // null source means deselect track.
-            if (obj == NULL) {
-                mPendingSeekTimeUs = kInvalidTimeUs;
-                mPaused = false;
-                notifyListener();
-                break;
-            }
-            mSource = static_cast<TimedTextSource*>(obj.get());
-            status_t err = mSource->start();
-            if (err != OK) {
-                notifyError(err);
-                break;
-            }
-            Parcel parcel;
-            err = mSource->extractGlobalDescriptions(&parcel);
-            if (err != OK) {
-                notifyError(err);
-                break;
-            }
-            notifyListener(&parcel);
-            break;
-        }
-    }
-}
-
-void TimedTextPlayer::doSeekAndRead(int64_t seekTimeUs) {
-    MediaSource::ReadOptions options;
-    options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
-    doRead(&options);
-}
-
-void TimedTextPlayer::doRead(MediaSource::ReadOptions* options) {
-    int64_t startTimeUs = 0;
-    int64_t endTimeUs = 0;
-    sp<ParcelEvent> parcelEvent = new ParcelEvent();
-    CHECK(mSource != NULL);
-    status_t err = mSource->read(&startTimeUs, &endTimeUs,
-                                 &(parcelEvent->parcel), options);
-    if (err == WOULD_BLOCK) {
-        sp<AMessage> msg = new AMessage(kWhatRetryRead, this);
-        if (options != NULL) {
-            int64_t seekTimeUs = kInvalidTimeUs;
-            MediaSource::ReadOptions::SeekMode seekMode =
-                MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC;
-            CHECK(options->getSeekTo(&seekTimeUs, &seekMode));
-            msg->setInt64("seekTimeUs", seekTimeUs);
-            msg->setInt32("seekMode", seekMode);
-        }
-        msg->setInt32("generation", mSendSubtitleGeneration);
-        msg->post(kWaitTimeUsToRetryRead);
-        return;
-    } else if (err != OK) {
-        notifyError(err);
-        return;
-    }
-
-    postTextEvent(parcelEvent, startTimeUs);
-    if (endTimeUs > 0) {
-        CHECK_GE(endTimeUs, startTimeUs);
-        // send an empty timed text to clear the subtitle when it reaches to the
-        // end time.
-        postTextEvent(NULL, endTimeUs);
-    }
-}
-
-void TimedTextPlayer::postTextEvent(const sp<ParcelEvent>& parcel, int64_t timeUs) {
-    int64_t delayUs = delayUsFromCurrentTime(timeUs);
-    sp<AMessage> msg = new AMessage(kWhatSendSubtitle, this);
-    msg->setInt32("generation", mSendSubtitleGeneration);
-    if (parcel != NULL) {
-        msg->setObject("subtitle", parcel);
-    }
-    msg->setInt64("fireTimeUs", timeUs);
-    msg->post(delayUs);
-}
-
-int64_t TimedTextPlayer::delayUsFromCurrentTime(int64_t fireTimeUs) {
-    sp<MediaPlayerBase> listener = mListener.promote();
-    if (listener == NULL) {
-        // TODO: it may be better to return kInvalidTimeUs
-        ALOGE("%s: Listener is NULL. (fireTimeUs = %" PRId64" )",
-              __FUNCTION__, fireTimeUs);
-        return 0;
-    }
-    int32_t positionMs = 0;
-    listener->getCurrentPosition(&positionMs);
-    int64_t positionUs = positionMs * 1000ll;
-
-    if (fireTimeUs <= positionUs + kAdjustmentProcessingTimeUs) {
-        return 0;
-    } else {
-        int64_t delayUs = fireTimeUs - positionUs - kAdjustmentProcessingTimeUs;
-        if (delayUs > kMaxDelayUs) {
-            return kMaxDelayUs;
-        }
-        return delayUs;
-    }
-}
-
-void TimedTextPlayer::notifyError(int error) {
-    sp<MediaPlayerBase> listener = mListener.promote();
-    if (listener == NULL) {
-        ALOGE("%s(error=%d): Listener is NULL.", __FUNCTION__, error);
-        return;
-    }
-    listener->sendEvent(MEDIA_INFO, MEDIA_INFO_TIMED_TEXT_ERROR, error);
-}
-
-void TimedTextPlayer::notifyListener(const Parcel *parcel) {
-    sp<MediaPlayerBase> listener = mListener.promote();
-    if (listener == NULL) {
-        ALOGE("%s: Listener is NULL.", __FUNCTION__);
-        return;
-    }
-    if (parcel != NULL && (parcel->dataSize() > 0)) {
-        listener->sendEvent(MEDIA_TIMED_TEXT, 0, 0, parcel);
-    } else {  // send an empty timed text to clear the screen
-        listener->sendEvent(MEDIA_TIMED_TEXT);
-    }
-}
-
-}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.h b/media/libstagefright/timedtext/TimedTextPlayer.h
deleted file mode 100644
index 9cb49ec..0000000
--- a/media/libstagefright/timedtext/TimedTextPlayer.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TIMEDTEXT_PLAYER_H_
-#define TIMEDTEXT_PLAYER_H_
-
-#include <binder/Parcel.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AHandler.h>
-#include <media/stagefright/MediaSource.h>
-#include <utils/RefBase.h>
-
-#include "TimedTextSource.h"
-
-namespace android {
-
-struct AMessage;
-class MediaPlayerBase;
-class TimedTextDriver;
-class TimedTextSource;
-
-class TimedTextPlayer : public AHandler {
-public:
-    TimedTextPlayer(const wp<MediaPlayerBase> &listener);
-
-    virtual ~TimedTextPlayer();
-
-    void start();
-    void pause();
-    void resume();
-    void seekToAsync(int64_t timeUs);
-    void setDataSource(sp<TimedTextSource> source);
-
-protected:
-    virtual void onMessageReceived(const sp<AMessage> &msg);
-
-private:
-    enum {
-        kWhatPause = 'paus',
-        kWhatResume = 'resm',
-        kWhatStart = 'strt',
-        kWhatSeek = 'seek',
-        kWhatRetryRead = 'read',
-        kWhatSendSubtitle = 'send',
-        kWhatSetSource = 'ssrc',
-    };
-
-    // To add Parcel into an AMessage as an object, it should be 'RefBase'.
-    struct ParcelEvent : public RefBase {
-        Parcel parcel;
-    };
-
-    wp<MediaPlayerBase> mListener;
-    sp<TimedTextSource> mSource;
-    int64_t mPendingSeekTimeUs;
-    bool mPaused;
-    int32_t mSendSubtitleGeneration;
-
-    void doSeekAndRead(int64_t seekTimeUs);
-    void doRead(MediaSource::ReadOptions* options = NULL);
-    void onTextEvent();
-    void postTextEvent(const sp<ParcelEvent>& parcel = NULL, int64_t timeUs = -1);
-    int64_t delayUsFromCurrentTime(int64_t fireTimeUs);
-    void notifyError(int error = 0);
-    void notifyListener(const Parcel *parcel = NULL);
-
-    DISALLOW_EVIL_CONSTRUCTORS(TimedTextPlayer);
-};
-
-}  // namespace android
-
-#endif  // TIMEDTEXT_PLAYER_H_
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.cpp b/media/libstagefright/timedtext/TimedTextSRTSource.cpp
deleted file mode 100644
index 2ac1e72..0000000
--- a/media/libstagefright/timedtext/TimedTextSRTSource.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
- /*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "TimedTextSRTSource"
-#include <utils/Log.h>
-
-#include <binder/Parcel.h>
-#include <media/stagefright/foundation/ADebug.h>  // for CHECK_xx
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDefs.h>  // for MEDIA_MIMETYPE_xxx
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-
-#include "TimedTextSRTSource.h"
-#include "TextDescriptions.h"
-
-namespace android {
-
-TimedTextSRTSource::TimedTextSRTSource(const sp<DataSource>& dataSource)
-        : mSource(dataSource),
-          mMetaData(new MetaData),
-          mIndex(0) {
-    // TODO: Need to detect the language, because SRT doesn't give language
-    // information explicitly.
-    mMetaData->setCString(kKeyMediaLanguage, "und");
-}
-
-TimedTextSRTSource::~TimedTextSRTSource() {
-}
-
-status_t TimedTextSRTSource::start() {
-    status_t err = scanFile();
-    if (err != OK) {
-        reset();
-    }
-    return err;
-}
-
-void TimedTextSRTSource::reset() {
-    mTextVector.clear();
-    mIndex = 0;
-}
-
-status_t TimedTextSRTSource::stop() {
-    reset();
-    return OK;
-}
-
-status_t TimedTextSRTSource::read(
-        int64_t *startTimeUs,
-        int64_t *endTimeUs,
-        Parcel *parcel,
-        const MediaSource::ReadOptions *options) {
-    AString text;
-    status_t err = getText(options, &text, startTimeUs, endTimeUs);
-    if (err != OK) {
-        return err;
-    }
-
-    CHECK_GE(*startTimeUs, 0);
-    extractAndAppendLocalDescriptions(*startTimeUs, text, parcel);
-    return OK;
-}
-
-sp<MetaData> TimedTextSRTSource::getFormat() {
-    return mMetaData;
-}
-
-status_t TimedTextSRTSource::scanFile() {
-    off64_t offset = 0;
-    int64_t startTimeUs;
-    bool endOfFile = false;
-
-    while (!endOfFile) {
-        TextInfo info;
-        status_t err = getNextSubtitleInfo(&offset, &startTimeUs, &info);
-        switch (err) {
-            case OK:
-                mTextVector.add(startTimeUs, info);
-                break;
-            case ERROR_END_OF_STREAM:
-                endOfFile = true;
-                break;
-            default:
-                return err;
-        }
-    }
-    if (mTextVector.isEmpty()) {
-        return ERROR_MALFORMED;
-    }
-    return OK;
-}
-
-/* SRT format:
- *   Subtitle number
- *   Start time --> End time
- *   Text of subtitle (one or more lines)
- *   Blank lines
- *
- * .srt file example:
- * 1
- * 00:00:20,000 --> 00:00:24,400
- * Altocumulus clouds occr between six thousand
- *
- * 2
- * 00:00:24,600 --> 00:00:27,800
- * and twenty thousand feet above ground level.
- */
-status_t TimedTextSRTSource::getNextSubtitleInfo(
-          off64_t *offset, int64_t *startTimeUs, TextInfo *info) {
-    AString data;
-    status_t err;
-
-    // To skip blank lines.
-    do {
-        if ((err = readNextLine(offset, &data)) != OK) {
-            return err;
-        }
-        data.trim();
-    } while (data.empty());
-
-    // Just ignore the first non-blank line which is subtitle sequence number.
-    if ((err = readNextLine(offset, &data)) != OK) {
-        return err;
-    }
-    int hour1, hour2, min1, min2, sec1, sec2, msec1, msec2;
-    // the start time format is: hours:minutes:seconds,milliseconds
-    // 00:00:24,600 --> 00:00:27,800
-    if (sscanf(data.c_str(), "%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d",
-               &hour1, &min1, &sec1, &msec1, &hour2, &min2, &sec2, &msec2) != 8) {
-        return ERROR_MALFORMED;
-    }
-
-    *startTimeUs = ((hour1 * 3600 + min1 * 60 + sec1) * 1000 + msec1) * 1000ll;
-    info->endTimeUs = ((hour2 * 3600 + min2 * 60 + sec2) * 1000 + msec2) * 1000ll;
-    if (info->endTimeUs <= *startTimeUs) {
-        return ERROR_MALFORMED;
-    }
-
-    info->offset = *offset;
-    bool needMoreData = true;
-    while (needMoreData) {
-        if ((err = readNextLine(offset, &data)) != OK) {
-            if (err == ERROR_END_OF_STREAM) {
-                break;
-            } else {
-                return err;
-            }
-        }
-
-        data.trim();
-        if (data.empty()) {
-            // it's an empty line used to separate two subtitles
-            needMoreData = false;
-        }
-    }
-    info->textLen = *offset - info->offset;
-    return OK;
-}
-
-status_t TimedTextSRTSource::readNextLine(off64_t *offset, AString *data) {
-    data->clear();
-    while (true) {
-        ssize_t readSize;
-        char character;
-        if ((readSize = mSource->readAt(*offset, &character, 1)) < 1) {
-            if (readSize == 0) {
-                return ERROR_END_OF_STREAM;
-            }
-            return ERROR_IO;
-        }
-
-        (*offset)++;
-
-        // a line could end with CR, LF or CR + LF
-        if (character == 10) {
-            break;
-        } else if (character == 13) {
-            if ((readSize = mSource->readAt(*offset, &character, 1)) < 1) {
-                if (readSize == 0) {  // end of the stream
-                    return OK;
-                }
-                return ERROR_IO;
-            }
-
-            (*offset)++;
-            if (character != 10) {
-                (*offset)--;
-            }
-            break;
-        }
-        data->append(character);
-    }
-    return OK;
-}
-
-status_t TimedTextSRTSource::getText(
-        const MediaSource::ReadOptions *options,
-        AString *text, int64_t *startTimeUs, int64_t *endTimeUs) {
-    if (mTextVector.size() == 0) {
-        return ERROR_END_OF_STREAM;
-    }
-    text->clear();
-    int64_t seekTimeUs;
-    MediaSource::ReadOptions::SeekMode mode;
-    if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
-        int64_t lastEndTimeUs =
-                mTextVector.valueAt(mTextVector.size() - 1).endTimeUs;
-        if (seekTimeUs < 0) {
-            return ERROR_OUT_OF_RANGE;
-        } else if (seekTimeUs >= lastEndTimeUs) {
-            return ERROR_END_OF_STREAM;
-        } else {
-            // binary search
-            size_t low = 0;
-            size_t high = mTextVector.size() - 1;
-            size_t mid = 0;
-
-            while (low <= high) {
-                mid = low + (high - low)/2;
-                int diff = compareExtendedRangeAndTime(mid, seekTimeUs);
-                if (diff == 0) {
-                    break;
-                } else if (diff < 0) {
-                    low = mid + 1;
-                } else {
-                    high = mid - 1;
-                }
-            }
-            mIndex = mid;
-        }
-    }
-
-    if (mIndex >= mTextVector.size()) {
-        return ERROR_END_OF_STREAM;
-    }
-
-    const TextInfo &info = mTextVector.valueAt(mIndex);
-    *startTimeUs = mTextVector.keyAt(mIndex);
-    *endTimeUs = info.endTimeUs;
-    mIndex++;
-
-    char *str = new char[info.textLen];
-    if (mSource->readAt(info.offset, str, info.textLen) < info.textLen) {
-        delete[] str;
-        return ERROR_IO;
-    }
-    text->append(str, info.textLen);
-    delete[] str;
-    return OK;
-}
-
-status_t TimedTextSRTSource::extractAndAppendLocalDescriptions(
-        int64_t timeUs, const AString &text, Parcel *parcel) {
-    const void *data = text.c_str();
-    size_t size = text.size();
-    int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS |
-                   TextDescriptions::OUT_OF_BAND_TEXT_SRT;
-
-    if (size > 0) {
-        return TextDescriptions::getParcelOfDescriptions(
-                (const uint8_t *)data, size, flag, timeUs / 1000, parcel);
-    }
-    return OK;
-}
-
-int TimedTextSRTSource::compareExtendedRangeAndTime(size_t index, int64_t timeUs) {
-    CHECK_LT(index, mTextVector.size());
-    int64_t endTimeUs = mTextVector.valueAt(index).endTimeUs;
-    int64_t startTimeUs = (index > 0) ?
-            mTextVector.valueAt(index - 1).endTimeUs : 0;
-    if (timeUs >= startTimeUs && timeUs < endTimeUs) {
-        return 0;
-    } else if (endTimeUs <= timeUs) {
-        return -1;
-    } else {
-        return 1;
-    }
-}
-
-}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.h b/media/libstagefright/timedtext/TimedTextSRTSource.h
deleted file mode 100644
index 232675e..0000000
--- a/media/libstagefright/timedtext/TimedTextSRTSource.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TIMED_TEXT_SRT_SOURCE_H_
-#define TIMED_TEXT_SRT_SOURCE_H_
-
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-#include <utils/Compat.h>  // off64_t
-
-#include "TimedTextSource.h"
-
-namespace android {
-
-struct AString;
-class DataSource;
-class MediaBuffer;
-class Parcel;
-
-class TimedTextSRTSource : public TimedTextSource {
-public:
-    TimedTextSRTSource(const sp<DataSource>& dataSource);
-    virtual status_t start();
-    virtual status_t stop();
-    virtual status_t read(
-            int64_t *startTimeUs,
-            int64_t *endTimeUs,
-            Parcel *parcel,
-            const MediaSource::ReadOptions *options = NULL);
-    virtual sp<MetaData> getFormat();
-
-protected:
-    virtual ~TimedTextSRTSource();
-
-private:
-    sp<DataSource> mSource;
-    sp<MetaData> mMetaData;
-
-    struct TextInfo {
-        int64_t endTimeUs;
-        // The offset of the text in the original file.
-        off64_t offset;
-        int textLen;
-    };
-
-    size_t mIndex;
-    KeyedVector<int64_t, TextInfo> mTextVector;
-
-    void reset();
-    status_t scanFile();
-    status_t getNextSubtitleInfo(
-            off64_t *offset, int64_t *startTimeUs, TextInfo *info);
-    status_t readNextLine(off64_t *offset, AString *data);
-    status_t getText(
-            const MediaSource::ReadOptions *options,
-            AString *text, int64_t *startTimeUs, int64_t *endTimeUs);
-    status_t extractAndAppendLocalDescriptions(
-            int64_t timeUs, const AString &text, Parcel *parcel);
-
-    // Compares the time range of the subtitle at index to the given timeUs.
-    // The time range of the subtitle to match with given timeUs is extended to
-    // [endTimeUs of the previous subtitle, endTimeUs of current subtitle).
-    //
-    // This compare function is used to find a next subtitle when read() is
-    // called with seek options. Note that timeUs within gap ranges, such as
-    // [200, 300) in the below example, will be matched to the closest future
-    // subtitle, [300, 400).
-    //
-    // For instance, assuming there are 3 subtitles in mTextVector,
-    // 0: [100, 200)      ----> [0, 200)
-    // 1: [300, 400)      ----> [200, 400)
-    // 2: [500, 600)      ----> [400, 600)
-    // If the 'index' parameter contains 1, this function
-    // returns 0, if timeUs is in [200, 400)
-    // returns -1, if timeUs >= 400,
-    // returns 1, if timeUs < 200.
-    int compareExtendedRangeAndTime(size_t index, int64_t timeUs);
-
-    DISALLOW_EVIL_CONSTRUCTORS(TimedTextSRTSource);
-};
-
-}  // namespace android
-
-#endif  // TIMED_TEXT_SRT_SOURCE_H_
diff --git a/media/libstagefright/timedtext/TimedTextSource.cpp b/media/libstagefright/timedtext/TimedTextSource.cpp
deleted file mode 100644
index e5aa382..0000000
--- a/media/libstagefright/timedtext/TimedTextSource.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
- /*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "TimedTextSource"
-#include <utils/Log.h>
-
-#include <media/stagefright/foundation/ADebug.h>  // CHECK_XX macro
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDefs.h>  // for MEDIA_MIMETYPE_xxx
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-
-#include "TimedTextSource.h"
-
-#include "TimedText3GPPSource.h"
-#include "TimedTextSRTSource.h"
-
-namespace android {
-
-// static
-sp<TimedTextSource> TimedTextSource::CreateTimedTextSource(
-        const sp<IMediaSource>& mediaSource) {
-    const char *mime;
-    CHECK(mediaSource->getFormat()->findCString(kKeyMIMEType, &mime));
-    if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) == 0) {
-        return new TimedText3GPPSource(mediaSource);
-    }
-    ALOGE("Unsupported mime type for subtitle. : %s", mime);
-    return NULL;
-}
-
-// static
-sp<TimedTextSource> TimedTextSource::CreateTimedTextSource(
-        const sp<DataSource>& dataSource, FileType filetype) {
-    switch(filetype) {
-        case OUT_OF_BAND_FILE_SRT:
-            return new TimedTextSRTSource(dataSource);
-        case OUT_OF_BAND_FILE_SMI:
-            // TODO: Implement for SMI.
-            ALOGE("Supporting SMI is not implemented yet");
-            break;
-        default:
-            ALOGE("Undefined subtitle format. : %d", filetype);
-    }
-    return NULL;
-}
-
-sp<MetaData> TimedTextSource::getFormat() {
-    return NULL;
-}
-
-}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextSource.h b/media/libstagefright/timedtext/TimedTextSource.h
deleted file mode 100644
index 9946721..0000000
--- a/media/libstagefright/timedtext/TimedTextSource.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TIMED_TEXT_SOURCE_H_
-#define TIMED_TEXT_SOURCE_H_
-
-#include <media/stagefright/foundation/ABase.h>  // for DISALLOW_XXX macro.
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>  // for MediaSource::ReadOptions
-#include <utils/RefBase.h>
-
-namespace android {
-
-class DataSource;
-class MetaData;
-class Parcel;
-
-class TimedTextSource : public RefBase {
- public:
-  enum FileType {
-      OUT_OF_BAND_FILE_SRT = 1,
-      OUT_OF_BAND_FILE_SMI = 2,
-  };
-  static sp<TimedTextSource> CreateTimedTextSource(
-      const sp<IMediaSource>& source);
-  static sp<TimedTextSource> CreateTimedTextSource(
-      const sp<DataSource>& source, FileType filetype);
-  TimedTextSource() {}
-  virtual status_t start() = 0;
-  virtual status_t stop() = 0;
-  // Returns subtitle parcel and its start time.
-  virtual status_t read(
-          int64_t *startTimeUs,
-          int64_t *endTimeUs,
-          Parcel *parcel,
-          const MediaSource::ReadOptions *options = NULL) = 0;
-  virtual status_t extractGlobalDescriptions(Parcel * /* parcel */) {
-      return INVALID_OPERATION;
-  }
-  virtual sp<MetaData> getFormat();
-
- protected:
-  virtual ~TimedTextSource() { }
-
- private:
-  DISALLOW_EVIL_CONSTRUCTORS(TimedTextSource);
-};
-
-}  // namespace android
-
-#endif  // TIMED_TEXT_SOURCE_H_
diff --git a/media/libstagefright/timedtext/test/Android.mk b/media/libstagefright/timedtext/test/Android.mk
deleted file mode 100644
index e0e0e0d..0000000
--- a/media/libstagefright/timedtext/test/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# ================================================================
-# Unit tests for libstagefright_timedtext
-# ================================================================
-
-# ================================================================
-# A test for TimedTextSRTSource
-# ================================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := TimedTextSRTSource_test
-
-LOCAL_MODULE_TAGS := eng tests
-
-LOCAL_SRC_FILES := TimedTextSRTSource_test.cpp
-
-LOCAL_C_INCLUDES := \
-    $(TOP)/external/expat/lib \
-    $(TOP)/frameworks/av/media/libstagefright/timedtext
-
-LOCAL_SHARED_LIBRARIES := \
-    libbinder \
-    libexpat \
-    libstagefright \
-    libstagefright_foundation \
-    libutils
-
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CLANG := true
-
-include $(BUILD_NATIVE_TEST)
diff --git a/media/libstagefright/timedtext/test/TimedTextSRTSource_test.cpp b/media/libstagefright/timedtext/test/TimedTextSRTSource_test.cpp
deleted file mode 100644
index 211e732..0000000
--- a/media/libstagefright/timedtext/test/TimedTextSRTSource_test.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "TimedTextSRTSource_test"
-#include <utils/Log.h>
-
-#include <gtest/gtest.h>
-
-#include <binder/Parcel.h>
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaErrors.h>
-#include <utils/misc.h>
-
-#include <TimedTextSource.h>
-#include <TimedTextSRTSource.h>
-
-namespace android {
-namespace test {
-
-static const int kSecToUsec = 1000000;
-static const int kSecToMsec = 1000;
-static const int kMsecToUsec = 1000;
-
-/* SRT format (http://en.wikipedia.org/wiki/SubRip)
- *   Subtitle number
- *   Start time --> End time
- *   Text of subtitle (one or more lines)
- *   Blank lines
- */
-static const char *kSRTString =
-    "1\n00:00:1,000 --> 00:00:1,500\n1\n\n"
-    "2\n00:00:2,000 --> 00:00:2,500\n2\n\n"
-    "3\n00:00:3,000 --> 00:00:3,500\n3\n\n"
-    "4\n00:00:4,000 --> 00:00:4,500\n4\n\n"
-    "5\n00:00:5,000 --> 00:00:5,500\n5\n\n"
-    // edge case : previos end time = next start time
-    "6\n00:00:5,500 --> 00:00:5,800\n6\n\n"
-    "7\n00:00:5,800 --> 00:00:6,000\n7\n\n"
-    "8\n00:00:6,000 --> 00:00:7,000\n8\n\n";
-
-class SRTDataSourceStub : public DataSource {
-public:
-    SRTDataSourceStub(const char *data, size_t size) :
-        mData(data), mSize(size) {}
-    virtual ~SRTDataSourceStub() {}
-
-    virtual status_t initCheck() const {
-        return OK;
-    }
-
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
-        if ((size_t)offset >= mSize) return 0;
-
-        ssize_t avail = mSize - offset;
-        if ((size_t)avail > size) {
-            avail = size;
-        }
-        memcpy(data, mData + offset, avail);
-        return avail;
-    }
-
-private:
-    const char *mData;
-    size_t mSize;
-};
-
-class TimedTextSRTSourceTest : public testing::Test {
-protected:
-    void SetUp() {
-        sp<DataSource> stub= new SRTDataSourceStub(
-                kSRTString,
-                strlen(kSRTString));
-        mSource = new TimedTextSRTSource(stub);
-        mSource->start();
-    }
-
-    void CheckStartTimeMs(const Parcel& parcel, int32_t timeMs) {
-        int32_t intval;
-        parcel.setDataPosition(8);
-        parcel.readInt32(&intval);
-        EXPECT_EQ(timeMs, intval);
-    }
-
-    void CheckDataEquals(const Parcel& parcel, const char* content) {
-        int32_t intval;
-        parcel.setDataPosition(16);
-        parcel.readInt32(&intval);
-        parcel.setDataPosition(24);
-        const char* data = (const char*) parcel.readInplace(intval);
-
-        int32_t content_len = strlen(content);
-        EXPECT_EQ(content_len, intval);
-        EXPECT_TRUE(strncmp(data, content, content_len) == 0);
-    }
-
-    sp<TimedTextSource> mSource;
-    int64_t startTimeUs;
-    int64_t endTimeUs;
-    Parcel parcel;
-    AString subtitle;
-    status_t err;
-};
-
-TEST_F(TimedTextSRTSourceTest, readAll) {
-    for (int i = 1; i <= 5; i++) {
-        err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
-        EXPECT_EQ(OK, err);
-        CheckStartTimeMs(parcel, i * kSecToMsec);
-        subtitle = AStringPrintf("%d\n\n", i);
-        CheckDataEquals(parcel, subtitle.c_str());
-    }
-    // read edge cases
-    err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
-    EXPECT_EQ(OK, err);
-    CheckStartTimeMs(parcel, 5500);
-    subtitle = AStringPrintf("6\n\n");
-    CheckDataEquals(parcel, subtitle.c_str());
-
-    err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
-    EXPECT_EQ(OK, err);
-    CheckStartTimeMs(parcel, 5800);
-    subtitle = AStringPrintf("7\n\n");
-    CheckDataEquals(parcel, subtitle.c_str());
-
-    err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
-    EXPECT_EQ(OK, err);
-    CheckStartTimeMs(parcel, 6000);
-    subtitle = AStringPrintf("8\n\n");
-    CheckDataEquals(parcel, subtitle.c_str());
-
-    err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
-    EXPECT_EQ(ERROR_END_OF_STREAM, err);
-}
-
-TEST_F(TimedTextSRTSourceTest, seekTimeIsEarlierThanFirst) {
-    MediaSource::ReadOptions options;
-    options.setSeekTo(500, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
-    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
-    EXPECT_EQ(OK, err);
-    EXPECT_EQ(1 * kSecToUsec, startTimeUs);
-    CheckStartTimeMs(parcel, 1 * kSecToMsec);
-}
-
-TEST_F(TimedTextSRTSourceTest, seekTimeIsLaterThanLast) {
-    MediaSource::ReadOptions options;
-    options.setSeekTo(7 * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
-    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
-    EXPECT_EQ(ERROR_END_OF_STREAM, err);
-
-    options.setSeekTo(8 * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
-    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
-    EXPECT_EQ(ERROR_END_OF_STREAM, err);
-}
-
-TEST_F(TimedTextSRTSourceTest, seekTimeIsMatched) {
-    for (int i = 1; i <= 5; i++) {
-        MediaSource::ReadOptions options;
-        options.setSeekTo(i * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
-        err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
-        EXPECT_EQ(OK, err);
-        EXPECT_EQ(i * kSecToUsec, startTimeUs);
-
-        options.setSeekTo(i * kSecToUsec + 100, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
-        err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
-        EXPECT_EQ(OK, err);
-        EXPECT_EQ(i * kSecToUsec, startTimeUs);
-    }
-}
-
-TEST_F(TimedTextSRTSourceTest, seekTimeInBetweenTwo) {
-    for (int i = 1; i <= 4; i++) {
-        MediaSource::ReadOptions options;
-        options.setSeekTo(i * kSecToUsec + 500000, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
-        err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
-        EXPECT_EQ(OK, err);
-        EXPECT_EQ((i + 1) * kSecToUsec, startTimeUs);
-
-        options.setSeekTo(i * kSecToUsec + 600000, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
-        err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
-        EXPECT_EQ(OK, err);
-        EXPECT_EQ((i + 1) * kSecToUsec, startTimeUs);
-    }
-}
-
-TEST_F(TimedTextSRTSourceTest, checkEdgeCase) {
-    MediaSource::ReadOptions options;
-    options.setSeekTo(5500 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
-    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
-    EXPECT_EQ(OK, err);
-    EXPECT_EQ(5500 * kMsecToUsec, startTimeUs);
-    subtitle = AStringPrintf("6\n\n");
-    CheckDataEquals(parcel, subtitle.c_str());
-
-    options.setSeekTo(5800 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
-    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
-    EXPECT_EQ(OK, err);
-    EXPECT_EQ(5800 * kMsecToUsec, startTimeUs);
-    subtitle = AStringPrintf("7\n\n");
-    CheckDataEquals(parcel, subtitle.c_str());
-
-    options.setSeekTo(6000 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
-    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
-    EXPECT_EQ(OK, err);
-    EXPECT_EQ(6000 * kMsecToUsec, startTimeUs);
-    subtitle = AStringPrintf("8\n\n");
-    CheckDataEquals(parcel, subtitle.c_str());
-}
-
-}  // namespace test
-}  // namespace android
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index e2014b7..5f70479 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -54,6 +54,10 @@
             void        handleSyncStartEvent(const sp<SyncEvent>& event);
             void        clearSyncStartEvent();
 
+            void        updateTrackFrameInfo(int64_t trackFramesReleased,
+                                             int64_t sourceFramesRead,
+                                             uint32_t halSampleRate,
+                                             const ExtendedTimestamp &timestamp);
 private:
     friend class AudioFlinger;  // for mState
 
@@ -72,6 +76,8 @@
             // be dropped and therefore not read by the application.
             sp<SyncEvent>                       mSyncStartEvent;
 
+            AudioRecordServerProxy             *mAudioRecordServerProxy;
+
             // number of captured frames to drop after the start sync event has been received.
             // when < 0, maximum frames to drop before starting capture even if sync event is
             // not received
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 7a29cce..2fd5758 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -220,6 +220,94 @@
 }
 #endif
 
+// Track the CLOCK_BOOTTIME versus CLOCK_MONOTONIC timebase offset
+struct {
+    // call when you acquire a partial wakelock
+    void acquire(const sp<IBinder> &wakeLockToken) {
+        pthread_mutex_lock(&mLock);
+        if (wakeLockToken.get() == nullptr) {
+            adjustTimebaseOffset(&mBoottimeOffset, ExtendedTimestamp::TIMEBASE_BOOTTIME);
+        } else {
+            if (mCount == 0) {
+                adjustTimebaseOffset(&mBoottimeOffset, ExtendedTimestamp::TIMEBASE_BOOTTIME);
+            }
+            ++mCount;
+        }
+        pthread_mutex_unlock(&mLock);
+    }
+
+    // call when you release a partial wakelock.
+    void release(const sp<IBinder> &wakeLockToken) {
+        if (wakeLockToken.get() == nullptr) {
+            return;
+        }
+        pthread_mutex_lock(&mLock);
+        if (--mCount < 0) {
+            ALOGE("negative wakelock count");
+            mCount = 0;
+        }
+        pthread_mutex_unlock(&mLock);
+    }
+
+    // retrieves the boottime timebase offset from monotonic.
+    int64_t getBoottimeOffset() {
+        pthread_mutex_lock(&mLock);
+        int64_t boottimeOffset = mBoottimeOffset;
+        pthread_mutex_unlock(&mLock);
+        return boottimeOffset;
+    }
+
+    // Adjusts the timebase offset between TIMEBASE_MONOTONIC
+    // and the selected timebase.
+    // Currently only TIMEBASE_BOOTTIME is allowed.
+    //
+    // This only needs to be called upon acquiring the first partial wakelock
+    // after all other partial wakelocks are released.
+    //
+    // We do an empirical measurement of the offset rather than parsing
+    // /proc/timer_list since the latter is not a formal kernel ABI.
+    static void adjustTimebaseOffset(int64_t *offset, ExtendedTimestamp::Timebase timebase) {
+        int clockbase;
+        switch (timebase) {
+        case ExtendedTimestamp::TIMEBASE_BOOTTIME:
+            clockbase = SYSTEM_TIME_BOOTTIME;
+            break;
+        default:
+            LOG_ALWAYS_FATAL("invalid timebase %d", timebase);
+            break;
+        }
+        // try three times to get the clock offset, choose the one
+        // with the minimum gap in measurements.
+        const int tries = 3;
+        nsecs_t bestGap, measured;
+        for (int i = 0; i < tries; ++i) {
+            const nsecs_t tmono = systemTime(SYSTEM_TIME_MONOTONIC);
+            const nsecs_t tbase = systemTime(clockbase);
+            const nsecs_t tmono2 = systemTime(SYSTEM_TIME_MONOTONIC);
+            const nsecs_t gap = tmono2 - tmono;
+            if (i == 0 || gap < bestGap) {
+                bestGap = gap;
+                measured = tbase - ((tmono + tmono2) >> 1);
+            }
+        }
+
+        // to avoid micro-adjusting, we don't change the timebase
+        // unless it is significantly different.
+        //
+        // Assumption: It probably takes more than toleranceNs to
+        // suspend and resume the device.
+        static int64_t toleranceNs = 10000; // 10 us
+        if (llabs(*offset - measured) > toleranceNs) {
+            ALOGV("Adjusting timebase offset old: %lld  new: %lld",
+                    (long long)*offset, (long long)measured);
+            *offset = measured;
+        }
+    }
+
+    pthread_mutex_t mLock;
+    int32_t mCount;
+    int64_t mBoottimeOffset;
+} gBoottime = { PTHREAD_MUTEX_INITIALIZER, 0, 0 }; // static, so use POD initialization
 
 // ----------------------------------------------------------------------------
 //      CPU Stats
@@ -945,6 +1033,7 @@
         BatteryNotifier::getInstance().noteStartAudio();
         mNotifiedBatteryStart = true;
     }
+    gBoottime.acquire(mWakeLockToken);
 }
 
 void AudioFlinger::ThreadBase::releaseWakeLock()
@@ -955,6 +1044,7 @@
 
 void AudioFlinger::ThreadBase::releaseWakeLock_l()
 {
+    gBoottime.release(mWakeLockToken);
     if (mWakeLockToken != 0) {
         ALOGV("releaseWakeLock_l() %s", mThreadName);
         if (mPowerManager != 0) {
@@ -5685,6 +5775,9 @@
         }
     }
 
+    mTimestamp.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_BOOTTIME] =
+            gBoottime.getBoottimeOffset();
+
     // used to request a deferred sleep, to be executed later while mutex is unlocked
     uint32_t sleepUs = 0;
 
@@ -5898,6 +5991,28 @@
             }
         }
 
+        // Update server timestamp with server stats
+        // systemTime() is optional if the hardware supports timestamps.
+        mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER] += framesRead;
+        mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = systemTime();
+
+        // Update server timestamp with kernel stats
+        if (mInput->stream->get_capture_position != nullptr) {
+            int64_t position, time;
+            int ret = mInput->stream->get_capture_position(mInput->stream, &position, &time);
+            if (ret == NO_ERROR) {
+                mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = position;
+                mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] = time;
+                // Note: In general record buffers should tend to be empty in
+                // a properly running pipeline.
+                //
+                // Also, it is not advantageous to call get_presentation_position during the read
+                // as the read obtains a lock, preventing the timestamp call from executing.
+            }
+        }
+        // Use this to track timestamp information
+        // ALOGD("%s", mTimestamp.toString().c_str());
+
         if (framesRead < 0 || (framesRead == 0 && mPipeSource == 0)) {
             ALOGE("read failed: framesRead=%d", framesRead);
             // Force input into standby so that it tries to recover at next read attempt
@@ -6026,6 +6141,11 @@
                 break;
             }
 
+            // update frame information and push timestamp out
+            activeTrack->updateTrackFrameInfo(
+                    activeTrack->mAudioRecordServerProxy->framesReleased(),
+                    mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER],
+                    mSampleRate, mTimestamp);
         }
 
 unlock:
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index ae8bbb9..ad47277 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1324,6 +1324,8 @@
             // rolling index that is never cleared
             int32_t                             mRsmpInRear;    // last filled frame + 1
 
+            ExtendedTimestamp                   mTimestamp;
+
             // For dumpsys
             const sp<NBAIO_Sink>                mTeeSink;
 
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 5830f75..b4c1fdd 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1418,8 +1418,10 @@
         return;
     }
 
-    mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount,
-                                              mFrameSize, !isExternalTrack());
+    mAudioRecordServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount,
+            mFrameSize, !isExternalTrack());
+    mServerProxy = mAudioRecordServerProxy;
+
     mResamplerBufferProvider = new ResamplerBufferProvider(this);
 
     if (flags & IAudioFlinger::TRACK_FAST) {
@@ -1556,6 +1558,24 @@
     mFramesToDrop = 0;
 }
 
+void AudioFlinger::RecordThread::RecordTrack::updateTrackFrameInfo(
+        int64_t trackFramesReleased, int64_t sourceFramesRead,
+        uint32_t halSampleRate, const ExtendedTimestamp &timestamp)
+{
+    ExtendedTimestamp local = timestamp;
+
+    // Convert HAL frames to server-side track frames at track sample rate.
+    // We use trackFramesReleased and sourceFramesRead as an anchor point.
+    for (int i = ExtendedTimestamp::LOCATION_SERVER; i < ExtendedTimestamp::LOCATION_MAX; ++i) {
+        if (local.mTimeNs[i] != 0) {
+            const int64_t relativeServerFrames = local.mPosition[i] - sourceFramesRead;
+            const int64_t relativeTrackFrames = relativeServerFrames
+                    * mSampleRate / halSampleRate; // TODO: potential computation overflow
+            local.mPosition[i] = relativeTrackFrames + trackFramesReleased;
+        }
+    }
+    mAudioRecordServerProxy->setExtendedTimestamp(local);
+}
 
 AudioFlinger::RecordThread::PatchRecord::PatchRecord(RecordThread *recordThread,
                                                      uint32_t sampleRate,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 941757a..ec70ed4 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1809,6 +1809,7 @@
         mpClientInterface->closeInput(mInputs.keyAt(input_index));
     }
     mInputs.clear();
+    SoundTrigger::setCaptureState(false);
     nextAudioPortGeneration();
 
     if (patchRemoved) {
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
new file mode 100644
index 0000000..239b4e1
--- /dev/null
+++ b/services/mediacodec/Android.mk
@@ -0,0 +1,27 @@
+LOCAL_PATH := $(call my-dir)
+
+# service library
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := MediaCodecService.cpp
+LOCAL_SHARED_LIBRARIES := libmedia libbinder libutils liblog libstagefright_omx
+LOCAL_C_INCLUDES := \
+    $(TOP)/frameworks/av/media/libstagefright \
+    $(TOP)/frameworks/native/include/media/openmax
+LOCAL_MODULE:= libmediacodecservice
+LOCAL_32_BIT_ONLY := true
+include $(BUILD_SHARED_LIBRARY)
+
+
+# service executable
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := main_codecservice.cpp
+LOCAL_SHARED_LIBRARIES := libmedia libmediacodecservice libbinder libutils liblog
+LOCAL_C_INCLUDES := \
+    $(TOP)/frameworks/av/media/libstagefright \
+    $(TOP)/frameworks/native/include/media/openmax
+LOCAL_MODULE:= mediacodec
+LOCAL_32_BIT_ONLY := true
+LOCAL_INIT_RC := mediacodec.rc
+include $(BUILD_EXECUTABLE)
+
+
diff --git a/services/mediacodec/MODULE_LICENSE_APACHE2 b/services/mediacodec/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/mediacodec/MODULE_LICENSE_APACHE2
diff --git a/services/mediacodec/MediaCodecService.cpp b/services/mediacodec/MediaCodecService.cpp
new file mode 100644
index 0000000..fc1e5d9
--- /dev/null
+++ b/services/mediacodec/MediaCodecService.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MediaCodecService"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "MediaCodecService.h"
+
+namespace android {
+
+sp<IOMX> MediaCodecService::getOMX() {
+
+    Mutex::Autolock autoLock(mLock);
+
+    if (mOMX.get() == NULL) {
+        mOMX = new OMX;
+    }
+
+    return mOMX;
+}
+
+
+status_t MediaCodecService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+        uint32_t flags)
+{
+    return BnMediaCodecService::onTransact(code, data, reply, flags);
+}
+
+}   // namespace android
diff --git a/services/mediacodec/MediaCodecService.h b/services/mediacodec/MediaCodecService.h
new file mode 100644
index 0000000..d64debb
--- /dev/null
+++ b/services/mediacodec/MediaCodecService.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_CODEC_SERVICE_H
+#define ANDROID_MEDIA_CODEC_SERVICE_H
+
+#include <binder/BinderService.h>
+#include <media/IMediaCodecService.h>
+#include <include/OMX.h>
+
+namespace android {
+
+class MediaCodecService : public BinderService<MediaCodecService>, public BnMediaCodecService
+{
+    friend class BinderService<MediaCodecService>;    // for MediaCodecService()
+public:
+    MediaCodecService() : BnMediaCodecService() { }
+    virtual ~MediaCodecService() { }
+    virtual void onFirstRef() { }
+
+    static const char*  getServiceName() { return "media.codec"; }
+
+    virtual sp<IOMX>    getOMX();
+
+    virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                uint32_t flags);
+
+private:
+    Mutex               mLock;
+    sp<IOMX>            mOMX;
+};
+
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_CODEC_SERVICE_H
diff --git a/services/mediacodec/NOTICE b/services/mediacodec/NOTICE
new file mode 100644
index 0000000..34bdaf1
--- /dev/null
+++ b/services/mediacodec/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2015, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
new file mode 100644
index 0000000..aedf0c3
--- /dev/null
+++ b/services/mediacodec/main_codecservice.cpp
@@ -0,0 +1,45 @@
+/*
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "mediacodec"
+//#define LOG_NDEBUG 0
+
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+// from LOCAL_C_INCLUDES
+#include "MediaCodecService.h"
+
+using namespace android;
+
+int main(int argc __unused, char** argv)
+{
+    ALOGI("@@@ mediacodecservice starting");
+    signal(SIGPIPE, SIG_IGN);
+
+    strcpy(argv[0], "media.codec");
+    sp<ProcessState> proc(ProcessState::self());
+    sp<IServiceManager> sm = defaultServiceManager();
+    MediaCodecService::instantiate();
+    ProcessState::self()->startThreadPool();
+    IPCThreadState::self()->joinThreadPool();
+}
diff --git a/services/mediacodec/mediacodec.rc b/services/mediacodec/mediacodec.rc
new file mode 100644
index 0000000..e8df7be
--- /dev/null
+++ b/services/mediacodec/mediacodec.rc
@@ -0,0 +1,5 @@
+service mediacodec /system/bin/mediacodec
+    class main
+    user mediacodec
+    group camera drmrpc mediadrm
+    ioprio rt 4