blob: a8c82d981a373393938c5afd6f1db1133146eb4d [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 <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <base/files/file_path.h>
#include <base/files/scoped_file.h>
#include <base/memory/weak_ptr.h>
#include <brillo/message_loops/message_loop.h>
#include <gtest/gtest_prod.h>
#include "midis/ports.h"
namespace midis {
class FileHandler;
class SubDeviceClientFdHolder;
// Class which holds information related to a MIDI device.
// We use the name variable (derived from the ioctl) as a basis
// to arrive at an identifier.
class Device {
Device(const std::string& name,
const std::string& manufacturer,
uint32_t card,
uint32_t device,
uint32_t num_subdevices,
uint32_t flags,
InPort::SubscribeCallback in_sub_cb,
OutPort::SubscribeCallback out_sub_cb,
InPort::DeletionCallback in_del_cb,
OutPort::DeletionCallback out_del_cb,
OutPort::SendMidiDataCallback send_data_cb,
const std::map<uint32_t, unsigned int>& port_caps);
const std::string& GetName() const { return name_; }
const std::string& GetManufacturer() const { return manufacturer_; }
uint32_t GetCard() const { return card_; }
uint32_t GetDeviceNum() const { return device_; }
uint32_t GetNumSubdevices() const { return num_subdevices_; }
uint32_t GetFlags() const { return flags_; }
// Adds a client which wishes to read data on a particular subdevice
// This function should return one end of a pipe file descriptor
// This will be sent back to the client, and it can listen on that for events.
// A device can be bidirectional, and so we should also have a watch on the
// pipe FD so that we can read MIDI events and send them to the MIDI
// H/W.
// Returns:
// A valid base::ScopedFD on success.
// An empty base::ScopedFD otherwise.
base::ScopedFD AddClientToReadSubdevice(uint32_t client_id,
uint32_t subdevice_id);
// Callback function which is invoked by the FileHandler object when data is
// received *from* a particular subdevice of a MIDI H/W device or external
// client.
void HandleReceiveData(const char* buffer,
uint32_t subdevice,
size_t buf_len) const;
// This function is called when a Client is removed from the service for
// orderly or unorderly reasons (like disconnection). The client is removed
// from all subdevices.
void RemoveClientFromDevice(uint32_t client_id);
friend class ClientTest;
friend class DeviceTest;
FRIEND_TEST(ClientTest, AddClientAndReceiveMessages);
FRIEND_TEST(DeviceTest, TestDevicePortCreation);
// This function initializes subscriptions for all the listed ports.
// As the ports are initialized, they get stored in |in_ports_| and
// |out_ports_| respectively.
bool StartMonitoring();
// Removes all the port subscriptions which were started during
// StartMontoring(). This function is called if : a. Something has gone wrong
// with the Device monitor and we need to bail b. Something has gone wrong
// while adding the device. c. During a graceful shutdown.
void StopMonitoring();
// Callback function which is invoked by SubDeviceClientFdHolder object when
// data is received from client to be sent *to* a particular subdevice.
void WriteClientDataToDevice(uint32_t subdevice_id,
const uint8_t* buffer,
size_t buf_len);
std::string name_;
std::string manufacturer_;
// TODO(pmalani): Unused, so remove
uint32_t card_;
uint32_t device_;
uint32_t num_subdevices_;
// TODO(pmalani): Unused, so remove.
uint32_t flags_;
// This data-structure performs the following map:
// subdevice ---> (client_1, pipefd_1), (client_2, pipefd_2), ...., (client_n,
// pipefd_n).
std::map<uint32_t, std::vector<std::unique_ptr<SubDeviceClientFdHolder>>>
// Callbacks to be run by the InPort and OutPort objects.
InPort::SubscribeCallback in_sub_cb_;
OutPort::SubscribeCallback out_sub_cb_;
InPort::DeletionCallback in_del_cb_;
OutPort::DeletionCallback out_del_cb_;
OutPort::SendMidiDataCallback send_data_cb_;
// Map storing all the valid seq port_ids and the corresponding caps.
std::map<uint32_t, unsigned int> port_caps_;
// This data structure maps the port_id to corresponding InPort we create.
std::map<uint32_t, std::unique_ptr<InPort>> in_ports_;
// This data structure maps the port_id to corresponding OutPort we create.
std::map<uint32_t, std::unique_ptr<OutPort>> out_ports_;
base::WeakPtrFactory<Device> weak_factory_;
} // namespace midis
#endif // MIDIS_DEVICE_H_