普通文本  |  358行  |  11.75 KB

// Copyright 2014 The Chromium Authors. All rights reserved.
// 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 <string>

#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "media/midi/usb_midi_device.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace media {

namespace {

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() {}
  ~Logger() {}

  void AddLog(const std::string& message) { log_ += message; }
  std::string TakeLog() {
    std::string result;
    result.swap(log_);
    return result;
  }

 private:
  std::string log_;

  DISALLOW_COPY_AND_ASSIGN(Logger);
};

class FakeUsbMidiDevice : public UsbMidiDevice {
 public:
  explicit FakeUsbMidiDevice(Logger* logger) : logger_(logger) {}
  virtual ~FakeUsbMidiDevice() {}

  virtual std::vector<uint8> GetDescriptor() OVERRIDE {
    logger_->AddLog("UsbMidiDevice::GetDescriptor\n");
    return descriptor_;
  }

  virtual void Send(int endpoint_number,
                    const std::vector<uint8>& 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 SetDescriptor(const std::vector<uint8> descriptor) {
    descriptor_ = descriptor;
  }

 private:
  std::vector<uint8> descriptor_;
  Logger* logger_;

  DISALLOW_COPY_AND_ASSIGN(FakeUsbMidiDevice);
};

class FakeMidiManagerClient : public MidiManagerClient {
 public:
  explicit FakeMidiManagerClient(Logger* logger)
      : complete_start_session_(false),
        result_(MIDI_NOT_SUPPORTED),
        logger_(logger) {}
  virtual ~FakeMidiManagerClient() {}

  virtual void CompleteStartSession(int client_id, MidiResult result) OVERRIDE {
    complete_start_session_ = true;
    result_ = result;
  }

  virtual void ReceiveMidiData(uint32 port_index,
                               const uint8* data,
                               size_t size,
                               double timestamp) OVERRIDE {
    logger_->AddLog("MidiManagerClient::ReceiveMidiData ");
    logger_->AddLog(base::StringPrintf("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");
  }

  virtual 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)));
  }

  bool complete_start_session_;
  MidiResult result_;

 private:
  Logger* logger_;

  DISALLOW_COPY_AND_ASSIGN(FakeMidiManagerClient);
};

class TestUsbMidiDeviceFactory : public UsbMidiDevice::Factory {
 public:
  TestUsbMidiDeviceFactory() {}
  virtual ~TestUsbMidiDeviceFactory() {}
  virtual void EnumerateDevices(UsbMidiDeviceDelegate* device,
                                Callback callback) OVERRIDE {
    callback_ = callback;
  }

  Callback callback_;

 private:
  DISALLOW_COPY_AND_ASSIGN(TestUsbMidiDeviceFactory);
};

class MidiManagerUsbForTesting : public MidiManagerUsb {
 public:
  explicit MidiManagerUsbForTesting(
      scoped_ptr<UsbMidiDevice::Factory> device_factory)
      : MidiManagerUsb(device_factory.PassAs<UsbMidiDevice::Factory>()) {}
  virtual ~MidiManagerUsbForTesting() {}

  void CallCompleteInitialization(MidiResult result) {
    CompleteInitialization(result);
    base::RunLoop run_loop;
    run_loop.RunUntilIdle();
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(MidiManagerUsbForTesting);
};

class MidiManagerUsbTest : public ::testing::Test {
 public:
  MidiManagerUsbTest() : message_loop_(new base::MessageLoop) {
    scoped_ptr<TestUsbMidiDeviceFactory> factory(new TestUsbMidiDeviceFactory);
    factory_ = factory.get();
    manager_.reset(
        new MidiManagerUsbForTesting(factory.PassAs<UsbMidiDevice::Factory>()));
  }
  virtual ~MidiManagerUsbTest() {
    std::string leftover_logs = logger_.TakeLog();
    if (!leftover_logs.empty()) {
      ADD_FAILURE() << "Log should be empty: " << leftover_logs;
    }
  }

 protected:
  void Initialize() {
    client_.reset(new FakeMidiManagerClient(&logger_));
    manager_->StartSession(client_.get(), 0);
  }

  void Finalize() {
    manager_->EndSession(client_.get());
  }

  bool IsInitializationCallbackInvoked() {
    return client_->complete_start_session_;
  }

  MidiResult GetInitializationResult() {
    return client_->result_;
  }

  void RunCallbackUntilCallbackInvoked(
      bool result, UsbMidiDevice::Devices* devices) {
    factory_->callback_.Run(result, devices);
    base::RunLoop run_loop;
    while (!client_->complete_start_session_)
      run_loop.RunUntilIdle();
  }

