Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3bd0270c authored by Lajos Molnar's avatar Lajos Molnar Committed by Android Git Automerger
Browse files

am b74b2098: Merge "stagefright: Fix bugs in playlist fetcher logic" into klp-dev

* commit 'b74b2098':
  stagefright: Fix bugs in playlist fetcher logic
parents 47ef192f b74b2098
Loading
Loading
Loading
Loading
+100 −27
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ namespace android {

// static
const int64_t PlaylistFetcher::kMinBufferedDurationUs = 10000000ll;
const int64_t PlaylistFetcher::kMaxMonitorDelayUs = 3000000ll;

PlaylistFetcher::PlaylistFetcher(
        const sp<AMessage> &notify,
@@ -61,6 +62,7 @@ PlaylistFetcher::PlaylistFetcher(
      mSeqNumber(-1),
      mNumRetries(0),
      mStartup(true),
      mPrepared(false),
      mNextPTSTimeUs(-1ll),
      mMonitorQueueGeneration(0),
      mRefreshState(INITIAL_MINIMUM_RELOAD_DELAY),
@@ -103,10 +105,16 @@ int64_t PlaylistFetcher::getSegmentStartTimeUs(int32_t seqNumber) const {
    return segmentStartUs;
}

bool PlaylistFetcher::timeToRefreshPlaylist(int64_t nowUs) const {
    if (mPlaylist == NULL) {
int64_t PlaylistFetcher::delayUsToRefreshPlaylist() const {
    int64_t nowUs = ALooper::GetNowUs();

    if (mPlaylist == NULL || mLastPlaylistFetchTimeUs < 0ll) {
        CHECK_EQ((int)mRefreshState, (int)INITIAL_MINIMUM_RELOAD_DELAY);
        return true;
        return 0ll;
    }

    if (mPlaylist->isComplete()) {
        return (~0llu >> 1);
    }

    int32_t targetDurationSecs;
@@ -157,7 +165,8 @@ bool PlaylistFetcher::timeToRefreshPlaylist(int64_t nowUs) const {
            break;
    }

    return mLastPlaylistFetchTimeUs + minPlaylistAgeUs <= nowUs;
    int64_t delayUs = mLastPlaylistFetchTimeUs + minPlaylistAgeUs - nowUs;
    return delayUs > 0ll ? delayUs : 0ll;
}

status_t PlaylistFetcher::decryptBuffer(
@@ -274,7 +283,15 @@ status_t PlaylistFetcher::decryptBuffer(
    return OK;
}

void PlaylistFetcher::postMonitorQueue(int64_t delayUs) {
void PlaylistFetcher::postMonitorQueue(int64_t delayUs, int64_t minDelayUs) {
    int64_t maxDelayUs = delayUsToRefreshPlaylist();
    if (maxDelayUs < minDelayUs) {
        maxDelayUs = minDelayUs;
    }
    if (delayUs > maxDelayUs) {
        ALOGV("Need to refresh playlist in %lld", maxDelayUs);
        delayUs = maxDelayUs;
    }
    sp<AMessage> msg = new AMessage(kWhatMonitorQueue, id());
    msg->setInt32("generation", mMonitorQueueGeneration);
    msg->post(delayUs);
@@ -415,6 +432,7 @@ status_t PlaylistFetcher::onStart(const sp<AMessage> &msg) {
    if (mStartTimeUs >= 0ll) {
        mSeqNumber = -1;
        mStartup = true;
        mPrepared = false;
    }

    postMonitorQueue();
@@ -456,40 +474,62 @@ void PlaylistFetcher::queueDiscontinuity(

void PlaylistFetcher::onMonitorQueue() {
    bool downloadMore = false;
    refreshPlaylist();

    status_t finalResult;
    int32_t targetDurationSecs;
    int64_t targetDurationUs = kMinBufferedDurationUs;
    if (mPlaylist != NULL) {
        CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs));
        targetDurationUs = targetDurationSecs * 1000000ll;
    }

    // buffer at least 3 times the target duration, or up to 10 seconds
    int64_t durationToBufferUs = targetDurationUs * 3;
    if (durationToBufferUs > kMinBufferedDurationUs)  {
        durationToBufferUs = kMinBufferedDurationUs;
    }

    int64_t bufferedDurationUs = 0ll;
    status_t finalResult = NOT_ENOUGH_DATA;
    if (mStreamTypeMask == LiveSession::STREAMTYPE_SUBTITLES) {
        sp<AnotherPacketSource> packetSource =
            mPacketSources.valueFor(LiveSession::STREAMTYPE_SUBTITLES);

        int64_t bufferedDurationUs =
        bufferedDurationUs =
                packetSource->getBufferedDurationUs(&finalResult);

        downloadMore = (bufferedDurationUs < kMinBufferedDurationUs);
        finalResult = OK;
    } else {
        bool first = true;
        int64_t minBufferedDurationUs = 0ll;

        for (size_t i = 0; i < mPacketSources.size(); ++i) {
            if ((mStreamTypeMask & mPacketSources.keyAt(i)) == 0) {
                continue;
            }

            int64_t bufferedDurationUs =
            int64_t bufferedStreamDurationUs =
                mPacketSources.valueAt(i)->getBufferedDurationUs(&finalResult);

            if (first || bufferedDurationUs < minBufferedDurationUs) {
                minBufferedDurationUs = bufferedDurationUs;
            if (first || bufferedStreamDurationUs < bufferedDurationUs) {
                bufferedDurationUs = bufferedStreamDurationUs;
                first = false;
            }
        }
    }
    downloadMore = (bufferedDurationUs < durationToBufferUs);

    // signal start if buffered up at least the target size
    if (!mPrepared && bufferedDurationUs > targetDurationUs && downloadMore) {
        mPrepared = true;

        downloadMore =
            !first && (minBufferedDurationUs < kMinBufferedDurationUs);
        ALOGV("prepared, buffered=%lld > %lld",
                bufferedDurationUs, targetDurationUs);
        sp<AMessage> msg = mNotify->dup();
        msg->setInt32("what", kWhatTemporarilyDoneFetching);
        msg->post();
    }

    if (finalResult == OK && downloadMore) {
        ALOGV("monitoring, buffered=%lld < %lld",
                bufferedDurationUs, durationToBufferUs);
        onDownloadNext();
    } else {
        // Nothing to do yet, try again in a second.
@@ -498,15 +538,17 @@ void PlaylistFetcher::onMonitorQueue() {
        msg->setInt32("what", kWhatTemporarilyDoneFetching);
        msg->post();

        postMonitorQueue(1000000ll);
        int64_t delayUs = mPrepared ? kMaxMonitorDelayUs : targetDurationUs / 2;
        ALOGV("pausing for %lld, buffered=%lld > %lld",
                delayUs, bufferedDurationUs, durationToBufferUs);
        // :TRICKY: need to enforce minimum delay because the delay to
        // refresh the playlist will become 0
        postMonitorQueue(delayUs, mPrepared ? targetDurationUs * 2 : 0);
    }
}

void PlaylistFetcher::onDownloadNext() {
    int64_t nowUs = ALooper::GetNowUs();

    if (mLastPlaylistFetchTimeUs < 0ll
            || (!mPlaylist->isComplete() && timeToRefreshPlaylist(nowUs))) {
status_t PlaylistFetcher::refreshPlaylist() {
    if (delayUsToRefreshPlaylist() <= 0) {
        bool unchanged;
        sp<M3UParser> playlist = mSession->fetchPlaylist(
                mURI.c_str(), mPlaylistHash, &unchanged);
@@ -522,7 +564,7 @@ void PlaylistFetcher::onDownloadNext() {
            } else {
                ALOGE("failed to load playlist at url '%s'", mURI.c_str());
                notifyError(ERROR_IO);
                return;
                return ERROR_IO;
            }
        } else {
            mRefreshState = INITIAL_MINIMUM_RELOAD_DELAY;
@@ -535,6 +577,13 @@ void PlaylistFetcher::onDownloadNext() {

        mLastPlaylistFetchTimeUs = ALooper::GetNowUs();
    }
    return OK;
}

void PlaylistFetcher::onDownloadNext() {
    if (refreshPlaylist() != OK) {
        return;
    }

    int32_t firstSeqNumberInPlaylist;
    if (mPlaylist->meta() == NULL || !mPlaylist->meta()->findInt32(
@@ -553,12 +602,18 @@ void PlaylistFetcher::onDownloadNext() {

        if (mPlaylist->isComplete() || mPlaylist->isEvent()) {
            mSeqNumber = getSeqNumberForTime(mStartTimeUs);
            ALOGV("Initial sequence number for time %lld is %ld from (%ld .. %ld)",
                    mStartTimeUs, mSeqNumber, firstSeqNumberInPlaylist,
                    lastSeqNumberInPlaylist);
        } else {
            // If this is a live session, start 3 segments from the end.
            mSeqNumber = lastSeqNumberInPlaylist - 3;
            if (mSeqNumber < firstSeqNumberInPlaylist) {
                mSeqNumber = firstSeqNumberInPlaylist;
            }
            ALOGV("Initial sequence number for live event %ld from (%ld .. %ld)",
                    mSeqNumber, firstSeqNumberInPlaylist,
                    lastSeqNumberInPlaylist);
        }

        mStartTimeUs = -1ll;
@@ -570,16 +625,34 @@ void PlaylistFetcher::onDownloadNext() {
            ++mNumRetries;

            if (mSeqNumber > lastSeqNumberInPlaylist) {
                mLastPlaylistFetchTimeUs = -1;
                postMonitorQueue(3000000ll);
                // refresh in increasing fraction (1/2, 1/3, ...) of the
                // playlist's target duration or 3 seconds, whichever is less
                int32_t targetDurationSecs;
                CHECK(mPlaylist->meta()->findInt32(
                        "target-duration", &targetDurationSecs));
                int64_t delayUs = mPlaylist->size() * targetDurationSecs *
                        1000000ll / (1 + mNumRetries);
                if (delayUs > kMaxMonitorDelayUs) {
                    delayUs = kMaxMonitorDelayUs;
                }
                ALOGV("sequence number high: %ld from (%ld .. %ld), monitor in %lld (retry=%d)",
                        mSeqNumber, firstSeqNumberInPlaylist,
                        lastSeqNumberInPlaylist, delayUs, mNumRetries);
                postMonitorQueue(delayUs);
                return;
            }

            // we've missed the boat, let's start from the lowest sequence
            // number available and signal a discontinuity.

            ALOGI("We've missed the boat, restarting playback.");
            mSeqNumber = lastSeqNumberInPlaylist;
            ALOGI("We've missed the boat, restarting playback."
                  "  mStartup=%d, was  looking for %d in %d-%d",
                    mStartup, mSeqNumber, firstSeqNumberInPlaylist,
                    lastSeqNumberInPlaylist);
            mSeqNumber = lastSeqNumberInPlaylist - 3;
            if (mSeqNumber < firstSeqNumberInPlaylist) {
                mSeqNumber = firstSeqNumberInPlaylist;
            }
            explicitDiscontinuity = true;

            // fall through
+5 −2
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ private:
    };

    static const int64_t kMinBufferedDurationUs;
    static const int64_t kMaxMonitorDelayUs;

    sp<AMessage> mNotify;
    sp<LiveSession> mSession;
@@ -97,6 +98,7 @@ private:
    int32_t mSeqNumber;
    int32_t mNumRetries;
    bool mStartup;
    bool mPrepared;
    int64_t mNextPTSTimeUs;

    int32_t mMonitorQueueGeneration;
@@ -120,10 +122,11 @@ private:
    status_t decryptBuffer(
            size_t playlistIndex, const sp<ABuffer> &buffer);

    void postMonitorQueue(int64_t delayUs = 0);
    void postMonitorQueue(int64_t delayUs = 0, int64_t minDelayUs = 0);
    void cancelMonitorQueue();

    bool timeToRefreshPlaylist(int64_t nowUs) const;
    int64_t delayUsToRefreshPlaylist() const;
    status_t refreshPlaylist();

    // Returns the media time in us of the segment specified by seqNumber.
    // This is computed by summing the durations of all segments before it.