blob: d1ed28c7f3bf80d9f6a670c8e24c624e212ba848 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromecast/media/audio/audio_output_service/output_connection.h"
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/check.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "chromecast/media/audio/audio_output_service/output_socket.h"
#include "chromecast/net/socket_util.h"
#include "net/base/net_errors.h"
#include "net/socket/stream_socket.h"
namespace chromecast {
namespace media {
namespace audio_output_service {
namespace {
constexpr base::TimeDelta kReconnectDelay = base::Seconds(1);
constexpr int kMaxRetries = 3;
} // namespace
OutputConnection::OutputConnection(
mojo::PendingRemote<mojom::AudioSocketBroker> pending_socket_broker)
: socket_broker_(std::move(pending_socket_broker)) {
DCHECK(socket_broker_.is_connected());
}
OutputConnection::~OutputConnection() = default;
void OutputConnection::Connect() {
DCHECK(!connecting_socket_);
socket_broker_->GetSocketDescriptor(base::BindOnce(
&OutputConnection::OnSocketDescriptor, weak_factory_.GetWeakPtr()));
}
void OutputConnection::OnSocketDescriptor(mojo::PlatformHandle handle) {
if (!handle.is_valid_fd()) {
LOG(ERROR) << "Received invalid socket descriptor.";
HandleConnectResult(net::ERR_FAILED);
return;
}
connecting_socket_ = AdoptUnnamedSocketHandle(handle.TakeFD());
if (!connecting_socket_) {
LOG(ERROR) << "Cannot adopt socket descriptor.";
HandleConnectResult(net::ERR_FAILED);
return;
}
DCHECK(connecting_socket_->IsConnected());
HandleConnectResult(net::OK);
}
void OutputConnection::HandleConnectResult(int result) {
DCHECK_NE(result, net::ERR_IO_PENDING);
if (result == net::OK) {
log_connection_failure_ = true;
retry_count_ = 0;
auto socket = std::make_unique<OutputSocket>(std::move(connecting_socket_));
OnConnected(std::move(socket));
return;
}
base::TimeDelta delay = kReconnectDelay;
if (log_connection_failure_) {
LOG(ERROR) << "Failed to connect to audio output service: " << result;
log_connection_failure_ = false;
delay = base::TimeDelta(); // No reconnect delay on the first failure.
}
connecting_socket_.reset();
if (++retry_count_ > kMaxRetries) {
OnConnectionFailed();
return;
}
base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&OutputConnection::Connect, weak_factory_.GetWeakPtr()),
delay);
}
} // namespace audio_output_service
} // namespace media
} // namespace chromecast