diff options
author | davve <davve@opera.com> | 2015-12-11 04:05:22 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-12-11 12:06:48 +0000 |
commit | 2536c36bebcb87fa8b2f18bd4da9b9951eb63607 (patch) | |
tree | 904dcc4dde5adfad4b6ea7c843659faabbd61415 /content | |
parent | 9f815753bd4c99e2209965cf8ac724aa0803db45 (diff) | |
download | chromium_src-2536c36bebcb87fa8b2f18bd4da9b9951eb63607.zip chromium_src-2536c36bebcb87fa8b2f18bd4da9b9951eb63607.tar.gz chromium_src-2536c36bebcb87fa8b2f18bd4da9b9951eb63607.tar.bz2 |
Hook up RendererMediaSessionManager with browser side
Implements the basic IPC messages for activation and deactivation back
and forth.
The browser side is still unimplemented.
BUG=497735
Review URL: https://codereview.chromium.org/1441883003
Cr-Commit-Position: refs/heads/master@{#364673}
Diffstat (limited to 'content')
12 files changed, 378 insertions, 10 deletions
diff --git a/content/browser/media/android/browser_media_session_manager.cc b/content/browser/media/android/browser_media_session_manager.cc new file mode 100644 index 0000000..146a60fe --- /dev/null +++ b/content/browser/media/android/browser_media_session_manager.cc @@ -0,0 +1,34 @@ +// Copyright 2015 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/android/browser_media_session_manager.h" + +#include "content/common/media/media_session_messages_android.h" +#include "content/public/browser/render_frame_host.h" + +namespace content { + +BrowserMediaSessionManager::BrowserMediaSessionManager( + RenderFrameHost* render_frame_host) + : render_frame_host_(render_frame_host) {} + +void BrowserMediaSessionManager::OnActivate(int session_id, int request_id) { + NOTIMPLEMENTED(); + Send(new MediaSessionMsg_DidActivate(GetRoutingID(), request_id, false)); +} + +void BrowserMediaSessionManager::OnDeactivate(int session_id, int request_id) { + NOTIMPLEMENTED(); + Send(new MediaSessionMsg_DidDeactivate(GetRoutingID(), request_id)); +} + +int BrowserMediaSessionManager::GetRoutingID() const { + return render_frame_host_->GetRoutingID(); +} + +bool BrowserMediaSessionManager::Send(IPC::Message* msg) { + return render_frame_host_->Send(msg); +} + +} // namespace content diff --git a/content/browser/media/android/browser_media_session_manager.h b/content/browser/media/android/browser_media_session_manager.h new file mode 100644 index 0000000..c03bf1b --- /dev/null +++ b/content/browser/media/android/browser_media_session_manager.h @@ -0,0 +1,38 @@ +// Copyright 2015 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_ANDROID_BROWSER_MEDIA_SESSION_MANAGER_H_ +#define CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_MEDIA_SESSION_MANAGER_H_ + +#include "base/basictypes.h" + +namespace IPC { +class Message; +} + +namespace content { + +class RenderFrameHost; + +class BrowserMediaSessionManager { + public: + BrowserMediaSessionManager(RenderFrameHost* render_frame_host); + + // Message handlers. + void OnActivate(int session_id, int request_id); + void OnDeactivate(int session_id, int request_id); + + int GetRoutingID() const; + + bool Send(IPC::Message* msg); + + private: + RenderFrameHost* const render_frame_host_; + + DISALLOW_COPY_AND_ASSIGN(BrowserMediaSessionManager); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_MEDIA_SESSION_MANAGER_H_ diff --git a/content/browser/media/media_web_contents_observer.cc b/content/browser/media/media_web_contents_observer.cc index dc79efa..42dcf93 100644 --- a/content/browser/media/media_web_contents_observer.cc +++ b/content/browser/media/media_web_contents_observer.cc @@ -16,7 +16,9 @@ #if defined(OS_ANDROID) #include "content/browser/media/android/browser_media_player_manager.h" +#include "content/browser/media/android/browser_media_session_manager.h" #include "content/common/media/media_player_messages_android.h" +#include "content/common/media/media_session_messages_android.h" #include "media/base/android/media_player_android.h" #endif // defined(OS_ANDROID) @@ -35,6 +37,7 @@ void MediaWebContentsObserver::RenderFrameDeleted( // Always destroy the media players before CDMs because we do not support // detaching CDMs from media players yet. See http://crbug.com/330324 media_player_managers_.erase(render_frame_host); + media_session_managers_.erase(render_frame_host); // TODO(xhwang): Currently MediaWebContentsObserver, BrowserMediaPlayerManager // and BrowserCdmManager all run on browser UI thread. So this call is okay. @@ -295,6 +298,12 @@ bool MediaWebContentsObserver::OnMediaPlayerMessageReceived( GetMediaPlayerManager(render_frame_host), BrowserMediaPlayerManager::OnNotifyExternalSurface) #endif // defined(VIDEO_HOLE) + IPC_MESSAGE_FORWARD(MediaSessionHostMsg_Activate, + GetMediaSessionManager(render_frame_host), + BrowserMediaSessionManager::OnActivate) + IPC_MESSAGE_FORWARD(MediaSessionHostMsg_Deactivate, + GetMediaSessionManager(render_frame_host), + BrowserMediaSessionManager::OnDeactivate) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -354,6 +363,18 @@ BrowserMediaPlayerManager* MediaWebContentsObserver::GetMediaPlayerManager( return manager; } +BrowserMediaSessionManager* MediaWebContentsObserver::GetMediaSessionManager( + RenderFrameHost* render_frame_host) { + auto it = media_session_managers_.find(render_frame_host); + if (it != media_session_managers_.end()) + return it->second; + + BrowserMediaSessionManager* manager = + new BrowserMediaSessionManager(render_frame_host); + media_session_managers_.set(render_frame_host, make_scoped_ptr(manager)); + return manager; +} + #if defined(VIDEO_HOLE) void MediaWebContentsObserver::OnFrameInfoUpdated() { for (auto it = media_player_managers_.begin(); diff --git a/content/browser/media/media_web_contents_observer.h b/content/browser/media/media_web_contents_observer.h index 0a24913..4af84a4 100644 --- a/content/browser/media/media_web_contents_observer.h +++ b/content/browser/media/media_web_contents_observer.h @@ -19,6 +19,7 @@ namespace content { class BrowserCdmManager; class BrowserMediaPlayerManager; +class BrowserMediaSessionManager; // This class manages all RenderFrame based media related managers at the // browser side. It receives IPC messages from media RenderFrameObservers and @@ -46,6 +47,9 @@ class CONTENT_EXPORT MediaWebContentsObserver : public WebContentsObserver { BrowserMediaPlayerManager* GetMediaPlayerManager( RenderFrameHost* render_frame_host); + BrowserMediaSessionManager* GetMediaSessionManager( + RenderFrameHost* render_frame_host); + #if defined(VIDEO_HOLE) void OnFrameInfoUpdated(); #endif // defined(VIDEO_HOLE) @@ -113,6 +117,12 @@ class CONTENT_EXPORT MediaWebContentsObserver : public WebContentsObserver { base::ScopedPtrHashMap<RenderFrameHost*, scoped_ptr<BrowserMediaPlayerManager>>; MediaPlayerManagerMap media_player_managers_; + + // Map from RenderFrameHost* to BrowserMediaSessionManager. + using MediaSessionManagerMap = + base::ScopedPtrHashMap<RenderFrameHost*, + scoped_ptr<BrowserMediaSessionManager>>; + MediaSessionManagerMap media_session_managers_; #endif // defined(OS_ANDROID) // Tracking variables and associated power save blockers for media playback. diff --git a/content/common/content_message_generator.h b/content/common/content_message_generator.h index aa7d25c..a3b31ad 100644 --- a/content/common/content_message_generator.h +++ b/content/common/content_message_generator.h @@ -72,4 +72,5 @@ #include "content/common/android/sync_compositor_messages.h" #include "content/common/gin_java_bridge_messages.h" #include "content/common/media/media_player_messages_android.h" +#include "content/common/media/media_session_messages_android.h" #endif // defined(OS_ANDROID) diff --git a/content/common/media/media_session_messages_android.h b/content/common/media/media_session_messages_android.h new file mode 100644 index 0000000..3ea4a7e --- /dev/null +++ b/content/common/media/media_session_messages_android.h @@ -0,0 +1,33 @@ +// Copyright 2015 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. + +// IPC messages for the Media Session API. +// Multiply-included message file, hence no include guard. + +#include "base/basictypes.h" +#include "content/common/android/gin_java_bridge_errors.h" +#include "content/common/content_export.h" +#include "ipc/ipc_message_macros.h" + +#undef IPC_MESSAGE_EXPORT +#define IPC_MESSAGE_EXPORT CONTENT_EXPORT +#define IPC_MESSAGE_START MediaSessionMsgStart + +// Messages for notifying the render process of media session status ------- + +IPC_MESSAGE_ROUTED2(MediaSessionMsg_DidActivate, + int /* request_id */, + bool /* success */) + +IPC_MESSAGE_ROUTED1(MediaSessionMsg_DidDeactivate, int /* request_id */) + +// Messages for controlling the media session in browser process ---------- + +IPC_MESSAGE_ROUTED2(MediaSessionHostMsg_Activate, + int /* session_id */, + int /* request_id */) + +IPC_MESSAGE_ROUTED2(MediaSessionHostMsg_Deactivate, + int /* session_id */, + int /* request_id */) diff --git a/content/content_browser.gypi b/content/content_browser.gypi index d708336..6cea7d4 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -980,6 +980,8 @@ 'browser/media/android/browser_demuxer_android.h', 'browser/media/android/browser_media_player_manager.cc', 'browser/media/android/browser_media_player_manager.h', + 'browser/media/android/browser_media_session_manager.cc', + 'browser/media/android/browser_media_session_manager.h', 'browser/media/android/media_resource_getter_impl.cc', 'browser/media/android/media_resource_getter_impl.h', 'browser/media/android/media_session.cc', diff --git a/content/content_common.gypi b/content/content_common.gypi index b809c35..d1fb8a7 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi @@ -428,6 +428,7 @@ 'common/media/media_param_traits.h', 'common/media/media_player_messages_android.h', 'common/media/media_player_messages_enums_android.h', + 'common/media/media_session_messages_android.h', 'common/media/media_stream_messages.h', 'common/media/media_stream_options.cc', 'common/media/media_stream_options.h', diff --git a/content/renderer/media/android/renderer_media_session_manager.cc b/content/renderer/media/android/renderer_media_session_manager.cc index c39c0dc..58b0888 100644 --- a/content/renderer/media/android/renderer_media_session_manager.cc +++ b/content/renderer/media/android/renderer_media_session_manager.cc @@ -5,6 +5,8 @@ #include "content/renderer/media/android/renderer_media_session_manager.h" #include "base/logging.h" +#include "content/common/media/media_session_messages_android.h" +#include "content/public/renderer/render_thread.h" #include "content/renderer/media/android/webmediasession_android.h" namespace content { @@ -22,6 +24,16 @@ RendererMediaSessionManager::~RendererMediaSessionManager() { "destroyed only after all media sessions are destroyed."; } +bool RendererMediaSessionManager::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(RendererMediaSessionManager, msg) + IPC_MESSAGE_HANDLER(MediaSessionMsg_DidActivate, OnDidActivate) + IPC_MESSAGE_HANDLER(MediaSessionMsg_DidDeactivate, OnDidDeactivate) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + int RendererMediaSessionManager::RegisterMediaSession( WebMediaSessionAndroid* session) { sessions_[next_session_id_] = session; @@ -32,4 +44,38 @@ void RendererMediaSessionManager::UnregisterMediaSession(int session_id) { sessions_.erase(session_id); } +void RendererMediaSessionManager::Activate( + int session_id, + scoped_ptr<blink::WebMediaSessionActivateCallback> callback) { + int request_id = pending_activation_requests_.Add(callback.release()); + Send(new MediaSessionHostMsg_Activate(routing_id(), session_id, request_id)); +} + +void RendererMediaSessionManager::Deactivate( + int session_id, + scoped_ptr<blink::WebMediaSessionDeactivateCallback> callback) { + int request_id = pending_deactivation_requests_.Add(callback.release()); + Send( + new MediaSessionHostMsg_Deactivate(routing_id(), session_id, request_id)); +} + +void RendererMediaSessionManager::OnDidActivate(int request_id, bool success) { + DCHECK(pending_activation_requests_.Lookup(request_id)) << request_id; + blink::WebMediaSessionActivateCallback* callback = + pending_activation_requests_.Lookup(request_id); + if (success) { + callback->onSuccess(); + } else { + callback->onError( + blink::WebMediaSessionError(blink::WebMediaSessionError::Activate)); + } + pending_activation_requests_.Remove(request_id); +} + +void RendererMediaSessionManager::OnDidDeactivate(int request_id) { + DCHECK(pending_deactivation_requests_.Lookup(request_id)) << request_id; + pending_deactivation_requests_.Lookup(request_id)->onSuccess(); + pending_deactivation_requests_.Remove(request_id); +} + } // namespace content diff --git a/content/renderer/media/android/renderer_media_session_manager.h b/content/renderer/media/android/renderer_media_session_manager.h index f07b230c..c7f7504 100644 --- a/content/renderer/media/android/renderer_media_session_manager.h +++ b/content/renderer/media/android/renderer_media_session_manager.h @@ -7,9 +7,11 @@ #include <map> +#include "base/id_map.h" #include "base/macros.h" #include "content/common/content_export.h" #include "content/public/renderer/render_frame_observer.h" +#include "third_party/WebKit/public/platform/modules/mediasession/WebMediaSession.h" namespace content { @@ -20,15 +22,35 @@ class CONTENT_EXPORT RendererMediaSessionManager : public RenderFrameObserver { RendererMediaSessionManager(RenderFrame* render_frame); ~RendererMediaSessionManager() override; + // RenderFrameObserver override. + bool OnMessageReceived(const IPC::Message& msg) override; + int RegisterMediaSession(WebMediaSessionAndroid* session); void UnregisterMediaSession(int session_id); + void Activate(int session_id, + scoped_ptr<blink::WebMediaSessionActivateCallback> callback); + void Deactivate( + int session_id, + scoped_ptr<blink::WebMediaSessionDeactivateCallback> callback); + + void OnDidActivate(int request_id, bool success); + void OnDidDeactivate(int request_id); + private: friend class WebMediaSessionTest; std::map<int, WebMediaSessionAndroid*> sessions_; int next_session_id_; + using ActivationRequests = + IDMap<blink::WebMediaSessionActivateCallback, IDMapOwnPointer>; + ActivationRequests pending_activation_requests_; + + using DeactivationRequests = + IDMap<blink::WebMediaSessionDeactivateCallback, IDMapOwnPointer>; + DeactivationRequests pending_deactivation_requests_; + DISALLOW_COPY_AND_ASSIGN(RendererMediaSessionManager); }; diff --git a/content/renderer/media/android/webmediasession_android.cc b/content/renderer/media/android/webmediasession_android.cc index 7eddd31..b10d5f2 100644 --- a/content/renderer/media/android/webmediasession_android.cc +++ b/content/renderer/media/android/webmediasession_android.cc @@ -22,19 +22,13 @@ WebMediaSessionAndroid::~WebMediaSessionAndroid() { } void WebMediaSessionAndroid::activate( - blink::WebMediaSessionActivateCallback* raw_callback) { - NOTIMPLEMENTED(); - - scoped_ptr<blink::WebMediaSessionActivateCallback> callback(raw_callback); - callback->onError(blink::WebMediaSessionError::Activate); + blink::WebMediaSessionActivateCallback* callback) { + session_manager_->Activate(session_id_, make_scoped_ptr(callback)); } void WebMediaSessionAndroid::deactivate( - blink::WebMediaSessionDeactivateCallback* raw_callback) { - NOTIMPLEMENTED(); - - scoped_ptr<blink::WebMediaSessionDeactivateCallback> callback(raw_callback); - callback->onSuccess(); + blink::WebMediaSessionDeactivateCallback* callback) { + session_manager_->Deactivate(session_id_, make_scoped_ptr(callback)); } void WebMediaSessionAndroid::setMetadata( diff --git a/content/renderer/media/android/webmediasession_android_unittest.cc b/content/renderer/media/android/webmediasession_android_unittest.cc index fb153f7..69e8138 100644 --- a/content/renderer/media/android/webmediasession_android_unittest.cc +++ b/content/renderer/media/android/webmediasession_android_unittest.cc @@ -5,13 +5,23 @@ #include "content/renderer/media/android/webmediasession_android.h" #include "base/memory/scoped_ptr.h" +#include "content/common/media/media_session_messages_android.h" #include "content/renderer/media/android/renderer_media_session_manager.h" #include "testing/gmock/include/gmock/gmock.h" namespace content { +namespace { + +const int kRouteId = 0; + +} // anonymous namespace + class WebMediaSessionTest : public testing::Test { public: + void OnSuccess() { ++success_count_; } + void OnError() { ++error_count_; } + bool SessionManagerHasSession(RendererMediaSessionManager* session_manager, WebMediaSessionAndroid* session) { for (auto& iter : session_manager->sessions_) { @@ -24,6 +34,34 @@ class WebMediaSessionTest : public testing::Test { bool IsSessionManagerEmpty(RendererMediaSessionManager* session_manager) { return session_manager->sessions_.empty(); } + + protected: + int success_count_ = 0; + int error_count_ = 0; +}; + +class TestActivateCallback : public blink::WebMediaSessionActivateCallback { + public: + TestActivateCallback(WebMediaSessionTest* test) : test_(test) {} + + private: + void onSuccess() override { test_->OnSuccess(); } + void onError(const blink::WebMediaSessionError&) override { + test_->OnError(); + } + + WebMediaSessionTest* test_; +}; + +class TestDeactivateCallback : public blink::WebMediaSessionDeactivateCallback { + public: + TestDeactivateCallback(WebMediaSessionTest* test) : test_(test) {} + + private: + void onSuccess() override { test_->OnSuccess(); } + void onError() override { test_->OnError(); } + + WebMediaSessionTest* test_; }; TEST_F(WebMediaSessionTest, TestRegistration) { @@ -83,4 +121,132 @@ TEST_F(WebMediaSessionTest, TestMultipleRegistrationOutOfOrder) { EXPECT_TRUE(IsSessionManagerEmpty(session_manager.get())); } +TEST_F(WebMediaSessionTest, ActivationOutOfOrder) { + scoped_ptr<RendererMediaSessionManager> session_manager( + new RendererMediaSessionManager(nullptr)); + + scoped_ptr<WebMediaSessionAndroid> session( + new WebMediaSessionAndroid(session_manager.get())); + + // Request activate three times + session->activate(new TestActivateCallback(this)); // request 1 + session->activate(new TestActivateCallback(this)); // request 2 + session->activate(new TestActivateCallback(this)); // request 3 + + // Confirm activation out of order + session_manager->OnMessageReceived( + MediaSessionMsg_DidActivate(kRouteId, 3, true)); + + session_manager->OnMessageReceived( + MediaSessionMsg_DidActivate(kRouteId, 2, true)); + + session_manager->OnMessageReceived( + MediaSessionMsg_DidActivate(kRouteId, 1, true)); + + EXPECT_EQ(3, success_count_); + EXPECT_EQ(0, error_count_); +} + +TEST_F(WebMediaSessionTest, ActivationInOrder) { + scoped_ptr<RendererMediaSessionManager> session_manager( + new RendererMediaSessionManager(nullptr)); + + scoped_ptr<WebMediaSessionAndroid> session( + new WebMediaSessionAndroid(session_manager.get())); + + // Request activate three times + session->activate(new TestActivateCallback(this)); // request 1 + session_manager->OnMessageReceived( + MediaSessionMsg_DidActivate(kRouteId, 1, true)); + + session->activate(new TestActivateCallback(this)); // request 2 + session_manager->OnMessageReceived( + MediaSessionMsg_DidActivate(kRouteId, 2, true)); + + session->activate(new TestActivateCallback(this)); // request 3 + session_manager->OnMessageReceived( + MediaSessionMsg_DidActivate(kRouteId, 3, true)); + + EXPECT_EQ(3, success_count_); + EXPECT_EQ(0, error_count_); +} + +TEST_F(WebMediaSessionTest, ActivationInFlight) { + scoped_ptr<RendererMediaSessionManager> session_manager( + new RendererMediaSessionManager(nullptr)); + + scoped_ptr<WebMediaSessionAndroid> session( + new WebMediaSessionAndroid(session_manager.get())); + + session->activate(new TestActivateCallback(this)); // request 1 + session->activate(new TestActivateCallback(this)); // request 2 + session->activate(new TestActivateCallback(this)); // request 3 + + session_manager->OnMessageReceived( + MediaSessionMsg_DidActivate(kRouteId, 1, true)); + + session->activate(new TestActivateCallback(this)); // request 4 + session->activate(new TestActivateCallback(this)); // request 5 + + session_manager->OnMessageReceived( + MediaSessionMsg_DidActivate(kRouteId, 3, true)); + session_manager->OnMessageReceived( + MediaSessionMsg_DidActivate(kRouteId, 2, true)); + session_manager->OnMessageReceived( + MediaSessionMsg_DidActivate(kRouteId, 5, true)); + session_manager->OnMessageReceived( + MediaSessionMsg_DidActivate(kRouteId, 4, true)); + + EXPECT_EQ(5, success_count_); + EXPECT_EQ(0, error_count_); +} + +TEST_F(WebMediaSessionTest, ActivationFailure) { + scoped_ptr<RendererMediaSessionManager> session_manager( + new RendererMediaSessionManager(nullptr)); + + scoped_ptr<WebMediaSessionAndroid> session( + new WebMediaSessionAndroid(session_manager.get())); + + session->activate(new TestActivateCallback(this)); // request 1 + session->activate(new TestActivateCallback(this)); // request 2 + session->activate(new TestActivateCallback(this)); // request 3 + + session_manager->OnMessageReceived( + MediaSessionMsg_DidActivate(kRouteId, 1, true)); + EXPECT_EQ(1, success_count_); + EXPECT_EQ(0, error_count_); + session_manager->OnMessageReceived( + MediaSessionMsg_DidActivate(kRouteId, 2, false)); + EXPECT_EQ(1, success_count_); + EXPECT_EQ(1, error_count_); + session_manager->OnMessageReceived( + MediaSessionMsg_DidActivate(kRouteId, 3, true)); + EXPECT_EQ(2, success_count_); + EXPECT_EQ(1, error_count_); +} + +TEST_F(WebMediaSessionTest, Deactivation) { + scoped_ptr<RendererMediaSessionManager> session_manager( + new RendererMediaSessionManager(nullptr)); + + scoped_ptr<WebMediaSessionAndroid> session( + new WebMediaSessionAndroid(session_manager.get())); + + // Request deactivate three times + session->deactivate(new TestDeactivateCallback(this)); // request 1 + session->deactivate(new TestDeactivateCallback(this)); // request 2 + session->deactivate(new TestDeactivateCallback(this)); // request 3 + session_manager->OnMessageReceived( + MediaSessionMsg_DidDeactivate(kRouteId, 1)); + EXPECT_EQ(1, success_count_); + session_manager->OnMessageReceived( + MediaSessionMsg_DidDeactivate(kRouteId, 2)); + EXPECT_EQ(2, success_count_); + session_manager->OnMessageReceived( + MediaSessionMsg_DidDeactivate(kRouteId, 3)); + EXPECT_EQ(3, success_count_); + EXPECT_EQ(0, error_count_); +} + } // namespace content |