Merge "PlaylistFetcher:don't signal a/v eos on subttitle eos" into lmp-dev
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 72e51f9..b5256f0 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -580,7 +580,14 @@
      * Caution: calling this method too often may be inefficient;
      * if you need a high resolution mapping between frame position and presentation time,
      * consider implementing that at application level, based on the low resolution timestamps.
-     * Returns NO_ERROR if timestamp is valid.
+     * Returns NO_ERROR    if timestamp is valid.
+     *         WOULD_BLOCK if called in STOPPED or FLUSHED state, or if called immediately after
+     *                     start/ACTIVE, when the number of frames consumed is less than the
+     *                     overall hardware latency to physical output. In WOULD_BLOCK cases,
+     *                     one might poll again, or use getPosition(), or use 0 position and
+     *                     current time for the timestamp.
+     *         INVALID_OPERATION  if called on a FastTrack, wrong state, or some other error.
+     *
      * The timestamp parameter is undefined on return, if status is not NO_ERROR.
      */
             status_t    getTimestamp(AudioTimestamp& timestamp);
@@ -747,6 +754,8 @@
                                                     // reset by stop() but continues monotonically
                                                     // after new IAudioTrack to restore mPosition,
                                                     // and could be easily widened to uint64_t
+    int64_t                 mStartUs;               // the start time after flush or stop.
+                                                    // only used for offloaded and direct tracks.
 
     audio_output_flags_t    mFlags;
         // const after set(), except for bits AUDIO_OUTPUT_FLAG_FAST and AUDIO_OUTPUT_FLAG_OFFLOAD.
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 87717da..cf18a45 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -27,6 +27,7 @@
 
 #include <media/mediaplayer.h>
 #include <media/AudioSystem.h>
+#include <media/AudioTimestamp.h>
 #include <media/Metadata.h>
 
 // Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
@@ -97,6 +98,7 @@
         virtual uint32_t    latency() const = 0;
         virtual float       msecsPerFrame() const = 0;
         virtual status_t    getPosition(uint32_t *position) const = 0;
+        virtual status_t    getTimestamp(AudioTimestamp &ts) const = 0;
         virtual status_t    getFramesWritten(uint32_t *frameswritten) const = 0;
         virtual int         getSessionId() const = 0;
         virtual audio_stream_type_t getAudioStreamType() const = 0;
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index ff7da83..762dca5 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -37,6 +37,19 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
+static int64_t convertTimespecToUs(const struct timespec &tv)
+{
+    return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000;
+}
+
+// current monotonic time in microseconds.
+static int64_t getNowUs()
+{
+    struct timespec tv;
+    (void) clock_gettime(CLOCK_MONOTONIC, &tv);
+    return convertTimespecToUs(tv);
+}
+
 // static
 status_t AudioTrack::getMinFrameCount(
         size_t* frameCount,
@@ -420,6 +433,7 @@
     mServer = 0;
     mPosition = 0;
     mReleased = 0;
+    mStartUs = 0;
     AudioSystem::acquireAudioSessionId(mSessionId, mClientPid);
     mSequence = 1;
     mObservedSequence = mSequence;
@@ -451,6 +465,12 @@
         // reset current position as seen by client to 0
         mPosition = 0;
         mReleased = 0;
+        // For offloaded tracks, we don't know if the hardware counters are really zero here,
+        // since the flush is asynchronous and stop may not fully drain.
+        // We save the time when the track is started to later verify whether
+        // the counters are realistic (i.e. start from zero after this time).
+        mStartUs = getNowUs();
+
         // force refresh of remaining frames by processAudioBuffer() as last
         // write before stop could be partial.
         mRefreshRemaining = true;
@@ -587,9 +607,18 @@
 
     if (isOffloaded_l()) {
         if (mOutput != AUDIO_IO_HANDLE_NONE) {
+            // An offload output can be re-used between two audio tracks having
+            // the same configuration. A timestamp query for a paused track
+            // while the other is running would return an incorrect time.
+            // To fix this, cache the playback position on a pause() and return
+            // this time when requested until the track is resumed.
+
+            // OffloadThread sends HAL pause in its threadLoop. Time saved
+            // here can be slightly off.
+
+            // TODO: check return code for getRenderPosition.
+
             uint32_t halFrames;
-            // OffloadThread sends HAL pause in its threadLoop.. time saved
-            // here can be slightly off
             AudioSystem::getRenderPosition(mOutput, &halFrames, &mPausedPosition);
             ALOGV("AudioTrack::pause for offload, cache current position %u", mPausedPosition);
         }
@@ -825,6 +854,8 @@
             uint32_t halFrames;
             AudioSystem::getRenderPosition(mOutput, &halFrames, &dspFrames);
         }
+        // FIXME: dspFrames may not be zero in (mState == STATE_STOPPED || mState == STATE_FLUSHED)
+        // due to hardware latency. We leave this behavior for now.
         *position = dspFrames;
     } else {
         // IAudioTrack::stop() isn't synchronous; we don't know when presentation completes
@@ -1881,13 +1912,70 @@
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
         return INVALID_OPERATION;
     }
