#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>
looper = new ALooper;
looper->start();
}
- liveSession = new LiveSession;
+ liveSession = new LiveSession(NULL /* notify */);
looper->registerHandler(liveSession);
liveSession->connect(uri.string());
mLiveLooper->setName("http live");
mLiveLooper->start();
+ sp<AMessage> notify = new AMessage(kWhatSessionNotify, id());
+
mLiveSession = new LiveSession(
+ notify,
(mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
mUIDValid, mUID);
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() {
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
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;
sp<LiveSession> mLiveSession;
sp<ATSParser> mTSParser;
+ void onSessionNotify(const sp<AMessage> &msg);
+
DISALLOW_EVIL_CONSTRUCTORS(HTTPLiveSource);
};
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;
}
namespace android {
-LiveSession::LiveSession(uint32_t flags, bool uidValid, uid_t uid)
- : mFlags(flags),
+LiveSession::LiveSession(
+ const sp<AMessage> ¬ify, uint32_t flags, bool uidValid, uid_t uid)
+ : mNotify(notify),
+ mFlags(flags),
mUIDValid(uidValid),
mUID(uid),
+ mInPreparationPhase(true),
mDataSource(new LiveDataSource),
mHTTPDataSource(
HTTPBase::Create(
if (playlist == NULL) {
ALOGE("unable to fetch master playlist '%s'.", url.c_str());
- mDataSource->queueEOS(ERROR_IO);
+ signalEOS(ERROR_IO);
return;
}
void LiveSession::onDisconnect() {
ALOGI("onDisconnect");
- mDataSource->queueEOS(ERROR_END_OF_STREAM);
+ signalEOS(ERROR_END_OF_STREAM);
Mutex::Autolock autoLock(mLock);
mDisconnectPending = false;
// 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 {
mSeqNumber, firstSeqNumberInPlaylist,
firstSeqNumberInPlaylist + mPlaylist->size() - 1);
- mDataSource->queueEOS(ERROR_END_OF_STREAM);
+ signalEOS(ERROR_END_OF_STREAM);
return;
}
}
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;
}
if (err != OK) {
ALOGE("decryptBuffer failed w/ error %d", err);
- mDataSource->queueEOS(err);
+ signalEOS(err);
return;
}
mBandwidthItems.removeAt(bandwidthIndex);
if (mBandwidthItems.isEmpty()) {
- mDataSource->queueEOS(ERROR_UNSUPPORTED);
+ signalEOS(ERROR_UNSUPPORTED);
return;
}
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);
}
}
// Don't log any URLs.
kFlagIncognito = 1,
};
- LiveSession(uint32_t flags = 0, bool uidValid = false, uid_t uid = 0);
+ LiveSession(
+ const sp<AMessage> ¬ify,
+ uint32_t flags = 0, bool uidValid = false, uid_t uid = 0);
sp<DataSource> getDataSource();
bool isSeekable() const;
bool hasDynamicDuration() const;
+ // Posted notification's "what" field will carry one of the following:
+ enum {
+ kWhatPrepared,
+ kWhatPreparationFailed,
+ };
+
protected:
virtual ~LiveSession();
unsigned long mBandwidth;
};
+ sp<AMessage> mNotify;
uint32_t mFlags;
bool mUIDValid;
uid_t mUID;
+ bool mInPreparationPhase;
+
sp<LiveDataSource> mDataSource;
sp<HTTPBase> mHTTPDataSource;
// 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);
};