Commit a279f98a authored by Fabrice de Gans-Riberi's avatar Fabrice de Gans-Riberi Committed by Commit Bot

[fuchsia] Add a Cast Streaming Demuxer.

* Move the existing Cast Streaming browser test into a separate file.
* Add more Cast Streaming browser tests.

Bug: 1042501
Change-Id: I34752670b58a8b54b3eccdf6fb17f9d7f2c5c11c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2194790Reviewed-by: default avatarDavid Dorwin <ddorwin@chromium.org>
Reviewed-by: default avatarThomas Guilbert <tguilbert@chromium.org>
Commit-Queue: Fabrice de Gans-Riberi <fdegans@chromium.org>
Cr-Commit-Position: refs/heads/master@{#772353}
parent 748e391e
......@@ -54,4 +54,19 @@ fuchsia::web::LoadUrlParams CreateLoadUrlParamsWithUserActivation() {
return load_url_params;
}
fuchsia::web::WebMessage CreateWebMessageWithMessagePortRequest(
fidl::InterfaceRequest<fuchsia::web::MessagePort> message_port_request,
fuchsia::mem::Buffer buffer) {
fuchsia::web::OutgoingTransferable outgoing;
outgoing.set_message_port(std::move(message_port_request));
std::vector<fuchsia::web::OutgoingTransferable> outgoing_vector;
outgoing_vector.push_back(std::move(outgoing));
fuchsia::web::WebMessage web_message;
web_message.set_outgoing_transfer(std::move(outgoing_vector));
web_message.set_data(std::move(buffer));
return web_message;
}
} // namespace cr_fuchsia
......@@ -31,6 +31,12 @@ base::Optional<base::Value> ExecuteJavaScript(fuchsia::web::Frame* frame,
// autoplay to be used, which is used by many media tests.
fuchsia::web::LoadUrlParams CreateLoadUrlParamsWithUserActivation();
// Creates a WebMessage with one outgoing transferable set to
// |message_port_request| and data set to |buffer|.
fuchsia::web::WebMessage CreateWebMessageWithMessagePortRequest(
fidl::InterfaceRequest<fuchsia::web::MessagePort> message_port_request,
fuchsia::mem::Buffer buffer);
} // namespace cr_fuchsia
#endif // FUCHSIA_BASE_FRAME_TEST_UTIL_H_
......@@ -106,6 +106,7 @@ component("web_engine_core") {
"//media",
"//media/fuchsia/cdm/service",
"//media/fuchsia/mojom",
"//media/mojo/common",
"//media/mojo/services",
"//mojo/public/cpp/bindings",
"//services/media_session/public/mojom",
......@@ -199,6 +200,8 @@ component("web_engine_core") {
"context_provider_impl.h",
"context_provider_main.cc",
"context_provider_main.h",
"renderer/cast_streaming_demuxer.cc",
"renderer/cast_streaming_demuxer.h",
"renderer/on_load_script_injector.cc",
"renderer/on_load_script_injector.h",
"renderer/url_request_rules_receiver.cc",
......@@ -278,6 +281,7 @@ source_set("browsertest_core") {
test("web_engine_browsertests") {
sources = [
"browser/accessibility_bridge_browsertest.cc",
"browser/cast_streaming_browsertest.cc",
"browser/content_directory_browsertest.cc",
"browser/context_impl_browsertest.cc",
"browser/frame_impl_browsertest.cc",
......
// 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 "content/public/test/browser_test.h"
#include "fuchsia/base/fit_adapter.h"
#include "fuchsia/base/frame_test_util.h"
#include "fuchsia/base/mem_buffer_util.h"
#include "fuchsia/base/result_receiver.h"
#include "fuchsia/base/test_navigation_listener.h"
#include "fuchsia/engine/browser/frame_impl.h"
#include "fuchsia/engine/switches.h"
#include "fuchsia/engine/test/test_data.h"
#include "fuchsia/engine/test/web_engine_browser_test.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
const char kCastStreamingReceiverPath[] = "/cast_streaming_receiver.html";
} // namespace
// Base test fixture for Cast Streaming tests.
class CastStreamingBaseTest : public cr_fuchsia::WebEngineBrowserTest {
public:
CastStreamingBaseTest() {
set_test_server_root(base::FilePath(cr_fuchsia::kTestServerRoot));
}
~CastStreamingBaseTest() override = default;
CastStreamingBaseTest(const CastStreamingBaseTest&) = delete;
CastStreamingBaseTest& operator=(const CastStreamingBaseTest&) = delete;
protected:
// Creates a Frame with |navigation_listener_| attached.
fuchsia::web::FramePtr CreateFrame() {
return WebEngineBrowserTest::CreateFrame(&navigation_listener_);
}
cr_fuchsia::TestNavigationListener navigation_listener_;
};
// Test fixture for Cast Streaming tests with the Cast Streaming Receiver flag
// disabled.
class CastStreamingDisabledTest : public CastStreamingBaseTest {
public:
CastStreamingDisabledTest() = default;
~CastStreamingDisabledTest() override = default;
CastStreamingDisabledTest(const CastStreamingDisabledTest&) = delete;
CastStreamingDisabledTest& operator=(const CastStreamingDisabledTest&) =
delete;
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
content::BrowserTestBase::SetUpCommandLine(command_line);
command_line->RemoveSwitch(switches::kEnableCastStreamingReceiver);
}
};
// Test fixture for Cast Streaming tests with the Cast Streaming Receiver flag
// enabled.
class CastStreamingTest : public CastStreamingBaseTest {
public:
CastStreamingTest() = default;
~CastStreamingTest() override = default;
CastStreamingTest(const CastStreamingTest&) = delete;
CastStreamingTest& operator=(const CastStreamingTest&) = delete;
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
content::BrowserTestBase::SetUpCommandLine(command_line);
command_line->AppendSwitch(switches::kEnableCastStreamingReceiver);
}
};
// Check that attempting to load the cast streaming media source URL when the
// command line switch is not set fails as expected.
IN_PROC_BROWSER_TEST_F(CastStreamingDisabledTest, LoadFailure) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL page_url(embedded_test_server()->GetURL(kCastStreamingReceiverPath));
fuchsia::web::FramePtr frame = CreateFrame();
fuchsia::web::NavigationControllerPtr controller;
frame->GetNavigationController(controller.NewRequest());
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
controller.get(), fuchsia::web::LoadUrlParams(), page_url.spec()));
navigation_listener_.RunUntilTitleEquals("error");
}
// Check that the Cast Streaming MessagePort gets properly set on the Frame.
IN_PROC_BROWSER_TEST_F(CastStreamingTest, FrameMessagePort) {
fuchsia::web::FramePtr frame = CreateFrame();
FrameImpl* frame_impl = context_impl()->GetFrameImplForTest(&frame);
ASSERT_TRUE(frame_impl);
EXPECT_FALSE(frame_impl->cast_streaming_session_client_for_test());
fuchsia::web::MessagePortPtr cast_streaming_message_port;
base::RunLoop run_loop;
cr_fuchsia::ResultReceiver<fuchsia::web::Frame_PostMessage_Result>
post_result(run_loop.QuitClosure());
frame->PostMessage(
"cast-streaming:receiver",
cr_fuchsia::CreateWebMessageWithMessagePortRequest(
cast_streaming_message_port.NewRequest(),
cr_fuchsia::MemBufferFromString("hi", "test")),
cr_fuchsia::CallbackToFitFunction(post_result.GetReceiveCallback()));
run_loop.Run();
ASSERT_TRUE(post_result->is_response());
EXPECT_TRUE(frame_impl->cast_streaming_session_client_for_test());
}
// Check that attempting to load the cast streaming media source URL when the
// command line switch is set properly succeeds.
IN_PROC_BROWSER_TEST_F(CastStreamingTest, LoadSuccess) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL page_url(embedded_test_server()->GetURL(kCastStreamingReceiverPath));
fuchsia::web::FramePtr frame = CreateFrame();
fuchsia::web::NavigationControllerPtr controller;
frame->GetNavigationController(controller.NewRequest());
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
controller.get(), fuchsia::web::LoadUrlParams(), page_url.spec()));
navigation_listener_.RunUntilTitleEquals("canplay");
}
......@@ -24,7 +24,6 @@
#include "fuchsia/base/test_navigation_listener.h"
#include "fuchsia/base/url_request_rewrite_test_util.h"
#include "fuchsia/engine/browser/frame_impl.h"
#include "fuchsia/engine/switches.h"
#include "fuchsia/engine/test/test_data.h"
#include "fuchsia/engine/test/web_engine_browser_test.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
......@@ -70,21 +69,6 @@ const char kDataUrl[] =
"data:text/html;base64,PGI+SGVsbG8sIHdvcmxkLi4uPC9iPg==";
const int64_t kOnLoadScriptId = 0;
fuchsia::web::WebMessage CreateWebMessageWithMessagePortRequest(
fidl::InterfaceRequest<fuchsia::web::MessagePort> message_port_request,
fuchsia::mem::Buffer buffer) {
fuchsia::web::OutgoingTransferable outgoing;
outgoing.set_message_port(std::move(message_port_request));
std::vector<fuchsia::web::OutgoingTransferable> outgoing_vector;
outgoing_vector.push_back(std::move(outgoing));
fuchsia::web::WebMessage web_message;
web_message.set_outgoing_transfer(std::move(outgoing_vector));
web_message.set_data(std::move(buffer));
return web_message;
}
MATCHER_P(NavigationHandleUrlEquals,
url,
"Checks equality with a NavigationHandle's URL.") {
......@@ -1212,7 +1196,7 @@ IN_PROC_BROWSER_TEST_F(FrameImplTest, PostMessagePassMessagePort) {
post_result;
frame->PostMessage(
post_message_url.GetOrigin().spec(),
CreateWebMessageWithMessagePortRequest(
cr_fuchsia::CreateWebMessageWithMessagePortRequest(
message_port.NewRequest(),
cr_fuchsia::MemBufferFromString("hi", "test")),
cr_fuchsia::CallbackToFitFunction(post_result.GetReceiveCallback()));
......@@ -1272,7 +1256,7 @@ IN_PROC_BROWSER_TEST_F(FrameImplTest, PostMessageMessagePortDisconnected) {
post_result;
frame->PostMessage(
post_message_url.GetOrigin().spec(),
CreateWebMessageWithMessagePortRequest(
cr_fuchsia::CreateWebMessageWithMessagePortRequest(
message_port.NewRequest(),
cr_fuchsia::MemBufferFromString("hi", "test")),
cr_fuchsia::CallbackToFitFunction(post_result.GetReceiveCallback()));
......@@ -1327,7 +1311,7 @@ IN_PROC_BROWSER_TEST_F(FrameImplTest, PostMessageUseContentProvidedPort) {
post_result;
frame->PostMessage(
"*",
CreateWebMessageWithMessagePortRequest(
cr_fuchsia::CreateWebMessageWithMessagePortRequest(
message_port.NewRequest(),
cr_fuchsia::MemBufferFromString("hi", "test")),
cr_fuchsia::CallbackToFitFunction(post_result.GetReceiveCallback()));
......@@ -1373,7 +1357,7 @@ IN_PROC_BROWSER_TEST_F(FrameImplTest, PostMessageUseContentProvidedPort) {
post_result;
frame->PostMessage(
"*",
CreateWebMessageWithMessagePortRequest(
cr_fuchsia::CreateWebMessageWithMessagePortRequest(
ack_message_port.NewRequest(),
cr_fuchsia::MemBufferFromString("hi", "test")),
cr_fuchsia::CallbackToFitFunction(post_result.GetReceiveCallback()));
......@@ -1428,7 +1412,7 @@ IN_PROC_BROWSER_TEST_F(FrameImplTest, PostMessageBadOriginDropped) {
unused_post_result;
frame->PostMessage(
"https://example.com",
CreateWebMessageWithMessagePortRequest(
cr_fuchsia::CreateWebMessageWithMessagePortRequest(
unused_message_port.NewRequest(),
cr_fuchsia::MemBufferFromString("bad origin, bad!", "test")),
cr_fuchsia::CallbackToFitFunction(
......@@ -1449,7 +1433,7 @@ IN_PROC_BROWSER_TEST_F(FrameImplTest, PostMessageBadOriginDropped) {
post_result;
frame->PostMessage(
"*",
CreateWebMessageWithMessagePortRequest(
cr_fuchsia::CreateWebMessageWithMessagePortRequest(
message_port.NewRequest(),
cr_fuchsia::MemBufferFromString("good origin", "test")),
cr_fuchsia::CallbackToFitFunction(post_result.GetReceiveCallback()));
......@@ -1675,44 +1659,6 @@ IN_PROC_BROWSER_TEST_F(FrameImplTest, InvalidHeader) {
}
}
// Test fixture for Cast Streaming tests.
class CastStreamingFrameImplTest : public FrameImplTest {
public:
CastStreamingFrameImplTest() = default;
~CastStreamingFrameImplTest() override = default;
private:
void SetUpCommandLine(base::CommandLine* command_line) override {
content::BrowserTestBase::SetUpCommandLine(command_line);
command_line->AppendSwitch(switches::kEnableCastStreamingReceiver);
}
};
// Check that the Cast Streaming MessagePort is properly set.
IN_PROC_BROWSER_TEST_F(CastStreamingFrameImplTest, CastStreamingMessagePort) {
fuchsia::web::FramePtr frame = CreateFrame();
FrameImpl* frame_impl = context_impl()->GetFrameImplForTest(&frame);
ASSERT_TRUE(frame_impl);
EXPECT_FALSE(frame_impl->cast_streaming_session_client_for_test());
fuchsia::web::MessagePortPtr cast_streaming_message_port;
base::RunLoop run_loop;
cr_fuchsia::ResultReceiver<fuchsia::web::Frame_PostMessage_Result>
post_result(run_loop.QuitClosure());
frame->PostMessage(
"cast-streaming:receiver",
CreateWebMessageWithMessagePortRequest(
cast_streaming_message_port.NewRequest(),
cr_fuchsia::MemBufferFromString("hi", "test")),
cr_fuchsia::CallbackToFitFunction(post_result.GetReceiveCallback()));
run_loop.Run();
ASSERT_TRUE(post_result->is_response());
EXPECT_TRUE(frame_impl->cast_streaming_session_client_for_test());
}
class RequestMonitoringFrameImplBrowserTest : public FrameImplTest {
public:
RequestMonitoringFrameImplBrowserTest() = default;
......
......@@ -152,10 +152,12 @@ void WebEngineContentBrowserClient::
void WebEngineContentBrowserClient::AppendExtraCommandLineSwitches(
base::CommandLine* command_line,
int child_process_id) {
// TODO(https://crbug.com/1083520): Pass based on process type.
constexpr char const* kSwitchesToCopy[] = {
switches::kContentDirectories,
switches::kCorsExemptHeaders,
switches::kDisableSoftwareVideoDecoders,
switches::kEnableCastStreamingReceiver,
switches::kEnableProtectedVideoBuffers,
switches::kEnableWidevine,
switches::kForceProtectedVideoOutputBuffers,
......
......@@ -6,6 +6,11 @@
#include "base/command_line.h"
#include "fuchsia/engine/switches.h"
#include "url/gurl.h"
namespace {
constexpr char kCastStreamingReceiverUrl[] = "data:cast_streaming_receiver";
} // namespace
bool IsCastStreamingEnabled() {
static bool is_cast_streaming_enabled =
......@@ -13,3 +18,7 @@ bool IsCastStreamingEnabled() {
switches::kEnableCastStreamingReceiver);
return is_cast_streaming_enabled;
}
bool IsCastStreamingMediaSourceUrl(const GURL& url) {
return url == kCastStreamingReceiverUrl;
}
......@@ -5,7 +5,12 @@
#ifndef FUCHSIA_ENGINE_COMMON_CAST_STREAMING_H_
#define FUCHSIA_ENGINE_COMMON_CAST_STREAMING_H_
class GURL;
// Returns true if Cast Streaming is enabled for this process.
bool IsCastStreamingEnabled();
// Returns true if |url| is the Cast Streaming media source URL.
bool IsCastStreamingMediaSourceUrl(const GURL& url);
#endif // FUCHSIA_ENGINE_COMMON_CAST_STREAMING_H_
// 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 "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 buffers on the main thread and sends them to the media thread.
class CastStreamingDemuxerStream : public media::DemuxerStream {
public:
explicit CastStreamingDemuxerStream(
mojo::ScopedDataPipeConsumerHandle consumer)
: decoder_buffer_reader_(std::move(consumer)) {}
~CastStreamingDemuxerStream() override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
// TODO(crbug.com/1042501): Receive |buffer| through a Mojo interface.
void ReceiveBuffer(media::mojom::DecoderBufferPtr buffer) {
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;
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_);
DCHECK(!current_buffer_);
current_buffer_ = buffer;
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; }
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:
CastStreamingAudioDemuxerStream(media::AudioDecoderConfig decoder_config,
mojo::ScopedDataPipeConsumerHandle consumer)
: CastStreamingDemuxerStream(std::move(consumer)),
config_(decoder_config) {}
~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:
CastStreamingVideoDemuxerStream(media::VideoDecoderConfig decoder_config,
mojo::ScopedDataPipeConsumerHandle consumer)
: CastStreamingDemuxerStream(std::move(consumer)),
config_(decoder_config) {}
~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(
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner)
: media_task_runner_(media_task_runner) {
DVLOG(1) << __func__;
}
CastStreamingDemuxer::~CastStreamingDemuxer() = default;
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);
// TODO(crbug.com/1042501): Properly initialize the demuxer once the mojo
// service has been implemented.
std::move(status_cb).Run(media::PipelineStatus::PIPELINE_OK);
}
void CastStreamingDemuxer::AbortPendingReads() {
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__;
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);
}
// 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 "media/base/demuxer.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
namespace base {
class SingleThreadTaskRunner;
}
class CastStreamingAudioDemuxerStream;
class CastStreamingVideoDemuxerStream;
// media::Demuxer implementation for a Cast Streaming Receiver.
class CastStreamingDemuxer : public media::Demuxer {
public:
explicit CastStreamingDemuxer(
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner);
~CastStreamingDemuxer() final;
CastStreamingDemuxer(const CastStreamingDemuxer&) = delete;
CastStreamingDemuxer& operator=(const CastStreamingDemuxer&) = delete;
private:
// 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_;
media::DemuxerHost* host_ = nullptr;
std::unique_ptr<CastStreamingAudioDemuxerStream> audio_stream_;
std::unique_ptr<CastStreamingVideoDemuxerStream> video_stream_;
};
#endif // FUCHSIA_ENGINE_RENDERER_LIBCAST_STREAMING_DEMUXER_H_
......@@ -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"
......@@ -236,6 +238,20 @@ 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)) {
// TODO(crbug.com/1042501): Add a mojo service to properly initialize the
// demuxer and send frames to it.
return std::make_unique<CastStreamingDemuxer>(media_task_runner);
}
return nullptr;
}
bool WebEngineContentRendererClient::RunClosureWhenInForeground(
content::RenderFrame* render_frame,
base::OnceClosure closure) {
......
......@@ -36,6 +36,10 @@ 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);
......
<!DOCTYPE html>
<!--
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.
-->
<html>
<body>
<video src="data:cast_streaming_receiver">
<script>
var video = document.querySelector('video');
video.onerror = function() {
document.title = "error";
}
video.oncanplay = function() {
document.title = "canplay";
}
</script>
</body>
</html>
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