Bug 1427699. P2 - rewrite InitAsCloneInternal() to mimic the case where data is downloaded from a channel.
Note we add mClient->CacheClientSuspend() so the network state of the element
is changed to IDLE because we have no channel to fetch data initially.
MozReview-Commit-ID: DgJbMxvJBzH
--- a/dom/media/ChannelMediaResource.cpp
+++ b/dom/media/ChannelMediaResource.cpp
@@ -25,17 +25,17 @@ mozilla::LazyLogModule gMediaResourceLog
namespace mozilla {
ChannelMediaResource::ChannelMediaResource(MediaResourceCallback* aCallback,
nsIChannel* aChannel,
nsIURI* aURI,
bool aIsPrivateBrowsing)
: BaseMediaResource(aCallback, aChannel, aURI)
, mCacheStream(this, aIsPrivateBrowsing)
- , mSuspendAgent(mCacheStream, !aChannel /*aSuspended*/)
+ , mSuspendAgent(mCacheStream)
{
}
ChannelMediaResource::~ChannelMediaResource()
{
MOZ_ASSERT(mClosed);
MOZ_ASSERT(!mChannel);
MOZ_ASSERT(!mListener);
--- a/dom/media/ChannelMediaResource.h
+++ b/dom/media/ChannelMediaResource.h
@@ -18,19 +18,18 @@ namespace mozilla {
/**
* This class is responsible for managing the suspend count and report suspend
* status of channel.
**/
class ChannelSuspendAgent
{
public:
- ChannelSuspendAgent(MediaCacheStream& aCacheStream, bool aSuspended)
+ explicit ChannelSuspendAgent(MediaCacheStream& aCacheStream)
: mCacheStream(aCacheStream)
- , mSuspendCount(aSuspended ? 1 : 0)
{
}
// True when the channel has been suspended or needs to be suspended.
bool IsSuspended();
// Return true when the channel is logically suspended, i.e. the suspend
// count goes from 0 to 1.
@@ -45,17 +44,17 @@ public:
void Revoke();
private:
// Only suspends channel but not changes the suspend count.
void SuspendInternal();
nsIChannel* mChannel = nullptr;
MediaCacheStream& mCacheStream;
- uint32_t mSuspendCount;
+ uint32_t mSuspendCount = 0;
bool mIsChannelSuspended = false;
};
DDLoggedTypeDeclNameAndBase(ChannelMediaResource, BaseMediaResource);
/**
* This is the MediaResource implementation that wraps Necko channels.
* Much of its functionality is actually delegated to MediaCache via
--- a/dom/media/MediaCache.cpp
+++ b/dom/media/MediaCache.cpp
@@ -2869,57 +2869,42 @@ MediaCacheStream::Init(int64_t aContentL
void
MediaCacheStream::InitAsClone(MediaCacheStream* aOriginal)
{
MOZ_ASSERT(!mMediaCache, "Has been initialized.");
MOZ_ASSERT(aOriginal->mMediaCache, "Don't clone an uninitialized stream.");
// Use the same MediaCache as our clone.
mMediaCache = aOriginal->mMediaCache;
- // This needs to be done before OpenStream() to avoid data race.
- mClientSuspended = true;
- // Cloned streams are initially suspended, since there is no channel open
- // initially for a clone.
- mCacheSuspended = true;
- mChannelEnded = true;
-
OwnerThread()->Dispatch(
NS_NewRunnableFunction("MediaCacheStream::InitAsClone", [
this,
aOriginal,
r1 = RefPtr<ChannelMediaResource>(mClient),
r2 = RefPtr<ChannelMediaResource>(aOriginal->mClient)
]() { InitAsCloneInternal(aOriginal); }));
}
void
MediaCacheStream::InitAsCloneInternal(MediaCacheStream* aOriginal)
{
MOZ_ASSERT(OwnerThread()->IsOnCurrentThread());
- AutoLock lock(aOriginal->mMediaCache->Monitor());
+ AutoLock lock(mMediaCache->Monitor());
+ // Download data and notify events if necessary. Note the order is important
+ // in order to mimic the behavior of data being downloaded from the channel.
+
+ // Step 1: copy/download data from the original stream.
mResourceID = aOriginal->mResourceID;
-
- // Grab cache blocks from aOriginal as readahead blocks for our stream
mStreamLength = aOriginal->mStreamLength;
mIsTransportSeekable = aOriginal->mIsTransportSeekable;
mDownloadStatistics = aOriginal->mDownloadStatistics;
mDownloadStatistics.Stop();
- // Notify the client that we have new data so the decoder has a chance to
- // compute 'canplaythrough' and buffer ranges.
- mClient->CacheClientNotifyDataReceived();
-
- if (aOriginal->mDidNotifyDataEnded &&
- NS_SUCCEEDED(aOriginal->mNotifyDataEndedStatus)) {
- mNotifyDataEndedStatus = aOriginal->mNotifyDataEndedStatus;
- mDidNotifyDataEnded = true;
- mClient->CacheClientNotifyDataEnded(mNotifyDataEndedStatus);
- }
-
+ // Grab cache blocks from aOriginal as readahead blocks for our stream
for (uint32_t i = 0; i < aOriginal->mBlocks.Length(); ++i) {
int32_t cacheBlockIndex = aOriginal->mBlocks[i];
if (cacheBlockIndex < 0)
continue;
while (i >= mBlocks.Length()) {
mBlocks.AppendElement(-1);
}
@@ -2929,18 +2914,36 @@ MediaCacheStream::InitAsCloneInternal(Me
}
// Copy the partial block.
mChannelOffset = aOriginal->mChannelOffset;
memcpy(mPartialBlockBuffer.get(),
aOriginal->mPartialBlockBuffer.get(),
BLOCK_SIZE);
+ // Step 2: notify the client that we have new data so the decoder has a chance
+ // to compute 'canplaythrough' and buffer ranges.
+ mClient->CacheClientNotifyDataReceived();
+
+ // Step 3: notify download ended if necessary.
+ if (aOriginal->mDidNotifyDataEnded &&
+ NS_SUCCEEDED(aOriginal->mNotifyDataEndedStatus)) {
+ mNotifyDataEndedStatus = aOriginal->mNotifyDataEndedStatus;
+ mDidNotifyDataEnded = true;
+ mClient->CacheClientNotifyDataEnded(mNotifyDataEndedStatus);
+ }
+
+ // Step 4: notify download is suspended by the cache.
+ mClientSuspended = true;
+ mCacheSuspended = true;
+ mChannelEnded = true;
+ mClient->CacheClientSuspend();
+
+ // Step 5: add the stream to be managed by the cache.
mMediaCache->OpenStream(lock, this, true /* aIsClone */);
-
// Wake up the reader which is waiting for the cloned data.
lock.NotifyAll();
}
nsIEventTarget*
MediaCacheStream::OwnerThread() const
{
return mMediaCache->OwnerThread();