| 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
|
|
|