BufferingSettings: hook up internal BufferingSettings API.
Test: compiles
Bug: 32524218
Change-Id: I4b3f1689681560f0c1af3bfc62adee1ce630e218
diff --git a/include/media/BufferingSettings.h b/include/media/BufferingSettings.h
index 7dd9d40..281a5c1 100644
--- a/include/media/BufferingSettings.h
+++ b/include/media/BufferingSettings.h
@@ -40,6 +40,8 @@
static const int kNoWatermark = -1;
static bool IsValidBufferingMode(int mode);
+ static bool IsTimeBasedBufferingMode(int mode);
+ static bool IsSizeBasedBufferingMode(int mode);
BufferingMode mInitialBufferingMode; // for prepare
BufferingMode mRebufferingMode; // for playback
diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h
index 8eff914..88a416a 100644
--- a/include/media/stagefright/Utils.h
+++ b/include/media/stagefright/Utils.h
@@ -23,6 +23,7 @@
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <system/audio.h>
+#include <media/BufferingSettings.h>
#include <media/MediaPlayerInterface.h>
namespace android {
@@ -90,6 +91,9 @@
void readFromAMessage(
const sp<AMessage> &msg, AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
+void writeToAMessage(const sp<AMessage> &msg, const BufferingSettings &buffering);
+void readFromAMessage(const sp<AMessage> &msg, BufferingSettings *buffering /* nonnull */);
+
AString nameForFd(int fd);
} // namespace android
diff --git a/media/libmedia/BufferingSettings.cpp b/media/libmedia/BufferingSettings.cpp
index 6dc4a53..5d6e03d 100644
--- a/media/libmedia/BufferingSettings.cpp
+++ b/media/libmedia/BufferingSettings.cpp
@@ -28,6 +28,16 @@
return (mode >= BUFFERING_MODE_NONE && mode < BUFFERING_MODE_COUNT);
}
+// static
+bool BufferingSettings::IsTimeBasedBufferingMode(int mode) {
+ return (mode == BUFFERING_MODE_TIME_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE);
+}
+
+// static
+bool BufferingSettings::IsSizeBasedBufferingMode(int mode) {
+ return (mode == BUFFERING_MODE_SIZE_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE);
+}
+
BufferingSettings::BufferingSettings()
: mInitialBufferingMode(BUFFERING_MODE_NONE),
mRebufferingMode(BUFFERING_MODE_NONE),
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 8761e9d..3051df8 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -38,11 +38,12 @@
namespace android {
-static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
-static int64_t kHighWaterMarkUs = 5000000ll; // 5secs
-static int64_t kHighWaterMarkRebufferUs = 15000000ll; // 15secs
-static const ssize_t kLowWaterMarkBytes = 40000;
-static const ssize_t kHighWaterMarkBytes = 200000;
+static const int kLowWaterMarkMs = 2000; // 2secs
+static const int kHighWaterMarkMs = 5000; // 5secs
+static const int kHighWaterMarkRebufferMs = 15000; // 15secs
+
+static const int kLowWaterMarkKB = 40;
+static const int kHighWaterMarkKB = 200;
NuPlayer::GenericSource::GenericSource(
const sp<AMessage> ¬ify,
@@ -241,6 +242,16 @@
return OK;
}
+status_t NuPlayer::GenericSource::getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) {
+ mBufferingMonitor->getDefaultBufferingSettings(buffering);
+ return OK;
+}
+
+status_t NuPlayer::GenericSource::setBufferingSettings(const BufferingSettings& buffering) {
+ return mBufferingMonitor->setBufferingSettings(buffering);
+}
+
status_t NuPlayer::GenericSource::startSources() {
// Start the selected A/V tracks now before we start buffering.
// Widevine sources might re-initialize crypto when starting, if we delay
@@ -1451,11 +1462,48 @@
mFirstDequeuedBufferRealUs(-1ll),
mFirstDequeuedBufferMediaUs(-1ll),
mlastDequeuedBufferMediaUs(-1ll) {
+ getDefaultBufferingSettings(&mSettings);
}
NuPlayer::GenericSource::BufferingMonitor::~BufferingMonitor() {
}
+void NuPlayer::GenericSource::BufferingMonitor::getDefaultBufferingSettings(
+ BufferingSettings *buffering /* nonnull */) {
+ buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
+ buffering->mRebufferingMode = BUFFERING_MODE_TIME_THEN_SIZE;
+ buffering->mInitialWatermarkMs = kHighWaterMarkMs;
+ buffering->mRebufferingWatermarkLowMs = kLowWaterMarkMs;
+ buffering->mRebufferingWatermarkHighMs = kHighWaterMarkRebufferMs;
+ buffering->mRebufferingWatermarkLowKB = kLowWaterMarkKB;
+ buffering->mRebufferingWatermarkHighKB = kHighWaterMarkKB;
+}
+
+status_t NuPlayer::GenericSource::BufferingMonitor::setBufferingSettings(
+ const BufferingSettings &buffering) {
+ Mutex::Autolock _l(mLock);
+ if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
+ || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode)
+ && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)
+ || (buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
+ && buffering.mRebufferingWatermarkLowKB > buffering.mRebufferingWatermarkHighKB)) {
+ return BAD_VALUE;
+ }
+ mSettings = buffering;
+ if (mSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) {
+ mSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
+ }
+ if (!mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) {
+ mSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
+ mSettings.mRebufferingWatermarkHighMs = INT32_MAX;
+ }
+ if (!mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) {
+ mSettings.mRebufferingWatermarkLowKB = BufferingSettings::kNoWatermark;
+ mSettings.mRebufferingWatermarkHighKB = INT32_MAX;
+ }
+ return OK;
+}
+
void NuPlayer::GenericSource::BufferingMonitor::prepare(
const sp<NuCachedSource2> &cachedSource,
int64_t durationUs,
@@ -1684,7 +1732,9 @@
stopBufferingIfNecessary_l();
return;
- } else if (cachedDurationUs >= 0ll) {
+ }
+
+ if (cachedDurationUs >= 0ll) {
if (mDurationUs > 0ll) {
int64_t cachedPosUs = getLastReadPosition_l() + cachedDurationUs;
int percentage = 100.0 * cachedPosUs / mDurationUs;
@@ -1695,36 +1745,40 @@
notifyBufferingUpdate_l(percentage);
}
- ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec",
- cachedDurationUs / 1000000.0f);
+ ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
- if (cachedDurationUs < kLowWaterMarkUs) {
- // Take into account the data cached in downstream components to try to avoid
- // unnecessary pause.
- if (mOffloadAudio && mFirstDequeuedBufferRealUs >= 0) {
- int64_t downStreamCacheUs = mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs
- - (ALooper::GetNowUs() - mFirstDequeuedBufferRealUs);
- if (downStreamCacheUs > 0) {
- cachedDurationUs += downStreamCacheUs;
+ if (mPrepareBuffering) {
+ if (cachedDurationUs > mSettings.mInitialWatermarkMs * 1000) {
+ stopBufferingIfNecessary_l();
+ }
+ } else if (mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) {
+ if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) {
+ // Take into account the data cached in downstream components to try to avoid
+ // unnecessary pause.
+ if (mOffloadAudio && mFirstDequeuedBufferRealUs >= 0) {
+ int64_t downStreamCacheUs =
+ mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs
+ - (ALooper::GetNowUs() - mFirstDequeuedBufferRealUs);
+ if (downStreamCacheUs > 0) {
+ cachedDurationUs += downStreamCacheUs;
+ }
}
- }
- if (cachedDurationUs < kLowWaterMarkUs) {
- startBufferingIfNecessary_l();
- }
- } else {
- int64_t highWaterMark = mPrepareBuffering ? kHighWaterMarkUs : kHighWaterMarkRebufferUs;
- if (cachedDurationUs > highWaterMark) {
+ if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) {
+ startBufferingIfNecessary_l();
+ }
+ } else if (cachedDurationUs > mSettings.mRebufferingWatermarkHighMs * 1000) {
stopBufferingIfNecessary_l();
}
}
- } else if (cachedDataRemaining >= 0) {
+ } else if (cachedDataRemaining >= 0
+ && mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) {
ALOGV("onPollBuffering_l: cachedDataRemaining %zd bytes",
cachedDataRemaining);
- if (cachedDataRemaining < kLowWaterMarkBytes) {
+ if (cachedDataRemaining < (mSettings.mRebufferingWatermarkLowKB << 10)) {
startBufferingIfNecessary_l();
- } else if (cachedDataRemaining > kHighWaterMarkBytes) {
+ } else if (cachedDataRemaining > (mSettings.mRebufferingWatermarkHighKB << 10)) {
stopBufferingIfNecessary_l();
}
}
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 38d8616..cc61c11 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -50,6 +50,10 @@
status_t setDataSource(const sp<DataSource>& dataSource);
+ virtual status_t getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) override;
+ virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
+
virtual void prepareAsync();
virtual void start();
@@ -119,6 +123,9 @@
public:
explicit BufferingMonitor(const sp<AMessage> ¬ify);
+ void getDefaultBufferingSettings(BufferingSettings *buffering /* nonnull */);
+ status_t setBufferingSettings(const BufferingSettings &buffering);
+
// Set up state.
void prepare(const sp<NuCachedSource2> &cachedSource,
int64_t durationUs,
@@ -167,6 +174,7 @@
mutable Mutex mLock;
+ BufferingSettings mSettings;
bool mOffloadAudio;
int64_t mFirstDequeuedBufferRealUs;
int64_t mFirstDequeuedBufferMediaUs;
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 51bfad4..05e6201 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -32,6 +32,11 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/Utils.h>
+// default buffer prepare/ready/underflow marks
+static const int kReadyMarkMs = 5000; // 5 seconds
+static const int kPrepareMarkMs = 1500; // 1.5 seconds
+static const int kUnderflowMarkMs = 1000; // 1 second
+
namespace android {
NuPlayer::HTTPLiveSource::HTTPLiveSource(
@@ -49,6 +54,7 @@
mFetchMetaDataGeneration(0),
mHasMetadata(false),
mMetadataSelected(false) {
+ getDefaultBufferingSettings(&mBufferingSettings);
if (headers) {
mExtraHeaders = *headers;
@@ -76,6 +82,42 @@
}
}
+status_t NuPlayer::HTTPLiveSource::getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) {
+ buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
+ buffering->mRebufferingMode = BUFFERING_MODE_TIME_ONLY;
+ buffering->mInitialWatermarkMs = kPrepareMarkMs;
+ buffering->mRebufferingWatermarkLowMs = kUnderflowMarkMs;
+ buffering->mRebufferingWatermarkHighMs = kReadyMarkMs;
+
+ return OK;
+}
+
+status_t NuPlayer::HTTPLiveSource::setBufferingSettings(const BufferingSettings& buffering) {
+ if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
+ || buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
+ || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode)
+ && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)) {
+ return BAD_VALUE;
+ }
+
+ mBufferingSettings = buffering;
+
+ if (mBufferingSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) {
+ mBufferingSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
+ }
+ if (mBufferingSettings.mRebufferingMode == BUFFERING_MODE_NONE) {
+ mBufferingSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
+ mBufferingSettings.mRebufferingWatermarkHighMs = INT32_MAX;
+ }
+
+ if (mLiveSession != NULL) {
+ mLiveSession->setBufferingSettings(mBufferingSettings);
+ }
+
+ return OK;
+}
+
void NuPlayer::HTTPLiveSource::prepareAsync() {
if (mLiveLooper == NULL) {
mLiveLooper = new ALooper;
@@ -94,6 +136,7 @@
mLiveLooper->registerHandler(mLiveSession);
+ mLiveSession->setBufferingSettings(mBufferingSettings);
mLiveSession->connectAsync(
mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
}
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index 45fc8c1..2866a6a 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -34,6 +34,10 @@
const char *url,
const KeyedVector<String8, String8> *headers);
+ virtual status_t getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) override;
+ virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
+
virtual void prepareAsync();
virtual void start();
@@ -80,6 +84,7 @@
int32_t mFetchMetaDataGeneration;
bool mHasMetadata;
bool mMetadataSelected;
+ BufferingSettings mBufferingSettings;
void onSessionNotify(const sp<AMessage> &msg);
void pollForRawData(
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index f8a6a4e..fb59938 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -311,6 +311,31 @@
msg->post();
}
+status_t NuPlayer::getDefaultBufferingSettings(
+ BufferingSettings *buffering /* nonnull */) {
+ sp<AMessage> msg = new AMessage(kWhatGetDefaultBufferingSettings, this);
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("err", &err));
+ if (err == OK) {
+ readFromAMessage(response, buffering);
+ }
+ }
+ return err;
+}
+
+status_t NuPlayer::setBufferingSettings(const BufferingSettings& buffering) {
+ sp<AMessage> msg = new AMessage(kWhatSetBufferingSettings, this);
+ writeToAMessage(msg, buffering);
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("err", &err));
+ }
+ return err;
+}
+
void NuPlayer::prepareAsync() {
(new AMessage(kWhatPrepare, this))->post();
}
@@ -505,6 +530,48 @@
break;
}
+ case kWhatGetDefaultBufferingSettings:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ ALOGV("kWhatGetDefaultBufferingSettings");
+ BufferingSettings buffering;
+ status_t err = OK;
+ if (mSource != NULL) {
+ err = mSource->getDefaultBufferingSettings(&buffering);
+ } else {
+ err = INVALID_OPERATION;
+ }
+ sp<AMessage> response = new AMessage;
+ if (err == OK) {
+ writeToAMessage(response, buffering);
+ }
+ response->setInt32("err", err);
+ response->postReply(replyID);
+ break;
+ }
+
+ case kWhatSetBufferingSettings:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ ALOGV("kWhatSetBufferingSettings");
+ BufferingSettings buffering;
+ readFromAMessage(msg, &buffering);
+ status_t err = OK;
+ if (mSource != NULL) {
+ err = mSource->setBufferingSettings(buffering);
+ } else {
+ err = INVALID_OPERATION;
+ }
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", err);
+ response->postReply(replyID);
+ break;
+ }
+
case kWhatPrepare:
{
mSource->prepareAsync();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index c8b0102..1603432 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -50,6 +50,9 @@
void setDataSourceAsync(const sp<DataSource> &source);
+ status_t getDefaultBufferingSettings(BufferingSettings* buffering /* nonnull */);
+ status_t setBufferingSettings(const BufferingSettings& buffering);
+
void prepareAsync();
void setVideoSurfaceTextureAsync(
@@ -137,6 +140,8 @@
kWhatGetTrackInfo = 'gTrI',
kWhatGetSelectedTrack = 'gSel',
kWhatSelectTrack = 'selT',
+ kWhatGetDefaultBufferingSettings = 'gDBS',
+ kWhatSetBufferingSettings = 'sBuS',
};
wp<NuPlayerDriver> mDriver;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 6ec79e6..aa3d77b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -183,6 +183,26 @@
return OK;
}
+status_t NuPlayerDriver::getDefaultBufferingSettings(BufferingSettings* buffering) {
+ ALOGV("getDefaultBufferingSettings(%p)", this);
+ Mutex::Autolock autoLock(mLock);
+ if (mState == STATE_IDLE) {
+ return INVALID_OPERATION;
+ }
+
+ return mPlayer->getDefaultBufferingSettings(buffering);
+}
+
+status_t NuPlayerDriver::setBufferingSettings(const BufferingSettings& buffering) {
+ ALOGV("setBufferingSettings(%p)", this);
+ Mutex::Autolock autoLock(mLock);
+ if (mState == STATE_IDLE) {
+ return INVALID_OPERATION;
+ }
+
+ return mPlayer->setBufferingSettings(buffering);
+}
+
status_t NuPlayerDriver::prepare() {
ALOGV("prepare(%p)", this);
Mutex::Autolock autoLock(mLock);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 317b34c..9e61c04 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -43,6 +43,11 @@
virtual status_t setVideoSurfaceTexture(
const sp<IGraphicBufferProducer> &bufferProducer);
+
+ virtual status_t getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) override;
+ virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
+
virtual status_t prepare();
virtual status_t prepareAsync();
virtual status_t start();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 5197167..5ee0712 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -63,6 +63,10 @@
: mNotify(notify) {
}
+ virtual status_t getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) = 0;
+ virtual status_t setBufferingSettings(const BufferingSettings& buffering) = 0;
+
virtual void prepareAsync() = 0;
virtual void start() = 0;
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index fb1f31a..9264e49 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -32,11 +32,11 @@
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;
+// Default Buffer Underflow/Prepare/StartServer/Overflow Marks
+static const int kUnderflowMarkMs = 1000; // 1 second
+static const int kPrepareMarkMs = 3000; // 3 seconds
+//static const int kStartServerMarkMs = 5000;
+static const int kOverflowMarkMs = 10000; // 10 seconds
NuPlayer::RTSPSource::RTSPSource(
const sp<AMessage> ¬ify,
@@ -62,6 +62,7 @@
mSeekGeneration(0),
mEOSTimeoutAudio(0),
mEOSTimeoutVideo(0) {
+ getDefaultBufferingSettings(&mBufferingSettings);
if (headers) {
mExtraHeaders = *headers;
@@ -83,6 +84,34 @@
}
}
+status_t NuPlayer::RTSPSource::getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) {
+ buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
+ buffering->mRebufferingMode = BUFFERING_MODE_TIME_ONLY;
+ buffering->mInitialWatermarkMs = kPrepareMarkMs;
+ buffering->mRebufferingWatermarkLowMs = kUnderflowMarkMs;
+ buffering->mRebufferingWatermarkHighMs = kOverflowMarkMs;
+
+ return OK;
+}
+
+status_t NuPlayer::RTSPSource::setBufferingSettings(const BufferingSettings& buffering) {
+ if (mLooper == NULL) {
+ mBufferingSettings = buffering;
+ return OK;
+ }
+
+ sp<AMessage> msg = new AMessage(kWhatSetBufferingSettings, this);
+ writeToAMessage(msg, buffering);
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("err", &err));
+ }
+
+ return err;
+}
+
void NuPlayer::RTSPSource::prepareAsync() {
if (mIsSDP && mHTTPService == NULL) {
notifyPrepared(BAD_VALUE);
@@ -328,7 +357,8 @@
int64_t bufferedDurationUs = src->getBufferedDurationUs(&finalResult);
// isFinished when duration is 0 checks for EOS result only
- if (bufferedDurationUs > kPrepareMarkUs || src->isFinished(/* duration */ 0)) {
+ if (bufferedDurationUs > mBufferingSettings.mInitialWatermarkMs * 1000
+ || src->isFinished(/* duration */ 0)) {
++preparedCount;
}
@@ -336,13 +366,16 @@
++overflowCount;
++finishedCount;
} else {
- if (bufferedDurationUs < kUnderflowMarkUs) {
+ if (bufferedDurationUs < mBufferingSettings.mRebufferingWatermarkLowMs * 1000) {
++underflowCount;
}
- if (bufferedDurationUs > kOverflowMarkUs) {
+ if (bufferedDurationUs > mBufferingSettings.mRebufferingWatermarkHighMs * 1000) {
++overflowCount;
}
- if (bufferedDurationUs < kStartServerMarkUs) {
+ int64_t startServerMarkUs =
+ (mBufferingSettings.mRebufferingWatermarkLowMs
+ + mBufferingSettings.mRebufferingWatermarkHighMs) / 2 * 1000ll;
+ if (bufferedDurationUs < startServerMarkUs) {
++startCount;
}
}
@@ -479,6 +512,36 @@
} else if (msg->what() == kWhatSignalEOS) {
onSignalEOS(msg);
return;
+ } else if (msg->what() == kWhatSetBufferingSettings) {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ BufferingSettings buffering;
+ readFromAMessage(msg, &buffering);
+
+ status_t err = OK;
+ if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
+ || buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
+ || (buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs
+ && buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode))) {
+ err = BAD_VALUE;
+ } else {
+ if (buffering.mInitialBufferingMode == BUFFERING_MODE_NONE) {
+ buffering.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
+ }
+ if (buffering.mRebufferingMode == BUFFERING_MODE_NONE) {
+ buffering.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
+ buffering.mRebufferingWatermarkHighMs = INT32_MAX;
+ }
+
+ mBufferingSettings = buffering;
+ }
+
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", err);
+ response->postReply(replyID);
+
+ return;
}
CHECK_EQ(msg->what(), (int)kWhatNotify);
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index 363f8bb..0812991 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -40,6 +40,10 @@
uid_t uid = 0,
bool isSDP = false);
+ virtual status_t getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) override;
+ virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
+
virtual void prepareAsync();
virtual void start();
virtual void stop();
@@ -67,6 +71,7 @@
kWhatPerformSeek = 'seek',
kWhatPollBuffering = 'poll',
kWhatSignalEOS = 'eos ',
+ kWhatSetBufferingSettings = 'sBuS',
};
enum State {
@@ -81,12 +86,6 @@
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;
@@ -110,6 +109,7 @@
bool mBuffering;
bool mInPreparationPhase;
bool mEOSPending;
+ BufferingSettings mBufferingSettings;
sp<ALooper> mLooper;
sp<MyHandler> mHandler;
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index 7f9f913..a9a1244 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -51,6 +51,22 @@
}
}
+status_t NuPlayer::StreamingSource::getDefaultBufferingSettings(
+ BufferingSettings *buffering /* nonnull */) {
+ *buffering = BufferingSettings();
+ return OK;
+}
+
+status_t NuPlayer::StreamingSource::setBufferingSettings(
+ const BufferingSettings &buffering) {
+ if (buffering.mInitialBufferingMode != BUFFERING_MODE_NONE
+ || buffering.mRebufferingMode != BUFFERING_MODE_NONE) {
+ return BAD_VALUE;
+ }
+
+ return OK;
+}
+
void NuPlayer::StreamingSource::prepareAsync() {
if (mLooper == NULL) {
mLooper = new ALooper;
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.h b/media/libmediaplayerservice/nuplayer/StreamingSource.h
index db88c7f..2e1d2b3 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.h
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.h
@@ -32,6 +32,10 @@
const sp<AMessage> ¬ify,
const sp<IStreamSource> &source);
+ virtual status_t getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) override;
+ virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
+
virtual void prepareAsync();
virtual void start();
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index f2638ed..68a5b86 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -1770,6 +1770,45 @@
*sync = settings;
}
+void writeToAMessage(const sp<AMessage> &msg, const BufferingSettings &buffering) {
+ msg->setInt32("init-mode", buffering.mInitialBufferingMode);
+ msg->setInt32("rebuffer-mode", buffering.mRebufferingMode);
+ msg->setInt32("init-ms", buffering.mInitialWatermarkMs);
+ msg->setInt32("init-kb", buffering.mInitialWatermarkKB);
+ msg->setInt32("rebuffer-low-ms", buffering.mRebufferingWatermarkLowMs);
+ msg->setInt32("rebuffer-high-ms", buffering.mRebufferingWatermarkHighMs);
+ msg->setInt32("rebuffer-low-kb", buffering.mRebufferingWatermarkLowKB);
+ msg->setInt32("rebuffer-high-kb", buffering.mRebufferingWatermarkHighKB);
+}
+
+void readFromAMessage(const sp<AMessage> &msg, BufferingSettings *buffering /* nonnull */) {
+ int32_t value;
+ if (msg->findInt32("init-mode", &value) == OK) {
+ buffering->mInitialBufferingMode = (BufferingMode)value;
+ }
+ if (msg->findInt32("rebuffer-mode", &value) == OK) {
+ buffering->mRebufferingMode = (BufferingMode)value;
+ }
+ if (msg->findInt32("init-ms", &value) == OK) {
+ buffering->mInitialWatermarkMs = value;
+ }
+ if (msg->findInt32("init-kb", &value) == OK) {
+ buffering->mInitialWatermarkKB = value;
+ }
+ if (msg->findInt32("rebuffer-low-ms", &value) == OK) {
+ buffering->mRebufferingWatermarkLowMs = value;
+ }
+ if (msg->findInt32("rebuffer-high-ms", &value) == OK) {
+ buffering->mRebufferingWatermarkHighMs = value;
+ }
+ if (msg->findInt32("rebuffer-low-kb", &value) == OK) {
+ buffering->mRebufferingWatermarkLowKB = value;
+ }
+ if (msg->findInt32("rebuffer-high-kb", &value) == OK) {
+ buffering->mRebufferingWatermarkHighKB = value;
+ }
+}
+
AString nameForFd(int fd) {
const size_t SIZE = 256;
char buffer[SIZE];
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 477280a..e144942 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -49,11 +49,6 @@
const int64_t LiveSession::kUpSwitchMarginUs = 5000000ll;
const int64_t LiveSession::kResumeThresholdUs = 100000ll;
-// Buffer Prepare/Ready/Underflow Marks
-const int64_t LiveSession::kReadyMarkUs = 5000000ll;
-const int64_t LiveSession::kPrepareMarkUs = 1500000ll;
-const int64_t LiveSession::kUnderflowMarkUs = 1000000ll;
-
struct LiveSession::BandwidthEstimator : public RefBase {
BandwidthEstimator();
@@ -495,6 +490,13 @@
return new HTTPDownloader(mHTTPService, mExtraHeaders);
}
+void LiveSession::setBufferingSettings(
+ const BufferingSettings &buffering) {
+ sp<AMessage> msg = new AMessage(kWhatSetBufferingSettings, this);
+ writeToAMessage(msg, buffering);
+ msg->post();
+}
+
void LiveSession::connectAsync(
const char *url, const KeyedVector<String8, String8> *headers) {
sp<AMessage> msg = new AMessage(kWhatConnect, this);
@@ -620,6 +622,12 @@
void LiveSession::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
+ case kWhatSetBufferingSettings:
+ {
+ readFromAMessage(msg, &mBufferingSettings);
+ break;
+ }
+
case kWhatConnect:
{
onConnect(msg);
@@ -830,7 +838,10 @@
// If switching up, require a cushion bigger than kUnderflowMark
// to avoid buffering immediately after the switch.
// (If we don't have that cushion we'd rather cancel and try again.)
- int64_t delayUs = switchUp ? (kUnderflowMarkUs + 1000000ll) : 0;
+ int64_t delayUs =
+ switchUp ?
+ (mBufferingSettings.mRebufferingWatermarkLowMs * 1000ll + 1000000ll)
+ : 0;
bool needResumeUntil = false;
sp<AMessage> stopParams = msg;
if (checkSwitchProgress(stopParams, delayUs, &needResumeUntil)) {
@@ -2189,13 +2200,16 @@
}
++activeCount;
- int64_t readyMark = mInPreparationPhase ? kPrepareMarkUs : kReadyMarkUs;
- if (bufferedDurationUs > readyMark
+ int64_t readyMarkUs =
+ (mInPreparationPhase ?
+ mBufferingSettings.mInitialWatermarkMs :
+ mBufferingSettings.mRebufferingWatermarkHighMs) * 1000ll;
+ if (bufferedDurationUs > readyMarkUs
|| mPacketSources[i]->isFinished(0)) {
++readyCount;
}
if (!mPacketSources[i]->isFinished(0)) {
- if (bufferedDurationUs < kUnderflowMarkUs) {
+ if (bufferedDurationUs < mBufferingSettings.mRebufferingWatermarkLowMs * 1000ll) {
++underflowCount;
}
if (bufferedDurationUs > mUpSwitchMark) {
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index a0138be..abf8cf0 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -18,6 +18,7 @@
#define LIVE_SESSION_H_
+#include <media/BufferingSettings.h>
#include <media/stagefright/foundation/AHandler.h>
#include <media/mediaplayer.h>
@@ -72,6 +73,8 @@
uint32_t flags,
const sp<IMediaHTTPService> &httpService);
+ void setBufferingSettings(const BufferingSettings &buffering);
+
int64_t calculateMediaTimeUs(int64_t firstTimeUs, int64_t timeUs, int32_t discontinuitySeq);
status_t dequeueAccessUnit(StreamType stream, sp<ABuffer> *accessUnit);
@@ -129,6 +132,7 @@
kWhatChangeConfiguration2 = 'chC2',
kWhatChangeConfiguration3 = 'chC3',
kWhatPollBuffering = 'poll',
+ kWhatSetBufferingSettings = 'sBuS',
};
// Bandwidth Switch Mark Defaults
@@ -138,9 +142,7 @@
static const int64_t kResumeThresholdUs;
// Buffer Prepare/Ready/Underflow Marks
- static const int64_t kReadyMarkUs;
- static const int64_t kPrepareMarkUs;
- static const int64_t kUnderflowMarkUs;
+ BufferingSettings mBufferingSettings;
struct BandwidthEstimator;
struct BandwidthItem {