You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
7.2 KiB
173 lines
7.2 KiB
// 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_
|