Commit 130188c1 authored by Thomas Guilbert's avatar Thomas Guilbert Committed by Commit Bot

Add FlingingRenderer

The FlingingRenderer adapts from the media::Renderer interface to the
MediaController interface. It is used in the context of RemotePlayback,
and is created from an already existing presentation ID

Bug: 790766
Change-Id: I2284468f3342ad4123e5318c3f2c930a171fea06
Reviewed-on: https://chromium-review.googlesource.com/1003229Reviewed-by: default avatarNick Carter <nick@chromium.org>
Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Commit-Queue: Thomas Guilbert <tguilbert@chromium.org>
Cr-Commit-Position: refs/heads/master@{#551799}
parent 64fd4659
...@@ -1060,6 +1060,8 @@ jumbo_source_set("browser") { ...@@ -1060,6 +1060,8 @@ jumbo_source_set("browser") {
"media/capture/web_contents_tracker.h", "media/capture/web_contents_tracker.h",
"media/cdm_registry_impl.cc", "media/cdm_registry_impl.cc",
"media/cdm_registry_impl.h", "media/cdm_registry_impl.h",
"media/flinging_renderer.cc",
"media/flinging_renderer.h",
"media/media_devices_permission_checker.cc", "media/media_devices_permission_checker.cc",
"media/media_devices_permission_checker.h", "media/media_devices_permission_checker.h",
"media/media_devices_util.cc", "media/media_devices_util.cc",
......
// Copyright 2018 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/browser/media/flinging_renderer.h"
#include "base/memory/ptr_util.h"
#include "content/browser/frame_host/render_frame_host_delegate.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/presentation_service_delegate.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/common/content_client.h"
namespace content {
FlingingRenderer::FlingingRenderer(std::unique_ptr<MediaController> controller)
: controller_(std::move(controller)) {}
FlingingRenderer::~FlingingRenderer() = default;
// static
std::unique_ptr<FlingingRenderer> FlingingRenderer::Create(
RenderFrameHost* render_frame_host,
const std::string& presentation_id) {
DVLOG(1) << __func__;
ContentClient* content_client = GetContentClient();
if (!content_client)
return nullptr;
ContentBrowserClient* browser_client = content_client->browser();
if (!browser_client)
return nullptr;
ControllerPresentationServiceDelegate* presentation_delegate =
browser_client->GetControllerPresentationServiceDelegate(
static_cast<RenderFrameHostImpl*>(render_frame_host)
->delegate()
->GetAsWebContents());
if (!presentation_delegate)
return nullptr;
auto media_controller = presentation_delegate->GetMediaController(
render_frame_host->GetProcess()->GetID(),
render_frame_host->GetRoutingID(), presentation_id);
if (!media_controller)
return nullptr;
return base::WrapUnique<FlingingRenderer>(
new FlingingRenderer(std::move(media_controller)));
}
// media::Renderer implementation
void FlingingRenderer::Initialize(media::MediaResource* media_resource,
media::RendererClient* client,
const media::PipelineStatusCB& init_cb) {
DVLOG(2) << __func__;
init_cb.Run(media::PIPELINE_OK);
}
void FlingingRenderer::SetCdm(media::CdmContext* cdm_context,
const media::CdmAttachedCB& cdm_attached_cb) {
// The flinging renderer does not support playing encrypted content.
NOTREACHED();
}
void FlingingRenderer::Flush(const base::Closure& flush_cb) {
DVLOG(2) << __func__;
// There is nothing to reset, we can no-op the call.
flush_cb.Run();
}
void FlingingRenderer::StartPlayingFrom(base::TimeDelta time) {
DVLOG(2) << __func__;
controller_->Seek(time);
controller_->Play();
}
void FlingingRenderer::SetPlaybackRate(double playback_rate) {
DVLOG(2) << __func__;
if (playback_rate == 0)
controller_->Pause();
else
controller_->Play();
}
void FlingingRenderer::SetVolume(float volume) {
DVLOG(2) << __func__;
controller_->SetVolume(volume);
}
base::TimeDelta FlingingRenderer::GetMediaTime() {
// TODO(https://crbug.com/830871): return correct media time.
return base::TimeDelta();
}
} // namespace content
// Copyright 2018 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 CONTENT_BROWSER_MEDIA_FLINGING_RENDERER_H_
#define CONTENT_BROWSER_MEDIA_FLINGING_RENDERER_H_
#include "base/callback.h"
#include "content/common/content_export.h"
#include "content/public/browser/media_controller.h"
#include "media/base/media_resource.h"
#include "media/base/renderer.h"
#include "media/base/renderer_client.h"
#include "url/gurl.h"
namespace content {
class FlingingRendererTest;
class RenderFrameHost;
// FlingingRenderer adapts from the media::Renderer interface to the
// MediaController interface. The MediaController is used to issue simple media
// playback commands. In this case, the media we are controlling should be an
// already existing RemotingCastSession, which should have been initiated by a
// blink::RemotePlayback object, using the PresentationService.
class CONTENT_EXPORT FlingingRenderer : public media::Renderer {
public:
// Helper method to create a FlingingRenderer from an already existing
// presentation ID.
// Returns nullptr if there was an error getting the MediaControllor for the
// given presentation ID.
static std::unique_ptr<FlingingRenderer> Create(
RenderFrameHost* render_frame_host,
const std::string& presentation_id);
~FlingingRenderer() override;
// media::Renderer implementation
void Initialize(media::MediaResource* media_resource,
media::RendererClient* client,
const media::PipelineStatusCB& init_cb) override;
void SetCdm(media::CdmContext* cdm_context,
const media::CdmAttachedCB& cdm_attached_cb) override;
void Flush(const base::Closure& flush_cb) override;
void StartPlayingFrom(base::TimeDelta time) override;
void SetPlaybackRate(double playback_rate) override;
void SetVolume(float volume) override;
base::TimeDelta GetMediaTime() override;
private:
friend class FlingingRendererTest;
explicit FlingingRenderer(std::unique_ptr<MediaController> controller);
std::unique_ptr<MediaController> controller_;
DISALLOW_COPY_AND_ASSIGN(FlingingRenderer);
};
} // namespace content
#endif // CONTENT_BROWSER_MEDIA_FLINGING_RENDERER_H_
// Copyright 2018 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/browser/media/flinging_renderer.h"
#include "base/version.h"
#include "content/public/browser/media_controller.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::StrictMock;
namespace content {
class MockMediaController : public MediaController {
public:
MOCK_METHOD0(Play, void());
MOCK_METHOD0(Pause, void());
MOCK_METHOD1(SetMute, void(bool));
MOCK_METHOD1(SetVolume, void(float));
MOCK_METHOD1(Seek, void(base::TimeDelta));
};
class FlingingRendererTest : public testing::Test {
public:
FlingingRendererTest()
: media_controller_(new StrictMock<MockMediaController>()),
renderer_(std::unique_ptr<MediaController>(media_controller_)) {}
protected:
StrictMock<MockMediaController>* media_controller_;
FlingingRenderer renderer_;
};
TEST_F(FlingingRendererTest, StartPlayingFromTime) {
base::TimeDelta seek_time = base::TimeDelta::FromSeconds(10);
EXPECT_CALL(*media_controller_, Play());
EXPECT_CALL(*media_controller_, Seek(seek_time));
renderer_.StartPlayingFrom(seek_time);
}
TEST_F(FlingingRendererTest, StartPlayingFromBeginning) {
EXPECT_CALL(*media_controller_, Play());
EXPECT_CALL(*media_controller_, Seek(base::TimeDelta()));
renderer_.StartPlayingFrom(base::TimeDelta());
}
TEST_F(FlingingRendererTest, SetPlaybackRate) {
double playback_rate = 1.0;
EXPECT_CALL(*media_controller_, Play());
renderer_.SetPlaybackRate(playback_rate);
}
TEST_F(FlingingRendererTest, SetPlaybackRateToZero) {
double playback_rate = 0.0;
EXPECT_CALL(*media_controller_, Pause());
renderer_.SetPlaybackRate(playback_rate);
}
// Setting the volume to a positive value should not change the mute state.
TEST_F(FlingingRendererTest, SetVolume) {
float volume = 0.5;
EXPECT_CALL(*media_controller_, SetVolume(volume));
EXPECT_CALL(*media_controller_, SetMute(_)).Times(0);
renderer_.SetVolume(volume);
}
// Setting the volume to 0 should not set the mute state.
TEST_F(FlingingRendererTest, SetVolumeToZero) {
float volume = 0;
EXPECT_CALL(*media_controller_, SetVolume(volume));
EXPECT_CALL(*media_controller_, SetMute(_)).Times(0);
renderer_.SetVolume(volume);
}
} // namespace content
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
#include "content/browser/media/android/media_player_renderer.h" #include "content/browser/media/android/media_player_renderer.h"
#include "content/browser/media/flinging_renderer.h"
#include "media/mojo/services/mojo_renderer_service.h" // nogncheck #include "media/mojo/services/mojo_renderer_service.h" // nogncheck
#endif #endif
...@@ -161,6 +162,17 @@ void MediaInterfaceProxy::CreateRenderer( ...@@ -161,6 +162,17 @@ void MediaInterfaceProxy::CreateRenderer(
CreateMediaPlayerRenderer(std::move(request)); CreateMediaPlayerRenderer(std::move(request));
return; return;
} }
if (type == media::mojom::HostedRendererType::kFlinging) {
std::unique_ptr<FlingingRenderer> renderer =
FlingingRenderer::Create(render_frame_host_, type_specific_id);
media::MojoRendererService::Create(
std::move(renderer),
media::MojoRendererService::InitiateSurfaceRequestCB(),
std::move(request));
return;
}
#endif #endif
InterfaceFactory* factory = GetMediaInterfaceFactory(); InterfaceFactory* factory = GetMediaInterfaceFactory();
......
...@@ -1365,6 +1365,7 @@ test("content_unittests") { ...@@ -1365,6 +1365,7 @@ test("content_unittests") {
"../browser/media/capture/audio_mirroring_manager_unittest.cc", "../browser/media/capture/audio_mirroring_manager_unittest.cc",
"../browser/media/capture/web_contents_audio_input_stream_unittest.cc", "../browser/media/capture/web_contents_audio_input_stream_unittest.cc",
"../browser/media/cdm_registry_impl_unittest.cc", "../browser/media/cdm_registry_impl_unittest.cc",
"../browser/media/flinging_renderer_unittest.cc",
"../browser/media/media_devices_permission_checker_unittest.cc", "../browser/media/media_devices_permission_checker_unittest.cc",
"../browser/media/media_internals_unittest.cc", "../browser/media/media_internals_unittest.cc",
"../browser/media/midi_host_unittest.cc", "../browser/media/midi_host_unittest.cc",
......
...@@ -21,6 +21,14 @@ enum HostedRendererType { ...@@ -21,6 +21,14 @@ enum HostedRendererType {
// are better off using the native Android MediaPlayer. // are better off using the native Android MediaPlayer.
[EnableIf=is_android] [EnableIf=is_android]
kMediaPlayer, kMediaPlayer,
// content::FlingingRenderer: Used to control a CastSession, in the context
// of RemotePlayback. The CastSession must have already been started via the
// PresentationService. This renderer does not actually render anything on the
// local device, but instead serves as a link to/from media content playing on
// a cast device.
[EnableIf=is_android]
kFlinging,
}; };
// A factory for creating media mojo interfaces. Renderers can only access // A factory for creating media mojo interfaces. Renderers can only access
...@@ -39,6 +47,9 @@ interface InterfaceFactory { ...@@ -39,6 +47,9 @@ interface InterfaceFactory {
// media/audio/audio_device_description.h. // media/audio/audio_device_description.h.
// If |type_specific_id| is empty, kDefaultDeviceId will be used. // If |type_specific_id| is empty, kDefaultDeviceId will be used.
// - kMediaPlayer: unused. // - kMediaPlayer: unused.
// - kFlinging: represents a PresentationID for a session that has already
// been started. If the ID cannot be found (e.g. the session has already
// ended), CreateRenderer will be a no-op.
CreateRenderer(HostedRendererType type, string type_specific_id, CreateRenderer(HostedRendererType type, string type_specific_id,
Renderer& renderer); Renderer& renderer);
......
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