Chromium Code Reviews| 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 d32be6e12d075994bf16c4fcc3e6b6e41704e9c8..d221c6ae1b7b78f0714fa6405169daf9b763bba9 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; |
| @@ -70,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. |
| @@ -81,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( |
| @@ -89,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) { |
| @@ -105,30 +113,60 @@ class PresentationFrame { |
| private: |
| MediaSource GetMediaSourceFromListener( |
| content::PresentationScreenAvailabilityListener* listener) const; |
| + // Gets the OffscreenPresentationSession associated with |presentation_id| |
|
miu
2015/10/07 21:51:46
nit: add a line of whitespace above this line
imcheng
2015/10/10 04:39:43
Done.
|
| + // within this frame. Returns nullptr if |presentation_id| is not |
| + // registered as an offscreen presentation. |
| + OffscreenPresentationSession* FindOffscreenSession( |
| + const std::string& presentation_id) const; |
| + |
| base::SmallMap<std::map<std::string, MediaRoute::Id>> |
| presentation_id_to_route_id_; |
| 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. They (and the BrowserContext) are |
| + // guaranteed to outlive this object. |
| + 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( |
| + web_contents_->GetBrowserContext())), |
| delegate_observer_(nullptr) { |
| DCHECK(web_contents_); |
| DCHECK(router_); |
| + DCHECK(offscreen_presentation_manager_); |
| } |
| PresentationFrame::~PresentationFrame() { |
| @@ -142,10 +180,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_->ConnectToOffscreenPresentation( |
| + 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."; |
|
miu
2015/10/07 21:51:46
nit: DLOG(ERROR) since this message does not help
imcheng
2015/10/10 04:39:43
Done.
|
| + } else { |
| + offscreen_presentation_sessions_.insert(presentation_id, |
| + offscreen_session.Pass()); |
| + } |
| + } |
| } |
| void PresentationFrame::OnPresentationSessionClosed( |
| @@ -163,13 +221,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,10 +259,45 @@ void PresentationFrame::Reset() { |
| presentation_id_to_route_id_.clear(); |
| sinks_observer_.reset(); |
| + offscreen_presentation_sessions_.clear(); |
| session_state_observers_.clear(); |
| session_messages_observers_.clear(); |
| } |
| +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); |
| @@ -221,16 +307,23 @@ bool 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)) { |
|
miu
2015/10/07 21:51:46
OOC, why can there only be one observer? Should |
imcheng
2015/10/10 04:39:43
The only caller is the renderer where Presentation
|
| + 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( |
| @@ -243,8 +336,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( |
| @@ -270,6 +370,10 @@ class PresentationFrameManager { |
| bool RemoveScreenAvailabilityListener( |
| const RenderFrameHostId& render_frame_host_id, |
| content::PresentationScreenAvailabilityListener* listener); |
| + 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); |
| @@ -290,15 +394,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( |
| @@ -310,14 +412,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_); |
| } |
| @@ -331,11 +433,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( |
| @@ -354,13 +457,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) { |
| @@ -386,6 +482,24 @@ bool PresentationFrameManager::HasScreenAvailabilityListenerForTest( |
| presentation_frame->HasScreenAvailabilityListenerForTest(source_id); |
| } |
| +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) { |
| @@ -437,8 +551,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); |
| } |
| @@ -570,11 +684,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); |
| } |
| } |
| @@ -584,14 +699,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); |
| } |
| @@ -664,9 +780,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( |
| @@ -674,22 +790,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( |
| @@ -700,25 +804,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( |