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