summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2013-02-06 10:44:39 -0800
committerAndreas Huber <andih@google.com>2013-02-06 10:44:39 -0800
commit0df36ec3303c2c6bf9b42c07945ac8bd234153f3 (patch)
tree558d8e8d18ce64e84114d3b3d53209c0b4e27693
parentec0c597cabf169ca646bcea5faac1bd81ed4484d (diff)
downloadframeworks_av-0df36ec3303c2c6bf9b42c07945ac8bd234153f3.zip
frameworks_av-0df36ec3303c2c6bf9b42c07945ac8bd234153f3.tar.gz
frameworks_av-0df36ec3303c2c6bf9b42c07945ac8bd234153f3.tar.bz2
HLS now properly publishes its "seekable" flags after connection
has successfully completed and a sufficient amount of data fetched, and only then signals that preparation is completed. Change-Id: I7684a14238b826909f518f2af506966e522dfcfc
-rw-r--r--cmds/stagefright/stagefright.cpp3
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp74
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.h8
-rw-r--r--media/libstagefright/foundation/ALooperRoster.cpp3
-rw-r--r--media/libstagefright/httplive/LiveSession.cpp53
-rw-r--r--media/libstagefright/include/LiveSession.h15
6 files changed, 127 insertions, 29 deletions
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 2b935ed..2aae64d 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -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());
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index ae67906..655ee55 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -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
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index 269f3c0..067d1da 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -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);
};
diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp
index dff931d..ad10d2b 100644
--- a/media/libstagefright/foundation/ALooperRoster.cpp
+++ b/media/libstagefright/foundation/ALooperRoster.cpp
@@ -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;
}
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 733753b..962b01c 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -40,10 +40,13 @@
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);
}
}
diff --git a/media/libstagefright/include/LiveSession.h b/media/libstagefright/include/LiveSession.h
index f329cc9..db44a33 100644
--- a/media/libstagefright/include/LiveSession.h
+++ b/media/libstagefright/include/LiveSession.h
@@ -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);
};