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..7522618779f055a65cbd98e379868d1d5dfe4d55 |
--- /dev/null |
+++ b/chrome/browser/media/router/offscreen_presentation_manager.cc |
@@ -0,0 +1,238 @@ |
+// 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 "base/memory/ptr_util.h" |
+#include "content/public/browser/render_frame_host.h" |
+#include "content/public/browser/render_process_host.h" |
+#include "content/public/browser/web_contents.h" |
+ |
+namespace media_router { |
+ |
+// OffscreenPresentationConnection implementation. |
+// //////////////////////////////// |
+ |
+OffscreenPresentationManager::OffscreenPresentationConnection:: |
+ OffscreenPresentationConnection( |
+ OffscreenPresentationManager::OffscreenPresentationSession* session) |
+ : session_(session) { |
+ DCHECK(session_); |
+} |
+ |
+OffscreenPresentationManager::OffscreenPresentationConnection:: |
+ ~OffscreenPresentationConnection() { |
+ if (session_) { |
+ content::PresentationConnectionStateChangeInfo remove_reason( |
+ content::PRESENTATION_CONNECTION_STATE_CLOSED); |
+ remove_reason.close_reason = |
+ content::PRESENTATION_CONNECTION_CLOSE_REASON_WENT_AWAY; |
+ session_->RemoveConnection(this, remove_reason); |
+ } |
+} |
+ |
+void OffscreenPresentationManager::OffscreenPresentationConnection::SendMessage( |
+ std::unique_ptr<content::PresentationSessionMessage> message, |
+ const content::SendMessageCallback& callback) { |
+ if (!session_) { |
+ callback.Run(false); |
+ return; |
+ } |
+ |
+ session_->SendMessageFrom(this, std::move(message), callback); |
+} |
+ |
+void OffscreenPresentationManager::OffscreenPresentationConnection:: |
+ ListenForMessages( |
+ const content::PresentationSessionMessageCallback& callback) { |
+ DCHECK(messages_callback_.is_null()); |
+ DCHECK(!callback.is_null()); |
+ messages_callback_ = callback; |
+} |
+ |
+void OffscreenPresentationManager::OffscreenPresentationConnection:: |
+ ListenForStateChange( |
+ const content::PresentationConnectionStateChangedCallback& callback) { |
+ DCHECK(state_change_callback_.is_null()); |
+ DCHECK(!state_change_callback_.is_null()); |
+ state_change_callback_ = callback; |
+} |
+ |
+void OffscreenPresentationManager::OffscreenPresentationConnection:: |
+ RemoveFromPresentation( |
+ const content::PresentationConnectionStateChangeInfo& remove_reason) { |
+ if (session_) { |
+ session_->RemoveConnection(this, remove_reason); |
+ session_ = nullptr; |
+ } |
+} |
+ |
+void OffscreenPresentationManager::OffscreenPresentationConnection:: |
+ OnConnectionStateChanged( |
+ const content::PresentationConnectionStateChangeInfo& info) { |
+ if (!state_change_callback_.is_null()) |
+ state_change_callback_.Run(info); |
+ |
+ if (info.state == content::PRESENTATION_CONNECTION_STATE_CLOSED || |
+ info.state == content::PRESENTATION_CONNECTION_STATE_TERMINATED) { |
+ session_ = nullptr; |
+ } |
+} |
+ |
+void OffscreenPresentationManager::OffscreenPresentationConnection:: |
+ OnMessageReceived( |
+ std::unique_ptr<content::PresentationSessionMessage> message) { |
+ if (messages_callback_.is_null()) |
+ return; |
+ |
+ // TODO(imcheng): Implement message queueing/batching. |
+ ScopedVector<content::PresentationSessionMessage> messages; |
+ messages.push_back(std::move(message)); |
+ messages_callback_.Run(messages, true); |
+} |
+ |
+// OffscreenPresentationManager implementation. //////////////////////////////// |
+ |
+OffscreenPresentationManager::~OffscreenPresentationManager() {} |
+ |
+void OffscreenPresentationManager::RegisterOffscreenPresentationReceiver( |
+ const std::string& presentation_id, |
+ const ReceiverConnectionAvailableCallback& receiver_available_callback) { |
+ DCHECK(!ContainsKey(offscreen_presentations_, presentation_id)); |
+ |
+ offscreen_presentations_.insert( |
+ std::make_pair(presentation_id, |
+ base::WrapUnique(new OffscreenPresentation( |
+ presentation_id, receiver_available_callback, this)))); |
+} |
+ |
+void OffscreenPresentationManager::UnregisterOffscreenPresentationReceiver( |
+ const std::string& presentation_id) { |
+ DCHECK(ContainsKey(offscreen_presentations_, presentation_id)); |
+ offscreen_presentations_.erase(presentation_id); |
+} |
+ |
+std::unique_ptr<OffscreenPresentationManager::OffscreenPresentationConnection> |
+OffscreenPresentationManager::ConnectToOffscreenPresentation( |
+ const std::string& presentation_id, |
+ const RenderFrameHostId& controller_frame_id) { |
+ auto it = offscreen_presentations_.find(presentation_id); |
+ if (it == offscreen_presentations_.end()) |
+ return std::unique_ptr<OffscreenPresentationConnection>(); |
+ |
+ return it->second->AddSession(controller_frame_id); |
+} |
+ |
+OffscreenPresentationManager::OffscreenPresentationManager() {} |
+ |
+// OffscreenPresentationSession implementation. ///////////////////////////// |
+ |
+OffscreenPresentationManager::OffscreenPresentationSession:: |
+ OffscreenPresentationSession(const RenderFrameHostId& controller_frame_id, |
+ OffscreenPresentation* presentation) |
+ : controller_frame_id_(controller_frame_id), |
+ presentation_(presentation), |
+ controller_(nullptr), |
+ receiver_(nullptr) { |
+ DCHECK(presentation_); |
+} |
+ |
+void OffscreenPresentationManager::OffscreenPresentationSession::Init( |
+ OffscreenPresentationManager::OffscreenPresentationConnection* controller, |
+ OffscreenPresentationManager::OffscreenPresentationConnection* receiver) { |
+ DCHECK(!controller_); |
+ DCHECK(!receiver_); |
+ DCHECK(controller); |
+ DCHECK(receiver); |
+ controller_ = controller; |
+ receiver_ = receiver; |
+} |
+ |
+OffscreenPresentationManager::OffscreenPresentationSession:: |
+ ~OffscreenPresentationSession() { |
+ DCHECK(!controller_ || !receiver_); |
+} |
+ |
+void OffscreenPresentationManager::OffscreenPresentationSession:: |
+ RemoveConnection( |
+ OffscreenPresentationConnection* connection, |
+ const content::PresentationConnectionStateChangeInfo& remove_reason) { |
+ DCHECK(connection); |
+ OffscreenPresentationConnection* other_connection = nullptr; |
+ if (connection == controller_) { |
+ controller_ = nullptr; |
+ other_connection = receiver_; |
+ } else { |
+ DCHECK(connection == receiver_); |
+ receiver_ = nullptr; |
+ other_connection = controller_; |
+ } |
+ |
+ DCHECK(other_connection); |
+ other_connection->OnConnectionStateChanged(remove_reason); |
+ presentation_->RemoveSession(controller_frame_id_); |
+ // |this| is deleted beyond this point. |
+} |
+ |
+void OffscreenPresentationManager::OffscreenPresentationSession:: |
+ SendMessageFrom( |
+ OffscreenPresentationConnection* connection, |
+ std::unique_ptr<content::PresentationSessionMessage> message, |
+ const content::SendMessageCallback& callback) { |
+ OffscreenPresentationConnection* other_connection = |
+ connection == controller_ ? receiver_ : controller_; |
+ DCHECK(other_connection); |
+ |
+ other_connection->OnMessageReceived(std::move(message)); |
+ callback.Run(true); |
+} |
+ |
+// OffscreenPresentation implementation. /////////////////////////////////////// |
+ |
+OffscreenPresentationManager::OffscreenPresentation::OffscreenPresentation( |
+ const std::string& presentation_id, |
+ const ReceiverConnectionAvailableCallback& receiver_available_callback, |
+ OffscreenPresentationManager* manager) |
+ : presentation_id_(presentation_id), |
+ receiver_available_callback_(receiver_available_callback), |
+ manager_(manager) { |
+ DCHECK(!receiver_available_callback_.is_null()); |
+ DCHECK(manager_); |
+} |
+ |
+OffscreenPresentationManager::OffscreenPresentation::~OffscreenPresentation() { |
+ // The receiver must have destroyed all connections before unregistration. |
+ DCHECK(sessions_.empty()); |
+} |
+ |
+std::unique_ptr<OffscreenPresentationManager::OffscreenPresentationConnection> |
+OffscreenPresentationManager::OffscreenPresentation::AddSession( |
+ const RenderFrameHostId& controller_frame_id) { |
+ if (ContainsKey(sessions_, controller_frame_id)) { |
+ DLOG(ERROR) << "Frame " << controller_frame_id.first << ", " |
+ << controller_frame_id.second << " already registered as a " |
+ << "controller for presentation " << presentation_id_; |
+ return std::unique_ptr<OffscreenPresentationConnection>(); |
+ } |
+ |
+ std::unique_ptr<OffscreenPresentationSession> session( |
+ new OffscreenPresentationSession(controller_frame_id, this)); |
+ std::unique_ptr<OffscreenPresentationConnection> controller_connection( |
+ new OffscreenPresentationConnection(session.get())); |
+ std::unique_ptr<OffscreenPresentationConnection> receiver_connection( |
+ new OffscreenPresentationConnection(session.get())); |
+ |
+ session->Init(controller_connection.get(), receiver_connection.get()); |
+ sessions_.insert(std::make_pair(controller_frame_id, std::move(session))); |
+ receiver_available_callback_.Run(std::move(receiver_connection)); |
+ return controller_connection; |
+} |
+ |
+void OffscreenPresentationManager::OffscreenPresentation::RemoveSession( |
+ const RenderFrameHostId& controller_frame_id) { |
+ DCHECK(ContainsKey(sessions_, controller_frame_id)); |
+ sessions_.erase(controller_frame_id); |
+} |
+ |
+} // namespace media_router |