| 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;
|
| }
|
|
|
|
|