blob: 74ca7f3a6c4e859c132f0328b6a9857774ad4441 [file] [log] [blame]
// 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.
#include <openssl/x509.h>
#include <functional>
#include <memory>
#include <string>
#include <vector>
#include "absl/types/optional.h"
#include "cast/common/channel/cast_message_handler.h"
#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/sender/public/sender_socket_factory.h"
#include "cast/standalone_sender/looping_file_sender.h"
#include "cast/streaming/environment.h"
#include "cast/streaming/sender_session.h"
#include "platform/api/scoped_wake_lock.h"
#include "platform/api/serial_delete_ptr.h"
#include "platform/base/error.h"
#include "platform/base/interface_info.h"
#include "platform/impl/task_runner.h"
namespace Json {
class Value;
namespace openscreen {
namespace cast {
// A single-use sender-side Cast Agent that manages the workflow for a mirroring
// session, casting the content from a local file indefinitely. After being
// constructed and having its Connect() method called, the LoopingFileCastAgent
// steps through the following workflow:
// 1. Waits for a CastSocket representing a successful connection to a remote
// Cast Receiver's agent.
// 2. Sends a LAUNCH request to the Cast Receiver to start its Mirroring App.
// 3. Waits for a RECEIVER_STATUS message from the Receiver indicating launch
// success, or a LAUNCH_ERROR.
// 4. Once launched, message routing (i.e., a VirtualConnection) is requested,
// for messaging between the SenderSession (locally) and the remote
// Mirroring App.
// 5. Once message routing is established, the local SenderSession is created
// and begins the mirroring-specific OFFER/ANSWER messaging to negotiate
// the streaming parameters.
// 6. Streaming commences.
// If at any point an error occurs, the LoopingFileCastAgent executes a clean
// shut-down (both locally, and with the remote Cast Receiver), and then invokes
// the ShutdownCallback that was passed to the constructor.
// Normal shutdown happens when either:
// 1. Receiver-side, the Mirroring App is shut down. This will cause the
// ShutdownCallback passed to the constructor to be invoked.
// 2. This LoopingFileCastAgent is destroyed (automatic shutdown is part of
// the destruction procedure).
class LoopingFileCastAgent final
: public SenderSocketFactory::Client,
public VirtualConnectionRouter::SocketErrorHandler,
public ConnectionNamespaceHandler::VirtualConnectionPolicy,
public CastMessageHandler,
public SenderSession::Client {
using ShutdownCallback = std::function<void()>;
// |shutdown_callback| is invoked after normal shutdown, whether initiated
// sender- or receiver-side; or, for any fatal error.
LoopingFileCastAgent(TaskRunner* task_runner,
ShutdownCallback shutdown_callback);
struct ConnectionSettings {
// The endpoint of the receiver we wish to connect to.
IPEndpoint receiver_endpoint;
// The path to the file that we want to play.
std::string path_to_file;
// The maximum bitrate. Default value means a reasonable default will be
// selected.
int max_bitrate = 0;
// Whether the stream should include video, or just be audio only.
bool should_include_video = true;
// Whether we should use the hacky RTP stream IDs for legacy android
// receivers, or if we should use the proper values.
bool use_android_rtp_hack = true;
// Connect to a Cast Receiver, and start the workflow to establish a
// mirroring/streaming session. Destroy the LoopingFileCastAgent to shutdown
// and disconnect.
void Connect(ConnectionSettings settings);
// SenderSocketFactory::Client overrides.
void OnConnected(SenderSocketFactory* factory,
const IPEndpoint& endpoint,
std::unique_ptr<CastSocket> socket) override;
void OnError(SenderSocketFactory* factory,
const IPEndpoint& endpoint,
Error error) override;
// VirtualConnectionRouter::SocketErrorHandler overrides.
void OnClose(CastSocket* cast_socket) override;
void OnError(CastSocket* socket, Error error) override;
// ConnectionNamespaceHandler::VirtualConnectionPolicy overrides.
bool IsConnectionAllowed(
const VirtualConnection& virtual_conn) const override;
// CastMessageHandler overrides.
void OnMessage(VirtualConnectionRouter* router,
CastSocket* socket,
::cast::channel::CastMessage message) override;
// Returns the Cast application ID for either A/V mirroring or audio-only
// mirroring, as configured by the ConnectionSettings.
const char* GetMirroringAppId() const;
// Called by OnMessage() to determine whether the Cast Receiver has launched
// or unlaunched the Mirroring App. If the former, a VirtualConnection is
// requested. Otherwise, the workflow is aborted and Shutdown() is called.
void HandleReceiverStatus(const Json::Value& status);
// Called by the |connection_handler_| after message routing to the Cast
// Receiver's Mirroring App has been established (if |success| is true).
void OnRemoteMessagingOpened(bool success);
// Once we have a connection to the receiver we need to create and start
// a sender session. This method results in the OFFER/ANSWER exchange
// being completed and a session should be started.
void CreateAndStartSession();
// SenderSession::Client overrides.
void OnNegotiated(const SenderSession* session,
SenderSession::ConfiguredSenders senders,
capture_recommendations) override;
void OnError(const SenderSession* session, Error error) override;
// Helper for stopping the current session, and/or unwinding a remote
// connection request (pre-session). This ensures LoopingFileCastAgent is in a
// terminal shutdown state.
void Shutdown();
// Member variables set as part of construction.
TaskRunner* const task_runner_;
ShutdownCallback shutdown_callback_;
VirtualConnectionRouter router_;
ConnectionNamespaceHandler connection_handler_;
SenderSocketFactory socket_factory_;
std::unique_ptr<TlsConnectionFactory> connection_factory_;
CastSocketMessagePort message_port_;
// Counter for distinguishing request messages sent to the Cast Receiver.
int next_request_id_ = 1;
// Initialized by Connect().
absl::optional<ConnectionSettings> connection_settings_;
SerialDeletePtr<ScopedWakeLock> wake_lock_;
// If non-empty, this is the sessionId associated with the Cast Receiver
// application that this LoopingFileCastAgent launched.
std::string app_session_id_;
// This is set once LoopingFileCastAgent has requested to start messaging to
// the mirroring app on a Cast Receiver.
absl::optional<VirtualConnection> remote_connection_;
// Member variables set while a streaming to the mirroring app on a Cast
// Receiver.
std::unique_ptr<Environment> environment_;
std::unique_ptr<SenderSession> current_session_;
std::unique_ptr<LoopingFileSender> file_sender_;
} // namespace cast
} // namespace openscreen