Chromium Code Reviews| 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..f4ce74e1ac413a26709c347db90c997224d6ad09 |
| --- /dev/null |
| +++ b/chrome/browser/media/router/offscreen_presentation_manager.cc |
| @@ -0,0 +1,228 @@ |
| +// 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" |
| + |
| +namespace media_router { |
| + |
| +OffscreenPresentationManager::OffscreenPresentationSession:: |
| + OffscreenPresentationSession( |
| + bool is_controller, |
| + OffscreenPresentationManager::OffscreenPresentationConnection* |
| + connection) |
| + : is_controller_(is_controller), |
| + state_change_listener_(nullptr), |
| + connection_(connection) { |
| + DCHECK(connection_); |
| +} |
| + |
| +OffscreenPresentationManager::OffscreenPresentationSession:: |
| + ~OffscreenPresentationSession() { |
| + connection_->RemoveSession(is_controller_); |
| +} |
| + |
| +void OffscreenPresentationManager::OffscreenPresentationSession::SendMessage( |
| + scoped_ptr<content::PresentationSessionMessage> message, |
| + const content::SendMessageCallback& callback) { |
| + connection_->SendMessage(is_controller_, message.Pass(), callback); |
| +} |
| + |
| +void OffscreenPresentationManager::OffscreenPresentationSession:: |
| + ListenForMessages( |
| + const content::PresentationSessionMessageCallback& callback) { |
| + messages_callback_ = callback; |
| +} |
| + |
| +void OffscreenPresentationManager::OffscreenPresentationSession:: |
| + ListenForStateChanges(content::PresentationSessionStateListener* listener) { |
| + state_change_listener_ = listener; |
| +} |
| + |
| +void OffscreenPresentationManager::OffscreenPresentationSession:: |
| + OnSessionStateChanged(content::PresentationSessionState state) { |
| + if (state_change_listener_) |
| + state_change_listener_->OnSessionStateChanged(state); |
| +} |
| + |
| +void OffscreenPresentationManager::OffscreenPresentationSession:: |
| + OnMessageReceived(scoped_ptr<content::PresentationSessionMessage> message) { |
|
mark a. foltz
2015/10/01 18:39:12
IIUC the PresentationService gets batches of messa
imcheng
2015/10/06 00:59:14
Yes. I added a TODO here. I want to make sure it w
|
| + if (!messages_callback_.is_null()) { |
| + ScopedVector<content::PresentationSessionMessage> messages; |
| + messages.push_back(message.release()); |
| + messages_callback_.Run(messages.Pass(), true); |
| + } |
| +} |
| + |
| +OffscreenPresentationManager::~OffscreenPresentationManager() {} |
| + |
| +void OffscreenPresentationManager::RegisterOffscreenPresentationReceiver( |
| + const std::string& presentation_id, |
| + const ReceiverSessionAvailableCallback& receiver_available_callback) { |
| + DCHECK(!ContainsKey(offscreen_presentations_, presentation_id)); |
|
mark a. foltz
2015/10/01 18:39:12
Well this will be a no-op in release builds. Mayb
imcheng
2015/10/06 00:59:13
insert() will also be no-op if there is already an
|
| + |
| + offscreen_presentations_.insert( |
| + presentation_id, |
| + make_scoped_ptr(new OffscreenPresentation( |
| + presentation_id, receiver_available_callback, this))); |
| +} |
| + |
| +void OffscreenPresentationManager::UnregisterOffscreenPresentationReceiver( |
| + const std::string& presentation_id) { |
| + auto it = offscreen_presentations_.find(presentation_id); |
| + DCHECK(it != offscreen_presentations_.end()); |
|
mark a. foltz
2015/10/01 18:39:12
Similar comment here - it would be better to DLOG
imcheng
2015/10/06 00:59:13
We are always deleting the OffscreenPresentation h
|
| + it->second->OnReceiverDetached(); |
| +} |
| + |
| +scoped_ptr<OffscreenPresentationManager::OffscreenPresentationSession> |
| +OffscreenPresentationManager::CreateOffscreenPresentationConnection( |
| + const std::string& presentation_id, |
| + const RenderFrameHostId& controller_frame_id) { |
| + auto it = offscreen_presentations_.find(presentation_id); |
| + if (it == offscreen_presentations_.end()) |
| + return scoped_ptr< |
| + OffscreenPresentationManager::OffscreenPresentationSession>(); |
| + |
| + return it->second->AddConnectionAndNotifyReceiver(controller_frame_id); |
| +} |
| + |
| +OffscreenPresentationManager::OffscreenPresentationManager() {} |
| + |
| +void OffscreenPresentationManager::RemovePresentation( |
|
mark a. foltz
2015/10/01 18:39:12
This must only be called on presentations that are
imcheng
2015/10/06 00:59:14
This function is removed. But that is correct - I
|
| + const std::string& presentation_id) { |
| + offscreen_presentations_.erase(presentation_id); |
| +} |
| + |
| +OffscreenPresentationManager::OffscreenPresentationConnection:: |
| + OffscreenPresentationConnection( |
| + const RenderFrameHostId& controller_frame_id, |
| + OffscreenPresentation* presentation) |
| + : presentation_(presentation), |
| + controller_frame_id_(controller_frame_id), |
| + controller_(nullptr), |
|
mark a. foltz
2015/10/01 18:39:12
This class would be simpler by accepting a non-nul
imcheng
2015/10/06 00:59:13
The issue is that OffscreenPresentationConnection
|
| + receiver_(nullptr) { |
| + DCHECK(presentation_); |
| +} |
| + |
| +void OffscreenPresentationManager::OffscreenPresentationConnection::Init( |
| + OffscreenPresentationManager::OffscreenPresentationSession* controller, |
| + OffscreenPresentationManager::OffscreenPresentationSession* receiver) { |
| + DCHECK(!controller_); |
| + DCHECK(!receiver_); |
| + DCHECK(controller); |
| + DCHECK(receiver); |
| + controller_ = controller; |
| + receiver_ = receiver; |
| +} |
| + |
| +OffscreenPresentationManager::OffscreenPresentationConnection:: |
| + ~OffscreenPresentationConnection() { |
| + DCHECK(!controller_); |
| + DCHECK(!receiver_); |
| +} |
| + |
| +void OffscreenPresentationManager::OffscreenPresentationConnection:: |
| + RemoveSession(bool is_controller) { |
| + OffscreenPresentationManager::OffscreenPresentationSession* other_session = |
| + nullptr; |
| + if (is_controller) { |
|
mark a. foltz
2015/10/01 18:39:12
This would seem simpler as:
if (is_controller &&
imcheng
2015/10/06 00:59:14
Ack
|
| + DCHECK(controller_); |
| + controller_ = nullptr; |
| + other_session = receiver_; |
| + } else { |
| + DCHECK(receiver_); |
| + receiver_ = nullptr; |
| + other_session = controller_; |
| + } |
| + |
| + if (other_session) { |
| + other_session->OnSessionStateChanged( |
| + content::PRESENTATION_SESSION_STATE_DISCONNECTED); |
| + } else { |
| + presentation_->RemoveConnection(controller_frame_id_); |
| + // |this| is deleted beyond this point. |
| + } |
| +} |
| + |
| +void OffscreenPresentationManager::OffscreenPresentationConnection::SendMessage( |
| + bool is_controller, |
| + scoped_ptr<content::PresentationSessionMessage> message, |
| + const content::SendMessageCallback& callback) { |
| + OffscreenPresentationManager::OffscreenPresentationSession* other_session = |
|
mark a. foltz
2015/10/01 18:39:12
Help me understand - the connection will always ha
imcheng
2015/10/06 00:59:13
Went with your other comment in the .h - SendMessa
|
| + is_controller ? receiver_ : controller_; |
| + if (!other_session) { |
| + callback.Run(false); |
| + return; |
| + } else { |
| + other_session->OnMessageReceived(message.Pass()); |
| + callback.Run(true); |
| + } |
| +} |
| + |
| +OffscreenPresentationManager::OffscreenPresentation::OffscreenPresentation( |
| + const std::string& presentation_id, |
| + const ReceiverSessionAvailableCallback& 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() {} |
| + |
| +void OffscreenPresentationManager::OffscreenPresentation::OnReceiverDetached() { |
| + receiver_available_callback_.Reset(); |
| + MaybeSelfDestruct(); |
| +} |
| + |
| +scoped_ptr<OffscreenPresentationManager::OffscreenPresentationSession> |
| +OffscreenPresentationManager::OffscreenPresentation:: |
| + AddConnectionAndNotifyReceiver( |
| + const RenderFrameHostId& controller_frame_id) { |
| + DCHECK(!ContainsKey(connections_, controller_frame_id)); |
| + |
| + if (IsReceiverGone()) { |
| + return scoped_ptr< |
| + OffscreenPresentationManager::OffscreenPresentationSession>(); |
| + } |
| + |
| + scoped_ptr<OffscreenPresentationConnection> connection( |
| + new OffscreenPresentationManager::OffscreenPresentationConnection( |
| + controller_frame_id, this)); |
|
mark a. foltz
2015/10/01 18:39:12
ISTM the connection should create and own the rece
imcheng
2015/10/06 00:59:14
Per comment above, I could new these Session objec
|
| + scoped_ptr<OffscreenPresentationManager::OffscreenPresentationSession> |
| + controller_session( |
| + new OffscreenPresentationManager::OffscreenPresentationSession( |
| + true, connection.get())); |
| + scoped_ptr<OffscreenPresentationManager::OffscreenPresentationSession> |
| + receiver_session( |
| + new OffscreenPresentationManager::OffscreenPresentationSession( |
| + false, connection.get())); |
| + |
| + connection->Init(controller_session.get(), receiver_session.get()); |
| + connections_.insert(controller_frame_id, connection.Pass()); |
| + receiver_available_callback_.Run(receiver_session.Pass()); |
| + return controller_session.Pass(); |
| +} |
| + |
| +void OffscreenPresentationManager::OffscreenPresentation::RemoveConnection( |
|
mark a. foltz
2015/10/01 18:39:12
What guarantees that the two sessions are in the d
imcheng
2015/10/06 00:59:13
In the new patchset, this is only called from Offs
|
| + const RenderFrameHostId& controller_frame_id) { |
| + DCHECK(ContainsKey(connections_, controller_frame_id)); |
| + |
| + connections_.erase(controller_frame_id); |
| + MaybeSelfDestruct(); |
| +} |
| + |
| +void OffscreenPresentationManager::OffscreenPresentation::MaybeSelfDestruct() { |
| + if (IsReceiverGone() && connections_.empty()) |
| + manager_->RemovePresentation(presentation_id_); |
| + // |this| will be deleted beyond this point. |
| +} |
| + |
| +} // namespace media_router |