  scoped_ptr<MidiManagerUsbForTesting> manager_;
  scoped_ptr<FakeMidiManagerClient> client_;
  // Owned by manager_.
  TestUsbMidiDeviceFactory* factory_;
  Logger logger_;

 private:
  scoped_ptr<base::MessageLoop> message_loop_;

  DISALLOW_COPY_AND_ASSIGN(MidiManagerUsbTest);
};


TEST_F(MidiManagerUsbTest, Initialize) {
  scoped_ptr<FakeUsbMidiDevice> device(new FakeUsbMidiDevice(&logger_));
  uint8 descriptor[] = {
    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->SetDescriptor(ToVector(descriptor));

  Initialize();
  ScopedVector<UsbMidiDevice> devices;
  devices.push_back(device.release());
  EXPECT_FALSE(IsInitializationCallbackInvoked());
  RunCallbackUntilCallbackInvoked(true, &devices);
  EXPECT_EQ(MIDI_OK, GetInitializationResult());

  ASSERT_EQ(1u, manager_->input_ports().size());
  ASSERT_EQ(2u, manager_->output_ports().size());
  ASSERT_TRUE(manager_->input_stream());
  std::vector<UsbMidiInputStream::JackUniqueKey> keys =
      manager_->input_stream()->RegisteredJackKeysForTesting();
  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, keys.size());
  EXPECT_EQ(2, keys[0].endpoint_number);

  EXPECT_EQ("UsbMidiDevice::GetDescriptor\n", logger_.TakeLog());
}

TEST_F(MidiManagerUsbTest, InitializeFail) {
  Initialize();

  EXPECT_FALSE(IsInitializationCallbackInvoked());
  RunCallbackUntilCallbackInvoked(false, NULL);
  EXPECT_EQ(MIDI_INITIALIZATION_ERROR, GetInitializationResult());
}

TEST_F(MidiManagerUsbTest, InitializeFailBecauseOfInvalidDescriptor) {
  scoped_ptr<FakeUsbMidiDevice> device(new FakeUsbMidiDevice(&logger_));
  uint8 descriptor[] = {0x04};
  device->SetDescriptor(ToVector(descriptor));

  Initialize();
  ScopedVector<UsbMidiDevice> devices;
  devices.push_back(device.release());
  EXPECT_FALSE(IsInitializationCallbackInvoked());
  RunCallbackUntilCallbackInvoked(true, &devices);
  EXPECT_EQ(MIDI_INITIALIZATION_ERROR, GetInitializationResult());
  EXPECT_EQ("UsbMidiDevice::GetDescriptor\n", logger_.TakeLog());
}

TEST_F(MidiManagerUsbTest, Send) {
  scoped_ptr<FakeUsbMidiDevice> device(new FakeUsbMidiDevice(&logger_));
  FakeMidiManagerClient client(&logger_);
  uint8 descriptor[] = {
    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->SetDescriptor(ToVector(descriptor));
  uint8 data[] = {
    0x90, 0x45, 0x7f,
    0xf0, 0x00, 0x01, 0xf7,
  };

  Initialize();
  ScopedVector<UsbMidiDevice> devices;
  devices.push_back(device.release());
  EXPECT_FALSE(IsInitializationCallbackInvoked());
  RunCallbackUntilCallbackInvoked(true, &devices);
  EXPECT_EQ(MIDI_OK, GetInitializationResult());
  ASSERT_EQ(2u, manager_->output_streams().size());

  manager_->DispatchSendMidiData(&client, 1, ToVector(data), 0);
  EXPECT_EQ("UsbMidiDevice::GetDescriptor\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, Receive) {
  scoped_ptr<FakeUsbMidiDevice> device(new FakeUsbMidiDevice(&logger_));
  uint8 descriptor[] = {
    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->SetDescriptor(ToVector(descriptor));
  uint8 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();
  ScopedVector<UsbMidiDevice> devices;
  UsbMidiDevice* device_raw = device.get();
  devices.push_back(device.release());
  EXPECT_FALSE(IsInitializationCallbackInvoked());
  RunCallbackUntilCallbackInvoked(true, &devices);
  EXPECT_EQ(MIDI_OK, GetInitializationResult());

  manager_->ReceiveUsbMidiData(device_raw, 2, data, arraysize(data),
                               base::TimeTicks());
  Finalize();

  EXPECT_EQ("UsbMidiDevice::GetDescriptor\n"
            "MidiManagerClient::ReceiveMidiData port_index = 0 "
            "data = 0x90 0x45 0x7f\n"
            "MidiManagerClient::ReceiveMidiData port_index = 0 "
            "data = 0xf0 0x00 0x01\n"
            "MidiManagerClient::ReceiveMidiData port_index = 0 data = 0xf7\n",
            logger_.TakeLog());
}

}  // namespace

}  // namespace media