Home | History | Annotate | Download | only in midi
      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 
     16 namespace media {
     17 
     18 namespace {
     19 
     20 template<typename T, size_t N>
     21 std::vector<T> ToVector(const T (&array)[N]) {
     22   return std::vector<T>(array, array + N);
     23 }
     24 
     25 class 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 
     43 class 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 
     74 class 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 
    114 class 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 
    129 class 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 
    146 class 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 
    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,
    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 
    241 TEST_F(MidiManagerUsbTest, InitializeFail) {
    242   Initialize();
    243 
    244   EXPECT_FALSE(IsInitializationCallbackInvoked());
    245   RunCallbackUntilCallbackInvoked(false, NULL);
    246   EXPECT_EQ(MIDI_INITIALIZATION_ERROR, GetInitializationResult());
    247 }
    248 
    249 TEST_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 
    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,
    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 
    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,
    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