Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5689)

Unified Diff: chrome/browser/media/router/presentation_service_delegate_impl.cc

Issue 1314413005: [Presentation API] 1-UA presentation support + presenter APIs. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 e29a9057d8c2ed3661a075a7aaa743ec3b4b43f6..93b0f0bc9b534e297d214e9424ea046d6c67dbe4 100644
--- a/chrome/browser/media/router/presentation_service_delegate_impl.cc
+++ b/chrome/browser/media/router/presentation_service_delegate_impl.cc
@@ -10,7 +10,6 @@
#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"
@@ -20,6 +19,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/route_request_result.h"
@@ -37,6 +38,9 @@ using content::RenderFrameHost;
namespace media_router {
+using OffscreenPresentationConnection =
+ OffscreenPresentationManager::OffscreenPresentationConnection;
+
namespace {
using DelegateObserver = content::PresentationServiceDelegate::Observer;
@@ -79,6 +83,9 @@ class PresentationFrame {
bool HasScreenAvailabilityListenerForTest(
const MediaSource::Id& source_id) const;
std::string GetDefaultPresentationId() const;
+ void SendMessage(const content::PresentationSessionInfo& session,
+ std::unique_ptr<content::PresentationSessionMessage> message,
+ const content::SendMessageCallback send_message_cb);
void ListenForConnectionStateChange(
const content::PresentationSessionInfo& connection,
const content::PresentationConnectionStateChangedCallback&
@@ -88,15 +95,16 @@ class PresentationFrame {
const content::PresentationSessionMessageCallback& message_cb);
void Reset();
- void RemoveConnection(const std::string& presentation_id,
- const MediaRoute::Id& route_id);
+ void RemoveConnection(
+ const std::string& presentation_id,
+ const content::PresentationConnectionStateChangeInfo& state_change_info);
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);
+ const MediaRoute& route);
void OnPresentationServiceDelegateDestroyed() const;
void set_delegate_observer(DelegateObserver* observer) {
@@ -106,11 +114,25 @@ class PresentationFrame {
private:
MediaSource GetMediaSourceFromListener(
content::PresentationScreenAvailabilityListener* listener) const;
+ // Gets the OffscreenPresentationConnection associated with |presentation_id|
+ // within this frame. Returns nullptr if |presentation_id| is not
+ // registered as an offscreen presentation.
+ OffscreenPresentationConnection* FindOffscreenConnection(
+ const std::string& presentation_id) const;
+
base::SmallMap<std::map<std::string, MediaRoute::Id>>
presentation_id_to_route_id_;
base::SmallMap<
std::map<std::string, std::unique_ptr<PresentationMediaSinksObserver>>>
url_to_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 OffscreenPresentationConnection within this frame.
+ std::map<std::string, std::unique_ptr<OffscreenPresentationConnection>>
+ offscreen_presentation_connections_;
+
base::ScopedPtrHashMap<
MediaRoute::Id,
std::unique_ptr<PresentationConnectionStateSubscription>>
@@ -119,9 +141,11 @@ class PresentationFrame {
RenderFrameHostId render_frame_host_id_;
- // References to the owning WebContents, and the corresponding MediaRouter.
+ // References to the owning WebContents, the corresponding MediaRouter, and
+ // OffscreenPresentationManager.
const content::WebContents* web_contents_;
- MediaRouter* router_;
+ MediaRouter* const router_;
+ OffscreenPresentationManager* const offscreen_presentation_manager_;
DelegateObserver* delegate_observer_;
};
@@ -133,9 +157,13 @@ PresentationFrame::PresentationFrame(
: render_frame_host_id_(render_frame_host_id),
web_contents_(web_contents),
router_(router),
+ offscreen_presentation_manager_(
+ OffscreenPresentationManagerFactory::GetOrCreateForBrowserContext(
+ web_contents_->GetBrowserContext())),
delegate_observer_(nullptr) {
DCHECK(web_contents_);
DCHECK(router_);
+ DCHECK(offscreen_presentation_manager_);
}
PresentationFrame::~PresentationFrame() {
@@ -148,8 +176,31 @@ void PresentationFrame::OnPresentationServiceDelegateDestroyed() const {
void PresentationFrame::OnPresentationSessionStarted(
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 (route.is_offscreen_presentation()) {
+ DCHECK(!ContainsKey(offscreen_presentation_connections_, presentation_id));
+ std::unique_ptr<OffscreenPresentationConnection> offscreen_connection =
+ offscreen_presentation_manager_->ConnectToOffscreenPresentation(
+ presentation_id, render_frame_host_id_);
+
+ // |offscreen_connection| could be nullptr for a couple of reasons:
+ // 1) An OffscreenPresentationConnection for presentation_id already exists.
+ // This could be due to a race between two or more route requests.
+ // 2) The receiver is 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_connection) {
+ // TODO(imcheng): we should probably reject the route request and detach
+ // the route in this case. crbug.com/513859
+ DLOG(ERROR) << "CreateOffscreenPresentationConnection returned nullptr.";
+ } else {
+ offscreen_presentation_connections_.insert(
+ std::make_pair(presentation_id, std::move(offscreen_connection)));
+ }
+ }
}
const MediaRoute::Id PresentationFrame::GetRouteId(
@@ -158,13 +209,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) {
MediaSource source(GetMediaSourceFromListener(listener));
@@ -205,18 +249,65 @@ bool PresentationFrame::HasScreenAvailabilityListenerForTest(
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();
url_to_sinks_observer_.clear();
+ offscreen_presentation_connections_.clear();
connection_state_subscriptions_.clear();
session_messages_observers_.clear();
}
-void PresentationFrame::RemoveConnection(const std::string& presentation_id,
- const MediaRoute::Id& route_id) {
+void PresentationFrame::SendMessage(
+ const content::PresentationSessionInfo& session,
+ std::unique_ptr<content::PresentationSessionMessage> message,
+ const content::SendMessageCallback send_message_cb) {
+ OffscreenPresentationConnection* offscreen_connection =
+ FindOffscreenConnection(session.presentation_id);
+ if (offscreen_connection) {
+ offscreen_connection->SendMessage(std::move(message), send_message_cb);
+ } else {
+ 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;
+ }
+ if (message->is_binary()) {
+ router_->SendRouteBinaryMessage(it->second, std::move(message->data),
+ send_message_cb);
+ } else {
+ router_->SendRouteMessage(it->second, message->message, send_message_cb);
+ }
+ }
+}
+
+OffscreenPresentationConnection* PresentationFrame::FindOffscreenConnection(
+ const std::string& presentation_id) const {
+ auto offscreen_connection_it =
+ offscreen_presentation_connections_.find(presentation_id);
+ return offscreen_connection_it != offscreen_presentation_connections_.end()
+ ? offscreen_connection_it->second.get()
+ : nullptr;
+}
+
+void PresentationFrame::RemoveConnection(
+ const std::string& presentation_id,
+ const content::PresentationConnectionStateChangeInfo& state_change_info) {
+ auto it = presentation_id_to_route_id_.find(presentation_id);
+ if (it == presentation_id_to_route_id_.end())
+ return;
+
// Remove the presentation id mapping so a later call to Reset is a no-op.
- presentation_id_to_route_id_.erase(presentation_id);
+ MediaRoute::Id route_id = it->second;
+ presentation_id_to_route_id_.erase(it);
+
+ if (OffscreenPresentationConnection* offscreen_connection =
+ FindOffscreenConnection(presentation_id)) {
+ offscreen_connection->RemoveFromPresentation(state_change_info);
+ offscreen_presentation_connections_.erase(presentation_id);
+ return;
+ }
+ // Not an offscreen presentation.
// We no longer need to observe route messages.
auto observer_iter = std::find_if(
session_messages_observers_.begin(), session_messages_observers_.end(),
@@ -241,6 +332,14 @@ void PresentationFrame::ListenForConnectionStateChange(
return;
}
+ // An offscreen controller presentation listens for state change from both
+ // the receiver and MR.
+ OffscreenPresentationConnection* offscreen_connection =
+ FindOffscreenConnection(connection.presentation_id);
+ if (offscreen_connection) {
+ offscreen_connection->ListenForStateChange(state_changed_cb);
+ }
+
const MediaRoute::Id& route_id = it->second;
if (connection_state_subscriptions_.contains(route_id)) {
DLOG(ERROR) << __FUNCTION__ << "Already listening connection state change "
@@ -264,6 +363,15 @@ void PresentationFrame::ListenForSessionMessages(
return;
}
+ // An offscreen controller presentation listens for messages from both the
+ // receiver and MR.
+ OffscreenPresentationConnection* offscreen_connection =
+ FindOffscreenConnection(session.presentation_id);
+ if (offscreen_connection) {
+ offscreen_connection->ListenForMessages(message_cb);
+ }
+
+ // TODO(imcheng): Limit to 1 observer per presentation.
session_messages_observers_.push_back(
new PresentationSessionMessagesObserver(message_cb, it->second, router_));
}
@@ -291,6 +399,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,
+ std::unique_ptr<content::PresentationSessionMessage> message,
+ const content::SendMessageCallback send_message_cb);
void ListenForConnectionStateChange(
const RenderFrameHostId& render_frame_host_id,
const content::PresentationSessionInfo& connection,
@@ -318,9 +430,10 @@ class PresentationFrameManager {
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);
+ void RemoveConnection(
+ const RenderFrameHostId& render_frame_host_id,
+ const std::string& presentation_id,
+ const content::PresentationConnectionStateChangeInfo& state_change_info);
bool HasScreenAvailabilityListenerForTest(
const RenderFrameHostId& render_frame_host_id,
const MediaSource::Id& source_id) const;
@@ -329,16 +442,14 @@ class PresentationFrameManager {
void OnPresentationSessionStarted(
const RenderFrameHostId& render_frame_host_id,
const content::PresentationSessionInfo& session,
- const MediaRoute::Id& route_id);
+ const MediaRoute& route);
void OnDefaultPresentationSessionStarted(
const PresentationRequest& request,
const content::PresentationSessionInfo& session,
- const MediaRoute::Id& route_id);
+ const MediaRoute& route);
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();
@@ -379,14 +490,14 @@ class PresentationFrameManager {
default_presentation_request_observers_;
// 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_);
}
@@ -399,19 +510,19 @@ PresentationFrameManager::~PresentationFrameManager() {
void PresentationFrameManager::OnPresentationSessionStarted(
const RenderFrameHostId& render_frame_host_id,
const content::PresentationSessionInfo& session,
- const MediaRoute::Id& route_id) {
+ const MediaRoute& route) {
auto presentation_frame = GetOrAddPresentationFrame(render_frame_host_id);
- presentation_frame->OnPresentationSessionStarted(session, route_id);
+ presentation_frame->OnPresentationSessionStarted(session, route);
}
void PresentationFrameManager::OnDefaultPresentationSessionStarted(
const PresentationRequest& request,
const content::PresentationSessionInfo& session,
- const MediaRoute::Id& route_id) {
+ const MediaRoute& route) {
auto presentation_frame =
presentation_frames_.get(request.render_frame_host_id());
if (presentation_frame)
- presentation_frame->OnPresentationSessionStarted(session, route_id);
+ presentation_frame->OnPresentationSessionStarted(session, route);
if (default_presentation_request_ &&
default_presentation_request_->Equals(request)) {
@@ -427,13 +538,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) {
@@ -459,6 +563,24 @@ bool PresentationFrameManager::HasScreenAvailabilityListenerForTest(
presentation_frame->HasScreenAvailabilityListenerForTest(source_id);
}
+void PresentationFrameManager::SendMessage(
+ const RenderFrameHostId& render_frame_host_id,
+ const content::PresentationSessionInfo& session,
+ std::unique_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, std::move(message), send_message_cb);
+}
+
void PresentationFrameManager::ListenForConnectionStateChange(
const RenderFrameHostId& render_frame_host_id,
const content::PresentationSessionInfo& connection,
@@ -548,11 +670,11 @@ void PresentationFrameManager::Reset(
void PresentationFrameManager::RemoveConnection(
const RenderFrameHostId& render_frame_host_id,
- const MediaRoute::Id& route_id,
- const std::string& presentation_id) {
+ const std::string& presentation_id,
+ const content::PresentationConnectionStateChangeInfo& state_change_info) {
auto presentation_frame = presentation_frames_.get(render_frame_host_id);
if (presentation_frame)
- presentation_frame->RemoveConnection(route_id, presentation_id);
+ presentation_frame->RemoveConnection(presentation_id, state_change_info);
}
PresentationFrame* PresentationFrameManager::GetOrAddPresentationFrame(
@@ -686,11 +808,12 @@ void PresentationServiceDelegateImpl::OnJoinRouteResponse(
DVLOG(1) << "OnJoinRouteResponse: "
<< "route_id: " << result.route()->media_route_id()
<< ", presentation URL: " << session.presentation_url
- << ", presentation ID: " << session.presentation_id;
+ << ", presentation ID: " << session.presentation_id
+ << ", offscreen? " << result.route()->is_offscreen_presentation();
DCHECK_EQ(session.presentation_id, result.presentation_id());
frame_manager_->OnPresentationSessionStarted(
RenderFrameHostId(render_process_id, render_frame_id), session,
- result.route()->media_route_id());
+ *result.route());
success_cb.Run(session);
}
}
@@ -700,14 +823,15 @@ void PresentationServiceDelegateImpl::OnStartSessionSucceeded(
int render_frame_id,
const content::PresentationSessionStartedCallback& 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), new_session,
- route_id);
+ route);
success_cb.Run(new_session);
}
@@ -778,7 +902,12 @@ void PresentationServiceDelegateImpl::CloseConnection(
}
router_->DetachRoute(route_id);
- frame_manager_->RemoveConnection(rfh_id, presentation_id, route_id);
+
+ content::PresentationConnectionStateChangeInfo state_change_info(
+ content::PRESENTATION_CONNECTION_STATE_CLOSED);
+ state_change_info.close_reason =
+ content::PRESENTATION_CONNECTION_CLOSE_REASON_CLOSED;
+ frame_manager_->RemoveConnection(rfh_id, presentation_id, state_change_info);
// 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.
@@ -795,8 +924,12 @@ void PresentationServiceDelegateImpl::Terminate(
DVLOG(1) << "No active route for: " << presentation_id;
return;
}
+
router_->TerminateRoute(route_id);
- frame_manager_->RemoveConnection(rfh_id, presentation_id, route_id);
+
+ content::PresentationConnectionStateChangeInfo state_change_info(
+ content::PRESENTATION_CONNECTION_STATE_TERMINATED);
+ frame_manager_->RemoveConnection(rfh_id, presentation_id, state_change_info);
}
void PresentationServiceDelegateImpl::ListenForSessionMessages(
@@ -804,9 +937,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(
@@ -814,22 +947,10 @@ void PresentationServiceDelegateImpl::SendMessage(
int render_frame_id,
const content::PresentationSessionInfo& session,
std::unique_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);
- }
+ 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, std::move(message),
+ send_message_cb);
}
void PresentationServiceDelegateImpl::ListenForConnectionStateChange(
@@ -843,6 +964,18 @@ void PresentationServiceDelegateImpl::ListenForConnectionStateChange(
state_changed_cb);
}
+std::vector<content::PresentationSessionInfo>
+PresentationServiceDelegateImpl::GetReceiverConnections(
+ int render_process_id,
+ int render_frame_id,
+ const content::PresentationSessionStartedCallback& callback) {
+ // We only support receiver APIs in offscreen tabs created for offscreen
+ // presentations.
+ // See ReceiverPresentationServiceDelegateImpl for details.
+ NOTIMPLEMENTED();
+ return std::vector<content::PresentationSessionInfo>();
+}
+
void PresentationServiceDelegateImpl::OnRouteResponse(
const PresentationRequest& presentation_request,
const RouteRequestResult& result) {
@@ -852,7 +985,7 @@ void PresentationServiceDelegateImpl::OnRouteResponse(
content::PresentationSessionInfo session_info(
presentation_request.presentation_url(), result.presentation_id());
frame_manager_->OnDefaultPresentationSessionStarted(
- presentation_request, session_info, result.route()->media_route_id());
+ presentation_request, session_info, *result.route());
}
void PresentationServiceDelegateImpl::AddDefaultPresentationRequestObserver(

Powered by Google App Engine
This is Rietveld 408576698