Send estimated bandwidth value as informational event when cache fetcher pauses

o Application can make informed decision about the available network bandwidth
  when cache fetcher pauses.

o Application can also adjust how frequently the bandwidth is estimated within
  a range from one second to one minute.

Change-Id: I90068001343e79da1886de03c565537787e1580b
This commit is contained in:
James Dong
2011-05-25 19:37:03 -07:00
parent da188fbe4b
commit a9d0febdd0
11 changed files with 162 additions and 99 deletions

View File

@@ -100,6 +100,9 @@ enum media_info_type {
MEDIA_INFO_BUFFERING_START = 701,
// MediaPlayer is resuming playback after filling buffers.
MEDIA_INFO_BUFFERING_END = 702,
// Bandwidth in recent past
MEDIA_INFO_NETWORK_BANDWIDTH = 703,
// 8xx
// Bad interleaving means that a media has been improperly interleaved or not
// interleaved at all, e.g has all the video samples first then all the audio
@@ -128,6 +131,9 @@ enum media_player_states {
enum media_set_parameter_keys {
KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX = 1000,
KEY_PARAMETER_TIMED_TEXT_ADD_OUT_OF_BAND_SOURCE = 1001,
// Streaming/buffering parameters
KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS = 1100,
};
// ----------------------------------------------------------------------------
// ref-counted object for callbacks

View File

@@ -634,6 +634,7 @@ void AwesomePlayer::onBufferingUpdate() {
mFlags |= CACHE_UNDERRUN;
pause_l();
ensureCacheIsFetching_l();
sendCacheStats();
notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
} else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
if (mFlags & CACHE_UNDERRUN) {
@@ -692,6 +693,7 @@ void AwesomePlayer::onBufferingUpdate() {
mFlags |= CACHE_UNDERRUN;
pause_l();
ensureCacheIsFetching_l();
sendCacheStats();
notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
} else if (eos || cachedDurationUs > highWaterMarkUs) {
if (mFlags & CACHE_UNDERRUN) {
@@ -711,6 +713,18 @@ void AwesomePlayer::onBufferingUpdate() {
postBufferingEvent_l();
}
void AwesomePlayer::sendCacheStats() {
sp<MediaPlayerBase> listener = mListener.promote();
if (listener != NULL) {
int32_t kbps = 0;
status_t err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
if (err == OK) {
listener->sendEvent(
MEDIA_INFO, MEDIA_INFO_NETWORK_BANDWIDTH, kbps);
}
}
}
void AwesomePlayer::onStreamDone() {
// Posted whenever any stream finishes playing.
@@ -2083,6 +2097,10 @@ status_t AwesomePlayer::setParameter(int key, const Parcel &request) {
return mTextPlayer->setParameter(key, request);
}
case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS:
{
return setCacheStatCollectFreq(request);
}
default:
{
return ERROR_UNSUPPORTED;
@@ -2090,6 +2108,16 @@ status_t AwesomePlayer::setParameter(int key, const Parcel &request) {
}
}
status_t AwesomePlayer::setCacheStatCollectFreq(const Parcel &request) {
if (mCachedSource != NULL) {
int32_t freqMs = request.readInt32();
LOGD("Request to keep cache stats in the past %d ms",
freqMs);
return mCachedSource->setCacheStatCollectFreq(freqMs);
}
return ERROR_UNSUPPORTED;
}
status_t AwesomePlayer::getParameter(int key, Parcel *reply) {
return OK;
}

View File

@@ -14,6 +14,10 @@
* limitations under the License.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "HTTPBase"
#include <utils/Log.h>
#include "include/HTTPBase.h"
#if CHROMIUM_AVAILABLE
@@ -22,11 +26,19 @@
#include "include/NuHTTPDataSource.h"
#include <media/stagefright/foundation/ALooper.h>
#include <cutils/properties.h>
namespace android {
HTTPBase::HTTPBase() {}
HTTPBase::HTTPBase()
: mNumBandwidthHistoryItems(0),
mTotalTransferTimeUs(0),
mTotalTransferBytes(0),
mPrevBandwidthMeasureTimeUs(0),
mPrevEstimatedBandWidthKbps(0),
mBandWidthCollectFreqMs(5000) {
}
// static
sp<HTTPBase> HTTPBase::Create(uint32_t flags) {
@@ -42,4 +54,69 @@ sp<HTTPBase> HTTPBase::Create(uint32_t flags) {
}
}
void HTTPBase::addBandwidthMeasurement(
size_t numBytes, int64_t delayUs) {
Mutex::Autolock autoLock(mLock);
BandwidthEntry entry;
entry.mDelayUs = delayUs;
entry.mNumBytes = numBytes;
mTotalTransferTimeUs += delayUs;
mTotalTransferBytes += numBytes;
mBandwidthHistory.push_back(entry);
if (++mNumBandwidthHistoryItems > 100) {
BandwidthEntry *entry = &*mBandwidthHistory.begin();
mTotalTransferTimeUs -= entry->mDelayUs;
mTotalTransferBytes -= entry->mNumBytes;
mBandwidthHistory.erase(mBandwidthHistory.begin());
--mNumBandwidthHistoryItems;
int64_t timeNowUs = ALooper::GetNowUs();
if (timeNowUs - mPrevBandwidthMeasureTimeUs >=
mBandWidthCollectFreqMs * 1000LL) {
if (mPrevBandwidthMeasureTimeUs != 0) {
mPrevEstimatedBandWidthKbps =
(mTotalTransferBytes * 8E3 / mTotalTransferTimeUs);
}
mPrevBandwidthMeasureTimeUs = timeNowUs;
}
}
}
bool HTTPBase::estimateBandwidth(int32_t *bandwidth_bps) {
Mutex::Autolock autoLock(mLock);
if (mNumBandwidthHistoryItems < 2) {
return false;
}
*bandwidth_bps = ((double)mTotalTransferBytes * 8E6 / mTotalTransferTimeUs);
return true;
}
status_t HTTPBase::getEstimatedBandwidthKbps(int32_t *kbps) {
Mutex::Autolock autoLock(mLock);
*kbps = mPrevEstimatedBandWidthKbps;
return OK;
}
status_t HTTPBase::setBandwidthStatCollectFreq(int32_t freqMs) {
Mutex::Autolock autoLock(mLock);
if (freqMs < kMinBandwidthCollectFreqMs
|| freqMs > kMaxBandwidthCollectFreqMs) {
LOGE("frequency (%d ms) is out of range [1000, 60000]", freqMs);
return BAD_VALUE;
}
LOGI("frequency set to %d ms", freqMs);
mBandWidthCollectFreqMs = freqMs;
return OK;
}
} // namespace android

View File

@@ -19,6 +19,7 @@
#include <utils/Log.h>
#include "include/NuCachedSource2.h"
#include "include/HTTPBase.h"
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -201,6 +202,16 @@ NuCachedSource2::~NuCachedSource2() {
mCache = NULL;
}
status_t NuCachedSource2::getEstimatedBandwidthKbps(int32_t *kbps) {
HTTPBase* source = static_cast<HTTPBase *>(mSource.get());
return source->getEstimatedBandwidthKbps(kbps);
}
status_t NuCachedSource2::setCacheStatCollectFreq(int32_t freqMs) {
HTTPBase *source = static_cast<HTTPBase *>(mSource.get());
return source->setBandwidthStatCollectFreq(freqMs);
}
status_t NuCachedSource2::initCheck() const {
return mSource->initCheck();
}

View File

@@ -97,9 +97,6 @@ NuHTTPDataSource::NuHTTPDataSource(uint32_t flags)
mContentLengthValid(false),
mHasChunkedTransferEncoding(false),
mChunkDataBytesLeft(0),
mNumBandwidthHistoryItems(0),
mTotalTransferTimeUs(0),
mTotalTransferBytes(0),
mDecryptHandle(NULL),
mDrmManagerClient(NULL) {
}
@@ -431,7 +428,7 @@ ssize_t NuHTTPDataSource::readAt(off64_t offset, void *data, size_t size) {
}
int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
addBandwidthMeasurement_l(n, delayUs);
addBandwidthMeasurement(n, delayUs);
numBytesRead += (size_t)n;
@@ -517,36 +514,6 @@ void NuHTTPDataSource::applyTimeoutResponse() {
}
}
bool NuHTTPDataSource::estimateBandwidth(int32_t *bandwidth_bps) {
Mutex::Autolock autoLock(mLock);
if (mNumBandwidthHistoryItems < 2) {
return false;
}
*bandwidth_bps = ((double)mTotalTransferBytes * 8E6 / mTotalTransferTimeUs);
return true;
}
void NuHTTPDataSource::addBandwidthMeasurement_l(
size_t numBytes, int64_t delayUs) {
BandwidthEntry entry;
entry.mDelayUs = delayUs;
entry.mNumBytes = numBytes;
mTotalTransferTimeUs += delayUs;
mTotalTransferBytes += numBytes;
mBandwidthHistory.push_back(entry);
if (++mNumBandwidthHistoryItems > 100) {
BandwidthEntry *entry = &*mBandwidthHistory.begin();
mTotalTransferTimeUs -= entry->mDelayUs;
mTotalTransferBytes -= entry->mNumBytes;
mBandwidthHistory.erase(mBandwidthHistory.begin());
--mNumBandwidthHistoryItems;
}
}
sp<DecryptHandle> NuHTTPDataSource::DrmInitialization() {
if (mDrmManagerClient == NULL) {
mDrmManagerClient = new DrmManagerClient();

View File

@@ -34,9 +34,6 @@ ChromiumHTTPDataSource::ChromiumHTTPDataSource(uint32_t flags)
mCurrentOffset(0),
mIOResult(OK),
mContentSize(-1),
mNumBandwidthHistoryItems(0),
mTotalTransferTimeUs(0),
mTotalTransferBytes(0),
mDecryptHandle(NULL),
mDrmManagerClient(NULL) {
mDelegate->setOwner(this);
@@ -188,7 +185,7 @@ ssize_t ChromiumHTTPDataSource::readAt(off64_t offset, void *data, size_t size)
// The read operation was successful, mIOResult contains
// the number of bytes read.
addBandwidthMeasurement_l(mIOResult, delayUs);
addBandwidthMeasurement(mIOResult, delayUs);
mCurrentOffset += mIOResult;
return mIOResult;
@@ -246,36 +243,6 @@ void ChromiumHTTPDataSource::onDisconnectComplete() {
clearDRMState_l();
}
void ChromiumHTTPDataSource::addBandwidthMeasurement_l(
size_t numBytes, int64_t delayUs) {
BandwidthEntry entry;
entry.mDelayUs = delayUs;
entry.mNumBytes = numBytes;
mTotalTransferTimeUs += delayUs;
mTotalTransferBytes += numBytes;
mBandwidthHistory.push_back(entry);
if (++mNumBandwidthHistoryItems > 100) {
BandwidthEntry *entry = &*mBandwidthHistory.begin();
mTotalTransferTimeUs -= entry->mDelayUs;
mTotalTransferBytes -= entry->mNumBytes;
mBandwidthHistory.erase(mBandwidthHistory.begin());
--mNumBandwidthHistoryItems;
}
}
bool ChromiumHTTPDataSource::estimateBandwidth(int32_t *bandwidth_bps) {
Mutex::Autolock autoLock(mLock);
if (mNumBandwidthHistoryItems < 2) {
return false;
}
*bandwidth_bps = ((double)mTotalTransferBytes * 8E6 / mTotalTransferTimeUs);
return true;
}
sp<DecryptHandle> ChromiumHTTPDataSource::DrmInitialization() {
Mutex::Autolock autoLock(mLock);

View File

@@ -93,6 +93,7 @@ struct AwesomePlayer {
status_t setParameter(int key, const Parcel &request);
status_t getParameter(int key, Parcel *reply);
status_t setCacheStatCollectFreq(const Parcel &request);
status_t seekTo(int64_t timeUs);
@@ -291,6 +292,7 @@ private:
void setNativeWindow_l(const sp<ANativeWindow> &native);
bool isStreamingHTTP() const;
void sendCacheStats();
AwesomePlayer(const AwesomePlayer &);
AwesomePlayer &operator=(const AwesomePlayer &);

View File

@@ -43,8 +43,6 @@ struct ChromiumHTTPDataSource : public HTTPBase {
virtual status_t getSize(off64_t *size);
virtual uint32_t flags();
virtual bool estimateBandwidth(int32_t *bandwidth_bps);
virtual sp<DecryptHandle> DrmInitialization();
virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
@@ -67,11 +65,6 @@ private:
DISCONNECTING
};
struct BandwidthEntry {
int64_t mDelayUs;
size_t mNumBytes;
};
const uint32_t mFlags;
mutable Mutex mLock;
@@ -94,11 +87,6 @@ private:
String8 mContentType;
List<BandwidthEntry> mBandwidthHistory;
size_t mNumBandwidthHistoryItems;
int64_t mTotalTransferTimeUs;
size_t mTotalTransferBytes;
sp<DecryptHandle> mDecryptHandle;
DrmManagerClient *mDrmManagerClient;
@@ -121,8 +109,6 @@ private:
void onReadCompleted(ssize_t size);
void onDisconnectComplete();
void addBandwidthMeasurement_l(size_t numBytes, int64_t delayUs);
void clearDRMState_l();
DISALLOW_EVIL_CONSTRUCTORS(ChromiumHTTPDataSource);

View File

@@ -20,6 +20,8 @@
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaErrors.h>
#include <utils/threads.h>
namespace android {
@@ -40,11 +42,41 @@ struct HTTPBase : public DataSource {
// Returns true if bandwidth could successfully be estimated,
// false otherwise.
virtual bool estimateBandwidth(int32_t *bandwidth_bps) = 0;
virtual bool estimateBandwidth(int32_t *bandwidth_bps);
virtual status_t getEstimatedBandwidthKbps(int32_t *kbps);
virtual status_t setBandwidthStatCollectFreq(int32_t freqMs);
static sp<HTTPBase> Create(uint32_t flags = 0);
protected:
void addBandwidthMeasurement(size_t numBytes, int64_t delayUs);
private:
struct BandwidthEntry {
int64_t mDelayUs;
size_t mNumBytes;
};
Mutex mLock;
List<BandwidthEntry> mBandwidthHistory;
size_t mNumBandwidthHistoryItems;
int64_t mTotalTransferTimeUs;
size_t mTotalTransferBytes;
enum {
kMinBandwidthCollectFreqMs = 1000, // 1 second
kMaxBandwidthCollectFreqMs = 60000, // one minute
};
int64_t mPrevBandwidthMeasureTimeUs;
int32_t mPrevEstimatedBandWidthKbps;
int32_t mBandWidthCollectFreqMs;
DISALLOW_EVIL_CONSTRUCTORS(HTTPBase);
};

View File

@@ -47,8 +47,10 @@ struct NuCachedSource2 : public DataSource {
size_t cachedSize();
size_t approxDataRemaining(status_t *finalStatus);
status_t setCacheStatCollectFreq(int32_t freqMs);
void resumeFetchingIfNecessary();
status_t getEstimatedBandwidthKbps(int32_t *kbps);
protected:
virtual ~NuCachedSource2();

View File

@@ -43,10 +43,6 @@ struct NuHTTPDataSource : public HTTPBase {
virtual status_t getSize(off64_t *size);
virtual uint32_t flags();
// Returns true if bandwidth could successfully be estimated,
// false otherwise.
virtual bool estimateBandwidth(int32_t *bandwidth_bps);
virtual sp<DecryptHandle> DrmInitialization();
virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
virtual String8 getUri();
@@ -63,11 +59,6 @@ private:
CONNECTED
};
struct BandwidthEntry {
int64_t mDelayUs;
size_t mNumBytes;
};
Mutex mLock;
uint32_t mFlags;
@@ -93,11 +84,6 @@ private:
// chunk header (or -1 if no more chunks).
ssize_t mChunkDataBytesLeft;
List<BandwidthEntry> mBandwidthHistory;
size_t mNumBandwidthHistoryItems;
int64_t mTotalTransferTimeUs;
size_t mTotalTransferBytes;
sp<DecryptHandle> mDecryptHandle;
DrmManagerClient *mDrmManagerClient;
@@ -114,7 +100,6 @@ private:
ssize_t internalRead(void *data, size_t size);
void applyTimeoutResponse();
void addBandwidthMeasurement_l(size_t numBytes, int64_t delayUs);
static void MakeFullHeaders(
const KeyedVector<String8, String8> *overrides,