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.
4
5#include "media/midi/midi_manager_usb.h"
6
7#include <string>
8
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"
15
16namespace media {
17
18namespace {
19
20template<typename T, size_t N>
21std::vector<T> ToVector(const T (&array)[N]) {
22  return std::vector<T>(array, array + N);
23}
24
25class Logger {
26 public:
27  Logger() {}
28  ~Logger() {}
29
30  void AddLog(const std::string& message) { log_ += message; }
31  std::string TakeLog() {
32    std::string result;
33    result.swap(log_);
34    return result;
35  }
36
37 private:
38  std::string log_;
39
40  DISALLOW_COPY_AND_ASSIGN(Logger);
41};
42
43class FakeUsbMidiDevice : public UsbMidiDevice {
44 public:
45  explicit FakeUsbMidiDevice(Logger* logger) : logger_(logger) {}
46  virtual ~FakeUsbMidiDevice() {}
47
48  virtual std::vector<uint8> GetDescriptor() OVERRIDE {
49    logger_->AddLog("UsbMidiDevice::GetDescriptor\n");
50    return descriptor_;
51  }
52
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 =",
57                                       endpoint_number));
58    for (size_t i = 0; i < data.size(); ++i)
59      logger_->AddLog(base::StringPrintf(" 0x%02x", data[i]));
60    logger_->AddLog("\n");
61  }
62
63  void SetDescriptor(const std::vector<uint8> descriptor) {
64    descriptor_ = descriptor;
65  }
66
67 private:
68  std::vector<uint8> descriptor_;
69  Logger* logger_;
70
71  DISALLOW_COPY_AND_ASSIGN(FakeUsbMidiDevice);
72};
73
74class FakeMidiManagerClient : public MidiManagerClient {
75 public:
76  explicit FakeMidiManagerClient(Logger* logger)
77      : complete_start_session_(false),
78        result_(MIDI_NOT_SUPPORTED),
79        logger_(logger) {}
80  virtual ~FakeMidiManagerClient() {}
81
82  virtual void CompleteStartSession(int client_id, MidiResult result) OVERRIDE {
83    complete_start_session_ = true;
84    result_ = result;
85  }
86
87  virtual void ReceiveMidiData(uint32 port_index,
88                               const uint8* data,
89                               size_t size,
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");
96  }
97
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)));
103  }
104
105  bool complete_start_session_;
106  MidiResult result_;
107
108 private:
109  Logger* logger_;
110
111  DISALLOW_COPY_AND_ASSIGN(FakeMidiManagerClient);
112};
113
114class TestUsbMidiDeviceFactory : public UsbMidiDevice::Factory {
115 public:
116  TestUsbMidiDeviceFactory() {}
117  virtual ~TestUsbMidiDeviceFactory() {}
118  virtual void EnumerateDevices(UsbMidiDeviceDelegate* device,
119                                Callback callback) OVERRIDE {
120    callback_ = callback;
121  }
122
123  Callback callback_;
124
125 private:
126  DISALLOW_COPY_AND_ASSIGN(TestUsbMidiDeviceFactory);
127};
128
129class MidiManagerUsbForTesting : public MidiManagerUsb {
130 public:
131  explicit MidiManagerUsbForTesting(
132      scoped_ptr<UsbMidiDevice::Factory> device_factory)
133      : MidiManagerUsb(device_factory.PassAs<UsbMidiDevice::Factory>()) {}
134  virtual ~MidiManagerUsbForTesting() {}
135
136  void CallCompleteInitialization(MidiResult result) {
137    CompleteInitialization(result);
138    base::RunLoop run_loop;
139    run_loop.RunUntilIdle();
140  }
141
142 private:
143  DISALLOW_COPY_AND_ASSIGN(MidiManagerUsbForTesting);
144};
145
146class MidiManagerUsbTest : public ::testing::Test {
147 public:
148  MidiManagerUsbTest() : message_loop_(new base::MessageLoop) {
149    scoped_ptr<TestUsbMidiDeviceFactory> factory(new TestUsbMidiDeviceFactory);
150    factory_ = factory.get();
151    manager_.reset(
152        new MidiManagerUsbForTesting(factory.PassAs<UsbMidiDevice::Factory>()));
153  }
154  virtual ~MidiManagerUsbTest() {
155    std::string leftover_logs = logger_.TakeLog();
156    if (!leftover_logs.empty()) {
157      ADD_FAILURE() << "Log should be empty: " << leftover_logs;
158    }
159  }
160
161 protected:
162  void Initialize() {
163    client_.reset(new FakeMidiManagerClient(&logger_));
164    manager_->StartSession(client_.get(), 0);
165  }
166
167  void Finalize() {
168    manager_->EndSession(client_.get());
169  }
170
171  bool IsInitializationCallbackInvoked() {
172    return client_->complete_start_session_;
173  }
174
175  MidiResult GetInitializationResult() {
176    return client_->result_;
177  }
178
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();
185  }
186
187  scoped_ptr<MidiManagerUsbForTesting> manager_;
188  scoped_ptr<FakeMidiManagerClient> client_;
189  // Owned by manager_.
190  TestUsbMidiDeviceFactory* factory_;
191  Logger logger_;
192
193 private:
194  scoped_ptr<base::MessageLoop> message_loop_;
195
196  DISALLOW_COPY_AND_ASSIGN(MidiManagerUsbTest);
197};
198
199
200TEST_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,
217  };
218  device->SetDescriptor(ToVector(descriptor));
219
220  Initialize();
221  ScopedVector<UsbMidiDevice> devices;
222  devices.push_back(device.release());
223  EXPECT_FALSE(IsInitializationCallbackInvoked());
224  RunCallbackUntilCallbackInvoked(true, &devices);
225  EXPECT_EQ(MIDI_OK, GetInitializationResult());
226
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);
237
238  EXPECT_EQ("UsbMidiDevice::GetDescriptor\n", logger_.TakeLog());
239}
240
241TEST_F(MidiManagerUsbTest, InitializeFail) {
242  Initialize();
243
244  EXPECT_FALSE(IsInitializationCallbackInvoked());
245  RunCallbackUntilCallbackInvoked(false, NULL);
246  EXPECT_EQ(MIDI_INITIALIZATION_ERROR, GetInitializationResult());
247}
248
249TEST_F(MidiManagerUsbTest, InitializeFailBecauseOfInvalidDescriptor) {
250  scoped_ptr<FakeUsbMidiDevice> device(new FakeUsbMidiDevice(&logger_));
251  uint8 descriptor[] = {0x04};
252  device->SetDescriptor(ToVector(descriptor));
253
254  Initialize();
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());
261}
262
263TEST_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,
281  };
282
283  device->SetDescriptor(ToVector(descriptor));
284  uint8 data[] = {
285    0x90, 0x45, 0x7f,
286    0xf0, 0x00, 0x01, 0xf7,
287  };
288
289  Initialize();
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());
296
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",
304            logger_.TakeLog());
305}
306
307TEST_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,
324  };
325
326  device->SetDescriptor(ToVector(descriptor));
327  uint8 data[] = {
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,
332  };
333
334  Initialize();
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());
341
342  manager_->ReceiveUsbMidiData(device_raw, 2, data, arraysize(data),
343                               base::TimeTicks());
344  Finalize();
345
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",
352            logger_.TakeLog());
353}
354
355}  // namespace
356
357}  // namespace media
358