Commit ab6a4c33 authored by Bill Carr's avatar Bill Carr Committed by Chromium LUCI CQ

Pass Pipeline Status Across Mojo Renderer OnError Boundary

This change updates the Mojo Renderer OnError method to take in a
media::Status object, wrapping a PipelineStatus, in order to pass the
error code from the Mojo Renderer Service to the Mojo Renderer.

This was a basic missing bit of functionality that will allow Mojo
Renderers to communicate a more accurate error state for telemetry &
logging purposes.

The media::Status object was used as part of a longer term plan to
allow passing a render or platform specific error status (such as an OS
native status code, e.g. an HRESULT on Windows). A part 2 change will
move the Renderer OnError method to replace PipelineStatus with the
Status object but preserve the existing PipelineStatus enumeration
values & strings for telemetry & logging reporting purposes.

Bug: 1146085
Change-Id: I22faa88cb30e86dceda5a2630d416a62fb0e66ac
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2553920Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarFrank Liberato <liberato@chromium.org>
Reviewed-by: default avatarTed Meyer <tmathmeyer@chromium.org>
Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Commit-Queue: William Carr <wicarr@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#833424}
parent b1c4eac3
...@@ -8,6 +8,96 @@ ...@@ -8,6 +8,96 @@
namespace media { namespace media {
base::Optional<PipelineStatus> StatusCodeToPipelineStatus(StatusCode status) {
switch (status) {
case StatusCode::kOk:
return PIPELINE_OK;
case StatusCode::kPipelineErrorNetwork:
return PIPELINE_ERROR_NETWORK;
case StatusCode::kPipelineErrorDecode:
return PIPELINE_ERROR_DECODE;
case StatusCode::kPipelineErrorAbort:
return PIPELINE_ERROR_ABORT;
case StatusCode::kPipelineErrorInitializationFailed:
return PIPELINE_ERROR_INITIALIZATION_FAILED;
case StatusCode::kPipelineErrorCouldNotRender:
return PIPELINE_ERROR_COULD_NOT_RENDER;
case StatusCode::kPipelineErrorRead:
return PIPELINE_ERROR_READ;
case StatusCode::kPipelineErrorInvalidState:
return PIPELINE_ERROR_INVALID_STATE;
case StatusCode::kPipelineErrorDemuxerErrorCouldNotOpen:
return DEMUXER_ERROR_COULD_NOT_OPEN;
case StatusCode::kPipelineErrorDemuxerErrorCouldNotParse:
return DEMUXER_ERROR_COULD_NOT_PARSE;
case StatusCode::kPipelineErrorDemuxerErrorNoSupportedStreams:
return DEMUXER_ERROR_NO_SUPPORTED_STREAMS;
case StatusCode::kPipelineErrorDecoderErrorNotSupported:
return DECODER_ERROR_NOT_SUPPORTED;
case StatusCode::kPipelineErrorChuckDemuxerErrorAppendFailed:
return CHUNK_DEMUXER_ERROR_APPEND_FAILED;
case StatusCode::kPipelineErrorChunkDemuxerErrorEosStatusDecodeError:
return CHUNK_DEMUXER_ERROR_EOS_STATUS_DECODE_ERROR;
case StatusCode::kPipelineErrorChunkDemuxerErrorEosStatusNetworkError:
return CHUNK_DEMUXER_ERROR_EOS_STATUS_NETWORK_ERROR;
case StatusCode::kPipelineErrorAudioRendererError:
return AUDIO_RENDERER_ERROR;
case StatusCode::kPipelineErrorExternalRendererFailed:
return PIPELINE_ERROR_EXTERNAL_RENDERER_FAILED;
case StatusCode::kPipelineErrorDemuxerErrorDetectedHLS:
return DEMUXER_ERROR_DETECTED_HLS;
default:
NOTREACHED();
return base::nullopt;
}
}
StatusCode PipelineStatusToStatusCode(PipelineStatus status) {
switch (status) {
case PIPELINE_OK:
return StatusCode::kOk;
case PIPELINE_ERROR_NETWORK:
return StatusCode::kPipelineErrorNetwork;
case PIPELINE_ERROR_DECODE:
return StatusCode::kPipelineErrorDecode;
case PIPELINE_ERROR_ABORT:
return StatusCode::kPipelineErrorAbort;
case PIPELINE_ERROR_INITIALIZATION_FAILED:
return StatusCode::kPipelineErrorInitializationFailed;
case PIPELINE_ERROR_COULD_NOT_RENDER:
return StatusCode::kPipelineErrorCouldNotRender;
case PIPELINE_ERROR_READ:
return StatusCode::kPipelineErrorRead;
case PIPELINE_ERROR_INVALID_STATE:
return StatusCode::kPipelineErrorInvalidState;
case DEMUXER_ERROR_COULD_NOT_OPEN:
return StatusCode::kPipelineErrorDemuxerErrorCouldNotOpen;
case DEMUXER_ERROR_COULD_NOT_PARSE:
return StatusCode::kPipelineErrorDemuxerErrorCouldNotParse;
case DEMUXER_ERROR_NO_SUPPORTED_STREAMS:
return StatusCode::kPipelineErrorDemuxerErrorNoSupportedStreams;
case DECODER_ERROR_NOT_SUPPORTED:
return StatusCode::kPipelineErrorDecoderErrorNotSupported;
case CHUNK_DEMUXER_ERROR_APPEND_FAILED:
return StatusCode::kPipelineErrorChuckDemuxerErrorAppendFailed;
case CHUNK_DEMUXER_ERROR_EOS_STATUS_DECODE_ERROR:
return StatusCode::kPipelineErrorChunkDemuxerErrorEosStatusDecodeError;
case CHUNK_DEMUXER_ERROR_EOS_STATUS_NETWORK_ERROR:
return StatusCode::kPipelineErrorChunkDemuxerErrorEosStatusNetworkError;
case AUDIO_RENDERER_ERROR:
return StatusCode::kPipelineErrorAudioRendererError;
case PIPELINE_ERROR_EXTERNAL_RENDERER_FAILED:
return StatusCode::kPipelineErrorExternalRendererFailed;
case DEMUXER_ERROR_DETECTED_HLS:
return StatusCode::kPipelineErrorDemuxerErrorDetectedHLS;
}
NOTREACHED();
// TODO(crbug.com/1153465): Log pipeline status that failed to convert.
// Return a generic decode error.
return StatusCode::kPipelineErrorDecode;
}
std::string PipelineStatusToString(PipelineStatus status) { std::string PipelineStatusToString(PipelineStatus status) {
#define STRINGIFY_STATUS_CASE(status) \ #define STRINGIFY_STATUS_CASE(status) \
case status: \ case status: \
......
...@@ -10,8 +10,10 @@ ...@@ -10,8 +10,10 @@
#include <string> #include <string>
#include "base/callback.h" #include "base/callback.h"
#include "base/optional.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "media/base/media_export.h" #include "media/base/media_export.h"
#include "media/base/status.h"
#include "media/base/timestamp_constants.h" #include "media/base/timestamp_constants.h"
namespace media { namespace media {
...@@ -59,6 +61,10 @@ enum PipelineStatus { ...@@ -59,6 +61,10 @@ enum PipelineStatus {
PIPELINE_STATUS_MAX = DEMUXER_ERROR_DETECTED_HLS, PIPELINE_STATUS_MAX = DEMUXER_ERROR_DETECTED_HLS,
}; };
MEDIA_EXPORT base::Optional<PipelineStatus> StatusCodeToPipelineStatus(
StatusCode status);
MEDIA_EXPORT StatusCode PipelineStatusToStatusCode(PipelineStatus status);
// Returns a string version of the status, unique to each PipelineStatus, and // Returns a string version of the status, unique to each PipelineStatus, and
// not including any ':'. This makes it suitable for usage in // not including any ':'. This makes it suitable for usage in
// MediaError.message as the UA-specific-error-code. // MediaError.message as the UA-specific-error-code.
......
...@@ -122,10 +122,40 @@ enum class StatusCode : StatusCodeType { ...@@ -122,10 +122,40 @@ enum class StatusCode : StatusCodeType {
kVaapiBadImageSize = 0x0000070C, kVaapiBadImageSize = 0x0000070C,
kVaapiNoTexture = 0x0000070D, kVaapiNoTexture = 0x0000070D,
// Format errors: 0x08 // Format Errors: 0x08
kH264ParsingError = 0x00000801, kH264ParsingError = 0x00000801,
kH264BufferTooSmall = 0x00000802, kH264BufferTooSmall = 0x00000802,
// Pipeline Errors: 0x09
// Deprecated: kPipelineErrorUrlNotFound = 0x00000901,
kPipelineErrorNetwork = 0x00000902,
kPipelineErrorDecode = 0x00000903,
// Deprecated: kPipelineErrorDecrypt = 0x00000904,
kPipelineErrorAbort = 0x00000905,
kPipelineErrorInitializationFailed = 0x00000906,
// Unused: 0x00000907
kPipelineErrorCouldNotRender = 0x00000908,
kPipelineErrorRead = 0x00000909,
// Deprecated: kPipelineErrorOperationPending = 0x0000090a,
kPipelineErrorInvalidState = 0x0000090b,
// Demuxer related errors.
kPipelineErrorDemuxerErrorCouldNotOpen = 0x0000090c,
kPipelineErrorDemuxerErrorCouldNotParse = 0x0000090d,
kPipelineErrorDemuxerErrorNoSupportedStreams = 0x0000090e,
// Decoder related errors.
kPipelineErrorDecoderErrorNotSupported = 0x0000090f,
// ChunkDemuxer related errors.
kPipelineErrorChuckDemuxerErrorAppendFailed = 0x00000910,
kPipelineErrorChunkDemuxerErrorEosStatusDecodeError = 0x00000911,
kPipelineErrorChunkDemuxerErrorEosStatusNetworkError = 0x00000912,
// Audio rendering errors.
kPipelineErrorAudioRendererError = 0x00000913,
// Deprecated: kPipelineErrorAudioRendererErrorSpliceFailed = 0x00000914,
kPipelineErrorExternalRendererFailed = 0x00000915,
// Android only. Used as a signal to fallback MediaPlayerRenderer, and thus
// not exactly an 'error' per say.
kPipelineErrorDemuxerErrorDetectedHLS = 0x00000916,
// DecodeStatus temporary codes. These names were chosen to match the // DecodeStatus temporary codes. These names were chosen to match the
// DecodeStatus enum, so that un-converted code can DecodeStatus::OK/etc. // DecodeStatus enum, so that un-converted code can DecodeStatus::OK/etc.
// Note that OK must result in Status::is_ok(), since converted code will // Note that OK must result in Status::is_ok(), since converted code will
......
...@@ -248,16 +248,23 @@ void MojoRenderer::OnEnded() { ...@@ -248,16 +248,23 @@ void MojoRenderer::OnEnded() {
client_->OnEnded(); client_->OnEnded();
} }
void MojoRenderer::OnError() { void MojoRenderer::OnError(const Status& status) {
DVLOG(1) << __func__; DVLOG(1) << __func__;
DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(!init_cb_); DCHECK(!init_cb_);
encountered_error_ = true; encountered_error_ = true;
base::Optional<PipelineStatus> pipeline_status =
StatusCodeToPipelineStatus(status.code());
// If an unexpected status code is encountered default
// back to a decode error.
if (!pipeline_status) {
// TODO(crbug.com/1153465): Log status code that failed to convert.
pipeline_status = PipelineStatus::PIPELINE_ERROR_DECODE;
}
// TODO(tim): Should we plumb error code from remote renderer? client_->OnError(*pipeline_status);
// http://crbug.com/410451.
client_->OnError(PIPELINE_ERROR_DECODE);
} }
void MojoRenderer::OnVideoNaturalSizeChange(const gfx::Size& size) { void MojoRenderer::OnVideoNaturalSizeChange(const gfx::Size& size) {
......
...@@ -72,7 +72,7 @@ class MojoRenderer : public Renderer, public mojom::RendererClient { ...@@ -72,7 +72,7 @@ class MojoRenderer : public Renderer, public mojom::RendererClient {
void OnBufferingStateChange(BufferingState state, void OnBufferingStateChange(BufferingState state,
BufferingStateChangeReason reason) override; BufferingStateChangeReason reason) override;
void OnEnded() override; void OnEnded() override;
void OnError() override; void OnError(const Status& status) override;
void OnAudioConfigChange(const AudioDecoderConfig& config) override; void OnAudioConfigChange(const AudioDecoderConfig& config) override;
void OnVideoConfigChange(const VideoDecoderConfig& config) override; void OnVideoConfigChange(const VideoDecoderConfig& config) override;
void OnVideoNaturalSizeChange(const gfx::Size& size) override; void OnVideoNaturalSizeChange(const gfx::Size& size) override;
......
...@@ -74,7 +74,7 @@ interface RendererClient { ...@@ -74,7 +74,7 @@ interface RendererClient {
// Executed if any error was encountered during decode or rendering. If // Executed if any error was encountered during decode or rendering. If
// this error happens during an operation that has a completion callback, // this error happens during an operation that has a completion callback,
// OnError() will be called before firing the completion callback. // OnError() will be called before firing the completion callback.
OnError(); OnError(Status status);
// Executed whenever DemuxerStream status returns kConfigChange. Initial // Executed whenever DemuxerStream status returns kConfigChange. Initial
// configs provided by OnMetadata. // configs provided by OnMetadata.
......
...@@ -71,7 +71,7 @@ class MockRendererClient : public mojom::RendererClient { ...@@ -71,7 +71,7 @@ class MockRendererClient : public mojom::RendererClient {
MOCK_METHOD2(OnBufferingStateChange, MOCK_METHOD2(OnBufferingStateChange,
void(BufferingState state, BufferingStateChangeReason reason)); void(BufferingState state, BufferingStateChangeReason reason));
MOCK_METHOD0(OnEnded, void()); MOCK_METHOD0(OnEnded, void());
MOCK_METHOD0(OnError, void()); MOCK_METHOD1(OnError, void(const Status& status));
MOCK_METHOD1(OnVideoOpacityChange, void(bool opaque)); MOCK_METHOD1(OnVideoOpacityChange, void(bool opaque));
MOCK_METHOD1(OnAudioConfigChange, void(const AudioDecoderConfig&)); MOCK_METHOD1(OnAudioConfigChange, void(const AudioDecoderConfig&));
MOCK_METHOD1(OnVideoConfigChange, void(const VideoDecoderConfig&)); MOCK_METHOD1(OnVideoConfigChange, void(const VideoDecoderConfig&));
......
...@@ -153,7 +153,9 @@ void MojoRendererService::SetCdm( ...@@ -153,7 +153,9 @@ void MojoRendererService::SetCdm(
void MojoRendererService::OnError(PipelineStatus error) { void MojoRendererService::OnError(PipelineStatus error) {
DVLOG(1) << __func__ << "(" << error << ")"; DVLOG(1) << __func__ << "(" << error << ")";
state_ = STATE_ERROR; state_ = STATE_ERROR;
client_->OnError(); StatusCode status_code = PipelineStatusToStatusCode(error);
auto status = Status(status_code, PipelineStatusToString(error));
client_->OnError(status);
} }
void MojoRendererService::OnEnded() { void MojoRendererService::OnEnded() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment