Bug 479863. AdFire 'suspend' event and do correct networkState transitions when downloads suspend and resume. Also avoid firing 'stalled' while the download is suspended. r=doublec

--HG--
extra : rebase_source : 0615871c062638d575a66e29b630040821a9f9cf
This commit is contained in:
Robert O'Callahan 2009-05-18 14:03:37 +12:00
Родитель 72572eda3e
Коммит 786308b090
7 изменённых файлов: 97 добавлений и 26 удалений

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

@ -128,6 +128,20 @@ public:
// when the resource has completed seeking.
void SeekCompleted();
// Called by the media stream, on the main thread, when the download
// has been suspended by the cache or because the element itself
// asked the decoder to suspend the download.
void DownloadSuspended();
// Called by the media stream, on the main thread, when the download
// has been resumed by the cache or because the element itself
// asked the decoder to resumed the download.
void DownloadResumed();
// Called by the media decoder to indicate that the download has stalled
// (no data has arrived for a while).
void DownloadStalled();
// Draw the latest video data. See nsMediaDecoder for
// details.
void Paint(gfxContext* aContext,

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

@ -617,8 +617,6 @@ nsresult nsHTMLMediaElement::LoadWithChannel(nsIChannel *aChannel,
return rv;
}
mBegun = PR_TRUE;
DispatchAsyncProgressEvent(NS_LITERAL_STRING("loadstart"));
return NS_OK;
@ -1196,6 +1194,8 @@ nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel,
rv = mDecoder->Play();
}
mBegun = PR_TRUE;
return rv;
}
@ -1291,6 +1291,28 @@ void nsHTMLMediaElement::SeekCompleted()
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("seeked"));
}
void nsHTMLMediaElement::DownloadSuspended()
{
if (mBegun) {
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("suspend"));
}
}
void nsHTMLMediaElement::DownloadResumed()
{
if (mBegun) {
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
}
}
void nsHTMLMediaElement::DownloadStalled()
{
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
DispatchAsyncProgressEvent(NS_LITERAL_STRING("stalled"));
}
}
PRBool nsHTMLMediaElement::ShouldCheckAllowOrigin()
{
return nsContentUtils::GetBoolPref("media.enforce_same_site_origin",

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

@ -985,9 +985,11 @@ nsMediaCache::Update()
PRBool enableReading;
if (stream->mStreamLength >= 0 &&
desiredOffset >= stream->mStreamLength) {
// We're at the end of the stream. Nothing to read.
// We're at the end of the stream. Nothing to read, but we don't
// need to suspend, we may as well just keep reading and hit EOF
// (or discover more data if the server lied to us).
LOG(PR_LOG_DEBUG, ("Stream %p at end of stream", stream));
enableReading = PR_FALSE;
enableReading = PR_TRUE;
} else if (desiredOffset < stream->mStreamOffset) {
// We're reading to try to catch up to where the current stream
// reader wants to be. Better not stop.

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

@ -171,7 +171,7 @@ void nsMediaDecoder::Progress(PRBool aTimer)
if (!mDataTime.IsNull() &&
now - mDataTime >= TimeDuration::FromMilliseconds(STALL_MS)) {
mElement->DispatchAsyncProgressEvent(NS_LITERAL_STRING("stalled"));
mElement->DownloadStalled();
// Null it out
mDataTime = TimeStamp();
}

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

@ -501,17 +501,25 @@ void nsMediaChannelStream::Suspend(PRBool aCloseImmediately)
{
NS_ASSERTION(NS_IsMainThread(), "Don't call on main thread");
nsHTMLMediaElement* element = mDecoder->GetMediaElement();
if (!element) {
// Shutting down; do nothing.
return;
}
if (mChannel) {
if (aCloseImmediately && mCacheStream.IsSeekable()) {
// Kill off our channel right now, but don't tell anyone about it.
mIgnoreClose = PR_TRUE;
CloseChannel();
element->DownloadSuspended();
} else if (mSuspendCount == 0) {
{
nsAutoLock lock(mLock);
mChannelStatistics.Stop(TimeStamp::Now());
}
mChannel->Suspend();
element->DownloadSuspended();
}
}
@ -523,6 +531,12 @@ void nsMediaChannelStream::Resume()
NS_ASSERTION(NS_IsMainThread(), "Don't call on main thread");
NS_ASSERTION(mSuspendCount > 0, "Too many resumes!");
nsHTMLMediaElement* element = mDecoder->GetMediaElement();
if (!element) {
// Shutting down; do nothing.
return;
}
--mSuspendCount;
if (mSuspendCount == 0) {
if (mChannel) {
@ -535,9 +549,11 @@ void nsMediaChannelStream::Resume()
// timed out the connection and we should reopen it.
mReopenOnError = PR_TRUE;
mChannel->Resume();
element->DownloadResumed();
} else {
// Need to recreate the channel
CacheClientSeek(mOffset, PR_FALSE);
element->DownloadResumed();
}
}
}

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

@ -17,9 +17,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=479863
</div>
<video id='v1' onerror="event.stopPropagation()"></video>
<video id='v2' onerror="event.stopPropagation()" autobuffer></video>
<video id='v3' onerror="event.stopPropagation()" autoplay></video>
<video id='v4' onerror="event.stopPropagation()"></video>
<video id='v5' onerror="event.stopPropagation()"></video>
<video id='v6' onerror="event.stopPropagation()"></video>
<pre id="test">
<script type="application/javascript">
var stalls = { v1:false, v2:false, v3:false, v4:false, v5:false, v6:false };
var loads = { v1:false, v2:false, v3:false, v4:false, v5:false, v6:false };
var suspends = {};
var loads = {};
var totalLoadEvents = 0;
var expectedLoadEvents = 6;
@ -27,13 +35,12 @@ function loaded(event) {
loads[event.target.id] = true;
++totalLoadEvents;
if (totalLoadEvents == expectedLoadEvents) {
ok(stalls.v1, "v1 should stall");
// We might get accidental stalls on very slow machines, so lets not test these
// ok(!stalls.v2, "v2 should not stall");
// ok(!stalls.v3, "v3 should not stall");
ok(stalls.v4, "v4 should stall");
ok(stalls.v5, "v5 should stall");
ok(stalls.v6, "v6 should stall");
ok(suspends.v1, "v1 should suspend");
ok(!suspends.v2, "v2 should not suspend");
ok(!suspends.v3, "v3 should not suspend");
ok(suspends.v4, "v4 should suspend");
ok(suspends.v5, "v5 should suspend");
ok(suspends.v6, "v6 should suspend");
ok(loads.v1, "v1 should load after setting autobuffer");
ok(loads.v2, "v2 should load");
ok(loads.v3, "v3 should load");
@ -43,8 +50,11 @@ function loaded(event) {
SimpleTest.finish();
}
}
function stalled(event) {
stalls[event.target.id] = true;
function suspended(event) {
is(event.target.networkState, event.target.NETWORK_IDLE,
event.target.id + " suspended networkState");
suspends[event.target.id] = true;
if (event.target.id == "v1") {
event.target.autobuffer = true;
} else if (event.target.id == "v4") {
@ -55,17 +65,24 @@ function stalled(event) {
event.target.autoplay = true;
}
}
</script>
<video id='v1' src="seek.ogv" onstalled="stalled(event)" onload="loaded(event)"></video>
<video id='v2' src="seek.ogv" onstalled="stalled(event)" onload="loaded(event)" autobuffer></video>
<video id='v3' src="seek.ogv" onstalled="stalled(event)" onload="loaded(event)" autoplay></video>
<video id='v4' src="seek.ogv" onstalled="stalled(event)" onload="loaded(event)"></video>
<video id='v5' src="seek.ogv" onstalled="stalled(event)" onload="loaded(event)"></video>
<video id='v6' src="seek.ogv" onstalled="stalled(event)" onload="loaded(event)"></video>
function logEvent(event) {
dump(event.type + " " + event.target.id + "\n");
}
<pre id="test">
<script type="application/javascript">
var key = Math.random();
var eventList = ["metadataloaded", "loadeddata", "playing", "load", "stalled", "suspend", "ended"];
for (var i = 1; i <= expectedLoadEvents; ++i) {
var id = "v" + i;
suspends[id] = loads[id] = false;
var v = document.getElementById(id);
v.addEventListener("suspend", suspended, false);
v.addEventListener("load", loaded, false);
for (var n = 0; n < eventList.length; ++n) {
v.addEventListener(eventList[n], logEvent, false);
}
v.src = "seek.ogv?key=" + key + "&id=" + id;
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>

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

@ -24,7 +24,7 @@ function log(msg) {
// We don't track: progress, canplay, canplaythrough and stalled events,
// as these can be delivered out of order, and/or multiple times.
var gEventTypes = [ 'loadstart', 'suspend', 'load', 'abort', 'error', 'emptied', 'play', 'pause', 'loadedmetadata', 'loadeddata', 'waiting', 'playing', 'seeking', 'seeked', 'timeupdate', 'ended', 'ratechange', 'durationchange', 'volumechange' ];
var gEventTypes = [ 'loadstart', 'load', 'abort', 'error', 'emptied', 'play', 'pause', 'loadedmetadata', 'loadeddata', 'waiting', 'playing', 'seeking', 'seeked', 'timeupdate', 'ended', 'ratechange', 'durationchange', 'volumechange' ];
var gEventNum = 0;
var gTestNum = 0;