Index: third_party/WebKit/Source/core/html/HTMLMediaElement.cpp |
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp |
index fd0253d4b2ba2749411fa315a8644f330c73c0ee..3997b9e26c8fd084b3bf10f43a99231639fe0a21 100644 |
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp |
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp |
@@ -82,6 +82,7 @@ |
#include "platform/audio/AudioBus.h" |
#include "platform/audio/AudioSourceProviderClient.h" |
#include "platform/graphics/GraphicsLayer.h" |
+#include "platform/json/JSONValues.h" |
#include "platform/mediastream/MediaStreamDescriptor.h" |
#include "platform/network/NetworkStateNotifier.h" |
#include "platform/network/ParsedContentType.h" |
@@ -221,6 +222,29 @@ void RemoveElementFromDocumentMap(HTMLMediaElement* element, |
map.erase(it); |
} |
+std::unique_ptr<JSONObject> BuildSimpleErrorMessage(const String& error) { |
+ DEFINE_STATIC_LOCAL(const String, element_error_label, ("MediaElementError")); |
+ std::unique_ptr<JSONObject> json_message = JSONObject::Create(); |
+ std::unique_ptr<JSONArray> errors = JSONArray::Create(); |
+ errors->PushString(error); |
+ json_message->SetArray(element_error_label, std::move(errors)); |
+ return json_message; |
+} |
+ |
+std::unique_ptr<JSONObject> BuildErrorMessage( |
+ const std::map<std::string, std::vector<std::string>>& messages) { |
+ std::unique_ptr<JSONObject> json_messages = JSONObject::Create(); |
+ for (const auto& entry : messages) { |
+ std::unique_ptr<JSONArray> errors = JSONArray::Create(); |
+ for (const auto& error : entry.second) |
+ errors->PushString(WebString::FromUTF8(error)); |
+ json_messages->SetArray(WebString::FromUTF8(entry.first), |
+ std::move(errors)); |
+ } |
+ |
+ return json_messages; |
+} |
+ |
class AudioSourceProviderClientLockScope { |
STACK_ALLOCATED(); |
@@ -1115,15 +1139,18 @@ void HTMLMediaElement::LoadSourceFromAttribute() { |
// If the src attribute's value is the empty string ... jump down to the |
// failed step below |
if (src_value.IsEmpty()) { |
- MediaLoadingFailed(WebMediaPlayer::kNetworkStateFormatError); |
- BLINK_MEDIA_LOG << "loadSourceFromAttribute(" << (void*)this |
+ BLINK_MEDIA_LOG << "LoadSourceFromAttribute(" << (void*)this |
<< "), empty 'src'"; |
+ MediaLoadingFailed(WebMediaPlayer::kNetworkStateFormatError, |
+ BuildSimpleErrorMessage("Empty src attribute")); |
return; |
} |
KURL media_url = GetDocument().CompleteURL(src_value); |
if (!IsSafeToLoadURL(media_url, kComplain)) { |
- MediaLoadingFailed(WebMediaPlayer::kNetworkStateFormatError); |
+ MediaLoadingFailed( |
+ WebMediaPlayer::kNetworkStateFormatError, |
+ BuildSimpleErrorMessage("Media load rejected by URL safety check")); |
return; |
} |
@@ -1160,7 +1187,9 @@ void HTMLMediaElement::LoadResource(const WebMediaPlayerSource& source, |
LocalFrame* frame = GetDocument().GetFrame(); |
if (!frame) { |
- MediaLoadingFailed(WebMediaPlayer::kNetworkStateFormatError); |
+ MediaLoadingFailed(WebMediaPlayer::kNetworkStateFormatError, |
+ BuildSimpleErrorMessage( |
+ "Resource load failure: document has no frame")); |
return; |
} |
@@ -1218,7 +1247,11 @@ void HTMLMediaElement::LoadResource(const WebMediaPlayerSource& source, |
StartPlayerLoad(); |
} |
} else { |
- MediaLoadingFailed(WebMediaPlayer::kNetworkStateFormatError); |
+ MediaLoadingFailed( |
+ WebMediaPlayer::kNetworkStateFormatError, |
+ BuildSimpleErrorMessage(attempt_load |
+ ? "Unable to load URL due to content type" |
+ : "Unable to attach MediaSource")); |
} |
// If there is no poster to display, allow the media engine to render video |
@@ -1264,14 +1297,18 @@ void HTMLMediaElement::StartPlayerLoad(const KURL& player_provided_url) { |
// TODO(srirama.m): Figure out how frame can be null when |
// coming from executeDeferredLoad() |
if (!frame) { |
- MediaLoadingFailed(WebMediaPlayer::kNetworkStateFormatError); |
+ MediaLoadingFailed( |
+ WebMediaPlayer::kNetworkStateFormatError, |
+ BuildSimpleErrorMessage("Player load failure: document has no frame")); |
return; |
} |
web_media_player_ = |
frame->Loader().Client()->CreateWebMediaPlayer(*this, source, this); |
if (!web_media_player_) { |
- MediaLoadingFailed(WebMediaPlayer::kNetworkStateFormatError); |
+ MediaLoadingFailed(WebMediaPlayer::kNetworkStateFormatError, |
+ BuildSimpleErrorMessage( |
+ "Player load failure: error creating media player")); |
return; |
} |
@@ -1514,8 +1551,9 @@ void HTMLMediaElement::WaitForSourceChange() { |
GetLayoutObject()->UpdateFromElement(); |
} |
-void HTMLMediaElement::NoneSupported() { |
- BLINK_MEDIA_LOG << "noneSupported(" << (void*)this << ")"; |
+void HTMLMediaElement::NoneSupported(std::unique_ptr<JSONObject> messages) { |
+ BLINK_MEDIA_LOG << "NoneSupported(" << (void*)this << ", messages='" |
+ << messages->ToJSONString() << "')"; |
StopPeriodicTimers(); |
load_state_ = kWaitingForSource; |
@@ -1526,7 +1564,8 @@ void HTMLMediaElement::NoneSupported() { |
// 1 - Set the error attribute to a new MediaError object whose code attribute |
// is set to MEDIA_ERR_SRC_NOT_SUPPORTED. |
- error_ = MediaError::Create(MediaError::kMediaErrSrcNotSupported); |
+ error_ = |
+ MediaError::Create(MediaError::kMediaErrSrcNotSupported, messages.get()); |
// 2 - Forget the media element's media-resource-specific text tracks. |
ForgetResourceSpecificTracks(); |
@@ -1595,7 +1634,13 @@ void HTMLMediaElement::NetworkStateChanged() { |
SetNetworkState(GetWebMediaPlayer()->GetNetworkState()); |
} |
-void HTMLMediaElement::MediaLoadingFailed(WebMediaPlayer::NetworkState error) { |
+void HTMLMediaElement::MediaLoadingFailed( |
+ WebMediaPlayer::NetworkState error, |
+ std::unique_ptr<JSONObject> messages) { |
+ BLINK_MEDIA_LOG << "MediaLoadingFailed(" << (void*)this << ", " |
+ << static_cast<int>(error) << ", messages='" |
+ << messages->ToJSONString() << "')"; |
+ |
StopPeriodicTimers(); |
// If we failed while trying to load a <source> element, the movie was never |
@@ -1635,13 +1680,23 @@ void HTMLMediaElement::MediaLoadingFailed(WebMediaPlayer::NetworkState error) { |
if (error == WebMediaPlayer::kNetworkStateNetworkError && |
ready_state_ >= kHaveMetadata) { |
- MediaEngineError(MediaError::Create(MediaError::kMediaErrNetwork)); |
+ MediaEngineError( |
+ MediaError::Create(MediaError::kMediaErrNetwork, messages.get())); |
} else if (error == WebMediaPlayer::kNetworkStateDecodeError) { |
- MediaEngineError(MediaError::Create(MediaError::kMediaErrDecode)); |
+ MediaEngineError( |
+ MediaError::Create(MediaError::kMediaErrDecode, messages.get())); |
} else if ((error == WebMediaPlayer::kNetworkStateFormatError || |
error == WebMediaPlayer::kNetworkStateNetworkError) && |
load_state_ == kLoadingFromSrcAttr) { |
- NoneSupported(); |
+ if (!messages->size()) { |
+ // Generate a more meaningful error message to differentiate the two types |
+ // of MEDIA_SRC_ERR_NOT_SUPPORTED. |
+ NoneSupported(BuildSimpleErrorMessage( |
+ error == WebMediaPlayer::kNetworkStateFormatError ? "Format error" |
+ : "Network error")); |
+ } else { |
+ NoneSupported(std::move(messages)); |
+ } |
} |
UpdateDisplayState(); |
@@ -1661,7 +1716,8 @@ void HTMLMediaElement::SetNetworkState(WebMediaPlayer::NetworkState state) { |
if (state == WebMediaPlayer::kNetworkStateFormatError || |
state == WebMediaPlayer::kNetworkStateNetworkError || |
state == WebMediaPlayer::kNetworkStateDecodeError) { |
- MediaLoadingFailed(state); |
+ MediaLoadingFailed( |
+ state, BuildErrorMessage(web_media_player_->GetErrorMessages())); |
return; |
} |