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