Index: chrome/browser/media/router/presentation_service_delegate_impl.cc |
diff --git a/chrome/browser/media/router/presentation_service_delegate_impl.cc b/chrome/browser/media/router/presentation_service_delegate_impl.cc |
index 5c1d26befe11dd62c98624d5abb6c882ba3b5e0a..02d48688e83fedf0d85d0ff4c18d20c1d6188138 100644 |
--- a/chrome/browser/media/router/presentation_service_delegate_impl.cc |
+++ b/chrome/browser/media/router/presentation_service_delegate_impl.cc |
@@ -9,7 +9,6 @@ |
#include "base/containers/scoped_ptr_hash_map.h" |
#include "base/containers/scoped_ptr_map.h" |
#include "base/containers/small_map.h" |
-#include "base/guid.h" |
#include "base/strings/string_util.h" |
#include "base/strings/stringprintf.h" |
#include "chrome/browser/media/router/create_presentation_session_request.h" |
@@ -19,6 +18,8 @@ |
#include "chrome/browser/media/router/media_router_factory.h" |
#include "chrome/browser/media/router/media_sink.h" |
#include "chrome/browser/media/router/media_source_helper.h" |
+#include "chrome/browser/media/router/offscreen_presentation_manager.h" |
+#include "chrome/browser/media/router/offscreen_presentation_manager_factory.h" |
#include "chrome/browser/media/router/presentation_media_sinks_observer.h" |
#include "chrome/browser/media/router/presentation_session_messages_observer.h" |
#include "chrome/browser/media/router/presentation_session_state_observer.h" |
@@ -36,6 +37,9 @@ using content::RenderFrameHost; |
namespace media_router { |
+using OffscreenPresentationSession = |
+ OffscreenPresentationManager::OffscreenPresentationSession; |
+ |
namespace { |
using DelegateObserver = content::PresentationServiceDelegate::Observer; |
@@ -44,8 +48,6 @@ using PresentationSessionErrorCallback = |
using PresentationSessionSuccessCallback = |
content::PresentationServiceDelegate::PresentationSessionSuccessCallback; |
-using RenderFrameHostId = std::pair<int, int>; |
- |
// Returns the unique identifier for the supplied RenderFrameHost. |
RenderFrameHostId GetRenderFrameHostId(RenderFrameHost* render_frame_host) { |
int render_process_id = render_frame_host->GetProcess()->GetID(); |
@@ -72,7 +74,9 @@ GURL GetLastCommittedURLForFrame(RenderFrameHostId render_frame_host_id) { |
// * PresentationFrameManager.RemoveDelegateObserver. |
class PresentationFrame { |
public: |
- PresentationFrame(content::WebContents* web_contents, MediaRouter* router); |
+ PresentationFrame(content::WebContents* web_contents, |
+ const RenderFrameHostId& render_frame_host_id, |
+ MediaRouter* router); |
~PresentationFrame(); |
// Mirror corresponding APIs in PresentationServiceDelegateImpl. |
@@ -83,6 +87,9 @@ class PresentationFrame { |
bool HasScreenAvailabilityListenerForTest( |
const MediaSource::Id& source_id) const; |
std::string GetDefaultPresentationId() const; |
+ void SendMessage(const content::PresentationSessionInfo& session, |
+ scoped_ptr<content::PresentationSessionMessage> message, |
+ const content::SendMessageCallback send_message_cb); |
bool ListenForSessionStateChange( |
content::PresentationSessionStateListener* listener); |
void ListenForSessionMessages( |
@@ -91,13 +98,12 @@ class PresentationFrame { |
void Reset(); |
const MediaRoute::Id GetRouteId(const std::string& presentation_id) const; |
- const std::vector<MediaRoute::Id> GetRouteIds() const; |
void OnPresentationSessionClosed(const std::string& presentation_id); |
void OnPresentationSessionStarted( |
bool is_default_presentation, |
const content::PresentationSessionInfo& session, |
- const MediaRoute::Id& route_id); |
+ const MediaRoute& route); |
void OnPresentationServiceDelegateDestroyed() const; |
void set_delegate_observer(DelegateObserver* observer) { |
@@ -111,31 +117,57 @@ class PresentationFrame { |
private: |
MediaSource GetMediaSourceFromListener( |
content::PresentationScreenAvailabilityListener* listener) const; |
+ OffscreenPresentationSession* FindOffscreenSession( |
mark a. foltz
2015/10/01 06:25:28
Can you document this method? Which session is re
imcheng
2015/10/06 00:59:14
Done.
|
+ const std::string& presentation_id) const; |
+ |
base::SmallMap<std::map<std::string, MediaRoute::Id>> |
presentation_id_to_route_id_; |
std::string default_presentation_url_; |
scoped_ptr<PresentationMediaSinksObserver> sinks_observer_; |
+ // Controller objects for offscreen presentations. Note that offscreen |
+ // presentations are manipulated with these objects instead of the observers |
+ // and MediaRouter objects below. |
+ // Maps from presentation ID to the corresponding OffscreenController within |
+ // this frame. |
+ base::ScopedPtrMap<std::string, scoped_ptr<OffscreenPresentationSession>> |
+ offscreen_presentation_sessions_; |
+ |
+ // For non-offscreen presentations. |
// Maps from presentation ID to the corresponding presentation session's |
// state change observer within this frame. |
base::ScopedPtrMap<std::string, scoped_ptr<PresentationSessionStateObserver>> |
session_state_observers_; |
ScopedVector<PresentationSessionMessagesObserver> session_messages_observers_; |
- // References to the owning WebContents, and the corresponding MediaRouter. |
- const content::WebContents* web_contents_; |
- MediaRouter* router_; |
+ // References to the owning WebContents. |
+ const content::WebContents* const web_contents_; |
+ |
+ // ID of owning RenderFrameHost. |
+ const RenderFrameHostId render_frame_host_id_; |
+ |
+ // References to MediaRouter / OffscreenPresentationManager owned by |
+ // the associated BrowserContext. |
mark a. foltz
2015/10/01 06:25:28
I'm assuming that the BC outlives this object; can
imcheng
2015/10/06 00:59:14
Done.
|
+ MediaRouter* const router_; |
+ OffscreenPresentationManager* const offscreen_presentation_manager_; |
DelegateObserver* delegate_observer_; |
}; |
-PresentationFrame::PresentationFrame(content::WebContents* web_contents, |
- MediaRouter* router) |
+PresentationFrame::PresentationFrame( |
+ content::WebContents* web_contents, |
+ const RenderFrameHostId& render_frame_host_id, |
+ MediaRouter* router) |
: web_contents_(web_contents), |
+ render_frame_host_id_(render_frame_host_id), |
router_(router), |
+ offscreen_presentation_manager_( |
+ OffscreenPresentationManagerFactory::GetOrCreateForBrowserContext( |
mark a. foltz
2015/10/01 06:25:28
Do we need to look this up for every presentation
imcheng
2015/10/06 00:59:15
We don't need to look it up for every frame. Howev
|
+ web_contents_->GetBrowserContext())), |
delegate_observer_(nullptr) { |
DCHECK(web_contents_); |
DCHECK(router_); |
+ DCHECK(offscreen_presentation_manager_); |
} |
PresentationFrame::~PresentationFrame() { |
@@ -149,10 +181,30 @@ void PresentationFrame::OnPresentationServiceDelegateDestroyed() const { |
void PresentationFrame::OnPresentationSessionStarted( |
bool is_default_presentation, |
const content::PresentationSessionInfo& session, |
- const MediaRoute::Id& route_id) { |
- presentation_id_to_route_id_[session.presentation_id] = route_id; |
+ const MediaRoute& route) { |
+ const std::string& presentation_id = session.presentation_id; |
+ presentation_id_to_route_id_[presentation_id] = route.media_route_id(); |
if (is_default_presentation && delegate_observer_) |
delegate_observer_->OnDefaultPresentationStarted(session); |
+ if (route.is_offscreen_presentation()) { |
+ DCHECK(!ContainsKey(offscreen_presentation_sessions_, presentation_id)); |
+ scoped_ptr<OffscreenPresentationSession> offscreen_session = |
+ offscreen_presentation_manager_->CreateOffscreenPresentationConnection( |
+ presentation_id, render_frame_host_id_); |
+ |
+ // If |offscreen_session| is nullptr, then the receiver is most likely |
+ // already gone, so the route will die soon. This should happen very rarely |
+ // since the receiver has to unregister itself between when offscreen |
+ // presentation was created and when the resulting route arrived at MR. |
+ if (!offscreen_session) { |
+ // TODO(imcheng): we should probably reject the route request in this |
+ // case. crbug.com/513859 |
+ LOG(ERROR) << "CreateOffscreenPresentationConnection returned nullptr."; |
+ } else { |
+ offscreen_presentation_sessions_.insert(presentation_id, |
+ offscreen_session.Pass()); |
+ } |
+ } |
} |
void PresentationFrame::OnPresentationSessionClosed( |
@@ -170,13 +222,6 @@ const MediaRoute::Id PresentationFrame::GetRouteId( |
return it != presentation_id_to_route_id_.end() ? it->second : ""; |
} |
-const std::vector<MediaRoute::Id> PresentationFrame::GetRouteIds() const { |
- std::vector<MediaRoute::Id> route_ids; |
- for (const auto& e : presentation_id_to_route_id_) |
- route_ids.push_back(e.second); |
- return route_ids; |
-} |
- |
bool PresentationFrame::SetScreenAvailabilityListener( |
content::PresentationScreenAvailabilityListener* listener) { |
if (sinks_observer_ && sinks_observer_->listener() == listener) { |
@@ -208,12 +253,48 @@ void PresentationFrame::Reset() { |
presentation_id_to_route_id_.clear(); |
sinks_observer_.reset(); |
+ offscreen_presentation_sessions_.clear(); |
+ session_state_observers_.clear(); |
default_presentation_url_.clear(); |
session_state_observers_.clear(); |
session_messages_observers_.clear(); |
} |
-void PresentationFrame::ListenForSessionStateChange( |
+void PresentationFrame::SendMessage( |
+ const content::PresentationSessionInfo& session, |
+ scoped_ptr<content::PresentationSessionMessage> message, |
+ const content::SendMessageCallback send_message_cb) { |
+ auto it = presentation_id_to_route_id_.find(session.presentation_id); |
+ if (it == presentation_id_to_route_id_.end()) { |
+ DVLOG(2) << "ListenForSessionMessages: no route for " |
+ << session.presentation_id; |
+ return; |
+ } |
+ |
+ OffscreenPresentationSession* offscreen_session = |
+ FindOffscreenSession(session.presentation_id); |
+ if (offscreen_session) { |
+ offscreen_session->SendMessage(message.Pass(), send_message_cb); |
+ } else { |
+ if (message->is_binary()) { |
+ router_->SendRouteBinaryMessage(it->second, message->data.Pass(), |
+ send_message_cb); |
+ } else { |
+ router_->SendRouteMessage(it->second, message->message, send_message_cb); |
+ } |
+ } |
+} |
+ |
+OffscreenPresentationSession* PresentationFrame::FindOffscreenSession( |
+ const std::string& presentation_id) const { |
+ auto offscreen_session_it = |
+ offscreen_presentation_sessions_.find(presentation_id); |
+ return offscreen_session_it != offscreen_presentation_sessions_.end() |
+ ? offscreen_session_it->second |
+ : nullptr; |
+} |
+ |
+bool PresentationFrame::ListenForSessionStateChange( |
content::PresentationSessionStateListener* listener) { |
std::string presentation_id(listener->GetSessionInfo().presentation_id); |
auto it = presentation_id_to_route_id_.find(presentation_id); |
@@ -222,16 +303,23 @@ void PresentationFrame::ListenForSessionStateChange( |
return false; |
} |
- if (ContainsKey(session_state_observers_, presentation_id)) { |
- DVLOG(2) << "ListenForSessionStateChange: already contains a state " |
- << "observer for session " << presentation_id; |
- return false; |
+ OffscreenPresentationSession* offscreen_session = |
+ FindOffscreenSession(presentation_id); |
+ if (offscreen_session) { |
+ offscreen_session->ListenForStateChanges(listener); |
+ return true; |
+ } else { |
+ if (ContainsKey(session_state_observers_, presentation_id)) { |
+ DVLOG(2) << "ListenForSessionStateChange: already contains a state " |
+ << "observer for session " << presentation_id; |
+ return false; |
+ } |
+ |
+ session_state_observers_.insert( |
+ presentation_id, make_scoped_ptr(new PresentationSessionStateObserver( |
+ listener, it->second, router_))); |
+ return true; |
} |
- |
- session_state_observers_.insert( |
- presentation_id, make_scoped_ptr(new PresentationSessionStateObserver( |
- listener, it->second, router_))); |
- return true; |
} |
void PresentationFrame::ListenForSessionMessages( |
@@ -244,8 +332,15 @@ void PresentationFrame::ListenForSessionMessages( |
return; |
} |
- session_messages_observers_.push_back( |
- new PresentationSessionMessagesObserver(message_cb, it->second, router_)); |
+ OffscreenPresentationSession* offscreen_session = |
+ FindOffscreenSession(session.presentation_id); |
+ if (offscreen_session) { |
+ offscreen_session->ListenForMessages(message_cb); |
+ } else { |
+ session_messages_observers_.push_back( |
+ new PresentationSessionMessagesObserver(message_cb, it->second, |
+ router_)); |
+ } |
} |
MediaSource PresentationFrame::GetMediaSourceFromListener( |
@@ -272,7 +367,11 @@ class PresentationFrameManager { |
const RenderFrameHostId& render_frame_host_id, |
content::PresentationScreenAvailabilityListener* listener); |
void SetDefaultPresentationUrl(const RenderFrameHostId& render_frame_host_id, |
- const std::string& default_presentation_url); |
+ const std::string& default_presentation_url); |
+ void SendMessage(const RenderFrameHostId& render_frame_host_id, |
+ const content::PresentationSessionInfo& session, |
+ scoped_ptr<content::PresentationSessionMessage> message, |
+ const content::SendMessageCallback send_message_cb); |
bool ListenForSessionStateChange( |
const RenderFrameHostId& render_frame_host_id, |
content::PresentationSessionStateListener* listener); |
@@ -293,15 +392,13 @@ class PresentationFrameManager { |
const RenderFrameHostId& render_frame_host_id, |
bool is_default_presentation, |
const content::PresentationSessionInfo& session, |
- const MediaRoute::Id& route_id); |
+ const MediaRoute& route); |
void OnPresentationSessionClosed( |
const RenderFrameHostId& render_frame_host_id, |
const std::string& presentation_id); |
const MediaRoute::Id GetRouteId(const RenderFrameHostId& render_frame_host_id, |
const std::string& presentation_id) const; |
- const std::vector<MediaRoute::Id> GetRouteIds( |
- const RenderFrameHostId& render_frame_host_id) const; |
private: |
PresentationFrame* GetOrAddPresentationFrame( |
@@ -313,14 +410,14 @@ class PresentationFrameManager { |
presentation_frames_; |
// References to the owning WebContents, and the corresponding MediaRouter. |
+ content::WebContents* const web_contents_; |
MediaRouter* router_; |
- content::WebContents* web_contents_; |
}; |
PresentationFrameManager::PresentationFrameManager( |
content::WebContents* web_contents, |
MediaRouter* router) |
- : router_(router), web_contents_(web_contents) { |
+ : web_contents_(web_contents), router_(router) { |
DCHECK(web_contents_); |
DCHECK(router_); |
} |
@@ -334,11 +431,12 @@ void PresentationFrameManager::OnPresentationSessionStarted( |
const RenderFrameHostId& render_frame_host_id, |
bool is_default_presentation, |
const content::PresentationSessionInfo& session, |
- const MediaRoute::Id& route_id) { |
+ const MediaRoute& route) { |
auto presentation_frame = presentation_frames_.get(render_frame_host_id); |
- if (presentation_frame) |
+ if (presentation_frame) { |
presentation_frame->OnPresentationSessionStarted(is_default_presentation, |
- session, route_id); |
+ session, route); |
+ } |
} |
void PresentationFrameManager::OnPresentationSessionClosed( |
@@ -357,13 +455,6 @@ const MediaRoute::Id PresentationFrameManager::GetRouteId( |
: ""; |
} |
-const std::vector<MediaRoute::Id> PresentationFrameManager::GetRouteIds( |
- const RenderFrameHostId& render_frame_host_id) const { |
- auto presentation_frame = presentation_frames_.get(render_frame_host_id); |
- return presentation_frame ? presentation_frame->GetRouteIds() |
- : std::vector<MediaRoute::Id>(); |
-} |
- |
bool PresentationFrameManager::SetScreenAvailabilityListener( |
const RenderFrameHostId& render_frame_host_id, |
content::PresentationScreenAvailabilityListener* listener) { |
@@ -396,7 +487,25 @@ void PresentationFrameManager::SetDefaultPresentationUrl( |
presentation_frame->set_default_presentation_url(default_presentation_url); |
} |
-void PresentationFrameManager::ListenForSessionStateChange( |
+void PresentationFrameManager::SendMessage( |
+ const RenderFrameHostId& render_frame_host_id, |
+ const content::PresentationSessionInfo& session, |
+ scoped_ptr<content::PresentationSessionMessage> message, |
+ const content::SendMessageCallback send_message_cb) { |
+ PresentationFrame* presentation_frame = |
+ presentation_frames_.get(render_frame_host_id); |
+ if (!presentation_frame) { |
+ DVLOG(2) << "SendMessage: PresentationFrame does not exist " |
+ << "for: (" << render_frame_host_id.first << ", " |
+ << render_frame_host_id.second << ")"; |
+ send_message_cb.Run(false); |
+ return; |
+ } |
+ |
+ presentation_frame->SendMessage(session, message.Pass(), send_message_cb); |
+} |
+ |
+bool PresentationFrameManager::ListenForSessionStateChange( |
const RenderFrameHostId& render_frame_host_id, |
content::PresentationSessionStateListener* listener) { |
PresentationFrame* presentation_frame = |
@@ -447,8 +556,8 @@ PresentationFrame* PresentationFrameManager::GetOrAddPresentationFrame( |
if (!presentation_frames_.contains(render_frame_host_id)) { |
presentation_frames_.add( |
render_frame_host_id, |
- scoped_ptr<PresentationFrame>( |
- new PresentationFrame(web_contents_, router_))); |
+ scoped_ptr<PresentationFrame>(new PresentationFrame( |
+ web_contents_, render_frame_host_id, router_))); |
} |
return presentation_frames_.get(render_frame_host_id); |
} |
@@ -578,11 +687,12 @@ void PresentationServiceDelegateImpl::OnJoinRouteResponse( |
DVLOG(1) << "OnJoinRouteResponse: " |
<< "route_id: " << route->media_route_id() |
<< ", presentation URL: " << session.presentation_url |
- << ", presentation ID: " << session.presentation_id; |
+ << ", presentation ID: " << session.presentation_id |
+ << ", offscreen? " << route->is_offscreen_presentation(); |
DCHECK_EQ(session.presentation_id, presentation_id); |
- frame_manager_->OnPresentationSessionStarted( |
- RenderFrameHostId(render_process_id, render_frame_id), false, session, |
- route->media_route_id()); |
+ RenderFrameHostId rfh_id(render_process_id, render_frame_id); |
+ frame_manager_->OnPresentationSessionStarted(rfh_id, false, session, |
+ *route); |
success_cb.Run(session); |
} |
} |
@@ -592,14 +702,15 @@ void PresentationServiceDelegateImpl::OnStartSessionSucceeded( |
int render_frame_id, |
const PresentationSessionSuccessCallback& success_cb, |
const content::PresentationSessionInfo& new_session, |
- const MediaRoute::Id& route_id) { |
+ const MediaRoute& route) { |
+ const MediaRoute::Id& route_id = route.media_route_id(); |
DVLOG(1) << "OnStartSessionSucceeded: " |
<< "route_id: " << route_id |
<< ", presentation URL: " << new_session.presentation_url |
<< ", presentation ID: " << new_session.presentation_id; |
- frame_manager_->OnPresentationSessionStarted( |
- RenderFrameHostId(render_process_id, render_frame_id), false, new_session, |
- route_id); |
+ RenderFrameHostId rfh_id(render_process_id, render_frame_id); |
+ frame_manager_->OnPresentationSessionStarted(rfh_id, false, new_session, |
+ route); |
success_cb.Run(new_session); |
} |
@@ -672,9 +783,9 @@ void PresentationServiceDelegateImpl::ListenForSessionMessages( |
int render_frame_id, |
const content::PresentationSessionInfo& session, |
const content::PresentationSessionMessageCallback& message_cb) { |
- frame_manager_->ListenForSessionMessages( |
- RenderFrameHostId(render_process_id, render_frame_id), session, |
- message_cb); |
+ RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id); |
+ frame_manager_->ListenForSessionMessages(render_frame_host_id, session, |
+ message_cb); |
} |
void PresentationServiceDelegateImpl::SendMessage( |
@@ -682,22 +793,10 @@ void PresentationServiceDelegateImpl::SendMessage( |
int render_frame_id, |
const content::PresentationSessionInfo& session, |
scoped_ptr<content::PresentationSessionMessage> message, |
- const SendMessageCallback& send_message_cb) { |
- const MediaRoute::Id& route_id = frame_manager_->GetRouteId( |
- RenderFrameHostId(render_process_id, render_frame_id), |
- session.presentation_id); |
- if (route_id.empty()) { |
- DVLOG(1) << "No active route for " << session.presentation_id; |
- send_message_cb.Run(false); |
- return; |
- } |
- |
- if (message->is_binary()) { |
- router_->SendRouteBinaryMessage(route_id, message->data.Pass(), |
- send_message_cb); |
- } else { |
- router_->SendRouteMessage(route_id, message->message, send_message_cb); |
- } |
+ const content::SendMessageCallback& send_message_cb) { |
+ RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id); |
+ frame_manager_->SendMessage(render_frame_host_id, session, message.Pass(), |
+ send_message_cb); |
} |
bool PresentationServiceDelegateImpl::ListenForSessionStateChange( |
@@ -708,25 +807,48 @@ bool PresentationServiceDelegateImpl::ListenForSessionStateChange( |
RenderFrameHostId(render_process_id, render_frame_id), listener); |
} |
+void PresentationServiceDelegateImpl::GetPresentationReceiverSession( |
+ int render_process_id, |
+ int render_frame_id, |
+ const content::PresentationReceiverSessionAvailableCallback& callback) { |
+ // We only support receiver APIs in offscreen tabs created for offscreen |
+ // presentations. |
+ // See ReceiverPresentationServiceDelegateImpl for details. |
+ NOTIMPLEMENTED(); |
+ callback.Run(nullptr); |
+} |
+ |
+std::vector<content::PresentationSessionInfo> |
+PresentationServiceDelegateImpl::GetPresentationReceiverSessions( |
+ int render_process_id, |
+ int render_frame_id) { |
+ // See comment in |GetPresentationReceiverSession()|. |
+ NOTIMPLEMENTED(); |
+ return std::vector<content::PresentationSessionInfo>(); |
+} |
+ |
void PresentationServiceDelegateImpl::OnRouteResponse( |
const MediaRoute* route, |
const std::string& presentation_id, |
const std::string& error) { |
if (!route) |
return; |
+ |
const MediaSource& source = route->media_source(); |
DCHECK(!source.Empty()); |
if (!default_source_.Equals(source)) |
return; |
+ |
RenderFrameHost* main_frame = web_contents_->GetMainFrame(); |
if (!main_frame) |
return; |
+ |
RenderFrameHostId render_frame_host_id(GetRenderFrameHostId(main_frame)); |
- frame_manager_->OnPresentationSessionStarted( |
- render_frame_host_id, true, |
- content::PresentationSessionInfo(PresentationUrlFromMediaSource(source), |
- presentation_id), |
- route->media_route_id()); |
+ content::PresentationSessionInfo session( |
+ PresentationUrlFromMediaSource(source), presentation_id); |
+ |
+ frame_manager_->OnPresentationSessionStarted(render_frame_host_id, true, |
+ session, *route); |
} |
void PresentationServiceDelegateImpl::AddDefaultMediaSourceObserver( |