• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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.
4 
5 #ifndef CAST_RECEIVER_APPLICATION_AGENT_H_
6 #define CAST_RECEIVER_APPLICATION_AGENT_H_
7 
8 #include <map>
9 #include <memory>
10 #include <string>
11 #include <vector>
12 
13 #include "cast/common/channel/cast_socket_message_port.h"
14 #include "cast/common/channel/connection_namespace_handler.h"
15 #include "cast/common/channel/virtual_connection_router.h"
16 #include "cast/common/public/cast_socket.h"
17 #include "cast/receiver/channel/device_auth_namespace_handler.h"
18 #include "cast/receiver/public/receiver_socket_factory.h"
19 #include "platform/api/serial_delete_ptr.h"
20 #include "platform/api/task_runner.h"
21 #include "platform/base/error.h"
22 #include "platform/base/ip_address.h"
23 #include "util/json/json_value.h"
24 
25 namespace openscreen {
26 namespace cast {
27 
28 class CastSocket;
29 
30 // A service accepting CastSocket connections, and providing a minimal
31 // implementation of the CastV2 application control protocol to launch receiver
32 // applications and route messages to/from them.
33 //
34 // Workflow: One or more Applications are registered under this ApplicationAgent
35 // (e.g., a "mirroring" app). Later, a ReceiverSocketFactory (external to this
36 // class) will listen and establish CastSocket connections, and then pass
37 // CastSockets to this ApplicationAgent via the OnConnect() method. As each
38 // connection is made, device authentication will take place. Then, Cast V2
39 // application messages asking about application availability are received and
40 // responded to, based on what Applications are registered. Finally, the remote
41 // may request the LAUNCH of an Application (and later a STOP).
42 //
43 // In the meantime, this ApplicationAgent broadcasts RECEIVER_STATUS about what
44 // application is running. In addition, it attempts to launch an "idle screen"
45 // Application whenever no other Application is running. The "idle screen"
46 // Application is usually some kind of screen saver or wallpaper/clock display.
47 // Registering the "idle screen" Application is optional, and if it's not
48 // registered, then nothing will be running during idle periods.
49 class ApplicationAgent final
50     : public ReceiverSocketFactory::Client,
51       public CastMessageHandler,
52       public ConnectionNamespaceHandler::VirtualConnectionPolicy,
53       public VirtualConnectionRouter::SocketErrorHandler {
54  public:
55   class Application {
56    public:
57     // Returns the one or more application IDs that are supported. This list
58     // must not mutate while the Application is registered.
59     virtual const std::vector<std::string>& GetAppIds() const = 0;
60 
61     // Launches the application and returns true if successful. |app_id| is the
62     // specific ID that was used to launch the app, and |app_params| is a
63     // pass-through for any arbitrary app-specfic structure (or null if not
64     // provided). If the Application wishes to send/receive messages, it uses
65     // the provided |message_port| and must call MessagePort::SetClient() before
66     // any flow will occur.
67     virtual bool Launch(const std::string& app_id,
68                         const Json::Value& app_params,
69                         MessagePort* message_port) = 0;
70 
71     // These reflect the current state of the application, and the data is used
72     // to populate RECEIVER_STATUS messages.
73     virtual std::string GetSessionId() = 0;
74     virtual std::string GetDisplayName() = 0;
75     virtual std::vector<std::string> GetSupportedNamespaces() = 0;
76 
77     // Stops the application, if running.
78     virtual void Stop() = 0;
79 
80    protected:
81     virtual ~Application();
82   };
83 
84   ApplicationAgent(
85       TaskRunner* task_runner,
86       DeviceAuthNamespaceHandler::CredentialsProvider* credentials_provider);
87 
88   ~ApplicationAgent() final;
89 
90   // Return the interface by which the CastSocket inbound traffic is delivered
91   // into this agent and any running Applications.
cast_socket_client()92   CastSocket::Client* cast_socket_client() { return &router_; }
93 
94   // Registers an Application for launching by this agent. |app| must outlive
95   // this ApplicationAgent, or until UnregisterApplication() is called.
96   void RegisterApplication(Application* app,
97                            bool auto_launch_for_idle_screen = false);
98   void UnregisterApplication(Application* app);
99 
100   // Stops the given |app| if it is the one currently running. This is used by
101   // applications that encounter "exit" conditions where they need to STOP
102   // (e.g., due to timeout of user activity, end of media playback, or fatal
103   // errors).
104   void StopApplicationIfRunning(Application* app);
105 
106  private:
107   // ReceiverSocketFactory::Client overrides.
108   void OnConnected(ReceiverSocketFactory* factory,
109                    const IPEndpoint& endpoint,
110                    std::unique_ptr<CastSocket> socket) final;
111   void OnError(ReceiverSocketFactory* factory, Error error) final;
112 
113   // CastMessageHandler overrides.
114   void OnMessage(VirtualConnectionRouter* router,
115                  CastSocket* socket,
116                  ::cast::channel::CastMessage message) final;
117 
118   // ConnectionNamespaceHandler::VirtualConnectionPolicy overrides.
119   bool IsConnectionAllowed(const VirtualConnection& virtual_conn) const final;
120 
121   // VirtualConnectionRouter::SocketErrorHandler overrides.
122   void OnClose(CastSocket* socket) final;
123   void OnError(CastSocket* socket, Error error) final;
124 
125   // OnMessage() delegates to these to take action for each |request|. Each of
126   // these returns a non-empty response message if a reply should be sent back
127   // to the requestor.
128   Json::Value HandlePing();
129   Json::Value HandleGetAppAvailability(const Json::Value& request);
130   Json::Value HandleGetStatus(const Json::Value& request);
131   Json::Value HandleLaunch(const Json::Value& request, CastSocket* socket);
132   Json::Value HandleStop(const Json::Value& request);
133   Json::Value HandleInvalidCommand(const Json::Value& request);
134 
135   // Stops the currently-running Application and attempts to launch the
136   // Application referred to by |app_id|. If this fails, the "idle screen"
137   // Application will be automatically launched as a failure fall-back. |socket|
138   // is non-null only when the application switch was caused by a remote LAUNCH
139   // request.
140   Error SwitchToApplication(std::string app_id,
141                             const Json::Value& app_params,
142                             CastSocket* socket);
143 
144   // Stops the currently-running Application and launches the "idle screen."
145   void GoIdle();
146 
147   // Populates the given |message| object with the RECEIVER_STATUS fields,
148   // reflecting the currently-launched app (if any), and a fake volume level
149   // status.
150   void PopulateReceiverStatus(Json::Value* message);
151 
152   // Broadcasts new RECEIVER_STATUS to all endpoints. This is called after an
153   // Application LAUNCH or STOP.
154   void BroadcastReceiverStatus();
155 
156   TaskRunner* const task_runner_;
157   DeviceAuthNamespaceHandler auth_handler_;
158   VirtualConnectionRouter router_;
159   ConnectionNamespaceHandler connection_handler_;
160 
161   std::map<std::string, Application*> registered_applications_;
162   Application* idle_screen_app_ = nullptr;
163 
164   CastSocketMessagePort message_port_;
165   Application* launched_app_ = nullptr;
166   std::string launched_via_app_id_;
167 };
168 
169 }  // namespace cast
170 }  // namespace openscreen
171 
172 #endif  // CAST_RECEIVER_APPLICATION_AGENT_H_
173