OSDN Git Service

HLS now properly publishes its "seekable" flags after connection
authorAndreas Huber <andih@google.com>
Wed, 6 Feb 2013 18:44:39 +0000 (10:44 -0800)
committerAndreas Huber <andih@google.com>
Wed, 6 Feb 2013 18:44:39 +0000 (10:44 -0800)
has successfully completed and a sufficient amount of data fetched,
and only then signals that preparation is completed.

Change-Id: I7684a14238b826909f518f2af506966e522dfcfc

cmds/stagefright/stagefright.cpp
media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
media/libstagefright/foundation/ALooperRoster.cpp
media/libstagefright/httplive/LiveSession.cpp
media/libstagefright/include/LiveSession.h

index 2b935ed..2aae64d 100644 (file)
@@ -30,6 +30,7 @@
 #include <binder/ProcessState.h>
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
 #include "include/LiveSession.h"
 #include "include/NuCachedSource2.h"
 #include <media/stagefright/AudioPlayer.h>
@@ -1004,7 +1005,7 @@ int main(int argc, char **argv) {
                     looper = new ALooper;
                     looper->start();
                 }
-                liveSession = new LiveSession;
+                liveSession = new LiveSession(NULL /* notify */);
                 looper->registerHandler(liveSession);
 
                 liveSession->connect(uri.string());
index ae67906..655ee55 100644 (file)
@@ -71,7 +71,10 @@ void NuPlayer::HTTPLiveSource::prepareAsync() {
     mLiveLooper->setName("http live");
     mLiveLooper->start();
 
+    sp<AMessage> notify = new AMessage(kWhatSessionNotify, id());
+
     mLiveSession = new LiveSession(
+            notify,
             (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
             mUIDValid, mUID);
 
@@ -81,23 +84,6 @@ void NuPlayer::HTTPLiveSource::prepareAsync() {
             mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
 
     mTSParser = new ATSParser;
-
-    notifyVideoSizeChanged(0, 0);
-
-    uint32_t flags = FLAG_CAN_PAUSE;
-    if (mLiveSession->isSeekable()) {
-        flags |= FLAG_CAN_SEEK;
-        flags |= FLAG_CAN_SEEK_BACKWARD;
-        flags |= FLAG_CAN_SEEK_FORWARD;
-    }
-
-    if (mLiveSession->hasDynamicDuration()) {
-        flags |= FLAG_DYNAMIC_DURATION;
-    }
-
-    notifyFlagsChanged(flags);
-
-    notifyPrepared();
 }
 
 void NuPlayer::HTTPLiveSource::start() {
@@ -214,5 +200,59 @@ status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) {
     return OK;
 }
 
+void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatSessionNotify:
+        {
+            onSessionNotify(msg);
+            break;
+        }
+
+        default:
+            Source::onMessageReceived(msg);
+            break;
+    }
+}
+
+void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) {
+    int32_t what;
+    CHECK(msg->findInt32("what", &what));
+
+    switch (what) {
+        case LiveSession::kWhatPrepared:
+        {
+            notifyVideoSizeChanged(0, 0);
+
+            uint32_t flags = FLAG_CAN_PAUSE;
+            if (mLiveSession->isSeekable()) {
+                flags |= FLAG_CAN_SEEK;
+                flags |= FLAG_CAN_SEEK_BACKWARD;
+                flags |= FLAG_CAN_SEEK_FORWARD;
+            }
+
+            if (mLiveSession->hasDynamicDuration()) {
+                flags |= FLAG_DYNAMIC_DURATION;
+            }
+
+            notifyFlagsChanged(flags);
+
+            notifyPrepared();
+            break;
+        }
+
+        case LiveSession::kWhatPreparationFailed:
+        {
+            status_t err;
+            CHECK(msg->findInt32("err", &err));
+
+            notifyPrepared(err);
+            break;
+        }
+
+        default:
+            TRESPASS();
+    }
+}
+
 }  // namespace android
 
index 269f3c0..067d1da 100644 (file)
@@ -49,12 +49,18 @@ protected:
 
     virtual sp<MetaData> getFormatMeta(bool audio);
 
+    virtual void onMessageReceived(const sp<AMessage> &msg);
+
 private:
     enum Flags {
         // Don't log any URLs.
         kFlagIncognito = 1,
     };
 
+    enum {
+        kWhatSessionNotify,
+    };
+
     AString mURL;
     KeyedVector<String8, String8> mExtraHeaders;
     bool mUIDValid;
@@ -66,6 +72,8 @@ private:
     sp<LiveSession> mLiveSession;
     sp<ATSParser> mTSParser;
 
+    void onSessionNotify(const sp<AMessage> &msg);
+
     DISALLOW_EVIL_CONSTRUCTORS(HTTPLiveSource);
 };
 
