blob: 6c78d9718a9a3099ae151514add928aee3818711 [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_MEDIA_ROUTER_BROWSER_PRESENTATION_LOCAL_PRESENTATION_MANAGER_H_
#define COMPONENTS_MEDIA_ROUTER_BROWSER_PRESENTATION_LOCAL_PRESENTATION_MANAGER_H_
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <unordered_map>
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/threading/thread_checker.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/media_router/common/media_route.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/presentation_service_delegate.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "third_party/blink/public/mojom/presentation/presentation.mojom.h"
namespace content {
class WebContents;
}
namespace media_router {
// Manages all local presentations started in the associated Profile and
// facilitates communication between the controllers and the receiver of a
// local presentation. A local presentation may be an offscreen presentation for
// Presentation API 1-UA mode, or a presentation to a wired display.
//
// Design doc:
// https://docs.google.com/document/d/1XM3jhMJTQyhEC5PDAAJFNIaKh6UUEihqZDz_ztEe4Co/edit#heading=h.hadpx5oi0gml
//
// Example usage:
//
// Receiver is created to host the local presentation and registers itself
// so that controller frames can connect to it:
//
// LocalPresentationManager* manager =
// LocalPresentationManagerFactory::GetOrCreateForBrowserContext(
// web_contents_->GetBrowserContext());
// manager->OnLocalPresentationReceiverCreated(presentation_info,
// base::BindRepeating(
// &PresentationServiceImpl::OnReceiverConnectionAvailable));
//
// Controlling frame establishes connection with the receiver side, resulting
// in a connection with the two endpoints being the controller
// PresentationConnectionRemote and receiver PresentationConnectionReceiver.
// Note calling this will trigger receiver frame's
// PresentationServiceImpl::OnReceiverConnectionAvailable.
//
// manager->RegisterLocalPresentationController(
// presentation_info,
// std::move(controller_connection_remote),
// std::move(receiver_connection_receiver));
//
// Invoked on receiver's PresentationServiceImpl when controller connection is
// established.
//
// |presentation_receiver_remote_|: mojo::Remote<T> for the implementation of
// the blink::mojom::PresentationService interface in the renderer process.
// |controller_connection_remote|: mojo::PendingRemote<T> for
// blink::PresentationConnection object in controlling frame's render process.
// |receiver_connection_receiver|: mojo::PendingReceiver<T> to be bind to
// blink::PresentationConnection object in receiver frame's render process.
// void PresentationServiceImpl::OnReceiverConnectionAvailable(
// const blink::mojom::PresentationInfo& presentation_info,
// PresentationConnectionRemote controller_connection_remote,
// PresentationConnectionReceiver receiver_connection_receiver) {
// presentation_receiver_remote_->OnReceiverConnectionAvailable(
// blink::mojom::PresentationInfo::From(presentation_info),
// std::move(controller_connection_remote),
// std::move(receiver_connection_receiver));
// }
//
// Send message from controlling/receiver frame to receiver/controlling frame:
//
// |target_connection_|: member variable of mojo::PendingRemote<T> for
// blink::PresentationConnection type, referring to
// remote PresentationConnectionProxy object on
// receiver/controlling frame.
// |message|: Text message to be sent.
// PresentationConnctionPtr::SendString(
// const blink::WebString& message) {
// target_connection_->OnMessage(
// blink::mojom::PresentationConnectionMessage::NewMessage(
// message.Utf8()),
// base::BindOnce(&OnMessageReceived));
// }
//
// A controller or receiver leaves the local presentation (e.g., due to
// navigation) by unregistering themselves from LocalPresentation object.
//
// When the receiver is no longer associated with a local presentation, it
// shall unregister itself with LocalPresentationManager. Unregistration
// will prevent additional controllers from establishing a connection with the
// receiver:
//
// In receiver's PSImpl::Reset() {
// local_presentation_manager->
// OnLocalPresentationReceiverTerminated(presentation_id);
// }
//
// This class is not thread safe. All functions must be invoked on the UI
// thread. All callbacks passed into this class will also be invoked on UI
// thread.
class LocalPresentationManager : public KeyedService {
public:
// Used by
// LocalPresentationManagerFactory::BuildServiceInstanceForBrowserContext.
LocalPresentationManager();
LocalPresentationManager(const LocalPresentationManager&) = delete;
LocalPresentationManager& operator=(const LocalPresentationManager&) = delete;
~LocalPresentationManager() override;
// Registers controller PresentationConnectionPtr to presentation with
// |presentation_id| and |render_frame_id|.
// Creates a new presentation if no presentation with |presentation_id|
// exists.
// |controller_connection_remote|, |receiver_connection_receiver|: Not owned
// by this class. Ownership is transferred to presentation receiver via
// |receiver_callback| passed below.
virtual void RegisterLocalPresentationController(
const blink::mojom::PresentationInfo& presentation_info,
const content::GlobalRenderFrameHostId& render_frame_id,
mojo::PendingRemote<blink::mojom::PresentationConnection>
controller_connection_remote,
mojo::PendingReceiver<blink::mojom::PresentationConnection>
receiver_connection_receiver,
const MediaRoute& route);
// Unregisters controller PresentationConnectionPtr to presentation with
// |presentation_id|, |render_frame_id|. It does nothing if there is no
// controller that matches the provided arguments. It removes presentation
// that matches the arguments if the presentation has no |receiver_callback|
// and any other pending controller.
virtual void UnregisterLocalPresentationController(
const std::string& presentation_id,
const content::GlobalRenderFrameHostId& render_frame_id);
// Registers |receiver_callback| and set |receiver_web_contents| to
// presentation with |presentation_info|.
virtual void OnLocalPresentationReceiverCreated(
const blink::mojom::PresentationInfo& presentation_info,
const content::ReceiverConnectionAvailableCallback& receiver_callback,
content::WebContents* receiver_web_contents);
// Unregisters ReceiverConnectionAvailableCallback associated with
// |presentation_id|.
virtual void OnLocalPresentationReceiverTerminated(
const std::string& presentation_id);
// Returns true if this class has a local presentation with
// |presentation_id|.
virtual bool IsLocalPresentation(const std::string& presentation_id);
// Returns true if this class has a local presentation with |web_contents|.
virtual bool IsLocalPresentation(content::WebContents* web_contents);
// Returns nullptr if |presentation_id| is not associated with a local
// presentation.
virtual const MediaRoute* GetRoute(const std::string& presentation_id);
private:
// Represents a local presentation registered with
// LocalPresentationManager. Contains callback to the receiver to inform
// it of new connections established from a controller. Contains set of
// controllers registered to LocalPresentationManager before corresponding
// receiver.
class LocalPresentation {
public:
explicit LocalPresentation(
const blink::mojom::PresentationInfo& presentation_info);
LocalPresentation(const LocalPresentation&) = delete;
LocalPresentation& operator=(const LocalPresentation&) = delete;
~LocalPresentation();
// Register controller with |render_frame_id|. If |receiver_callback_| has
// been set, invoke |receiver_callback_| with |controller_connection_remote|
// and |receiver_connection_receiver| as parameter, else creates a
// ControllerConnection object with |controller_connection_remote| and
// |receiver_connection_receiver|, and store it in |pending_controllers_|
// map.
void RegisterController(
const content::GlobalRenderFrameHostId& render_frame_id,
mojo::PendingRemote<blink::mojom::PresentationConnection>
controller_connection_remote,
mojo::PendingReceiver<blink::mojom::PresentationConnection>
receiver_connection_receiver,
const MediaRoute& route);
// Unregister controller with |render_frame_id|. Do nothing if there is no
// pending controller with |render_frame_id|.
void UnregisterController(
const content::GlobalRenderFrameHostId& render_frame_id);
// Register |receiver_callback| and set |receiver_web_contents| to current
// local_presentation object. For each controller in |pending_controllers_|
// map, invoke |receiver_callback| with controller as parameter. Clear
// |pending_controllers_| map afterwards.
void RegisterReceiver(
const content::ReceiverConnectionAvailableCallback& receiver_callback,
content::WebContents* receiver_web_contents);
private:
friend class LocalPresentationManagerTest;
friend class LocalPresentationManager;
// Returns false if receiver_callback_ is null and there are no pending
// controllers.
bool IsValid() const;
const blink::mojom::PresentationInfo presentation_info_;
std::optional<MediaRoute> route_;
raw_ptr<content::WebContents, DanglingUntriaged> receiver_web_contents_ =
nullptr;
// Callback to invoke whenever a receiver connection is available.
content::ReceiverConnectionAvailableCallback receiver_callback_;
// Stores controller information.
// |controller_connection_remote|: mojo::PendingRemote<T> to
// blink::PresentationConnection object in controlling frame;
// |receiver_connection_receiver|: mojo::PendingReceiver<T> to be bind to
// blink::PresentationConnection object in receiver frame.
struct ControllerConnection {
public:
ControllerConnection(
mojo::PendingRemote<blink::mojom::PresentationConnection>
controller_connection_remote,
mojo::PendingReceiver<blink::mojom::PresentationConnection>
receiver_connection_receiver);
~ControllerConnection();
mojo::PendingRemote<blink::mojom::PresentationConnection>
controller_connection_remote;
mojo::PendingReceiver<blink::mojom::PresentationConnection>
receiver_connection_receiver;
};
// Contains ControllerConnection objects registered via
// |RegisterController()| before |receiver_callback_| is set.
std::unordered_map<content::GlobalRenderFrameHostId,
std::unique_ptr<ControllerConnection>,
content::GlobalRenderFrameHostIdHasher>
pending_controllers_;
};
private:
friend class LocalPresentationManagerTest;
friend class MockLocalPresentationManager;
FRIEND_TEST_ALL_PREFIXES(ControllerPresentationServiceDelegateImplTest,
ConnectToLocalPresentation);
using LocalPresentationMap =
std::map<std::string, std::unique_ptr<LocalPresentation>>;
// Creates a local presentation with |presentation_info|.
LocalPresentation* GetOrCreateLocalPresentation(
const blink::mojom::PresentationInfo& presentation_info);
// Maps from presentation ID to LocalPresentation.
LocalPresentationMap local_presentations_;
THREAD_CHECKER(thread_checker_);
};
} // namespace media_router
#endif // COMPONENTS_MEDIA_ROUTER_BROWSER_PRESENTATION_LOCAL_PRESENTATION_MANAGER_H_