If none of the < source > tags provided for an HTML5 < video > tag are playable, I want to display an error.
According to this page on the Mozilla Developer Network, it seems I have to check the networkState property of the video element to see if any sources loaded, as each seperate source tag throws its own error when it fails to load.
To detect that all child elements have failed to load, check the value of the media element's networkState attribute. If this is HTMLMediaElement.NETWORK_NO_SOURCE, you know that all the sources failed to load.
But at what point should I check the networkState? If I check immediately on calling video_tag.load(), it always tells me the networkState is NETWORK_NO_SOURCE even if the source elements are valid and the video plays fine. Therefore, I assume I hvae to wait until the source tags have been tried by the browser.
Here's the test:
var state = this._video_tag.networkState;
console.log( 'networkState', state );
if( state == this._video_tag.NETWORK_NO_SOURCE )
{
throw new Error( 'No valid sources' );
}
I have tried all of the following video element events with invalid source tags: loadstart, loadedmetadata, loadeddata & error with the following results (in Firefox):
However, if I check out the video tag in Firebug, the networkState is NETWORK_NO_SOURCE just as expected.
What event should I be using to control when to check the video tag, or is there a better way of doing this?
If you are using source tags you can set the onerror attribute on the last source tag in the list instead. See the bottom of section 4.8.8 on this page for more details.
Quote from that reference:
If the author isn't sure if user agents will all be able to render the media resources provided, the author can listen to the error event on the last source element and trigger fallback behavior:
<script> function fallback(video) { // replace <video> with its contents while (video.hasChildNodes()) { if (video.firstChild instanceof HTMLSourceElement) video.removeChild(video.firstChild); else video.parentNode.insertBefore(video.firstChild, video); } video.parentNode.removeChild(video); } </script> <video controls autoplay> <source src='video.mp4' type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'> <source src='video.ogv' type='video/ogg; codecs="theora, vorbis"' onerror="fallback(parentNode)"> ... </video>
This example isn't perfect because you don't get the event object like you do when the onerror attribute is on the video tag (which only works if you have a src attribute in the video tag instead of in a series of tags. However, I believe you can then retrieve the error state from the video tag with the networkState JS variable on that tag. I haven't tested that though. So it is up to you at that point. It sounds like what I have here might be satisfactory for your needs.
Notes:
While you can instead listen for an "error" event on the last source tag, I found that this was unreliable. In cases where the preload attribute is not set to none, I could not find a way to reliably add a listener for the event before the event fired. This forced me to use the onerror attribute.
If you do find a way to reliably listen for the event I wanted to add this note. According to this Chromium issue the error event on the source tag does NOT bubble which means that you have to listen to it on that specific tag.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With