blob: 2bdc3e9029b4cc9b4334bf8576ffe27930700b7d [file] [log] [blame]
// 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.
#ifndef CONTENT_BROWSER_PRESENTATION_PRESENTATION_SERVICE_IMPL_H_
#define CONTENT_BROWSER_PRESENTATION_PRESENTATION_SERVICE_IMPL_H_
#include <deque>
#include <map>
#include <memory>
#include <string>
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/containers/hash_tables.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/presentation_screen_availability_listener.h"
#include "content/public/browser/presentation_service_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/frame_navigate_params.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "third_party/WebKit/public/platform/modules/presentation/presentation.mojom.h"
namespace content {
struct FrameNavigateParams;
struct LoadCommittedDetails;
struct PresentationSessionMessage;
class RenderFrameHost;
// Implementation of Mojo PresentationService.
// It handles Presentation API requests coming from Blink / renderer process
// and delegates the requests to the embedder's media router via
// PresentationServiceDelegate.
// An instance of this class tied to a RenderFrameHost and listens to events
// related to the RFH via implementing WebContentsObserver.
// This class is instantiated on-demand via Mojo's ConnectToRemoteService
// from the renderer when the first presentation API request is handled.
class CONTENT_EXPORT PresentationServiceImpl
: public NON_EXPORTED_BASE(blink::mojom::PresentationService),
public WebContentsObserver,
public PresentationServiceDelegate::Observer {
public:
using NewSessionCallback =
base::Callback<void(blink::mojom::PresentationSessionInfoPtr,
blink::mojom::PresentationErrorPtr)>;
~PresentationServiceImpl() override;
// Static factory method to create an instance of PresentationServiceImpl.
// |render_frame_host|: The RFH the instance is associated with.
// |request|: The instance will be bound to this request. Used for Mojo setup.
static void CreateMojoService(
RenderFrameHost* render_frame_host,
mojo::InterfaceRequest<blink::mojom::PresentationService> request);
private:
friend class PresentationServiceImplTest;
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, Reset);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, DidNavigateThisFrame);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
DidNavigateOtherFrame);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, ThisRenderFrameDeleted);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
OtherRenderFrameDeleted);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, DelegateFails);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
SetDefaultPresentationUrl);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
SetSameDefaultPresentationUrl);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ClearDefaultPresentationUrl);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ListenForDefaultSessionStart);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ListenForDefaultSessionStartAfterSet);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
DefaultSessionStartReset);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ReceiveSessionMessagesAfterReset);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
MaxPendingStartSessionRequests);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
MaxPendingJoinSessionRequests);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ListenForConnectionStateChange);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ListenForConnectionClose);
// Maximum number of pending JoinSession requests at any given time.
static const int kMaxNumQueuedSessionRequests = 10;
using SessionMessagesCallback =
base::Callback<void(mojo::Array<blink::mojom::SessionMessagePtr>)>;
using SendSessionMessageCallback = base::Callback<void(bool)>;
// Listener implementation owned by PresentationServiceImpl. An instance of
// this is created when PresentationRequest.getAvailability() is resolved.
// The instance receives screen availability results from the embedder and
// propagates results back to PresentationServiceImpl.
class CONTENT_EXPORT ScreenAvailabilityListenerImpl
: public PresentationScreenAvailabilityListener {
public:
ScreenAvailabilityListenerImpl(
const std::string& availability_url,
PresentationServiceImpl* service);
~ScreenAvailabilityListenerImpl() override;
// PresentationScreenAvailabilityListener implementation.
std::string GetAvailabilityUrl() const override;
void OnScreenAvailabilityChanged(bool available) override;
void OnScreenAvailabilityNotSupported() override;
private:
const std::string availability_url_;
PresentationServiceImpl* const service_;
};
// Ensures the provided NewSessionCallback is invoked exactly once
// before it goes out of scope.
class NewSessionCallbackWrapper {
public:
explicit NewSessionCallbackWrapper(
const NewSessionCallback& callback);
~NewSessionCallbackWrapper();
void Run(blink::mojom::PresentationSessionInfoPtr session,
blink::mojom::PresentationErrorPtr error);
private:
NewSessionCallback callback_;
DISALLOW_COPY_AND_ASSIGN(NewSessionCallbackWrapper);
};
// |render_frame_host|: The RFH this instance is associated with.
// |web_contents|: The WebContents to observe.
// |delegate|: Where Presentation API requests are delegated to. Not owned
// by this class.
PresentationServiceImpl(
RenderFrameHost* render_frame_host,
WebContents* web_contents,
PresentationServiceDelegate* delegate);
// PresentationService implementation.
void SetDefaultPresentationURL(const mojo::String& url) override;
void SetClient(blink::mojom::PresentationServiceClientPtr client) override;
void ListenForScreenAvailability(const mojo::String& url) override;
void StopListeningForScreenAvailability(const mojo::String& url) override;
void StartSession(
const mojo::String& presentation_url,
const NewSessionCallback& callback) override;
void JoinSession(
const mojo::String& presentation_url,
const mojo::String& presentation_id,
const NewSessionCallback& callback) override;
void SendSessionMessage(blink::mojom::PresentationSessionInfoPtr session_info,
blink::mojom::SessionMessagePtr session_message,
const SendSessionMessageCallback& callback) override;
void CloseConnection(const mojo::String& presentation_url,
const mojo::String& presentation_id) override;
void Terminate(const mojo::String& presentation_url,
const mojo::String& presentation_id) override;
void ListenForSessionMessages(
blink::mojom::PresentationSessionInfoPtr session) override;
// Creates a binding between this object and |request|.
void Bind(mojo::InterfaceRequest<blink::mojom::PresentationService> request);
// WebContentsObserver override.
void DidNavigateAnyFrame(
content::RenderFrameHost* render_frame_host,
const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) override;
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
void WebContentsDestroyed() override;
// PresentationServiceDelegate::Observer
void OnDelegateDestroyed() override;
// Passed to embedder's implementation of PresentationServiceDelegate for
// later invocation when default presentation has started.
void OnDefaultPresentationStarted(
const PresentationSessionInfo& session_info);
// Finds the callback from |pending_join_session_cbs_| using
// |request_session_id|.
// If it exists, invoke it with |session| and |error|, then erase it from
// |pending_join_session_cbs_|.
// Returns true if the callback was found.
bool RunAndEraseJoinSessionMojoCallback(
int request_session_id,
blink::mojom::PresentationSessionInfoPtr session,
blink::mojom::PresentationErrorPtr error);
// Removes all listeners and resets default presentation URL on this instance
// and informs the PresentationServiceDelegate of such.
void Reset();
// These functions are bound as base::Callbacks and passed to
// embedder's implementation of PresentationServiceDelegate for later
// invocation.
void OnStartSessionSucceeded(
int request_session_id,
const PresentationSessionInfo& session_info);
void OnStartSessionError(
int request_session_id,
const PresentationError& error);
void OnJoinSessionSucceeded(
int request_session_id,
const PresentationSessionInfo& session_info);
void OnJoinSessionError(
int request_session_id,
const PresentationError& error);
void OnSendMessageCallback(bool sent);
// Calls to |delegate_| to start listening for state changes for |connection|.
// State changes will be returned via |OnConnectionStateChanged|.
void ListenForConnectionStateChange(
const PresentationSessionInfo& connection);
// Passed to embedder's implementation of PresentationServiceDelegate for
// later invocation when session messages arrive.
void OnSessionMessages(
const content::PresentationSessionInfo& session,
const ScopedVector<PresentationSessionMessage>& messages,
bool pass_ownership);
// Associates a JoinSession |callback| with a unique request ID and
// stores it in a map.
// Returns a positive value on success.
int RegisterJoinSessionCallback(const NewSessionCallback& callback);
// Invoked by the embedder's PresentationServiceDelegate when a
// PresentationConnection's state has changed.
void OnConnectionStateChanged(
const PresentationSessionInfo& connection,
const PresentationConnectionStateChangeInfo& info);
// Returns true if this object is associated with |render_frame_host|.
bool FrameMatches(content::RenderFrameHost* render_frame_host) const;
// Embedder-specific delegate to forward Presentation requests to.
// May be null if embedder does not support Presentation API.
PresentationServiceDelegate* delegate_;
// Proxy to the PresentationServiceClient to send results (e.g., screen
// availability) to.
blink::mojom::PresentationServiceClientPtr client_;
std::string default_presentation_url_;
using ScreenAvailabilityListenerMap =
std::map<std::string, std::unique_ptr<ScreenAvailabilityListenerImpl>>;
ScreenAvailabilityListenerMap screen_availability_listeners_;
// For StartSession requests.
// Set to a positive value when a StartSession request is being processed.
int start_session_request_id_;
std::unique_ptr<NewSessionCallbackWrapper> pending_start_session_cb_;
// For JoinSession requests.
base::hash_map<int, linked_ptr<NewSessionCallbackWrapper>>
pending_join_session_cbs_;
// RAII binding of |this| to an Presentation interface request.
// The binding is removed when binding_ is cleared or goes out of scope.
std::unique_ptr<mojo::Binding<blink::mojom::PresentationService>> binding_;
// There can be only one send message request at a time.
std::unique_ptr<SendSessionMessageCallback> send_message_callback_;
std::unique_ptr<SessionMessagesCallback> on_session_messages_callback_;
// ID of the RenderFrameHost this object is associated with.
int render_process_id_;
int render_frame_id_;
// NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<PresentationServiceImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PresentationServiceImpl);
};
} // namespace content
#endif // CONTENT_BROWSER_PRESENTATION_PRESENTATION_SERVICE_IMPL_H_