Bug 687972. Try 2: Run autoplay for an element after reaching loadedmetadata if all download streams for its resource are suspended by the media cache. r=cpearce

This commit is contained in:
Robert O'Callahan 2011-11-30 18:05:49 +13:00
Родитель 2459a6d110
Коммит 2768e1cac2
6 изменённых файлов: 57 добавлений и 24 удалений

Просмотреть файл

@ -2064,10 +2064,6 @@ void nsHTMLMediaElement::MetadataLoaded(PRUint32 aChannels, PRUint32 aRate)
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata"));
if (!mBegun) {
// Something ended our downloaded. We're probably done with downloading already.
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
}
if (mDecoder && mDecoder->IsSeekable()) {
ProcessMediaFragmentURI();
mDecoder->SetEndTime(mFragmentEnd);

Просмотреть файл

@ -451,6 +451,9 @@ void nsBuiltinDecoder::MetadataLoaded(PRUint32 aChannels,
mElement->FirstFrameLoaded(resourceIsLoaded);
}
// This can run cache callbacks.
mStream->EnsureCacheUpToDate();
// The element can run javascript via events
// before reaching here, so only change the
// state if we're still set to the original
@ -467,6 +470,10 @@ void nsBuiltinDecoder::MetadataLoaded(PRUint32 aChannels,
if (resourceIsLoaded) {
ResourceLoaded();
}
// Run NotifySuspendedStatusChanged now to give us a chance to notice
// that autoplay should run.
NotifySuspendedStatusChanged();
}
void nsBuiltinDecoder::ResourceLoaded()

Просмотреть файл

@ -1369,6 +1369,8 @@ nsMediaCache::Update()
break;
}
stream->mHasHadUpdate = true;
if (NS_FAILED(rv)) {
// Close the streams that failed due to error. This will cause all
// client Read and Seek operations on those streams to fail. Blocked
@ -1885,6 +1887,18 @@ nsMediaCacheStream::IsSeekable()
return mIsSeekable;
}
bool
nsMediaCacheStream::AreAllStreamsForResourceSuspended()
{
ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
nsMediaCache::ResourceStreamIterator iter(mResourceID);
while (nsMediaCacheStream* stream = iter.Next()) {
if (!stream->mCacheSuspended)
return false;
}
return true;
}
void
nsMediaCacheStream::Close()
{
@ -1898,6 +1912,14 @@ nsMediaCacheStream::Close()
gMediaCache->QueueUpdate();
}
void
nsMediaCacheStream::EnsureCacheUpdate()
{
if (mHasHadUpdate)
return;
gMediaCache->Update();
}
void
nsMediaCacheStream::CloseInternal(ReentrantMonitorAutoEnter& aReentrantMonitor)
{

Просмотреть файл

@ -227,6 +227,7 @@ public:
// data for this stream.
nsMediaCacheStream(nsMediaChannelStream* aClient)
: mClient(aClient), mResourceID(0), mInitialized(false),
mHasHadUpdate(false),
mIsSeekable(false), mCacheSuspended(false),
mDidNotifyDataEnded(false),
mUsingNullPrincipal(false),
@ -263,6 +264,11 @@ public:
bool IsClosed() const { return mClosed; }
// Get the principal for this stream.
nsIPrincipal* GetCurrentPrincipal() { return mPrincipal; }
// Ensure a global media cache update has run with this stream present.
// This ensures the cache has had a chance to suspend or unsuspend this stream.
// Called only on main thread. This can change the state of streams, fire
// notifications, etc.
void EnsureCacheUpdate();
// These callbacks are called on the main thread by the client
// when data has been received via the channel.
@ -346,6 +352,9 @@ public:
// Returns the last set value of SetSeekable.
bool IsSeekable();
// Returns true when all streams for this resource are suspended.
bool AreAllStreamsForResourceSuspended();
// These methods must be called on a different thread from the main
// thread. They should always be called on the same thread for a given
// stream.
@ -447,6 +456,9 @@ private:
PRInt64 mResourceID;
// Set to true when Init or InitAsClone has been called
bool mInitialized;
// Set to true when nsMediaCache::Update() has finished while this stream
// was present.
bool mHasHadUpdate;
// The following fields are protected by the cache's monitor but are
// only written on the main thread.

Просмотреть файл

@ -74,7 +74,6 @@ nsMediaChannelStream::nsMediaChannelStream(nsMediaDecoder* aDecoder,
mReopenOnError(false), mIgnoreClose(false),
mCacheStream(this),
mLock("nsMediaChannelStream.mLock"),
mCacheSuspendCount(0),
mIgnoreResume(false)
{
}
@ -547,8 +546,9 @@ nsMediaStream* nsMediaChannelStream::CloneData(nsMediaDecoder* aDecoder)
// 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);
stream->mChannelStatistics = mChannelStatistics;
stream->mChannelStatistics.Stop(TimeStamp::Now());
}
return stream;
}
@ -770,11 +770,6 @@ nsMediaChannelStream::CacheClientSeek(PRInt64 aOffset, bool aResume)
NS_ASSERTION(mSuspendCount > 0, "Too many resumes!");
// No need to mess with the channel, since we're making a new one
--mSuspendCount;
{
MutexAutoLock lock(mLock);
NS_ASSERTION(mCacheSuspendCount > 0, "CacheClientSeek(aResume=true) without previous CacheClientSuspend!");
--mCacheSuspendCount;
}
}
nsresult rv = RecreateChannel();
@ -788,10 +783,6 @@ nsMediaChannelStream::CacheClientSeek(PRInt64 aOffset, bool aResume)
nsresult
nsMediaChannelStream::CacheClientSuspend()
{
{
MutexAutoLock lock(mLock);
++mCacheSuspendCount;
}
Suspend(false);
mDecoder->NotifySuspendedStatusChanged();
@ -802,11 +793,6 @@ nsresult
nsMediaChannelStream::CacheClientResume()
{
Resume();
{
MutexAutoLock lock(mLock);
NS_ASSERTION(mCacheSuspendCount > 0, "CacheClientResume without previous CacheClientSuspend!");
--mCacheSuspendCount;
}
mDecoder->NotifySuspendedStatusChanged();
return NS_OK;
@ -830,11 +816,16 @@ nsMediaChannelStream::IsDataCachedToEndOfStream(PRInt64 aOffset)
return mCacheStream.IsDataCachedToEndOfStream(aOffset);
}
void
nsMediaChannelStream::EnsureCacheUpToDate()
{
mCacheStream.EnsureCacheUpdate();
}
bool
nsMediaChannelStream::IsSuspendedByCache()
{
MutexAutoLock lock(mLock);
return mCacheSuspendCount > 0;
return mCacheStream.AreAllStreamsForResourceSuspended();
}
bool

Просмотреть файл

@ -236,6 +236,9 @@ public:
// block the load event. Any new loads initiated (for example to seek)
// will also be in the background.
void MoveLoadsToBackground();
// Ensures that the value returned by IsSuspendedByCache below is up to date
// (i.e. the cache has examined this stream at least once).
virtual void EnsureCacheUpToDate() {}
// These can be called on any thread.
// Cached blocks associated with this stream will not be evicted
@ -267,6 +270,8 @@ public:
// data, otherwise we may not be able to make progress.
// nsMediaDecoder::NotifySuspendedStatusChanged is called when this
// changes.
// For resources using the media cache, this returns true only when all
// streams for the same resource are all suspended.
virtual bool IsSuspendedByCache() = 0;
// Returns true if this stream has been suspended.
virtual bool IsSuspended() = 0;
@ -382,6 +387,7 @@ public:
bool IsClosed() const { return mCacheStream.IsClosed(); }
virtual nsMediaStream* CloneData(nsMediaDecoder* aDecoder);
virtual nsresult ReadFromCache(char* aBuffer, PRInt64 aOffset, PRUint32 aCount);
virtual void EnsureCacheUpToDate();
// Other thread
virtual void SetReadMode(nsMediaCacheStream::ReadMode aMode);
@ -475,10 +481,9 @@ protected:
// Any thread access
nsMediaCacheStream mCacheStream;
// This lock protects mChannelStatistics and mCacheSuspendCount
// This lock protects mChannelStatistics
Mutex mLock;
nsChannelStatistics mChannelStatistics;
PRUint32 mCacheSuspendCount;
// True if we couldn't suspend the stream and we therefore don't want
// to resume later. This is usually due to the channel not being in the