diff --git a/content/html/content/public/nsHTMLMediaElement.h b/content/html/content/public/nsHTMLMediaElement.h index 509b8b1c3f26..11167b743862 100644 --- a/content/html/content/public/nsHTMLMediaElement.h +++ b/content/html/content/public/nsHTMLMediaElement.h @@ -118,6 +118,10 @@ public: // when the resource has a network error during loading. void NetworkError(); + // Called by the video decoder object, on the main thread, when the + // resource has a decode error during metadata loading or decoding. + void DecodeError(); + // Called by the video decoder object, on the main thread, // when the video playback has ended. void PlaybackEnded(); @@ -309,11 +313,11 @@ protected: nsresult NewURIFromString(const nsAutoString& aURISpec, nsIURI** aURI); /** - * Called when all postential resources are exhausted. Changes network + * Called when all potential resources are exhausted. Changes network * state to NETWORK_NO_SOURCE, and sends error event with code - * MEDIA_ERR_NONE_SUPPORTED. + * MEDIA_ERR_SRC_NOT_SUPPORTED. */ - void NoSupportedMediaError(); + void NoSupportedMediaSourceError(); /** * Attempts to load resources from the children. This is a diff --git a/content/html/content/src/nsHTMLMediaElement.cpp b/content/html/content/src/nsHTMLMediaElement.cpp index 70b226e99460..9d0d02e3bc84 100644 --- a/content/html/content/src/nsHTMLMediaElement.cpp +++ b/content/html/content/src/nsHTMLMediaElement.cpp @@ -234,7 +234,7 @@ NS_IMETHODIMP nsHTMLMediaElement::MediaLoadListener::OnStartRequest(nsIRequest* // error. if (NS_FAILED(rv) && !mNextListener && element) { // Load failed, attempt to load the next candidate resource. If there - // are none, this will trigger a MEDIA_ERR_NONE_SUPPORTED error. + // are none, this will trigger a MEDIA_ERR_SRC_NOT_SUPPORTED error. element->NotifyLoadError(); } // If InitializeDecoderForChannel did not return a listener (but may @@ -407,9 +407,9 @@ void nsHTMLMediaElement::AbortExistingLoads() mIsRunningSelectResource = PR_FALSE; } -void nsHTMLMediaElement::NoSupportedMediaError() +void nsHTMLMediaElement::NoSupportedMediaSourceError() { - mError = new nsHTMLMediaError(nsIDOMHTMLMediaError::MEDIA_ERR_NONE_SUPPORTED); + mError = new nsHTMLMediaError(nsIDOMHTMLMediaError::MEDIA_ERR_SRC_NOT_SUPPORTED); mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE; DispatchAsyncProgressEvent(NS_LITERAL_STRING("error")); ChangeDelayLoadStatus(PR_FALSE); @@ -479,7 +479,7 @@ void nsHTMLMediaElement::SelectResource() if (NS_SUCCEEDED(rv)) return; } - NoSupportedMediaError(); + NoSupportedMediaSourceError(); } else { // Otherwise, the source elements will be used. LoadFromSourceChildren(); @@ -489,7 +489,7 @@ void nsHTMLMediaElement::SelectResource() void nsHTMLMediaElement::NotifyLoadError() { if (mIsLoadingFromSrcAttribute) { - NoSupportedMediaError(); + NoSupportedMediaSourceError(); } else { QueueLoadFromSourceTask(); } @@ -506,7 +506,7 @@ void nsHTMLMediaElement::LoadFromSourceChildren() // Exhausted candidates, wait for more candidates to be appended to // the media element. mLoadWaitStatus = WAITING_FOR_SOURCE; - NoSupportedMediaError(); + NoSupportedMediaSourceError(); return; } @@ -1370,6 +1370,16 @@ void nsHTMLMediaElement::NetworkError() ChangeDelayLoadStatus(PR_FALSE); } +void nsHTMLMediaElement::DecodeError() +{ + mError = new nsHTMLMediaError(nsIDOMHTMLMediaError::MEDIA_ERR_DECODE); + mBegun = PR_FALSE; + DispatchAsyncProgressEvent(NS_LITERAL_STRING("error")); + mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY; + DispatchAsyncSimpleEvent(NS_LITERAL_STRING("emptied")); + ChangeDelayLoadStatus(PR_FALSE); +} + void nsHTMLMediaElement::PlaybackEnded() { NS_ASSERTION(mDecoder->IsEnded(), "Decoder fired ended, but not in ended state"); diff --git a/content/media/ogg/nsOggDecoder.cpp b/content/media/ogg/nsOggDecoder.cpp index d992e6d3dd5c..1e66d61425e2 100644 --- a/content/media/ogg/nsOggDecoder.cpp +++ b/content/media/ogg/nsOggDecoder.cpp @@ -746,7 +746,7 @@ void nsOggDecodeStateMachine::HandleDecodeErrors(OggPlayErrorCode aErrorCode) aErrorCode != E_OGGPLAY_CONTINUE) { mState = DECODER_STATE_SHUTDOWN; nsCOMPtr event = - NS_NEW_RUNNABLE_METHOD(nsOggDecoder, mDecoder, NetworkError); + NS_NEW_RUNNABLE_METHOD(nsOggDecoder, mDecoder, DecodeError); NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); } } @@ -1764,7 +1764,7 @@ void nsOggDecodeStateMachine::LoadOggHeaders(nsChannelReader* aReader) LOG(PR_LOG_DEBUG, ("Frame rate: %f", mFramerate)); int aspectd, aspectn; - // this can return E_OGGPLAY_UNINITIALIZED if the video has + // this can return E_OGGPLAY_UNINITIALISED if the video has // no aspect ratio data. We assume 1.0 in that case. OggPlayErrorCode r = oggplay_get_video_aspect_ratio(mPlayer, i, &aspectd, &aspectn); @@ -1785,6 +1785,12 @@ void nsOggDecodeStateMachine::LoadOggHeaders(nsChannelReader* aReader) } } + if (mVideoTrack == -1 && mAudioTrack == -1) { + nsAutoMonitor mon(mDecoder->GetMonitor()); + HandleDecodeErrors(E_OGGPLAY_UNINITIALISED); + return; + } + SetTracksActive(); if (mVideoTrack == -1) { @@ -2162,6 +2168,17 @@ void nsOggDecoder::NetworkError() Shutdown(); } +void nsOggDecoder::DecodeError() +{ + if (mShuttingDown) + return; + + if (mElement) + mElement->DecodeError(); + + Shutdown(); +} + PRBool nsOggDecoder::IsSeeking() const { return mPlayState == PLAY_STATE_SEEKING || mNextState == PLAY_STATE_SEEKING; diff --git a/content/media/ogg/nsOggDecoder.h b/content/media/ogg/nsOggDecoder.h index a0f531b6ae91..8222036b64bd 100644 --- a/content/media/ogg/nsOggDecoder.h +++ b/content/media/ogg/nsOggDecoder.h @@ -472,6 +472,9 @@ private: void RegisterShutdownObserver(); void UnregisterShutdownObserver(); + // Notifies the element that decoding has failed. + void DecodeError(); + /****** * The following members should be accessed with the decoder lock held. ******/ diff --git a/content/media/test/Makefile.in b/content/media/test/Makefile.in index 8d1657b84d36..b50b6ddf6d03 100644 --- a/content/media/test/Makefile.in +++ b/content/media/test/Makefile.in @@ -87,6 +87,7 @@ _TEST_FILES = \ test_constants.html \ test_controls.html \ test_currentTime.html \ + test_decode_error.html \ test_decoder_disable.html \ test_load.html \ test_media_selection.html \ @@ -115,6 +116,7 @@ _TEST_FILES += \ 320x240.allow-origin.ogv \ 320x240.allow-origin.ogv^headers^ \ 448636.ogv \ + bogus.ogv \ bug495129.ogv \ bug461281.ogg \ bug482461.ogv \ @@ -128,6 +130,7 @@ _TEST_FILES += \ bug504613.ogv \ bug504644.ogv \ bug506094.ogv \ + dirac.ogv \ seek.ogv \ short-video.ogv \ small-shot.ogg \ @@ -137,6 +140,8 @@ _TEST_FILES += \ # Wave sample files _TEST_FILES += \ big.wav \ + bogus.wav \ + r11025_msadpcm_c1.wav \ r11025_s16_c1.wav \ r11025_s16_c1_trailing.wav \ r11025_u8_c1.wav \ @@ -144,6 +149,11 @@ _TEST_FILES += \ r16000_u8_c1_list.wav \ $(NULL) +# Other files +_TEST_FILES += \ + bogus.duh \ + $(NULL) + # These tests need to be converted to be backend-independent. This list # is deprecated, do not add to it. ifdef MOZ_OGG diff --git a/content/media/test/dirac.ogg b/content/media/test/dirac.ogg new file mode 100644 index 000000000000..2986cf1e8054 Binary files /dev/null and b/content/media/test/dirac.ogg differ diff --git a/content/media/test/manifest.js b/content/media/test/manifest.js index 65bb3c94e791..e84b0c70f33d 100644 --- a/content/media/test/manifest.js +++ b/content/media/test/manifest.js @@ -11,10 +11,10 @@ var gSmallTests = [ { name:"bogus.duh", type:"bogus/duh" } ]; -// These are files that we just want to make sure we can play through. -// We can also check metadata. -// Put files of the same type together in this list so if something crashes -// we have some idea of which backend is responsible. +// These are files that must fire an error during load or playback, and do not +// cause a crash. Put files of the same type together in this list so if +// something crashes we have some idea of which backend is responsible. Used +// by test_playback_errors, which expects one error event and no ended event. var gPlayTests = [ // 8-bit samples { name:"r11025_u8_c1.wav", type:"audio/x-wav", duration:1.0 }, @@ -71,6 +71,20 @@ var gAudioTests = [ { name:"bogus.duh", type:"bogus/duh", duration:123 } ]; +// These are files suitable for testing various decoder failures that are +// expected to fire MEDIA_ERR_DECODE. Used by test_decode_error, which expects +// an error and emptied event, and no loadedmetadata or ended event. +var gDecodeErrorTests = [ + // Valid files with unsupported codecs + { name:"r11025_msadpcm_c1.wav", type:"audio/x-wav" }, + { name:"dirac.ogg", type:"video/ogg" }, + // Invalid files + { name:"bogus.wav", type:"audio/x-wav" }, + { name:"bogus.ogv", type:"video/ogg" }, + + { name:"bogus.duh", type:"bogus/duh" } +]; + function checkMetadata(msg, e, test) { if (test.width) { is(e.videoWidth, test.width, msg + " video width"); diff --git a/content/media/test/r11025_msadpcm_c1.wav b/content/media/test/r11025_msadpcm_c1.wav new file mode 100644 index 000000000000..2e883ba5ed31 Binary files /dev/null and b/content/media/test/r11025_msadpcm_c1.wav differ diff --git a/content/media/test/test_constants.html b/content/media/test/test_constants.html index 753b3dd90865..73f9d9856f44 100644 --- a/content/media/test/test_constants.html +++ b/content/media/test/test_constants.html @@ -18,129 +18,226 @@ is(HTMLElement.NETWORK_EMPTY, undefined); is(HTMLElement.NETWORK_IDLE, undefined); is(HTMLElement.NETWORK_LOADING, undefined); is(HTMLElement.NETWORK_LOADED, undefined); +is(HTMLElement.NETWORK_NO_SOURCE, undefined); is(HTMLElement.HAVE_NOTHING, undefined); is(HTMLElement.HAVE_METADATA, undefined); is(HTMLElement.HAVE_CURRENT_DATA, undefined); is(HTMLElement.HAVE_FUTURE_DATA, undefined); is(HTMLElement.HAVE_ENOUGH_DATA, undefined); +is(HTMLElement.MEDIA_ERR_ABORTED, undefined); +is(HTMLElement.MEDIA_ERR_NETWORK, undefined); +is(HTMLElement.MEDIA_ERR_DECODE, undefined); +is(HTMLElement.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined); is(HTMLMediaElement.NETWORK_EMPTY, 0); is(HTMLMediaElement.NETWORK_IDLE, 1); is(HTMLMediaElement.NETWORK_LOADING, 2); is(HTMLMediaElement.NETWORK_LOADED, 3); +is(HTMLMediaElement.NETWORK_NO_SOURCE, 4); is(HTMLMediaElement.HAVE_NOTHING, 0); is(HTMLMediaElement.HAVE_METADATA, 1); is(HTMLMediaElement.HAVE_CURRENT_DATA, 2); is(HTMLMediaElement.HAVE_FUTURE_DATA, 3); is(HTMLMediaElement.HAVE_ENOUGH_DATA, 4); +is(HTMLMediaElement.MEDIA_ERR_ABORTED, undefined); +is(HTMLMediaElement.MEDIA_ERR_NETWORK, undefined); +is(HTMLMediaElement.MEDIA_ERR_DECODE, undefined); +is(HTMLMediaElement.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined); is(HTMLVideoElement.NETWORK_EMPTY, undefined); is(HTMLVideoElement.NETWORK_IDLE, undefined); is(HTMLVideoElement.NETWORK_LOADING, undefined); is(HTMLVideoElement.NETWORK_LOADED, undefined); +is(HTMLVideoElement.NETWORK_NO_SOURCE, undefined); is(HTMLVideoElement.HAVE_NOTHING, undefined); is(HTMLVideoElement.HAVE_METADATA, undefined); is(HTMLVideoElement.HAVE_CURRENT_DATA, undefined); is(HTMLVideoElement.HAVE_FUTURE_DATA, undefined); is(HTMLVideoElement.HAVE_ENOUGH_DATA, undefined); +is(HTMLVideoElement.MEDIA_ERR_ABORTED, undefined); +is(HTMLVideoElement.MEDIA_ERR_NETWORK, undefined); +is(HTMLVideoElement.MEDIA_ERR_DECODE, undefined); +is(HTMLVideoElement.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined); is(HTMLAudioElement.NETWORK_EMPTY, undefined); is(HTMLAudioElement.NETWORK_IDLE, undefined); is(HTMLAudioElement.NETWORK_LOADING, undefined); is(HTMLAudioElement.NETWORK_LOADED, undefined); +is(HTMLAudioElement.NETWORK_NO_SOURCE, undefined); is(HTMLAudioElement.HAVE_NOTHING, undefined); is(HTMLAudioElement.HAVE_METADATA, undefined); is(HTMLAudioElement.HAVE_CURRENT_DATA, undefined); is(HTMLAudioElement.HAVE_FUTURE_DATA, undefined); is(HTMLAudioElement.HAVE_ENOUGH_DATA, undefined); +is(HTMLAudioElement.MEDIA_ERR_ABORTED, undefined); +is(HTMLAudioElement.MEDIA_ERR_NETWORK, undefined); +is(HTMLAudioElement.MEDIA_ERR_DECODE, undefined); +is(HTMLAudioElement.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined); is(HTMLSourceElement.NETWORK_EMPTY, undefined); is(HTMLSourceElement.NETWORK_IDLE, undefined); is(HTMLSourceElement.NETWORK_LOADING, undefined); is(HTMLSourceElement.NETWORK_LOADED, undefined); +is(HTMLSourceElement.NETWORK_NO_SOURCE, undefined); is(HTMLSourceElement.HAVE_NOTHING, undefined); is(HTMLSourceElement.HAVE_METADATA, undefined); is(HTMLSourceElement.HAVE_CURRENT_DATA, undefined); is(HTMLSourceElement.HAVE_FUTURE_DATA, undefined); is(HTMLSourceElement.HAVE_ENOUGH_DATA, undefined); +is(HTMLSourceElement.MEDIA_ERR_ABORTED, undefined); +is(HTMLSourceElement.MEDIA_ERR_NETWORK, undefined); +is(HTMLSourceElement.MEDIA_ERR_DECODE, undefined); +is(HTMLSourceElement.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined); +is(HTMLMediaError.NETWORK_EMPTY, undefined); +is(HTMLMediaError.NETWORK_IDLE, undefined); +is(HTMLMediaError.NETWORK_LOADING, undefined); +is(HTMLMediaError.NETWORK_LOADED, undefined); +is(HTMLMediaError.NETWORK_NO_SOURCE, undefined); +is(HTMLMediaError.HAVE_NOTHING, undefined); +is(HTMLMediaError.HAVE_METADATA, undefined); +is(HTMLMediaError.HAVE_CURRENT_DATA, undefined); +is(HTMLMediaError.HAVE_FUTURE_DATA, undefined); +is(HTMLMediaError.HAVE_ENOUGH_DATA, undefined); +is(HTMLMediaError.MEDIA_ERR_ABORTED, 1); +is(HTMLMediaError.MEDIA_ERR_NETWORK, 2); +is(HTMLMediaError.MEDIA_ERR_DECODE, 3); +is(HTMLMediaError.MEDIA_ERR_SRC_NOT_SUPPORTED, 4); is(document.body.NETWORK_EMPTY, undefined); is(document.body.NETWORK_IDLE, undefined); is(document.body.NETWORK_LOADING, undefined); is(document.body.NETWORK_LOADED, undefined); +is(document.body.NETWORK_NO_SOURCE, undefined); is(document.body.HAVE_NOTHING, undefined); is(document.body.HAVE_METADATA, undefined); is(document.body.HAVE_CURRENT_DATA, undefined); is(document.body.HAVE_FUTURE_DATA, undefined); is(document.body.HAVE_ENOUGH_DATA, undefined); +is(document.body.MEDIA_ERR_ABORTED, undefined); +is(document.body.MEDIA_ERR_NETWORK, undefined); +is(document.body.MEDIA_ERR_DECODE, undefined); +is(document.body.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined); is(document.getElementsByTagName("video")[0].NETWORK_EMPTY, 0); is(document.getElementsByTagName("video")[0].NETWORK_IDLE, 1); is(document.getElementsByTagName("video")[0].NETWORK_LOADING, 2); is(document.getElementsByTagName("video")[0].NETWORK_LOADED, 3); +is(document.getElementsByTagName("video")[0].NETWORK_NO_SOURCE, 4); is(document.getElementsByTagName("video")[0].HAVE_NOTHING, 0); is(document.getElementsByTagName("video")[0].HAVE_METADATA, 1); is(document.getElementsByTagName("video")[0].HAVE_CURRENT_DATA, 2); is(document.getElementsByTagName("video")[0].HAVE_FUTURE_DATA, 3); is(document.getElementsByTagName("video")[0].HAVE_ENOUGH_DATA, 4); +is(document.getElementsByTagName("video")[0].MEDIA_ERR_ABORTED, undefined); +is(document.getElementsByTagName("video")[0].MEDIA_ERR_NETWORK, undefined); +is(document.getElementsByTagName("video")[0].MEDIA_ERR_DECODE, undefined); +is(document.getElementsByTagName("video")[0].MEDIA_ERR_SRC_NOT_SUPPORTED, undefined); is(document.getElementsByTagName("audio")[0].NETWORK_EMPTY, 0); is(document.getElementsByTagName("audio")[0].NETWORK_IDLE, 1); is(document.getElementsByTagName("audio")[0].NETWORK_LOADING, 2); is(document.getElementsByTagName("audio")[0].NETWORK_LOADED, 3); +is(document.getElementsByTagName("audio")[0].NETWORK_NO_SOURCE, 4); is(document.getElementsByTagName("audio")[0].HAVE_NOTHING, 0); is(document.getElementsByTagName("audio")[0].HAVE_METADATA, 1); is(document.getElementsByTagName("audio")[0].HAVE_CURRENT_DATA, 2); is(document.getElementsByTagName("audio")[0].HAVE_FUTURE_DATA, 3); is(document.getElementsByTagName("audio")[0].HAVE_ENOUGH_DATA, 4); +is(document.getElementsByTagName("audio")[0].MEDIA_ERR_ABORTED, undefined); +is(document.getElementsByTagName("audio")[0].MEDIA_ERR_NETWORK, undefined); +is(document.getElementsByTagName("audio")[0].MEDIA_ERR_DECODE, undefined); +is(document.getElementsByTagName("audio")[0].MEDIA_ERR_SRC_NOT_SUPPORTED, undefined); is(document.getElementsByTagName("source")[0].NETWORK_EMPTY, undefined); is(document.getElementsByTagName("source")[0].NETWORK_IDLE, undefined); is(document.getElementsByTagName("source")[0].NETWORK_LOADING, undefined); is(document.getElementsByTagName("source")[0].NETWORK_LOADED, undefined); +is(document.getElementsByTagName("source")[0].NETWORK_NO_SOURCE, undefined); is(document.getElementsByTagName("source")[0].HAVE_NOTHING, undefined); is(document.getElementsByTagName("source")[0].HAVE_METADATA, undefined); is(document.getElementsByTagName("source")[0].HAVE_CURRENT_DATA, undefined); is(document.getElementsByTagName("source")[0].HAVE_FUTURE_DATA, undefined); is(document.getElementsByTagName("source")[0].HAVE_ENOUGH_DATA, undefined); +is(document.getElementsByTagName("source")[0].MEDIA_ERR_ABORTED, undefined); +is(document.getElementsByTagName("source")[0].MEDIA_ERR_NETWORK, undefined); +is(document.getElementsByTagName("source")[0].MEDIA_ERR_DECODE, undefined); +is(document.getElementsByTagName("source")[0].MEDIA_ERR_SRC_NOT_SUPPORTED, undefined); is(HTMLElement.prototype.NETWORK_EMPTY, undefined); is(HTMLElement.prototype.NETWORK_IDLE, undefined); is(HTMLElement.prototype.NETWORK_LOADING, undefined); is(HTMLElement.prototype.NETWORK_LOADED, undefined); +is(HTMLElement.prototype.NETWORK_NO_SOURCE, undefined); is(HTMLElement.prototype.HAVE_NOTHING, undefined); is(HTMLElement.prototype.HAVE_METADATA, undefined); is(HTMLElement.prototype.HAVE_CURRENT_DATA, undefined); is(HTMLElement.prototype.HAVE_FUTURE_DATA, undefined); is(HTMLElement.prototype.HAVE_ENOUGH_DATA, undefined); +is(HTMLElement.prototype.MEDIA_ERR_ABORTED, undefined); +is(HTMLElement.prototype.MEDIA_ERR_NETWORK, undefined); +is(HTMLElement.prototype.MEDIA_ERR_DECODE, undefined); +is(HTMLElement.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined); todo_is(HTMLMediaElement.prototype.NETWORK_EMPTY, 0, "HTMLMediaElement.prototype.NETWORK_EMPTY"); todo_is(HTMLMediaElement.prototype.NETWORK_IDLE, 1, "HTMLMediaElement.prototype.NETWORK_IDLE"); todo_is(HTMLMediaElement.prototype.NETWORK_LOADING, 2, "HTMLMediaElement.prototype.NETWORK_LOADING"); todo_is(HTMLMediaElement.prototype.NETWORK_LOADED, 3, "HTMLMediaElement.prototype.NETWORK_LOADED"); +todo_is(HTMLMediaElement.prototype.NETWORK_NO_SOURCE, 4, "HTMLMediaElement.prototype.NETWORK_NO_SOURCE"); todo_is(HTMLMediaElement.prototype.HAVE_NOTHING, 0, "HTMLMediaElement.prototype.HAVE_NOTHING"); todo_is(HTMLMediaElement.prototype.HAVE_METADATA, 1, "HTMLMediaElement.prototype.HAVE_METADATA"); todo_is(HTMLMediaElement.prototype.HAVE_CURRENT_DATA, 2, "HTMLMediaElement.prototype.HAVE_CURRENT_DATA"); todo_is(HTMLMediaElement.prototype.HAVE_FUTURE_DATA, 3, "HTMLMediaElement.prototype.HAVE_FUTURE_DATA"); todo_is(HTMLMediaElement.prototype.HAVE_ENOUGH_DATA, 4, "HTMLMediaElement.prototype.HAVE_ENOUGH_DATA"); +is(HTMLMediaElement.prototype.MEDIA_ERR_ABORTED, undefined, "HTMLMediaElement.prototype.MEDIA_ERR_ABORTED"); +is(HTMLMediaElement.prototype.MEDIA_ERR_NETWORK, undefined, "HTMLMediaElement.prototype.MEDIA_ERR_NETWORK"); +is(HTMLMediaElement.prototype.MEDIA_ERR_DECODE, undefined, "HTMLMediaElement.prototype.MEDIA_ERR_DECODE"); +is(HTMLMediaElement.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined, "HTMLMediaElement.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED"); is(HTMLVideoElement.prototype.NETWORK_EMPTY, 0); is(HTMLVideoElement.prototype.NETWORK_IDLE, 1); is(HTMLVideoElement.prototype.NETWORK_LOADING, 2); is(HTMLVideoElement.prototype.NETWORK_LOADED, 3); +is(HTMLVideoElement.prototype.NETWORK_NO_SOURCE, 4); is(HTMLVideoElement.prototype.HAVE_NOTHING, 0); is(HTMLVideoElement.prototype.HAVE_METADATA, 1); is(HTMLVideoElement.prototype.HAVE_CURRENT_DATA, 2); is(HTMLVideoElement.prototype.HAVE_FUTURE_DATA, 3); is(HTMLVideoElement.prototype.HAVE_ENOUGH_DATA, 4); +is(HTMLVideoElement.prototype.MEDIA_ERR_ABORTED, undefined); +is(HTMLVideoElement.prototype.MEDIA_ERR_NETWORK, undefined); +is(HTMLVideoElement.prototype.MEDIA_ERR_DECODE, undefined); +is(HTMLVideoElement.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined); is(HTMLAudioElement.prototype.NETWORK_EMPTY, 0); is(HTMLAudioElement.prototype.NETWORK_IDLE, 1); is(HTMLAudioElement.prototype.NETWORK_LOADING, 2); is(HTMLAudioElement.prototype.NETWORK_LOADED, 3); +is(HTMLAudioElement.prototype.NETWORK_NO_SOURCE, 4); is(HTMLAudioElement.prototype.HAVE_NOTHING, 0); is(HTMLAudioElement.prototype.HAVE_METADATA, 1); is(HTMLAudioElement.prototype.HAVE_CURRENT_DATA, 2); is(HTMLAudioElement.prototype.HAVE_FUTURE_DATA, 3); is(HTMLAudioElement.prototype.HAVE_ENOUGH_DATA, 4); +is(HTMLAudioElement.prototype.MEDIA_ERR_ABORTED, undefined); +is(HTMLAudioElement.prototype.MEDIA_ERR_NETWORK, undefined); +is(HTMLAudioElement.prototype.MEDIA_ERR_DECODE, undefined); +is(HTMLAudioElement.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined); is(HTMLSourceElement.prototype.NETWORK_EMPTY, undefined); is(HTMLSourceElement.prototype.NETWORK_IDLE, undefined); is(HTMLSourceElement.prototype.NETWORK_LOADING, undefined); is(HTMLSourceElement.prototype.NETWORK_LOADED, undefined); +is(HTMLSourceElement.prototype.NETWORK_NO_SOURCE, undefined); is(HTMLSourceElement.prototype.HAVE_NOTHING, undefined); is(HTMLSourceElement.prototype.HAVE_METADATA, undefined); is(HTMLSourceElement.prototype.HAVE_CURRENT_DATA, undefined); is(HTMLSourceElement.prototype.HAVE_FUTURE_DATA, undefined); is(HTMLSourceElement.prototype.HAVE_ENOUGH_DATA, undefined); - +is(HTMLSourceElement.prototype.MEDIA_ERR_ABORTED, undefined); +is(HTMLSourceElement.prototype.MEDIA_ERR_NETWORK, undefined); +is(HTMLSourceElement.prototype.MEDIA_ERR_DECODE, undefined); +is(HTMLSourceElement.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined); +is(HTMLMediaError.prototype.NETWORK_EMPTY, undefined); +is(HTMLMediaError.prototype.NETWORK_IDLE, undefined); +is(HTMLMediaError.prototype.NETWORK_LOADING, undefined); +is(HTMLMediaError.prototype.NETWORK_LOADED, undefined); +is(HTMLMediaError.prototype.NETWORK_NO_SOURCE, undefined); +is(HTMLMediaError.prototype.HAVE_NOTHING, undefined); +is(HTMLMediaError.prototype.HAVE_METADATA, undefined); +is(HTMLMediaError.prototype.HAVE_CURRENT_DATA, undefined); +is(HTMLMediaError.prototype.HAVE_FUTURE_DATA, undefined); +is(HTMLMediaError.prototype.HAVE_ENOUGH_DATA, undefined); +is(HTMLMediaError.prototype.MEDIA_ERR_ABORTED, 1); +is(HTMLMediaError.prototype.MEDIA_ERR_NETWORK, 2); +is(HTMLMediaError.prototype.MEDIA_ERR_DECODE, 3); +is(HTMLMediaError.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED, 4); diff --git a/content/media/test/test_decode_error.html b/content/media/test/test_decode_error.html new file mode 100644 index 000000000000..831f58a04298 --- /dev/null +++ b/content/media/test/test_decode_error.html @@ -0,0 +1,61 @@ + + + + Media test: unknown/invalid formats raise decode error + + + + + + + +
+
+
+ + diff --git a/content/media/test/test_info_leak.html b/content/media/test/test_info_leak.html index 6a3ea04ad1df..981cf3431ad5 100644 --- a/content/media/test/test_info_leak.html +++ b/content/media/test/test_info_leak.html @@ -164,8 +164,8 @@ function checkState() { test_is(gMedia.autoplay, false, "Autoplay leaked"); test_is(gMedia.controls, false, "Controls leaked"); test_is(gMedia.muted, false, "muted leaked"); - test_ok(gMedia.error==null || gMedia.error.code==HTMLMediaError.MEDIA_ERR_NONE_SUPPORTED, - "Error code should not exist or be NONE_SUPPORTED. gMedia.error=" + + test_ok(gMedia.error==null || gMedia.error.code==HTMLMediaError.MEDIA_ERR_SRC_NOT_SUPPORTED, + "Error code should not exist or be SRC_NOT_SUPPORTED. gMedia.error=" + (gMedia.error ? gMedia.error.code : "null")); test_is(gMedia.currentSrc, "", "Leaked currentSrc"); diff --git a/content/media/wave/nsWaveDecoder.cpp b/content/media/wave/nsWaveDecoder.cpp index 38eea168b08f..cdbbbc9f329e 100644 --- a/content/media/wave/nsWaveDecoder.cpp +++ b/content/media/wave/nsWaveDecoder.cpp @@ -490,25 +490,17 @@ nsWaveStateMachine::Run() PRBool loaded = LoadRIFFChunk() && LoadFormatChunk() && FindDataOffset(); monitor.Enter(); + if (!loaded) { + ChangeState(STATE_ERROR); + } + if (mState == STATE_LOADING_METADATA) { - nsCOMPtr event; - State newState; - - if (loaded) { - mMetadataValid = PR_TRUE; - if (mNextState != STATE_SEEKING) { - event = NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, MetadataLoaded); - } - newState = mNextState; - } else { - event = NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, MediaErrorDecode); - newState = STATE_ERROR; - } - - if (event) { + mMetadataValid = PR_TRUE; + if (mNextState != STATE_SEEKING) { + nsCOMPtr event = NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, MetadataLoaded); NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); } - ChangeState(newState); + ChangeState(mNextState); } } break; @@ -545,7 +537,7 @@ nsWaveStateMachine::Run() TimeStamp now = TimeStamp::Now(); TimeStamp lastWakeup = now - - TimeDuration::FromMilliseconds(AUDIO_BUFFER_LENGTH); + TimeDuration::FromMilliseconds(AUDIO_BUFFER_LENGTH); do { TimeDuration sleepTime = now - lastWakeup; @@ -580,17 +572,17 @@ nsWaveStateMachine::Run() if (mState != STATE_ENDED && availableOffset < mPlaybackPosition + len && !mStream->IsSuspendedByCache()) { - mBufferingStart = now; - mBufferingEndOffset = mPlaybackPosition + - TimeToBytes(mBufferingWait.ToSeconds()); - mBufferingEndOffset = PR_MAX(mPlaybackPosition + len, mBufferingEndOffset); - mNextState = mState; - ChangeState(STATE_BUFFERING); + mBufferingStart = now; + mBufferingEndOffset = mPlaybackPosition + + TimeToBytes(mBufferingWait.ToSeconds()); + mBufferingEndOffset = PR_MAX(mPlaybackPosition + len, mBufferingEndOffset); + mNextState = mState; + ChangeState(STATE_BUFFERING); - nsCOMPtr event = - NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, UpdateReadyStateForData); - NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); - break; + nsCOMPtr event = + NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, UpdateReadyStateForData); + NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); + break; } if (len > 0) { @@ -739,10 +731,16 @@ nsWaveStateMachine::Run() break; case STATE_ERROR: - monitor.Wait(); - if (mState != STATE_SHUTDOWN) { - NS_WARNING("Invalid state transition"); - ChangeState(STATE_ERROR); + { + nsCOMPtr event = NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, DecodeError); + NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); + + monitor.Wait(); + + if (mState != STATE_SHUTDOWN) { + NS_WARNING("Invalid state transition"); + ChangeState(STATE_ERROR); + } } break; @@ -1531,18 +1529,15 @@ nsWaveDecoder::UnregisterShutdownObserver() } void -nsWaveDecoder::MediaErrorDecode() +nsWaveDecoder::DecodeError() { if (mShuttingDown) { return; } -#if 0 if (mElement) { - mElement->MediaErrorDecode(); + mElement->DecodeError(); } -#else - NS_WARNING("MediaErrorDecode fired, but not implemented."); -#endif + Shutdown(); } void diff --git a/content/media/wave/nsWaveDecoder.h b/content/media/wave/nsWaveDecoder.h index 7b7684edd91f..bf9b95596479 100644 --- a/content/media/wave/nsWaveDecoder.h +++ b/content/media/wave/nsWaveDecoder.h @@ -244,8 +244,8 @@ private: // Notifies the element that playback has completed. void PlaybackEnded(); - // Notifies the element that metadata loading has failed. - void MediaErrorDecode(); + // Notifies the element that decoding has failed. + void DecodeError(); void RegisterShutdownObserver(); void UnregisterShutdownObserver(); diff --git a/dom/interfaces/html/nsIDOMHTMLMediaError.idl b/dom/interfaces/html/nsIDOMHTMLMediaError.idl index 06e132e4cdf7..8ba84877328a 100644 --- a/dom/interfaces/html/nsIDOMHTMLMediaError.idl +++ b/dom/interfaces/html/nsIDOMHTMLMediaError.idl @@ -53,7 +53,7 @@ interface nsIDOMHTMLMediaError : nsISupports const unsigned short MEDIA_ERR_DECODE = 3; /* No suitable media resource could be found */ - const unsigned short MEDIA_ERR_NONE_SUPPORTED = 4; + const unsigned short MEDIA_ERR_SRC_NOT_SUPPORTED = 4; readonly attribute unsigned short code; };