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 |