| // 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/presentation_service_delegate_impl.h" |
| |
| #include <string> |
| #include <utility> |
| |
| #include "base/containers/scoped_ptr_hash_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_connection_request.h" |
| #include "chrome/browser/media/router/media_route.h" |
| #include "chrome/browser/media/router/media_router.h" |
| #include "chrome/browser/media/router/media_router_dialog_controller.h" |
| #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/presentation_media_sinks_observer.h" |
| #include "chrome/browser/media/router/presentation_session_messages_observer.h" |
| #include "chrome/browser/sessions/session_tab_helper.h" |
| #include "content/public/browser/presentation_screen_availability_listener.h" |
| #include "content/public/browser/presentation_session.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/render_process_host.h" |
| |
| DEFINE_WEB_CONTENTS_USER_DATA_KEY( |
| media_router::PresentationServiceDelegateImpl); |
| |
| using content::RenderFrameHost; |
| |
| namespace media_router { |
| |
| namespace { |
| |
| using DelegateObserver = content::PresentationServiceDelegate::Observer; |
| |
| // Returns the unique identifier for the supplied RenderFrameHost. |
| RenderFrameHostId GetRenderFrameHostId(RenderFrameHost* render_frame_host) { |
| int render_process_id = render_frame_host->GetProcess()->GetID(); |
| int render_frame_id = render_frame_host->GetRoutingID(); |
| return RenderFrameHostId(render_process_id, render_frame_id); |
| } |
| |
| // Gets the last committed URL for the render frame specified by |
| // |render_frame_host_id|. |
| GURL GetLastCommittedURLForFrame(RenderFrameHostId render_frame_host_id) { |
| RenderFrameHost* render_frame_host = RenderFrameHost::FromID( |
| render_frame_host_id.first, render_frame_host_id.second); |
| DCHECK(render_frame_host); |
| return render_frame_host->GetLastCommittedURL(); |
| } |
| |
| } // namespace |
| |
| // Used by PresentationServiceDelegateImpl to manage |
| // listeners and default presentation info in a render frame. |
| // Its lifetime: |
| // * PresentationFrameManager AddDelegateObserver |
| // * Reset 0+ times. |
| // * PresentationFrameManager.RemoveDelegateObserver. |
| class PresentationFrame { |
| public: |
| PresentationFrame(content::WebContents* web_contents, MediaRouter* router); |
| ~PresentationFrame(); |
| |
| // Mirror corresponding APIs in PresentationServiceDelegateImpl. |
| bool SetScreenAvailabilityListener( |
| content::PresentationScreenAvailabilityListener* listener); |
| bool RemoveScreenAvailabilityListener( |
| content::PresentationScreenAvailabilityListener* listener); |
| bool HasScreenAvailabilityListenerForTest( |
| const MediaSource::Id& source_id) const; |
| std::string GetDefaultPresentationId() const; |
| void ListenForConnectionStateChange( |
| const content::PresentationSessionInfo& connection, |
| const content::PresentationConnectionStateChangedCallback& |
| state_changed_cb); |
| void ListenForSessionMessages( |
| const content::PresentationSessionInfo& session, |
| const content::PresentationSessionMessageCallback& message_cb); |
| |
| void Reset(); |
| void RemoveConnection(const std::string& presentation_id, |
| const MediaRoute::Id& route_id); |
| |
| const MediaRoute::Id GetRouteId(const std::string& presentation_id) const; |
| const std::vector<MediaRoute::Id> GetRouteIds() const; |
| |
| void OnPresentationSessionStarted( |
| const content::PresentationSessionInfo& session, |
| const MediaRoute::Id& route_id); |
| void OnPresentationServiceDelegateDestroyed() const; |
| |
| void set_delegate_observer(DelegateObserver* observer) { |
| delegate_observer_ = observer; |
| } |
| |
| private: |
| MediaSource GetMediaSourceFromListener( |
| content::PresentationScreenAvailabilityListener* listener) const; |
| base::SmallMap<std::map<std::string, MediaRoute::Id>> |
| presentation_id_to_route_id_; |
| scoped_ptr<PresentationMediaSinksObserver> sinks_observer_; |
| base::ScopedPtrHashMap<MediaRoute::Id, |
| scoped_ptr<PresentationConnectionStateSubscription>> |
| connection_state_subscriptions_; |
| ScopedVector<PresentationSessionMessagesObserver> session_messages_observers_; |
| |
| // References to the owning WebContents, and the corresponding MediaRouter. |
| const content::WebContents* web_contents_; |
| MediaRouter* router_; |
| |
| DelegateObserver* delegate_observer_; |
| }; |
| |
| PresentationFrame::PresentationFrame(content::WebContents* web_contents, |
| MediaRouter* router) |
| : web_contents_(web_contents), |
| router_(router), |
| delegate_observer_(nullptr) { |
| DCHECK(web_contents_); |
| DCHECK(router_); |
| } |
| |
| PresentationFrame::~PresentationFrame() { |
| } |
| |
| void PresentationFrame::OnPresentationServiceDelegateDestroyed() const { |
| if (delegate_observer_) |
| delegate_observer_->OnDelegateDestroyed(); |
| } |
| |
| void PresentationFrame::OnPresentationSessionStarted( |
| const content::PresentationSessionInfo& session, |
| const MediaRoute::Id& route_id) { |
| presentation_id_to_route_id_[session.presentation_id] = route_id; |
| } |
| |
| const MediaRoute::Id PresentationFrame::GetRouteId( |
| const std::string& presentation_id) const { |
| auto it = presentation_id_to_route_id_.find(presentation_id); |
| 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) |
| return false; |
| |
| MediaSource source(GetMediaSourceFromListener(listener)); |
| sinks_observer_.reset( |
| new PresentationMediaSinksObserver(router_, listener, source)); |
| |
| if (!sinks_observer_->Init()) { |
| sinks_observer_.reset(); |
| listener->OnScreenAvailabilityNotSupported(); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool PresentationFrame::RemoveScreenAvailabilityListener( |
| content::PresentationScreenAvailabilityListener* listener) { |
| if (sinks_observer_ && sinks_observer_->listener() == listener) { |
| sinks_observer_.reset(); |
| return true; |
| } |
| return false; |
| } |
| |
| bool PresentationFrame::HasScreenAvailabilityListenerForTest( |
| const MediaSource::Id& source_id) const { |
| return sinks_observer_ && sinks_observer_->source().id() == source_id; |
| } |
| |
| void PresentationFrame::Reset() { |
| for (const auto& pid_route_id : presentation_id_to_route_id_) |
| router_->DetachRoute(pid_route_id.second); |
| |
| presentation_id_to_route_id_.clear(); |
| sinks_observer_.reset(); |
| connection_state_subscriptions_.clear(); |
| session_messages_observers_.clear(); |
| } |
| |
| void PresentationFrame::RemoveConnection(const std::string& presentation_id, |
| const MediaRoute::Id& route_id) { |
| // Remove the presentation id mapping so a later call to Reset is a no-op. |
| presentation_id_to_route_id_.erase(presentation_id); |
| |
| // We no longer need to observe route messages. |
| auto observer_iter = std::find_if( |
| session_messages_observers_.begin(), session_messages_observers_.end(), |
| [&route_id](const PresentationSessionMessagesObserver* observer) { |
| return route_id == observer->route_id(); |
| }); |
| if (observer_iter != session_messages_observers_.end()) |
| session_messages_observers_.erase(observer_iter); |
| |
| // We keep the PresentationConnectionStateChangedCallback registered with MR |
| // so the MRP can tell us when terminate() completed. |
| } |
| |
| void PresentationFrame::ListenForConnectionStateChange( |
| const content::PresentationSessionInfo& connection, |
| const content::PresentationConnectionStateChangedCallback& |
| state_changed_cb) { |
| auto it = presentation_id_to_route_id_.find(connection.presentation_id); |
| if (it == presentation_id_to_route_id_.end()) { |
| DLOG(ERROR) << __FUNCTION__ << "route id not found for presentation: " |
| << connection.presentation_id; |
| return; |
| } |
| |
| const MediaRoute::Id& route_id = it->second; |
| if (connection_state_subscriptions_.contains(route_id)) { |
| DLOG(ERROR) << __FUNCTION__ << "Already listening connection state change " |
| "for route: " |
| << route_id; |
| return; |
| } |
| |
| connection_state_subscriptions_.add( |
| route_id, router_->AddPresentationConnectionStateChangedCallback( |
| it->second, state_changed_cb)); |
| } |
| |
| void PresentationFrame::ListenForSessionMessages( |
| const content::PresentationSessionInfo& session, |
| const content::PresentationSessionMessageCallback& 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; |
| } |
| |
| session_messages_observers_.push_back( |
| new PresentationSessionMessagesObserver(message_cb, it->second, router_)); |
| } |
| |
| MediaSource PresentationFrame::GetMediaSourceFromListener( |
| content::PresentationScreenAvailabilityListener* listener) const { |
| // If the default presentation URL is empty then fall back to tab mirroring. |
| std::string availability_url(listener->GetAvailabilityUrl()); |
| return availability_url.empty() |
| ? MediaSourceForTab(SessionTabHelper::IdForTab(web_contents_)) |
| : MediaSourceForPresentationUrl(availability_url); |
| } |
| |
| // Used by PresentationServiceDelegateImpl to manage PresentationFrames. |
| class PresentationFrameManager { |
| public: |
| PresentationFrameManager(content::WebContents* web_contents, |
| MediaRouter* router); |
| ~PresentationFrameManager(); |
| |
| // Mirror corresponding APIs in PresentationServiceDelegateImpl. |
| bool SetScreenAvailabilityListener( |
| const RenderFrameHostId& render_frame_host_id, |
| content::PresentationScreenAvailabilityListener* listener); |
| bool RemoveScreenAvailabilityListener( |
| const RenderFrameHostId& render_frame_host_id, |
| content::PresentationScreenAvailabilityListener* listener); |
| void ListenForConnectionStateChange( |
| const RenderFrameHostId& render_frame_host_id, |
| const content::PresentationSessionInfo& connection, |
| const content::PresentationConnectionStateChangedCallback& |
| state_changed_cb); |
| void ListenForSessionMessages( |
| const RenderFrameHostId& render_frame_host_id, |
| const content::PresentationSessionInfo& session, |
| const content::PresentationSessionMessageCallback& message_cb); |
| |
| // Sets or clears the default presentation request and callback for the given |
| // frame. Also sets / clears the default presentation requests for the owning |
| // tab WebContents. |
| void SetDefaultPresentationUrl( |
| const RenderFrameHostId& render_frame_host_id, |
| const std::string& default_presentation_url, |
| const content::PresentationSessionStartedCallback& callback); |
| void AddDelegateObserver(const RenderFrameHostId& render_frame_host_id, |
| DelegateObserver* observer); |
| void RemoveDelegateObserver(const RenderFrameHostId& render_frame_host_id); |
| void AddDefaultPresentationRequestObserver( |
| PresentationServiceDelegateImpl::DefaultPresentationRequestObserver* |
| observer); |
| void RemoveDefaultPresentationRequestObserver( |
| PresentationServiceDelegateImpl::DefaultPresentationRequestObserver* |
| observer); |
| void Reset(const RenderFrameHostId& render_frame_host_id); |
| void RemoveConnection(const RenderFrameHostId& render_frame_host_id, |
| const MediaRoute::Id& route_id, |
| const std::string& presentation_id); |
| bool HasScreenAvailabilityListenerForTest( |
| const RenderFrameHostId& render_frame_host_id, |
| const MediaSource::Id& source_id) const; |
| void SetMediaRouterForTest(MediaRouter* router); |
| |
| void OnPresentationSessionStarted( |
| const RenderFrameHostId& render_frame_host_id, |
| const content::PresentationSessionInfo& session, |
| const MediaRoute::Id& route_id); |
| void OnDefaultPresentationSessionStarted( |
| const PresentationRequest& request, |
| const content::PresentationSessionInfo& session, |
| const MediaRoute::Id& route_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; |
| |
| const PresentationRequest* default_presentation_request() const { |
| return default_presentation_request_.get(); |
| } |
| |
| private: |
| PresentationFrame* GetOrAddPresentationFrame( |
| const RenderFrameHostId& render_frame_host_id); |
| |
| // Sets the default presentation request for the owning WebContents and |
| // notifies observers of changes. |
| void SetDefaultPresentationRequest( |
| const PresentationRequest& default_presentation_request); |
| |
| // Clears the default presentation request for the owning WebContents and |
| // notifies observers of changes. Also resets |
| // |default_presentation_started_callback_|. |
| void ClearDefaultPresentationRequest(); |
| |
| bool IsMainFrame(const RenderFrameHostId& render_frame_host_id) const; |
| |
| // Maps a frame identifier to a PresentationFrame object for frames |
| // that are using presentation API. |
| base::ScopedPtrHashMap<RenderFrameHostId, scoped_ptr<PresentationFrame>> |
| presentation_frames_; |
| |
| // Default presentation request for the owning tab WebContents. |
| scoped_ptr<PresentationRequest> default_presentation_request_; |
| |
| // Callback to invoke when default presentation has started. |
| content::PresentationSessionStartedCallback |
| default_presentation_started_callback_; |
| |
| // References to the observers listening for changes to this tab WebContent's |
| // default presentation. |
| base::ObserverList< |
| PresentationServiceDelegateImpl::DefaultPresentationRequestObserver> |
| default_presentation_request_observers_; |
| |
| // References to the owning WebContents, and the corresponding MediaRouter. |
| MediaRouter* router_; |
| content::WebContents* web_contents_; |
| }; |
| |
| PresentationFrameManager::PresentationFrameManager( |
| content::WebContents* web_contents, |
| MediaRouter* router) |
| : router_(router), web_contents_(web_contents) { |
| DCHECK(web_contents_); |
| DCHECK(router_); |
| } |
| |
| PresentationFrameManager::~PresentationFrameManager() { |
| for (auto& frame : presentation_frames_) |
| frame.second->OnPresentationServiceDelegateDestroyed(); |
| } |
| |
| void PresentationFrameManager::OnPresentationSessionStarted( |
| const RenderFrameHostId& render_frame_host_id, |
| const content::PresentationSessionInfo& session, |
| const MediaRoute::Id& route_id) { |
| auto presentation_frame = GetOrAddPresentationFrame(render_frame_host_id); |
| presentation_frame->OnPresentationSessionStarted(session, route_id); |
| } |
| |
| void PresentationFrameManager::OnDefaultPresentationSessionStarted( |
| const PresentationRequest& request, |
| const content::PresentationSessionInfo& session, |
| const MediaRoute::Id& route_id) { |
| auto presentation_frame = |
| presentation_frames_.get(request.render_frame_host_id()); |
| if (presentation_frame) |
| presentation_frame->OnPresentationSessionStarted(session, route_id); |
| |
| if (default_presentation_request_ && |
| default_presentation_request_->Equals(request)) { |
| default_presentation_started_callback_.Run(session); |
| } |
| } |
| |
| const MediaRoute::Id PresentationFrameManager::GetRouteId( |
| const RenderFrameHostId& render_frame_host_id, |
| const std::string& presentation_id) const { |
| auto presentation_frame = presentation_frames_.get(render_frame_host_id); |
| return presentation_frame ? presentation_frame->GetRouteId(presentation_id) |
| : ""; |
| } |
| |
| 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) { |
| DCHECK(listener); |
| auto presentation_frame = GetOrAddPresentationFrame(render_frame_host_id); |
| return presentation_frame->SetScreenAvailabilityListener(listener); |
| } |
| |
| bool PresentationFrameManager::RemoveScreenAvailabilityListener( |
| const RenderFrameHostId& render_frame_host_id, |
| content::PresentationScreenAvailabilityListener* listener) { |
| DCHECK(listener); |
| auto presentation_frame = presentation_frames_.get(render_frame_host_id); |
| return presentation_frame && |
| presentation_frame->RemoveScreenAvailabilityListener(listener); |
| } |
| |
| bool PresentationFrameManager::HasScreenAvailabilityListenerForTest( |
| const RenderFrameHostId& render_frame_host_id, |
| const MediaSource::Id& source_id) const { |
| auto presentation_frame = presentation_frames_.get(render_frame_host_id); |
| return presentation_frame && |
| presentation_frame->HasScreenAvailabilityListenerForTest(source_id); |
| } |
| |
| void PresentationFrameManager::ListenForConnectionStateChange( |
| const RenderFrameHostId& render_frame_host_id, |
| const content::PresentationSessionInfo& connection, |
| const content::PresentationConnectionStateChangedCallback& |
| state_changed_cb) { |
| auto presentation_frame = presentation_frames_.get(render_frame_host_id); |
| if (presentation_frame) { |
| presentation_frame->ListenForConnectionStateChange(connection, |
| state_changed_cb); |
| } |
| } |
| |
| void PresentationFrameManager::ListenForSessionMessages( |
| const RenderFrameHostId& render_frame_host_id, |
| const content::PresentationSessionInfo& session, |
| const content::PresentationSessionMessageCallback& message_cb) { |
| PresentationFrame* presentation_frame = |
| presentation_frames_.get(render_frame_host_id); |
| if (!presentation_frame) { |
| DVLOG(2) << "ListenForSessionMessages: PresentationFrame does not exist " |
| << "for: (" << render_frame_host_id.first << ", " |
| << render_frame_host_id.second << ")"; |
| return; |
| } |
| presentation_frame->ListenForSessionMessages(session, message_cb); |
| } |
| |
| void PresentationFrameManager::SetDefaultPresentationUrl( |
| const RenderFrameHostId& render_frame_host_id, |
| const std::string& default_presentation_url, |
| const content::PresentationSessionStartedCallback& callback) { |
| if (!IsMainFrame(render_frame_host_id)) |
| return; |
| |
| if (default_presentation_url.empty()) { |
| ClearDefaultPresentationRequest(); |
| } else { |
| DCHECK(!callback.is_null()); |
| GURL frame_url(GetLastCommittedURLForFrame(render_frame_host_id)); |
| PresentationRequest request(render_frame_host_id, default_presentation_url, |
| frame_url); |
| default_presentation_started_callback_ = callback; |
| SetDefaultPresentationRequest(request); |
| } |
| } |
| |
| void PresentationFrameManager::AddDelegateObserver( |
| const RenderFrameHostId& render_frame_host_id, |
| DelegateObserver* observer) { |
| auto presentation_frame = GetOrAddPresentationFrame(render_frame_host_id); |
| presentation_frame->set_delegate_observer(observer); |
| } |
| |
| void PresentationFrameManager::RemoveDelegateObserver( |
| const RenderFrameHostId& render_frame_host_id) { |
| auto presentation_frame = presentation_frames_.get(render_frame_host_id); |
| if (presentation_frame) { |
| presentation_frame->set_delegate_observer(nullptr); |
| presentation_frames_.erase(render_frame_host_id); |
| } |
| } |
| |
| void PresentationFrameManager::AddDefaultPresentationRequestObserver( |
| PresentationServiceDelegateImpl::DefaultPresentationRequestObserver* |
| observer) { |
| default_presentation_request_observers_.AddObserver(observer); |
| } |
| |
| void PresentationFrameManager::RemoveDefaultPresentationRequestObserver( |
| PresentationServiceDelegateImpl::DefaultPresentationRequestObserver* |
| observer) { |
| default_presentation_request_observers_.RemoveObserver(observer); |
| } |
| |
| void PresentationFrameManager::Reset( |
| const RenderFrameHostId& render_frame_host_id) { |
| auto presentation_frame = presentation_frames_.get(render_frame_host_id); |
| if (presentation_frame) |
| presentation_frame->Reset(); |
| |
| if (default_presentation_request_ && |
| render_frame_host_id == |
| default_presentation_request_->render_frame_host_id()) { |
| ClearDefaultPresentationRequest(); |
| } |
| } |
| |
| void PresentationFrameManager::RemoveConnection( |
| const RenderFrameHostId& render_frame_host_id, |
| const MediaRoute::Id& route_id, |
| const std::string& presentation_id) { |
| auto presentation_frame = presentation_frames_.get(render_frame_host_id); |
| if (presentation_frame) |
| presentation_frame->RemoveConnection(route_id, presentation_id); |
| } |
| |
| PresentationFrame* PresentationFrameManager::GetOrAddPresentationFrame( |
| const RenderFrameHostId& render_frame_host_id) { |
| if (!presentation_frames_.contains(render_frame_host_id)) { |
| presentation_frames_.add( |
| render_frame_host_id, |
| scoped_ptr<PresentationFrame>( |
| new PresentationFrame(web_contents_, router_))); |
| } |
| return presentation_frames_.get(render_frame_host_id); |
| } |
| |
| void PresentationFrameManager::ClearDefaultPresentationRequest() { |
| default_presentation_started_callback_.Reset(); |
| if (!default_presentation_request_) |
| return; |
| |
| default_presentation_request_.reset(); |
| FOR_EACH_OBSERVER( |
| PresentationServiceDelegateImpl::DefaultPresentationRequestObserver, |
| default_presentation_request_observers_, OnDefaultPresentationRemoved()); |
| } |
| |
| bool PresentationFrameManager::IsMainFrame( |
| const RenderFrameHostId& render_frame_host_id) const { |
| RenderFrameHost* main_frame = web_contents_->GetMainFrame(); |
| return main_frame && GetRenderFrameHostId(main_frame) == render_frame_host_id; |
| } |
| |
| void PresentationFrameManager::SetDefaultPresentationRequest( |
| const PresentationRequest& default_presentation_request) { |
| if (default_presentation_request_ && |
| default_presentation_request_->Equals(default_presentation_request)) |
| return; |
| |
| default_presentation_request_.reset( |
| new PresentationRequest(default_presentation_request)); |
| FOR_EACH_OBSERVER( |
| PresentationServiceDelegateImpl::DefaultPresentationRequestObserver, |
| default_presentation_request_observers_, |
| OnDefaultPresentationChanged(*default_presentation_request_)); |
| } |
| |
| void PresentationFrameManager::SetMediaRouterForTest(MediaRouter* router) { |
| router_ = router; |
| } |
| |
| PresentationServiceDelegateImpl* |
| PresentationServiceDelegateImpl::GetOrCreateForWebContents( |
| content::WebContents* web_contents) { |
| DCHECK(web_contents); |
| // CreateForWebContents does nothing if the delegate instance already exists. |
| PresentationServiceDelegateImpl::CreateForWebContents(web_contents); |
| return PresentationServiceDelegateImpl::FromWebContents(web_contents); |
| } |
| |
| PresentationServiceDelegateImpl::PresentationServiceDelegateImpl( |
| content::WebContents* web_contents) |
| : web_contents_(web_contents), |
| router_(MediaRouterFactory::GetApiForBrowserContext( |
| web_contents_->GetBrowserContext())), |
| frame_manager_(new PresentationFrameManager(web_contents, router_)), |
| weak_factory_(this) { |
| DCHECK(web_contents_); |
| DCHECK(router_); |
| } |
| |
| PresentationServiceDelegateImpl::~PresentationServiceDelegateImpl() { |
| } |
| |
| void PresentationServiceDelegateImpl::AddObserver(int render_process_id, |
| int render_frame_id, |
| DelegateObserver* observer) { |
| DCHECK(observer); |
| frame_manager_->AddDelegateObserver( |
| RenderFrameHostId(render_process_id, render_frame_id), observer); |
| } |
| |
| void PresentationServiceDelegateImpl::RemoveObserver(int render_process_id, |
| int render_frame_id) { |
| frame_manager_->RemoveDelegateObserver( |
| RenderFrameHostId(render_process_id, render_frame_id)); |
| } |
| |
| bool PresentationServiceDelegateImpl::AddScreenAvailabilityListener( |
| int render_process_id, |
| int render_frame_id, |
| content::PresentationScreenAvailabilityListener* listener) { |
| DCHECK(listener); |
| return frame_manager_->SetScreenAvailabilityListener( |
| RenderFrameHostId(render_process_id, render_frame_id), listener); |
| } |
| |
| void PresentationServiceDelegateImpl::RemoveScreenAvailabilityListener( |
| int render_process_id, |
| int render_frame_id, |
| content::PresentationScreenAvailabilityListener* listener) { |
| DCHECK(listener); |
| frame_manager_->RemoveScreenAvailabilityListener( |
| RenderFrameHostId(render_process_id, render_frame_id), listener); |
| } |
| |
| void PresentationServiceDelegateImpl::Reset(int render_process_id, |
| int render_frame_id) { |
| RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id); |
| frame_manager_->Reset(render_frame_host_id); |
| } |
| |
| void PresentationServiceDelegateImpl::SetDefaultPresentationUrl( |
| int render_process_id, |
| int render_frame_id, |
| const std::string& default_presentation_url, |
| const content::PresentationSessionStartedCallback& callback) { |
| RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id); |
| frame_manager_->SetDefaultPresentationUrl(render_frame_host_id, |
| default_presentation_url, callback); |
| } |
| |
| void PresentationServiceDelegateImpl::OnJoinRouteResponse( |
| int render_process_id, |
| int render_frame_id, |
| const content::PresentationSessionInfo& session, |
| const content::PresentationSessionStartedCallback& success_cb, |
| const content::PresentationSessionErrorCallback& error_cb, |
| const MediaRoute* route, |
| const std::string& presentation_id, |
| const std::string& error_text) { |
| if (!route) { |
| error_cb.Run(content::PresentationError( |
| content::PRESENTATION_ERROR_NO_PRESENTATION_FOUND, error_text)); |
| } else { |
| DVLOG(1) << "OnJoinRouteResponse: " |
| << "route_id: " << route->media_route_id() |
| << ", presentation URL: " << session.presentation_url |
| << ", presentation ID: " << session.presentation_id; |
| DCHECK_EQ(session.presentation_id, presentation_id); |
| frame_manager_->OnPresentationSessionStarted( |
| RenderFrameHostId(render_process_id, render_frame_id), session, |
| route->media_route_id()); |
| success_cb.Run(session); |
| } |
| } |
| |
| void PresentationServiceDelegateImpl::OnStartSessionSucceeded( |
| int render_process_id, |
| int render_frame_id, |
| const content::PresentationSessionStartedCallback& success_cb, |
| const content::PresentationSessionInfo& new_session, |
| const MediaRoute::Id& 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), new_session, |
| route_id); |
| success_cb.Run(new_session); |
| } |
| |
| void PresentationServiceDelegateImpl::StartSession( |
| int render_process_id, |
| int render_frame_id, |
| const std::string& presentation_url, |
| const content::PresentationSessionStartedCallback& success_cb, |
| const content::PresentationSessionErrorCallback& error_cb) { |
| if (presentation_url.empty() || !IsValidPresentationUrl(presentation_url)) { |
| error_cb.Run(content::PresentationError(content::PRESENTATION_ERROR_UNKNOWN, |
| "Invalid presentation arguments.")); |
| return; |
| } |
| |
| RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id); |
| scoped_ptr<CreatePresentationConnectionRequest> request( |
| new CreatePresentationConnectionRequest( |
| render_frame_host_id, presentation_url, |
| GetLastCommittedURLForFrame(render_frame_host_id), |
| base::Bind(&PresentationServiceDelegateImpl::OnStartSessionSucceeded, |
| weak_factory_.GetWeakPtr(), render_process_id, |
| render_frame_id, success_cb), |
| error_cb)); |
| MediaRouterDialogController* controller = |
| MediaRouterDialogController::GetOrCreateForWebContents(web_contents_); |
| if (!controller->ShowMediaRouterDialogForPresentation(std::move(request))) { |
| LOG(ERROR) << "Media router dialog already exists. Ignoring StartSession."; |
| error_cb.Run(content::PresentationError(content::PRESENTATION_ERROR_UNKNOWN, |
| "Unable to create dialog.")); |
| return; |
| } |
| } |
| |
| void PresentationServiceDelegateImpl::JoinSession( |
| int render_process_id, |
| int render_frame_id, |
| const std::string& presentation_url, |
| const std::string& presentation_id, |
| const content::PresentationSessionStartedCallback& success_cb, |
| const content::PresentationSessionErrorCallback& error_cb) { |
| std::vector<MediaRouteResponseCallback> route_response_callbacks; |
| route_response_callbacks.push_back(base::Bind( |
| &PresentationServiceDelegateImpl::OnJoinRouteResponse, |
| weak_factory_.GetWeakPtr(), render_process_id, render_frame_id, |
| content::PresentationSessionInfo(presentation_url, presentation_id), |
| success_cb, error_cb)); |
| router_->JoinRoute( |
| MediaSourceForPresentationUrl(presentation_url).id(), presentation_id, |
| GetLastCommittedURLForFrame( |
| RenderFrameHostId(render_process_id, render_frame_id)) |
| .GetOrigin(), |
| web_contents_, route_response_callbacks); |
| } |
| |
| void PresentationServiceDelegateImpl::CloseConnection( |
| int render_process_id, |
| int render_frame_id, |
| const std::string& presentation_id) { |
| const RenderFrameHostId rfh_id(render_process_id, render_frame_id); |
| const MediaRoute::Id& route_id = |
| frame_manager_->GetRouteId(rfh_id, presentation_id); |
| if (route_id.empty()) { |
| DVLOG(1) << "No active route for: " << presentation_id; |
| return; |
| } |
| |
| router_->DetachRoute(route_id); |
| frame_manager_->RemoveConnection(rfh_id, presentation_id, route_id); |
| // TODO(mfoltz): close() should always succeed so there is no need to keep the |
| // state_changed_cb around - remove it and fire the ChangeEvent on the |
| // PresentationConnection in Blink. |
| } |
| |
| void PresentationServiceDelegateImpl::Terminate( |
| int render_process_id, |
| int render_frame_id, |
| const std::string& presentation_id) { |
| const RenderFrameHostId rfh_id(render_process_id, render_frame_id); |
| const MediaRoute::Id& route_id = |
| frame_manager_->GetRouteId(rfh_id, presentation_id); |
| if (route_id.empty()) { |
| DVLOG(1) << "No active route for: " << presentation_id; |
| return; |
| } |
| router_->TerminateRoute(route_id); |
| frame_manager_->RemoveConnection(rfh_id, presentation_id, route_id); |
| } |
| |
| void PresentationServiceDelegateImpl::ListenForSessionMessages( |
| int render_process_id, |
| 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); |
| } |
| |
| void PresentationServiceDelegateImpl::SendMessage( |
| int render_process_id, |
| 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, std::move(message->data), |
| send_message_cb); |
| } else { |
| router_->SendRouteMessage(route_id, message->message, send_message_cb); |
| } |
| } |
| |
| void PresentationServiceDelegateImpl::ListenForConnectionStateChange( |
| int render_process_id, |
| int render_frame_id, |
| const content::PresentationSessionInfo& connection, |
| const content::PresentationConnectionStateChangedCallback& |
| state_changed_cb) { |
| frame_manager_->ListenForConnectionStateChange( |
| RenderFrameHostId(render_process_id, render_frame_id), connection, |
| state_changed_cb); |
| } |
| |
| void PresentationServiceDelegateImpl::OnRouteResponse( |
| const PresentationRequest& presentation_request, |
| const MediaRoute* route, |
| const std::string& presentation_id, |
| const std::string& error) { |
| if (!route) |
| return; |
| |
| content::PresentationSessionInfo session_info( |
| presentation_request.presentation_url(), presentation_id); |
| frame_manager_->OnDefaultPresentationSessionStarted( |
| presentation_request, session_info, route->media_route_id()); |
| } |
| |
| void PresentationServiceDelegateImpl::AddDefaultPresentationRequestObserver( |
| DefaultPresentationRequestObserver* observer) { |
| frame_manager_->AddDefaultPresentationRequestObserver(observer); |
| } |
| |
| void PresentationServiceDelegateImpl::RemoveDefaultPresentationRequestObserver( |
| DefaultPresentationRequestObserver* observer) { |
| frame_manager_->RemoveDefaultPresentationRequestObserver(observer); |
| } |
| |
| PresentationRequest |
| PresentationServiceDelegateImpl::GetDefaultPresentationRequest() const { |
| DCHECK(HasDefaultPresentationRequest()); |
| return *frame_manager_->default_presentation_request(); |
| } |
| |
| bool PresentationServiceDelegateImpl::HasDefaultPresentationRequest() const { |
| return frame_manager_->default_presentation_request() != nullptr; |
| } |
| |
| base::WeakPtr<PresentationServiceDelegateImpl> |
| PresentationServiceDelegateImpl::GetWeakPtr() { |
| return weak_factory_.GetWeakPtr(); |
| } |
| |
| void PresentationServiceDelegateImpl::SetMediaRouterForTest( |
| MediaRouter* router) { |
| router_ = router; |
| frame_manager_->SetMediaRouterForTest(router); |
| } |
| |
| bool PresentationServiceDelegateImpl::HasScreenAvailabilityListenerForTest( |
| int render_process_id, |
| int render_frame_id, |
| const MediaSource::Id& source_id) const { |
| RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id); |
| return frame_manager_->HasScreenAvailabilityListenerForTest( |
| render_frame_host_id, source_id); |
| } |
| |
| } // namespace media_router |