Loading media/libstagefright/httplive/LiveSession.cpp +111 −12 Original line number Diff line number Diff line Loading @@ -36,11 +36,10 @@ #include <ctype.h> #include <openssl/aes.h> #include <openssl/md5.h> namespace android { const int64_t LiveSession::kMaxPlaylistAgeUs = 15000000ll; LiveSession::LiveSession(uint32_t flags, bool uidValid, uid_t uid) : mFlags(flags), mUIDValid(uidValid), Loading @@ -59,7 +58,8 @@ LiveSession::LiveSession(uint32_t flags, bool uidValid, uid_t uid) mDurationUs(-1), mSeekDone(false), mDisconnectPending(false), mMonitorQueueGeneration(0) { mMonitorQueueGeneration(0), mRefreshState(INITIAL_MINIMUM_RELOAD_DELAY) { if (mUIDValid) { mHTTPDataSource->setUID(mUID); } Loading Loading @@ -175,7 +175,8 @@ void LiveSession::onConnect(const sp<AMessage> &msg) { mMasterURL = url; sp<M3UParser> playlist = fetchPlaylist(url.c_str()); bool dummy; sp<M3UParser> playlist = fetchPlaylist(url.c_str(), &dummy); if (playlist == NULL) { LOGE("unable to fetch master playlist '%s'.", url.c_str()); Loading Loading @@ -289,7 +290,9 @@ status_t LiveSession::fetchFile(const char *url, sp<ABuffer> *out) { return OK; } sp<M3UParser> LiveSession::fetchPlaylist(const char *url) { sp<M3UParser> LiveSession::fetchPlaylist(const char *url, bool *unchanged) { *unchanged = false; sp<ABuffer> buffer; status_t err = fetchFile(url, &buffer); Loading @@ -297,6 +300,38 @@ sp<M3UParser> LiveSession::fetchPlaylist(const char *url) { return NULL; } // MD5 functionality is not available on the simulator, treat all // playlists as changed. #if defined(HAVE_ANDROID_OS) uint8_t hash[16]; MD5_CTX m; MD5_Init(&m); MD5_Update(&m, buffer->data(), buffer->size()); MD5_Final(hash, &m); if (mPlaylist != NULL && !memcmp(hash, mPlaylistHash, 16)) { // playlist unchanged if (mRefreshState != THIRD_UNCHANGED_RELOAD_ATTEMPT) { mRefreshState = (RefreshState)(mRefreshState + 1); } *unchanged = true; LOGV("Playlist unchanged, refresh state is now %d", (int)mRefreshState); return NULL; } memcpy(mPlaylistHash, hash, sizeof(hash)); mRefreshState = INITIAL_MINIMUM_RELOAD_DELAY; #endif sp<M3UParser> playlist = new M3UParser(url, buffer->data(), buffer->size()); Loading Loading @@ -384,6 +419,63 @@ size_t LiveSession::getBandwidthIndex() { return index; } bool LiveSession::timeToRefreshPlaylist(int64_t nowUs) const { if (mPlaylist == NULL) { CHECK_EQ((int)mRefreshState, (int)INITIAL_MINIMUM_RELOAD_DELAY); return true; } int32_t targetDurationSecs; CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs)); int64_t targetDurationUs = targetDurationSecs * 1000000ll; int64_t minPlaylistAgeUs; switch (mRefreshState) { case INITIAL_MINIMUM_RELOAD_DELAY: { size_t n = mPlaylist->size(); if (n > 0) { sp<AMessage> itemMeta; CHECK(mPlaylist->itemAt(n - 1, NULL /* uri */, &itemMeta)); int64_t itemDurationUs; CHECK(itemMeta->findInt64("durationUs", &itemDurationUs)); minPlaylistAgeUs = itemDurationUs; break; } // fall through } case FIRST_UNCHANGED_RELOAD_ATTEMPT: { minPlaylistAgeUs = targetDurationUs / 2; break; } case SECOND_UNCHANGED_RELOAD_ATTEMPT: { minPlaylistAgeUs = (targetDurationUs * 3) / 2; break; } case THIRD_UNCHANGED_RELOAD_ATTEMPT: { minPlaylistAgeUs = targetDurationUs * 3; break; } default: TRESPASS(); break; } return mLastPlaylistFetchTimeUs + minPlaylistAgeUs <= nowUs; } void LiveSession::onDownloadNext() { size_t bandwidthIndex = getBandwidthIndex(); Loading @@ -392,8 +484,7 @@ rinse_repeat: if (mLastPlaylistFetchTimeUs < 0 || (ssize_t)bandwidthIndex != mPrevBandwidthIndex || (!mPlaylist->isComplete() && mLastPlaylistFetchTimeUs + kMaxPlaylistAgeUs <= nowUs)) { || (!mPlaylist->isComplete() && timeToRefreshPlaylist(nowUs))) { AString url; if (mBandwidthItems.size() > 0) { url = mBandwidthItems.editItemAt(bandwidthIndex).mURI; Loading @@ -403,12 +494,20 @@ rinse_repeat: bool firstTime = (mPlaylist == NULL); mPlaylist = fetchPlaylist(url.c_str()); if (mPlaylist == NULL) { bool unchanged; sp<M3UParser> playlist = fetchPlaylist(url.c_str(), &unchanged); if (playlist == NULL) { if (unchanged) { // We succeeded in fetching the playlist, but it was // unchanged from the last time we tried. } else { LOGE("failed to load playlist at url '%s'", url.c_str()); mDataSource->queueEOS(ERROR_IO); return; } } else { mPlaylist = playlist; } if (firstTime) { Mutex::Autolock autoLock(mLock); Loading media/libstagefright/include/LiveSession.h +13 −3 Original line number Diff line number Diff line Loading @@ -62,8 +62,6 @@ private: kMaxNumRetries = 5, }; static const int64_t kMaxPlaylistAgeUs; enum { kWhatConnect = 'conn', kWhatDisconnect = 'disc', Loading Loading @@ -106,6 +104,16 @@ private: int32_t mMonitorQueueGeneration; enum RefreshState { INITIAL_MINIMUM_RELOAD_DELAY, FIRST_UNCHANGED_RELOAD_ATTEMPT, SECOND_UNCHANGED_RELOAD_ATTEMPT, THIRD_UNCHANGED_RELOAD_ATTEMPT }; RefreshState mRefreshState; uint8_t mPlaylistHash[16]; void onConnect(const sp<AMessage> &msg); void onDisconnect(); void onDownloadNext(); Loading @@ -113,7 +121,7 @@ private: void onSeek(const sp<AMessage> &msg); status_t fetchFile(const char *url, sp<ABuffer> *out); sp<M3UParser> fetchPlaylist(const char *url); sp<M3UParser> fetchPlaylist(const char *url, bool *unchanged); size_t getBandwidthIndex(); status_t decryptBuffer( Loading @@ -121,6 +129,8 @@ private: void postMonitorQueue(int64_t delayUs = 0); bool timeToRefreshPlaylist(int64_t nowUs) const; static int SortByBandwidth(const BandwidthItem *, const BandwidthItem *); DISALLOW_EVIL_CONSTRUCTORS(LiveSession); Loading Loading
media/libstagefright/httplive/LiveSession.cpp +111 −12 Original line number Diff line number Diff line Loading @@ -36,11 +36,10 @@ #include <ctype.h> #include <openssl/aes.h> #include <openssl/md5.h> namespace android { const int64_t LiveSession::kMaxPlaylistAgeUs = 15000000ll; LiveSession::LiveSession(uint32_t flags, bool uidValid, uid_t uid) : mFlags(flags), mUIDValid(uidValid), Loading @@ -59,7 +58,8 @@ LiveSession::LiveSession(uint32_t flags, bool uidValid, uid_t uid) mDurationUs(-1), mSeekDone(false), mDisconnectPending(false), mMonitorQueueGeneration(0) { mMonitorQueueGeneration(0), mRefreshState(INITIAL_MINIMUM_RELOAD_DELAY) { if (mUIDValid) { mHTTPDataSource->setUID(mUID); } Loading Loading @@ -175,7 +175,8 @@ void LiveSession::onConnect(const sp<AMessage> &msg) { mMasterURL = url; sp<M3UParser> playlist = fetchPlaylist(url.c_str()); bool dummy; sp<M3UParser> playlist = fetchPlaylist(url.c_str(), &dummy); if (playlist == NULL) { LOGE("unable to fetch master playlist '%s'.", url.c_str()); Loading Loading @@ -289,7 +290,9 @@ status_t LiveSession::fetchFile(const char *url, sp<ABuffer> *out) { return OK; } sp<M3UParser> LiveSession::fetchPlaylist(const char *url) { sp<M3UParser> LiveSession::fetchPlaylist(const char *url, bool *unchanged) { *unchanged = false; sp<ABuffer> buffer; status_t err = fetchFile(url, &buffer); Loading @@ -297,6 +300,38 @@ sp<M3UParser> LiveSession::fetchPlaylist(const char *url) { return NULL; } // MD5 functionality is not available on the simulator, treat all // playlists as changed. #if defined(HAVE_ANDROID_OS) uint8_t hash[16]; MD5_CTX m; MD5_Init(&m); MD5_Update(&m, buffer->data(), buffer->size()); MD5_Final(hash, &m); if (mPlaylist != NULL && !memcmp(hash, mPlaylistHash, 16)) { // playlist unchanged if (mRefreshState != THIRD_UNCHANGED_RELOAD_ATTEMPT) { mRefreshState = (RefreshState)(mRefreshState + 1); } *unchanged = true; LOGV("Playlist unchanged, refresh state is now %d", (int)mRefreshState); return NULL; } memcpy(mPlaylistHash, hash, sizeof(hash)); mRefreshState = INITIAL_MINIMUM_RELOAD_DELAY; #endif sp<M3UParser> playlist = new M3UParser(url, buffer->data(), buffer->size()); Loading Loading @@ -384,6 +419,63 @@ size_t LiveSession::getBandwidthIndex() { return index; } bool LiveSession::timeToRefreshPlaylist(int64_t nowUs) const { if (mPlaylist == NULL) { CHECK_EQ((int)mRefreshState, (int)INITIAL_MINIMUM_RELOAD_DELAY); return true; } int32_t targetDurationSecs; CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs)); int64_t targetDurationUs = targetDurationSecs * 1000000ll; int64_t minPlaylistAgeUs; switch (mRefreshState) { case INITIAL_MINIMUM_RELOAD_DELAY: { size_t n = mPlaylist->size(); if (n > 0) { sp<AMessage> itemMeta; CHECK(mPlaylist->itemAt(n - 1, NULL /* uri */, &itemMeta)); int64_t itemDurationUs; CHECK(itemMeta->findInt64("durationUs", &itemDurationUs)); minPlaylistAgeUs = itemDurationUs; break; } // fall through } case FIRST_UNCHANGED_RELOAD_ATTEMPT: { minPlaylistAgeUs = targetDurationUs / 2; break; } case SECOND_UNCHANGED_RELOAD_ATTEMPT: { minPlaylistAgeUs = (targetDurationUs * 3) / 2; break; } case THIRD_UNCHANGED_RELOAD_ATTEMPT: { minPlaylistAgeUs = targetDurationUs * 3; break; } default: TRESPASS(); break; } return mLastPlaylistFetchTimeUs + minPlaylistAgeUs <= nowUs; } void LiveSession::onDownloadNext() { size_t bandwidthIndex = getBandwidthIndex(); Loading @@ -392,8 +484,7 @@ rinse_repeat: if (mLastPlaylistFetchTimeUs < 0 || (ssize_t)bandwidthIndex != mPrevBandwidthIndex || (!mPlaylist->isComplete() && mLastPlaylistFetchTimeUs + kMaxPlaylistAgeUs <= nowUs)) { || (!mPlaylist->isComplete() && timeToRefreshPlaylist(nowUs))) { AString url; if (mBandwidthItems.size() > 0) { url = mBandwidthItems.editItemAt(bandwidthIndex).mURI; Loading @@ -403,12 +494,20 @@ rinse_repeat: bool firstTime = (mPlaylist == NULL); mPlaylist = fetchPlaylist(url.c_str()); if (mPlaylist == NULL) { bool unchanged; sp<M3UParser> playlist = fetchPlaylist(url.c_str(), &unchanged); if (playlist == NULL) { if (unchanged) { // We succeeded in fetching the playlist, but it was // unchanged from the last time we tried. } else { LOGE("failed to load playlist at url '%s'", url.c_str()); mDataSource->queueEOS(ERROR_IO); return; } } else { mPlaylist = playlist; } if (firstTime) { Mutex::Autolock autoLock(mLock); Loading
media/libstagefright/include/LiveSession.h +13 −3 Original line number Diff line number Diff line Loading @@ -62,8 +62,6 @@ private: kMaxNumRetries = 5, }; static const int64_t kMaxPlaylistAgeUs; enum { kWhatConnect = 'conn', kWhatDisconnect = 'disc', Loading Loading @@ -106,6 +104,16 @@ private: int32_t mMonitorQueueGeneration; enum RefreshState { INITIAL_MINIMUM_RELOAD_DELAY, FIRST_UNCHANGED_RELOAD_ATTEMPT, SECOND_UNCHANGED_RELOAD_ATTEMPT, THIRD_UNCHANGED_RELOAD_ATTEMPT }; RefreshState mRefreshState; uint8_t mPlaylistHash[16]; void onConnect(const sp<AMessage> &msg); void onDisconnect(); void onDownloadNext(); Loading @@ -113,7 +121,7 @@ private: void onSeek(const sp<AMessage> &msg); status_t fetchFile(const char *url, sp<ABuffer> *out); sp<M3UParser> fetchPlaylist(const char *url); sp<M3UParser> fetchPlaylist(const char *url, bool *unchanged); size_t getBandwidthIndex(); status_t decryptBuffer( Loading @@ -121,6 +129,8 @@ private: void postMonitorQueue(int64_t delayUs = 0); bool timeToRefreshPlaylist(int64_t nowUs) const; static int SortByBandwidth(const BandwidthItem *, const BandwidthItem *); DISALLOW_EVIL_CONSTRUCTORS(LiveSession); Loading