Bug 1364001. P1 - add an API to throttle download.
MozReview-Commit-ID: HdmAgvo1GE3
--- a/dom/media/MediaCache.cpp
+++ b/dom/media/MediaCache.cpp
@@ -19,18 +19,20 @@
#include "nsIPrincipal.h"
#include "mozilla/Attributes.h"
#include "mozilla/Services.h"
#include <algorithm>
namespace mozilla {
#undef LOG
+#undef LOGI
LazyLogModule gMediaCacheLog("MediaCache");
#define LOG(...) MOZ_LOG(gMediaCacheLog, LogLevel::Debug, (__VA_ARGS__))
+#define LOGI(...) MOZ_LOG(gMediaCacheLog, LogLevel::Info, (__VA_ARGS__))
// Readahead blocks for non-seekable streams will be limited to this
// fraction of the cache space. We don't normally evict such blocks
// because replacing them requires a seek, but we need to make sure
// they don't monopolize the cache.
static const double NONSEEKABLE_READAHEAD_MAX = 0.5;
@@ -1238,22 +1240,24 @@ MediaCache::Update()
} else if (mIndex.Length() > uint32_t(maxBlocks)) {
// We're in the process of bringing the cache size back to the
// desired limit, so don't bring in more data yet
LOG("Stream %p throttling to reduce cache size", stream);
enableReading = false;
} else {
TimeDuration predictedNewDataUse = PredictNextUseForIncomingData(stream);
- if (stream->mCacheSuspended &&
+ if (stream->mThrottleReadahead &&
+ stream->mCacheSuspended &&
predictedNewDataUse.ToSeconds() > resumeThreshold) {
// Don't need data for a while, so don't bother waking up the stream
LOG("Stream %p avoiding wakeup since more data is not needed", stream);
enableReading = false;
- } else if (predictedNewDataUse.ToSeconds() > readaheadLimit) {
+ } else if (stream->mThrottleReadahead &&
+ predictedNewDataUse.ToSeconds() > readaheadLimit) {
// Don't read ahead more than this much
LOG("Stream %p throttling to avoid reading ahead too far", stream);
enableReading = false;
} else if (freeBlockCount > 0) {
// Free blocks in the cache, so keep reading
LOG("Stream %p reading since there are free blocks", stream);
enableReading = true;
} else if (latestNextUse <= TimeDuration(0)) {
@@ -2203,16 +2207,28 @@ MediaCacheStream::Seek(int32_t aWhence,
LOG("Stream %p Seek to %" PRId64, this, mStreamOffset);
gMediaCache->NoteSeek(this, oldOffset);
gMediaCache->QueueUpdate();
return NS_OK;
}
+void
+MediaCacheStream::ThrottleReadahead(bool bThrottle)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (mThrottleReadahead != bThrottle) {
+ LOGI("Stream %p ThrottleReadahead %d", this, bThrottle);
+ mThrottleReadahead = bThrottle;
+ ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
+ gMediaCache->QueueUpdate();
+ }
+}
+
int64_t
MediaCacheStream::Tell()
{
ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
return mStreamOffset;
}
nsresult
@@ -2485,8 +2501,9 @@ nsresult MediaCacheStream::GetCachedRang
}
return NS_OK;
}
} // namespace mozilla
// avoid redefined macro in unified build
#undef LOG
+#undef LOGI
--- a/dom/media/MediaCache.h
+++ b/dom/media/MediaCache.h
@@ -343,16 +343,18 @@ public:
// this will block until the data is available or the stream is
// closed, otherwise it won't block.
nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes);
// Seeks to aOffset in the stream then performs a Read operation. See
// 'Read' for argument and return details.
nsresult ReadAt(int64_t aOffset, char* aBuffer,
uint32_t aCount, uint32_t* aBytes);
+ void ThrottleReadahead(bool bThrottle);
+
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
private:
friend class MediaCache;
/**
* A doubly-linked list of blocks. Add/Remove/Get methods are all
* constant time. We declare this here so that a stream can contain a
@@ -509,13 +511,15 @@ private:
// mChannelOffset%BLOCK_SIZE bytes have been filled in with good data,
// the rest are garbage.
// Heap allocate this buffer since the exact power-of-2 will cause allocation
// slop when combined with the rest of the object members.
UniquePtr<uint8_t[]> mPartialBlockBuffer = MakeUnique<uint8_t[]>(BLOCK_SIZE);
// True if associated with a private browsing window.
const bool mIsPrivateBrowsing;
+
+ bool mThrottleReadahead = false;
};
} // namespace mozilla
#endif
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -711,16 +711,22 @@ ChannelMediaResource::MediaReadAt(int64_
aOffset += bytesRead;
aCount -= bytesRead;
curr += bytesRead;
}
bytes->SetLength(curr - start);
return bytes.forget();
}
+void
+ChannelMediaResource::ThrottleReadahead(bool bThrottle)
+{
+ mCacheStream.ThrottleReadahead(bThrottle);
+}
+
int64_t ChannelMediaResource::Tell()
{
return mCacheStream.Tell();
}
nsresult ChannelMediaResource::GetCachedRanges(MediaByteRangeSet& aRanges)
{
return mCacheStream.GetCachedRanges(aRanges);
--- a/dom/media/MediaResource.h
+++ b/dom/media/MediaResource.h
@@ -248,16 +248,21 @@ public:
bool ok = bytes->SetLength(aCount, fallible);
NS_ENSURE_TRUE(ok, nullptr);
char* curr = reinterpret_cast<char*>(bytes->Elements());
nsresult rv = ReadFromCache(curr, aOffset, aCount);
NS_ENSURE_SUCCESS(rv, nullptr);
return bytes.forget();
}
+ // Pass true to limit the amount of readahead data (specified by
+ // "media.cache_readahead_limit") or false to read as much as the
+ // cache size allows.
+ virtual void ThrottleReadahead(bool bThrottle) { }
+
// Report the current offset in bytes from the start of the stream.
// This is used to approximate where we currently are in the playback of a
// media.
// A call to ReadAt will update this position.
virtual int64_t Tell() = 0;
// Moves any existing channel loads into or out of background. Background
// loads don't block the load event. This also determines whether or not any
// new loads initiated (for example to seek) will be in the background.
@@ -551,16 +556,18 @@ public:
// MediaCacheStream::NotifyDataReceived/Ended.
// This can fail.
nsresult CacheClientSeek(int64_t aOffset, bool aResume);
// Suspend the current load since data is currently not wanted
nsresult CacheClientSuspend();
// Resume the current load since data is wanted again
nsresult CacheClientResume();
+ void ThrottleReadahead(bool bThrottle) override;
+
// Ensure that the media cache writes any data held in its partial block.
// Called on the main thread.
void FlushCache() override;
// Notify that the last data byte range was loaded.
void NotifyLastByteRange() override;
// Main thread