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..73ce1e8ab198da9ca09cf54545039f191f96a246 |
| --- /dev/null |
| +++ b/chrome/browser/media/router/presentation_service_delegate_impl.cc |
| @@ -0,0 +1,320 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
|
mark a. foltz
2015/05/11 07:36:21
Copyright
haibinlu
2015/05/13 01:40:19
Done.
|
| +// 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/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_router_impl.h" |
|
mark a. foltz
2015/05/11 07:36:21
Why does this class need to know about the MR impl
haibinlu
2015/05/13 01:40:19
removed.
|
| +#include "chrome/browser/media/router/media_router_impl_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_helper.h" |
| +#include "chrome/browser/media/router/presentation_media_sinks_observer.h" |
| +#include "chrome/browser/sessions/session_tab_helper.h" |
| +#include "chrome/browser/ui/webui/media_router/media_router_dialog_controller.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 { |
| + |
| +PresentationServiceDelegateImpl::PresentationServiceDelegateImpl( |
| + content::WebContents* web_contents) |
| + : num_observers_(0u), |
| + web_contents_(web_contents), |
| + router_(MediaRouterImplFactory::GetMediaRouterForBrowserContext( |
| + web_contents_->GetBrowserContext())), |
| + weak_factory_(this) { |
| + DCHECK(router_); |
| +} |
| + |
| +PresentationServiceDelegateImpl::~PresentationServiceDelegateImpl() { |
| + DCHECK(observers_.empty()); |
| + DCHECK_EQ(0u, num_observers_); |
| + |
| + for (const auto& delegate_observer_entry : delegate_observers_) |
| + delegate_observer_entry.second->OnDelegateDestroyed(); |
| +} |
| + |
| +void PresentationServiceDelegateImpl::AddObserver( |
| + int render_process_id, |
| + int render_frame_id, |
| + content::PresentationServiceDelegate::Observer* observer) { |
| + DCHECK(observer); |
| + |
| + RenderFrameHostId rfh_id(render_process_id, render_frame_id); |
| + DCHECK(!ContainsKey(delegate_observers_, rfh_id)); |
| + |
| + delegate_observers_[rfh_id] = observer; |
| +} |
| + |
| +void PresentationServiceDelegateImpl::RemoveObserver(int render_process_id, |
| + int render_frame_id) { |
| + delegate_observers_.erase( |
| + RenderFrameHostId(render_process_id, render_frame_id)); |
| +} |
| + |
| +MediaSource PresentationServiceDelegateImpl::GetMediaSourceFromListener( |
| + content::PresentationScreenAvailabilityListener* listener) { |
| + // If the default presentation URL is empty then fall back to 1-UA mode, |
| + // i.e. offscreeen tab rendering. |
| + std::string presentation_url(listener->GetPresentationUrl()); |
| + return presentation_url.empty() |
| + ? ForTabMediaSource(SessionTabHelper::IdForTab(web_contents_)) |
| + : ForPresentationUrl(presentation_url); |
| +} |
| + |
| +bool PresentationServiceDelegateImpl::AddScreenAvailabilityListener( |
| + int render_process_id, |
| + int routing_id, |
| + content::PresentationScreenAvailabilityListener* listener) { |
| + DCHECK(listener); |
| + |
| + if (num_observers_ >= kMaxNumSources) { |
| + return false; |
| + } |
| + |
| + RenderFrameHostId rfh_id(render_process_id, routing_id); |
| + MediaSource source(GetMediaSourceFromListener(listener)); |
| + auto& observers_for_frame = observers_[rfh_id]; |
| + // Already exists. |
| + if (ContainsKey(observers_for_frame, source.id())) |
| + return false; |
| + |
| + linked_ptr<PresentationMediaSinksObserver> observer( |
| + new PresentationMediaSinksObserver(router_, listener, source)); |
| + observers_for_frame.insert(std::make_pair(source.id(), observer)); |
| + num_observers_++; |
| + return true; |
| +} |
| + |
| +void PresentationServiceDelegateImpl::RemoveScreenAvailabilityListener( |
| + int render_process_id, |
| + int routing_id, |
| + content::PresentationScreenAvailabilityListener* listener) { |
| + DCHECK(listener); |
| + |
| + RenderFrameHostId rfh_id(render_process_id, routing_id); |
| + MediaSource source(GetMediaSourceFromListener(listener)); |
| + auto it = observers_.find(rfh_id); |
| + if (it != observers_.end()) { |
| + auto& observers_by_id = it->second; |
| + auto observer_it = observers_by_id.find(source.id()); |
| + if (observer_it != observers_by_id.end()) { |
| + observers_by_id.erase(observer_it); |
| + num_observers_--; |
| + |
| + if (observers_by_id.empty()) |
| + observers_.erase(it); |
| + } |
| + } |
| +} |
| + |
| +void PresentationServiceDelegateImpl::Reset(int render_process_id, |
| + int routing_id) { |
| + RenderFrameHostId rfh_id(render_process_id, routing_id); |
| + UnregisterAllObserversFromFrame(rfh_id); |
| + default_presentation_infos_.erase(rfh_id); |
| + if (IsMainFrame(rfh_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 rfh_id(render_process_id, render_frame_id); |
| + if (default_presentation_url.empty() && default_presentation_id.empty()) { |
| + default_presentation_infos_.erase(rfh_id); |
| + } else { |
| + default_presentation_infos_[rfh_id].reset( |
| + new content::PresentationSessionInfo(default_presentation_url, |
| + default_presentation_id)); |
| + } |
| + |
| + if (IsMainFrame(rfh_id)) { |
| + // This is the main frame, that means tab-level default presentation |
| + // might have been updated. |
| + MediaSource new_default_source; |
| + if (!default_presentation_url.empty()) |
| + new_default_source = ForPresentationUrl(default_presentation_url); |
| + std::string new_default_source_host(GetSourceHostForFrame(rfh_id)); |
| + UpdateDefaultMediaSourceAndNotifyObservers(new_default_source, |
| + new_default_source_host); |
| + } |
| +} |
| + |
| +bool PresentationServiceDelegateImpl::IsMainFrame( |
| + RenderFrameHostId rfh_id) const { |
| + RenderFrameHost* main_frame = web_contents_->GetMainFrame(); |
| + return main_frame && GetRenderFrameHostId(main_frame) == rfh_id; |
| +} |
| + |
| +void PresentationServiceDelegateImpl:: |
| + UpdateDefaultMediaSourceAndNotifyObservers( |
| + const MediaSource& new_default_source, |
| + const std::string& new_default_source_host) { |
| + if (!new_default_source.Equals(default_source_) || |
| + new_default_source_host != default_source_host_) { |
| + default_source_ = new_default_source; |
| + default_source_host_ = new_default_source_host; |
| + FOR_EACH_OBSERVER( |
| + DefaultMediaSourceObserver, default_media_source_observers_, |
| + OnDefaultMediaSourceChanged(default_source_, default_source_host_)); |
| + } |
| +} |
| + |
| +std::string PresentationServiceDelegateImpl::GetOrGeneratePresentationId( |
| + RenderFrameHostId rfh_id, |
| + const std::string& presentation_id) const { |
| + if (!presentation_id.empty()) |
| + return presentation_id; |
| + |
| + auto it = default_presentation_infos_.find(rfh_id); |
| + if (it != default_presentation_infos_.end()) { |
| + const std::string& default_presentation_id = it->second->presentation_id; |
| + if (!default_presentation_id.empty()) |
| + return default_presentation_id; |
| + } |
| + |
| + return base::GenerateGUID(); |
| +} |
| + |
| +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) { |
| + if (presentation_url.empty() || !IsValidPresentationUrl(presentation_url)) { |
| + error_cb.Run(content::PresentationError(content::PRESENTATION_ERROR_UNKNOWN, |
| + "Invalid presentation arguments.")); |
| + return; |
| + } |
| + |
| + RenderFrameHostId rfh_id(render_process_id, render_frame_id); |
| + scoped_ptr<CreateSessionRequest> context(new CreateSessionRequest( |
| + presentation_url, GetOrGeneratePresentationId(rfh_id, presentation_id), |
| + GURL(GetSourceHostForFrame(rfh_id)), success_cb, error_cb)); |
| + |
| + // NOTE: Currently this request is ignored if a dialog is already open, e.g. |
| + // via browser action. In practice, this should rarely happen, but log |
| + // an error message in case it does. |
| + MediaRouterDialogController* controller = |
| + MediaRouterDialogController::GetInstance(); |
| + DCHECK(controller); |
| + bool created = controller->ShowMediaRouterDialogForPresentation( |
| + web_contents_, context.Pass()); |
| + if (!created) { |
| + 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 PresentationSessionSuccessCallback& success_cb, |
| + const PresentationSessionErrorCallback& error_cb) { |
| + NOTIMPLEMENTED(); |
| +} |
| + |
| +void PresentationServiceDelegateImpl::ListenForSessionMessages( |
| + int render_process_id, |
| + int render_frame_id, |
| + const PresentationSessionMessageCallback& message_cb) { |
| + NOTIMPLEMENTED(); |
| +} |
| + |
| +void PresentationServiceDelegateImpl::OnRouteCreated(const MediaRoute& route) { |
| + const MediaSource& source = route.media_source(); |
| + DCHECK(!source.Empty()); |
| + if (default_source_.Equals(source)) { |
| + RenderFrameHost* main_frame = web_contents_->GetMainFrame(); |
| + if (main_frame) { |
| + RenderFrameHostId rfh_id(GetRenderFrameHostId(main_frame)); |
| + auto it = delegate_observers_.find(rfh_id); |
| + if (it != delegate_observers_.end()) { |
| + // TODO(imcheng): Pass in valid default presentation ID once it is |
| + // available from MediaRoute URN. |
| + it->second->OnDefaultPresentationStarted( |
| + content::PresentationSessionInfo(GetPresentationUrl(source), |
| + std::string())); |
| + } |
| + } |
| + } |
| +} |
| + |
| +MediaSource PresentationServiceDelegateImpl::GetDefaultMediaSource() const { |
| + return default_source_; |
| +} |
| + |
| +std::string PresentationServiceDelegateImpl::GetSourceHostForFrame( |
| + RenderFrameHostId rfh_id) const { |
| + RenderFrameHost* rfh = RenderFrameHost::FromID(rfh_id.first, rfh_id.second); |
| + DCHECK(rfh); |
| + std::string host = rfh->GetLastCommittedURL().host(); |
| + if (StartsWithASCII(host, "www.", false)) |
| + host = host.substr(4); |
| + return host; |
| +} |
| + |
| +void PresentationServiceDelegateImpl::UnregisterAllObserversFromFrame( |
| + RenderFrameHostId rfh_id) { |
| + auto it = observers_.find(rfh_id); |
| + if (it != observers_.end()) { |
| + auto& observers_by_id = it->second; |
| + num_observers_ -= observers_by_id.size(); |
| + observers_.erase(it); |
| + } |
| +} |
| + |
| +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; |
| +} |
| + |
| +// static |
| +PresentationServiceDelegateImpl::RenderFrameHostId |
| +PresentationServiceDelegateImpl::GetRenderFrameHostId(RenderFrameHost* rfh) { |
| + int render_process_id = rfh->GetProcess()->GetID(); |
| + int routing_id = rfh->GetRoutingID(); |
| + return RenderFrameHostId(render_process_id, routing_id); |
| +} |
| + |
| +base::WeakPtr<PresentationServiceDelegateImpl> |
| +PresentationServiceDelegateImpl::GetWeakPtr() { |
| + return weak_factory_.GetWeakPtr(); |
| +} |
| + |
| +} // namespace media_router |