1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef COMPONENTS_CAST_CHANNEL_CAST_MESSAGE_HANDLER_H_
6 #define COMPONENTS_CAST_CHANNEL_CAST_MESSAGE_HANDLER_H_
8 #include "base/callback_list.h"
9 #include "base/containers/flat_map.h"
10 #include "base/containers/flat_set.h"
11 #include "base/gtest_prod_util.h"
12 #include "base/macros.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/sequence_checker.h"
15 #include "base/time/tick_clock.h"
16 #include "base/token.h"
17 #include "base/values.h"
18 #include "components/cast_channel/cast_message_util.h"
19 #include "components/cast_channel/cast_socket.h"
21 namespace service_manager {
25 namespace cast_channel {
27 class CastSocketService;
29 template <typename CallbackType>
30 struct PendingRequest {
32 PendingRequest(int request_id,
33 CallbackType callback,
34 const base::TickClock* clock)
35 : request_id(request_id),
36 callback(std::move(callback)),
37 timeout_timer(clock) {}
39 virtual ~PendingRequest() = default;
42 CallbackType callback;
43 base::OneShotTimer timeout_timer;
46 // |app_id|: ID of app the result is for.
47 // |result|: Availability result from the receiver.
48 using GetAppAvailabilityCallback =
49 base::OnceCallback<void(const std::string& app_id,
50 GetAppAvailabilityResult result)>;
52 // Represents an app availability request to a Cast sink.
53 struct GetAppAvailabilityRequest
54 : public PendingRequest<GetAppAvailabilityCallback> {
56 GetAppAvailabilityRequest(int request_id,
57 GetAppAvailabilityCallback callback,
58 const base::TickClock* clock,
59 const std::string& app_id);
60 ~GetAppAvailabilityRequest() override;
62 // App ID of the request.
66 // Represents an app launch request to a Cast sink.
67 using LaunchSessionCallback =
68 base::OnceCallback<void(LaunchSessionResponse response)>;
69 using LaunchSessionRequest = PendingRequest<LaunchSessionCallback>;
71 enum class Result { kOk, kFailed };
72 using ResultCallback = base::OnceCallback<void(Result result)>;
74 // Represents an app stop request to a Cast sink.
75 using StopSessionRequest = PendingRequest<ResultCallback>;
77 // Reresents request for a sink to set its volume level.
78 using SetVolumeRequest = PendingRequest<ResultCallback>;
80 // Represents a virtual connection on a cast channel. A virtual connection is
81 // given by a source and destination ID pair, and must be created before
82 // messages can be sent. Virtual connections are managed by CastMessageHandler.
83 struct VirtualConnection {
84 VirtualConnection(int channel_id,
85 const std::string& source_id,
86 const std::string& destination_id);
89 bool operator<(const VirtualConnection& other) const;
91 // ID of cast channel.
94 // Source ID (e.g. sender-0).
95 std::string source_id;
97 // Destination ID (e.g. receiver-0).
98 std::string destination_id;
101 struct InternalMessage {
102 InternalMessage(CastMessageType type, base::Value message);
105 CastMessageType type;
109 // Default timeout amount for requests waiting for a response.
110 constexpr base::TimeDelta kRequestTimeout = base::TimeDelta::FromSeconds(5);
112 // Handles messages that are sent between this browser instance and the Cast
113 // devices connected to it. This class also manages virtual connections (VCs)
114 // with each connected Cast device and ensures a proper VC exists before the
115 // message is sent. This makes the concept of VC transparent to the client.
116 // This class may be created on any sequence, but other methods (including
117 // destructor) must be run on the same sequence that CastSocketService runs on.
118 class CastMessageHandler : public CastSocket::Observer {
122 virtual ~Observer() = default;
123 virtual void OnAppMessage(int channel_id, const CastMessage& message) {}
124 virtual void OnInternalMessage(int channel_id,
125 const InternalMessage& message) {}
128 // |connector|: Connector to be used for data_decoder service. The connector
129 // must not be bound to any thread.
130 // |data_decoder_batch_id|: Batch ID used for data_decoder service.
131 CastMessageHandler(CastSocketService* socket_service,
132 std::unique_ptr<service_manager::Connector> connector,
133 const base::Token& data_decoder_batch_id,
134 const std::string& user_agent,
135 const std::string& browser_version,
136 const std::string& locale);
137 ~CastMessageHandler() override;
139 // Ensures a virtual connection exists for (|source_id|, |destination_id|) on
140 // the device given by |channel_id|, sending a virtual connection request to
141 // the device if necessary. Although a virtual connection is automatically
142 // created when sending a message, a caller may decide to create it beforehand
143 // in order to receive messages sooner.
144 virtual void EnsureConnection(int channel_id,
145 const std::string& source_id,
146 const std::string& destination_id);
148 // Sends an app availability for |app_id| to the device given by |socket|.
149 // |callback| is always invoked asynchronously, and will be invoked when a
150 // response is received, or if the request timed out. No-ops if there is
151 // already a pending request with the same socket and app ID.
152 virtual void RequestAppAvailability(CastSocket* socket,
153 const std::string& app_id,
154 GetAppAvailabilityCallback callback);
156 // Sends a receiver status request to the socket given by |channel_id|.
157 virtual void RequestReceiverStatus(int channel_id);
159 // Sends a broadcast message containing |app_ids| and |request| to the socket
160 // given by |channel_id|.
161 virtual void SendBroadcastMessage(int channel_id,
162 const std::vector<std::string>& app_ids,
163 const BroadcastRequest& request);
165 // Requests a session launch for |app_id| on the device given by |channel_id|.
166 // |callback| will be invoked with the response or with a timed out result if
167 // no response comes back before |launch_timeout|.
168 virtual void LaunchSession(int channel_id,
169 const std::string& app_id,
170 base::TimeDelta launch_timeout,
171 LaunchSessionCallback callback);
173 // Stops the session given by |session_id| on the device given by
174 // |channel_id|. |callback| will be invoked with the result of the stop
176 virtual void StopSession(int channel_id,
177 const std::string& session_id,
178 ResultCallback callback);
180 // Sends |message| to the device given by |channel_id|. The caller may use
181 // this method to forward app messages from the SDK client to the device. It
182 // is invalid to call this method with a message in one of the Cast internal
183 // message namespaces.
184 virtual Result SendAppMessage(int channel_id, const CastMessage& message);
186 // Sends a media command |body|. Returns the ID of the request that is sent to
187 // the receiver. It is invalid to call this with a message body that is not a
188 // media command. Returns |base::nullopt| if |channel_id| is invalid.
190 // Note: This API is designed to return a request ID instead of taking a
191 // callback. This is because a MEDIA_STATUS message from the receiver can be
192 // the response to a media command from a client. Thus when we get a
193 // MEDIA_STATUS message, we need to be able to (1) broadcast the message to
194 // all clients and (2) make sure the client that sent the media command
195 // receives the message only once *and* in the form of a response (by setting
196 // the sequenceNumber on the message).
197 virtual base::Optional<int> SendMediaRequest(
199 const base::Value& body,
200 const std::string& source_id,
201 const std::string& destination_id);
203 // Sends a set system volume command |body|. |callback| will be invoked
204 // with the result of the operation. It is invalid to call this with
205 // a message body that is not a volume request.
206 virtual Result SendSetVolumeRequest(int channel_id,
207 const base::Value& body,
208 const std::string& source_id,
209 ResultCallback callback);
211 void AddObserver(Observer* observer);
212 void RemoveObserver(Observer* observer);
214 // CastSocket::Observer implementation.
215 void OnError(const CastSocket& socket, ChannelError error_state) override;
216 void OnMessage(const CastSocket& socket, const CastMessage& message) override;
217 void OnReadyStateChanged(const CastSocket& socket) override;
219 const std::string& sender_id() const { return sender_id_; }
222 friend class CastMessageHandlerTest;
223 FRIEND_TEST_ALL_PREFIXES(CastMessageHandlerTest, HandlePendingRequest);
225 // Set of PendingRequests for a CastSocket.
226 class PendingRequests {
231 // Returns true if this is the first request for the given app ID.
232 bool AddAppAvailabilityRequest(
233 std::unique_ptr<GetAppAvailabilityRequest> request);
235 bool AddLaunchRequest(std::unique_ptr<LaunchSessionRequest> request,
236 base::TimeDelta timeout);
237 bool AddStopRequest(std::unique_ptr<StopSessionRequest> request);
238 void AddVolumeRequest(std::unique_ptr<SetVolumeRequest> request);
239 void HandlePendingRequest(int request_id, const base::Value& response);
242 // Invokes the pending callback associated with |request_id| with a timed
244 void AppAvailabilityTimedOut(int request_id);
245 void LaunchSessionTimedOut(int request_id);
246 void StopSessionTimedOut(int request_id);
247 void SetVolumeTimedOut(int request_id);
249 // Requests are kept in the order in which they were created.
250 std::vector<std::unique_ptr<GetAppAvailabilityRequest>>
251 pending_app_availability_requests_;
252 std::unique_ptr<LaunchSessionRequest> pending_launch_session_request_;
253 std::unique_ptr<StopSessionRequest> pending_stop_session_request_;
254 base::flat_map<int, std::unique_ptr<SetVolumeRequest>>
255 pending_volume_requests_by_id_;
258 // Used internally to generate the next ID to use in a request type message.
259 // Returns a positive integer (unless the counter overflows).
260 int NextRequestId() { return ++next_request_id_; }
262 PendingRequests* GetOrCreatePendingRequests(int channel_id);
264 // Sends |message| over |socket|. This also ensures the necessary virtual
265 // connection exists before sending the message.
266 void SendCastMessage(CastSocket* socket, const CastMessage& message);
268 // Sends a virtual connection request to |socket| if the virtual connection
269 // for (|source_id|, |destination_id|) does not yet exist.
270 void DoEnsureConnection(CastSocket* socket,
271 const std::string& source_id,
272 const std::string& destination_id);
274 // Callback for CastTransport::SendMessage.
275 void OnMessageSent(int result);
277 void HandleCastInternalMessage(int channel_id,
278 const std::string& source_id,
279 const std::string& destination_id,
280 std::unique_ptr<base::Value> payload);
282 // Set of pending requests keyed by socket ID.
283 base::flat_map<int, std::unique_ptr<PendingRequests>> pending_requests_;
285 // Source ID used for platform messages. The suffix is randomized to
286 // distinguish it from other Cast senders on the same network.
287 const std::string sender_id_;
289 // Used for parsing JSON payload from receivers.
290 std::unique_ptr<service_manager::Connector> connector_;
291 const base::Token data_decoder_batch_id_;
293 // User agent and browser version strings included in virtual connection
295 const std::string user_agent_;
296 const std::string browser_version_;
298 // Locale string used for session launch requests.
299 const std::string locale_;
301 int next_request_id_ = 0;
303 base::ObserverList<Observer>::Unchecked observers_;
305 // Set of virtual connections opened to receivers.
306 base::flat_set<VirtualConnection> virtual_connections_;
308 CastSocketService* const socket_service_;
310 // Non-owned pointer to TickClock used for request timeouts.
311 const base::TickClock* const clock_;
313 SEQUENCE_CHECKER(sequence_checker_);
314 base::WeakPtrFactory<CastMessageHandler> weak_ptr_factory_;
316 DISALLOW_COPY_AND_ASSIGN(CastMessageHandler);
319 } // namespace cast_channel
321 #endif // COMPONENTS_CAST_CHANNEL_CAST_MESSAGE_HANDLER_H_