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 "base/callback.h"
      8 #include "base/logging.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "media/midi/usb_midi_descriptor_parser.h"
     13 #include "media/midi/usb_midi_device.h"
     14 #include "media/midi/usb_midi_input_stream.h"
     15 #include "media/midi/usb_midi_jack.h"
     16 #include "media/midi/usb_midi_output_stream.h"
     17 
     18 namespace media {
     19 
     20 MidiManagerUsb::MidiManagerUsb(scoped_ptr<UsbMidiDevice::Factory> factory)
     21     : device_factory_(factory.Pass()) {
     22 }
     23 
     24 MidiManagerUsb::~MidiManagerUsb() {
     25 }
     26 
     27 void MidiManagerUsb::StartInitialization() {
     28   Initialize(
     29       base::Bind(&MidiManager::CompleteInitialization, base::Unretained(this)));
     30 }
     31 
     32 void MidiManagerUsb::Initialize(
     33     base::Callback<void(MidiResult result)> callback) {
     34   initialize_callback_ = callback;
     35   // This is safe because EnumerateDevices cancels the operation on destruction.
     36   device_factory_->EnumerateDevices(
     37       this,
     38       base::Bind(&MidiManagerUsb::OnEnumerateDevicesDone,
     39                  base::Unretained(this)));
     40 }
     41 
     42 void MidiManagerUsb::DispatchSendMidiData(MidiManagerClient* client,
     43                                           uint32_t port_index,
     44                                           const std::vector<uint8>& data,
     45                                           double timestamp) {
     46   DCHECK_LT(port_index, output_streams_.size());
     47   output_streams_[port_index]->Send(data);
     48   client->AccumulateMidiBytesSent(data.size());
     49 }
     50 
     51 void MidiManagerUsb::ReceiveUsbMidiData(UsbMidiDevice* device,
     52                                         int endpoint_number,
     53                                         const uint8* data,
     54                                         size_t size,
     55                                         base::TimeTicks time) {
     56   if (!input_stream_)
     57     return;
     58   input_stream_->OnReceivedData(device,
     59                                 endpoint_number,
     60                                 data,
     61                                 size,
     62                                 time);
     63 }
     64 
     65 void MidiManagerUsb::OnReceivedData(size_t jack_index,
     66                                     const uint8* data,
     67                                     size_t size,
     68                                     base::TimeTicks time) {
     69   ReceiveMidiData(jack_index, data, size, time);
     70 }
     71 
     72 
     73 void MidiManagerUsb::OnEnumerateDevicesDone(bool result,
     74                                             UsbMidiDevice::Devices* devices) {
     75   if (!result) {
     76     initialize_callback_.Run(MIDI_INITIALIZATION_ERROR);
     77     return;
     78   }
     79   devices->swap(devices_);
     80   for (size_t i = 0; i < devices_.size(); ++i) {
     81     UsbMidiDescriptorParser parser;
     82     std::vector<uint8> descriptor = devices_[i]->GetDescriptor();
     83     const uint8* data = descriptor.size() > 0 ? &descriptor[0] : NULL;
     84     std::vector<UsbMidiJack> jacks;
     85     bool parse_result = parser.Parse(devices_[i],
     86                                      data,
     87                                      descriptor.size(),
     88                                      &jacks);
     89     if (!parse_result) {
     90       initialize_callback_.Run(MIDI_INITIALIZATION_ERROR);
     91       return;
     92     }
     93     std::vector<UsbMidiJack> input_jacks;
     94     for (size_t j = 0; j < jacks.size(); ++j) {
     95       if (jacks[j].direction() == UsbMidiJack::DIRECTION_OUT) {
     96         output_streams_.push_back(new UsbMidiOutputStream(jacks[j]));
     97         // TODO(yhirano): Set appropriate properties.
     98         // TODO(yhiran): Port ID should contain product ID / vendor ID.
     99         // Port ID must be unique in a MIDI manager. This (and the below) ID
    100         // setting is sufficiently unique although there is no user-friendly
    101         // meaning.
    102         MidiPortInfo port;
    103         port.id = base::StringPrintf("port-%ld-%ld",
    104                                      static_cast<long>(i),
    105                                      static_cast<long>(j));
    106         AddOutputPort(port);
    107       } else {
    108         DCHECK_EQ(jacks[j].direction(), UsbMidiJack::DIRECTION_IN);
    109         input_jacks.push_back(jacks[j]);
    110         // TODO(yhirano): Set appropriate properties.
    111         MidiPortInfo port;
    112         port.id = base::StringPrintf("port-%ld-%ld",
    113                                      static_cast<long>(i),
    114                                      static_cast<long>(j));
    115         AddInputPort(port);
    116       }
    117     }
    118     input_stream_.reset(new UsbMidiInputStream(input_jacks, this));
    119   }
    120   initialize_callback_.Run(MIDI_OK);
    121 }
    122 
    123 }  // namespace media
    124