Bug 521176. Don't unnecessarily start an HTTP transaction when cloning a media resource. r=doublec
--- a/content/media/nsMediaCache.cpp
+++ b/content/media/nsMediaCache.cpp
@@ -2144,21 +2144,27 @@ nsMediaCacheStream::InitAsClone(nsMediaC
// Grab cache blocks from aOriginal as readahead blocks for our stream
nsAutoMonitor mon(gMediaCache->Monitor());
mPrincipal = aOriginal->mPrincipal;
mStreamLength = aOriginal->mStreamLength;
mIsSeekable = aOriginal->mIsSeekable;
+ // Cloned streams are initially suspended, since there is no channel open
+ // initially for a clone.
+ mCacheSuspended = PR_TRUE;
+
for (PRUint32 i = 0; i < aOriginal->mBlocks.Length(); ++i) {
PRInt32 cacheBlockIndex = aOriginal->mBlocks[i];
if (cacheBlockIndex < 0)
continue;
while (i >= mBlocks.Length()) {
mBlocks.AppendElement(-1);
}
+ // Every block is a readahead block for the clone because the clone's initial
+ // stream offset is zero
gMediaCache->AddBlockOwnerAsReadahead(cacheBlockIndex, this, i);
}
return NS_OK;
}
--- a/content/media/nsMediaStream.cpp
+++ b/content/media/nsMediaStream.cpp
@@ -381,16 +381,25 @@ nsresult nsMediaChannelStream::Open(nsIS
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
if (!mLock)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = mCacheStream.Init();
if (NS_FAILED(rv))
return rv;
NS_ASSERTION(mOffset == 0, "Who set mOffset already?");
+
+ if (!mChannel) {
+ // When we're a clone, the decoder might ask us to Open even though
+ // we haven't established an mChannel (because we might not need one)
+ NS_ASSERTION(!aStreamListener,
+ "Should have already been given a channel if we're to return a stream listener");
+ return NS_OK;
+ }
+
return OpenChannel(aStreamListener);
}
nsresult nsMediaChannelStream::OpenChannel(nsIStreamListener** aStreamListener)
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
NS_ENSURE_TRUE(mChannel, NS_ERROR_NULL_POINTER);
NS_ASSERTION(!mListener, "Listener should have been removed by now");
@@ -475,17 +484,24 @@ already_AddRefed<nsIPrincipal> nsMediaCh
}
nsMediaStream* nsMediaChannelStream::CloneData(nsMediaDecoder* aDecoder)
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
nsMediaChannelStream* stream = new nsMediaChannelStream(aDecoder, nsnull, mURI);
if (stream) {
- stream->RecreateChannel();
+ // Initially the clone is treated as suspended by the cache, because
+ // we don't have a channel. If the cache needs to read data from the clone
+ // it will call CacheClientResume (or CacheClientSeek with aResume true)
+ // which will recreate the channel. This way, if all of the media data
+ // is already in the cache we don't create an unneccesary HTTP channel
+ // and perform a useless HTTP transaction.
+ stream->mSuspendCount = 1;
+ stream->mCacheSuspendCount = 1;
stream->mCacheStream.InitAsClone(&mCacheStream);
}
return stream;
}
void nsMediaChannelStream::CloseChannel()
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
@@ -573,16 +589,17 @@ void nsMediaChannelStream::Resume()
NS_ASSERTION(mSuspendCount > 0, "Too many resumes!");
nsHTMLMediaElement* element = mDecoder->GetMediaElement();
if (!element) {
// Shutting down; do nothing.
return;
}
+ NS_ASSERTION(mSuspendCount > 0, "Resume without previous Suspend!");
--mSuspendCount;
if (mSuspendCount == 0) {
if (mChannel) {
// Just wake up our existing channel
{
nsAutoLock lock(mLock);
mChannelStatistics.Start(TimeStamp::Now());
}
@@ -683,16 +700,21 @@ nsMediaChannelStream::CacheClientSeek(PR
NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
CloseChannel();
if (aResume) {
NS_ASSERTION(mSuspendCount > 0, "Too many resumes!");
// No need to mess with the channel, since we're making a new one
--mSuspendCount;
+ {
+ nsAutoLock lock(mLock);
+ NS_ASSERTION(mCacheSuspendCount > 0, "CacheClientSeek(aResume=true) without previous CacheClientSuspend!");
+ --mCacheSuspendCount;
+ }
}
nsresult rv = RecreateChannel();
if (NS_FAILED(rv))
return rv;
mOffset = aOffset;
return OpenChannel(nsnull);
@@ -712,16 +734,17 @@ nsMediaChannelStream::CacheClientSuspend
}
nsresult
nsMediaChannelStream::CacheClientResume()
{
Resume();
{
nsAutoLock lock(mLock);
+ NS_ASSERTION(mCacheSuspendCount > 0, "CacheClientResume without previous CacheClientSuspend!");
--mCacheSuspendCount;
}
mDecoder->NotifySuspendedStatusChanged();
return NS_OK;
}
PRInt64