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

Commit 641e0c71 authored by Robert Shih's avatar Robert Shih
Browse files

Miscellaneous RTSP improvements

1. Server side management based on buffer monitoring
2. Notify prepared after more buffering
3. Drop stale access units after seek

Bug: 27292698
Change-Id: Ic41686bb3514eb1d4c206bb155d45f34b6350810
parent c52198dc
Loading
Loading
Loading
Loading
+78 −24
Original line number Diff line number Diff line
@@ -32,6 +32,12 @@ namespace android {

const int64_t kNearEOSTimeoutUs = 2000000ll; // 2 secs

// Buffer Underflow/Prepare/StartServer/Overflow Marks
const int64_t NuPlayer::RTSPSource::kUnderflowMarkUs   =  1000000ll;
const int64_t NuPlayer::RTSPSource::kPrepareMarkUs     =  3000000ll;
const int64_t NuPlayer::RTSPSource::kStartServerMarkUs =  5000000ll;
const int64_t NuPlayer::RTSPSource::kOverflowMarkUs    = 10000000ll;

NuPlayer::RTSPSource::RTSPSource(
        const sp<AMessage> &notify,
        const sp<IMediaHTTPService> &httpService,
@@ -51,6 +57,7 @@ NuPlayer::RTSPSource::RTSPSource(
      mFinalResult(OK),
      mDisconnectReplyID(0),
      mBuffering(false),
      mInPreparationPhase(true),
      mSeekGeneration(0),
      mEOSTimeoutAudio(0),
      mEOSTimeoutVideo(0) {
@@ -127,29 +134,6 @@ void NuPlayer::RTSPSource::stop() {
    msg->postAndAwaitResponse(&dummy);
}

void NuPlayer::RTSPSource::pause() {
    int64_t mediaDurationUs = 0;
    getDuration(&mediaDurationUs);
    for (size_t index = 0; index < mTracks.size(); index++) {
        TrackInfo *info = &mTracks.editItemAt(index);
        sp<AnotherPacketSource> source = info->mSource;

        // Check if EOS or ERROR is received
        if (source != NULL && source->isFinished(mediaDurationUs)) {
            return;
        }
    }
    if (mHandler != NULL) {
        mHandler->pause();
    }
}

void NuPlayer::RTSPSource::resume() {
    if (mHandler != NULL) {
        mHandler->resume();
    }
}

status_t NuPlayer::RTSPSource::feedMoreTSData() {
    Mutex::Autolock _l(mBufferingLock);
    return mFinalResult;
@@ -324,6 +308,73 @@ void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) {
    mHandler->seek(seekTimeUs);
}

void NuPlayer::RTSPSource::schedulePollBuffering() {
    sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
    msg->post(1000000ll); // 1 second intervals
}

void NuPlayer::RTSPSource::checkBuffering(
        bool *prepared, bool *underflow, bool *overflow, bool *startServer) {
    size_t numTracks = mTracks.size();
    size_t preparedCount, underflowCount, overflowCount, startCount;
    preparedCount = underflowCount = overflowCount = startCount = 0;
    for (size_t i = 0; i < numTracks; ++i) {
        status_t finalResult;
        TrackInfo *info = &mTracks.editItemAt(i);
        sp<AnotherPacketSource> src = info->mSource;
        int64_t bufferedDurationUs = src->getBufferedDurationUs(&finalResult);

        // isFinished when duration is 0 checks for EOS result only
        if (bufferedDurationUs > kPrepareMarkUs || src->isFinished(/* duration */ 0)) {
            ++preparedCount;
        }

        if (src->isFinished(/* duration */ 0)) {
            ++overflowCount;
        } else {
            if (bufferedDurationUs < kUnderflowMarkUs) {
                ++underflowCount;
            }
            if (bufferedDurationUs > kOverflowMarkUs) {
                ++overflowCount;
            }
            if (bufferedDurationUs < kStartServerMarkUs) {
                ++startCount;
            }
        }
    }

    *prepared    = (preparedCount == numTracks);
    *underflow   = (underflowCount > 0);
    *overflow    = (overflowCount == numTracks);
    *startServer = (startCount > 0);
}

void NuPlayer::RTSPSource::onPollBuffering() {
    bool prepared, underflow, overflow, startServer;
    checkBuffering(&prepared, &underflow, &overflow, &startServer);

    if (prepared && mInPreparationPhase) {
        mInPreparationPhase = false;
        notifyPrepared();
    }

    if (!mInPreparationPhase && underflow) {
        startBufferingIfNecessary();
    }

    if (overflow && mHandler != NULL) {
        stopBufferingIfNecessary();
        mHandler->pause();
    }

    if (startServer && mHandler != NULL) {
        mHandler->resume();
    }

    schedulePollBuffering();
}

void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    if (msg->what() == kWhatDisconnect) {
        sp<AReplyToken> replyID;
@@ -348,6 +399,9 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {

        performSeek(seekTimeUs);
        return;
    } else if (msg->what() == kWhatPollBuffering) {
        onPollBuffering();
        return;
    }

    CHECK_EQ(msg->what(), (int)kWhatNotify);
@@ -372,7 +426,7 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
            }

            notifyFlagsChanged(flags);
            notifyPrepared();
            schedulePollBuffering();
            break;
        }

+11 −2
Original line number Diff line number Diff line
@@ -43,8 +43,6 @@ struct NuPlayer::RTSPSource : public NuPlayer::Source {
    virtual void prepareAsync();
    virtual void start();
    virtual void stop();
    virtual void pause();
    virtual void resume();

    virtual status_t feedMoreTSData();

@@ -65,6 +63,7 @@ private:
        kWhatNotify          = 'noti',
        kWhatDisconnect      = 'disc',
        kWhatPerformSeek     = 'seek',
        kWhatPollBuffering   = 'poll',
    };

    enum State {
@@ -79,6 +78,12 @@ private:
        kFlagIncognito = 1,
    };

    // Buffer Prepare/Underflow/Overflow/Resume Marks
    static const int64_t kPrepareMarkUs;
    static const int64_t kUnderflowMarkUs;
    static const int64_t kOverflowMarkUs;
    static const int64_t kStartServerMarkUs;

    struct TrackInfo {
        sp<AnotherPacketSource> mSource;

@@ -100,6 +105,7 @@ private:
    sp<AReplyToken> mDisconnectReplyID;
    Mutex mBufferingLock;
    bool mBuffering;
    bool mInPreparationPhase;

    sp<ALooper> mLooper;
    sp<MyHandler> mHandler;
@@ -126,6 +132,9 @@ private:
    void finishDisconnectIfPossible();

    void performSeek(int64_t seekTimeUs);
    void schedulePollBuffering();
    void checkBuffering(bool *prepared, bool *underflow, bool *overflow, bool *startServer);
    void onPollBuffering();

    bool haveSufficientDataOnAllTracks();

+12 −1
Original line number Diff line number Diff line
@@ -235,7 +235,7 @@ struct MyHandler : public AHandler {
        sp<AMessage> msg = new AMessage('paus', this);
        mPauseGeneration++;
        msg->setInt32("pausecheck", mPauseGeneration);
        msg->post(kPauseDelayUs);
        msg->post();
    }

    void resume() {
@@ -979,6 +979,11 @@ struct MyHandler : public AHandler {

            case 'accu':
            {
                if (mSeekPending) {
                    ALOGV("Stale access unit.");
                    break;
                }

                int32_t timeUpdate;
                if (msg->findInt32("time-update", &timeUpdate) && timeUpdate) {
                    size_t trackIndex;
@@ -1070,6 +1075,12 @@ struct MyHandler : public AHandler {
                    ALOGW("This is a live stream, ignoring pause request.");
                    break;
                }

                if (mPausing) {
                    ALOGV("This stream is already paused.");
                    break;
                }

                mCheckPending = true;
                ++mCheckGeneration;
                mPausing = true;