-    if (mState != STATE_ACTIVE && mState != STATE_PAUSED) {
-        return INVALID_OPERATION;
+
+    switch (mState) {
+    case STATE_ACTIVE:
+    case STATE_PAUSED:
+        break; // handle below
+    case STATE_FLUSHED:
+    case STATE_STOPPED:
+        return WOULD_BLOCK;
+    case STATE_STOPPING:
+    case STATE_PAUSED_STOPPING:
+        if (!isOffloaded_l()) {
+            return INVALID_OPERATION;
+        }
+        break; // offloaded tracks handled below
+    default:
+        LOG_ALWAYS_FATAL("Invalid mState in getTimestamp(): %d", mState);
+        break;
     }
+
     // The presented frame count must always lag behind the consumed frame count.
     // To avoid a race, read the presented frames first.  This ensures that presented <= consumed.
     status_t status = mAudioTrack->getTimestamp(timestamp);
-    if (status == NO_ERROR) {
+    if (status != NO_ERROR) {
+        ALOGW_IF(status != WOULD_BLOCK, "getTimestamp error:%#x", status);
+        return status;
+    }
+    if (isOffloadedOrDirect_l()) {
+        if (isOffloaded_l() && (mState == STATE_PAUSED || mState == STATE_PAUSED_STOPPING)) {
+            // use cached paused position in case another offloaded track is running.
+            timestamp.mPosition = mPausedPosition;
+            clock_gettime(CLOCK_MONOTONIC, &timestamp.mTime);
+            return NO_ERROR;
+        }
+
+        // Check whether a pending flush or stop has completed, as those commands may
+        // be asynchronous or return near finish.
+        if (mStartUs != 0 && mSampleRate != 0) {
+            static const int kTimeJitterUs = 100000; // 100 ms
+            static const int k1SecUs = 1000000;
+
+            const int64_t timeNow = getNowUs();
+
+            if (timeNow < mStartUs + k1SecUs) { // within first second of starting
+                const int64_t timestampTimeUs = convertTimespecToUs(timestamp.mTime);
+                if (timestampTimeUs < mStartUs) {
+                    return WOULD_BLOCK;  // stale timestamp time, occurs before start.
+                }
+                const int64_t deltaTimeUs = timestampTimeUs - mStartUs;
+                const int64_t deltaPositionByUs = timestamp.mPosition * 1000000LL / mSampleRate;
+
+                if (deltaPositionByUs > deltaTimeUs + kTimeJitterUs) {
+                    // Verify that the counter can't count faster than the sample rate
+                    // since the start time.  If greater, then that means we have failed
+                    // to completely flush or stop the previous playing track.
+                    ALOGW("incomplete flush or stop:"
+                            " deltaTimeUs(%lld) deltaPositionUs(%lld) tsmPosition(%u)",
+                            (long long)deltaTimeUs, (long long)deltaPositionByUs,
+                            timestamp.mPosition);
+                    return WOULD_BLOCK;
+                }
+            }
+            mStartUs = 0; // no need to check again, start timestamp has either expired or unneeded.
+        }
+    } else {
         // Update the mapping between local consumed (mPosition) and server consumed (mServer)
         (void) updateAndGetPosition_l();
         // Server consumed (mServer) and presented both use the same server time base,
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index c8cb7ed..8eb1269 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -43,6 +43,7 @@
 #include <utils/Errors.h>  // for status_t
 #include <utils/String8.h>
 #include <utils/SystemClock.h>
+#include <utils/Timers.h>
 #include <utils/Vector.h>
 
 #include <media/IMediaHTTPService.h>
@@ -1496,6 +1497,12 @@
     return mTrack->getPosition(position);
 }
 
+status_t MediaPlayerService::AudioOutput::getTimestamp(AudioTimestamp &ts) const
+{
+    if (mTrack == 0) return NO_INIT;
+    return mTrack->getTimestamp(ts);
+}
+
 status_t MediaPlayerService::AudioOutput::getFramesWritten(uint32_t *frameswritten) const
 {
     if (mTrack == 0) return NO_INIT;
@@ -1971,6 +1978,15 @@
     return NO_ERROR;
 }
 
+status_t MediaPlayerService::AudioCache::getTimestamp(AudioTimestamp &ts) const
+{
+    ts.mPosition = mSize / mFrameSize;
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    ts.mTime.tv_sec = now / 1000000000LL;
+    ts.mTime.tv_nsec = now - (1000000000LL * ts.mTime.tv_sec);
+    return NO_ERROR;
+}
+
 status_t MediaPlayerService::AudioCache::getFramesWritten(uint32_t *written) const
 {
     if (written == 0) return BAD_VALUE;
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 4fe7075..3b96e88 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -85,6 +85,7 @@
         virtual uint32_t        latency() const;
         virtual float           msecsPerFrame() const;
         virtual status_t        getPosition(uint32_t *position) const;
+        virtual status_t        getTimestamp(AudioTimestamp &ts) const;
         virtual status_t        getFramesWritten(uint32_t *frameswritten) const;
         virtual int             getSessionId() const;
         virtual uint32_t        getSampleRate() const;
@@ -198,6 +199,7 @@
         virtual uint32_t        latency() const;
         virtual float           msecsPerFrame() const;
         virtual status_t        getPosition(uint32_t *position) const;
+        virtual status_t        getTimestamp(AudioTimestamp &ts) const;
         virtual status_t        getFramesWritten(uint32_t *frameswritten) const;
         virtual int             getSessionId() const;
         virtual uint32_t        getSampleRate() const;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index bd67cbd..142107d 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -106,6 +106,10 @@
     return OK;
 }
 
+sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
+    return mFileMeta;
+}
+
 status_t NuPlayer::GenericSource::initFromDataSource() {
     sp<MediaExtractor> extractor;
 
@@ -144,10 +148,10 @@
         checkDrmStatus(mDataSource);
     }
 
-    sp<MetaData> fileMeta = extractor->getMetaData();
-    if (fileMeta != NULL) {
+    mFileMeta = extractor->getMetaData();
+    if (mFileMeta != NULL) {
         int64_t duration;
-        if (fileMeta->findInt64(kKeyDuration, &duration)) {
+        if (mFileMeta->findInt64(kKeyDuration, &duration)) {
             mDurationUs = duration;
         }
     }
@@ -1256,6 +1260,8 @@
 
             sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs);
             track->mPackets->queueAccessUnit(buffer);
+            formatChange = false;
+            seeking = false;
             ++numBuffers;
         } else if (err == WOULD_BLOCK) {
             break;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 454edeb..24bb6af 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -59,6 +59,8 @@
 
     virtual status_t feedMoreTSData();
 
+    virtual sp<MetaData> getFileFormatMeta() const;
+
     virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
 
     virtual status_t getDuration(int64_t *durationUs);
@@ -125,6 +127,7 @@
     sp<DataSource> mDataSource;
     sp<NuCachedSource2> mCachedSource;
     sp<WVMExtractor> mWVMExtractor;
+    sp<MetaData> mFileMeta;
     DrmManagerClient *mDrmManagerClient;
     sp<DecryptHandle> mDecryptHandle;
     bool mStarted;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 7c6d576..5321deb 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1730,6 +1730,10 @@
     return err;
 }
 
+sp<MetaData> NuPlayer::getFileMeta() {
+    return mSource->getFileFormatMeta();
+}
+
 void NuPlayer::schedulePollDuration() {
     sp<AMessage> msg = new AMessage(kWhatPollDuration, id());
     msg->setInt32("generation", mPollDurationGeneration);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 2e951bd..7197e5f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -67,6 +67,8 @@
     status_t getSelectedTrack(int32_t type, Parcel* reply) const;
     status_t selectTrack(size_t trackIndex, bool select);
 
+    sp<MetaData> getFileMeta();
+
     static const size_t kAggregateBufferSizeBytes;
 
 protected:
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 4e6b4d8..7ec9876 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -45,6 +45,7 @@
       mPlayerFlags(0),
       mAtEOS(false),
       mLooping(false),
+      mAutoLoop(false),
       mStartupSeekTimeUs(-1) {
     mLooper->setName("NuPlayerDriver Looper");
 
@@ -270,7 +271,14 @@
                 mPositionUs = -1;
             } else {
                 mPlayer->resume();
-                mPositionUs -= ALooper::GetNowUs() - mPauseStartedTimeUs;
+                if (mNotifyTimeRealUs != -1) {
+                    // Pause time must be set if here by setPauseStartedTimeIfNeeded().
+                    //CHECK(mPauseStartedTimeUs != -1);
+
+                    // if no seek occurs, adjust our notify time so that getCurrentPosition()
+                    // is continuous if read immediately after calling start().
+                    mNotifyTimeRealUs += ALooper::GetNowUs() - mPauseStartedTimeUs;
+                }
             }
             break;
         }
@@ -378,15 +386,36 @@
     Mutex::Autolock autoLock(mLock);
 
     if (mPositionUs < 0) {
+        // mPositionUs is the media time.
+        // It is negative under these cases
+        // (1) == -1 after reset, or very first playback, no stream notification yet.
+        // (2) == -1 start after end of stream, no stream notification yet.
+        // (3) == large negative # after ~292,471 years of continuous playback.
+
+        //CHECK_EQ(mPositionUs, -1);
         *msec = 0;
     } else if (mNotifyTimeRealUs == -1) {
+        // A seek has occurred just occurred, no stream notification yet.
+        // mPositionUs (>= 0) is the new media position.
         *msec = mPositionUs / 1000;
     } else {
+        // mPosition must be valid (i.e. >= 0) by the first check above.
+        // We're either playing or have pause time set: mPauseStartedTimeUs is >= 0
+        //LOG_ALWAYS_FATAL_IF(
+        //        !isPlaying() && mPauseStartedTimeUs < 0,
+        //        "Player in non-playing mState(%d) and mPauseStartedTimeUs(%lld) < 0",
+        //        mState, (long long)mPauseStartedTimeUs);
+        ALOG_ASSERT(mNotifyTimeRealUs >= 0);
         int64_t nowUs =
                 (isPlaying() ?  ALooper::GetNowUs() : mPauseStartedTimeUs);
         *msec = (mPositionUs + nowUs - mNotifyTimeRealUs + 500ll) / 1000;
+        // It is possible for *msec to be negative if the media position is > 596 hours.
+        // but we turn on this checking in NDEBUG == 0 mode.
+        ALOG_ASSERT(*msec >= 0);
+        ALOGV("getCurrentPosition nowUs(%lld)", (long long)nowUs);
     }
-
+    ALOGV("getCurrentPosition returning(%d) mPositionUs(%lld) mNotifyRealTimeUs(%lld)",
+            *msec, (long long)mPositionUs, (long long)mNotifyTimeRealUs);
     return OK;
 }
 
