am beffefa2: Merge "RTSP seeking is now asynchronous, MediaPlayer is not notified that the seek is complete until it actually is. Ignore seek requests on live streams." into gingerbread

Merge commit 'beffefa24f398b610d58dd583d9f5613dc529c28' into gingerbread-plus-aosp

* commit 'beffefa24f398b610d58dd583d9f5613dc529c28':
  RTSP seeking is now asynchronous, MediaPlayer is not notified that the seek is complete until it actually is. Ignore seek requests on live streams.
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 53543b3..ff28f3b 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -876,12 +876,19 @@
     return OK;
 }
 
+// static
+void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
+    static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
+}
+
+void AwesomePlayer::onRTSPSeekDone() {
+    notifyListener_l(MEDIA_SEEK_COMPLETE);
+    mSeekNotificationSent = true;
+}
+
 status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
     if (mRTSPController != NULL) {
-        mRTSPController->seek(timeUs);
-
-        notifyListener_l(MEDIA_SEEK_COMPLETE);
-        mSeekNotificationSent = true;
+        mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
         return OK;
     }
 
diff --git a/media/libstagefright/include/ARTSPController.h b/media/libstagefright/include/ARTSPController.h
index c2f3090..ce7ffe5 100644
--- a/media/libstagefright/include/ARTSPController.h
+++ b/media/libstagefright/include/ARTSPController.h
@@ -33,7 +33,7 @@
     status_t connect(const char *url);
     void disconnect();
 
-    void seek(int64_t timeUs);
+    void seekAsync(int64_t timeUs, void (*seekDoneCb)(void *), void *cookie);
 
     virtual size_t countTracks();
     virtual sp<MediaSource> getTrack(size_t index);
@@ -61,6 +61,7 @@
     enum {
         kWhatConnectDone    = 'cdon',
         kWhatDisconnectDone = 'ddon',
+        kWhatSeekDone       = 'sdon',
     };
 
     enum State {
@@ -79,6 +80,10 @@
     sp<MyHandler> mHandler;
     sp<AHandlerReflector<ARTSPController> > mReflector;
 
+    void (*mSeekDoneCb)(void *);
+    void *mSeekDoneCookie;
+    int64_t mLastSeekCompletedTimeUs;
+
     DISALLOW_EVIL_CONSTRUCTORS(ARTSPController);
 };
 
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index bbf482d..079adca 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -251,6 +251,9 @@
 
     static bool ContinuePreparation(void *cookie);
 
+    static void OnRTSPSeekDoneWrapper(void *cookie);
+    void onRTSPSeekDone();
+
     AwesomePlayer(const AwesomePlayer &);
     AwesomePlayer &operator=(const AwesomePlayer &);
 };
diff --git a/media/libstagefright/rtsp/ARTSPController.cpp b/media/libstagefright/rtsp/ARTSPController.cpp
index 4c53639..a7563ff 100644
--- a/media/libstagefright/rtsp/ARTSPController.cpp
+++ b/media/libstagefright/rtsp/ARTSPController.cpp
@@ -27,7 +27,10 @@
 
 ARTSPController::ARTSPController(const sp<ALooper> &looper)
     : mState(DISCONNECTED),
-      mLooper(looper) {
+      mLooper(looper),
+      mSeekDoneCb(NULL),
+      mSeekDoneCookie(NULL),
+      mLastSeekCompletedTimeUs(-1) {
     mReflector = new AHandlerReflector<ARTSPController>(this);
     looper->registerHandler(mReflector);
 }
@@ -80,14 +83,31 @@
     mHandler.clear();
 }
 
