blob: 916c7b062c00d5de2f3df9c565438c4964d4b32d [file] [log] [blame]
// Copyright 2017 The Chromium OS 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 <midis/client.h>
#include <sys/socket.h>
#include <utility>
#include <base/bind.h>
#include <base/posix/eintr_wrapper.h>
#include <mojo/public/cpp/system/platform_handle.h>
#include <mojo/public/cpp/system/handle.h>
#include "midis/constants.h"
namespace midis {
Client::Client(DeviceTracker* device_tracker,
uint32_t client_id,
ClientDeletionCallback del_cb,
arc::mojom::MidisServerRequest request,
arc::mojom::MidisClientPtr client_ptr)
: device_tracker_(device_tracker),
client_id_(client_id),
del_cb_(del_cb),
client_ptr_(std::move(client_ptr)),
binding_(this, std::move(request)),
weak_factory_(this) {
device_tracker_->AddDeviceObserver(this);
binding_.set_connection_error_handler(
base::Bind(&Client::TriggerClientDeletion, weak_factory_.GetWeakPtr()));
}
Client::~Client() {
LOG(INFO) << "Deleting client: " << client_id_;
device_tracker_->RemoveDeviceObserver(this);
}
void Client::TriggerClientDeletion() {
brillo::MessageLoop::TaskId ret_id = brillo::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(del_cb_, client_id_));
if (ret_id == brillo::MessageLoop::kTaskIdNull) {
LOG(ERROR) << "Couldn't schedule the client deletion callback!";
}
}
void Client::OnDeviceAddedOrRemoved(const Device& dev, bool added) {
arc::mojom::MidisDeviceInfoPtr dev_info = arc::mojom::MidisDeviceInfo::New();
dev_info->card = dev.GetCard();
dev_info->device_num = dev.GetDeviceNum();
dev_info->num_subdevices = dev.GetNumSubdevices();
dev_info->name = dev.GetName();
dev_info->manufacturer = dev.GetManufacturer();
if (added) {
client_ptr_->OnDeviceAdded(std::move(dev_info));
} else {
client_ptr_->OnDeviceRemoved(std::move(dev_info));
}
}
void Client::ListDevices(ListDevicesCallback callback) {
// Get all the device information from device_tracker.
std::vector<arc::mojom::MidisDeviceInfoPtr> device_list;
device_tracker_->ListDevices(&device_list);
std::move(callback).Run(std::move(device_list));
}
void Client::RequestPort(arc::mojom::MidisRequestPtr request,
RequestPortCallback callback) {
mojo::ScopedHandle handle = CreateRequestPortFD(
request->card, request->device_num, request->subdevice_num);
std::move(callback).Run(std::move(handle));
}
void Client::RequestPortDeprecated(arc::mojom::MidisRequestPtr request,
RequestPortDeprecatedCallback callback) {
mojo::ScopedHandle handle = CreateRequestPortFD(
request->card, request->device_num, request->subdevice_num);
if (!handle.is_valid()) {
return;
}
std::move(callback).Run(std::move(handle));
}
void Client::CloseDevice(arc::mojom::MidisRequestPtr request) {
device_tracker_->RemoveClientFromDevice(client_id_, request->card,
request->device_num);
}
mojo::ScopedHandle Client::CreateRequestPortFD(uint32_t card,
uint32_t device,
uint32_t subdevice) {
base::ScopedFD clientfd = device_tracker_->AddClientToReadSubdevice(
card, device, subdevice, client_id_);
if (!clientfd.is_valid()) {
LOG(ERROR) << "CreateRequestPortFD failed for device: " << device;
// We don't delete the client here, because this could mean an issue with
// the device h/w.
return mojo::ScopedHandle();
}
return mojo::WrapPlatformFile(clientfd.release());
}
} // namespace midis