blob: 7232667866792ce8be9d75decd76ccdc0c74acc5 [file] [log] [blame]
// Copyright 2019 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 CHROME_BROWSER_MEDIA_ROUTER_PROVIDERS_CAST_CAST_SESSION_CLIENT_H_
#define CHROME_BROWSER_MEDIA_ROUTER_PROVIDERS_CAST_CAST_SESSION_CLIENT_H_
#include <memory>
#include <string>
#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/values.h"
#include "chrome/browser/media/router/providers/cast/cast_internal_message_util.h"
#include "chrome/common/media_router/mojo/media_router.mojom.h"
#include "chrome/common/media_router/providers/cast/cast_media_source.h"
#include "components/cast_channel/cast_message_handler.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "third_party/blink/public/mojom/presentation/presentation.mojom.h"
#include "url/origin.h"
namespace media_router {
class CastActivityRecord;
class DataDecoder;
// Represents a Cast SDK client connection to a Cast session. This class
// contains PresentationConnection Mojo pipes to send and receive messages
// from/to the corresponding SDK client hosted in a presentation controlling
// frame in Blink.
class CastSessionClient {
public:
CastSessionClient(const std::string& client_id,
const url::Origin& origin,
int tab_id);
CastSessionClient(const CastSessionClient&) = delete;
CastSessionClient& operator=(const CastSessionClient&) = delete;
virtual ~CastSessionClient();
const std::string& client_id() const { return client_id_; }
const base::Optional<std::string>& session_id() const { return session_id_; }
const url::Origin& origin() const { return origin_; }
int tab_id() const { return tab_id_; }
// Initializes the PresentationConnection Mojo message pipes and returns the
// handles of the two pipes to be held by Blink. Also transitions the
// connection state to CONNECTED. This method can only be called once, and
// must be called before |SendMessageToClient()|.
virtual mojom::RoutePresentationConnectionPtr Init() = 0;
// Sends |message| to the Cast SDK client in Blink.
virtual void SendMessageToClient(
blink::mojom::PresentationConnectionMessagePtr message) = 0;
// Sends a media status message to the client. If |request_id| is given, it
// is used to look up the sequence number of a previous request, which is
// included in the outgoing message.
virtual void SendMediaStatusToClient(const base::Value& media_status,
base::Optional<int> request_id) = 0;
// Changes the PresentationConnection state to CLOSED/TERMINATED and resets
// PresentationConnection message pipes.
virtual void CloseConnection(
blink::mojom::PresentationConnectionCloseReason close_reason) = 0;
virtual void TerminateConnection() = 0;
// Tests whether the specified origin and tab ID match this session's origin
// and tab ID to the extent required by this sesssion's auto-join policy.
// Depending on the value of |auto_join_policy_|, |origin|, |tab_id|, or both
// may be ignored.
//
// TODO(jrw): It appears the real purpose of this method is to detect whether
// this session was created by an auto-join request, but auto-joining isn't
// implemented yet. This comment should probably be updated once auto-join is
// implemented and I've verified this method does what I think it does.
// Alternatively, it might make more sense to record at session creation time
// whether a particular session was created by an auto-join request, in which
// case I believe this method would no longer be needed.
virtual bool MatchesAutoJoinPolicy(url::Origin origin, int tab_id) const = 0;
virtual void SendErrorCodeToClient(
int sequence_number,
CastInternalMessage::ErrorCode error_code,
base::Optional<std::string> description) = 0;
// NOTE: This is current only called from SendErrorCodeToClient, but based on
// the old code this method based on, it seems likely it will have other
// callers once error handling for the Cast MRP is more fleshed out.
virtual void SendErrorToClient(int sequence_number, base::Value error) = 0;
private:
std::string client_id_;
base::Optional<std::string> session_id_;
// The origin and tab ID parameters originally passed to the CreateRoute
// method of the MediaRouteProvider Mojo interface.
url::Origin origin_;
int tab_id_;
};
class CastSessionClientFactoryForTest {
public:
virtual std::unique_ptr<CastSessionClient> MakeClientForTest(
const std::string& client_id,
const url::Origin& origin,
int tab_id) = 0;
};
// TODO(jrw): Move to a separate file.
class CastSessionClientImpl : public CastSessionClient,
public blink::mojom::PresentationConnection {
public:
CastSessionClientImpl(const std::string& client_id,
const url::Origin& origin,
int tab_id,
AutoJoinPolicy auto_join_policy,
DataDecoder* data_decoder,
CastActivityRecord* activity);
~CastSessionClientImpl() override;
// CastSessionClient implementation
mojom::RoutePresentationConnectionPtr Init() override;
// TODO(jrw): Remove redundant "ToClient" in the name of this and other
// methods.
void SendMessageToClient(
blink::mojom::PresentationConnectionMessagePtr message) override;
void SendMediaStatusToClient(const base::Value& media_status,
base::Optional<int> request_id) override;
void CloseConnection(
blink::mojom::PresentationConnectionCloseReason close_reason) override;
void TerminateConnection() override;
bool MatchesAutoJoinPolicy(url::Origin origin, int tab_id) const override;
void SendErrorCodeToClient(int sequence_number,
CastInternalMessage::ErrorCode error_code,
base::Optional<std::string> description) override;
void SendErrorToClient(int sequence_number, base::Value error) override;
// blink::mojom::PresentationConnection implementation
void OnMessage(
blink::mojom::PresentationConnectionMessagePtr message) override;
// Blink does not initiate state change or close using PresentationConnection.
// Instead, |PresentationService::Close/TerminateConnection| is used.
void DidChangeState(
blink::mojom::PresentationConnectionState state) override {}
void DidClose(
blink::mojom::PresentationConnectionCloseReason reason) override;
private:
void HandleParsedClientMessage(base::Value message);
void HandleV2ProtocolMessage(const CastInternalMessage& cast_message);
// Resets the PresentationConnection Mojo message pipes.
void TearDownPresentationConnection();
// Sends a response to the client indicating that a particular request
// succeeded or failed.
void SendResultResponse(int sequence_number, cast_channel::Result result);
const AutoJoinPolicy auto_join_policy_;
DataDecoder* const data_decoder_;
CastActivityRecord* const activity_;
// The maximum number of pending media requests, used to prevent memory leaks.
// Normally the number of pending requests should be fairly small, but each
// entry only consumes 2*sizeof(int) bytes, so the upper limit is set fairly
// high.
static constexpr std::size_t kMaxPendingMediaRequests = 1024;
// Maps internal, locally-generated request IDs to sequence numbers from cast
// messages received from the client. Used to set an appropriate
// sequenceNumber field in outgoing messages so a client can associate a media
// status message with a previous request.
//
// TODO(jrw): Investigate whether this mapping is really necessary, or if
// sequence numbers can be used directly without generating request IDs.
base::flat_map<int, int> pending_media_requests_;
// Binding for the PresentationConnection in Blink to receive incoming
// messages and respond to state changes.
mojo::Binding<blink::mojom::PresentationConnection> connection_binding_;
// Mojo message pipe to PresentationConnection in Blink to send messages and
// initiate state changes.
blink::mojom::PresentationConnectionPtr connection_;
base::WeakPtrFactory<CastSessionClientImpl> weak_ptr_factory_;
};
} // namespace media_router
#endif // CHROME_BROWSER_MEDIA_ROUTER_PROVIDERS_CAST_CAST_SESSION_CLIENT_H_