index dff931d..ad10d2b 100644 (file)
@@ -82,7 +82,8 @@ status_t ALooperRoster::postMessage_l(
     ssize_t index = mHandlers.indexOfKey(msg->target());
 
     if (index < 0) {
-        ALOGW("failed to post message. Target handler not registered.");
+        ALOGW("failed to post message '%s'. Target handler not registered.",
+              msg->debugString().c_str());
         return -ENOENT;
     }
 
index 733753b..962b01c 100644 (file)
 
 namespace android {
 
-LiveSession::LiveSession(uint32_t flags, bool uidValid, uid_t uid)
-    : mFlags(flags),
+LiveSession::LiveSession(
+        const sp<AMessage> &notify, uint32_t flags, bool uidValid, uid_t uid)
+    : mNotify(notify),
+      mFlags(flags),
       mUIDValid(uidValid),
       mUID(uid),
+      mInPreparationPhase(true),
       mDataSource(new LiveDataSource),
       mHTTPDataSource(
               HTTPBase::Create(
@@ -179,7 +182,7 @@ void LiveSession::onConnect(const sp<AMessage> &msg) {
     if (playlist == NULL) {
         ALOGE("unable to fetch master playlist '%s'.", url.c_str());
 
-        mDataSource->queueEOS(ERROR_IO);
+        signalEOS(ERROR_IO);
         return;
     }
 
@@ -207,7 +210,7 @@ void LiveSession::onConnect(const sp<AMessage> &msg) {
 void LiveSession::onDisconnect() {
     ALOGI("onDisconnect");
 
-    mDataSource->queueEOS(ERROR_END_OF_STREAM);
+    signalEOS(ERROR_END_OF_STREAM);
 
     Mutex::Autolock autoLock(mLock);
     mDisconnectPending = false;
@@ -561,7 +564,8 @@ rinse_repeat:
                 // unchanged from the last time we tried.
             } else {
                 ALOGE("failed to load playlist at url '%s'", url.c_str());
-                mDataSource->queueEOS(ERROR_IO);
+                signalEOS(ERROR_IO);
+
                 return;
             }
         } else {
@@ -704,7 +708,7 @@ rinse_repeat:
                  mSeqNumber, firstSeqNumberInPlaylist,
                  firstSeqNumberInPlaylist + mPlaylist->size() - 1);
 
-            mDataSource->queueEOS(ERROR_END_OF_STREAM);
+            signalEOS(ERROR_END_OF_STREAM);
             return;
         }
     }
@@ -737,7 +741,7 @@ rinse_repeat:
     status_t err = fetchFile(uri.c_str(), &buffer, range_offset, range_length);
     if (err != OK) {
         ALOGE("failed to fetch .ts segment at url '%s'", uri.c_str());
-        mDataSource->queueEOS(err);
+        signalEOS(err);
         return;
     }
 
@@ -748,7 +752,7 @@ rinse_repeat:
     if (err != OK) {
         ALOGE("decryptBuffer failed w/ error %d", err);
 
-        mDataSource->queueEOS(err);
+        signalEOS(err);
         return;
     }
 
@@ -760,7 +764,7 @@ rinse_repeat:
         mBandwidthItems.removeAt(bandwidthIndex);
 
         if (mBandwidthItems.isEmpty()) {
-            mDataSource->queueEOS(ERROR_UNSUPPORTED);
+            signalEOS(ERROR_UNSUPPORTED);
             return;
         }
 
@@ -824,11 +828,42 @@ rinse_repeat:
     postMonitorQueue();
 }
 
+void LiveSession::signalEOS(status_t err) {
+    if (mInPreparationPhase && mNotify != NULL) {
+        sp<AMessage> notify = mNotify->dup();
+
+        notify->setInt32(
+                "what",
+                err == ERROR_END_OF_STREAM
+                    ? kWhatPrepared : kWhatPreparationFailed);
+
+        if (err != ERROR_END_OF_STREAM) {
+            notify->setInt32("err", err);
+        }
+
+        notify->post();
+
+        mInPreparationPhase = false;
+    }
+
+    mDataSource->queueEOS(err);
+}
+
 void LiveSession::onMonitorQueue() {
     if (mSeekTimeUs >= 0
             || mDataSource->countQueuedBuffers() < kMaxNumQueuedFragments) {
         onDownloadNext();
     } else {
+        if (mInPreparationPhase) {
+            if (mNotify != NULL) {
+                sp<AMessage> notify = mNotify->dup();
+                notify->setInt32("what", kWhatPrepared);
+                notify->post();
+            }
+
+            mInPreparationPhase = false;
+        }
+
         postMonitorQueue(1000000ll);
     }
 }
index f329cc9..db44a33 100644 (file)
@@ -35,7 +35,9 @@ struct LiveSession : public AHandler {
         // Don't log any URLs.
         kFlagIncognito = 1,
     };
-    LiveSession(uint32_t flags = 0, bool uidValid = false, uid_t uid = 0);
+    LiveSession(
+            const sp<AMessage> &notify,
+            uint32_t flags = 0, bool uidValid = false, uid_t uid = 0);
 
     sp<DataSource> getDataSource();
 
@@ -53,6 +55,12 @@ struct LiveSession : public AHandler {
     bool isSeekable() const;
     bool hasDynamicDuration() const;
 
+    // Posted notification's "what" field will carry one of the following:
+    enum {
+        kWhatPrepared,
+        kWhatPreparationFailed,
+    };
+
 protected:
     virtual ~LiveSession();
 
@@ -76,10 +84,13 @@ private:
         unsigned long mBandwidth;
     };
 
+    sp<AMessage> mNotify;
     uint32_t mFlags;
     bool mUIDValid;
     uid_t mUID;
 
+    bool mInPreparationPhase;
+
     sp<LiveDataSource> mDataSource;
 
     sp<HTTPBase> mHTTPDataSource;
@@ -144,6 +155,8 @@ private:
     // This is computed by summing the durations of all segments before it.
     int64_t getSegmentStartTimeUs(int32_t seqNumber) const;
 
+    void signalEOS(status_t err);
+
     DISALLOW_EVIL_CONSTRUCTORS(LiveSession);
 };