Bug 1299072: P10. Pass decoding error details to media element's error attribute. r?jwwang
MozReview-Commit-ID: 49DurV9WI5S
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -4336,17 +4336,17 @@ void HTMLMediaElement::MetadataLoaded(co
"Video resolution must be known on 'loadedmetadata'");
DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata"));
if (mDecoder && mDecoder->IsTransportSeekable() && mDecoder->IsMediaSeekable()) {
ProcessMediaFragmentURI();
mDecoder->SetFragmentEndTime(mFragmentEnd);
}
if (mIsEncrypted) {
if (!mMediaSource && Preferences::GetBool("media.eme.mse-only", true)) {
- DecodeError();
+ DecodeError(NS_ERROR_DOM_MEDIA_FATAL_ERR);
return;
}
#ifdef MOZ_EME
// Dispatch a distinct 'encrypted' event for each initData we have.
for (const auto& initData : mPendingEncryptedInitData.mInitDatas) {
DispatchEncrypted(initData.mInitData, initData.mType);
}
@@ -4411,17 +4411,17 @@ void HTMLMediaElement::FirstFrameLoaded(
void HTMLMediaElement::NetworkError()
{
if (mDecoder) {
ShutdownDecoder();
}
Error(nsIDOMMediaError::MEDIA_ERR_NETWORK);
}
-void HTMLMediaElement::DecodeError()
+void HTMLMediaElement::DecodeError(const MediaResult& aError)
{
nsAutoString src;
GetCurrentSrc(src);
const char16_t* params[] = { src.get() };
ReportLoadError("MediaLoadDecodeError", params, ArrayLength(params));
if (mDecoder) {
ShutdownDecoder();
@@ -4435,45 +4435,50 @@ void HTMLMediaElement::DecodeError()
mError = nullptr;
if (mSourceLoadCandidate) {
DispatchAsyncSourceError(mSourceLoadCandidate);
QueueLoadFromSourceTask();
} else {
NS_WARNING("Should know the source we were loading from!");
}
} else {
- Error(nsIDOMMediaError::MEDIA_ERR_DECODE);
+ Error(nsIDOMMediaError::MEDIA_ERR_DECODE, aError);
}
}
bool HTMLMediaElement::HasError() const
{
return GetError();
}
void HTMLMediaElement::LoadAborted()
{
Error(nsIDOMMediaError::MEDIA_ERR_ABORTED);
}
-void HTMLMediaElement::Error(uint16_t aErrorCode)
+void HTMLMediaElement::Error(uint16_t aErrorCode,
+ const MediaResult& aErrorDetails)
{
NS_ASSERTION(aErrorCode == nsIDOMMediaError::MEDIA_ERR_DECODE ||
aErrorCode == nsIDOMMediaError::MEDIA_ERR_NETWORK ||
aErrorCode == nsIDOMMediaError::MEDIA_ERR_ABORTED,
"Only use nsIDOMMediaError codes!");
// Since we have multiple paths calling into DecodeError, e.g.
// MediaKeys::Terminated and EMEH264Decoder::Error. We should take the 1st
// one only in order not to fire multiple 'error' events.
if (mError) {
return;
}
-
- mError = new MediaError(this, aErrorCode);
+ nsCString message;
+ if (NS_FAILED(aErrorDetails)) {
+ message = aErrorDetails.Description();
+ }
+ mError = new MediaError(this, aErrorCode, message);
+
DispatchAsyncEvent(NS_LITERAL_STRING("error"));
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) {
ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
DispatchAsyncEvent(NS_LITERAL_STRING("emptied"));
} else {
ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
}
ChangeDelayLoadStatus(false);
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -174,17 +174,17 @@ public:
virtual void FirstFrameLoaded() final override;
// Called by the video decoder object, on the main thread,
// when the resource has a network error during loading.
virtual void NetworkError() final override;
// Called by the video decoder object, on the main thread, when the
// resource has a decode error during metadata loading or decoding.
- virtual void DecodeError() final override;
+ virtual void DecodeError(const MediaResult& aError) final override;
// Return true if error attribute is not null.
virtual bool HasError() const final override;
// Called by the video decoder object, on the main thread, when the
// resource load has been cancelled.
virtual void LoadAborted() final override;
@@ -1111,17 +1111,17 @@ protected:
* Dispatches an error event to a child source element.
*/
void DispatchAsyncSourceError(nsIContent* aSourceElement);
/**
* Resets the media element for an error condition as per aErrorCode.
* aErrorCode must be one of nsIDOMHTMLMediaError codes.
*/
- void Error(uint16_t aErrorCode);
+ void Error(uint16_t aErrorCode, const MediaResult& aErrorDetails = NS_OK);
/**
* Returns the URL spec of the currentSrc.
**/
void GetCurrentSpec(nsCString& aString);
/**
* Process any media fragment entries in the URI
--- a/dom/html/MediaError.cpp
+++ b/dom/html/MediaError.cpp
@@ -16,32 +16,35 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaErr
NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaError)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaError)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsIDOMMediaError)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMediaError)
NS_INTERFACE_MAP_END
-MediaError::MediaError(HTMLMediaElement* aParent, uint16_t aCode)
+MediaError::MediaError(HTMLMediaElement* aParent, uint16_t aCode,
+ const nsACString& aMessage)
: mParent(aParent)
, mCode(aCode)
+ , mMessage(aMessage)
{
}
NS_IMETHODIMP MediaError::GetCode(uint16_t* aCode)
{
if (aCode)
*aCode = Code();
return NS_OK;
}
NS_IMETHODIMP MediaError::GetMessage(nsAString& aResult)
{
+ CopyUTF8toUTF16(mMessage, aResult);
return NS_OK;
}
JSObject*
MediaError::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return MediaErrorBinding::Wrap(aCx, this, aGivenProto);
}
--- a/dom/html/MediaError.h
+++ b/dom/html/MediaError.h
@@ -17,17 +17,18 @@ namespace mozilla {
namespace dom {
class MediaError final : public nsIDOMMediaError,
public nsWrapperCache
{
~MediaError() {}
public:
- MediaError(HTMLMediaElement* aParent, uint16_t aCode);
+ MediaError(HTMLMediaElement* aParent, uint16_t aCode,
+ const nsACString& aMessage = nsCString());
// nsISupports
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaError)
// nsIDOMMediaError
NS_DECL_NSIDOMMEDIAERROR
@@ -43,14 +44,16 @@ public:
return mCode;
}
private:
RefPtr<HTMLMediaElement> mParent;
// Error code
const uint16_t mCode;
+ // Error details;
+ const nsCString mMessage;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_MediaError_h
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -1011,17 +1011,17 @@ MediaDecoder::NetworkError()
MOZ_ASSERT(IsShutdown());
}
void
MediaDecoder::DecodeError(const MediaResult& aError)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdown());
- mOwner->DecodeError();
+ mOwner->DecodeError(aError);
MOZ_ASSERT(IsShutdown());
}
void
MediaDecoder::UpdateSameOriginStatus(bool aSameOrigin)
{
MOZ_ASSERT(NS_IsMainThread());
mSameOriginMedia = aSameOrigin;
--- a/dom/media/MediaDecoderOwner.h
+++ b/dom/media/MediaDecoderOwner.h
@@ -6,16 +6,17 @@
#ifndef MediaDecoderOwner_h_
#define MediaDecoderOwner_h_
#include "AbstractMediaDecoder.h"
#include "nsAutoPtr.h"
namespace mozilla {
class VideoFrameContainer;
+class MediaResult;
namespace dom {
class HTMLMediaElement;
} // namespace dom
class MediaDecoderOwner
{
public:
@@ -62,17 +63,17 @@ public:
// The decoder owner should call Shutdown() on the decoder and drop the
// reference to the decoder to prevent further calls into the decoder.
virtual void NetworkError() = 0;
// Called by the decoder object, on the main thread, when the
// resource has a decode error during metadata loading or decoding.
// The decoder owner should call Shutdown() on the decoder and drop the
// reference to the decoder to prevent further calls into the decoder.
- virtual void DecodeError() = 0;
+ virtual void DecodeError(const MediaResult& aError) = 0;
// Return true if media element error attribute is not null.
virtual bool HasError() const = 0;
// Called by the video decoder object, on the main thread, when the
// resource load has been cancelled.
virtual void LoadAborted() = 0;
--- a/dom/media/eme/MediaKeys.cpp
+++ b/dom/media/eme/MediaKeys.cpp
@@ -83,17 +83,17 @@ MediaKeys::Terminated()
RefPtr<MediaKeySession>& session = iter.Data();
session->OnClosed();
}
keySessions.Clear();
MOZ_ASSERT(mKeySessions.Count() == 0);
// Notify the element about that CDM has terminated.
if (mElement) {
- mElement->DecodeError();
+ mElement->DecodeError(NS_ERROR_DOM_MEDIA_CDM_ERR);
}
Shutdown();
}
void
MediaKeys::Shutdown()
{
--- a/dom/media/gtest/MockMediaDecoderOwner.h
+++ b/dom/media/gtest/MockMediaDecoderOwner.h
@@ -20,17 +20,17 @@ public:
}
void FireTimeUpdate(bool aPeriodic) override {}
bool GetPaused() override { return false; }
void MetadataLoaded(const MediaInfo* aInfo,
nsAutoPtr<const MetadataTags> aTags) override
{
}
void NetworkError() override {}
- void DecodeError() override {}
+ void DecodeError(const MediaResult& aError) override {}
bool HasError() const override { return false; }
void LoadAborted() override {}
void PlaybackEnded() override {}
void SeekStarted() override {}
void SeekCompleted() override {}
void DownloadProgressed() override {}
void UpdateReadyState() override {}
void FirstFrameLoaded() override {}
--- a/dom/media/mediasource/MediaSource.cpp
+++ b/dom/media/mediasource/MediaSource.cpp
@@ -325,17 +325,17 @@ MediaSource::EndOfStream(const Optional<
mDecoder->Ended(true);
return;
}
switch (aError.Value()) {
case MediaSourceEndOfStreamError::Network:
mDecoder->NetworkError();
break;
case MediaSourceEndOfStreamError::Decode:
- mDecoder->DecodeError();
+ mDecoder->DecodeError(NS_ERROR_DOM_MEDIA_FATAL_ERR);
break;
default:
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
}
}
/* static */ bool
MediaSource::IsTypeSupported(const GlobalObject& aOwner, const nsAString& aType)