@@ -505,6 +534,7 @@
 
 void NuPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) {
     mPlayer->setAudioSink(audioSink);
+    mAudioSink = audioSink;
 }
 
 status_t NuPlayerDriver::setParameter(
@@ -634,7 +664,8 @@
         case MEDIA_PLAYBACK_COMPLETE:
         {
             if (mState != STATE_RESET_IN_PROGRESS) {
-                if (mLooping) {
+                if (mLooping || (mAutoLoop
+                        && (mAudioSink == NULL || mAudioSink->realtime()))) {
                     mPlayer->seekToAsync(0);
                     break;
                 }
@@ -700,6 +731,13 @@
         }
     }
 
+    sp<MetaData> meta = mPlayer->getFileMeta();
+    int32_t loop;
+    if (meta != NULL
+            && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
+        mAutoLoop = true;
+    }
+
     mCondition.broadcast();
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index e81d605..f2bd431 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -114,10 +114,12 @@
 
     sp<ALooper> mLooper;
     sp<NuPlayer> mPlayer;
+    sp<AudioSink> mAudioSink;
     uint32_t mPlayerFlags;
 
     bool mAtEOS;
     bool mLooping;
+    bool mAutoLoop;
 
     int64_t mStartupSeekTimeUs;
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 067784b..7674616 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -45,7 +45,7 @@
       mDrainVideoQueuePending(false),
       mAudioQueueGeneration(0),
       mVideoQueueGeneration(0),
-      mFirstAudioTimeUs(-1),
+      mFirstAnchorTimeMediaUs(-1),
       mAnchorTimeMediaUs(-1),
       mAnchorTimeRealUs(-1),
       mFlushingAudio(false),
@@ -54,12 +54,12 @@
       mHasVideo(false),
       mSyncQueues(false),
       mPaused(false),
+      mVideoSampleReceived(false),
       mVideoRenderingStarted(false),
       mVideoRenderingStartGeneration(0),
       mAudioRenderingStartGeneration(0),
       mLastPositionUpdateUs(-1ll),
-      mVideoLateByUs(0ll),
-      mVideoSampleReceived(false) {
+      mVideoLateByUs(0ll) {
 }
 
 NuPlayer::Renderer::~Renderer() {
@@ -115,6 +115,7 @@
     Mutex::Autolock autoLock(mLock);
     // CHECK(mAudioQueue.empty());
     // CHECK(mVideoQueue.empty());
+    mFirstAnchorTimeMediaUs = -1;
     mAnchorTimeMediaUs = -1;
     mAnchorTimeRealUs = -1;
     mSyncQueues = false;
@@ -339,19 +340,16 @@
             int64_t mediaTimeUs;
             CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
             ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
-            if (mFirstAudioTimeUs == -1) {
-                mFirstAudioTimeUs = mediaTimeUs;
+            if (mFirstAnchorTimeMediaUs == -1) {
+                mFirstAnchorTimeMediaUs = mediaTimeUs;
             }
 
-            uint32_t numFramesPlayed;
-            CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
+            int64_t nowUs = ALooper::GetNowUs();
+            mAnchorTimeMediaUs =
+                mFirstAnchorTimeMediaUs + getPlayedOutAudioDurationUs(nowUs);
+            mAnchorTimeRealUs = nowUs;
 
-            // TODO: figure out how to calculate initial latency.
-            // Otherwise, the initial time is not correct till the first sample
-            // is played.
-            mAnchorTimeMediaUs = mFirstAudioTimeUs
-                    + (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll;
-            mAnchorTimeRealUs = ALooper::GetNowUs();
+            notifyPosition();
         }
 
         size_t copy = entry->mBuffer->size() - entry->mOffset;
@@ -374,10 +372,6 @@
         notifyIfMediaRenderingStarted();
     }
 
-    if (sizeCopied != 0) {
-        notifyPosition();
-    }
-
     if (hasEOS) {
         (new AMessage(kWhatStopAudioSink, id()))->post();
     }
@@ -413,7 +407,7 @@
             // EOS
             int64_t postEOSDelayUs = 0;
             if (mAudioSink->needsTrailingPadding()) {
-                postEOSDelayUs = getAudioPendingPlayoutUs() + 1000 * mAudioSink->latency();
+                postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs());
             }
             notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs);
 
@@ -426,10 +420,15 @@
             int64_t mediaTimeUs;
             CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
             ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
+            if (mFirstAnchorTimeMediaUs == -1) {
+                mFirstAnchorTimeMediaUs = mediaTimeUs;
+            }
             mAnchorTimeMediaUs = mediaTimeUs;
 
-            mAnchorTimeRealUs = ALooper::GetNowUs()
-                    + getAudioPendingPlayoutUs() + 1000 * mAudioSink->latency() / 2;
+            int64_t nowUs = ALooper::GetNowUs();
+            mAnchorTimeRealUs = nowUs + getPendingAudioPlayoutDurationUs(nowUs);
+
+            notifyPosition();
         }
 
         size_t copy = entry->mBuffer->size() - entry->mOffset;
@@ -478,17 +477,13 @@
             break;
         }
     }
