| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/midi/midi_manager_alsa.h" | 5 #include "media/midi/midi_manager_alsa.h" |
| 6 | 6 |
| 7 #include <alsa/asoundlib.h> | 7 #include <alsa/asoundlib.h> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/memory/ref_counted.h" | 12 #include "base/memory/ref_counted.h" |
| 13 #include "base/message_loop/message_loop.h" | 13 #include "base/message_loop/message_loop.h" |
| 14 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
| 15 #include "base/threading/thread.h" | 15 #include "base/threading/thread.h" |
| 16 #include "media/midi/midi_port_info.h" | 16 #include "media/midi/midi_port_info.h" |
| 17 | 17 |
| 18 namespace media { | 18 namespace media { |
| 19 | 19 |
| 20 class MIDIManagerAlsa::MIDIDeviceInfo | 20 class MidiManagerAlsa::MidiDeviceInfo |
| 21 : public base::RefCounted<MIDIDeviceInfo> { | 21 : public base::RefCounted<MidiDeviceInfo> { |
| 22 public: | 22 public: |
| 23 MIDIDeviceInfo(MIDIManagerAlsa* manager, | 23 MidiDeviceInfo(MidiManagerAlsa* manager, |
| 24 const std::string& bus_id, | 24 const std::string& bus_id, |
| 25 snd_ctl_card_info_t* card, | 25 snd_ctl_card_info_t* card, |
| 26 const snd_rawmidi_info_t* midi, | 26 const snd_rawmidi_info_t* midi, |
| 27 int device) { | 27 int device) { |
| 28 opened_ = !snd_rawmidi_open(&midi_in_, &midi_out_, bus_id.c_str(), 0); | 28 opened_ = !snd_rawmidi_open(&midi_in_, &midi_out_, bus_id.c_str(), 0); |
| 29 if (!opened_) | 29 if (!opened_) |
| 30 return; | 30 return; |
| 31 | 31 |
| 32 const std::string id = base::StringPrintf("%s:%d", bus_id.c_str(), device); | 32 const std::string id = base::StringPrintf("%s:%d", bus_id.c_str(), device); |
| 33 const std::string name = snd_rawmidi_info_get_name(midi); | 33 const std::string name = snd_rawmidi_info_get_name(midi); |
| 34 // We assume that card longname is in the format of | 34 // We assume that card longname is in the format of |
| 35 // "<manufacturer> <name> at <bus>". Otherwise, we give up to detect | 35 // "<manufacturer> <name> at <bus>". Otherwise, we give up to detect |
| 36 // a manufacturer name here. | 36 // a manufacturer name here. |
| 37 std::string manufacturer; | 37 std::string manufacturer; |
| 38 const std::string card_name = snd_ctl_card_info_get_longname(card); | 38 const std::string card_name = snd_ctl_card_info_get_longname(card); |
| 39 size_t name_index = card_name.find(name); | 39 size_t name_index = card_name.find(name); |
| 40 if (std::string::npos != name_index) | 40 if (std::string::npos != name_index) |
| 41 manufacturer = card_name.substr(0, name_index - 1); | 41 manufacturer = card_name.substr(0, name_index - 1); |
| 42 const std::string version = | 42 const std::string version = |
| 43 base::StringPrintf("%s / ALSA library version %d.%d.%d", | 43 base::StringPrintf("%s / ALSA library version %d.%d.%d", |
| 44 snd_ctl_card_info_get_driver(card), | 44 snd_ctl_card_info_get_driver(card), |
| 45 SND_LIB_MAJOR, SND_LIB_MINOR, SND_LIB_SUBMINOR); | 45 SND_LIB_MAJOR, SND_LIB_MINOR, SND_LIB_SUBMINOR); |
| 46 port_info_ = MIDIPortInfo(id, manufacturer, name, version); | 46 port_info_ = MidiPortInfo(id, manufacturer, name, version); |
| 47 } | 47 } |
| 48 | 48 |
| 49 void Send(MIDIManagerClient* client, const std::vector<uint8>& data) { | 49 void Send(MidiManagerClient* client, const std::vector<uint8>& data) { |
| 50 ssize_t result = snd_rawmidi_write( | 50 ssize_t result = snd_rawmidi_write( |
| 51 midi_out_, reinterpret_cast<const void*>(&data[0]), data.size()); | 51 midi_out_, reinterpret_cast<const void*>(&data[0]), data.size()); |
| 52 if (static_cast<size_t>(result) != data.size()) { | 52 if (static_cast<size_t>(result) != data.size()) { |
| 53 // TODO(toyoshim): Disconnect and reopen the device. | 53 // TODO(toyoshim): Disconnect and reopen the device. |
| 54 LOG(ERROR) << "snd_rawmidi_write fails: " << strerror(-result); | 54 LOG(ERROR) << "snd_rawmidi_write fails: " << strerror(-result); |
| 55 } | 55 } |
| 56 base::MessageLoop::current()->PostTask( | 56 base::MessageLoop::current()->PostTask( |
| 57 FROM_HERE, | 57 FROM_HERE, |
| 58 base::Bind(&MIDIManagerClient::AccumulateMIDIBytesSent, | 58 base::Bind(&MidiManagerClient::AccumulateMidiBytesSent, |
| 59 base::Unretained(client), data.size())); | 59 base::Unretained(client), data.size())); |
| 60 } | 60 } |
| 61 | 61 |
| 62 const MIDIPortInfo& GetMIDIPortInfo() const { return port_info_; } | 62 const MidiPortInfo& GetMidiPortInfo() const { return port_info_; } |
| 63 bool IsOpened() const { return opened_; } | 63 bool IsOpened() const { return opened_; } |
| 64 | 64 |
| 65 private: | 65 private: |
| 66 friend class base::RefCounted<MIDIDeviceInfo>; | 66 friend class base::RefCounted<MidiDeviceInfo>; |
| 67 virtual ~MIDIDeviceInfo() { | 67 virtual ~MidiDeviceInfo() { |
| 68 if (opened_) { | 68 if (opened_) { |
| 69 snd_rawmidi_close(midi_in_); | 69 snd_rawmidi_close(midi_in_); |
| 70 snd_rawmidi_close(midi_out_); | 70 snd_rawmidi_close(midi_out_); |
| 71 } | 71 } |
| 72 } | 72 } |
| 73 | 73 |
| 74 bool opened_; | 74 bool opened_; |
| 75 MIDIPortInfo port_info_; | 75 MidiPortInfo port_info_; |
| 76 snd_rawmidi_t* midi_in_; | 76 snd_rawmidi_t* midi_in_; |
| 77 snd_rawmidi_t* midi_out_; | 77 snd_rawmidi_t* midi_out_; |
| 78 | 78 |
| 79 DISALLOW_COPY_AND_ASSIGN(MIDIDeviceInfo); | 79 DISALLOW_COPY_AND_ASSIGN(MidiDeviceInfo); |
| 80 }; | 80 }; |
| 81 | 81 |
| 82 MIDIManagerAlsa::MIDIManagerAlsa() | 82 MidiManagerAlsa::MidiManagerAlsa() |
| 83 : send_thread_("MIDISendThread") { | 83 : send_thread_("MidiSendThread") { |
| 84 } | 84 } |
| 85 | 85 |
| 86 bool MIDIManagerAlsa::Initialize() { | 86 bool MidiManagerAlsa::Initialize() { |
| 87 // TODO(toyoshim): Make Initialize() asynchronous. | 87 // TODO(toyoshim): Make Initialize() asynchronous. |
| 88 TRACE_EVENT0("midi", "MIDIManagerMac::Initialize"); | 88 // See http://crbug.com/339746. |
| 89 TRACE_EVENT0("midi", "MidiManagerMac::Initialize"); |
| 89 | 90 |
| 90 // Enumerate only hardware MIDI devices because software MIDIs running in | 91 // Enumerate only hardware MIDI devices because software MIDIs running in |
| 91 // the browser process is not secure. | 92 // the browser process is not secure. |
| 92 snd_ctl_card_info_t* card; | 93 snd_ctl_card_info_t* card; |
| 93 snd_rawmidi_info_t* midi_out; | 94 snd_rawmidi_info_t* midi_out; |
| 94 snd_rawmidi_info_t* midi_in; | 95 snd_rawmidi_info_t* midi_in; |
| 95 snd_ctl_card_info_alloca(&card); | 96 snd_ctl_card_info_alloca(&card); |
| 96 snd_rawmidi_info_alloca(&midi_out); | 97 snd_rawmidi_info_alloca(&midi_out); |
| 97 snd_rawmidi_info_alloca(&midi_in); | 98 snd_rawmidi_info_alloca(&midi_in); |
| 98 for (int index = -1; !snd_card_next(&index) && index >= 0; ) { | 99 for (int index = -1; !snd_card_next(&index) && index >= 0; ) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 116 snd_rawmidi_info_set_device(midi_out, device); | 117 snd_rawmidi_info_set_device(midi_out, device); |
| 117 snd_rawmidi_info_set_subdevice(midi_out, 0); | 118 snd_rawmidi_info_set_subdevice(midi_out, 0); |
| 118 snd_rawmidi_info_set_stream(midi_out, SND_RAWMIDI_STREAM_OUTPUT); | 119 snd_rawmidi_info_set_stream(midi_out, SND_RAWMIDI_STREAM_OUTPUT); |
| 119 output = snd_ctl_rawmidi_info(handle, midi_out) == 0; | 120 output = snd_ctl_rawmidi_info(handle, midi_out) == 0; |
| 120 snd_rawmidi_info_set_device(midi_in, device); | 121 snd_rawmidi_info_set_device(midi_in, device); |
| 121 snd_rawmidi_info_set_subdevice(midi_in, 0); | 122 snd_rawmidi_info_set_subdevice(midi_in, 0); |
| 122 snd_rawmidi_info_set_stream(midi_in, SND_RAWMIDI_STREAM_INPUT); | 123 snd_rawmidi_info_set_stream(midi_in, SND_RAWMIDI_STREAM_INPUT); |
| 123 input = snd_ctl_rawmidi_info(handle, midi_in) == 0; | 124 input = snd_ctl_rawmidi_info(handle, midi_in) == 0; |
| 124 if (!output && !input) | 125 if (!output && !input) |
| 125 continue; | 126 continue; |
| 126 scoped_refptr<MIDIDeviceInfo> port = new MIDIDeviceInfo( | 127 scoped_refptr<MidiDeviceInfo> port = new MidiDeviceInfo( |
| 127 this, id, card, output ? midi_out : midi_in, device); | 128 this, id, card, output ? midi_out : midi_in, device); |
| 128 if (!port->IsOpened()) { | 129 if (!port->IsOpened()) { |
| 129 DLOG(ERROR) << "MIDIDeviceInfo open fails"; | 130 DLOG(ERROR) << "MidiDeviceInfo open fails"; |
| 130 continue; | 131 continue; |
| 131 } | 132 } |
| 132 if (input) { | 133 if (input) { |
| 133 in_devices_.push_back(port); | 134 in_devices_.push_back(port); |
| 134 AddInputPort(port->GetMIDIPortInfo()); | 135 AddInputPort(port->GetMidiPortInfo()); |
| 135 } | 136 } |
| 136 if (output) { | 137 if (output) { |
| 137 out_devices_.push_back(port); | 138 out_devices_.push_back(port); |
| 138 AddOutputPort(port->GetMIDIPortInfo()); | 139 AddOutputPort(port->GetMidiPortInfo()); |
| 139 } | 140 } |
| 140 } | 141 } |
| 141 snd_ctl_close(handle); | 142 snd_ctl_close(handle); |
| 142 } | 143 } |
| 143 return true; | 144 return true; |
| 144 } | 145 } |
| 145 | 146 |
| 146 MIDIManagerAlsa::~MIDIManagerAlsa() { | 147 MidiManagerAlsa::~MidiManagerAlsa() { |
| 147 send_thread_.Stop(); | 148 send_thread_.Stop(); |
| 148 } | 149 } |
| 149 | 150 |
| 150 void MIDIManagerAlsa::DispatchSendMIDIData(MIDIManagerClient* client, | 151 void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client, |
| 151 uint32 port_index, | 152 uint32 port_index, |
| 152 const std::vector<uint8>& data, | 153 const std::vector<uint8>& data, |
| 153 double timestamp) { | 154 double timestamp) { |
| 154 if (out_devices_.size() <= port_index) | 155 if (out_devices_.size() <= port_index) |
| 155 return; | 156 return; |
| 156 | 157 |
| 157 base::TimeDelta delay; | 158 base::TimeDelta delay; |
| 158 if (timestamp != 0.0) { | 159 if (timestamp != 0.0) { |
| 159 base::TimeTicks time_to_send = | 160 base::TimeTicks time_to_send = |
| 160 base::TimeTicks() + base::TimeDelta::FromMicroseconds( | 161 base::TimeTicks() + base::TimeDelta::FromMicroseconds( |
| 161 timestamp * base::Time::kMicrosecondsPerSecond); | 162 timestamp * base::Time::kMicrosecondsPerSecond); |
| 162 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); | 163 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); |
| 163 } | 164 } |
| 164 | 165 |
| 165 if (!send_thread_.IsRunning()) | 166 if (!send_thread_.IsRunning()) |
| 166 send_thread_.Start(); | 167 send_thread_.Start(); |
| 167 | 168 |
| 168 scoped_refptr<MIDIDeviceInfo> device = out_devices_[port_index]; | 169 scoped_refptr<MidiDeviceInfo> device = out_devices_[port_index]; |
| 169 send_thread_.message_loop()->PostDelayedTask( | 170 send_thread_.message_loop()->PostDelayedTask( |
| 170 FROM_HERE, | 171 FROM_HERE, |
| 171 base::Bind(&MIDIDeviceInfo::Send, device, client, data), | 172 base::Bind(&MidiDeviceInfo::Send, device, client, data), |
| 172 delay); | 173 delay); |
| 173 } | 174 } |
| 174 | 175 |
| 175 MIDIManager* MIDIManager::Create() { | 176 MidiManager* MidiManager::Create() { |
| 176 return new MIDIManagerAlsa(); | 177 return new MidiManagerAlsa(); |
| 177 } | 178 } |
| 178 | 179 |
| 179 } // namespace media | 180 } // namespace media |
| OLD | NEW |