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
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index ee25cc6..30eb4b9 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -732,6 +732,7 @@
case kWhatPause:
{
CHECK(mRenderer != NULL);
+ mSource->pause();
mRenderer->pause();
break;
}
@@ -739,6 +740,7 @@
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 df84123..8622abe 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -54,6 +54,8 @@
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 b70d550..a5ff0ca 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -119,6 +119,25 @@
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;
}
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index 8451b9e..8cf34a0 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -43,6 +43,8 @@
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 cfbf501..4e5e2fa 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -135,7 +135,8 @@
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 @@
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 @@
mNumAccessUnitsReceived = 0;
mReceivedFirstRTCPPacket = false;
mReceivedFirstRTPPacket = false;
+ mPausing = false;
mSeekable = true;
sp<AMessage> reply = new AMessage('tear', id());
@@ -973,6 +985,100 @@
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 @@
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 @@
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 @@
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 @@
(new AMessage('abor', id()))->post();
}
+ mPausing = false;
mSeekPending = false;
sp<AMessage> msg = mNotify->dup();
@@ -1327,6 +1444,7 @@
bool mSeekable;
int64_t mKeepAliveTimeoutUs;
int32_t mKeepAliveGeneration;
+ bool mPausing;
Vector<TrackInfo> mTracks;