blob: 791029a34358fae6bdc32fe9f4622c23060e3507 [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 "cast/standalone_receiver/cast_agent.h"
#include <fstream>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include "absl/strings/str_cat.h"
#include "cast/common/channel/cast_socket_message_port.h"
#include "cast/common/channel/message_util.h"
#include "cast/streaming/constants.h"
#include "cast/streaming/offer_messages.h"
#include "platform/base/tls_credentials.h"
#include "platform/base/tls_listen_options.h"
#include "util/json/json_serialization.h"
#include "util/osp_logging.h"
#include "util/trace_logging.h"
namespace openscreen {
namespace cast {
namespace {
constexpr int kDefaultMaxBacklogSize = 64;
const TlsListenOptions kDefaultListenOptions{kDefaultMaxBacklogSize};
} // namespace
CastAgent::CastAgent(
TaskRunner* task_runner,
const InterfaceInfo& interface,
DeviceAuthNamespaceHandler::CredentialsProvider* credentials_provider,
TlsCredentials tls_credentials)
: task_runner_(task_runner),
credentials_provider_(credentials_provider),
tls_credentials_(std::move(tls_credentials)) {
const IPAddress address = interface.GetIpAddressV4()
? interface.GetIpAddressV4()
: interface.GetIpAddressV6();
OSP_CHECK(address);
environment_ = std::make_unique<Environment>(
&Clock::now, task_runner_,
IPEndpoint{address, kDefaultCastStreamingPort});
receive_endpoint_ = IPEndpoint{address, kDefaultCastPort};
}
CastAgent::~CastAgent() = default;
Error CastAgent::Start() {
TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneReceiver);
OSP_CHECK(!current_session_);
task_runner_->PostTask([this] {
wake_lock_ = ScopedWakeLock::Create(task_runner_);
auth_handler_ = MakeSerialDelete<DeviceAuthNamespaceHandler>(
task_runner_, credentials_provider_);
router_ = MakeSerialDelete<VirtualConnectionRouter>(task_runner_,
&connection_manager_);
message_port_ =
MakeSerialDelete<CastSocketMessagePort>(task_runner_, router_.get());
router_->AddHandlerForLocalId(kPlatformReceiverId, auth_handler_.get());
socket_factory_ = MakeSerialDelete<ReceiverSocketFactory>(
task_runner_, this, router_.get());
connection_factory_ = SerialDeletePtr<TlsConnectionFactory>(
task_runner_,
TlsConnectionFactory::CreateFactory(socket_factory_.get(), task_runner_)
.release());
connection_factory_->SetListenCredentials(tls_credentials_);
connection_factory_->Listen(receive_endpoint_, kDefaultListenOptions);
OSP_LOG_INFO << "Listening for connections at: " << receive_endpoint_;
});
return Error::None();
}
Error CastAgent::Stop() {
task_runner_->PostTask([this] {
router_.reset();
connection_factory_.reset();
controller_.reset();
current_session_.reset();
socket_factory_.reset();
wake_lock_.reset();
});
return Error::None();
}
void CastAgent::OnConnected(ReceiverSocketFactory* factory,
const IPEndpoint& endpoint,
std::unique_ptr<CastSocket> socket) {
TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneReceiver);
if (current_session_) {
OSP_LOG_WARN << "Already connected, dropping peer at: " << endpoint;
return;
}
OSP_LOG_INFO << "Received connection from peer at: " << endpoint;
message_port_->SetSocket(socket->GetWeakPtr());
router_->TakeSocket(this, std::move(socket));
controller_ =
std::make_unique<StreamingPlaybackController>(task_runner_, this);
current_session_ = std::make_unique<ReceiverSession>(
controller_.get(), environment_.get(), message_port_.get(),
ReceiverSession::Preferences{});
}
void CastAgent::OnError(ReceiverSocketFactory* factory, Error error) {
OSP_LOG_ERROR << "Cast agent received socket factory error: " << error;
StopCurrentSession();
}
void CastAgent::OnClose(CastSocket* cast_socket) {
OSP_VLOG << "Cast agent socket closed.";
StopCurrentSession();
}
void CastAgent::OnError(CastSocket* socket, Error error) {
OSP_LOG_ERROR << "Cast agent received socket error: " << error;
StopCurrentSession();
}
// Currently we don't do anything with the receiver output--the session
// is automatically linked to the playback controller when it is constructed, so
// we don't actually have to interface with the receivers. If we end up caring
// about the receiver configurations we will have to handle OnNegotiated here.
void CastAgent::OnNegotiated(const ReceiverSession* session,
ReceiverSession::ConfiguredReceivers receivers) {
OSP_VLOG << "Successfully negotiated with sender.";
}
void CastAgent::OnReceiversDestroying(const ReceiverSession* session,
ReceiversDestroyingReason reason) {
const auto GetReasoning = [&] {
switch (reason) {
case kEndOfSession:
return " at end of session.";
case kRenegotiated:
return ", to be replaced with new ones.";
}
return "";
};
OSP_VLOG << "Receiver instances destroying" << GetReasoning();
}
// Currently, we just kill the session if an error is encountered.
void CastAgent::OnError(const ReceiverSession* session, Error error) {
OSP_LOG_ERROR << "Cast agent received receiver session error: " << error;
StopCurrentSession();
}
void CastAgent::OnPlaybackError(StreamingPlaybackController* controller,
Error error) {
OSP_LOG_ERROR << "Cast agent received playback error: " << error;
StopCurrentSession();
}
void CastAgent::StopCurrentSession() {
current_session_.reset();
controller_.reset();
router_->CloseSocket(message_port_->GetSocketId());
message_port_->SetSocket(nullptr);
}
} // namespace cast
} // namespace openscreen