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 |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..945332bba213f271e072ff69f795a0cd496c58cd |
| --- /dev/null |
| +++ b/chrome/browser/media/router/presentation_service_delegate_impl.cc |
| @@ -0,0 +1,516 @@ |
| +// 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 "base/containers/scoped_ptr_hash_map.h" |
| +#include "base/guid.h" |
| +#include "base/strings/string_util.h" |
| +#include "base/strings/stringprintf.h" |
| +#include "chrome/browser/media/router/create_session_request.h" |
| +#include "chrome/browser/media/router/media_route.h" |
| +#include "chrome/browser/media/router/media_router.h" |
| +#include "chrome/browser/media/router/media_sink.h" |
| +#include "chrome/browser/media/router/media_source_helper.h" |
| +#include "chrome/browser/media/router/presentation_helper.h" |
| +#include "chrome/browser/media/router/presentation_media_sinks_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 { |
| + |
| +using RenderFrameHostId = std::pair<int, int>; |
| + |
| +namespace { |
| + |
| +// Returns the unique identifier for the supplied RenderViewHost. |
| +RenderFrameHostId GetRenderFrameHostId(RenderFrameHost* render_view_host) { |
| + int render_process_id = render_view_host->GetProcess()->GetID(); |
| + int render_frame_id = render_view_host->GetRoutingID(); |
| + return RenderFrameHostId(render_process_id, render_frame_id); |
| +} |
| + |
| +std::string GetDisplayNameForFrame(RenderFrameHostId render_frame_host_id) { |
| + RenderFrameHost* render_view_host = RenderFrameHost::FromID( |
| + render_frame_host_id.first, render_frame_host_id.second); |
| + std::string host = render_view_host->GetLastCommittedURL().host(); |
| + if (StartsWithASCII(host, "www.", false)) |
| + host = host.substr(4); |
| + return host; |
| +} |
| + |
| +} // 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: |
| + using DelegateObserver = content::PresentationServiceDelegate::Observer; |
| + |
| + PresentationFrame(content::WebContents* web_contents, MediaRouter* router); |
| + ~PresentationFrame(); |
| + |
| + // Mirror corresponding APIs in PresentationServiceDelegateImpl. |
|
mark a. foltz
2015/06/01 19:18:12
Why doesn't this implement content::PresentationSe
haibinlu
2015/06/01 21:44:58
PresentationFrame/Manager do not implement StartSe
mark a. foltz
2015/06/02 00:18:39
Acknowledged.
|
| + bool SetScreenAvailabilityListener( |
| + content::PresentationScreenAvailabilityListener* listener); |
| + bool RemoveScreenAvailabilityListener( |
| + content::PresentationScreenAvailabilityListener* listener); |
| + bool HasScreenAvailabilityListenerForTest( |
| + const MediaSourceId& source_id) const; |
| + void SetDefaultPresentationInfo(const std::string& default_presentation_url, |
| + const std::string& default_presentation_id); |
| + std::string GetDefaultPresentationId() const; |
| + void Reset(); |
| + |
| + void OnDefaultPresentationStarted( |
| + const content::PresentationSessionInfo& session) const; |
| + void OnPresentationServiceDelegateDestroyed() const; |
| + |
| + void set_delegate_observer(DelegateObserver* observer) { |
| + delegate_observer_ = observer; |
| + } |
| + |
| + private: |
| + MediaSource GetMediaSourceFromListener( |
| + content::PresentationScreenAvailabilityListener* listener) const; |
| + |
| + scoped_ptr<content::PresentationSessionInfo> default_presentation_info_; |
| + scoped_ptr<PresentationMediaSinksObserver> sink_observer_; |
|
mark a. foltz
2015/06/01 19:18:12
nit: sinks_observer_
haibinlu
2015/06/01 21:44:58
Done.
|
| + |
| + // 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::OnDefaultPresentationStarted( |
| + const content::PresentationSessionInfo& session) const { |
| + if (delegate_observer_) |
| + delegate_observer_->OnDefaultPresentationStarted(session); |
| +} |
| + |
| +bool PresentationFrame::SetScreenAvailabilityListener( |
| + content::PresentationScreenAvailabilityListener* listener) { |
| + if (sink_observer_ && sink_observer_->listener() == listener) { |
| + return false; |
| + } |
| + MediaSource source(GetMediaSourceFromListener(listener)); |
| + sink_observer_.reset( |
| + new PresentationMediaSinksObserver(router_, listener, source)); |
| + return true; |
| +} |
| + |
| +bool PresentationFrame::RemoveScreenAvailabilityListener( |
| + content::PresentationScreenAvailabilityListener* listener) { |
| + if (sink_observer_ && sink_observer_->listener() == listener) { |
| + sink_observer_.reset(); |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +bool PresentationFrame::HasScreenAvailabilityListenerForTest( |
| + const MediaSourceId& source_id) const { |
| + return sink_observer_ && sink_observer_->source().id() == source_id; |
| +} |
| + |
| +void PresentationFrame::Reset() { |
| + sink_observer_.reset(); |
| + default_presentation_info_.reset(); |
| +} |
| + |
| +void PresentationFrame::SetDefaultPresentationInfo( |
| + const std::string& default_presentation_url, |
| + const std::string& default_presentation_id) { |
| + if (default_presentation_url.empty() && default_presentation_id.empty()) { |
| + default_presentation_info_.reset(); |
| + } else { |
| + default_presentation_info_.reset(new content::PresentationSessionInfo( |
| + default_presentation_url, default_presentation_id)); |
| + } |
| +} |
| + |
| +std::string PresentationFrame::GetDefaultPresentationId() const { |
| + if (default_presentation_info_) |
| + return default_presentation_info_->presentation_id; |
|
mark a. foltz
2015/06/01 19:18:12
return default_presentation_info_ ? default_presen
haibinlu
2015/06/01 21:44:58
wez@ prefers "if() return a; return b;" style. I a
mark a. foltz
2015/06/02 00:18:39
Ok, we have different preferences on that front.
|
| + return ""; |
| +} |
| + |
| +MediaSource PresentationFrame::GetMediaSourceFromListener( |
| + content::PresentationScreenAvailabilityListener* listener) const { |
| + // If the default presentation URL is empty then fall back to tab mirroring. |
| + std::string presentation_url(listener->GetPresentationUrl()); |
| + if (presentation_url.empty()) |
|
mark a. foltz
2015/06/01 19:18:12
Ditto
haibinlu
2015/06/01 21:44:58
wez@ prefers "if() return a; return b;" style. I a
|
| + return MediaSourceForTab(SessionTabHelper::IdForTab(web_contents_)); |
| + return MediaSourceForPresentationUrl(presentation_url); |
| +} |
| + |
| +// Used by PresentationServiceDelegateImpl to manage PresentationFrames. |
| +class PresentationFrameManager { |
| + public: |
| + using DelegateObserver = content::PresentationServiceDelegate::Observer; |
|
mark a. foltz
2015/06/01 19:18:13
Repeated definition. Move to file level?
haibinlu
2015/06/01 21:44:58
Done.
|
| + |
| + 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 SetDefaultPresentationInfo(const RenderFrameHostId& render_frame_host_id, |
| + const std::string& default_presentation_url, |
| + const std::string& default_presentation_id); |
| + void AddDelegateObserver(const RenderFrameHostId& render_frame_host_id, |
| + DelegateObserver* observer); |
| + void RemoveDelegateObserver(const RenderFrameHostId& render_frame_host_id); |
| + void Reset(const RenderFrameHostId& render_frame_host_id); |
| + bool HasScreenAvailabilityListenerForTest( |
| + const RenderFrameHostId& render_frame_host_id, |
| + const MediaSourceId& source_id) const; |
| + void SetMediaRouterForTest(MediaRouter* router); |
| + |
| + // Returns default presentation ID, or empty string if no default |
| + // presentation ID is set in the frame. |
| + std::string GetDefaultPresentationId( |
| + const RenderFrameHostId& render_frame_host_id) const; |
| + |
| + void OnDefaultPresentationStarted( |
| + const RenderFrameHostId& render_frame_host_id, |
| + const content::PresentationSessionInfo& session) const; |
| + |
| + private: |
| + PresentationFrame* GetOrAddFrame( |
| + const RenderFrameHostId& render_frame_host_id); |
| + |
| + // Maps a frame identifier to a PresentationFrame object for frames |
| + // that are using presentation API. |
| + base::ScopedPtrHashMap<RenderFrameHostId, scoped_ptr<PresentationFrame>> |
| + presentation_frames_; |
| + |
| + // 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_); |
| +} |
| + |
| +PresentationFrameManager::~PresentationFrameManager() { |
| + for (auto& frame : presentation_frames_) |
| + frame.second->OnPresentationServiceDelegateDestroyed(); |
| +} |
| + |
| +void PresentationFrameManager::OnDefaultPresentationStarted( |
| + const RenderFrameHostId& render_frame_host_id, |
| + const content::PresentationSessionInfo& session) const { |
| + auto presentation_frame = presentation_frames_.get(render_frame_host_id); |
| + if (presentation_frame) |
| + presentation_frame->OnDefaultPresentationStarted(session); |
| +} |
| + |
| +bool PresentationFrameManager::SetScreenAvailabilityListener( |
| + const RenderFrameHostId& render_frame_host_id, |
| + content::PresentationScreenAvailabilityListener* listener) { |
| + DCHECK(listener); |
| + auto presentation_frame = GetOrAddFrame(render_frame_host_id); |
|
mark a. foltz
2015/06/01 19:18:12
GetOrAddPresentationFrame? (We aren't creating a D
haibinlu
2015/06/01 21:44:58
Done.
|
| + 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 MediaSourceId& source_id) const { |
| + auto presentation_frame = presentation_frames_.get(render_frame_host_id); |
| + return presentation_frame && |
| + presentation_frame->HasScreenAvailabilityListenerForTest(source_id); |
| +} |
| + |
| +void PresentationFrameManager::SetDefaultPresentationInfo( |
| + const RenderFrameHostId& render_frame_host_id, |
| + const std::string& default_presentation_url, |
| + const std::string& default_presentation_id) { |
| + auto presentation_frame = GetOrAddFrame(render_frame_host_id); |
| + presentation_frame->SetDefaultPresentationInfo(default_presentation_url, |
| + default_presentation_id); |
| +} |
| + |
| +std::string PresentationFrameManager::GetDefaultPresentationId( |
| + const RenderFrameHostId& render_frame_host_id) const { |
| + auto presentation_frame = presentation_frames_.get(render_frame_host_id); |
| + if (presentation_frame) |
| + return presentation_frame->GetDefaultPresentationId(); |
| + return ""; |
| +} |
| + |
| +void PresentationFrameManager::AddDelegateObserver( |
| + const RenderFrameHostId& render_frame_host_id, |
| + content::PresentationServiceDelegate::Observer* observer) { |
| + auto presentation_frame = GetOrAddFrame(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::Reset( |
| + const RenderFrameHostId& render_frame_host_id) { |
| + auto presentation_frame = presentation_frames_.get(render_frame_host_id); |
| + if (presentation_frame) |
| + presentation_frame->Reset(); |
| +} |
| + |
| +PresentationFrame* PresentationFrameManager::GetOrAddFrame( |
| + 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::SetMediaRouterForTest(MediaRouter* router) { |
| + router_ = router; |
| +} |
| + |
| +// TODO(haibinlu): Get router from MediaRouterMojoImplFactory once it lands. |
| +// BUG=464205 |
|
mark a. foltz
2015/06/01 19:18:12
https://codereview.chromium.org/1143603004/ has la
haibinlu
2015/06/01 21:44:58
Done.
|
| +PresentationServiceDelegateImpl::PresentationServiceDelegateImpl( |
| + content::WebContents* web_contents) |
| + : frame_manager_(new PresentationFrameManager(web_contents, nullptr)), |
| + web_contents_(web_contents), |
| + router_(nullptr), |
| + weak_factory_(this) { |
| +} |
| + |
| +PresentationServiceDelegateImpl::~PresentationServiceDelegateImpl() { |
| +} |
| + |
| +void PresentationServiceDelegateImpl::AddObserver( |
| + int render_process_id, |
| + int render_frame_id, |
| + content::PresentationServiceDelegate::Observer* 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); |
| + if (IsMainFrame(render_process_id, render_frame_id)) |
| + UpdateDefaultMediaSourceAndNotifyObservers(MediaSource(), std::string()); |
| +} |
| + |
| +void PresentationServiceDelegateImpl::SetDefaultPresentationUrl( |
| + int render_process_id, |
| + int render_frame_id, |
| + const std::string& default_presentation_url, |
| + const std::string& default_presentation_id) { |
| + RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id); |
| + frame_manager_->SetDefaultPresentationInfo( |
| + render_frame_host_id, default_presentation_url, default_presentation_id); |
| + if (IsMainFrame(render_process_id, render_frame_id)) { |
| + // This is the main frame, which means tab-level default presentation |
| + // might have been updated. |
| + MediaSource default_source; |
| + if (!default_presentation_url.empty()) |
| + default_source = MediaSourceForPresentationUrl(default_presentation_url); |
| + std::string default_frame_display_name( |
| + GetDisplayNameForFrame(render_frame_host_id)); |
| + UpdateDefaultMediaSourceAndNotifyObservers(default_source, |
| + default_frame_display_name); |
| + } |
| +} |
| + |
| +bool PresentationServiceDelegateImpl::IsMainFrame(int render_process_id, |
| + int render_frame_id) const { |
| + RenderFrameHost* main_frame = web_contents_->GetMainFrame(); |
| + return main_frame && |
| + GetRenderFrameHostId(main_frame) == |
| + RenderFrameHostId(render_process_id, render_frame_id); |
| +} |
| + |
| +void PresentationServiceDelegateImpl:: |
| + UpdateDefaultMediaSourceAndNotifyObservers( |
| + const MediaSource& default_source, |
| + const std::string& default_frame_display_name) { |
| + if (!default_source.Equals(default_source_) || |
| + default_frame_display_name != default_frame_display_name_) { |
| + default_source_ = default_source; |
| + default_frame_display_name_ = default_frame_display_name; |
| + FOR_EACH_OBSERVER(DefaultMediaSourceObserver, |
| + default_media_source_observers_, |
| + OnDefaultMediaSourceChanged(default_source_, |
| + default_frame_display_name_)); |
| + } |
| +} |
| + |
| +void PresentationServiceDelegateImpl::StartSession( |
| + int render_process_id, |
| + int render_frame_id, |
| + const std::string& presentation_url, |
| + const std::string& presentation_id, |
| + const PresentationSessionSuccessCallback& success_cb, |
| + const PresentationSessionErrorCallback& error_cb) { |
| + // BUG=464205 |
| + NOTIMPLEMENTED(); |
| +} |
| + |
| +void PresentationServiceDelegateImpl::JoinSession( |
| + int render_process_id, |
| + int render_frame_id, |
| + const std::string& presentation_url, |
| + const std::string& presentation_id, |
| + const PresentationSessionSuccessCallback& success_cb, |
| + const PresentationSessionErrorCallback& error_cb) { |
| + // BUG=464205 |
| + NOTIMPLEMENTED(); |
| +} |
| + |
| +void PresentationServiceDelegateImpl::ListenForSessionMessages( |
| + int render_process_id, |
| + int render_frame_id, |
| + const PresentationSessionMessageCallback& message_cb) { |
| + // BUG=464205 |
| + NOTIMPLEMENTED(); |
| +} |
| + |
| +void PresentationServiceDelegateImpl::SendMessage( |
| + int render_process_id, |
| + int render_frame_id, |
| + scoped_ptr<content::PresentationSessionMessage> message_request, |
| + const SendMessageCallback& send_message_cb) { |
| + // BUG=464205 |
| + NOTIMPLEMENTED(); |
| +} |
| + |
| +void PresentationServiceDelegateImpl::OnRouteCreated(const MediaRoute& route) { |
| + 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)); |
| + // TODO(imcheng): Pass in valid default presentation ID once it is |
| + // available from MediaRoute URN. BUG=493365 |
| + frame_manager_->OnDefaultPresentationStarted( |
| + render_frame_host_id, |
| + content::PresentationSessionInfo(PresentationUrlFromMediaSource(source), |
| + std::string())); |
| +} |
| + |
| +void PresentationServiceDelegateImpl::AddDefaultMediaSourceObserver( |
| + DefaultMediaSourceObserver* observer) { |
| + default_media_source_observers_.AddObserver(observer); |
| +} |
| + |
| +void PresentationServiceDelegateImpl::RemoveDefaultMediaSourceObserver( |
| + DefaultMediaSourceObserver* observer) { |
| + default_media_source_observers_.RemoveObserver(observer); |
| +} |
| + |
| +void PresentationServiceDelegateImpl::SetMediaRouterForTest( |
| + MediaRouter* router) { |
| + router_ = router; |
| + frame_manager_->SetMediaRouterForTest(router); |
| +} |
| + |
| +base::WeakPtr<PresentationServiceDelegateImpl> |
| +PresentationServiceDelegateImpl::GetWeakPtr() { |
| + return weak_factory_.GetWeakPtr(); |
| +} |
| + |
| +bool PresentationServiceDelegateImpl::HasScreenAvailabilityListenerForTest( |
| + int render_process_id, |
| + int render_frame_id, |
| + const MediaSourceId& 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 |