-    notifyPosition();
-
     return !mAudioQueue.empty();
 }
 
-int64_t NuPlayer::Renderer::getAudioPendingPlayoutUs() {
-    uint32_t numFramesPlayed;
-    CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
-
-    uint32_t numFramesPendingPlayout = mNumFramesWritten - numFramesPlayed;
-    return numFramesPendingPlayout * mAudioSink->msecsPerFrame() * 1000;
+int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) {
+    int64_t writtenAudioDurationUs =
+        mNumFramesWritten * 1000LL * mAudioSink->msecsPerFrame();
+    return writtenAudioDurationUs - getPlayedOutAudioDurationUs(nowUs);
 }
 
 void NuPlayer::Renderer::postDrainVideoQueue() {
@@ -521,12 +516,16 @@
         int64_t mediaTimeUs;
         CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
 
+        if (mFirstAnchorTimeMediaUs == -1 && !mHasAudio) {
+            mFirstAnchorTimeMediaUs = mediaTimeUs;
+        }
         if (mAnchorTimeMediaUs < 0) {
             delayUs = 0;
 
             if (!mHasAudio) {
                 mAnchorTimeMediaUs = mediaTimeUs;
                 mAnchorTimeRealUs = ALooper::GetNowUs();
+                notifyPosition();
             }
         } else {
             int64_t realTimeUs =
@@ -558,8 +557,6 @@
         entry = NULL;
 
         mVideoLateByUs = 0ll;
-
-        notifyPosition();
         return;
     }
 
@@ -605,8 +602,6 @@
         }
         notifyIfMediaRenderingStarted();
     }
-
-    notifyPosition();
 }
 
 void NuPlayer::Renderer::notifyVideoRenderingStart() {
@@ -783,7 +778,7 @@
             prepareForMediaRenderingStart();
 
             if (offloadingAudio()) {
-                mFirstAudioTimeUs = -1;
+                mFirstAnchorTimeMediaUs = -1;
             }
         }
 
@@ -871,9 +866,11 @@
 }
 
 void NuPlayer::Renderer::notifyPosition() {
-    if (mAnchorTimeRealUs < 0 || mAnchorTimeMediaUs < 0) {
-        return;
-    }
+    // notifyPosition() must be called only after setting mAnchorTimeRealUs
+    // and mAnchorTimeMediaUs, and must not be paused as it extrapolates position.
+    //CHECK_GE(mAnchorTimeRealUs, 0);
+    //CHECK_GE(mAnchorTimeMediaUs, 0);
+    //CHECK(!mPaused || !mHasAudio);  // video-only does display in paused mode.
 
     int64_t nowUs = ALooper::GetNowUs();
 
@@ -885,6 +882,18 @@
 
     int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs;
 
+    //ALOGD("notifyPosition: positionUs(%lld) nowUs(%lld) mAnchorTimeRealUs(%lld)"
+    //        " mAnchorTimeMediaUs(%lld) mFirstAnchorTimeMediaUs(%lld)",
+    //        (long long)positionUs, (long long)nowUs, (long long)mAnchorTimeRealUs,
+    //        (long long)mAnchorTimeMediaUs, (long long)mFirstAnchorTimeMediaUs);
+
+    // Due to adding the latency to mAnchorTimeRealUs in onDrainAudioQueue(),
+    // positionUs may be less than the first media time.  This is avoided
+    // here to prevent potential retrograde motion of the position bar
+    // when starting up after a seek.
+    if (positionUs < mFirstAnchorTimeMediaUs) {
+        positionUs = mFirstAnchorTimeMediaUs;
+    }
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatPosition);
     notify->setInt64("positionUs", positionUs);
@@ -937,17 +946,80 @@
     }
 }
 
-void NuPlayer::Renderer::onAudioOffloadTearDown() {
+// TODO: Remove unnecessary calls to getPlayedOutAudioDurationUs()
+// as it acquires locks and may query the audio driver.
+//
+// Some calls are not needed since notifyPosition() doesn't always deliver a message.
+// Some calls could conceivably retrieve extrapolated data instead of
+// accessing getTimestamp() or getPosition() every time a data buffer with
+// a media time is received.
+//
+int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) {
     uint32_t numFramesPlayed;
-    CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
+    int64_t numFramesPlayedAt;
+    AudioTimestamp ts;
+    static const int64_t kStaleTimestamp100ms = 100000;
 
+    status_t res = mAudioSink->getTimestamp(ts);
+    if (res == OK) {                 // case 1: mixing audio tracks and offloaded tracks.
+        numFramesPlayed = ts.mPosition;
+        numFramesPlayedAt =
+            ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
+        const int64_t timestampAge = nowUs - numFramesPlayedAt;
+        if (timestampAge > kStaleTimestamp100ms) {
+            // This is an audio FIXME.
+            // getTimestamp returns a timestamp which may come from audio mixing threads.
+            // After pausing, the MixerThread may go idle, thus the mTime estimate may
+            // become stale. Assuming that the MixerThread runs 20ms, with FastMixer at 5ms,
+            // the max latency should be about 25ms with an average around 12ms (to be verified).
+            // For safety we use 100ms.
+            ALOGW("getTimestamp: returned stale timestamp nowUs(%lld) numFramesPlayedAt(%lld)",
+                    (long long)nowUs, (long long)numFramesPlayedAt);
+            numFramesPlayedAt = nowUs - kStaleTimestamp100ms;
+        }
+        //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAt);
+    } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
+        numFramesPlayed = 0;
+        numFramesPlayedAt = nowUs;
+        //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
+        //        numFramesPlayed, (long long)numFramesPlayedAt);
+    } else {                         // case 3: transitory at new track or audio fast tracks.
+        res = mAudioSink->getPosition(&numFramesPlayed);
+        CHECK_EQ(res, (status_t)OK);
+        numFramesPlayedAt = nowUs;
+        numFramesPlayedAt += 1000LL * mAudioSink->latency() / 2; /* XXX */
+        //ALOGD("getPosition: %d %lld", numFramesPlayed, numFramesPlayedAt);
+    }
+
+    // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
+    //CHECK_EQ(numFramesPlayed & (1 << 31), 0);  // can't be negative until 12.4 hrs, test
+    int64_t durationUs = (int32_t)numFramesPlayed * 1000LL * mAudioSink->msecsPerFrame()
+            + nowUs - numFramesPlayedAt;
+    if (durationUs < 0) {
+        // Occurs when numFramesPlayed position is very small and the following:
+        // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
+        //     numFramesPlayedAt is greater than nowUs by time more than numFramesPlayed.
+        // (2) In case 3, using getPosition and adding mAudioSink->latency() to
+        //     numFramesPlayedAt, by a time amount greater than numFramesPlayed.
+        //
+        // Both of these are transitory conditions.
+        ALOGW("getPlayedOutAudioDurationUs: negative timestamp %lld set to zero", (long long)durationUs);
+        durationUs = 0;
+    }
+    ALOGV("getPlayedOutAudioDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
+            (long long)durationUs, (long long)nowUs, numFramesPlayed, (long long)numFramesPlayedAt);
+    return durationUs;
+}
+
+void NuPlayer::Renderer::onAudioOffloadTearDown() {
     int64_t firstAudioTimeUs;
     {
         Mutex::Autolock autoLock(mLock);
-        firstAudioTimeUs = mFirstAudioTimeUs;
+        firstAudioTimeUs = mFirstAnchorTimeMediaUs;
     }
-    int64_t currentPositionUs = firstAudioTimeUs
-            + (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll;
+
+    int64_t currentPositionUs =
+        firstAudioTimeUs + getPlayedOutAudioDurationUs(ALooper::GetNowUs());
 
     mAudioSink->stop();
     mAudioSink->flush();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 5c7d2d7..97fdae7 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -106,7 +106,7 @@
     int32_t mAudioQueueGeneration;
     int32_t mVideoQueueGeneration;
 
-    int64_t mFirstAudioTimeUs;
+    int64_t mFirstAnchorTimeMediaUs;
     int64_t mAnchorTimeMediaUs;
     int64_t mAnchorTimeRealUs;
 
@@ -130,7 +130,8 @@
     size_t fillAudioBuffer(void *buffer, size_t size);
 
     bool onDrainAudioQueue();
-    int64_t getAudioPendingPlayoutUs();
+    int64_t getPendingAudioPlayoutDurationUs(int64_t nowUs);
+    int64_t getPlayedOutAudioDurationUs(int64_t nowUs);
     void postDrainAudioQueue_l(int64_t delayUs = 0);
 
     void onDrainVideoQueue();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 7d994fa..2f06c31 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -76,6 +76,7 @@
 
     virtual sp<AMessage> getFormat(bool audio);
     virtual sp<MetaData> getFormatMeta(bool /* audio */) { return NULL; }
+    virtual sp<MetaData> getFileFormatMeta() const { return NULL; }
 
     virtual status_t dequeueAccessUnit(
             bool audio, sp<ABuffer> *accessUnit) = 0;
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 4569c1c..456be89 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -705,7 +705,9 @@
                     }
 
                     // Discard input buffer.
-                    inHeader->nFilledLen = 0;
+                    if (inHeader) {
+                        inHeader->nFilledLen = 0;
+                    }
 
                     aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
 
@@ -736,7 +738,7 @@
                         notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
                         mOutputPortSettingsChange = AWAITING_DISABLED;
 
-                        if (inHeader->nFilledLen == 0) {
+                        if (inHeader && inHeader->nFilledLen == 0) {
                             inInfo->mOwnedByUs = false;
                             mInputBufferCount++;
                             inQueue.erase(inQueue.begin());
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 3d17c89..818bb05 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3991,8 +3991,6 @@
             minFrames = 1;
         }
 
-        ALOGI("prepareTracks_l minFrames %d state %d frames ready %d, ",
-              minFrames, track->mState, track->framesReady());
         if ((track->framesReady() >= minFrames) && track->isReady() && !track->isPaused() &&
                 !track->isStopping_2() && !track->isStopped())
         {
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index d5f6c1e..95ac070 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -2667,59 +2667,69 @@
                 continue;
             }
 
+            if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
+                continue;
+            }
             audio_devices_t profileType = outProfile->mSupportedDevices.types();
             if ((profileType & mDefaultOutputDevice->mDeviceType) != AUDIO_DEVICE_NONE) {
                 profileType = mDefaultOutputDevice->mDeviceType;
             } else {
-                profileType = outProfile->mSupportedDevices[0]->mDeviceType;
-            }
-            if ((profileType & outputDeviceTypes) &&
-                    ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) {
-                sp<AudioOutputDescriptor> outputDesc = new AudioOutputDescriptor(outProfile);
-
-                outputDesc->mDevice = profileType;
-                audio_config_t config = AUDIO_CONFIG_INITIALIZER;
-                config.sample_rate = outputDesc->mSamplingRate;
-                config.channel_mask = outputDesc->mChannelMask;
-                config.format = outputDesc->mFormat;
-                audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-                status_t status = mpClientInterface->openOutput(outProfile->mModule->mHandle,
-                                                                &output,
-                                                                &config,
-                                                                &outputDesc->mDevice,
-                                                                String8(""),
-                                                                &outputDesc->mLatency,
-                                                                outputDesc->mFlags);
-
-                if (status != NO_ERROR) {
-                    ALOGW("Cannot open output stream for device %08x on hw module %s",
-                          outputDesc->mDevice,
-                          mHwModules[i]->mName);
-                } else {
-                    outputDesc->mSamplingRate = config.sample_rate;
-                    outputDesc->mChannelMask = config.channel_mask;
-                    outputDesc->mFormat = config.format;
-
-                    for (size_t k = 0; k  < outProfile->mSupportedDevices.size(); k++) {
-                        audio_devices_t type = outProfile->mSupportedDevices[k]->mDeviceType;
-                        ssize_t index =
-                                mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[k]);
-                        // give a valid ID to an attached device once confirmed it is reachable
-                        if ((index >= 0) && (mAvailableOutputDevices[index]->mId == 0)) {
-                            mAvailableOutputDevices[index]->mId = nextUniqueId();
-                            mAvailableOutputDevices[index]->mModule = mHwModules[i];
-                        }
+                // chose first device present in mSupportedDevices also part of
+                // outputDeviceTypes
+                for (size_t k = 0; k  < outProfile->mSupportedDevices.size(); k++) {
+                    profileType = outProfile->mSupportedDevices[k]->mDeviceType;
+                    if ((profileType & outputDeviceTypes) != 0) {
+                        break;
                     }
-                    if (mPrimaryOutput == 0 &&
-                            outProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
-                        mPrimaryOutput = output;
-                    }
-                    addOutput(output, outputDesc);
-                    setOutputDevice(output,
-                                    outputDesc->mDevice,
-                                    true);
                 }
             }
+            if ((profileType & outputDeviceTypes) == 0) {
+                continue;
+            }
+            sp<AudioOutputDescriptor> outputDesc = new AudioOutputDescriptor(outProfile);
+
+            outputDesc->mDevice = profileType;
+            audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+            config.sample_rate = outputDesc->mSamplingRate;
+            config.channel_mask = outputDesc->mChannelMask;
+            config.format = outputDesc->mFormat;
+            audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+            status_t status = mpClientInterface->openOutput(outProfile->mModule->mHandle,
+                                                            &output,
+                                                            &config,
+                                                            &outputDesc->mDevice,
+                                                            String8(""),
+                                                            &outputDesc->mLatency,
+                                                            outputDesc->mFlags);
+
+            if (status != NO_ERROR) {
+                ALOGW("Cannot open output stream for device %08x on hw module %s",
+                      outputDesc->mDevice,
+                      mHwModules[i]->mName);
+            } else {
+                outputDesc->mSamplingRate = config.sample_rate;
+                outputDesc->mChannelMask = config.channel_mask;
+                outputDesc->mFormat = config.format;
+
+                for (size_t k = 0; k  < outProfile->mSupportedDevices.size(); k++) {
+                    audio_devices_t type = outProfile->mSupportedDevices[k]->mDeviceType;
+                    ssize_t index =
+                            mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[k]);
+                    // give a valid ID to an attached device once confirmed it is reachable
+                    if ((index >= 0) && (mAvailableOutputDevices[index]->mId == 0)) {
+                        mAvailableOutputDevices[index]->mId = nextUniqueId();
+                        mAvailableOutputDevices[index]->mModule = mHwModules[i];
+                    }
+                }
+                if (mPrimaryOutput == 0 &&
+                        outProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+                    mPrimaryOutput = output;
+                }
+                addOutput(output, outputDesc);
+                setOutputDevice(output,
+                                outputDesc->mDevice,
+                                true);
+            }
         }
         // open input streams needed to access attached devices to validate
         // mAvailableInputDevices list
