| 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 namespace { | 19 namespace { |
| 20 const char kUnknown[] = "[unknown]"; | 20 const char kUnknown[] = "[unknown]"; |
| 21 } // namespace | 21 } // namespace |
| 22 | 22 |
| 23 class MIDIManagerAlsa::MIDIDeviceInfo | 23 class MidiManagerAlsa::MidiDeviceInfo |
| 24 : public base::RefCounted<MIDIDeviceInfo> { | 24 : public base::RefCounted<MidiDeviceInfo> { |
| 25 public: | 25 public: |
| 26 MIDIDeviceInfo(MIDIManagerAlsa* manager, | 26 MidiDeviceInfo(MidiManagerAlsa* manager, |
| 27 const std::string& card, | 27 const std::string& card, |
| 28 const snd_rawmidi_info_t* midi, | 28 const snd_rawmidi_info_t* midi, |
| 29 int device) { | 29 int device) { |
| 30 opened_ = !snd_rawmidi_open(&midi_in_, &midi_out_, card.c_str(), 0); | 30 opened_ = !snd_rawmidi_open(&midi_in_, &midi_out_, card.c_str(), 0); |
| 31 if (!opened_) | 31 if (!opened_) |
| 32 return; | 32 return; |
| 33 | 33 |
| 34 const std::string name = snd_rawmidi_info_get_name(midi); | 34 const std::string name = snd_rawmidi_info_get_name(midi); |
| 35 const std::string id = base::StringPrintf("%s:%d", card.c_str(), device); | 35 const std::string id = base::StringPrintf("%s:%d", card.c_str(), device); |
| 36 port_info_ = MIDIPortInfo(id, kUnknown, name, kUnknown); | 36 port_info_ = MidiPortInfo(id, kUnknown, name, kUnknown); |
| 37 } | 37 } |
| 38 | 38 |
| 39 void Send(MIDIManagerClient* client, const std::vector<uint8>& data) { | 39 void Send(MidiManagerClient* client, const std::vector<uint8>& data) { |
| 40 ssize_t result = snd_rawmidi_write( | 40 ssize_t result = snd_rawmidi_write( |
| 41 midi_out_, reinterpret_cast<const void*>(&data[0]), data.size()); | 41 midi_out_, reinterpret_cast<const void*>(&data[0]), data.size()); |
| 42 if (static_cast<size_t>(result) != data.size()) { | 42 if (static_cast<size_t>(result) != data.size()) { |
| 43 // TODO(toyoshim): Disconnect and reopen the device. | 43 // TODO(toyoshim): Disconnect and reopen the device. |
| 44 LOG(ERROR) << "snd_rawmidi_write fails: " << strerror(-result); | 44 LOG(ERROR) << "snd_rawmidi_write fails: " << strerror(-result); |
| 45 } | 45 } |
| 46 base::MessageLoop::current()->PostTask( | 46 base::MessageLoop::current()->PostTask( |
| 47 FROM_HERE, | 47 FROM_HERE, |
| 48 base::Bind(&MIDIManagerClient::AccumulateMIDIBytesSent, | 48 base::Bind(&MidiManagerClient::AccumulateMidiBytesSent, |
| 49 base::Unretained(client), data.size())); | 49 base::Unretained(client), data.size())); |
| 50 } | 50 } |
| 51 | 51 |
| 52 const MIDIPortInfo& GetMIDIPortInfo() const { return port_info_; } | 52 const MidiPortInfo& GetMidiPortInfo() const { return port_info_; } |
| 53 bool IsOpened() const { return opened_; } | 53 bool IsOpened() const { return opened_; } |
| 54 | 54 |
| 55 private: | 55 private: |
| 56 friend class base::RefCounted<MIDIDeviceInfo>; | 56 friend class base::RefCounted<MidiDeviceInfo>; |
| 57 virtual ~MIDIDeviceInfo() { | 57 virtual ~MidiDeviceInfo() { |
| 58 if (opened_) { | 58 if (opened_) { |
| 59 snd_rawmidi_close(midi_in_); | 59 snd_rawmidi_close(midi_in_); |
| 60 snd_rawmidi_close(midi_out_); | 60 snd_rawmidi_close(midi_out_); |
| 61 } | 61 } |
| 62 } | 62 } |
| 63 | 63 |
| 64 bool opened_; | 64 bool opened_; |
| 65 MIDIPortInfo port_info_; | 65 MidiPortInfo port_info_; |
| 66 snd_rawmidi_t* midi_in_; | 66 snd_rawmidi_t* midi_in_; |
| 67 snd_rawmidi_t* midi_out_; | 67 snd_rawmidi_t* midi_out_; |
| 68 | 68 |
| 69 DISALLOW_COPY_AND_ASSIGN(MIDIDeviceInfo); | 69 DISALLOW_COPY_AND_ASSIGN(MidiDeviceInfo); |
| 70 }; | 70 }; |
| 71 | 71 |
| 72 MIDIManagerAlsa::MIDIManagerAlsa() | 72 MidiManagerAlsa::MidiManagerAlsa() |
| 73 : send_thread_("MIDISendThread") { | 73 : send_thread_("MidiSendThread") { |
| 74 } | 74 } |
| 75 | 75 |
| 76 bool MIDIManagerAlsa::Initialize() { | 76 bool MidiManagerAlsa::Initialize() { |
| 77 // TODO(toyoshim): Make Initialize() asynchronous. | 77 // TODO(crbug.com/339746): Make Initialize() asynchronous. |
| 78 TRACE_EVENT0("midi", "MIDIManagerMac::Initialize"); | 78 TRACE_EVENT0("midi", "MidiManagerMac::Initialize"); |
| 79 | 79 |
| 80 // Enumerate only hardware MIDI devices because software MIDIs running in | 80 // Enumerate only hardware MIDI devices because software MIDIs running in |
| 81 // the browser process is not secure. | 81 // the browser process is not secure. |
| 82 snd_ctl_card_info_t* card; | 82 snd_ctl_card_info_t* card; |
| 83 snd_rawmidi_info_t* midi_out; | 83 snd_rawmidi_info_t* midi_out; |
| 84 snd_rawmidi_info_t* midi_in; | 84 snd_rawmidi_info_t* midi_in; |
| 85 snd_ctl_card_info_alloca(&card); | 85 snd_ctl_card_info_alloca(&card); |
| 86 snd_rawmidi_info_alloca(&midi_out); | 86 snd_rawmidi_info_alloca(&midi_out); |
| 87 snd_rawmidi_info_alloca(&midi_in); | 87 snd_rawmidi_info_alloca(&midi_in); |
| 88 for (int index = -1; !snd_card_next(&index) && index >= 0; ) { | 88 for (int index = -1; !snd_card_next(&index) && index >= 0; ) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 106 snd_rawmidi_info_set_device(midi_out, device); | 106 snd_rawmidi_info_set_device(midi_out, device); |
| 107 snd_rawmidi_info_set_subdevice(midi_out, 0); | 107 snd_rawmidi_info_set_subdevice(midi_out, 0); |
| 108 snd_rawmidi_info_set_stream(midi_out, SND_RAWMIDI_STREAM_OUTPUT); | 108 snd_rawmidi_info_set_stream(midi_out, SND_RAWMIDI_STREAM_OUTPUT); |
| 109 output = snd_ctl_rawmidi_info(handle, midi_out) == 0; | 109 output = snd_ctl_rawmidi_info(handle, midi_out) == 0; |
| 110 snd_rawmidi_info_set_device(midi_in, device); | 110 snd_rawmidi_info_set_device(midi_in, device); |
| 111 snd_rawmidi_info_set_subdevice(midi_in, 0); | 111 snd_rawmidi_info_set_subdevice(midi_in, 0); |
| 112 snd_rawmidi_info_set_stream(midi_in, SND_RAWMIDI_STREAM_INPUT); | 112 snd_rawmidi_info_set_stream(midi_in, SND_RAWMIDI_STREAM_INPUT); |
| 113 input = snd_ctl_rawmidi_info(handle, midi_in) == 0; | 113 input = snd_ctl_rawmidi_info(handle, midi_in) == 0; |
| 114 if (!output && !input) | 114 if (!output && !input) |
| 115 continue; | 115 continue; |
| 116 scoped_refptr<MIDIDeviceInfo> port = | 116 scoped_refptr<MidiDeviceInfo> port = |
| 117 new MIDIDeviceInfo(this, id, output ? midi_out : midi_in, device); | 117 new MidiDeviceInfo(this, id, output ? midi_out : midi_in, device); |
| 118 if (!port->IsOpened()) { | 118 if (!port->IsOpened()) { |
| 119 DLOG(ERROR) << "MIDIDeviceInfo open fails"; | 119 DLOG(ERROR) << "MidiDeviceInfo open fails"; |
| 120 continue; | 120 continue; |
| 121 } | 121 } |
| 122 if (input) { | 122 if (input) { |
| 123 in_devices_.push_back(port); | 123 in_devices_.push_back(port); |
| 124 AddInputPort(port->GetMIDIPortInfo()); | 124 AddInputPort(port->GetMidiPortInfo()); |
| 125 } | 125 } |
| 126 if (output) { | 126 if (output) { |
| 127 out_devices_.push_back(port); | 127 out_devices_.push_back(port); |
| 128 AddOutputPort(port->GetMIDIPortInfo()); | 128 AddOutputPort(port->GetMidiPortInfo()); |
| 129 } | 129 } |
| 130 } | 130 } |
| 131 snd_ctl_close(handle); | 131 snd_ctl_close(handle); |
| 132 } | 132 } |
| 133 return true; | 133 return true; |
| 134 } | 134 } |
| 135 | 135 |
| 136 MIDIManagerAlsa::~MIDIManagerAlsa() { | 136 MidiManagerAlsa::~MidiManagerAlsa() { |
| 137 send_thread_.Stop(); | 137 send_thread_.Stop(); |
| 138 } | 138 } |
| 139 | 139 |
| 140 void MIDIManagerAlsa::DispatchSendMIDIData(MIDIManagerClient* client, | 140 void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client, |
| 141 uint32 port_index, | 141 uint32 port_index, |
| 142 const std::vector<uint8>& data, | 142 const std::vector<uint8>& data, |
| 143 double timestamp) { | 143 double timestamp) { |
| 144 if (out_devices_.size() <= port_index) | 144 if (out_devices_.size() <= port_index) |
| 145 return; | 145 return; |
| 146 | 146 |
| 147 base::TimeDelta delay; | 147 base::TimeDelta delay; |
| 148 if (timestamp != 0.0) { | 148 if (timestamp != 0.0) { |
| 149 base::TimeTicks time_to_send = | 149 base::TimeTicks time_to_send = |
| 150 base::TimeTicks() + base::TimeDelta::FromMicroseconds( | 150 base::TimeTicks() + base::TimeDelta::FromMicroseconds( |
| 151 timestamp * base::Time::kMicrosecondsPerSecond); | 151 timestamp * base::Time::kMicrosecondsPerSecond); |
| 152 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); | 152 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); |
| 153 } | 153 } |
| 154 | 154 |
| 155 if (!send_thread_.IsRunning()) | 155 if (!send_thread_.IsRunning()) |
| 156 send_thread_.Start(); | 156 send_thread_.Start(); |
| 157 | 157 |
| 158 scoped_refptr<MIDIDeviceInfo> device = out_devices_[port_index]; | 158 scoped_refptr<MidiDeviceInfo> device = out_devices_[port_index]; |
| 159 send_thread_.message_loop()->PostDelayedTask( | 159 send_thread_.message_loop()->PostDelayedTask( |
| 160 FROM_HERE, | 160 FROM_HERE, |
| 161 base::Bind(&MIDIDeviceInfo::Send, device, client, data), | 161 base::Bind(&MidiDeviceInfo::Send, device, client, data), |
| 162 delay); | 162 delay); |
| 163 } | 163 } |
| 164 | 164 |
| 165 MIDIManager* MIDIManager::Create() { | 165 MidiManager* MidiManager::Create() { |
| 166 return new MIDIManagerAlsa(); | 166 return new MidiManagerAlsa(); |
| 167 } | 167 } |
| 168 | 168 |
| 169 } // namespace media | 169 } // namespace media |
| OLD | NEW |