Seek(duration);
}
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+void HTMLMediaElement::OnEmssPipelineError(MediaError* error) {
+ MediaEngineError(error);
+}
+#endif // defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+
void HTMLMediaElement::RemotePlaybackCompatibilityChanged(const WebURL& url,
bool is_compatible) {
if (RemotePlaybackClient())
void HTMLMediaElement::FireDeferredLoadAfterSourceOpen() {
LOG(INFO) << "FireDeferredLoadAfterSourceOpen(" << *this << ")";
- if (!web_media_player_ || !src_object_stream_descriptor_)
+ if (!web_media_player_ || !src_object_stream_descriptor_ || error_)
return;
auto source =
if (error) {
DLOG(ERROR) << __func__ << ": {code=" << error->code()
<< ", message=" << error->message() << "}";
- if (media_source_attachment_)
+ if (media_source_attachment_) {
media_source_attachment_->OnElementError();
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+ if (media_source_attachment_->IsElementaryMediaStreamSource()) {
+ media_source_attachment_->OnError(
+ media_source_tracer_, *error);
+ }
+#endif
+ }
}
}
void CloseMediaSource();
void DurationChanged(double duration, bool request_seek);
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+ // elementary media stream source
+
+ // Used when WebMediaPlayer implementation is not be used to report EMSS
+ // errors. Typically this happens when TTvd is used in low latency and
+ // decoding is managed directly by EMSS.
+ void OnEmssPipelineError(MediaError*);
+#endif
+
// controls
bool ShouldShowControls(
const RecordMetricsBehavior = RecordMetricsBehavior::kDoNotRecord) const;
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+#include "core/html/media/media_error.h"
+#endif // defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+
namespace blink {
#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
virtual bool IsGameMode(MediaSourceTracer* tracer) const = 0;
virtual bool IsLowLatencyMode(MediaSourceTracer* tracer) const = 0;
virtual bool IsVideoTextureMode(MediaSourceTracer* tracer) const = 0;
+ virtual void OnError(MediaSourceTracer*, const blink::MediaError&) = 0;
virtual void OnLoadDeferredUntilSourceOpen(
MediaSourceTracer* tracer,
base::OnceClosure on_source_opened) = 0;
return false;
}
+void MediaSourceAttachmentSupplement::OnError(MediaSourceTracer*,
+ const blink::MediaError&) {}
+
void MediaSourceAttachmentSupplement::OnLoadDeferredUntilSourceOpen(
MediaSourceTracer*,
base::OnceClosure) {}
bool IsGameMode(MediaSourceTracer* tracer) const override;
bool IsLowLatencyMode(MediaSourceTracer* tracer) const override;
bool IsVideoTextureMode(MediaSourceTracer* tracer) const override;
+ void OnError(MediaSourceTracer*, const blink::MediaError&) override;
void OnLoadDeferredUntilSourceOpen(
MediaSourceTracer* tracer,
base::OnceClosure on_source_opened) override;
void MsDecodingStream::OnClosedCaptions(std::vector<uint8_t> closed_captions) {}
-void MsDecodingStream::OnPlayerError(BackendError,
+void MsDecodingStream::OnPlayerError(BackendError error,
std::string message,
- base::OnceClosure on_error_reported) {}
+ base::OnceClosure on_error_reported) {
+ EMSS_DEBUG() << error << ", message = " << message;
+
+ if (auto client = client_.lock())
+ client->OnPlayerError(error, message);
+
+ // We're on control thread and we can safely assume that the error was already
+ // reported to JS after the client call above.
+ std::move(on_error_reported).Run();
+}
void MsDecodingStream::OnResumeComplete() {}
#include "media/base/audio_codecs.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/media_track.h"
+#include "media/base/pipeline_status.h"
#include "media/base/video_decoder_config.h"
#include "platform/mediastream/media_stream_component.h"
#include "services/elementary_media_stream_source/public/cpp/logger.h"
base::BindOnce(
[](base::WeakPtr<ElementaryMediaStreamSource> ptr,
OperationCallbackResult result) {
+ EMSS_DEBUG_NO_INSTANCE()
+ << "close() promise resolver, have ptr = " << !!ptr;
+
if (!ptr)
return;
return;
}
+ if (!ptr->close_resolver_) {
+ EMSS_DEBUG_NO_INSTANCE()
+ << "close() promise was already resolved.";
+ return;
+ }
+
ptr->ResolvePromise(
ptr->close_resolver_, result,
// This will fail only if Play/Pause/Seek triggered track state
base::BindOnce(
[](base::WeakPtr<ElementaryMediaStreamSource> ptr,
OperationCallbackResult result) {
+ EMSS_DEBUG_NO_INSTANCE()
+ << "open() promise resolver, have ptr = " << !!ptr;
+
if (!ptr)
return;
return;
}
+ if (!ptr->open_resolver_) {
+ EMSS_DEBUG_NO_INSTANCE()
+ << "open() promise was already resolved.";
+ return;
+ }
+
ptr->ResolvePromise(
ptr->open_resolver_, result,
// This will fail only if Play/Pause/Seek triggered track state
load_deferred_until_source_open_cb_ = std::move(on_source_opened);
}
+void ElementaryMediaStreamSource::OnPlayerError(
+ const blink::MediaError& media_error) {
+ using DemuxerMode = content::elementary_media_stream_source::DemuxerMode;
+
+ EMSS_DEBUG() << media_error.code() << ": " << media_error.message();
+
+ if (!web_elementary_media_stream_source_dispatcher_) {
+ EMSS_DEBUG();
+ return;
+ }
+
+ const bool is_ttvd_used =
+ web_elementary_media_stream_source_dispatcher_->pipeline_mode()
+ .demuxer_mode == DemuxerMode::kMediaStream;
+ if (!is_ttvd_used || IsLowLatencyMode()) {
+ // Non-TTvd transmits error directly from EMSS renderer. TTvd low latency
+ // generates error in MsDecodingStream and then passes this info to media
+ // element.
+ EMSS_DEBUG() << "A more precise error info is expected to be delivered by "
+ "other means and this one should be discarded.";
+ return;
+ }
+
+ const auto player_error =
+ media_error.code() == blink::MediaError::kMediaErrSrcNotSupported
+ ? BackendError::kConfigError
+ : BackendError::kPipelineError;
+ OnPlayerError(player_error, media_error.message().Ascii());
+}
+
void ElementaryMediaStreamSource::OnPause() {
EMSS_DEBUG();
DispatchEvent(*ElementaryMediaErrorEvent::Create(error, message));
+ if (media_stream_descriptor_ && IsLowLatencyMode()) {
+ // When TTvd is used in low latency modes, web media player will NOT make
+ // media element send an error, therefore we trigger it from EMSS:
+ PropagateErrorViaMediaSourceAttachment(error, message);
+ }
+
Stop();
}
OperationCallbackResult result,
const WTF::String& on_error) {
EMSS_DEBUG_NO_INSTANCE();
+ EMSS_LOG_ASSERT(resolver);
switch (result) {
case OperationCallbackResult::kSuccess:
}
}
+void ElementaryMediaStreamSource::PropagateErrorViaMediaSourceAttachment(
+ BackendError error,
+ const std::string& message) {
+ EMSS_DEBUG() << error << ", " << message;
+
+ if (!emss_attachment_ || !emss_tracer_)
+ return;
+
+ const auto error_code = error == BackendError::kConfigError
+ ? MediaError::kMediaErrSrcNotSupported
+ : MediaError::kMediaErrDecode;
+ emss_attachment_->OnEmssPipelineError(
+ emss_tracer_,
+ MakeGarbageCollected<MediaError>(error_code, String{message}));
+}
+
void ElementaryMediaStreamSource::SetReadyState(ReadyState state) {
EMSS_LOG(INFO) << "Requested ready state change from " << ready_state_
<< " to " << state;
bool IsLowLatencyMode() const;
bool IsVideoTextureMode() const;
void OnLoadDeferredUntilSourceOpen(base::OnceClosure on_source_opened);
+ void OnPlayerError(const blink::MediaError& media_error);
void OnPause();
void OnPlay();
void OnResume();
bool IsCalledByLifecycleObserver() const;
bool IsExecutionContextDestroyed() const;
void OnReadyStateChanged();
+ void PropagateErrorViaMediaSourceAttachment(BackendError,
+ const std::string& message);
void SetReadyState(ReadyState new_state);
static void ResolvePromise(ScriptPromiseResolver* resolver,
#ifndef TIZEN_SRC_CHROMIUM_IMPL_THIRD_PARTY_BLINK_RENDERER_MODULES_ELEMENTARY_MEDIA_STREAM_SOURCE_ELEMENTARY_MEDIA_STREAM_SOURCE_ATTACHMENT_H_
#define TIZEN_SRC_CHROMIUM_IMPL_THIRD_PARTY_BLINK_RENDERER_MODULES_ELEMENTARY_MEDIA_STREAM_SOURCE_ELEMENTARY_MEDIA_STREAM_SOURCE_ATTACHMENT_H_
+#include "core/html/media/media_error.h"
#include "third_party/blink/renderer/core/html/media/media_source_attachment.h"
namespace blink {
virtual void OnDurationChanged(MediaSourceTracer* tracer,
double duration,
ShouldSeekToNewDuration should_seek) = 0;
+ virtual void OnEmssPipelineError(MediaSourceTracer* tracer,
+ MediaError* error) = 0;
// URLRegistrable interface:
GetSource(tracer)->OnPause();
}
+void SameThreadElementaryMediaStreamSourceAttachment::OnError(
+ MediaSourceTracer* tracer,
+ const blink::MediaError& media_error) {
+ EMSS_DEBUG();
+
+ GetSource(tracer)->OnPlayerError(media_error);
+}
+
void SameThreadElementaryMediaStreamSourceAttachment::
OnLoadDeferredUntilSourceOpen(MediaSourceTracer* tracer,
base::OnceClosure on_source_opened) {
GetMediaElement(tracer)->DurationChanged(duration, seek_to_duration);
}
+void SameThreadElementaryMediaStreamSourceAttachment::OnEmssPipelineError(
+ MediaSourceTracer* tracer,
+ MediaError* error) {
+ EMSS_DEBUG();
+
+ GetMediaElement(tracer)->OnEmssPipelineError(error);
+}
+
} // namespace blink
bool IsVideoTextureMode(MediaSourceTracer* tracer) const override;
+ void OnError(MediaSourceTracer* tracer, const blink::MediaError&) override;
+
void OnLoadDeferredUntilSourceOpen(
MediaSourceTracer* tracer,
base::OnceClosure on_source_opened) override;
void OnDurationChanged(MediaSourceTracer* tracer,
double duration,
ShouldSeekToNewDuration) override;
+ void OnEmssPipelineError(MediaSourceTracer* tracer,
+ MediaError* error) override;
private:
// This class is created exclusively by URLElementaryMediaStreamSource, which
auto blink_source_dispatcher = std::make_shared<
blink::WebElementaryMediaStreamSourceDispatcher>(
- control_thread_task_runner, std::move(source_dispatcher),
+ pipeline_mode, control_thread_task_runner, std::move(source_dispatcher),
std::static_pointer_cast<blink::WebElementaryMediaStreamSourceControl>(
control_thread_source_impl));
WebElementaryMediaStreamSourceDispatcher::
WebElementaryMediaStreamSourceDispatcher(
+ PipelineMode pipeline_mode,
scoped_refptr<base::SingleThreadTaskRunner> control_thread_task_runner,
std::shared_ptr<SourceDispatcher> source_dispatcher,
std::shared_ptr<WebElementaryMediaStreamSourceControl> client)
: Dispatcher(std::move(control_thread_task_runner)),
+ pipeline_mode_(pipeline_mode),
source_dispatcher_(std::move(source_dispatcher)) {
EMSS_DEBUG() << "Constructing object";
scoped_refptr<base::SingleThreadTaskRunner> worker_thread_task_runner);
WebElementaryMediaStreamSourceDispatcher(
+ PipelineMode pipeline_mode,
scoped_refptr<base::SingleThreadTaskRunner> control_thread_task_runner,
std::shared_ptr<SourceDispatcher> source_dispatcher,
std::shared_ptr<WebElementaryMediaStreamSourceControl> client);
~WebElementaryMediaStreamSourceDispatcher() override;
+ const PipelineMode& pipeline_mode() const { return pipeline_mode_; }
+
std::shared_ptr<WebElementaryMediaTrackDispatcher> CreateAudioTrackDispatcher(
media::AudioDecoderConfig&& config,
DecodingMode decoding_mode) {
}
private:
+ const PipelineMode pipeline_mode_;
+
std::tuple<std::shared_ptr<WebElementaryMediaStreamSourceControl>> clients_;
std::shared_ptr<SourceDispatcher> source_dispatcher_;