@@ -2731,45 +2741,53 @@
                 ALOGW("Input profile contains no device on module %s", mHwModules[i]->mName);
                 continue;
             }
-
-            audio_devices_t profileType = inProfile->mSupportedDevices[0]->mDeviceType;
-            if (profileType & inputDeviceTypes) {
-                sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(inProfile);
-
-                inputDesc->mInputSource = AUDIO_SOURCE_MIC;
-                inputDesc->mDevice = profileType;
-
-                audio_config_t config = AUDIO_CONFIG_INITIALIZER;
-                config.sample_rate = inputDesc->mSamplingRate;
-                config.channel_mask = inputDesc->mChannelMask;
-                config.format = inputDesc->mFormat;
-                audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
-                status_t status = mpClientInterface->openInput(inProfile->mModule->mHandle,
-                                                               &input,
-                                                               &config,
-                                                               &inputDesc->mDevice,
-                                                               String8(""),
-                                                               AUDIO_SOURCE_MIC,
-                                                               AUDIO_INPUT_FLAG_NONE);
-
-                if (status == NO_ERROR) {
-                    for (size_t k = 0; k  < inProfile->mSupportedDevices.size(); k++) {
-                        audio_devices_t type = inProfile->mSupportedDevices[k]->mDeviceType;
-                        ssize_t index =
-                                mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]);
-                        // give a valid ID to an attached device once confirmed it is reachable
-                        if ((index >= 0) && (mAvailableInputDevices[index]->mId == 0)) {
-                            mAvailableInputDevices[index]->mId = nextUniqueId();
-                            mAvailableInputDevices[index]->mModule = mHwModules[i];
-                        }
-                    }
-                    mpClientInterface->closeInput(input);
-                } else {
-                    ALOGW("Cannot open input stream for device %08x on hw module %s",
-                          inputDesc->mDevice,
-                          mHwModules[i]->mName);
+            // chose first device present in mSupportedDevices also part of
+            // inputDeviceTypes
+            audio_devices_t profileType = AUDIO_DEVICE_NONE;
+            for (size_t k = 0; k  < inProfile->mSupportedDevices.size(); k++) {
+                profileType = inProfile->mSupportedDevices[k]->mDeviceType;
+                if (profileType & inputDeviceTypes) {
+                    break;
                 }
             }
+            if ((profileType & inputDeviceTypes) == 0) {
+                continue;
+            }
+            sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(inProfile);
+
+            inputDesc->mInputSource = AUDIO_SOURCE_MIC;
+            inputDesc->mDevice = profileType;
+
+            audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+            config.sample_rate = inputDesc->mSamplingRate;
+            config.channel_mask = inputDesc->mChannelMask;
+            config.format = inputDesc->mFormat;
+            audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
+            status_t status = mpClientInterface->openInput(inProfile->mModule->mHandle,
+                                                           &input,
+                                                           &config,
+                                                           &inputDesc->mDevice,
+                                                           String8(""),
+                                                           AUDIO_SOURCE_MIC,
+                                                           AUDIO_INPUT_FLAG_NONE);
+
+            if (status == NO_ERROR) {
+                for (size_t k = 0; k  < inProfile->mSupportedDevices.size(); k++) {
+                    audio_devices_t type = inProfile->mSupportedDevices[k]->mDeviceType;
+                    ssize_t index =
+                            mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]);
+                    // give a valid ID to an attached device once confirmed it is reachable
+                    if ((index >= 0) && (mAvailableInputDevices[index]->mId == 0)) {
+                        mAvailableInputDevices[index]->mId = nextUniqueId();
+                        mAvailableInputDevices[index]->mModule = mHwModules[i];
+                    }
+                }
+                mpClientInterface->closeInput(input);
+            } else {
+                ALOGW("Cannot open input stream for device %08x on hw module %s",
+                      inputDesc->mDevice,
+                      mHwModules[i]->mName);
+            }
         }
     }
     // make sure all attached devices have been allocated a unique ID