blob: d9322ff38455345fbd82adac85af2ddfc1966504 [file] [log] [blame]
// Copyright 2017 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 "components/cast_channel/cast_socket_service.h"
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "components/cast_channel/cast_socket.h"
#include "components/cast_channel/libcast_socket_service.h"
#include "components/cast_channel/logger.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
using content::BrowserThread;
namespace cast_channel {
const base::Feature kLibcastSocketService{"LibcastSocketService",
base::FEATURE_DISABLED_BY_DEFAULT};
// static
CastSocketService* CastSocketService::GetInstance() {
static CastSocketService* service =
base::FeatureList::IsEnabled(kLibcastSocketService)
? static_cast<CastSocketService*>(new LibcastSocketService())
: static_cast<CastSocketService*>(new CastSocketServiceImpl());
return service;
}
CastSocketService::CastSocketService()
: logger_(new Logger()),
// IO thread's task runner is used because of:
// (1) ChromeURLRequestContextGetter::GetURLRequestContext, which is
// called by CastMediaSinkServiceImpl, must run on IO thread. (2) Parts of
// CastChannel extension API functions run on IO thread.
task_runner_(content::GetIOThreadTaskRunner({})) {}
CastSocketService::~CastSocketService() = default;
int CastSocketServiceImpl::last_channel_id_ = 0;
CastSocketServiceImpl::CastSocketServiceImpl() = default;
// This is a leaky singleton and the dtor won't be called.
CastSocketServiceImpl::~CastSocketServiceImpl() = default;
CastSocket* CastSocketServiceImpl::AddSocket(
std::unique_ptr<CastSocket> socket) {
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(socket);
int id = ++last_channel_id_;
socket->set_id(id);
auto* socket_ptr = socket.get();
sockets_.insert(std::make_pair(id, std::move(socket)));
return socket_ptr;
}
std::unique_ptr<CastSocket> CastSocketServiceImpl::RemoveSocket(
int channel_id) {
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(channel_id > 0);
auto socket_it = sockets_.find(channel_id);
std::unique_ptr<CastSocket> socket;
if (socket_it != sockets_.end()) {
socket = std::move(socket_it->second);
sockets_.erase(socket_it);
}
return socket;
}
CastSocket* CastSocketServiceImpl::GetSocket(int channel_id) const {
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(channel_id > 0);
const auto& socket_it = sockets_.find(channel_id);
return socket_it == sockets_.end() ? nullptr : socket_it->second.get();
}
CastSocket* CastSocketServiceImpl::GetSocket(
const net::IPEndPoint& ip_endpoint) const {
DCHECK(task_runner_->BelongsToCurrentThread());
auto it = std::find_if(
sockets_.begin(), sockets_.end(),
[&ip_endpoint](
const std::pair<const int, std::unique_ptr<CastSocket>>& pair) {
return pair.second->ip_endpoint() == ip_endpoint;
});
return it == sockets_.end() ? nullptr : it->second.get();
}
void CastSocketServiceImpl::OpenSocket(
NetworkContextGetter network_context_getter,
const CastSocketOpenParams& open_params,
CastSocket::OnOpenCallback open_cb) {
DCHECK(task_runner_->BelongsToCurrentThread());
const net::IPEndPoint& ip_endpoint = open_params.ip_endpoint;
auto* socket = GetSocket(ip_endpoint);
if (!socket) {
// If cast socket does not exist.
if (socket_for_test_) {
socket = AddSocket(std::move(socket_for_test_));
} else {
socket = new CastSocketImpl(network_context_getter, open_params, logger_);
AddSocket(base::WrapUnique(socket));
}
}
for (auto& observer : observers_)
socket->AddObserver(&observer);
socket->Connect(std::move(open_cb));
}
void CastSocketServiceImpl::AddObserver(CastSocket::Observer* observer) {
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(observer);
if (observers_.HasObserver(observer))
return;
observers_.AddObserver(observer);
for (auto& socket_it : sockets_)
socket_it.second->AddObserver(observer);
}
void CastSocketServiceImpl::RemoveObserver(CastSocket::Observer* observer) {
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(observer);
for (auto& socket_it : sockets_)
socket_it.second->RemoveObserver(observer);
observers_.RemoveObserver(observer);
}
} // namespace cast_channel