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

Commit 06f0b858 authored by Manikanta Kanamarlapudi's avatar Manikanta Kanamarlapudi Committed by Steve Kondik
Browse files

HLSCustom: Bandwidth switching improvement in HLS

Bandwidth switching improvement in httplivecustom
stack

Change-Id: I4fa60f05a5e2ad194b381455389dd8b771cb5fd8
parent 1ea977c1
Loading
Loading
Loading
Loading
+55 −10
Original line number Diff line number Diff line
@@ -36,19 +36,21 @@ HTTPBase::HTTPBase()
      mTotalTransferBytes(0),
      mPrevBandwidthMeasureTimeUs(0),
      mPrevEstimatedBandWidthKbps(0),
      mBandWidthCollectFreqMs(5000) {
      mBandWidthCollectFreqMs(5000),
      mCustomBwEstimate(0) {
}

void HTTPBase::addBandwidthMeasurement(
        size_t numBytes, int64_t delayUs) {
    Mutex::Autolock autoLock(mLock);

    ALOGV("addBandwidthMeasurement");
    BandwidthEntry entry;
    entry.mDelayUs = delayUs;
    entry.mNumBytes = numBytes;
    mTotalTransferTimeUs += delayUs;
    mTotalTransferBytes += numBytes;

    if (!mCustomBwEstimate) {
        mBandwidthHistory.push_back(entry);
        if (++mNumBandwidthHistoryItems > 100) {
            BandwidthEntry *entry = &*mBandwidthHistory.begin();
@@ -68,6 +70,32 @@ void HTTPBase::addBandwidthMeasurement(
                mPrevBandwidthMeasureTimeUs = timeNowUs;
            }
        }
    } else {
        mNumBandwidthHistoryItems++;

        mBandwidthHistory.push_back(entry);

        if (mBandwidthHistory.size() > 8) {
            while (mTotalTransferTimeUs > 5000000 && mBandwidthHistory.size() > 8) {
                ALOGV("erase bandwidth item");
                BandwidthEntry *entry = &*mBandwidthHistory.begin();
                mTotalTransferTimeUs -= entry->mDelayUs;
                mTotalTransferBytes -= entry->mNumBytes;
                mBandwidthHistory.erase(mBandwidthHistory.begin());
                --mNumBandwidthHistoryItems;
            }
        }
        int64_t timeNowUs = ALooper::GetNowUs();
        if (timeNowUs - mPrevBandwidthMeasureTimeUs >=
                mBandWidthCollectFreqMs * 1000LL) {

            if (mPrevBandwidthMeasureTimeUs != 0) {
                mPrevEstimatedBandWidthKbps =
                    (mTotalTransferBytes * 8E3 / mTotalTransferTimeUs);
            }
            mPrevBandwidthMeasureTimeUs = timeNowUs;
        }
    }

}

@@ -75,9 +103,22 @@ bool HTTPBase::estimateBandwidth(int32_t *bandwidth_bps) {
    Mutex::Autolock autoLock(mLock);

    if (mNumBandwidthHistoryItems < 2) {
        ALOGV("only 2 items");
        return false;
    }

    if (mCustomBwEstimate) {
        if (mTotalTransferTimeUs > 5000000) {
            ALOGV("keep the latest 3 items when the total time is greater than 5s");
            while (mNumBandwidthHistoryItems >3) {
                List<BandwidthEntry>::iterator it = mBandwidthHistory.begin();
                mTotalTransferTimeUs -= it->mDelayUs;
                mTotalTransferBytes -= it->mNumBytes;
                it = mBandwidthHistory.erase(it);
                mNumBandwidthHistoryItems--;
            }
        }
    }
    *bandwidth_bps = ((double)mTotalTransferBytes * 8E6 / mTotalTransferTimeUs);

    return true;
@@ -104,6 +145,10 @@ status_t HTTPBase::setBandwidthStatCollectFreq(int32_t freqMs) {
    return OK;
}

void HTTPBase::setCustomBwEstimate(bool flag) {
   mCustomBwEstimate = flag;
}

// static
void HTTPBase::RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag) {
    int res = qtaguid_tagSocket(sockfd, kTag, uid);
+154 −12
Original line number Diff line number Diff line
@@ -69,7 +69,12 @@ LiveSessionCustom::LiveSessionCustom(
      mSwitchInProgress(false),
      mDisconnectReplyID(0),
      mSeekReplyID(0),
      mSeekPosition(-1ll) {
      mSeekPosition(-1ll),
      mPerformCheckBw(0),
      mMode(SWITCHING_NONE),
      mIsFirstDownloading(true),
      mIsSwitchingToReal(true),
      mEraseFirstTs(false) {

    mStreams[kAudioIndex] = StreamItem("audio");
    mStreams[kVideoIndex] = StreamItem("video");
@@ -79,9 +84,16 @@ LiveSessionCustom::LiveSessionCustom(
        mPacketSources.add(indexToType(i), new AnotherPacketSource(NULL /* meta */));
        mPacketSources2.add(indexToType(i), new AnotherPacketSource(NULL /* meta */));
    }

    mHTTPDataSource->setCustomBwEstimate(true);
    mLooper = new ALooper;
    mLooper->setName("PlaylistFetcher");
    mLooper->start();
}

LiveSessionCustom::~LiveSessionCustom() {
    mLooper->stop();
    mLooper.clear();
}

sp<ABuffer> LiveSessionCustom::createFormatChangeBuffer(bool swap) {
@@ -226,6 +238,18 @@ status_t LiveSessionCustom::disconnect() {
    return err;
}

bool LiveSessionCustom::switchFirstBandwidth() {
    ssize_t curband = getBandwidthIndex();
    if (mPrevBandwidthIndex != curband){
        changeConfiguration(-1ll /* timeUs */, curband, false /*pick track*/);
        ALOGV("switchFirstBandwidth  we need change bandwidth to index %d on the first time",curband);
        mEraseFirstTs = true;
        return true;
    }
    mIsSwitchingToReal = false;
    return false;
}

status_t LiveSessionCustom::seekTo(int64_t timeUs) {
    sp<AMessage> msg = new AMessage(kWhatSeek, id());
    msg->setInt64("timeUs", timeUs);
@@ -603,11 +627,11 @@ sp<PlaylistFetcher> LiveSessionCustom::addFetcher(const char *uri) {
    notify->setInt32("switchGeneration", mSwitchGeneration);

    FetcherInfo info;
    info.mFetcher = new PlaylistFetcher(notify, this, uri);
    info.mFetcher = new PlaylistFetcher(notify, this, uri, mIsFirstDownloading, mPrevBandwidthIndex);
    info.mDurationUs = -1ll;
    info.mIsPrepared = false;
    info.mToBeRemoved = false;
    looper()->registerHandler(info.mFetcher);
    mLooper->registerHandler(info.mFetcher);

    mFetcherInfos.add(uri, info);

@@ -635,13 +659,17 @@ ssize_t LiveSessionCustom::fetchFile(
        int64_t range_offset, int64_t range_length,
        uint32_t block_size, /* download block size */
        sp<DataSource> *source, /* to return and reuse source */
        String8 *actualUrl) {
        String8 *actualUrl,
        bool *eos) {
    off64_t size;
    sp<DataSource> temp_source;
    if (source == NULL) {
        source = &temp_source;
    }

    if (eos != NULL)
        *eos = false;

    if (*source == NULL) {
        if (!strncasecmp(url, "file://", 7)) {
            *source = new FileSource(url + 7);
@@ -661,7 +689,9 @@ ssize_t LiveSessionCustom::fetchFile(
                                    ? "" : StringPrintf("%lld",
                                            range_offset + range_length - 1).c_str()).c_str()));
            }
            ALOGV("HTTPDataSource connect");
            status_t err = mHTTPDataSource->connect(url, &headers);
            ALOGV("HTTPDataSource connect end");

            if (err != OK) {
                return err;
@@ -714,6 +744,12 @@ ssize_t LiveSessionCustom::fetchFile(
            }
        }

        if (maxBytesToRead == 0) {
            ALOGV("maxBytesToRead = 0");
            if (eos != NULL)
                *eos = true;
            break;
        }
        // The DataSource is responsible for informing us of error (n < 0) or eof (n == 0)
        // to help us break out of the loop.
        ssize_t n = (*source)->readAt(
@@ -725,6 +761,10 @@ ssize_t LiveSessionCustom::fetchFile(
        }

        if (n == 0) {
            if (eos != NULL) {
                ALOGV("HTTP read n = 0");
                *eos = true;
            }
            break;
        }

@@ -743,6 +783,14 @@ ssize_t LiveSessionCustom::fetchFile(
    return bytesRead;
}

void LiveSessionCustom::disconnectUrl() {
    ALOGV("LiveSessionCustom::disconnectUrl");
    if (mHTTPDataSource != NULL) {
        mHTTPDataSource->disconnect();
        ALOGV("LiveSessionCustom::disconnectUrl end");
    }
}

sp<M3UParser> LiveSessionCustom::fetchPlaylist(
        const char *url, uint8_t *curPlaylistHash, bool *unchanged) {
    ALOGV("fetchPlaylist '%s'", url);
@@ -839,8 +887,12 @@ size_t LiveSessionCustom::getBandwidthIndex() {
            }
        }

        int32_t realBps = bandwidthBps;
        // Consider only 80% of the available bandwidth usable.
        if (mIsFirstDownloading || mIsSwitchingToReal)
            bandwidthBps = (bandwidthBps * 8) / 10;
        else
            bandwidthBps = (bandwidthBps * 9) / 10;

        // Pick the highest bandwidth stream below or equal to estimated bandwidth.

@@ -849,6 +901,32 @@ size_t LiveSessionCustom::getBandwidthIndex() {
                                > (size_t)bandwidthBps) {
            --index;
        }

        if (mIsFirstDownloading) {
            mIsFirstDownloading = false;
            ALOGV("First downloading: return index: %d", index);
            return index;
        }

        if (mIsSwitchingToReal) {
            mIsSwitchingToReal = false;
            ALOGV("Switch to real bw: return index: %d", index);
            return index;
        }

        // In up switch case, only when the real estimated bandwidth is 30%
        // above the target duration, the index can be changed
        if ((mPrevBandwidthIndex >= 0) && mPrevBandwidthIndex < index) {
            if(!(realBps > mBandwidthItems.itemAt(index).mBandwidth*13/10)) {
                // real bps is not above 30% of the target bandwidth
                if(index > (mPrevBandwidthIndex + 1))
                    //eg: index:4, mPreBandwidthIndex:2, we should choose 3
                    index--;
                else
                    //eg: index:3  mPreBandwidthIndex:2, we should choose 2
                    index = mPrevBandwidthIndex;
            }
        }
    }
#elif 0
    // Change bandwidth at random()
@@ -973,7 +1051,8 @@ bool LiveSessionCustom::canSwitchUp() {
    for (size_t i = 0; i < mPacketSources.size(); ++i) {
        sp<AnotherPacketSource> source = mPacketSources.valueAt(i);
        int64_t dur = source->getBufferedDurationUs(&err);
        if (err == OK && dur > 10000000) {
        int64_t highWaterMark = mPrevBandwidthIndex < 3 ? 10000000ll : 15000000ll; // 10s for 0,1,2 index;  15s for the other ones.
        if (err == OK && dur > highWaterMark) {
            return true;
        }
    }
@@ -989,6 +1068,7 @@ void LiveSessionCustom::changeConfiguration(
    CHECK(!mReconfigurationInProgress);
    mReconfigurationInProgress = true;

    bool changeToLower = (bandwidthIndex < mPrevBandwidthIndex);
    mPrevBandwidthIndex = bandwidthIndex;

    ALOGV("changeConfiguration => timeUs:%lld us, bwIndex:%d, pickTrack:%d",
@@ -1035,7 +1115,7 @@ void LiveSessionCustom::changeConfiguration(
        if (discardFetcher) {
            mFetcherInfos.valueAt(i).mFetcher->stopAsync();
        } else {
            mFetcherInfos.valueAt(i).mFetcher->pauseAsync();
            mFetcherInfos.valueAt(i).mFetcher->pauseAsync(changeToLower);
        }
    }

@@ -1049,6 +1129,7 @@ void LiveSessionCustom::changeConfiguration(
    msg->setInt32("streamMask", streamMask);
    msg->setInt32("resumeMask", resumeMask);
    msg->setInt64("timeUs", timeUs);
    msg->setInt32("changeToLower", changeToLower);
    for (size_t i = 0; i < kMaxStreams; ++i) {
        if (streamMask & indexToType(i)) {
            msg->setString(mStreams[i].uriKey().c_str(), URIs[i].c_str());
@@ -1172,6 +1253,9 @@ void LiveSessionCustom::onChangeConfiguration3(const sp<AMessage> &msg) {

    mNewStreamMask = streamMask;

    int32_t changeToLower = 0;
    msg->findInt32("changeToLower", &changeToLower);

    // Of all existing fetchers:
    // * Resume fetchers that are still needed and assign them original packet sources.
    // * Mark otherwise unneeded fetchers for removal.
@@ -1253,16 +1337,33 @@ void LiveSessionCustom::onChangeConfiguration3(const sp<AMessage> &msg) {
                streamMask &= ~indexToType(j);
            }
        }

        int32_t seqNumber = -1;
        if (!mEraseFirstTs) {
            if (latestSeq >= 0)
                seqNumber = changeToLower == 1 ? latestSeq : (latestSeq + 1);
        } else {
            ALOGV("the first TS has been erased, restart the playlistfetcher");
            if (seqNumber == 0)  /* for VOD the playback should start from index 0 */
                seqNumber = -1;
            latestTimeUs = 1ll;
            mEraseFirstTs = false;
        }
        fetcher->startAsync(
                sources[kAudioIndex],
                sources[kVideoIndex],
                sources[kSubtitleIndex],
                timeUs,
                latestTimeUs /* min start time(us) */,
                latestSeq >= 0 ? latestSeq + 1 : -1 /* starting sequence number hint */ );
                seqNumber/* starting sequence number hint */ );
    }

    if (changeToLower == 1) {
        for (size_t i = 0; i < mFetcherInfos.size(); i++) {
            const FetcherInfo info = mFetcherInfos.valueAt(i);
            if (info.mToBeRemoved)
                info.mFetcher->onQueueEndAu();
        }
    }
    // All fetchers have now been started, the configuration change
    // has completed.

@@ -1336,7 +1437,7 @@ void LiveSessionCustom::tryToFinishBandwidthSwitch() {
void LiveSessionCustom::scheduleCheckBandwidthEvent() {
    sp<AMessage> msg = new AMessage(kWhatCheckBandwidth, id());
    msg->setInt32("generation", mCheckBandwidthGeneration);
    msg->post(10000000ll);
    msg->post((mPerformCheckBw == 1 && mMode == SWITCHING_LOW)? 3000000ll:7000000ll);
}

void LiveSessionCustom::cancelCheckBandwidthEvent() {
@@ -1360,12 +1461,53 @@ bool LiveSessionCustom::canSwitchBandwidthTo(size_t bandwidthIndex) {
    }

    if (bandwidthIndex == (size_t)mPrevBandwidthIndex) {
        ALOGV("canSwitch--the same bandwidth");
        mPerformCheckBw = 0;
        mMode = SWITCHING_NONE;
        return false;
    } else if (bandwidthIndex > (size_t)mPrevBandwidthIndex) {
        return canSwitchUp();
        ALOGV("canSwitch--high than the previous bw");
        if (canSwitchUp()) {
            if (mPerformCheckBw == 0) {
                mMode = SWITCHING_HIGH;
                mPerformCheckBw = 1;
                ALOGV("canSwitch--check the high mode in the first time");
                return false;
            } else {
                bool ret = (mMode == SWITCHING_HIGH);
                mMode = SWITCHING_NONE;
                mPerformCheckBw = 0;
                if (ret)
                    ALOGV("canSwitch--check the high mode in the second time, switch it");
                else
                    ALOGV("canSwitch--check the other mode in the second time(high), do't switch it");
                return ret;
            }
        } else {
            return false;
        }
    } else {
        if (bandwidthIndex < 1) {
            mMode = SWITCHING_NONE;
            mPerformCheckBw = 0;
            return true;
        }
        if (mPerformCheckBw == 0) {
            mMode = SWITCHING_LOW;
            mPerformCheckBw = 1;
            ALOGV("canSwitch--check the low mode in the first time");
            return false;
        } else {
            bool ret = (mMode == SWITCHING_LOW);
            mMode = SWITCHING_NONE;
            mPerformCheckBw = 0;
            if (ret)
                ALOGV("canSwitch--check the low mode in the second time, switch it");
            else
                ALOGV("canSwitch--check the other mode in the second time(low), do't switch it");
            return ret;
        }
    }
}

void LiveSessionCustom::onCheckBandwidth() {
+24 −1
Original line number Diff line number Diff line
@@ -111,6 +111,12 @@ private:
        kWhatSwapped                    = 'swap',
    };

    enum BandwidthSwitchingMode{
        SWITCHING_NONE            = 0,
        SWITCHING_HIGH            = 1,
        SWITCHING_LOW             = 2,
    };

    struct BandwidthItem {
        size_t mPlaylistIndex;
        unsigned long mBandwidth;
@@ -190,6 +196,18 @@ private:

    int64_t mSeekPosition; //cache the new seek position during changing configuration

    sp<ALooper> mLooper;

    int32_t mPerformCheckBw;

    BandwidthSwitchingMode mMode;

    bool mIsFirstDownloading;

    bool mIsSwitchingToReal;

    volatile bool mEraseFirstTs;

    sp<PlaylistFetcher> addFetcher(const char *uri);

    void onConnect(const sp<AMessage> &msg);
@@ -215,11 +233,16 @@ private:
            uint32_t block_size = 0,
            /* reuse DataSource if doing partial fetch */
            sp<DataSource> *source = NULL,
            String8 *actualUrl = NULL);
            String8 *actualUrl = NULL,
            bool *eos = NULL);

    sp<M3UParser> fetchPlaylist(
            const char *url, uint8_t *curPlaylistHash, bool *unchanged);

    void disconnectUrl();

    bool switchFirstBandwidth();

    size_t getBandwidthIndex();

    static int SortByBandwidth(const BandwidthItem *, const BandwidthItem *);
+87 −17
Original line number Diff line number Diff line
@@ -48,13 +48,15 @@ namespace android {
// static
const int64_t PlaylistFetcher::kMinBufferedDurationUs = 10000000ll;
const int64_t PlaylistFetcher::kMaxMonitorDelayUs = 3000000ll;
const int32_t PlaylistFetcher::kDownloadBlockSize = 192;
const int32_t PlaylistFetcher::kDownloadBlockSize = 32768;
const int32_t PlaylistFetcher::kNumSkipFrames = 10;

PlaylistFetcher::PlaylistFetcher(
        const sp<AMessage> &notify,
        const sp<LiveSessionCustom> &session,
        const char *uri)
        const char *uri,
        const bool first,
        const int32_t index)
    : mNotify(notify),
      mStartTimeUsNotify(notify->dup()),
      mSession(session),
@@ -72,7 +74,12 @@ PlaylistFetcher::PlaylistFetcher(
      mMonitorQueueGeneration(0),
      mRefreshState(INITIAL_MINIMUM_RELOAD_DELAY),
      mFirstPTSValid(false),
      mAbsoluteTimeAnchorUs(0ll) {
      mAbsoluteTimeAnchorUs(0ll),
      mStopFetching(false),
      mTargetDurationUs(10000000ll),
      mNumRetryKey(0),
      mBandwidthIndex(index),
      mIsFirstDownloading(first) {
    memset(mPlaylistHash, 0, sizeof(mPlaylistHash));
    mStartTimeUsNotify->setInt32("what", kWhatStartedAt);
    mStartTimeUsNotify->setInt32("streamMask", 0);
@@ -361,7 +368,8 @@ void PlaylistFetcher::startAsync(
    msg->post();
}

void PlaylistFetcher::pauseAsync() {
void PlaylistFetcher::pauseAsync(bool changeToLower) {
    mStopFetching = changeToLower;
    (new AMessage(kWhatPause, id()))->post();
}

@@ -377,6 +385,13 @@ void PlaylistFetcher::resumeUntilAsync(const sp<AMessage> &params) {
    msg->post();
}

void PlaylistFetcher::onQueueEndAu() {
    ALOGV("onQueueEndAu");
    for (size_t i = 0; i < mPacketSources.size(); i++) {
        mPacketSources.valueAt(i)->queueAccessUnit(mSession->createFormatChangeBuffer(true));
    }
}

void PlaylistFetcher::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatStart:
@@ -523,6 +538,11 @@ void PlaylistFetcher::onStop(const sp<AMessage> &msg) {
// the remaining time is too short (within a resume threshold) stop immediately
// instead.
status_t PlaylistFetcher::onResumeUntil(const sp<AMessage> &msg) {
    if (mStopFetching) {
        ALOGV("onResumeUntil met stopping fetching");
        stopAsync(true);
        return OK;
    }
    sp<AMessage> params;
    CHECK(msg->findMessage("params", &params));

@@ -601,11 +621,7 @@ void PlaylistFetcher::onMonitorQueue() {
        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 durationToBufferUs = mTargetDurationUs;

    int64_t bufferedDurationUs = 0ll;
    status_t finalResult = NOT_ENOUGH_DATA;
@@ -657,13 +673,16 @@ void PlaylistFetcher::onMonitorQueue() {
        msg->setInt32("generation", mMonitorQueueGeneration);
        msg->post(1000l);
    } else {
        if (mTargetDurationUs == 10000000ll)
            mTargetDurationUs = mBandwidthIndex < 3 ? 25000000ll : 30000000ll;
        // Nothing to do yet, try again in a second.

        sp<AMessage> msg = mNotify->dup();
        msg->setInt32("what", kWhatTemporarilyDoneFetching);
        msg->post();

        int64_t delayUs = mPrepared ? kMaxMonitorDelayUs : targetDurationUs / 2;
        //int64_t delayUs = mPrepared ? kMaxMonitorDelayUs : targetDurationUs / 2;
        int64_t delayUs = 2500000ll;
        ALOGV("pausing for %lld, buffered=%lld > %lld",
                delayUs, bufferedDurationUs, durationToBufferUs);
        // :TRICKY: need to enforce minimum delay because the delay to
@@ -730,6 +749,7 @@ void PlaylistFetcher::onDownloadNext() {
    if (mStartup && mSeqNumber >= 0
            && (mSeqNumber < firstSeqNumberInPlaylist || mSeqNumber > lastSeqNumberInPlaylist)) {
        // in case we guessed wrong during reconfiguration, try fetching the latest content.
        if (mPlaylist->isComplete())
            mSeqNumber = lastSeqNumberInPlaylist;
    }

@@ -743,7 +763,7 @@ void PlaylistFetcher::onDownloadNext() {
                    lastSeqNumberInPlaylist);
        } else {
            // If this is a live session, start 3 segments from the end.
            mSeqNumber = lastSeqNumberInPlaylist - 3;
            mSeqNumber = getSeqNumberInLiveStreaming(lastSeqNumberInPlaylist, firstSeqNumberInPlaylist);
            if (mSeqNumber < firstSeqNumberInPlaylist) {
                mSeqNumber = firstSeqNumberInPlaylist;
            }
@@ -839,16 +859,32 @@ void PlaylistFetcher::onDownloadNext() {
        status_t err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, junk,
                true /* first */);
        if (err != OK) {
            if (mNumRetryKey == 3) {
                ALOGE("fail to retry key for 3 times");
                notifyError(err);
            } else {
                mNumRetryKey++;
                ALOGV("retry key for %d times", mNumRetryKey);
                postMonitorQueue(1000000ll);
            }
            return;
        }
    }

    mNumRetryKey = 0;
    bool eos = false;
    // block-wise download
    ssize_t bytesRead;
    do {
        if (mStopFetching) {
            ALOGE("stop to fetch file");
            cancelMonitorQueue();
            mSession->disconnectUrl();
            return;
        }
        bytesRead = mSession->fetchFile(
                uri.c_str(), &buffer, range_offset, range_length, kDownloadBlockSize, &source);
                uri.c_str(), &buffer, range_offset, range_length, kDownloadBlockSize, &source, NULL, &eos);
        if (eos)
            ALOGV("fetch EOS in the latest fetching file");

        if (bytesRead < 0) {
            status_t err = bytesRead;
@@ -930,7 +966,9 @@ void PlaylistFetcher::onDownloadNext() {
        }

        mStartup = false;
    } while (bytesRead != 0);
    } while (bytesRead != 0 && !eos);

    mSession->disconnectUrl();

    if (bufferStartsWithTsSyncByte(buffer)) {
        // If we still don't see a stream after fetching a full ts segment mark it as
@@ -989,6 +1027,16 @@ void PlaylistFetcher::onDownloadNext() {
        return;
    }

    if (mIsFirstDownloading) {
        mIsFirstDownloading = false;
        if (mSession->switchFirstBandwidth()) {
            for (size_t i = 0; i< mPacketSources.size(); i++) {
                mPacketSources.valueAt(i)->eraseBuffer();
            }
            ALOGV("choose the real bandwidth index");
            return;
        }
    }
    ++mSeqNumber;

    postMonitorQueue();
@@ -1105,6 +1153,7 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &bu
                if (timeUs < mMinStartTimeUs) {
                    // TODO untested path
                    // try a later ts
                    /*
                    int32_t targetDuration;
                    mPlaylist->meta()->findInt32("target-duration", &targetDuration);
                    int32_t incr = (mMinStartTimeUs - timeUs) / 1000000 / targetDuration;
@@ -1114,7 +1163,8 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &bu
                    }
                    mSeqNumber += incr;
                    err = -EAGAIN;
                    break;
                    break;*/
                    continue;
                } else {
                    int64_t startTimeUs;
                    if (mStartTimeUsNotify != NULL
@@ -1401,4 +1451,24 @@ int64_t PlaylistFetcher::resumeThreshold(const sp<AMessage> &msg) {
    return 500000ll;
}

int32_t PlaylistFetcher::getSeqNumberInLiveStreaming(int32_t lastseqnum, int32_t firstseqnum) {
    int32_t targetDurationSecs;
    int64_t durationUsSecs;
    sp<AMessage> itemMeta;
    int32_t mIndex=0;
    int32_t totalDuration = 0;
    CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs));

    for(int32_t i = lastseqnum - firstseqnum; i >0; i--){
        CHECK(mPlaylist->itemAt(i,NULL,&itemMeta));
        CHECK(itemMeta->findInt64("durationUs",&durationUsSecs));
        durationUsSecs = durationUsSecs/1000000ll;
        totalDuration  += durationUsSecs;
        mIndex++;
        if(totalDuration>3*targetDurationSecs){
            break;
        }
    }
    return lastseqnum-mIndex+1;
}
}  // namespace android
+20 −2
Original line number Diff line number Diff line
@@ -49,7 +49,9 @@ struct PlaylistFetcher : public AHandler {
    PlaylistFetcher(
            const sp<AMessage> &notify,
            const sp<LiveSessionCustom> &session,
            const char *uri);
            const char *uri,
            const bool first,
            const int32_t index);

    sp<DataSource> getDataSource();

@@ -61,12 +63,14 @@ struct PlaylistFetcher : public AHandler {
            int64_t minStartTimeUs = 0ll /* start after this timestamp */,
            int32_t startSeqNumberHint = -1 /* try starting at this sequence number */);

    void pauseAsync();
    void pauseAsync(bool changeToLower);

    void stopAsync(bool selfTriggered = false);

    void resumeUntilAsync(const sp<AMessage> &params);

    void onQueueEndAu();

protected:
    virtual ~PlaylistFetcher();
    virtual void onMessageReceived(const sp<AMessage> &msg);
@@ -140,6 +144,18 @@ private:
    // the last block of cipher text (cipher-block chaining).
    unsigned char mAESInitVec[16];

    // this flag is written and read in the different threads, use volatile for
    // this variable member
    volatile bool mStopFetching;

    int64_t mTargetDurationUs;

    int32_t mNumRetryKey;

    int32_t mBandwidthIndex;

    bool mIsFirstDownloading;

    // Set first to true if decrypting the first segment of a playlist segment. When
    // first is true, reset the initialization vector based on the available
    // information in the manifest; otherwise, use the initialization vector as
@@ -190,6 +206,8 @@ private:
    // returned by resumeThreshold.
    int64_t resumeThreshold(const sp<AMessage> &msg);

    int32_t getSeqNumberInLiveStreaming(int32_t lastseqnum, int32_t firstseqnum);

    DISALLOW_EVIL_CONSTRUCTORS(PlaylistFetcher);
};

Loading