diff options
Diffstat (limited to 'chromium/fuchsia/engine/renderer')
13 files changed, 764 insertions, 57 deletions
diff --git a/chromium/fuchsia/engine/renderer/cast_streaming_demuxer.cc b/chromium/fuchsia/engine/renderer/cast_streaming_demuxer.cc new file mode 100644 index 00000000000..92937f33b35 --- /dev/null +++ b/chromium/fuchsia/engine/renderer/cast_streaming_demuxer.cc @@ -0,0 +1,352 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "fuchsia/engine/renderer/cast_streaming_demuxer.h" + +#include "base/bind.h" +#include "base/sequence_checker.h" +#include "base/single_thread_task_runner.h" +#include "fuchsia/engine/renderer/cast_streaming_receiver.h" +#include "media/base/audio_decoder_config.h" +#include "media/base/decoder_buffer.h" +#include "media/base/timestamp_constants.h" +#include "media/base/video_decoder_config.h" +#include "media/mojo/common/mojo_decoder_buffer_converter.h" + +namespace { + +// media::DemuxerStream shared audio/video implementation for Cast Streaming. +// Receives buffer metadata over a Mojo service and reads the buffers over a +// Mojo data pipe from the browser process. +class CastStreamingDemuxerStream : public media::DemuxerStream, + public mojom::CastStreamingBufferReceiver { + public: + CastStreamingDemuxerStream( + mojo::PendingReceiver<mojom::CastStreamingBufferReceiver> + pending_receiver, + mojo::ScopedDataPipeConsumerHandle consumer) + : receiver_(this, std::move(pending_receiver)), + decoder_buffer_reader_(std::move(consumer)) { + DVLOG(1) << __func__; + + // Mojo service disconnection means the Cast Streaming Session ended and no + // further buffer will be received. kAborted will be returned to the media + // pipeline for every subsequent DemuxerStream::Read() attempt. + receiver_.set_disconnect_handler(base::BindOnce( + &CastStreamingDemuxerStream::OnMojoDisconnect, base::Unretained(this))); + } + ~CastStreamingDemuxerStream() override { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + } + + // mojom::CastStreamingBufferReceiver implementation. + void ProvideBuffer(media::mojom::DecoderBufferPtr buffer) final { + DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + pending_buffer_metadata_.push_back(std::move(buffer)); + GetNextBuffer(); + } + + void AbortPendingRead() { + DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (pending_read_cb_) + std::move(pending_read_cb_).Run(Status::kAborted, nullptr); + } + + private: + void CompletePendingRead() { + DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!pending_read_cb_ || !current_buffer_) + return; + + if (current_buffer_->end_of_stream()) { + std::move(pending_read_cb_).Run(Status::kAborted, nullptr); + return; + } + + std::move(pending_read_cb_).Run(Status::kOk, std::move(current_buffer_)); + GetNextBuffer(); + } + + void GetNextBuffer() { + DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (current_buffer_ || pending_buffer_metadata_.empty()) + return; + + media::mojom::DecoderBufferPtr buffer = + std::move(pending_buffer_metadata_.front()); + pending_buffer_metadata_.pop_front(); + decoder_buffer_reader_.ReadDecoderBuffer( + std::move(buffer), + base::BindOnce(&CastStreamingDemuxerStream::OnBufferRead, + base::Unretained(this))); + } + + void OnBufferRead(scoped_refptr<media::DecoderBuffer> buffer) { + DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // Stop processing the pending buffer. OnMojoDisconnect() will trigger + // sending kAborted on subsequent Read() calls. This can happen if this + // object was in the process of reading a buffer off the data pipe when the + // Mojo connection ended. + if (!receiver_.is_bound()) + return; + + DCHECK(!current_buffer_); + current_buffer_ = buffer; + CompletePendingRead(); + } + + void OnMojoDisconnect() { + DVLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + receiver_.reset(); + pending_buffer_metadata_.clear(); + current_buffer_ = media::DecoderBuffer::CreateEOSBuffer(); + CompletePendingRead(); + } + + // DemuxerStream implementation. + void Read(ReadCB read_cb) final { + DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(pending_read_cb_.is_null()); + pending_read_cb_ = std::move(read_cb); + CompletePendingRead(); + } + bool IsReadPending() const final { return !pending_read_cb_.is_null(); } + Liveness liveness() const final { return Liveness::LIVENESS_LIVE; } + bool SupportsConfigChanges() final { return false; } + + mojo::Receiver<CastStreamingBufferReceiver> receiver_; + media::MojoDecoderBufferReader decoder_buffer_reader_; + + ReadCB pending_read_cb_; + base::circular_deque<media::mojom::DecoderBufferPtr> pending_buffer_metadata_; + scoped_refptr<media::DecoderBuffer> current_buffer_; + + SEQUENCE_CHECKER(sequence_checker_); +}; + +} // namespace + +class CastStreamingAudioDemuxerStream : public CastStreamingDemuxerStream { + public: + explicit CastStreamingAudioDemuxerStream( + mojom::AudioStreamInfoPtr audio_stream_info) + : CastStreamingDemuxerStream( + std::move(audio_stream_info->buffer_receiver), + std::move(audio_stream_info->data_pipe)), + config_(audio_stream_info->decoder_config) { + DVLOG(1) << __func__ + << ": config info: " << config_.AsHumanReadableString(); + } + ~CastStreamingAudioDemuxerStream() final = default; + + private: + // DemuxerStream implementation. + media::AudioDecoderConfig audio_decoder_config() final { return config_; } + media::VideoDecoderConfig video_decoder_config() final { + NOTREACHED(); + return media::VideoDecoderConfig(); + } + Type type() const final { return Type::AUDIO; } + + media::AudioDecoderConfig config_; +}; + +class CastStreamingVideoDemuxerStream : public CastStreamingDemuxerStream { + public: + explicit CastStreamingVideoDemuxerStream( + mojom::VideoStreamInfoPtr video_stream_info) + : CastStreamingDemuxerStream( + std::move(video_stream_info->buffer_receiver), + std::move(video_stream_info->data_pipe)), + config_(video_stream_info->decoder_config) { + DVLOG(1) << __func__ + << ": config info: " << config_.AsHumanReadableString(); + } + ~CastStreamingVideoDemuxerStream() final = default; + + private: + // DemuxerStream implementation. + media::AudioDecoderConfig audio_decoder_config() final { + NOTREACHED(); + return media::AudioDecoderConfig(); + } + media::VideoDecoderConfig video_decoder_config() final { return config_; } + Type type() const final { return Type::VIDEO; } + + media::VideoDecoderConfig config_; +}; + +CastStreamingDemuxer::CastStreamingDemuxer( + CastStreamingReceiver* receiver, + const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner) + : media_task_runner_(media_task_runner), + original_task_runner_(base::SequencedTaskRunnerHandle::Get()), + receiver_(receiver) { + DVLOG(1) << __func__; + DCHECK(receiver_); +} + +CastStreamingDemuxer::~CastStreamingDemuxer() { + DVLOG(1) << __func__; + DCHECK(media_task_runner_->BelongsToCurrentThread()); + + if (was_initialization_successful_) { + original_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&CastStreamingReceiver::OnDemuxerDestroyed, + base::Unretained(receiver_))); + } +} + +void CastStreamingDemuxer::OnStreamsInitialized( + mojom::AudioStreamInfoPtr audio_stream_info, + mojom::VideoStreamInfoPtr video_stream_info) { + DVLOG(1) << __func__; + DCHECK(!media_task_runner_->BelongsToCurrentThread()); + + media_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&CastStreamingDemuxer::OnStreamsInitializedOnMediaThread, + base::Unretained(this), std::move(audio_stream_info), + std::move(video_stream_info))); +} + +void CastStreamingDemuxer::OnStreamsInitializedOnMediaThread( + mojom::AudioStreamInfoPtr audio_stream_info, + mojom::VideoStreamInfoPtr video_stream_info) { + DVLOG(1) << __func__; + DCHECK(media_task_runner_->BelongsToCurrentThread()); + DCHECK(initialized_cb_); + + if (!audio_stream_info && !video_stream_info) { + std::move(initialized_cb_) + .Run(media::PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN); + return; + } + + if (audio_stream_info) { + audio_stream_ = std::make_unique<CastStreamingAudioDemuxerStream>( + std::move(audio_stream_info)); + } + if (video_stream_info) { + video_stream_ = std::make_unique<CastStreamingVideoDemuxerStream>( + std::move(video_stream_info)); + } + was_initialization_successful_ = true; + + std::move(initialized_cb_).Run(media::PipelineStatus::PIPELINE_OK); +} + +std::vector<media::DemuxerStream*> CastStreamingDemuxer::GetAllStreams() { + DVLOG(1) << __func__; + DCHECK(media_task_runner_->BelongsToCurrentThread()); + + std::vector<media::DemuxerStream*> streams; + if (video_stream_) + streams.push_back(video_stream_.get()); + if (audio_stream_) + streams.push_back(audio_stream_.get()); + return streams; +} + +std::string CastStreamingDemuxer::GetDisplayName() const { + return "CastStreamingDemuxer"; +} + +void CastStreamingDemuxer::Initialize(media::DemuxerHost* host, + media::PipelineStatusCallback status_cb) { + DVLOG(1) << __func__; + DCHECK(media_task_runner_->BelongsToCurrentThread()); + host_ = host; + + // Live streams have infinite duration. + host_->SetDuration(media::kInfiniteDuration); + initialized_cb_ = std::move(status_cb); + + original_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&CastStreamingReceiver::SetDemuxer, + base::Unretained(receiver_), base::Unretained(this))); +} + +void CastStreamingDemuxer::AbortPendingReads() { + DVLOG(2) << __func__; + DCHECK(media_task_runner_->BelongsToCurrentThread()); + + if (audio_stream_) + audio_stream_->AbortPendingRead(); + if (video_stream_) + video_stream_->AbortPendingRead(); +} + +// Not supported. +void CastStreamingDemuxer::StartWaitingForSeek(base::TimeDelta seek_time) {} + +// Not supported. +void CastStreamingDemuxer::CancelPendingSeek(base::TimeDelta seek_time) {} + +// Not supported. +void CastStreamingDemuxer::Seek(base::TimeDelta time, + media::PipelineStatusCallback status_cb) { + std::move(status_cb).Run(media::PipelineStatus::PIPELINE_OK); +} + +void CastStreamingDemuxer::Stop() { + DVLOG(1) << __func__; + DCHECK(media_task_runner_->BelongsToCurrentThread()); + + if (audio_stream_) + audio_stream_.reset(); + if (video_stream_) + video_stream_.reset(); +} + +base::TimeDelta CastStreamingDemuxer::GetStartTime() const { + return base::TimeDelta(); +} + +// Not supported. +base::Time CastStreamingDemuxer::GetTimelineOffset() const { + return base::Time(); +} + +// Not supported. +int64_t CastStreamingDemuxer::GetMemoryUsage() const { + return 0; +} + +base::Optional<media::container_names::MediaContainerName> +CastStreamingDemuxer::GetContainerForMetrics() const { + // Cast Streaming frames have no container. + return base::nullopt; +} + +// Not supported. +void CastStreamingDemuxer::OnEnabledAudioTracksChanged( + const std::vector<media::MediaTrack::Id>& track_ids, + base::TimeDelta curr_time, + TrackChangeCB change_completed_cb) { + DLOG(WARNING) << "Track changes are not supported."; + std::vector<media::DemuxerStream*> streams; + std::move(change_completed_cb).Run(media::DemuxerStream::AUDIO, streams); +} + +// Not supported. +void CastStreamingDemuxer::OnSelectedVideoTrackChanged( + const std::vector<media::MediaTrack::Id>& track_ids, + base::TimeDelta curr_time, + TrackChangeCB change_completed_cb) { + DLOG(WARNING) << "Track changes are not supported."; + std::vector<media::DemuxerStream*> streams; + std::move(change_completed_cb).Run(media::DemuxerStream::VIDEO, streams); +} diff --git a/chromium/fuchsia/engine/renderer/cast_streaming_demuxer.h b/chromium/fuchsia/engine/renderer/cast_streaming_demuxer.h new file mode 100644 index 00000000000..849320655bd --- /dev/null +++ b/chromium/fuchsia/engine/renderer/cast_streaming_demuxer.h @@ -0,0 +1,84 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FUCHSIA_ENGINE_RENDERER_CAST_STREAMING_DEMUXER_H_ +#define FUCHSIA_ENGINE_RENDERER_CAST_STREAMING_DEMUXER_H_ + +#include "fuchsia/engine/cast_streaming_session.mojom.h" +#include "media/base/demuxer.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" + +namespace base { +class SingleThreadTaskRunner; +} + +class CastStreamingReceiver; +class CastStreamingAudioDemuxerStream; +class CastStreamingVideoDemuxerStream; + +// media::Demuxer implementation for a Cast Streaming Receiver. +// This object is instantiated on the main thread, whose task runner is stored +// as |original_task_runner_|. OnStreamsInitialized() is the only method called +// on the main thread. Every other method is called on the media thread, whose +// task runner is |media_task_runner_|. +// |original_task_runner_| is used to post method calls to |receiver_|, which is +// guaranteed to outlive this object. +// TODO(crbug.com/1082821): Simplify the CastStreamingDemuxer initialization +// sequence when the CastStreamingReceiver Component has been implemented. +class CastStreamingDemuxer : public media::Demuxer { + public: + CastStreamingDemuxer( + CastStreamingReceiver* receiver, + const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner); + ~CastStreamingDemuxer() final; + + CastStreamingDemuxer(const CastStreamingDemuxer&) = delete; + CastStreamingDemuxer& operator=(const CastStreamingDemuxer&) = delete; + + void OnStreamsInitialized(mojom::AudioStreamInfoPtr audio_stream_info, + mojom::VideoStreamInfoPtr video_stream_info); + + private: + void OnStreamsInitializedOnMediaThread( + mojom::AudioStreamInfoPtr audio_stream_info, + mojom::VideoStreamInfoPtr video_stream_info); + + // media::Demuxer implementation. + std::vector<media::DemuxerStream*> GetAllStreams() final; + std::string GetDisplayName() const final; + void Initialize(media::DemuxerHost* host, + media::PipelineStatusCallback status_cb) final; + void AbortPendingReads() final; + void StartWaitingForSeek(base::TimeDelta seek_time) final; + void CancelPendingSeek(base::TimeDelta seek_time) final; + void Seek(base::TimeDelta time, + media::PipelineStatusCallback status_cb) final; + void Stop() final; + base::TimeDelta GetStartTime() const final; + base::Time GetTimelineOffset() const final; + int64_t GetMemoryUsage() const final; + base::Optional<media::container_names::MediaContainerName> + GetContainerForMetrics() const final; + void OnEnabledAudioTracksChanged( + const std::vector<media::MediaTrack::Id>& track_ids, + base::TimeDelta curr_time, + TrackChangeCB change_completed_cb) final; + void OnSelectedVideoTrackChanged( + const std::vector<media::MediaTrack::Id>& track_ids, + base::TimeDelta curr_time, + TrackChangeCB change_completed_cb) final; + + scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_; + scoped_refptr<base::SequencedTaskRunner> original_task_runner_; + media::DemuxerHost* host_ = nullptr; + std::unique_ptr<CastStreamingAudioDemuxerStream> audio_stream_; + std::unique_ptr<CastStreamingVideoDemuxerStream> video_stream_; + + // Set to true if the Demuxer was successfully initialized. + bool was_initialization_successful_ = false; + media::PipelineStatusCallback initialized_cb_; + CastStreamingReceiver* const receiver_; +}; + +#endif // FUCHSIA_ENGINE_RENDERER_LIBCAST_STREAMING_DEMUXER_H_ diff --git a/chromium/fuchsia/engine/renderer/cast_streaming_receiver.cc b/chromium/fuchsia/engine/renderer/cast_streaming_receiver.cc new file mode 100644 index 00000000000..98654200d90 --- /dev/null +++ b/chromium/fuchsia/engine/renderer/cast_streaming_receiver.cc @@ -0,0 +1,128 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "fuchsia/engine/renderer/cast_streaming_receiver.h" + +#include "content/public/renderer/render_frame.h" +#include "fuchsia/engine/renderer/cast_streaming_demuxer.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h" + +CastStreamingReceiver::CastStreamingReceiver( + content::RenderFrame* render_frame) { + DVLOG(1) << __func__; + DCHECK(render_frame); + + // It is fine to use an unretained pointer to |this| here as the + // AssociatedInterfaceRegistry, owned by |render_frame| will be torn-down at + // the same time as |this|. + render_frame->GetAssociatedInterfaceRegistry()->AddInterface( + base::BindRepeating(&CastStreamingReceiver::BindToReceiver, + base::Unretained(this))); +} + +CastStreamingReceiver::~CastStreamingReceiver() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} + +void CastStreamingReceiver::SetDemuxer(CastStreamingDemuxer* demuxer) { + DVLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(demuxer); + + if (demuxer_) { + // We do not support more than one active CastStreamingDemuxer in the same + // RenderFrame. Return early here. + demuxer->OnStreamsInitialized(mojom::AudioStreamInfoPtr(), + mojom::VideoStreamInfoPtr()); + return; + } + + DCHECK(!is_demuxer_initialized_); + + if (IsBound()) { + demuxer_ = demuxer; + MaybeCallEnableReceiverCallback(); + } else { + // The Cast Streaming Sender disconnected after |demuxer| was instantiated + // but before |demuxer| was initialized on the media thread. + demuxer->OnStreamsInitialized(mojom::AudioStreamInfoPtr(), + mojom::VideoStreamInfoPtr()); + } +} + +void CastStreamingReceiver::OnDemuxerDestroyed() { + DVLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(demuxer_); + + demuxer_ = nullptr; + is_demuxer_initialized_ = false; + cast_streaming_receiver_receiver_.reset(); +} + +void CastStreamingReceiver::BindToReceiver( + mojo::PendingAssociatedReceiver<mojom::CastStreamingReceiver> receiver) { + DVLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(!cast_streaming_receiver_receiver_.is_bound()); + + cast_streaming_receiver_receiver_.Bind(std::move(receiver)); + + // Mojo service disconnection means the Cast Streaming Session ended or the + // Cast Streaming Sender disconnected. + cast_streaming_receiver_receiver_.set_disconnect_handler(base::BindOnce( + &CastStreamingReceiver::OnReceiverDisconnected, base::Unretained(this))); +} + +bool CastStreamingReceiver::IsBound() const { + DVLOG(2) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + return cast_streaming_receiver_receiver_.is_bound(); +} + +void CastStreamingReceiver::MaybeCallEnableReceiverCallback() { + DVLOG(2) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (enable_receiver_callback_ && demuxer_) + std::move(enable_receiver_callback_).Run(); +} + +void CastStreamingReceiver::OnReceiverDisconnected() { + DVLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + cast_streaming_receiver_receiver_.reset(); + enable_receiver_callback_.Reset(); + + if (demuxer_ && !is_demuxer_initialized_) { + OnStreamsInitialized(mojom::AudioStreamInfoPtr(), + mojom::VideoStreamInfoPtr()); + } +} + +void CastStreamingReceiver::EnableReceiver(EnableReceiverCallback callback) { + DVLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(!enable_receiver_callback_); + DCHECK(callback); + + enable_receiver_callback_ = std::move(callback); + MaybeCallEnableReceiverCallback(); +} + +void CastStreamingReceiver::OnStreamsInitialized( + mojom::AudioStreamInfoPtr audio_stream_info, + mojom::VideoStreamInfoPtr video_stream_info) { + DVLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(!is_demuxer_initialized_); + DCHECK(demuxer_); + + is_demuxer_initialized_ = true; + demuxer_->OnStreamsInitialized(std::move(audio_stream_info), + std::move(video_stream_info)); +} diff --git a/chromium/fuchsia/engine/renderer/cast_streaming_receiver.h b/chromium/fuchsia/engine/renderer/cast_streaming_receiver.h new file mode 100644 index 00000000000..a95a4aededf --- /dev/null +++ b/chromium/fuchsia/engine/renderer/cast_streaming_receiver.h @@ -0,0 +1,63 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FUCHSIA_ENGINE_RENDERER_CAST_STREAMING_RECEIVER_H_ +#define FUCHSIA_ENGINE_RENDERER_CAST_STREAMING_RECEIVER_H_ + +#include "base/sequence_checker.h" +#include "fuchsia/engine/cast_streaming_session.mojom.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" +#include "mojo/public/cpp/bindings/pending_associated_receiver.h" + +namespace content { +class RenderFrame; +} // namespace content + +class CastStreamingDemuxer; + +// Handles the Cast Streaming Session lifetime in the renderer process. +// Owned by WebEngineRenderFrameObserver, this object will be destroyed on +// RenderFrame destruction. This is guaranteed to outlive the +// CastStreamingDemuxer that uses it as the RenderFrame destruction will have +// triggered the destruction of the media pipeline and the CastStreamingDemuxer +// before the call to content::RenderFrameObserver::OnDestruct(), which triggers +// this object destruction. +class CastStreamingReceiver : public mojom::CastStreamingReceiver { + public: + explicit CastStreamingReceiver(content::RenderFrame* frame); + ~CastStreamingReceiver() final; + + CastStreamingReceiver(const CastStreamingReceiver&) = delete; + CastStreamingReceiver& operator=(const CastStreamingReceiver&) = delete; + + void SetDemuxer(CastStreamingDemuxer* demuxer); + void OnDemuxerDestroyed(); + + // Returns true if a Mojo connection is active. + bool IsBound() const; + + private: + void BindToReceiver( + mojo::PendingAssociatedReceiver<mojom::CastStreamingReceiver> receiver); + + void MaybeCallEnableReceiverCallback(); + + void OnReceiverDisconnected(); + + // mojom::CastStreamingReceiver implementation. + void EnableReceiver(EnableReceiverCallback callback) final; + void OnStreamsInitialized(mojom::AudioStreamInfoPtr audio_stream_info, + mojom::VideoStreamInfoPtr video_stream_info) final; + + mojo::AssociatedReceiver<mojom::CastStreamingReceiver> + cast_streaming_receiver_receiver_{this}; + + EnableReceiverCallback enable_receiver_callback_; + CastStreamingDemuxer* demuxer_ = nullptr; + bool is_demuxer_initialized_ = false; + + SEQUENCE_CHECKER(sequence_checker_); +}; + +#endif // FUCHSIA_ENGINE_RENDERER_CAST_STREAMING_RECEIVER_H_ diff --git a/chromium/fuchsia/engine/renderer/on_load_script_injector.cc b/chromium/fuchsia/engine/renderer/on_load_script_injector.cc index b966fbacc1e..6fd0a6db314 100644 --- a/chromium/fuchsia/engine/renderer/on_load_script_injector.cc +++ b/chromium/fuchsia/engine/renderer/on_load_script_injector.cc @@ -28,12 +28,7 @@ void OnLoadScriptInjector::BindToReceiver( } void OnLoadScriptInjector::DidCommitProvisionalLoad( - bool is_same_document_navigation, ui::PageTransition transition) { - // Ignore pushState or document fragment navigation. - if (is_same_document_navigation) - return; - // Don't inject anything for subframes. if (!render_frame()->IsMainFrame()) return; diff --git a/chromium/fuchsia/engine/renderer/on_load_script_injector.h b/chromium/fuchsia/engine/renderer/on_load_script_injector.h index 80bd6b98d76..3e5364e8948 100644 --- a/chromium/fuchsia/engine/renderer/on_load_script_injector.h +++ b/chromium/fuchsia/engine/renderer/on_load_script_injector.h @@ -30,8 +30,7 @@ class OnLoadScriptInjector : public content::RenderFrameObserver, // RenderFrameObserver override: void OnDestruct() override; - void DidCommitProvisionalLoad(bool is_same_document_navigation, - ui::PageTransition transition) override; + void DidCommitProvisionalLoad(ui::PageTransition transition) override; private: // Called by OnDestruct(), when the RenderFrame is destroyed. diff --git a/chromium/fuchsia/engine/renderer/url_request_rules_receiver.cc b/chromium/fuchsia/engine/renderer/url_request_rules_receiver.cc index 0b0874954d0..c1da8c7bb99 100644 --- a/chromium/fuchsia/engine/renderer/url_request_rules_receiver.cc +++ b/chromium/fuchsia/engine/renderer/url_request_rules_receiver.cc @@ -11,13 +11,8 @@ #include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h" UrlRequestRulesReceiver::UrlRequestRulesReceiver( - content::RenderFrame* render_frame, - base::OnceCallback<void(int)> on_render_frame_deleted_callback) - : content::RenderFrameObserver(render_frame), - on_render_frame_deleted_callback_( - std::move(on_render_frame_deleted_callback)) { + content::RenderFrame* render_frame) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(on_render_frame_deleted_callback_); DCHECK(render_frame); // It is fine to use an unretained pointer to |this| here as the @@ -54,12 +49,3 @@ UrlRequestRulesReceiver::GetCachedRules() { base::AutoLock auto_lock(lock_); return cached_rules_; } - -void UrlRequestRulesReceiver::OnDestruct() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - // The RenderFrame corresponding to this object was destroyed, which means - // the AssociatedInterfaceRegsitry is also gone. It is expected that - // |on_render_frame_deleted_callback_| will delete |this|. - std::move(on_render_frame_deleted_callback_).Run(routing_id()); -} diff --git a/chromium/fuchsia/engine/renderer/url_request_rules_receiver.h b/chromium/fuchsia/engine/renderer/url_request_rules_receiver.h index 8b2db7b10c1..98125825f38 100644 --- a/chromium/fuchsia/engine/renderer/url_request_rules_receiver.h +++ b/chromium/fuchsia/engine/renderer/url_request_rules_receiver.h @@ -19,22 +19,18 @@ namespace content { class RenderFrame; } // namespace content -// Provides rewriting rules for network requests. UrlRequestRulesReceiver -// objects are owned by their respective WebEngineContentRendererClient and they -// will be destroyed on RenderFrame destruction. This is guaranteed to outlive -// any WebEngineURLLoaderThrottle that uses it as the RenderFrame destruction -// will have triggered the destruction of all pending -// WebEngineURLLoaderThrottles. +// Provides rewriting rules for network requests. Owned by +// WebEngineRenderFrameObserver, this object will be destroyed on RenderFrame +// destruction. This is guaranteed to outlive any WebEngineURLLoaderThrottle +// that uses it as the RenderFrame destruction will have triggered the +// destruction of all pending WebEngineURLLoaderThrottles. // This class should only be used on the IO thread, with the exception of the // GetCachedRules() implementation, which can be called from any sequence. class UrlRequestRulesReceiver : public mojom::UrlRequestRulesReceiver, - public WebEngineURLLoaderThrottle::CachedRulesProvider, - public content::RenderFrameObserver { + public WebEngineURLLoaderThrottle::CachedRulesProvider { public: - UrlRequestRulesReceiver( - content::RenderFrame* render_frame, - base::OnceCallback<void(int)> on_render_frame_deleted_callback); + UrlRequestRulesReceiver(content::RenderFrame* render_frame); ~UrlRequestRulesReceiver() override; private: @@ -48,9 +44,6 @@ class UrlRequestRulesReceiver scoped_refptr<WebEngineURLLoaderThrottle::UrlRequestRewriteRules> GetCachedRules() override; - // content::RenderFrameObserver implementation. - void OnDestruct() override; - base::Lock lock_; // This is accessed by WebEngineURLLoaderThrottles, which can be off-sequence @@ -61,7 +54,6 @@ class UrlRequestRulesReceiver mojo::AssociatedReceiver<mojom::UrlRequestRulesReceiver> url_request_rules_receiver_{this}; - base::OnceCallback<void(int)> on_render_frame_deleted_callback_; SEQUENCE_CHECKER(sequence_checker_); DISALLOW_COPY_AND_ASSIGN(UrlRequestRulesReceiver); diff --git a/chromium/fuchsia/engine/renderer/web_engine_content_renderer_client.cc b/chromium/fuchsia/engine/renderer/web_engine_content_renderer_client.cc index 2fc77c0d567..35d3f37a2fd 100644 --- a/chromium/fuchsia/engine/renderer/web_engine_content_renderer_client.cc +++ b/chromium/fuchsia/engine/renderer/web_engine_content_renderer_client.cc @@ -9,6 +9,8 @@ #include "components/cdm/renderer/widevine_key_system_properties.h" #include "components/media_control/renderer/media_playback_options.h" #include "content/public/renderer/render_frame.h" +#include "fuchsia/engine/common/cast_streaming.h" +#include "fuchsia/engine/renderer/cast_streaming_demuxer.h" #include "fuchsia/engine/renderer/on_load_script_injector.h" #include "fuchsia/engine/renderer/web_engine_url_loader_throttle_provider.h" #include "fuchsia/engine/switches.h" @@ -110,16 +112,16 @@ WebEngineContentRendererClient::WebEngineContentRendererClient() = default; WebEngineContentRendererClient::~WebEngineContentRendererClient() = default; -UrlRequestRulesReceiver* -WebEngineContentRendererClient::GetUrlRequestRulesReceiverForRenderFrameId( +WebEngineRenderFrameObserver* +WebEngineContentRendererClient::GetWebEngineRenderFrameObserverForRenderFrameId( int render_frame_id) const { - auto iter = url_request_receivers_by_id_.find(render_frame_id); - DCHECK(iter != url_request_receivers_by_id_.end()); + auto iter = render_frame_id_to_observer_map_.find(render_frame_id); + DCHECK(iter != render_frame_id_to_observer_map_.end()); return iter->second.get(); } void WebEngineContentRendererClient::OnRenderFrameDeleted(int render_frame_id) { - size_t count = url_request_receivers_by_id_.erase(render_frame_id); + size_t count = render_frame_id_to_observer_map_.erase(render_frame_id); DCHECK_EQ(count, 1u); } @@ -130,13 +132,14 @@ void WebEngineContentRendererClient::RenderFrameCreated( new OnLoadScriptInjector(render_frame); int render_frame_id = render_frame->GetRoutingID(); - auto rules_receiver = std::make_unique<UrlRequestRulesReceiver>( - content::RenderFrame::FromRoutingID(render_frame_id), + + auto render_frame_observer = std::make_unique<WebEngineRenderFrameObserver>( + render_frame, base::BindOnce(&WebEngineContentRendererClient::OnRenderFrameDeleted, base::Unretained(this))); - auto iter = url_request_receivers_by_id_.emplace(render_frame_id, - std::move(rules_receiver)); - DCHECK(iter.second); + auto render_frame_observer_iter = render_frame_id_to_observer_map_.emplace( + render_frame_id, std::move(render_frame_observer)); + DCHECK(render_frame_observer_iter.second); // Lifetime is tied to |render_frame| via content::RenderFrameObserver. new media_control::MediaPlaybackOptions(render_frame); @@ -235,6 +238,30 @@ bool WebEngineContentRendererClient::DeferMediaLoad( return RunClosureWhenInForeground(render_frame, std::move(closure)); } +std::unique_ptr<media::Demuxer> +WebEngineContentRendererClient::OverrideDemuxerForUrl( + content::RenderFrame* render_frame, + const GURL& url, + scoped_refptr<base::SingleThreadTaskRunner> media_task_runner) { + if (IsCastStreamingEnabled() && IsCastStreamingMediaSourceUrl(url)) { + auto iter = + render_frame_id_to_observer_map_.find(render_frame->GetRoutingID()); + DCHECK(iter != render_frame_id_to_observer_map_.end()); + // Do not create a CastStreamingDemuxer if the Cast Streaming MessagePort + // was not set in the browser process. This will manifest as an unbound + // CastStreamingReceiver object in the renderer process. + // TODO(crbug.com/1082821): Simplify the instantiation conditions for the + // CastStreamingDemuxer once the CastStreamingReceiver Component has been + // implemented. + if (iter->second->cast_streaming_receiver()->IsBound()) { + return std::make_unique<CastStreamingDemuxer>( + iter->second->cast_streaming_receiver(), media_task_runner); + } + } + + return nullptr; +} + bool WebEngineContentRendererClient::RunClosureWhenInForeground( content::RenderFrame* render_frame, base::OnceClosure closure) { diff --git a/chromium/fuchsia/engine/renderer/web_engine_content_renderer_client.h b/chromium/fuchsia/engine/renderer/web_engine_content_renderer_client.h index 93b3a110a9e..8c16a116bef 100644 --- a/chromium/fuchsia/engine/renderer/web_engine_content_renderer_client.h +++ b/chromium/fuchsia/engine/renderer/web_engine_content_renderer_client.h @@ -7,20 +7,21 @@ #include "base/macros.h" #include "content/public/renderer/content_renderer_client.h" -#include "fuchsia/engine/renderer/url_request_rules_receiver.h" +#include "fuchsia/engine/renderer/web_engine_render_frame_observer.h" class WebEngineContentRendererClient : public content::ContentRendererClient { public: WebEngineContentRendererClient(); ~WebEngineContentRendererClient() override; - // Returns the UrlRequestRulesReceiver corresponding to |render_frame_id|. - UrlRequestRulesReceiver* GetUrlRequestRulesReceiverForRenderFrameId( + // Returns the WebEngineRenderFrameObserver corresponding to + // |render_frame_id|. + WebEngineRenderFrameObserver* GetWebEngineRenderFrameObserverForRenderFrameId( int render_frame_id) const; private: - // Called by UrlRequestRulesReceivers when their corresponding RenderFrame is - // in the process of being deleted. + // Called by WebEngineRenderFrameObserver when its corresponding RenderFrame + // is in the process of being deleted. void OnRenderFrameDeleted(int render_frame_id); // content::ContentRendererClient overrides. @@ -35,13 +36,17 @@ class WebEngineContentRendererClient : public content::ContentRendererClient { bool DeferMediaLoad(content::RenderFrame* render_frame, bool has_played_media_before, base::OnceClosure closure) override; + std::unique_ptr<media::Demuxer> OverrideDemuxerForUrl( + content::RenderFrame* render_frame, + const GURL& url, + scoped_refptr<base::SingleThreadTaskRunner> media_task_runner) override; bool RunClosureWhenInForeground(content::RenderFrame* render_frame, base::OnceClosure closure); - // Map of rules receivers per RenderFrame ID. - std::map<int, std::unique_ptr<UrlRequestRulesReceiver>> - url_request_receivers_by_id_; + // Map of RenderFrame ID to WebEngineRenderFrameObserver. + std::map<int, std::unique_ptr<WebEngineRenderFrameObserver>> + render_frame_id_to_observer_map_; DISALLOW_COPY_AND_ASSIGN(WebEngineContentRendererClient); }; diff --git a/chromium/fuchsia/engine/renderer/web_engine_render_frame_observer.cc b/chromium/fuchsia/engine/renderer/web_engine_render_frame_observer.cc new file mode 100644 index 00000000000..8120227565b --- /dev/null +++ b/chromium/fuchsia/engine/renderer/web_engine_render_frame_observer.cc @@ -0,0 +1,25 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "fuchsia/engine/renderer/web_engine_render_frame_observer.h" + +#include "content/public/renderer/render_frame.h" + +WebEngineRenderFrameObserver::WebEngineRenderFrameObserver( + content::RenderFrame* render_frame, + base::OnceCallback<void(int)> on_render_frame_deleted_callback) + : content::RenderFrameObserver(render_frame), + url_request_rules_receiver_(render_frame), + cast_streaming_receiver_(render_frame), + on_render_frame_deleted_callback_( + std::move(on_render_frame_deleted_callback)) { + DCHECK(render_frame); + DCHECK(on_render_frame_deleted_callback_); +} + +WebEngineRenderFrameObserver::~WebEngineRenderFrameObserver() = default; + +void WebEngineRenderFrameObserver::OnDestruct() { + std::move(on_render_frame_deleted_callback_).Run(routing_id()); +} diff --git a/chromium/fuchsia/engine/renderer/web_engine_render_frame_observer.h b/chromium/fuchsia/engine/renderer/web_engine_render_frame_observer.h new file mode 100644 index 00000000000..5e3f5c5c8fe --- /dev/null +++ b/chromium/fuchsia/engine/renderer/web_engine_render_frame_observer.h @@ -0,0 +1,50 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FUCHSIA_ENGINE_RENDERER_WEB_ENGINE_RENDER_FRAME_OBSERVER_H_ +#define FUCHSIA_ENGINE_RENDERER_WEB_ENGINE_RENDER_FRAME_OBSERVER_H_ + +#include "base/callback.h" +#include "content/public/renderer/render_frame_observer.h" +#include "fuchsia/engine/renderer/cast_streaming_receiver.h" +#include "fuchsia/engine/renderer/url_request_rules_receiver.h" + +namespace content { +class RenderFrame; +} // namespace content + +// This class owns WebEngine-specific objects whose lifespan is tied to a +// RenderFrame. Owned by WebEngineContentRendererClient, this object will be +// destroyed on RenderFrame destruction, triggering the destruction of all of +// the objects it exposes. +class WebEngineRenderFrameObserver : public content::RenderFrameObserver { + public: + // |on_render_frame_deleted_callback| must delete |this|. + WebEngineRenderFrameObserver( + content::RenderFrame* render_frame, + base::OnceCallback<void(int)> on_render_frame_deleted_callback); + ~WebEngineRenderFrameObserver() final; + + WebEngineRenderFrameObserver(const WebEngineRenderFrameObserver&) = delete; + WebEngineRenderFrameObserver& operator=(const WebEngineRenderFrameObserver&) = + delete; + + UrlRequestRulesReceiver* url_request_rules_receiver() { + return &url_request_rules_receiver_; + } + CastStreamingReceiver* cast_streaming_receiver() { + return &cast_streaming_receiver_; + } + + private: + // content::RenderFrameObserver implementation. + void OnDestruct() final; + + UrlRequestRulesReceiver url_request_rules_receiver_; + CastStreamingReceiver cast_streaming_receiver_; + + base::OnceCallback<void(int)> on_render_frame_deleted_callback_; +}; + +#endif // FUCHSIA_ENGINE_RENDERER_WEB_ENGINE_RENDER_FRAME_OBSERVER_H_ diff --git a/chromium/fuchsia/engine/renderer/web_engine_url_loader_throttle_provider.cc b/chromium/fuchsia/engine/renderer/web_engine_url_loader_throttle_provider.cc index 5b24b461406..95e8e64d510 100644 --- a/chromium/fuchsia/engine/renderer/web_engine_url_loader_throttle_provider.cc +++ b/chromium/fuchsia/engine/renderer/web_engine_url_loader_throttle_provider.cc @@ -33,8 +33,9 @@ WebEngineURLLoaderThrottleProvider::CreateThrottles( std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles; throttles.emplace_back(std::make_unique<WebEngineURLLoaderThrottle>( - content_renderer_client_->GetUrlRequestRulesReceiverForRenderFrameId( - render_frame_id))); + content_renderer_client_ + ->GetWebEngineRenderFrameObserverForRenderFrameId(render_frame_id) + ->url_request_rules_receiver())); return throttles; } |