Fix: status checking in TimedTextDriver.

o fixes seeking error when there's no enabled text track.
o clean up status checking code for deselectTrack.
o fixes a potential bug : pause->backward seek can trigger unwanted
resume.

Bug: 6682160
Change-Id: I03d8788b27fb9c0a6092be83ad3578ccf3266905
(cherry picked from commit 2dafb6071d4f14e0e208912500694912211aa26b)
diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp
index 1a0dc7b..71da803 100644
--- a/media/libstagefright/timedtext/TimedTextDriver.cpp
+++ b/media/libstagefright/timedtext/TimedTextDriver.cpp
@@ -145,21 +145,41 @@
 }
 
 status_t TimedTextDriver::unselectTrack(size_t index) {
+    Mutex::Autolock autoLock(mLock);
     if (mCurrentTrackIndex != index) {
         return INVALID_OPERATION;
     }
-    status_t err = pause();
-    if (err != OK) {
-        return err;
+    switch (mState) {
+        case UNINITIALIZED:
+            return INVALID_OPERATION;
+        case PLAYING:
+            mPlayer->pause();
+            mState = UNINITIALIZED;
+            return OK;
+        case PAUSED:
+            mState = UNINITIALIZED;
+            return OK;
+        default:
+            TRESPASS();
     }
-    Mutex::Autolock autoLock(mLock);
-    mState = UNINITIALIZED;
-    return OK;
+    return UNKNOWN_ERROR;
 }
 
 status_t TimedTextDriver::seekToAsync(int64_t timeUs) {
-    mPlayer->seekToAsync(timeUs);
-    return OK;
+    Mutex::Autolock autoLock(mLock);
+    switch (mState) {
+        case UNINITIALIZED:
+            return INVALID_OPERATION;
+        case PAUSED:
+            mPlayer->seekToAsync(timeUs);
+            return OK;
+        case PLAYING:
+            mPlayer->seekToAsync(timeUs);
+            return OK;
+        defaut:
+            TRESPASS();
+    }
+    return UNKNOWN_ERROR;
 }
 
 status_t TimedTextDriver::addInBandTextSource(
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
index b9cac78..df7eb39 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp
@@ -41,6 +41,8 @@
 TimedTextPlayer::TimedTextPlayer(const wp<MediaPlayerBase> &listener)
     : mListener(listener),
       mSource(NULL),
+      mPendingSeekTimeUs(kInvalidTimeUs),
+      mPaused(false),
       mSendSubtitleGeneration(0) {
 }
 
@@ -53,9 +55,7 @@
 }
 
 void TimedTextPlayer::start() {
-    sp<AMessage> msg = new AMessage(kWhatSeek, id());
-    msg->setInt64("seekTimeUs", kInvalidTimeUs);
-    msg->post();
+    (new AMessage(kWhatStart, id()))->post();
 }
 
 void TimedTextPlayer::pause() {
@@ -81,11 +81,34 @@
 void TimedTextPlayer::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatPause: {
-            mSendSubtitleGeneration++;
+            mPaused = true;
             break;
         }
         case kWhatResume: {
-            doRead();
+            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: {
@@ -110,7 +133,6 @@
             break;
         }
         case kWhatSeek: {
-            mSendSubtitleGeneration++;
             int64_t seekTimeUs = kInvalidTimeUs;
             // Clear a displayed timed text before seeking.
             notifyListener();
@@ -123,6 +145,11 @@
                     seekTimeUs = positionMs * 1000ll;
                 }
             }
+            if (mPaused) {
+                mPendingSeekTimeUs = seekTimeUs;
+                break;
+            }
+            mSendSubtitleGeneration++;
             doSeekAndRead(seekTimeUs);
             break;
         }
@@ -221,22 +248,20 @@
 
 void TimedTextPlayer::postTextEvent(const sp<ParcelEvent>& parcel, int64_t timeUs) {
     int64_t delayUs = delayUsFromCurrentTime(timeUs);
-    sp<MediaPlayerBase> listener = mListener.promote();
-    if (listener != NULL) {
-        sp<AMessage> msg = new AMessage(kWhatSendSubtitle, id());
-        msg->setInt32("generation", mSendSubtitleGeneration);
-        if (parcel != NULL) {
-            msg->setObject("subtitle", parcel);
-        }
-        msg->setInt64("fireTimeUs", timeUs);
-        msg->post(delayUs);
+    sp<AMessage> msg = new AMessage(kWhatSendSubtitle, id());
+    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.", __FUNCTION__, fireTimeUs);
         return 0;
     }
     int32_t positionMs = 0;
@@ -256,19 +281,23 @@
 
 void TimedTextPlayer::notifyError(int error) {
     sp<MediaPlayerBase> listener = mListener.promote();
-    if (listener != NULL) {
-        listener->sendEvent(MEDIA_INFO, MEDIA_INFO_TIMED_TEXT_ERROR, error);
+    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) {
-        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);
-        }
+    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);
     }
 }
 
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.h b/media/libstagefright/timedtext/TimedTextPlayer.h
index d8f83af..ec8ed25 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.h
+++ b/media/libstagefright/timedtext/TimedTextPlayer.h
@@ -50,8 +50,9 @@
 private:
     enum {
         kWhatPause = 'paus',
-        kWhatSeek = 'seek',
         kWhatResume = 'resm',
+        kWhatStart = 'strt',
+        kWhatSeek = 'seek',
         kWhatRetryRead = 'read',
         kWhatSendSubtitle = 'send',
         kWhatSetSource = 'ssrc',
@@ -64,6 +65,8 @@
 
     wp<MediaPlayerBase> mListener;
     sp<TimedTextSource> mSource;
+    int64_t mPendingSeekTimeUs;
+    bool mPaused;
     int32_t mSendSubtitleGeneration;
 
     void doSeekAndRead(int64_t seekTimeUs);