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

Commit fba60daf authored by Roger Jönsson's avatar Roger Jönsson Committed by Andreas Huber
Browse files

Enable pause/resume for RTSP streaming

When a stream is paused, RTSP Pause is also sent to the server.
Otherwise the buffering might continue until the memory runs out.
When the stream is resumed, RTSP Play will be sent in order to
resume the buffering.

Change-Id: I5dc1761140827c532451638c3fd3f34271e5b9ab
parent b50e83ec
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -732,6 +732,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
        case kWhatPause:
        {
            CHECK(mRenderer != NULL);
            mSource->pause();
            mRenderer->pause();
            break;
        }
@@ -739,6 +740,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
        case kWhatResume:
        {
            CHECK(mRenderer != NULL);
            mSource->resume();
            mRenderer->resume();
            break;
        }
+2 −0
Original line number Diff line number Diff line
@@ -54,6 +54,8 @@ struct NuPlayer::Source : public AHandler {

    virtual void start() = 0;
    virtual void stop() {}
    virtual void pause() {}
    virtual void resume() {}

    // Returns OK iff more data was available,
    // an error or ERROR_END_OF_STREAM if not.
+19 −0
Original line number Diff line number Diff line
@@ -119,6 +119,25 @@ 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;
        }
    }
    mHandler->pause();
}

void NuPlayer::RTSPSource::resume() {
    mHandler->resume();
}

status_t NuPlayer::RTSPSource::feedMoreTSData() {
    return mFinalResult;
}
+2 −0
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@ 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();

+122 −4
Original line number Diff line number Diff line
@@ -135,7 +135,8 @@ struct MyHandler : public AHandler {
          mReceivedFirstRTPPacket(false),
          mSeekable(true),
          mKeepAliveTimeoutUs(kDefaultKeepAliveTimeoutUs),
          mKeepAliveGeneration(0) {
          mKeepAliveGeneration(0),
          mPausing(false) {
        mNetLooper->setName("rtsp net");
        mNetLooper->start(false /* runOnCallingThread */,
                          false /* canCallJava */,
@@ -199,6 +200,16 @@ struct MyHandler : public AHandler {
        return mSeekable;
    }

    void pause() {
        sp<AMessage> msg = new AMessage('paus', id());
        msg->post();
    }

    void resume() {
        sp<AMessage> msg = new AMessage('resu', id());
        msg->post();
    }

    static void addRR(const sp<ABuffer> &buf) {
        uint8_t *ptr = buf->data() + buf->size();
        ptr[0] = 0x80 | 0;
@@ -824,6 +835,7 @@ struct MyHandler : public AHandler {
                mNumAccessUnitsReceived = 0;
                mReceivedFirstRTCPPacket = false;
                mReceivedFirstRTPPacket = false;
                mPausing = false;
                mSeekable = true;

                sp<AMessage> reply = new AMessage('tear', id());
@@ -973,6 +985,100 @@ struct MyHandler : public AHandler {
                break;
            }

            case 'paus':
            {
                if (!mSeekable) {
                    ALOGW("This is a live stream, ignoring pause request.");
                    break;
                }
                mCheckPending = true;
                ++mCheckGeneration;
                mPausing = true;

                AString request = "PAUSE ";
                request.append(mSessionURL);
                request.append(" RTSP/1.0\r\n");

                request.append("Session: ");
                request.append(mSessionID);
                request.append("\r\n");

                request.append("\r\n");

                sp<AMessage> reply = new AMessage('pau2', id());
                mConn->sendRequest(request.c_str(), reply);
                break;
            }

            case 'pau2':
            {
                int32_t result;
                CHECK(msg->findInt32("result", &result));

                ALOGI("PAUSE completed with result %d (%s)",
                     result, strerror(-result));
                break;
            }

            case 'resu':
            {
                if (mPausing && mSeekPending) {
                    // If seeking, Play will be sent from see1 instead
                    break;
                }

                if (!mPausing) {
                    // Dont send PLAY if we have not paused
                    break;
                }
                AString request = "PLAY ";
                request.append(mSessionURL);
                request.append(" RTSP/1.0\r\n");

                request.append("Session: ");
                request.append(mSessionID);
                request.append("\r\n");

                request.append("\r\n");

                sp<AMessage> reply = new AMessage('res2', id());
                mConn->sendRequest(request.c_str(), reply);
                break;
            }

            case 'res2':
            {
                int32_t result;
                CHECK(msg->findInt32("result", &result));

                ALOGI("PLAY completed with result %d (%s)",
                     result, strerror(-result));

                mCheckPending = false;
                postAccessUnitTimeoutCheck();

                if (result == OK) {
                    sp<RefBase> obj;
                    CHECK(msg->findObject("response", &obj));
                    sp<ARTSPResponse> response =
                        static_cast<ARTSPResponse *>(obj.get());

                    if (response->mStatusCode != 200) {
                        result = UNKNOWN_ERROR;
                    } else {
                        parsePlayResponse(response);
                    }
                }

                if (result != OK) {
                    ALOGE("resume failed, aborting.");
                    (new AMessage('abor', id()))->post();
                }

                mPausing = false;
                break;
            }

            case 'seek':
            {
                if (!mSeekable) {
@@ -994,6 +1100,15 @@ struct MyHandler : public AHandler {
                mCheckPending = true;
                ++mCheckGeneration;

                sp<AMessage> reply = new AMessage('see1', id());
                reply->setInt64("time", timeUs);

                if (mPausing) {
                    // PAUSE already sent
                    ALOGI("Pause already sent");
                    reply->post();
                    break;
                }
                AString request = "PAUSE ";
                request.append(mSessionURL);
                request.append(" RTSP/1.0\r\n");
@@ -1004,8 +1119,6 @@ struct MyHandler : public AHandler {

                request.append("\r\n");

                sp<AMessage> reply = new AMessage('see1', id());
                reply->setInt64("time", timeUs);
                mConn->sendRequest(request.c_str(), reply);
                break;
            }
@@ -1049,7 +1162,10 @@ struct MyHandler : public AHandler {

            case 'see2':
            {
                CHECK(mSeekPending);
                if (mTracks.size() == 0) {
                    // We have already hit abor, break
                    break;
                }

                int32_t result;
                CHECK(msg->findInt32("result", &result));
@@ -1085,6 +1201,7 @@ struct MyHandler : public AHandler {
                    (new AMessage('abor', id()))->post();
                }

                mPausing = false;
                mSeekPending = false;

                sp<AMessage> msg = mNotify->dup();
@@ -1327,6 +1444,7 @@ private:
    bool mSeekable;
    int64_t mKeepAliveTimeoutUs;
    int32_t mKeepAliveGeneration;
    bool mPausing;

    Vector<TrackInfo> mTracks;