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 virtual ~FakeUsbMidiDevice() {}
48 virtual std::vector
<uint8
> GetDescriptor() OVERRIDE
{
49 logger_
->AddLog("UsbMidiDevice::GetDescriptor\n");
53 virtual void Send(int endpoint_number
,
54 const std::vector
<uint8
>& data
) OVERRIDE
{
55 logger_
->AddLog("UsbMidiDevice::Send ");
56 logger_
->AddLog(base::StringPrintf("endpoint = %d data =",
58 for (size_t i
= 0; i
< data
.size(); ++i
)
59 logger_
->AddLog(base::StringPrintf(" 0x%02x", data
[i
]));
60 logger_
->AddLog("\n");
63 void SetDescriptor(const std::vector
<uint8
> descriptor
) {
64 descriptor_
= descriptor
;
68 std::vector
<uint8
> descriptor_
;
71 DISALLOW_COPY_AND_ASSIGN(FakeUsbMidiDevice
);
74 class FakeMidiManagerClient
: public MidiManagerClient
{
76 explicit FakeMidiManagerClient(Logger
* logger
)
77 : complete_start_session_(false),
78 result_(MIDI_NOT_SUPPORTED
),
80 virtual ~FakeMidiManagerClient() {}
82 virtual void CompleteStartSession(int client_id
, MidiResult result
) OVERRIDE
{
83 complete_start_session_
= true;
87 virtual void ReceiveMidiData(uint32 port_index
,
90 double timestamp
) OVERRIDE
{
91 logger_
->AddLog("MidiManagerClient::ReceiveMidiData ");
92 logger_
->AddLog(base::StringPrintf("port_index = %d data =", port_index
));
93 for (size_t i
= 0; i
< size
; ++i
)
94 logger_
->AddLog(base::StringPrintf(" 0x%02x", data
[i
]));
95 logger_
->AddLog("\n");
98 virtual void AccumulateMidiBytesSent(size_t size
) OVERRIDE
{
99 logger_
->AddLog("MidiManagerClient::AccumulateMidiBytesSent ");
100 // Windows has no "%zu".
101 logger_
->AddLog(base::StringPrintf("size = %u\n",
102 static_cast<unsigned>(size
)));
105 bool complete_start_session_
;
111 DISALLOW_COPY_AND_ASSIGN(FakeMidiManagerClient
);
114 class TestUsbMidiDeviceFactory
: public UsbMidiDevice::Factory
{
116 TestUsbMidiDeviceFactory() {}
117 virtual ~TestUsbMidiDeviceFactory() {}
118 virtual void EnumerateDevices(UsbMidiDeviceDelegate
* device
,
119 Callback callback
) OVERRIDE
{
120 callback_
= callback
;
126 DISALLOW_COPY_AND_ASSIGN(TestUsbMidiDeviceFactory
);
129 class MidiManagerUsbForTesting
: public MidiManagerUsb
{
131 explicit MidiManagerUsbForTesting(
132 scoped_ptr
<UsbMidiDevice::Factory
> device_factory
)
133 : MidiManagerUsb(device_factory
.PassAs
<UsbMidiDevice::Factory
>()) {}
134 virtual ~MidiManagerUsbForTesting() {}
136 void CallCompleteInitialization(MidiResult result
) {
137 CompleteInitialization(result
);
138 base::RunLoop run_loop
;
139 run_loop
.RunUntilIdle();
143 DISALLOW_COPY_AND_ASSIGN(MidiManagerUsbForTesting
);
146 class MidiManagerUsbTest
: public ::testing::Test
{
148 MidiManagerUsbTest() : message_loop_(new base::MessageLoop
) {
149 scoped_ptr
<TestUsbMidiDeviceFactory
> factory(new TestUsbMidiDeviceFactory
);
150 factory_
= factory
.get();
152 new MidiManagerUsbForTesting(factory
.PassAs
<UsbMidiDevice::Factory
>()));
154 virtual ~MidiManagerUsbTest() {
155 std::string leftover_logs
= logger_
.TakeLog();
156 if (!leftover_logs
.empty()) {
157 ADD_FAILURE() << "Log should be empty: " << leftover_logs
;
163 client_
.reset(new FakeMidiManagerClient(&logger_
));
164 manager_
->StartSession(client_
.get(), 0);
168 manager_
->EndSession(client_
.get());
171 bool IsInitializationCallbackInvoked() {
172 return client_
->complete_start_session_
;
175 MidiResult
GetInitializationResult() {
176 return client_
->result_
;
179 void RunCallbackUntilCallbackInvoked(
180 bool result
, UsbMidiDevice::Devices
* devices
) {
181 factory_
->callback_
.Run(result
, devices
);
182 base::RunLoop run_loop
;
183 while (!client_
->complete_start_session_
)
184 run_loop
.RunUntilIdle();
187 scoped_ptr
<MidiManagerUsbForTesting
> manager_
;
188 scoped_ptr
<FakeMidiManagerClient
> client_
;
189 // Owned by manager_.
190 TestUsbMidiDeviceFactory
* factory_
;
194 scoped_ptr
<base::MessageLoop
> message_loop_
;
196 DISALLOW_COPY_AND_ASSIGN(MidiManagerUsbTest
);
200 TEST_F(MidiManagerUsbTest
, Initialize
) {
201 scoped_ptr
<FakeUsbMidiDevice
> device(new FakeUsbMidiDevice(&logger_
));
202 uint8 descriptor
[] = {
203 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, 0x86, 0x1a,
204 0x2d, 0x75, 0x54, 0x02, 0x00, 0x02, 0x00, 0x01, 0x09, 0x02,
205 0x75, 0x00, 0x02, 0x01, 0x00, 0x80, 0x30, 0x09, 0x04, 0x00,
206 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x09, 0x24, 0x01, 0x00,
207 0x01, 0x09, 0x00, 0x01, 0x01, 0x09, 0x04, 0x01, 0x00, 0x02,
208 0x01, 0x03, 0x00, 0x00, 0x07, 0x24, 0x01, 0x00, 0x01, 0x51,
209 0x00, 0x06, 0x24, 0x02, 0x01, 0x02, 0x00, 0x06, 0x24, 0x02,
210 0x01, 0x03, 0x00, 0x06, 0x24, 0x02, 0x02, 0x06, 0x00, 0x09,
211 0x24, 0x03, 0x01, 0x07, 0x01, 0x06, 0x01, 0x00, 0x09, 0x24,
212 0x03, 0x02, 0x04, 0x01, 0x02, 0x01, 0x00, 0x09, 0x24, 0x03,
213 0x02, 0x05, 0x01, 0x03, 0x01, 0x00, 0x09, 0x05, 0x02, 0x02,
214 0x20, 0x00, 0x00, 0x00, 0x00, 0x06, 0x25, 0x01, 0x02, 0x02,
215 0x03, 0x09, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00,
216 0x05, 0x25, 0x01, 0x01, 0x07,
218 device
->SetDescriptor(ToVector(descriptor
));
221 ScopedVector
<UsbMidiDevice
> devices
;
222 devices
.push_back(device
.release());
223 EXPECT_FALSE(IsInitializationCallbackInvoked());
224 RunCallbackUntilCallbackInvoked(true, &devices
);
225 EXPECT_EQ(MIDI_OK
, GetInitializationResult());
227 ASSERT_EQ(1u, manager_
->input_ports().size());
228 ASSERT_EQ(2u, manager_
->output_ports().size());
229 ASSERT_TRUE(manager_
->input_stream());
230 std::vector
<UsbMidiInputStream::JackUniqueKey
> keys
=
231 manager_
->input_stream()->RegisteredJackKeysForTesting();
232 ASSERT_EQ(2u, manager_
->output_streams().size());
233 EXPECT_EQ(2u, manager_
->output_streams()[0]->jack().jack_id
);
234 EXPECT_EQ(3u, manager_
->output_streams()[1]->jack().jack_id
);
235 ASSERT_EQ(1u, keys
.size());
236 EXPECT_EQ(2, keys
[0].endpoint_number
);
238 EXPECT_EQ("UsbMidiDevice::GetDescriptor\n", logger_
.TakeLog());
241 TEST_F(MidiManagerUsbTest
, InitializeFail
) {
244 EXPECT_FALSE(IsInitializationCallbackInvoked());
245 RunCallbackUntilCallbackInvoked(false, NULL
);
246 EXPECT_EQ(MIDI_INITIALIZATION_ERROR
, GetInitializationResult());
249 TEST_F(MidiManagerUsbTest
, InitializeFailBecauseOfInvalidDescriptor
) {
250 scoped_ptr
<FakeUsbMidiDevice
> device(new FakeUsbMidiDevice(&logger_
));
251 uint8 descriptor
[] = {0x04};
252 device
->SetDescriptor(ToVector(descriptor
));
255 ScopedVector
<UsbMidiDevice
> devices
;
256 devices
.push_back(device
.release());
257 EXPECT_FALSE(IsInitializationCallbackInvoked());
258 RunCallbackUntilCallbackInvoked(true, &devices
);
259 EXPECT_EQ(MIDI_INITIALIZATION_ERROR
, GetInitializationResult());
260 EXPECT_EQ("UsbMidiDevice::GetDescriptor\n", logger_
.TakeLog());
263 TEST_F(MidiManagerUsbTest
, Send
) {
264 scoped_ptr
<FakeUsbMidiDevice
> device(new FakeUsbMidiDevice(&logger_
));
265 FakeMidiManagerClient
client(&logger_
);
266 uint8 descriptor
[] = {
267 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, 0x86, 0x1a,
268 0x2d, 0x75, 0x54, 0x02, 0x00, 0x02, 0x00, 0x01, 0x09, 0x02,
269 0x75, 0x00, 0x02, 0x01, 0x00, 0x80, 0x30, 0x09, 0x04, 0x00,
270 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x09, 0x24, 0x01, 0x00,
271 0x01, 0x09, 0x00, 0x01, 0x01, 0x09, 0x04, 0x01, 0x00, 0x02,
272 0x01, 0x03, 0x00, 0x00, 0x07, 0x24, 0x01, 0x00, 0x01, 0x51,
273 0x00, 0x06, 0x24, 0x02, 0x01, 0x02, 0x00, 0x06, 0x24, 0x02,
274 0x01, 0x03, 0x00, 0x06, 0x24, 0x02, 0x02, 0x06, 0x00, 0x09,
275 0x24, 0x03, 0x01, 0x07, 0x01, 0x06, 0x01, 0x00, 0x09, 0x24,
276 0x03, 0x02, 0x04, 0x01, 0x02, 0x01, 0x00, 0x09, 0x24, 0x03,
277 0x02, 0x05, 0x01, 0x03, 0x01, 0x00, 0x09, 0x05, 0x02, 0x02,
278 0x20, 0x00, 0x00, 0x00, 0x00, 0x06, 0x25, 0x01, 0x02, 0x02,
279 0x03, 0x09, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00,
280 0x05, 0x25, 0x01, 0x01, 0x07,
283 device
->SetDescriptor(ToVector(descriptor
));
286 0xf0, 0x00, 0x01, 0xf7,
290 ScopedVector
<UsbMidiDevice
> devices
;
291 devices
.push_back(device
.release());
292 EXPECT_FALSE(IsInitializationCallbackInvoked());
293 RunCallbackUntilCallbackInvoked(true, &devices
);
294 EXPECT_EQ(MIDI_OK
, GetInitializationResult());
295 ASSERT_EQ(2u, manager_
->output_streams().size());
297 manager_
->DispatchSendMidiData(&client
, 1, ToVector(data
), 0);
298 EXPECT_EQ("UsbMidiDevice::GetDescriptor\n"
299 "UsbMidiDevice::Send endpoint = 2 data = "
300 "0x19 0x90 0x45 0x7f "
301 "0x14 0xf0 0x00 0x01 "
302 "0x15 0xf7 0x00 0x00\n"
303 "MidiManagerClient::AccumulateMidiBytesSent size = 7\n",
307 TEST_F(MidiManagerUsbTest
, Receive
) {
308 scoped_ptr
<FakeUsbMidiDevice
> device(new FakeUsbMidiDevice(&logger_
));
309 uint8 descriptor
[] = {
310 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08, 0x86, 0x1a,
311 0x2d, 0x75, 0x54, 0x02, 0x00, 0x02, 0x00, 0x01, 0x09, 0x02,
312 0x75, 0x00, 0x02, 0x01, 0x00, 0x80, 0x30, 0x09, 0x04, 0x00,
313 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x09, 0x24, 0x01, 0x00,
314 0x01, 0x09, 0x00, 0x01, 0x01, 0x09, 0x04, 0x01, 0x00, 0x02,
315 0x01, 0x03, 0x00, 0x00, 0x07, 0x24, 0x01, 0x00, 0x01, 0x51,
316 0x00, 0x06, 0x24, 0x02, 0x01, 0x02, 0x00, 0x06, 0x24, 0x02,
317 0x01, 0x03, 0x00, 0x06, 0x24, 0x02, 0x02, 0x06, 0x00, 0x09,
318 0x24, 0x03, 0x01, 0x07, 0x01, 0x06, 0x01, 0x00, 0x09, 0x24,
319 0x03, 0x02, 0x04, 0x01, 0x02, 0x01, 0x00, 0x09, 0x24, 0x03,
320 0x02, 0x05, 0x01, 0x03, 0x01, 0x00, 0x09, 0x05, 0x02, 0x02,
321 0x20, 0x00, 0x00, 0x00, 0x00, 0x06, 0x25, 0x01, 0x02, 0x02,
322 0x03, 0x09, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00,
323 0x05, 0x25, 0x01, 0x01, 0x07,
326 device
->SetDescriptor(ToVector(descriptor
));
328 0x09, 0x90, 0x45, 0x7f,
329 0x04, 0xf0, 0x00, 0x01,
330 0x49, 0x90, 0x88, 0x99, // This data should be ignored (CN = 4).
331 0x05, 0xf7, 0x00, 0x00,
335 ScopedVector
<UsbMidiDevice
> devices
;
336 UsbMidiDevice
* device_raw
= device
.get();
337 devices
.push_back(device
.release());
338 EXPECT_FALSE(IsInitializationCallbackInvoked());
339 RunCallbackUntilCallbackInvoked(true, &devices
);
340 EXPECT_EQ(MIDI_OK
, GetInitializationResult());
342 manager_
->ReceiveUsbMidiData(device_raw
, 2, data
, arraysize(data
),
346 EXPECT_EQ("UsbMidiDevice::GetDescriptor\n"
347 "MidiManagerClient::ReceiveMidiData port_index = 0 "
348 "data = 0x90 0x45 0x7f\n"
349 "MidiManagerClient::ReceiveMidiData port_index = 0 "
350 "data = 0xf0 0x00 0x01\n"
351 "MidiManagerClient::ReceiveMidiData port_index = 0 data = 0xf7\n",