blob: 4e25e5014d46d53c7cde370dd45cad5c2386348e [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/midi/midi_manager_usb.h"
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <string>
#include <utility>
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "media/midi/midi_service.h"
#include "media/midi/usb_midi_device.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace midi {
namespace {
using mojom::PortState;
using mojom::Result;
template<typename T, size_t N>
std::vector<T> ToVector(const T (&array)[N]) {
return std::vector<T>(array, array + N);
}
class Logger {
public:
Logger() = default;
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
~Logger() = default;
void AddLog(const std::string& message) { log_ += message; }
std::string TakeLog() {
std::string result;
result.swap(log_);
return result;
}
private:
std::string log_;
};
class FakeUsbMidiDevice : public UsbMidiDevice {
public:
explicit FakeUsbMidiDevice(Logger* logger) : logger_(logger) {}
FakeUsbMidiDevice(const FakeUsbMidiDevice&) = delete;
FakeUsbMidiDevice& operator=(const FakeUsbMidiDevice&) = delete;
~FakeUsbMidiDevice() override = default;
std::vector<uint8_t> GetDescriptors() override {
logger_->AddLog("UsbMidiDevice::GetDescriptors\n");
return descriptors_;
}
std::string GetManufacturer() override { return manufacturer_; }
std::string GetProductName() override { return product_name_; }
std::string GetDeviceVersion() override { return device_version_; }
void Send(int endpoint_number, const std::vector<uint8_t>& data) override {
logger_->AddLog("UsbMidiDevice::Send ");
logger_->AddLog(base::StringPrintf("endpoint = %d data =",
endpoint_number));
for (size_t i = 0; i < data.size(); ++i)
logger_->AddLog(base::StringPrintf(" 0x%02x", data[i]));
logger_->AddLog("\n");
}
void SetDescriptors(const std::vector<uint8_t> descriptors) {
descriptors_ = descriptors;
}
void SetManufacturer(const std::string& manufacturer) {
manufacturer_ = manufacturer;
}
void SetProductName(const std::string& product_name) {
product_name_ = product_name;
}
void SetDeviceVersion(const std::string& device_version) {
device_version_ = device_version;
}
private:
std::vector<uint8_t> descriptors_;
std::string manufacturer_;
std::string product_name_;
std::string device_version_;
raw_ptr<Logger> logger_;
};
class FakeMidiManagerClient : public MidiManagerClient {
public:
explicit FakeMidiManagerClient(Logger* logger)
: complete_start_session_(false),
result_(Result::NOT_SUPPORTED),
logger_(logger) {}
FakeMidiManagerClient(const FakeMidiManagerClient&) = delete;
FakeMidiManagerClient& operator=(const FakeMidiManagerClient&) = delete;
~FakeMidiManagerClient() override = default;
void AddInputPort(const mojom::PortInfo& info) override {
input_ports_.push_back(info);
}
void AddOutputPort(const mojom::PortInfo& info) override {
output_ports_.push_back(info);
}
void SetInputPortState(uint32_t port_index, PortState state) override {}
void SetOutputPortState(uint32_t port_index, PortState state) override {}
void CompleteStartSession(Result result) override {
complete_start_session_ = true;
result_ = result;
}
void ReceiveMidiData(uint32_t port_index,
const uint8_t* data,
size_t size,
base::TimeTicks timestamp) override {
logger_->AddLog("MidiManagerClient::ReceiveMidiData ");
logger_->AddLog(
base::StringPrintf("usb:port_index = %d data =", port_index));
for (size_t i = 0; i < size; ++i)
logger_->AddLog(base::StringPrintf(" 0x%02x", data[i]));
logger_->AddLog("\n");
}
void AccumulateMidiBytesSent(size_t size) override {
logger_->AddLog("MidiManagerClient::AccumulateMidiBytesSent ");
// Windows has no "%zu".
logger_->AddLog(base::StringPrintf("size = %u\n",
static_cast<unsigned>(size)));
}
void Detach() override {}
bool complete_start_session_;
Result result_;
std::vector<mojom::PortInfo> input_ports_;
std::vector<mojom::PortInfo> output_ports_;
private:
raw_ptr<Logger> logger_;
};
class TestUsbMidiDeviceFactory : public UsbMidiDevice::Factory {
public:
TestUsbMidiDeviceFactory() = default;
TestUsbMidiDeviceFactory(const TestUsbMidiDeviceFactory&) = delete;
TestUsbMidiDeviceFactory& operator=(const TestUsbMidiDeviceFactory&) = delete;
~TestUsbMidiDeviceFactory() override = default;
void EnumerateDevices(UsbMidiDeviceDelegate* device,
Callback callback) override {
callback_ = std::move(callback);
}
Callback callback_;
};
class MidiManagerUsbForTesting : public MidiManagerUsb {
public:
MidiManagerUsbForTesting(
std::unique_ptr<UsbMidiDevice::Factory> device_factory,
MidiService* service)
: MidiManagerUsb(service, std::move(device_factory)) {}
MidiManagerUsbForTesting(const MidiManagerUsbForTesting&) = delete;
MidiManagerUsbForTesting& operator=(const MidiManagerUsbForTesting&) = delete;
~MidiManagerUsbForTesting() override = default;
void CallCompleteInitialization(Result result) {
CompleteInitialization(result);
base::RunLoop run_loop;
run_loop.RunUntilIdle();
}
};
class MidiManagerFactoryForTesting : public midi::MidiService::ManagerFactory {
public:
MidiManagerFactoryForTesting() = default;
~MidiManagerFactoryForTesting() override = default;
std::unique_ptr<midi::MidiManager> Create(
midi::MidiService* service) override {
std::unique_ptr<TestUsbMidiDeviceFactory> device_factory =
std::make_unique<TestUsbMidiDeviceFactory>();
device_factory_ = device_factory.get();
std::unique_ptr<MidiManagerUsbForTesting> manager =
std::make_unique<MidiManagerUsbForTesting>(std::move(device_factory),
service);
// |manager| will be owned by the caller MidiService instance, and valid
// while the MidiService instance is running.
// MidiService::Shutdown() or destructor will destruct it, and |manager_|
// get to be invalid after that.
manager_ = manager.get();
return manager;
}
MidiManagerUsb* manager() {
DCHECK(manager_);
return manager_;
}
TestUsbMidiDeviceFactory* device_factory() {
DCHECK(device_factory_);
return device_factory_;
}
private:
// This field is not a raw_ptr<> because it was filtered by the rewriter for:
// #constexpr-ctor-field-initializer
RAW_PTR_EXCLUSION TestUsbMidiDeviceFactory* device_factory_ = nullptr;
// This field is not a raw_ptr<> because it was filtered by the rewriter for:
// #constexpr-ctor-field-initializer
RAW_PTR_EXCLUSION MidiManagerUsbForTesting* manager_ = nullptr;
};
class MidiManagerUsbTest : public ::testing::Test {
public:
MidiManagerUsbTest() {
std::unique_ptr<MidiManagerFactoryForTesting> factory =
std::make_unique<MidiManagerFactoryForTesting>();
factory_ = factory.get();
service_ = std::make_unique<MidiService>(std::move(factory));
}
MidiManagerUsbTest(const MidiManagerUsbTest&) = delete;
MidiManagerUsbTest& operator=(const MidiManagerUsbTest&) = delete;
~MidiManagerUsbTest() override {
service_->Shutdown();
base::RunLoop run_loop;
run_loop.RunUntilIdle();
std::string leftover_logs = logger_.TakeLog();
if (!leftover_logs.empty()) {
ADD_FAILURE() << "Log should be empty: " << leftover_logs;
}
}
protected:
void Initialize() {
client_ = std::make_unique<FakeMidiManagerClient>(&logger_);
service_->StartSession(client_.get());
}
void Finalize() { service_->EndSession(client_.get()); }
bool IsInitializationCallbackInvoked() {
return client_->complete_start_session_;
}
Result GetInitializationResult() { return client_->result_; }
void RunCallbackUntilCallbackInvoked(
bool result, UsbMidiDevice::Devices* devices) {
std::move(factory_->device_factory()->callback_).Run(result, devices);
while (!client_->complete_start_session_) {
base::RunLoop run_loop;
run_loop.RunUntilIdle();
}
}
const std::vector<mojom::PortInfo>& input_ports() {
return client_->input_ports_;
}
const std::vector<mojom::PortInfo>& output_ports() {
return client_->output_ports_;
}
MidiManagerUsb* manager() { return factory_->manager(); }
std::unique_ptr<FakeMidiManagerClient> client_;
Logger logger_;
private:
std::unique_ptr<MidiService> service_; // Must outlive `factory_`.
raw_ptr<MidiManagerFactoryForTesting> factory_;
base::test::SingleThreadTaskEnvironment task_environment_;
};
TEST_F(MidiManagerUsbTest, Initialize) {
std::unique_ptr<FakeUsbMidiDevice> device(new FakeUsbMidiDevice(&logger_));
uint8_t descriptors[] = {
0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, 0x86, 0x1a, 0x2d, 0x75,
0x54, 0x02, 0x00, 0x02, 0x00, 0x01, 0x09, 0x02, 0x75, 0x00, 0x02, 0x01,
0x00, 0x80, 0x30, 0x09, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01, 0x09, 0x04, 0x01,
0x00, 0x02, 0x01, 0x03, 0x00, 0x00, 0x07, 0x24, 0x01, 0x00, 0x01, 0x51,
0x00, 0x06, 0x24, 0x02, 0x01, 0x02, 0x00, 0x06, 0x24, 0x02, 0x01, 0x03,
0x00, 0x06, 0x24, 0x02, 0x02, 0x06, 0x00, 0x09, 0x24, 0x03, 0x01, 0x07,
0x01, 0x06, 0x01, 0x00, 0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x02, 0x01,
0x00, 0x09, 0x24, 0x03, 0x02, 0x05, 0x01, 0x03, 0x01, 0x00, 0x09, 0x05,
0x02, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x06, 0x25, 0x01, 0x02, 0x02,
0x03, 0x09, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x05, 0x25,
0x01, 0x01, 0x07,
};
device->SetDescriptors(ToVector(descriptors));
device->SetManufacturer("vendor1");
device->SetProductName("device1");
device->SetDeviceVersion("1.02");
Initialize();
UsbMidiDevice::Devices devices;
devices.push_back(std::move(device));
EXPECT_FALSE(IsInitializationCallbackInvoked());
RunCallbackUntilCallbackInvoked(true, &devices);
EXPECT_EQ(Result::OK, GetInitializationResult());
ASSERT_EQ(1u, input_ports().size());
EXPECT_EQ("usb:port-0-2", input_ports()[0].id);
EXPECT_EQ("vendor1", input_ports()[0].manufacturer);
EXPECT_EQ("device1", input_ports()[0].name);
EXPECT_EQ("1.02", input_ports()[0].version);
ASSERT_EQ(2u, output_ports().size());
EXPECT_EQ("usb:port-0-0", output_ports()[0].id);
EXPECT_EQ("vendor1", output_ports()[0].manufacturer);
EXPECT_EQ("device1", output_ports()[0].name);
EXPECT_EQ("1.02", output_ports()[0].version);
EXPECT_EQ("usb:port-0-1", output_ports()[1].id);
EXPECT_EQ("vendor1", output_ports()[1].manufacturer);
EXPECT_EQ("device1", output_ports()[1].name);
EXPECT_EQ("1.02", output_ports()[1].version);
ASSERT_TRUE(manager()->input_stream());
std::vector<UsbMidiJack> jacks = manager()->input_stream()->jacks();
ASSERT_EQ(2u, manager()->output_streams().size());
EXPECT_EQ(2u, manager()->output_streams()[0]->jack().jack_id);
EXPECT_EQ(3u, manager()->output_streams()[1]->jack().jack_id);
ASSERT_EQ(1u, jacks.size());
EXPECT_EQ(2, jacks[0].endpoint_number());
EXPECT_EQ("UsbMidiDevice::GetDescriptors\n", logger_.TakeLog());
}
TEST_F(MidiManagerUsbTest, InitializeMultipleDevices) {
std::unique_ptr<FakeUsbMidiDevice> device1(new FakeUsbMidiDevice(&logger_));
std::unique_ptr<FakeUsbMidiDevice> device2(new FakeUsbMidiDevice(&logger_));
uint8_t descriptors[] = {
0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, 0x86, 0x1a, 0x2d, 0x75,
0x54, 0x02, 0x00, 0x02, 0x00, 0x01, 0x09, 0x02, 0x75, 0x00, 0x02, 0x01,
0x00, 0x80, 0x30, 0x09, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01, 0x09, 0x04, 0x01,
0x00, 0x02, 0x01, 0x03, 0x00, 0x00, 0x07, 0x24, 0x01, 0x00, 0x01, 0x51,
0x00, 0x06, 0x24, 0x02, 0x01, 0x02, 0x00, 0x06, 0x24, 0x02, 0x01, 0x03,
0x00, 0x06, 0x24, 0x02, 0x02, 0x06, 0x00, 0x09, 0x24, 0x03, 0x01, 0x07,
0x01, 0x06, 0x01, 0x00, 0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x02, 0x01,
0x00, 0x09, 0x24, 0x03, 0x02, 0x05, 0x01, 0x03, 0x01, 0x00, 0x09, 0x05,
0x02, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x06, 0x25, 0x01, 0x02, 0x02,
0x03, 0x09, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x05, 0x25,
0x01, 0x01, 0x07,
};
device1->SetDescriptors(ToVector(descriptors));
device1->SetManufacturer("vendor1");
device1->SetProductName("device1");
device1->SetDeviceVersion("1.02");
device2->SetDescriptors(ToVector(descriptors));
device2->SetManufacturer("vendor2");
device2->SetProductName("device2");
device2->SetDeviceVersion("98.76");
Initialize();
UsbMidiDevice::Devices devices;
devices.push_back(std::move(device1));
devices.push_back(std::move(device2));
EXPECT_FALSE(IsInitializationCallbackInvoked());
RunCallbackUntilCallbackInvoked(true, &devices);
EXPECT_EQ(Result::OK, GetInitializationResult());
ASSERT_EQ(2u, input_ports().size());
EXPECT_EQ("usb:port-0-2", input_ports()[0].id);
EXPECT_EQ("vendor1", input_ports()[0].manufacturer);
EXPECT_EQ("device1", input_ports()[0].name);
EXPECT_EQ("1.02", input_ports()[0].version);
EXPECT_EQ("usb:port-1-2", input_ports()[1].id);
EXPECT_EQ("vendor2", input_ports()[1].manufacturer);
EXPECT_EQ("device2", input_ports()[1].name);
EXPECT_EQ("98.76", input_ports()[1].version);
ASSERT_EQ(4u, output_ports().size());
EXPECT_EQ("usb:port-0-0", output_ports()[0].id);
EXPECT_EQ("vendor1", output_ports()[0].manufacturer);
EXPECT_EQ("device1", output_ports()[0].name);
EXPECT_EQ("1.02", output_ports()[0].version);
EXPECT_EQ("usb:port-0-1", output_ports()[1].id);
EXPECT_EQ("vendor1", output_ports()[1].manufacturer);
EXPECT_EQ("device1", output_ports()[1].name);
EXPECT_EQ("1.02", output_ports()[1].version);
EXPECT_EQ("usb:port-1-0", output_ports()[2].id);
EXPECT_EQ("vendor2", output_ports()[2].manufacturer);
EXPECT_EQ("device2", output_ports()[2].name);
EXPECT_EQ("98.76", output_ports()[2].version);
EXPECT_EQ("usb:port-1-1", output_ports()[3].id);
EXPECT_EQ("vendor2", output_ports()[3].manufacturer);
EXPECT_EQ("device2", output_ports()[3].name);
EXPECT_EQ("98.76", output_ports()[3].version);
ASSERT_TRUE(manager()->input_stream());
std::vector<UsbMidiJack> jacks = manager()->input_stream()->jacks();
ASSERT_EQ(4u, manager()->output_streams().size());
EXPECT_EQ(2u, manager()->output_streams()[0]->jack().jack_id);
EXPECT_EQ(3u, manager()->output_streams()[1]->jack().jack_id);
ASSERT_EQ(2u, jacks.size());
EXPECT_EQ(2, jacks[0].endpoint_number());
EXPECT_EQ(
"UsbMidiDevice::GetDescriptors\n"
"UsbMidiDevice::GetDescriptors\n",
logger_.TakeLog());
}
TEST_F(MidiManagerUsbTest, InitializeFail) {
Initialize();
EXPECT_FALSE(IsInitializationCallbackInvoked());
RunCallbackUntilCallbackInvoked(false, NULL);
EXPECT_EQ(Result::INITIALIZATION_ERROR, GetInitializationResult());
}
TEST_F(MidiManagerUsbTest, InitializeFailBecauseOfInvalidDescriptors) {
std::unique_ptr<FakeUsbMidiDevice> device(new FakeUsbMidiDevice(&logger_));
uint8_t descriptors[] = {0x04};
device->SetDescriptors(ToVector(descriptors));
Initialize();
UsbMidiDevice::Devices devices;
devices.push_back(std::move(device));
EXPECT_FALSE(IsInitializationCallbackInvoked());
RunCallbackUntilCallbackInvoked(true, &devices);
EXPECT_EQ(Result::INITIALIZATION_ERROR, GetInitializationResult());
EXPECT_EQ("UsbMidiDevice::GetDescriptors\n", logger_.TakeLog());
}
TEST_F(MidiManagerUsbTest, Send) {
Initialize();
std::unique_ptr<FakeUsbMidiDevice> device(new FakeUsbMidiDevice(&logger_));
uint8_t descriptors[] = {
0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, 0x86, 0x1a, 0x2d, 0x75,
0x54, 0x02, 0x00, 0x02, 0x00, 0x01, 0x09, 0x02, 0x75, 0x00, 0x02, 0x01,
0x00, 0x80, 0x30, 0x09, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01, 0x09, 0x04, 0x01,
0x00, 0x02, 0x01, 0x03, 0x00, 0x00, 0x07, 0x24, 0x01, 0x00, 0x01, 0x51,
0x00, 0x06, 0x24, 0x02, 0x01, 0x02, 0x00, 0x06, 0x24, 0x02, 0x01, 0x03,
0x00, 0x06, 0x24, 0x02, 0x02, 0x06, 0x00, 0x09, 0x24, 0x03, 0x01, 0x07,
0x01, 0x06, 0x01, 0x00, 0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x02, 0x01,
0x00, 0x09, 0x24, 0x03, 0x02, 0x05, 0x01, 0x03, 0x01, 0x00, 0x09, 0x05,
0x02, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x06, 0x25, 0x01, 0x02, 0x02,
0x03, 0x09, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x05, 0x25,
0x01, 0x01, 0x07,
};
device->SetDescriptors(ToVector(descriptors));
uint8_t data[] = {
0x90, 0x45, 0x7f, 0xf0, 0x00, 0x01, 0xf7,
};
UsbMidiDevice::Devices devices;
devices.push_back(std::move(device));
EXPECT_FALSE(IsInitializationCallbackInvoked());
RunCallbackUntilCallbackInvoked(true, &devices);
EXPECT_EQ(Result::OK, GetInitializationResult());
ASSERT_EQ(2u, manager()->output_streams().size());
manager()->DispatchSendMidiData(client_.get(), 1, ToVector(data),
base::TimeTicks());
// Since UsbMidiDevice::Send is posted as a task, RunLoop should run to
// invoke the task.
base::RunLoop run_loop;
run_loop.RunUntilIdle();
EXPECT_EQ("UsbMidiDevice::GetDescriptors\n"
"UsbMidiDevice::Send endpoint = 2 data = "
"0x19 0x90 0x45 0x7f "
"0x14 0xf0 0x00 0x01 "
"0x15 0xf7 0x00 0x00\n"
"MidiManagerClient::AccumulateMidiBytesSent size = 7\n",
logger_.TakeLog());
}
TEST_F(MidiManagerUsbTest, SendFromCompromizedRenderer) {
std::unique_ptr<FakeUsbMidiDevice> device(new FakeUsbMidiDevice(&logger_));
uint8_t descriptors[] = {
0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, 0x86, 0x1a, 0x2d, 0x75,
0x54, 0x02, 0x00, 0x02, 0x00, 0x01, 0x09, 0x02, 0x75, 0x00, 0x02, 0x01,
0x00, 0x80, 0x30, 0x09, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01, 0x09, 0x04, 0x01,
0x00, 0x02, 0x01, 0x03, 0x00, 0x00, 0x07, 0x24, 0x01, 0x00, 0x01, 0x51,
0x00, 0x06, 0x24, 0x02, 0x01, 0x02, 0x00, 0x06, 0x24, 0x02, 0x01, 0x03,
0x00, 0x06, 0x24, 0x02, 0x02, 0x06, 0x00, 0x09, 0x24, 0x03, 0x01, 0x07,
0x01, 0x06, 0x01, 0x00, 0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x02, 0x01,
0x00, 0x09, 0x24, 0x03, 0x02, 0x05, 0x01, 0x03, 0x01, 0x00, 0x09, 0x05,
0x02, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x06, 0x25, 0x01, 0x02, 0x02,
0x03, 0x09, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x05, 0x25,
0x01, 0x01, 0x07,
};
device->SetDescriptors(ToVector(descriptors));
uint8_t data[] = {
0x90, 0x45, 0x7f, 0xf0, 0x00, 0x01, 0xf7,
};
Initialize();
UsbMidiDevice::Devices devices;
devices.push_back(std::move(device));
EXPECT_FALSE(IsInitializationCallbackInvoked());
RunCallbackUntilCallbackInvoked(true, &devices);
EXPECT_EQ(Result::OK, GetInitializationResult());
ASSERT_EQ(2u, manager()->output_streams().size());
EXPECT_EQ("UsbMidiDevice::GetDescriptors\n", logger_.TakeLog());
// The specified port index is invalid. The manager must ignore the request.
manager()->DispatchSendMidiData(client_.get(), 99, ToVector(data),
base::TimeTicks());
EXPECT_EQ("", logger_.TakeLog());
// The specified port index is invalid. The manager must ignore the request.
manager()->DispatchSendMidiData(client_.get(), 2, ToVector(data),
base::TimeTicks());
EXPECT_EQ("", logger_.TakeLog());
}
TEST_F(MidiManagerUsbTest, Receive) {
std::unique_ptr<FakeUsbMidiDevice> device(new FakeUsbMidiDevice(&logger_));
uint8_t descriptors[] = {
0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, 0x86, 0x1a, 0x2d, 0x75,
0x54, 0x02, 0x00, 0x02, 0x00, 0x01, 0x09, 0x02, 0x75, 0x00, 0x02, 0x01,
0x00, 0x80, 0x30, 0x09, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01, 0x09, 0x04, 0x01,
0x00, 0x02, 0x01, 0x03, 0x00, 0x00, 0x07, 0x24, 0x01, 0x00, 0x01, 0x51,
0x00, 0x06, 0x24, 0x02, 0x01, 0x02, 0x00, 0x06, 0x24, 0x02, 0x01, 0x03,
0x00, 0x06, 0x24, 0x02, 0x02, 0x06, 0x00, 0x09, 0x24, 0x03, 0x01, 0x07,
0x01, 0x06, 0x01, 0x00, 0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x02, 0x01,
0x00, 0x09, 0x24, 0x03, 0x02, 0x05, 0x01, 0x03, 0x01, 0x00, 0x09, 0x05,
0x02, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x06, 0x25, 0x01, 0x02, 0x02,
0x03, 0x09, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x05, 0x25,
0x01, 0x01, 0x07,
};
device->SetDescriptors(ToVector(descriptors));
uint8_t data[] = {
0x09, 0x90, 0x45, 0x7f, 0x04, 0xf0, 0x00,
0x01, 0x49, 0x90, 0x88, 0x99, // This data should be ignored (CN = 4).
0x05, 0xf7, 0x00, 0x00,
};
Initialize();
UsbMidiDevice::Devices devices;
UsbMidiDevice* device_raw = device.get();
devices.push_back(std::move(device));
EXPECT_FALSE(IsInitializationCallbackInvoked());
RunCallbackUntilCallbackInvoked(true, &devices);
EXPECT_EQ(Result::OK, GetInitializationResult());
manager()->ReceiveUsbMidiData(device_raw, 2, data, std::size(data),
base::TimeTicks());
Finalize();
EXPECT_EQ(
"UsbMidiDevice::GetDescriptors\n"
"MidiManagerClient::ReceiveMidiData usb:port_index = 0 "
"data = 0x90 0x45 0x7f\n"
"MidiManagerClient::ReceiveMidiData usb:port_index = 0 "
"data = 0xf0 0x00 0x01\n"
"MidiManagerClient::ReceiveMidiData usb:port_index = 0 data = 0xf7\n",
logger_.TakeLog());
}
TEST_F(MidiManagerUsbTest, AttachDevice) {
uint8_t descriptors[] = {
0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, 0x86, 0x1a, 0x2d, 0x75,
0x54, 0x02, 0x00, 0x02, 0x00, 0x01, 0x09, 0x02, 0x75, 0x00, 0x02, 0x01,
0x00, 0x80, 0x30, 0x09, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01, 0x09, 0x04, 0x01,
0x00, 0x02, 0x01, 0x03, 0x00, 0x00, 0x07, 0x24, 0x01, 0x00, 0x01, 0x51,
0x00, 0x06, 0x24, 0x02, 0x01, 0x02, 0x00, 0x06, 0x24, 0x02, 0x01, 0x03,
0x00, 0x06, 0x24, 0x02, 0x02, 0x06, 0x00, 0x09, 0x24, 0x03, 0x01, 0x07,
0x01, 0x06, 0x01, 0x00, 0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x02, 0x01,
0x00, 0x09, 0x24, 0x03, 0x02, 0x05, 0x01, 0x03, 0x01, 0x00, 0x09, 0x05,
0x02, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x06, 0x25, 0x01, 0x02, 0x02,
0x03, 0x09, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x05, 0x25,
0x01, 0x01, 0x07,
};
Initialize();
UsbMidiDevice::Devices devices;
EXPECT_FALSE(IsInitializationCallbackInvoked());
RunCallbackUntilCallbackInvoked(true, &devices);
EXPECT_EQ(Result::OK, GetInitializationResult());
ASSERT_EQ(0u, input_ports().size());
ASSERT_EQ(0u, output_ports().size());
ASSERT_TRUE(manager()->input_stream());
std::vector<UsbMidiJack> jacks = manager()->input_stream()->jacks();
ASSERT_EQ(0u, manager()->output_streams().size());
ASSERT_EQ(0u, jacks.size());
EXPECT_EQ("", logger_.TakeLog());
std::unique_ptr<FakeUsbMidiDevice> new_device(
new FakeUsbMidiDevice(&logger_));
new_device->SetDescriptors(ToVector(descriptors));
manager()->OnDeviceAttached(std::move(new_device));
ASSERT_EQ(1u, input_ports().size());
ASSERT_EQ(2u, output_ports().size());
ASSERT_TRUE(manager()->input_stream());
jacks = manager()->input_stream()->jacks();
ASSERT_EQ(2u, manager()->output_streams().size());
EXPECT_EQ(2u, manager()->output_streams()[0]->jack().jack_id);
EXPECT_EQ(3u, manager()->output_streams()[1]->jack().jack_id);
ASSERT_EQ(1u, jacks.size());
EXPECT_EQ(2, jacks[0].endpoint_number());
EXPECT_EQ("UsbMidiDevice::GetDescriptors\n", logger_.TakeLog());
}
} // namespace
} // namespace midi