Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(620)

Unified Diff: chrome/browser/media/router/offscreen_presentation_manager.cc

Issue 1314413005: [Presentation API] 1-UA presentation support + presenter APIs. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/media/router/offscreen_presentation_manager.cc
diff --git a/chrome/browser/media/router/offscreen_presentation_manager.cc b/chrome/browser/media/router/offscreen_presentation_manager.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1dd2f0f949731a1a2d6436ca3f160d0d8c0956ba
--- /dev/null
+++ b/chrome/browser/media/router/offscreen_presentation_manager.cc
@@ -0,0 +1,485 @@
+// 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 "chrome/browser/media/router/offscreen_presentation_manager.h"
+
+#include "content/public/browser/presentation_session_state_listener.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+
+using content::PresentationSessionInfo;
+using content::PresentationReceiverSessionAvailableCallback;
+
+namespace media_router {
+
+namespace {
+
+RenderFrameHostId GetMainFrameRenderFrameHostId(
+ content::WebContents* web_contents) {
+ content::RenderFrameHost* render_frame_host = web_contents->GetMainFrame();
+ DCHECK(render_frame_host);
+ return RenderFrameHostId(render_frame_host->GetProcess()->GetID(),
+ render_frame_host->GetRoutingID());
+}
+
+} // namespace
+
+OffscreenPresenterContext::OffscreenPresenterContext(
+ content::WebContents* presenter_web_contents,
+ const std::string& presentation_id,
+ OffscreenPresentationManager* manager)
+ : presenter_web_contents_(presenter_web_contents),
+ presentation_id_(presentation_id),
+ manager_(manager) {
+ DCHECK(presenter_web_contents_);
+ DCHECK(manager_);
+}
+
+OffscreenPresenterContext::~OffscreenPresenterContext() {
+ manager_->UnregisterPresenterTab(presenter_web_contents_);
+}
+
+void OffscreenPresenterContext::GetPresentationReceiverSession(
+ const RenderFrameHostId& frame_id,
+ const content::PresentationReceiverSessionAvailableCallback&
+ success_callback,
+ const base::Callback<void(const std::string&)>& error_callback) {
+ if (!IsPresenterFrame(frame_id)) {
+ DVLOG(1) << "Not a presenter frame: " << frame_id.first << ", "
+ << frame_id.second;
+ error_callback.Run("Not a presenter frame");
+ return;
+ }
+
+ manager_->GetReceiverSession(frame_id, success_callback);
+}
+
+std::vector<content::PresentationSessionInfo>
+OffscreenPresenterContext::GetPresentationReceiverSessions(
+ const RenderFrameHostId& frame_id) const {
+ if (!IsPresenterFrame(frame_id)) {
+ DVLOG(1) << "Not a presenter frame: " << frame_id.first << ", "
+ << frame_id.second;
+ return std::vector<content::PresentationSessionInfo>();
+ }
+
+ return manager_->GetPresentationReceiverSessions(frame_id);
+}
+
+bool OffscreenPresenterContext::IsPresenterFrame(
+ const RenderFrameHostId& frame_id) const {
+ return GetMainFrameRenderFrameHostId(presenter_web_contents_) == frame_id;
+}
+
+void OffscreenPresenterContext::SendMessage(
+ const RenderFrameHostId& frame_id,
+ const content::PresentationSessionInfo& session,
+ scoped_ptr<content::PresentationSessionMessage> message,
+ const content::SendMessageCallback& callback) {
+ DCHECK_EQ(presentation_id_, session.presentation_id);
+ DCHECK(!session.IsController());
+ DCHECK(IsPresenterFrame(frame_id));
+
+ manager_->SendMessage(session, message.Pass(), callback);
+}
+
+void OffscreenPresenterContext::ListenForMessages(
+ const RenderFrameHostId& frame_id,
miu 2015/09/27 00:22:08 1. |frame_id| argument is not used, so can you rem
imcheng 2015/09/30 01:13:41 1. Removed. Also removed some other unused fields
+ const content::PresentationSessionInfo& session,
+ const content::PresentationSessionMessageCallback& callback) {
+ DCHECK_EQ(presentation_id_, session.presentation_id);
+ DCHECK(!session.IsController());
+ DCHECK(IsPresenterFrame(frame_id));
+
+ manager_->ListenForMessages(session, callback);
+}
+
+void OffscreenPresenterContext::ListenForStateChanges(
+ const RenderFrameHostId& frame_id,
+ content::PresentationSessionStateListener* listener) {
+ DCHECK(listener);
+ DCHECK(IsPresenterFrame(frame_id));
+
+ const content::PresentationSessionInfo& session = listener->GetSessionInfo();
miu 2015/09/27 00:22:08 These three lines need to be wrapped in a #ifndef
imcheng 2015/09/30 01:13:41 Removed
+ DCHECK_EQ(presentation_id_, session.presentation_id);
+ DCHECK(!session.IsController());
+
+ manager_->ListenForStateChanges(listener);
+}
+
+OffscreenController::OffscreenController(
+ const RenderFrameHostId& controller_frame_id,
+ const content::PresentationSessionInfo& session,
+ OffscreenPresentationManager* manager)
+ : controller_frame_id_(controller_frame_id),
+ session_(session),
+ manager_(manager) {
+ DCHECK(manager_);
+ DCHECK(session.IsController());
+}
+
+OffscreenController::~OffscreenController() {
+ manager_->UnregisterController(controller_frame_id_,
+ session_.presentation_id);
+}
+
+void OffscreenController::SendMessage(
+ scoped_ptr<content::PresentationSessionMessage> message,
+ const content::SendMessageCallback& callback) {
+ manager_->SendMessage(session_, message.Pass(), callback);
+}
+
+void OffscreenController::ListenForMessages(
+ const content::PresentationSessionMessageCallback& callback) {
+ manager_->ListenForMessages(session_, callback);
+}
+
+void OffscreenController::ListenForStateChanges(
+ content::PresentationSessionStateListener* listener) {
+ DCHECK(listener);
+ DCHECK_EQ(session_.presentation_id,
+ listener->GetSessionInfo().presentation_id);
+ manager_->ListenForStateChanges(listener);
+}
+
+OffscreenPresentationManager::~OffscreenPresentationManager() {}
+
+void OffscreenPresentationManager::RegisterPresenterTab(
+ const std::string& presentation_id,
+ content::WebContents* presenter_web_contents) {
+ DCHECK(presenter_web_contents);
+ RenderFrameHostId presenter_frame_id(
+ GetMainFrameRenderFrameHostId(presenter_web_contents));
+ DCHECK(!ContainsKey(presenter_frames_, presenter_frame_id));
+ presenter_frames_[presenter_frame_id] = presentation_id;
+
+ auto* presentation_info =
+ GetOrCreateOffscreenPresentationInfo(presentation_id);
+ presentation_info->presenter_frame_id = presenter_frame_id;
+ // We wait until the controller side has registered before setting up the
+ // route.
+}
+
+void OffscreenPresentationManager::UnregisterPresenterTab(
+ content::WebContents* presenter_web_contents) {
+ DCHECK(presenter_web_contents);
+ RenderFrameHostId presenter_frame_id(
+ GetMainFrameRenderFrameHostId(presenter_web_contents));
+
+ auto it = presenter_frames_.find(presenter_frame_id);
+ if (it == presenter_frames_.end())
+ return;
+
+ std::string presentation_id = it->second;
+ presenter_frames_.erase(it);
+
+ auto* presentation_info = GetOffscreenPresentationInfo(presentation_id);
+ DCHECK(presentation_info);
+ DCHECK(presenter_frame_id == presentation_info->presenter_frame_id);
+ RemovePresenterAndNotifyStateChange(presentation_info);
+ if (presentation_info->IsEmpty())
+ offscreen_presentation_infos_.erase(presentation_id);
+}
+
+scoped_ptr<OffscreenPresenterContext>
+OffscreenPresentationManager::GetOffscreenPresenterContext(
+ content::WebContents* presenter_web_contents) {
+ DCHECK(presenter_web_contents);
+ RenderFrameHostId presenter_frame_id(
+ GetMainFrameRenderFrameHostId(presenter_web_contents));
+ auto it = presenter_frames_.find(presenter_frame_id);
+ if (it == presenter_frames_.end())
+ return scoped_ptr<OffscreenPresenterContext>();
+
+ return make_scoped_ptr(
+ new OffscreenPresenterContext(presenter_web_contents, it->second, this));
+}
+
+scoped_ptr<OffscreenController>
+OffscreenPresentationManager::RegisterController(
+ const content::PresentationSessionInfo& session,
+ const RenderFrameHostId& controller_frame_id) {
+ const std::string& presentation_id = session.presentation_id;
+ auto* presentation_info =
+ GetOrCreateOffscreenPresentationInfo(presentation_id);
+
+ auto& route = presentation_info->route;
+
+ // Check that this (presentation, controller) is not already registered.
+ DCHECK(!route.controller);
+ DCHECK(!route.presenter);
+
+ route.controller.reset(
+ new OffscreenPresentationSessionInfo(controller_frame_id, session));
+ content::PresentationSessionInfo presenter_session(std::string(),
+ presentation_id);
+ route.presenter.reset(new OffscreenPresentationSessionInfo(
+ controller_frame_id, presenter_session));
+
+ // Resolve pending getSession() request.
+ // Note: session objects for presenters do not contain presentation URLs.
+ if (!presentation_info->session_callback.is_null()) {
+ presentation_info->session_callback.Run(presenter_session);
+ presentation_info->session_callback.Reset();
+ }
+
+ return make_scoped_ptr(
+ new OffscreenController(controller_frame_id, session, this));
+}
+
+void OffscreenPresentationManager::GetReceiverSession(
+ const RenderFrameHostId& presenter_frame_id,
+ const PresentationReceiverSessionAvailableCallback& callback) {
+ DCHECK(!callback.is_null());
+ DCHECK(ContainsKey(presenter_frames_, presenter_frame_id));
+
+ const std::string& presentation_id = presenter_frames_[presenter_frame_id];
+ auto* presentation_info = GetOffscreenPresentationInfo(presentation_id);
+ DCHECK(presentation_info);
+ DCHECK(presenter_frame_id == presentation_info->presenter_frame_id);
+
+ // Resolve with the first route.
+ const auto& route = presentation_info->route;
+ if (route.presenter) {
+ callback.Run(route.presenter->session);
+ return;
+ } else {
+ presentation_info->session_callback = callback;
+ }
+}
+
+std::vector<content::PresentationSessionInfo>
+OffscreenPresentationManager::GetPresentationReceiverSessions(
+ const RenderFrameHostId& presenter_frame_id) const {
+ DCHECK(ContainsKey(presenter_frames_, presenter_frame_id));
+
+ auto it = presenter_frames_.find(presenter_frame_id);
+ DCHECK(it != presenter_frames_.end());
+ const std::string& presentation_id = it->second;
+ auto* presentation_info = GetOffscreenPresentationInfo(presentation_id);
+ DCHECK(presentation_info);
+
+ std::vector<content::PresentationSessionInfo> sessions;
+ // TODO(imcheng): Support multiple controllers.
+ if (presentation_info->route.presenter)
+ sessions.push_back(presentation_info->route.presenter->session);
+ return sessions;
+}
+
+void OffscreenPresentationManager::SendMessage(
+ const PresentationSessionInfo& session,
+ scoped_ptr<content::PresentationSessionMessage> message,
+ const content::SendMessageCallback& callback) {
+ const std::string& presentation_id = session.presentation_id;
+ auto* presentation_info = GetOffscreenPresentationInfo(presentation_id);
+ if (!presentation_info) {
+ LOG(ERROR) << "SendMessage: Unknown 1UA presentation " << presentation_id;
+ callback.Run(false);
+ return;
+ }
+
+ auto& route = presentation_info->route;
+ // From presenter to controller.
+ if (!session.IsController()) {
+ auto* controller = route.controller.get();
+ if (controller && !controller->message_callback.is_null()) {
+ ScopedVector<content::PresentationSessionMessage> messages;
+ messages.push_back(message.release());
+ controller->message_callback.Run(messages.Pass(), true);
+ }
+ } else {
+ auto* presenter = route.presenter.get();
+ // From controller to presenter.
+ if (presenter && !presenter->message_callback.is_null()) {
+ ScopedVector<content::PresentationSessionMessage> messages;
+ messages.push_back(message.release());
+ presenter->message_callback.Run(messages.Pass(), true);
+ }
+ }
+
+ callback.Run(true);
+}
+
+void OffscreenPresentationManager::ListenForMessages(
+ const PresentationSessionInfo& session,
+ const content::PresentationSessionMessageCallback& callback) {
+ const std::string& presentation_id = session.presentation_id;
+ auto* presentation_info = GetOffscreenPresentationInfo(presentation_id);
+ if (!presentation_info) {
+ LOG(ERROR) << "ListenForMessages: Unknown 1UA presentation "
+ << presentation_id;
+ return;
+ }
+
+ auto& route = presentation_info->route;
+ if (!session.IsController()) {
+ auto* presenter = route.presenter.get();
+ if (!presenter) {
+ LOG(ERROR) << "ListenForMessages: presenter frame not found for "
+ << presentation_id;
+ return;
+ }
+ DVLOG_IF(2, !presenter->message_callback.is_null())
+ << "Overwriting presenter frame message callback for "
+ << presentation_id;
+ presenter->message_callback = callback;
+ } else {
+ auto* controller = route.controller.get();
+ if (!controller) {
+ LOG(ERROR) << "ListenForMessages: controller frame not found for "
+ << presentation_id;
+ return;
+ }
+ DVLOG_IF(2, !controller->message_callback.is_null())
+ << "Overwriting controller frame message callback for "
+ << presentation_id;
+ controller->message_callback = callback;
+ }
+}
+
+void OffscreenPresentationManager::ListenForStateChanges(
+ content::PresentationSessionStateListener* listener) {
+ DCHECK(listener);
+
+ const content::PresentationSessionInfo& session = listener->GetSessionInfo();
+ const std::string& presentation_id = session.presentation_id;
+ auto* presentation_info = GetOffscreenPresentationInfo(presentation_id);
+ if (!presentation_info) {
+ LOG(ERROR) << "ListenForMessages: Unknown 1UA presentation "
+ << presentation_id;
+ return;
+ }
+
+ auto& route = presentation_info->route;
+ if (!session.IsController()) {
+ auto* presenter = route.presenter.get();
+ if (!presenter) {
+ LOG(ERROR) << "ListenForMessages: presenter frame not found for "
+ << presentation_id;
+ return;
+ }
+ DVLOG_IF(2, presenter->state_change_listener)
+ << "Overwriting presenter frame state change listener for "
+ << presentation_id;
+ presenter->state_change_listener = listener;
+ } else {
+ auto* controller = route.controller.get();
+ if (!controller) {
+ LOG(ERROR) << "ListenForMessages: controller frame not found for "
+ << presentation_id;
+ return;
+ }
+ DVLOG_IF(2, controller->state_change_listener)
+ << "Overwriting controller frame state change listener for "
+ << presentation_id;
+ controller->state_change_listener = listener;
+ }
+}
+
+void OffscreenPresentationManager::UnregisterController(
+ const RenderFrameHostId& controller_frame_id,
+ const std::string& presentation_id) {
+ auto it = offscreen_presentation_infos_.find(presentation_id);
+ if (it == offscreen_presentation_infos_.end())
+ return;
+
+ auto* presentation_info = it->second;
+ RemoveControllerAndNotifyStateChange(presentation_info, controller_frame_id);
+ if (presentation_info->IsEmpty())
+ offscreen_presentation_infos_.erase(it);
+}
+
+OffscreenPresentationManager::OffscreenPresentationManager() {}
+
+void OffscreenPresentationManager::RemovePresenterAndNotifyStateChange(
+ OffscreenPresentationInfo* presentation_info) {
+ presentation_info->presenter_frame_id = RenderFrameHostId();
+ presentation_info->session_callback.Reset();
+
+ auto& route = presentation_info->route;
+ if (route.presenter) {
+ route.presenter.reset();
+ auto& controller = route.controller;
+ if (controller && controller->state_change_listener) {
+ controller->state_change_listener->OnSessionStateChanged(
+ content::PRESENTATION_SESSION_STATE_DISCONNECTED);
+ }
+ }
+}
+
+void OffscreenPresentationManager::RemoveControllerAndNotifyStateChange(
+ OffscreenPresentationInfo* presentation_info,
+ const RenderFrameHostId& controller_frame_id) {
+ auto& route = presentation_info->route;
+ if (!route.controller ||
+ route.controller->controller_frame_id != controller_frame_id)
+ return;
+
+ route.controller.reset();
+
+ // Notify the corresponding presenter session object.
+ auto& presenter = route.presenter;
+ if (presenter && presenter->state_change_listener) {
+ presenter->state_change_listener->OnSessionStateChanged(
+ content::PRESENTATION_SESSION_STATE_DISCONNECTED);
+ }
+}
+
+OffscreenPresentationManager::OffscreenPresentationInfo*
+OffscreenPresentationManager::GetOrCreateOffscreenPresentationInfo(
+ const std::string& presentation_id) {
+ OffscreenPresentationInfo* info = nullptr;
+ auto presentation_info_it =
+ offscreen_presentation_infos_.find(presentation_id);
+ if (presentation_info_it == offscreen_presentation_infos_.end()) {
+ info = new OffscreenPresentationInfo;
+ offscreen_presentation_infos_.insert(presentation_id,
+ make_scoped_ptr(info));
+ } else {
+ info = presentation_info_it->second;
+ }
+ DCHECK(info);
+ return info;
+}
+
+OffscreenPresentationManager::OffscreenPresentationInfo*
+OffscreenPresentationManager::GetOffscreenPresentationInfo(
+ const std::string& presentation_id) const {
+ OffscreenPresentationInfo* info = nullptr;
+ auto presentation_info_it =
+ offscreen_presentation_infos_.find(presentation_id);
+ return presentation_info_it == offscreen_presentation_infos_.end()
+ ? nullptr
+ : presentation_info_it->second;
+}
+
+OffscreenPresentationManager::OffscreenPresentationSessionInfo::
+ OffscreenPresentationSessionInfo(
+ const RenderFrameHostId& controller_frame_id,
+ const content::PresentationSessionInfo& session)
+ : controller_frame_id(controller_frame_id),
+ session(session),
+ state_change_listener(nullptr) {}
+
+OffscreenPresentationManager::OffscreenPresentationSessionInfo::
+ ~OffscreenPresentationSessionInfo() {}
+
+OffscreenPresentationManager::OffscreenPresentationRoute::
+ OffscreenPresentationRoute() {}
+
+OffscreenPresentationManager::OffscreenPresentationRoute::
+ ~OffscreenPresentationRoute() {}
+
+OffscreenPresentationManager::OffscreenPresentationInfo::
+ OffscreenPresentationInfo() {}
+
+OffscreenPresentationManager::OffscreenPresentationInfo::
+ ~OffscreenPresentationInfo() {}
+
+bool OffscreenPresentationManager::OffscreenPresentationInfo::IsEmpty() const {
+ return !route.presenter && !route.controller;
+}
+
+} // namespace media_router

Powered by Google App Engine
This is Rietveld 408576698