1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/midi/midi_manager_usb.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/time/time.h"
13 #include "media/midi/usb_midi_device.h"
14 #include "testing/gtest/include/gtest/gtest.h"
20 template<typename T
, size_t N
>
21 std::vector
<T
> ToVector(const T (&array
)[N
]) {
22 return std::vector
<T
>(array
, array
+ N
);
30 void AddLog(const std::string
& message
) { log_
+= message
; }
31 std::string
TakeLog() {
40 DISALLOW_COPY_AND_ASSIGN(Logger
);
43 class FakeUsbMidiDevice
: public UsbMidiDevice
{
45 explicit FakeUsbMidiDevice(Logger
* logger
) : logger_(logger
) {}
46 ~FakeUsbMidiDevice() override
{}
48 std::vector
<uint8
> GetDescriptor() override
{
49 logger_
->AddLog("UsbMidiDevice::GetDescriptor\n");
53 void Send(int endpoint_number
, const std::vector
<uint8
>& data
) override
{
54 logger_
->AddLog("UsbMidiDevice::Send ");
55 logger_
->AddLog(base::StringPrintf("endpoint = %d data =",
57 for (size_t i
= 0; i
< data
.size(); ++i
)
58 logger_
->AddLog(base::StringPrintf(" 0x%02x", data
[i
]));
59 logger_
->AddLog("\n");
62 void SetDescriptor(const std::vector
<uint8
> descriptor
) {
63 descriptor_
= descriptor
;
67 std::vector
<uint8
> descriptor_
;
70 DISALLOW_COPY_AND_ASSIGN(FakeUsbMidiDevice
);
73 class FakeMidiManagerClient
: public MidiManagerClient
{
75 explicit FakeMidiManagerClient(Logger
* logger
)
76 : complete_start_session_(false),
77 result_(MIDI_NOT_SUPPORTED
),
79 ~FakeMidiManagerClient() override
{}
81 void AddInputPort(const MidiPortInfo
& info
) override
{
82 input_ports_
.push_back(info
);
85 void AddOutputPort(const MidiPortInfo
& info
) override
{
86 output_ports_
.push_back(info
);
89 void CompleteStartSession(MidiResult result
) override
{
90 complete_start_session_
= true;
94 void ReceiveMidiData(uint32 port_index
,
97 double timestamp
) override
{
98 logger_
->AddLog("MidiManagerClient::ReceiveMidiData ");
99 logger_
->AddLog(base::StringPrintf("port_index = %d data =", port_index
));
100 for (size_t i
= 0; i
< size
; ++i
)
101 logger_
->AddLog(base::StringPrintf(" 0x%02x", data
[i
]));
102 logger_
->AddLog("\n");
105 void AccumulateMidiBytesSent(size_t size
) override
{
106 logger_
->AddLog("MidiManagerClient::AccumulateMidiBytesSent ");
107 // Windows has no "%zu".
108 logger_
->AddLog(base::StringPrintf("size = %u\n",
109 static_cast<unsigned>(size
)));
112 bool complete_start_session_
;
114 MidiPortInfoList input_ports_
;
115 MidiPortInfoList output_ports_
;
120 DISALLOW_COPY_AND_ASSIGN(FakeMidiManagerClient
);
123 class TestUsbMidiDeviceFactory
: public UsbMidiDevice::Factory
{
125 TestUsbMidiDeviceFactory() {}
126 ~TestUsbMidiDeviceFactory() override
{}
127 void EnumerateDevices(UsbMidiDeviceDelegate
* device
,
128 Callback callback
) override
{
129 callback_
= callback
;
135 DISALLOW_COPY_AND_ASSIGN(TestUsbMidiDeviceFactory
);
138 class MidiManagerUsbForTesting
: public MidiManagerUsb
{
140 explicit MidiManagerUsbForTesting(
141 scoped_ptr
<UsbMidiDevice::Factory
> device_factory
)
142 : MidiManagerUsb(device_factory
.Pass()) {}
143 ~MidiManagerUsbForTesting() override
{}
145 void CallCompleteInitialization(MidiResult result
) {
146 CompleteInitialization(result
);
147 base::RunLoop run_loop
;
148 run_loop
.RunUntilIdle();
152 DISALLOW_COPY_AND_ASSIGN(MidiManagerUsbForTesting
);
155 class MidiManagerUsbTest
: public ::testing::Test
{
157 MidiManagerUsbTest() : message_loop_(new base::MessageLoop
) {
158 scoped_ptr
<TestUsbMidiDeviceFactory
> factory(new TestUsbMidiDeviceFactory
);
159 factory_
= factory
.get();
160 manager_
.reset(new MidiManagerUsbForTesting(factory
.Pass()));
162 virtual ~MidiManagerUsbTest() {
163 std::string leftover_logs
= logger_
.TakeLog();
164 if (!leftover_logs
.empty()) {
165 ADD_FAILURE() << "Log should be empty: " << leftover_logs
;
171 client_
.reset(new FakeMidiManagerClient(&logger_
));
172 manager_
->StartSession(client_
.get());
176 manager_
->EndSession(client_
.get());
179 bool IsInitializationCallbackInvoked() {
180 return client_
->complete_start_session_
;
183 MidiResult
GetInitializationResult() {
184 return client_
->result_
;
187 void RunCallbackUntilCallbackInvoked(
188 bool result
, UsbMidiDevice::Devices
* devices
) {
189 factory_
->callback_
.Run(result
, devices
);
190 while (!client_
->complete_start_session_
) {
191 base::RunLoop run_loop
;
192 run_loop
.RunUntilIdle();
196 const MidiPortInfoList
& input_ports() { return client_
->input_ports_
; }
197 const MidiPortInfoList
& output_ports() { return client_
->output_ports_
; }
199 scoped_ptr
<MidiManagerUsbForTesting
> manager_
;
200 scoped_ptr
<FakeMidiManagerClient
> client_
;
201 // Owned by manager_.
202 TestUsbMidiDeviceFactory
* factory_
;
206 scoped_ptr
<base::MessageLoop
> message_loop_
;
208 DISALLOW_COPY_AND_ASSIGN(MidiManagerUsbTest
);
212 TEST_F(MidiManagerUsbTest
, Initialize
) {
213 scoped_ptr
<FakeUsbMidiDevice
> device(new FakeUsbMidiDevice(&logger_
));
214 uint8 descriptor
[] = {
215 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, 0x86, 0x1a,
216 0x2d, 0x75, 0x54, 0x02, 0x00, 0x02, 0x00, 0x01, 0x09, 0x02,
217 0x75, 0x00, 0x02, 0x01, 0x00, 0x80, 0x30, 0x09, 0x04, 0x00,
218 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x09, 0x24, 0x01, 0x00,
219 0x01, 0x09, 0x00, 0x01, 0x01, 0x09, 0x04, 0x01, 0x00, 0x02,
220 0x01, 0x03, 0x00, 0x00, 0x07, 0x24, 0x01, 0x00, 0x01, 0x51,
221 0x00, 0x06, 0x24, 0x02, 0x01, 0x02, 0x00, 0x06, 0x24, 0x02,
222 0x01, 0x03, 0x00, 0x06, 0x24, 0x02, 0x02, 0x06, 0x00, 0x09,
223 0x24, 0x03, 0x01, 0x07, 0x01, 0x06, 0x01, 0x00, 0x09, 0x24,
224 0x03, 0x02, 0x04, 0x01, 0x02, 0x01, 0x00, 0x09, 0x24, 0x03,
225 0x02, 0x05, 0x01, 0x03, 0x01, 0x00, 0x09, 0x05, 0x02, 0x02,
226 0x20, 0x00, 0x00, 0x00, 0x00, 0x06, 0x25, 0x01, 0x02, 0x02,
227 0x03, 0x09, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00,
228 0x05, 0x25, 0x01, 0x01, 0x07,
230 device
->SetDescriptor(ToVector(descriptor
));
233 ScopedVector
<UsbMidiDevice
> devices
;
234 devices
.push_back(device
.release());
235 EXPECT_FALSE(IsInitializationCallbackInvoked());
236 RunCallbackUntilCallbackInvoked(true, &devices
);
237 EXPECT_EQ(MIDI_OK
, GetInitializationResult());
239 ASSERT_EQ(1u, input_ports().size());
240 ASSERT_EQ(2u, output_ports().size());
241 ASSERT_TRUE(manager_
->input_stream());
242 std::vector
<UsbMidiInputStream::JackUniqueKey
> keys
=
243 manager_
->input_stream()->RegisteredJackKeysForTesting();
244 ASSERT_EQ(2u, manager_
->output_streams().size());
245 EXPECT_EQ(2u, manager_
->output_streams()[0]->jack().jack_id
);
246 EXPECT_EQ(3u, manager_
->output_streams()[1]->jack().jack_id
);
247 ASSERT_EQ(1u, keys
.size());
248 EXPECT_EQ(2, keys
[0].endpoint_number
);
250 EXPECT_EQ("UsbMidiDevice::GetDescriptor\n", logger_
.TakeLog());
253 TEST_F(MidiManagerUsbTest
, InitializeFail
) {
256 EXPECT_FALSE(IsInitializationCallbackInvoked());
257 RunCallbackUntilCallbackInvoked(false, NULL
);
258 EXPECT_EQ(MIDI_INITIALIZATION_ERROR
, GetInitializationResult());
261 TEST_F(MidiManagerUsbTest
, InitializeFailBecauseOfInvalidDescriptor
) {
262 scoped_ptr
<FakeUsbMidiDevice
> device(new FakeUsbMidiDevice(&logger_
));
263 uint8 descriptor
[] = {0x04};
264 device
->SetDescriptor(ToVector(descriptor
));
267 ScopedVector
<UsbMidiDevice
> devices
;
268 devices
.push_back(device
.release());
269 EXPECT_FALSE(IsInitializationCallbackInvoked());
270 RunCallbackUntilCallbackInvoked(true, &devices
);
271 EXPECT_EQ(MIDI_INITIALIZATION_ERROR
, GetInitializationResult());
272 EXPECT_EQ("UsbMidiDevice::GetDescriptor\n", logger_
.TakeLog());
275 TEST_F(MidiManagerUsbTest
, Send
) {
276 scoped_ptr
<FakeUsbMidiDevice
> device(new FakeUsbMidiDevice(&logger_
));
277 FakeMidiManagerClient
client(&logger_
);
278 uint8 descriptor
[] = {
279 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, 0x86, 0x1a,
280 0x2d, 0x75, 0x54, 0x02, 0x00, 0x02, 0x00, 0x01, 0x09, 0x02,
281 0x75, 0x00, 0x02, 0x01, 0x00, 0x80, 0x30, 0x09, 0x04, 0x00,
282 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x09, 0x24, 0x01, 0x00,
283 0x01, 0x09, 0x00, 0x01, 0x01, 0x09, 0x04, 0x01, 0x00, 0x02,
284 0x01, 0x03, 0x00, 0x00, 0x07, 0x24, 0x01, 0x00, 0x01, 0x51,
285 0x00, 0x06, 0x24, 0x02, 0x01, 0x02, 0x00, 0x06, 0x24, 0x02,
286 0x01, 0x03, 0x00, 0x06, 0x24, 0x02, 0x02, 0x06, 0x00, 0x09,
287 0x24, 0x03, 0x01, 0x07, 0x01, 0x06, 0x01, 0x00, 0x09, 0x24,
288 0x03, 0x02, 0x04, 0x01, 0x02, 0x01, 0x00, 0x09, 0x24, 0x03,
289 0x02, 0x05, 0x01, 0x03, 0x01, 0x00, 0x09, 0x05, 0x02, 0x02,
290 0x20, 0x00, 0x00, 0x00, 0x00, 0x06, 0x25, 0x01, 0x02, 0x02,
291 0x03, 0x09, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00,
292 0x05, 0x25, 0x01, 0x01, 0x07,
295 device
->SetDescriptor(ToVector(descriptor
));
298 0xf0, 0x00, 0x01, 0xf7,
302 ScopedVector
<UsbMidiDevice
> devices
;
303 devices
.push_back(device
.release());
304 EXPECT_FALSE(IsInitializationCallbackInvoked());
305 RunCallbackUntilCallbackInvoked(true, &devices
);
306 EXPECT_EQ(MIDI_OK
, GetInitializationResult());
307 ASSERT_EQ(2u, manager_
->output_streams().size());
309 manager_
->DispatchSendMidiData(&client
, 1, ToVector(data
), 0);
310 EXPECT_EQ("UsbMidiDevice::GetDescriptor\n"
311 "UsbMidiDevice::Send endpoint = 2 data = "
312 "0x19 0x90 0x45 0x7f "
313 "0x14 0xf0 0x00 0x01 "
314 "0x15 0xf7 0x00 0x00\n"
315 "MidiManagerClient::AccumulateMidiBytesSent size = 7\n",
319 TEST_F(MidiManagerUsbTest
, Receive
) {
320 scoped_ptr
<FakeUsbMidiDevice
> device(new FakeUsbMidiDevice(&logger_
));
321 uint8 descriptor
[] = {
322 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, 0x86, 0x1a,
323 0x2d, 0x75, 0x54, 0x02, 0x00, 0x02, 0x00, 0x01, 0x09, 0x02,
324 0x75, 0x00, 0x02, 0x01, 0x00, 0x80, 0x30, 0x09, 0x04, 0x00,
325 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x09, 0x24, 0x01, 0x00,
326 0x01, 0x09, 0x00, 0x01, 0x01, 0x09, 0x04, 0x01, 0x00, 0x02,
327 0x01, 0x03, 0x00, 0x00, 0x07, 0x24, 0x01, 0x00, 0x01, 0x51,
328 0x00, 0x06, 0x24, 0x02, 0x01, 0x02, 0x00, 0x06, 0x24, 0x02,
329 0x01, 0x03, 0x00, 0x06, 0x24, 0x02, 0x02, 0x06, 0x00, 0x09,
330 0x24, 0x03, 0x01, 0x07, 0x01, 0x06, 0x01, 0x00, 0x09, 0x24,
331 0x03, 0x02, 0x04, 0x01, 0x02, 0x01, 0x00, 0x09, 0x24, 0x03,
332 0x02, 0x05, 0x01, 0x03, 0x01, 0x00, 0x09, 0x05, 0x02, 0x02,
333 0x20, 0x00, 0x00, 0x00, 0x00, 0x06, 0x25, 0x01, 0x02, 0x02,
334 0x03, 0x09, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00,
335 0x05, 0x25, 0x01, 0x01, 0x07,
338 device
->SetDescriptor(ToVector(descriptor
));
340 0x09, 0x90, 0x45, 0x7f,
341 0x04, 0xf0, 0x00, 0x01,
342 0x49, 0x90, 0x88, 0x99, // This data should be ignored (CN = 4).
343 0x05, 0xf7, 0x00, 0x00,
347 ScopedVector
<UsbMidiDevice
> devices
;
348 UsbMidiDevice
* device_raw
= device
.get();
349 devices
.push_back(device
.release());
350 EXPECT_FALSE(IsInitializationCallbackInvoked());
351 RunCallbackUntilCallbackInvoked(true, &devices
);
352 EXPECT_EQ(MIDI_OK
, GetInitializationResult());
354 manager_
->ReceiveUsbMidiData(device_raw
, 2, data
, arraysize(data
),
358 EXPECT_EQ("UsbMidiDevice::GetDescriptor\n"
359 "MidiManagerClient::ReceiveMidiData port_index = 0 "
360 "data = 0x90 0x45 0x7f\n"
361 "MidiManagerClient::ReceiveMidiData port_index = 0 "
362 "data = 0xf0 0x00 0x01\n"
363 "MidiManagerClient::ReceiveMidiData port_index = 0 data = 0xf7\n",