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