-void ARTSPController::seek(int64_t timeUs) {
+void ARTSPController::seekAsync(
+        int64_t timeUs,
+        void (*seekDoneCb)(void *), void *cookie) {
     Mutex::Autolock autoLock(mLock);
 
-    if (mState != CONNECTED) {
+    CHECK(seekDoneCb != NULL);
+    CHECK(mSeekDoneCb == NULL);
+
+    // Ignore seek requests that are too soon after the previous one has
+    // completed, we don't want to swamp the server.
+
+    bool tooEarly =
+        mLastSeekCompletedTimeUs >= 0
+            && ALooper::GetNowUs() < mLastSeekCompletedTimeUs + 500000ll;
+
+    if (mState != CONNECTED || tooEarly) {
+        (*seekDoneCb)(cookie);
         return;
     }
 
-    mHandler->seek(timeUs);
+    mSeekDoneCb = seekDoneCb;
+    mSeekDoneCookie = cookie;
+
+    sp<AMessage> msg = new AMessage(kWhatSeekDone, mReflector->id());
+    mHandler->seek(timeUs, msg);
 }
 
 size_t ARTSPController::countTracks() {
@@ -132,6 +152,19 @@
             break;
         }
 
+        case kWhatSeekDone:
+        {
+            LOGI("seek done");
+
+            mLastSeekCompletedTimeUs = ALooper::GetNowUs();
+
+            void (*seekDoneCb)(void *) = mSeekDoneCb;
+            mSeekDoneCb = NULL;
+
+            (*seekDoneCb)(mSeekDoneCookie);
+            break;
+        }
+
         default:
             TRESPASS();
             break;
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 2c9cfd3..05dd61b 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -88,7 +88,8 @@
           mCheckPending(false),
           mCheckGeneration(0),
           mTryTCPInterleaving(false),
-          mReceivedFirstRTCPPacket(false) {
+          mReceivedFirstRTCPPacket(false),
+          mSeekable(false) {
         mNetLooper->setName("rtsp net");
         mNetLooper->start(false /* runOnCallingThread */,
                           false /* canCallJava */,
@@ -115,9 +116,10 @@
         (new AMessage('abor', id()))->post();
     }
 
-    void seek(int64_t timeUs) {
+    void seek(int64_t timeUs, const sp<AMessage> &doneMsg) {
         sp<AMessage> msg = new AMessage('seek', id());
         msg->setInt64("time", timeUs);
+        msg->setMessage("doneMsg", doneMsg);
         msg->post();
     }
 
@@ -379,6 +381,7 @@
                 mFirstAccessUnitNTP = 0;
                 mNumAccessUnitsReceived = 0;
                 mReceivedFirstRTCPPacket = false;
+                mSeekable = false;
 
                 sp<AMessage> reply = new AMessage('tear', id());
 
@@ -551,7 +554,17 @@
 
             case 'seek':
             {
+                sp<AMessage> doneMsg;
+                CHECK(msg->findMessage("doneMsg", &doneMsg));
+
                 if (mSeekPending) {
+                    doneMsg->post();
+                    break;
+                }
+
+                if (!mSeekable) {
+                    LOGW("This is a live stream, ignoring seek request.");
+                    doneMsg->post();
                     break;
                 }
 
@@ -577,6 +590,7 @@
 
                 sp<AMessage> reply = new AMessage('see1', id());
                 reply->setInt64("time", timeUs);
+                reply->setMessage("doneMsg", doneMsg);
                 mConn->sendRequest(request.c_str(), reply);
                 break;
             }
@@ -605,7 +619,11 @@
 
                 request.append("\r\n");
 
+                sp<AMessage> doneMsg;
+                CHECK(msg->findMessage("doneMsg", &doneMsg));
+
                 sp<AMessage> reply = new AMessage('see2', id());
+                reply->setMessage("doneMsg", doneMsg);
                 mConn->sendRequest(request.c_str(), reply);
                 break;
             }
@@ -644,6 +662,11 @@
                 }
 
                 mSeekPending = false;
+
+                sp<AMessage> doneMsg;
+                CHECK(msg->findMessage("doneMsg", &doneMsg));
+
+                doneMsg->post();
                 break;
             }
 
@@ -714,6 +737,8 @@
     }
 
     void parsePlayResponse(const sp<ARTSPResponse> &response) {
+        mSeekable = false;
+
         ssize_t i = response->mHeaders.indexOfKey("range");
         if (i < 0) {
             // Server doesn't even tell use what range it is going to
@@ -777,6 +802,8 @@
 
             ++n;
         }
+
+        mSeekable = true;
     }
 
     sp<APacketSource> getPacketSource(size_t index) {
@@ -808,6 +835,7 @@
     int32_t mCheckGeneration;
     bool mTryTCPInterleaving;
     bool mReceivedFirstRTCPPacket;
+    bool mSeekable;
 
     struct TrackInfo {
         AString mURL;