blob: afab409266727ceb7ad69aa8d65eaf002d3f79f4 [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/device_tracker.h"
#include <fcntl.h>
#include <memory>
#include <utility>
#include <base/bind.h>
#include <base/location.h>
#include "midis/seq_handler.h"
namespace midis {
DeviceTracker::DeviceTracker() {}
bool DeviceTracker::InitDeviceTracker() {
seq_handler_ = std::make_unique<SeqHandler>(
base::Bind(&DeviceTracker::AddDevice, base::Unretained(this)),
base::Bind(&DeviceTracker::RemoveDevice, base::Unretained(this)),
base::Bind(&DeviceTracker::HandleReceiveData, base::Unretained(this)),
base::Bind(&DeviceTracker::IsDevicePresent, base::Unretained(this)),
base::Bind(&DeviceTracker::IsPortPresent, base::Unretained(this)));
if (!seq_handler_->InitSeq()) {
LOG(ERROR) << "Failed to start snd_seq tracker.";
return false;
}
return true;
}
void DeviceTracker::AddDevice(std::unique_ptr<Device> dev) {
uint32_t device_id = GenerateDeviceId(dev->GetCard(), dev->GetDeviceNum());
devices_.emplace(device_id, std::move(dev));
NotifyObserversDeviceAddedOrRemoved(*devices_.at(device_id), true);
}
void DeviceTracker::RemoveDevice(uint32_t sys_num, uint32_t dev_num) {
auto it = devices_.find(GenerateDeviceId(sys_num, dev_num));
if (it != devices_.end()) {
NotifyObserversDeviceAddedOrRemoved(*it->second, false);
devices_.erase(it);
LOG(INFO) << "Device: " << sys_num << "," << dev_num << " removed.";
} else {
LOG(ERROR) << "Device: " << sys_num << "," << dev_num << " not listed.";
}
}
void DeviceTracker::ListDevices(
std::vector<arc::mojom::MidisDeviceInfoPtr>* list) {
for (const auto& dev : devices_) {
arc::mojom::MidisDeviceInfoPtr dev_info =
arc::mojom::MidisDeviceInfo::New();
dev_info->card = dev.second->GetCard();
dev_info->device_num = dev.second->GetDeviceNum();
dev_info->num_subdevices = dev.second->GetNumSubdevices();
dev_info->name = dev.second->GetName();
dev_info->manufacturer = dev.second->GetManufacturer();
list->emplace_back(std::move(dev_info));
}
}
void DeviceTracker::AddDeviceObserver(Observer* obs) {
observer_list_.AddObserver(obs);
}
void DeviceTracker::RemoveDeviceObserver(Observer* obs) {
observer_list_.RemoveObserver(obs);
}
void DeviceTracker::NotifyObserversDeviceAddedOrRemoved(const Device& dev,
bool added) {
for (Observer& observer : observer_list_)
observer.OnDeviceAddedOrRemoved(dev, added);
}
base::ScopedFD DeviceTracker::AddClientToReadSubdevice(uint32_t sys_num,
uint32_t device_num,
uint32_t subdevice_num,
uint32_t client_id) {
Device* device = FindDevice(sys_num, device_num);
if (device) {
return device->AddClientToReadSubdevice(client_id, subdevice_num);
}
return base::ScopedFD();
}
void DeviceTracker::RemoveClientFromDevice(uint32_t client_id,
uint32_t sys_num,
uint32_t device_num) {
Device* device = FindDevice(sys_num, device_num);
if (device) {
device->RemoveClientFromDevice(client_id);
}
}
void DeviceTracker::RemoveClientFromDevices(uint32_t client_id) {
for (auto& id_device_pair : devices_) {
id_device_pair.second->RemoveClientFromDevice(client_id);
}
}
void DeviceTracker::HandleReceiveData(uint32_t card_id,
uint32_t device_id,
uint32_t port_id,
const char* buffer,
size_t buf_len) {
Device* device = FindDevice(card_id, device_id);
if (device) {
device->HandleReceiveData(buffer, port_id, buf_len);
}
}
bool DeviceTracker::IsDevicePresent(uint32_t card_id, uint32_t device_id) {
Device* device = FindDevice(card_id, device_id);
if (device) {
return true;
}
return false;
}
bool DeviceTracker::IsPortPresent(uint32_t card_id,
uint32_t device_id,
uint32_t port_id) {
Device* device = FindDevice(card_id, device_id);
if (!device) {
return false;
}
// TODO(pmalani): Check |port_caps_| instead.
if (port_id >= device->GetNumSubdevices()) {
return false;
}
return true;
}
Device* DeviceTracker::FindDevice(uint32_t card_id, uint32_t device_id) const {
auto it = devices_.find(GenerateDeviceId(card_id, device_id));
if (it != devices_.end()) {
return it->second.get();
}
return nullptr;
}
} // namespace midis