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
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index ec33478..ba40876 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -32,6 +32,12 @@
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> ¬ify,
const sp<IMediaHTTPService> &httpService,
@@ -51,6 +57,7 @@
mFinalResult(OK),
mDisconnectReplyID(0),
mBuffering(false),
+ mInPreparationPhase(true),
mSeekGeneration(0),
mEOSTimeoutAudio(0),
mEOSTimeoutVideo(0) {
@@ -127,29 +134,6 @@
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 @@
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 @@
performSeek(seekTimeUs);
return;
+ } else if (msg->what() == kWhatPollBuffering) {
+ onPollBuffering();
+ return;
}
CHECK_EQ(msg->what(), (int)kWhatNotify);
@@ -372,7 +426,7 @@
}
notifyFlagsChanged(flags);
- notifyPrepared();
+ schedulePollBuffering();
break;
}
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index 6438a1e..a6a7644 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -43,8 +43,6 @@
virtual void prepareAsync();
virtual void start();
virtual void stop();
- virtual void pause();
- virtual void resume();
virtual status_t feedMoreTSData();
@@ -65,6 +63,7 @@
kWhatNotify = 'noti',
kWhatDisconnect = 'disc',
kWhatPerformSeek = 'seek',
+ kWhatPollBuffering = 'poll',
};
enum State {
@@ -79,6 +78,12 @@
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 @@
sp<AReplyToken> mDisconnectReplyID;
Mutex mBufferingLock;
bool mBuffering;
+ bool mInPreparationPhase;
sp<ALooper> mLooper;
sp<MyHandler> mHandler;
@@ -126,6 +132,9 @@
void finishDisconnectIfPossible();
void performSeek(int64_t seekTimeUs);
+ void schedulePollBuffering();
+ void checkBuffering(bool *prepared, bool *underflow, bool *overflow, bool *startServer);
+ void onPollBuffering();
bool haveSufficientDataOnAllTracks();
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index eedbb42..6fa83fa 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -235,7 +235,7 @@
sp<AMessage> msg = new AMessage('paus', this);
mPauseGeneration++;
msg->setInt32("pausecheck", mPauseGeneration);
- msg->post(kPauseDelayUs);
+ msg->post();
}
void resume() {
@@ -979,6 +979,11 @@
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 @@
ALOGW("This is a live stream, ignoring pause request.");
break;
}
+
+ if (mPausing) {
+ ALOGV("This stream is already paused.");
+ break;
+ }
+
mCheckPending = true;
++mCheckGeneration;
mPausing = true;