From 46d13e3606b87d71379287672b54b50d0d9aa5cc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Roger=20J=C3=B6nsson?= Date: Mon, 21 Jan 2013 17:15:45 +0100 Subject: [PATCH] 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 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 2 + .../nuplayer/NuPlayerSource.h | 2 + .../libmediaplayerservice/nuplayer/RTSPSource.cpp | 19 ++++ media/libmediaplayerservice/nuplayer/RTSPSource.h | 2 + media/libstagefright/rtsp/MyHandler.h | 126 ++++++++++++++++++++- 5 files changed, 147 insertions(+), 4 deletions(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index ee25cc6543..30eb4b9f1c 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -732,6 +732,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { case kWhatPause: { CHECK(mRenderer != NULL); + mSource->pause(); mRenderer->pause(); break; } @@ -739,6 +740,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { case kWhatResume: { CHECK(mRenderer != NULL); + mSource->resume(); mRenderer->resume(); break; } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h index df84123fa2..8622abee1e 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h @@ -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. diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp index b70d5503f0..a5ff0ca2b3 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp @@ -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 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; } diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h index 8451b9e075..8cf34a093b 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.h +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h @@ -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(); diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h index cfbf501986..4e5e2fa15f 100644 --- a/media/libstagefright/rtsp/MyHandler.h +++ b/media/libstagefright/rtsp/MyHandler.h @@ -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 msg = new AMessage('paus', id()); + msg->post(); + } + + void resume() { + sp msg = new AMessage('resu', id()); + msg->post(); + } + static void addRR(const sp &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 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 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 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 obj; + CHECK(msg->findObject("response", &obj)); + sp response = + static_cast(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 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 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 msg = mNotify->dup(); @@ -1327,6 +1444,7 @@ private: bool mSeekable; int64_t mKeepAliveTimeoutUs; int32_t mKeepAliveGeneration; + bool mPausing; Vector mTracks; -- 2.11.0