Saturday, 17 October 2009

Yesterday I checked in a patch that removes support for the 'load' event on <video> and <audio> elements. We simply never fire it. Also, the networkState attribute is now never NETWORK_LOADED. When we've read to the end of the media resource, networkState changes to NETWORK_IDLE. We plan to ship this change for Firefox 3.6.

There are several reasons we're doing this, even though it will break some Web content. One reason is that the spec says that 'load' should only fire when/if we guarantee that we will never again hit the network for data for that media resource. We never guarantee this, because our cache may always discard data. For example if you play through a large media file that doesn't fit in the cache, we'll read from the network again if you seek back to the beginning. If you play through a resource that does fit in the cache, and then play another large resource we might evict blocks from the first resource to make room for the second resource. So we never followed the spec here, and if we do follow the spec then we can never fire the 'load' event.

Another reason is that 'load' is a dangerous and fairly useless event. Web authors expect that every media element will eventually receive a 'load' event, because documents and images do, right? But that expectation is in vain, in many situations a 'load' event will never be fired. Furthermore authors cannot predict those situations because they depend on client cache size and policy. It is quite likely that the author will always get 'load' events during testing but some clients won't get a 'load' event and the site will be broken for those clients. So since the 'load' event won't ever fire in some browsers, and in other browsers will fail to fire in unpredictable situations, authors should never use it. In practice we see authors inappropriately using 'load' when they should be using another event like 'canplaythrough' or 'suspend'.

In fact, this argument is persuasive enough that 'load' for media elements and the NETWORK_LOADED state have been removed from the spec. There was consensus from Mozilla, Google, Apple and Opera developers that this is the right thing to do. I expect that other browsers will be following suit soon; in fact, apparently Chrome has never fired a 'load' event on media elements.

If you have been using 'load' on your <video> or <audio> elements, you should use a different event. There are several to choose from depending on what you actually want:

If you want to do something when the video metadata is available (e.g. duration or size), use 'loadedmetadata'.

If you want to do something when the first frame of video can be displayed, use 'loadeddata'.

If you want to do something when the browser has stopped downloading the resource, use 'suspend'. Note however that the browser might stop before reaching the end of the resource, e.g. if its cache fills up, or the element doesn't have 'autobuffer' set.

If you want to do something when there's enough data loaded to start playing, use 'canplay'.

If you want to do something when there's enough data loaded to start playing and playback should be able to make it to the end without stalling on the network, use 'canplaythrough'. Note however that 'canplaythrough' might not fire because the browser's cache fills up, in which case you'll get a 'suspend'.

If you want to do something when the video has finished playing, use 'ended'.

Monday, 5 October 2009

We had a great time visiting relatives in Melbourne. During the week we took a three-day road trip along the Great Ocean Road southwest to the Twelve Apostles rock formations, then north to Hall's Gap in the Grampian mountains before returning to Melbourne. We did a lot of short walks --- at Anglesea, Marriner's Lookout, Maits Rest, the Cape Otway lighthouse, the Gibson Steps, the Loch Ard gorge, Chautauqua Peak, and McKenzie Falls. Along the way we saw wild koalas, kangaroos and wallabies. The Great Ocean Road reminded me of Big Sur. The stories of shipwrecks, settlers, hardship and survival were inspiring. A great trip.

One tip: a brochure claimed the return trip to the base of McKenzie Falls takes one hour and twenty minutes, so I almost skipped it, but we did it in twenty-five minutes, with two five-year-old kids. It's well worth it!